hostnamed parses its state information at the startup time and doesn't update it. This might lead to the situation when we are presenting administrator with inaccurate information. We should watch for changes in the system and update our state information accordingly. --- src/hostname/hostnamed.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+)
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index e57891b..045f24d 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -24,6 +24,10 @@ #include <unistd.h> #include <dlfcn.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + #include "util.h" #include "strv.h" #include "def.h" @@ -46,8 +50,12 @@ enum { typedef struct Context { char *data[_PROP_MAX]; Hashmap *polkit_registry; + int hostnamefd; + sd_event_source *hostname_fd_event_source; } Context; +static const char *proc_hostname = "/proc/sys/kernel/hostname"; + static void context_reset(Context *c) { int p; @@ -59,11 +67,21 @@ static void context_reset(Context *c) { } } +static void context_init(Context *c) { + assert(c); + + memzero(c, sizeof(*c)); + + c->hostnamefd = -1; +} + static void context_free(Context *c, sd_bus *bus) { assert(c); context_reset(c); bus_verify_polkit_async_registry_free(bus, c->polkit_registry); + sd_event_source_unref(c->hostname_fd_event_source); + close_nointr_nofail(c->hostnamefd); } static int context_read_data(Context *c) { @@ -592,6 +610,70 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { return 0; } +static int dispatch_hostname_change(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + int r = 0; + char hostname[HOST_NAME_MAX + 1] = {}, *t; + Context *context = (Context *) userdata; + + r = lseek(fd, 0, SEEK_SET); + if (r < 0) { + log_error("Failed to seek to begining of the file : %m"); + return -errno; + } + + r = read(fd, hostname, HOST_NAME_MAX); + if (r < 0) { + log_error("Failed to read hostname : %m"); + return -errno; + } + + strstrip(hostname); + + t = strdup(hostname); + if (!t) + return log_oom(); + free(context->data[PROP_HOSTNAME]); + context->data[PROP_HOSTNAME] = t; + + return r; +} + +static int open_hostname(sd_event *event, Context *context) { + int r = 0, fd; + + assert(event); + assert(context); + + fd = open(proc_hostname, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) { + log_error("Failed to open %s : %m", proc_hostname); + return -errno; + } + + context->hostnamefd = fd; + + r = sd_event_add_io(event, &context->hostname_fd_event_source, fd, EPOLLHUP, dispatch_hostname_change, context); + if (r < 0) { + /* poll on /proc/sys/kernel/hostname not supported by kernel */ + if (r == -EPERM) { + log_warning("Failed to register hostname fd in event loop: %m. Ignoring."); + close_nointr_nofail(fd); + return 0; + } + + log_error("Failed to register hostname fd in event loop : %m"); + return r; + } + + r = sd_event_source_set_priority(context->hostname_fd_event_source, SD_EVENT_PRIORITY_IMPORTANT); + if (r < 0) { + log_error("Failed to set priority for hostname fd event source : %m"); + return r; + } + + return r; +} + int main(int argc, char *argv[]) { Context context = {}; @@ -621,6 +703,8 @@ int main(int argc, char *argv[]) { goto finish; } + context_init(&context); + r = sd_event_default(&event); if (r < 0) { log_error("Failed to allocate event loop: %s", strerror(-r)); @@ -639,6 +723,10 @@ int main(int argc, char *argv[]) { goto finish; } + r = open_hostname(event, &context); + if (r < 0) + goto finish; + r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL); if (r < 0) { log_error("Failed to run event loop: %s", strerror(-r)); -- 1.8.4.2 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel