chiark / gitweb /
util: make a couple of files we write atomic
[elogind.git] / src / hostnamed.c
index 8c0035a03774c17ee837ce7cb22bf3747cebbda6..68c5715b0e1cc1ed7ab6df2cd510a7407c844d6b 100644 (file)
@@ -24,6 +24,7 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
+#include <dlfcn.h>
 
 #include "util.h"
 #include "strv.h"
@@ -110,6 +111,18 @@ static int read_data(void) {
         return 0;
 }
 
+static bool check_nss(void) {
+
+        void *dl;
+
+        if ((dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY))) {
+                dlclose(dl);
+                return true;
+        }
+
+        return false;
+}
+
 static const char* fallback_icon_name(void) {
 
 #if defined(__i386__) || defined(__x86_64__)
@@ -188,7 +201,7 @@ static int write_data_static_hostname(void) {
                 return 0;
         }
 
-        return write_one_line_file("/etc/hostname", data[PROP_STATIC_HOSTNAME]);
+        return write_one_line_file_atomic("/etc/hostname", data[PROP_STATIC_HOSTNAME]);
 }
 
 static int write_data_other(void) {
@@ -568,7 +581,13 @@ static DBusHandlerResult hostname_message_handler(
 
                 if (!streq_ptr(name, data[k])) {
 
-                        r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-machine-info", interactive, &error);
+                        /* Since the pretty hostname should always be
+                         * changed at the same time as the static one,
+                         * use the same policy action for both... */
+
+                        r = verify_polkit(connection, message, k == PROP_PRETTY_HOSTNAME ?
+                                          "org.freedesktop.hostname1.set-static-hostname" :
+                                          "org.freedesktop.hostname1.set-machine-info", interactive, &error);
                         if (r < 0)
                                 return bus_send_error_reply(connection, message, &error, r);
 
@@ -636,17 +655,55 @@ oom:
         return DBUS_HANDLER_RESULT_NEED_MEMORY;
 }
 
-int main(int argc, char *argv[]) {
-        const DBusObjectPathVTable hostname_vtable = {
+static int connect_bus(DBusConnection **_bus) {
+        static const DBusObjectPathVTable hostname_vtable = {
                 .message_function = hostname_message_handler
         };
-
-        DBusConnection *bus = NULL;
         DBusError error;
+        DBusConnection *bus = NULL;
         int r;
 
+        assert(_bus);
+
         dbus_error_init(&error);
 
+        bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+        if (!bus) {
+                log_error("Failed to get system D-Bus connection: %s", error.message);
+                r = -ECONNREFUSED;
+                goto fail;
+        }
+
+        if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL)) {
+                log_error("Not enough memory");
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (dbus_bus_request_name(bus, "org.freedesktop.hostname1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
+                log_error("Failed to register name on bus: %s", error.message);
+                r = -EEXIST;
+                goto fail;
+        }
+
+        if (_bus)
+                *_bus = bus;
+
+        return 0;
+
+fail:
+        dbus_connection_close(bus);
+        dbus_connection_unref(bus);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
+int main(int argc, char *argv[]) {
+        int r;
+        DBusConnection *bus = NULL;
+
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
         log_open();
@@ -657,6 +714,9 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
+        if (!check_nss())
+                log_warning("Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!");
+
         umask(0022);
 
         r = read_data();
@@ -665,24 +725,9 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
-        if (!bus) {
-                log_error("Failed to get system D-Bus connection: %s", error.message);
-                r = -ECONNREFUSED;
-                goto finish;
-        }
-
-        if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL)) {
-                log_error("Not enough memory");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (dbus_bus_request_name(bus, "org.freedesktop.hostname1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) {
-                log_error("Failed to register name on bus: %s", error.message);
-                r = -EEXIST;
+        r = connect_bus(&bus);
+        if (r < 0)
                 goto finish;
-        }
 
         while (dbus_connection_read_write_dispatch(bus, -1))
                 ;
@@ -698,7 +743,5 @@ finish:
                 dbus_connection_unref(bus);
         }
 
-        dbus_error_free(&error);
-
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }