From c7837840f5747694838a6b36b6eee8e82b221889 Mon Sep 17 00:00:00 2001 From: Arian van Putten Date: Sat, 18 Jul 2026 22:19:18 +0200 Subject: [PATCH] firstboot: apply hostname via hostnamed varlink API Previously we just wrote /etc/hostname and returned. The kernel hostname was left at whatever PID 1 sethostname()'d very early in boot (before /etc/hostname existed), which meant hostnamectl reported the transient hostname instead of the static one until the next reboot. Call io.systemd.Hostname.SetStaticHostname on the running system so hostnamed writes /etc/hostname and updates the kernel hostname in one step. If hostnamed is unreachable (masked or absent on minimal images) fall back to writing /etc/hostname directly. --root=/--image= also keeps writing the file directly, since hostnamed only manages the running system. --- src/firstboot/firstboot.c | 35 +++++++++++++++++++++++++++++---- units/systemd-firstboot.service | 1 + 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index b7d30baf3c..cfadbea289 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -777,19 +777,46 @@ static int process_hostname(int rfd, sd_varlink **mute_console_link) { * and let it be resolved on each first boot. */ const char *hostname = arg_hostname; _cleanup_free_ char *resolved = NULL; + _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL; if (!arg_root) { r = hostname_substitute_wildcards(arg_hostname, &resolved); if (r < 0) log_warning_errno(r, "Failed to resolve wildcards in hostname '%s', writing it verbatim: %m", arg_hostname); else if (!hostname_is_valid(resolved, VALID_HOSTNAME_TRAILING_DOT)) log_warning("Resolved hostname '%s' is invalid, writing template '%s' verbatim instead.", resolved, arg_hostname); - else + else { hostname = resolved; + + r = sd_varlink_connect_address(&vl, "/run/systemd/io.systemd.Hostname"); + if (r < 0) + log_warning_errno(r, "Failed to connect to systemd-hostnamed, writing /etc/hostname directly: %m"); + } } - r = write_string_file_full_label(pfd, f, hostname, - WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL, - /* ts= */ NULL, /* label_fn= */ NULL, arg_label_context); + if (vl) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *reply = NULL; + const char *error_id = NULL; + r = sd_varlink_callbo( + vl, + "io.systemd.Hostname.SetStaticHostname", + &reply, + &error_id, + SD_JSON_BUILD_PAIR_STRING("newValue", hostname)); + if (r < 0) + log_warning_errno(r, "Failed to call io.systemd.Hostname.SetStaticHostname, writing /etc/hostname directly: %m"); + else if (error_id) + log_warning_errno(sd_varlink_error_to_errno(error_id, reply), + "Failed to set static hostname, writing /etc/hostname directly: %s", error_id); + else { + log_info("Static hostname configured via systemd-hostnamed."); + return 0; + } + } + + r = write_string_file_full_label( + pfd, f, hostname, + WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL, + /* ts= */ NULL, /* label_fn= */ NULL, arg_label_context); if (r < 0) return log_error_errno(r, "Failed to write /etc/hostname: %m"); diff --git a/units/systemd-firstboot.service b/units/systemd-firstboot.service index fb1c59ad6f..9fb0314f6f 100644 --- a/units/systemd-firstboot.service +++ b/units/systemd-firstboot.service @@ -23,6 +23,7 @@ After=systemd-sysusers.service systemd-tmpfiles-setup.service # Let vconsole-setup do its setup before starting user interaction: After=systemd-vconsole-setup.service After=systemd-mute-console.socket +After=systemd-hostnamed.socket Wants=first-boot-complete.target Before=first-boot-complete.target sysinit.target