]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/hostname/hostnamed.c
hostnamed,shared/hostname-setup: expose the origin of the current hostname
[thirdparty/systemd.git] / src / hostname / hostnamed.c
index 9e8a4dd8a4218fbe40f4982ea29131ae1994c329..f0bf29028fad8ec84beaef0eb9185e65f42ba6da 100644 (file)
@@ -31,6 +31,7 @@
 #include "service-util.h"
 #include "signal-util.h"
 #include "stat-util.h"
+#include "string-table.h"
 #include "strv.h"
 #include "user-util.h"
 #include "util.h"
@@ -60,6 +61,8 @@ enum {
 typedef struct Context {
         char *data[_PROP_MAX];
 
+        HostnameSource hostname_source;
+
         struct stat etc_hostname_stat;
         struct stat etc_os_release_stat;
         struct stat etc_machine_info_stat;
@@ -317,35 +320,46 @@ static int context_update_kernel_hostname(
                 const char *transient_hn) {
 
         const char *hn;
-        struct utsname u;
+        HostnameSource hns;
         int r;
 
         assert(c);
 
-        if (!transient_hn) {
-                /* If no transient hostname is passed in, then let's check what is currently set. */
-                assert_se(uname(&u) >= 0);
-                transient_hn =
-                        isempty(u.nodename) || streq(u.nodename, "(none)") ? NULL : u.nodename;
-        }
-
         /* /etc/hostname has the highest preference ... */
-        if (c->data[PROP_STATIC_HOSTNAME])
+        if (c->data[PROP_STATIC_HOSTNAME]) {
                 hn = c->data[PROP_STATIC_HOSTNAME];
+                hns = HOSTNAME_STATIC;
 
         /* ... the transient hostname, (ie: DHCP) comes next ... */
-        else if (!isempty(transient_hn))
+        } else if (transient_hn) {
                 hn = transient_hn;
+                hns = HOSTNAME_TRANSIENT;
 
         /* ... and the ultimate fallback */
-        else
+        } else {
                 hn = FALLBACK_HOSTNAME;
+                hns = HOSTNAME_FALLBACK;
+        }
 
         r = sethostname_idempotent(hn);
         if (r < 0)
-                return r;
+                return log_error_errno(r, "Failed to set hostname: %m");
+
+        if (c->hostname_source != hns) {
+                c->hostname_source = hns;
+                r = 1;
+        }
 
         (void) nscd_flush_cache(STRV_MAKE("hosts"));
+
+        if (r == 0)
+                log_debug("Hostname was already set to <%s>.", hn);
+        else {
+                log_info("Hostname set to <%s> (%s)", hn, hostname_source_to_string(hns));
+
+                hostname_update_source_hint(hn, hns);
+        }
+
         return r; /* 0 if no change, 1 if something was done  */
 }
 
@@ -452,6 +466,50 @@ static int property_get_static_hostname(
 
 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_fallback_hostname, "s", FALLBACK_HOSTNAME);
 
+static int property_get_hostname_source(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Context *c = userdata;
+        int r;
+        assert(c);
+
+        context_read_etc_hostname(c);
+
+        if (c->hostname_source < 0) {
+                char hostname[HOST_NAME_MAX + 1] = {};
+                _cleanup_free_ char *fallback = NULL;
+
+                (void) get_hostname_filtered(hostname);
+
+                if (streq_ptr(hostname, c->data[PROP_STATIC_HOSTNAME]))
+                        c->hostname_source = HOSTNAME_STATIC;
+
+                else {
+                        /* If the hostname was not set by us, try to figure out where it came from. If we set
+                         * it to the fallback hostname, the file will tell us. We compare the string because
+                         * it is possible that the hostname was set by an older version that had a different
+                         * fallback, in the initramfs or before we reexecuted. */
+
+                        r = read_one_line_file("/run/systemd/fallback-hostname", &fallback);
+                        if (r < 0 && r != -ENOENT)
+                                log_warning_errno(r, "Failed to read /run/systemd/fallback-hostname, ignoring: %m");
+
+                        if (streq_ptr(fallback, hostname))
+                                c->hostname_source = HOSTNAME_FALLBACK;
+                        else
+                                c->hostname_source = HOSTNAME_TRANSIENT;
+                }
+        }
+
+        return sd_bus_message_append(reply, "s", hostname_source_to_string(c->hostname_source));
+}
+
 static int property_get_machine_info_field(
                 sd_bus *bus,
                 const char *path,
@@ -570,7 +628,6 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
         Context *c = userdata;
         const char *name;
         int interactive, r;
-        struct utsname u;
 
         assert(m);
         assert(c);
@@ -579,20 +636,15 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
         if (r < 0)
                 return r;
 
-        context_read_etc_hostname(c);
-
-        if (isempty(name))
-                name = c->data[PROP_STATIC_HOSTNAME];
+        name = empty_to_null(name);
 
-        if (isempty(name))
-                name = FALLBACK_HOSTNAME;
+        /* We always go through with the procedure below without comparing to the current hostname, because
+         * we might want to adjust hostname source information even if the actual hostname is unchanged. */
 
         if (!hostname_is_valid(name, 0))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
 
-        assert_se(uname(&u) >= 0);
-        if (streq_ptr(name, u.nodename))
-                return sd_bus_reply_method_return(m, NULL);
+        context_read_etc_hostname(c);
 
         r = bus_verify_polkit_async(
                         m,
@@ -609,18 +661,12 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
         r = context_update_kernel_hostname(c, name);
-        if (r < 0) {
-                log_error_errno(r, "Failed to set hostname: %m");
+        if (r < 0)
                 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
-        } else if (r == 0)
-                log_debug("Hostname was already set to <%s>.", name);
-        else {
-                log_info("Hostname set to <%s>", name);
-
+        else if (r > 0)
                 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
                                                       "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
                                                       "Hostname", "HostnameSource", NULL);
-        }
 
         return sd_bus_reply_method_return(m, NULL);
 }
@@ -645,7 +691,7 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
         if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
                 return sd_bus_reply_method_return(m, NULL);
 
-        if (!isempty(name) && !hostname_is_valid(name, 0))
+        if (name && !hostname_is_valid(name, 0))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
 
         r = bus_verify_polkit_async(
@@ -666,25 +712,21 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
         if (r < 0)
                 return r;
 
-        r = context_update_kernel_hostname(c, NULL);
-        if (r < 0) {
-                log_error_errno(r, "Failed to set hostname: %m");
-                return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
-        }
-
         r = context_write_data_static_hostname(c);
         if (r < 0) {
                 log_error_errno(r, "Failed to write static hostname: %m");
                 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
         }
 
-        if (c->data[PROP_STATIC_HOSTNAME])
-                log_info("Changed static hostname to <%s>", c->data[PROP_STATIC_HOSTNAME]);
-        else
-                log_info("Unset static hostname.");
+        r = context_update_kernel_hostname(c, NULL);
+        if (r < 0) {
+                log_error_errno(r, "Failed to set hostname: %m");
+                return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
+        }
 
         (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
-                                              "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
+                                              "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
+                                              "StaticHostname", "Hostname", "HostnameSource", NULL);
 
         return sd_bus_reply_method_return(m, NULL);
 }
@@ -850,6 +892,7 @@ static const sd_bus_vtable hostname_vtable[] = {
         SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("FallbackHostname", "s", property_get_fallback_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -960,7 +1003,9 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **ret) {
 }
 
 static int run(int argc, char *argv[]) {
-        _cleanup_(context_destroy) Context context = {};
+        _cleanup_(context_destroy) Context context = {
+                .hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
+        };
         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;