#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"
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;
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 */
}
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,
Context *c = userdata;
const char *name;
int interactive, r;
- struct utsname u;
assert(m);
assert(c);
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,
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);
}
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(
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);
}
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),
}
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;