]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: keep machine-id transient until first boot completes
authorHarald Seiler <hws@denx.de>
Sun, 6 Sep 2020 19:23:36 +0000 (21:23 +0200)
committerHarald Seiler <hws@denx.de>
Mon, 19 Oct 2020 14:28:22 +0000 (16:28 +0200)
Currently, a loss of power after the machine-id was written but before
all units with ConditionFirstBoot=yes ran would lead to the next boot
finding a valid machine-id, thus not being marked first boot and not
re-running these units.

To make the first boot mechanism more robust, instead of writing
/etc/machine-id very early, fill it with a marker value "uninitialized"
and overmount it with a transiently provisioned machine-id.  Then, after
the first boots completes (when systemd-machine-id-commit.service runs),
write the real machine-id to disk.

This mechanism is of course only invoked on first boot.  If a first boot
is not detected, the machine-id is handled as previously.

Fixes: #4511
src/core/machine-id-setup.c
src/core/machine-id-setup.h
src/core/main.c
src/machine-id-setup/machine-id-setup-main.c

index 6aecd36fe6c087802602527a4388b70f4a310fe3..4e9a8d266e6cbf80b6024c9015b350f3b9a90844 100644 (file)
@@ -11,6 +11,7 @@
 #include "fd-util.h"
 #include "fs-util.h"
 #include "id128-util.h"
+#include "io-util.h"
 #include "log.h"
 #include "machine-id-setup.h"
 #include "macro.h"
@@ -86,7 +87,7 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) {
         return 0;
 }
 
-int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
+int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_id, sd_id128_t *ret) {
         const char *etc_machine_id, *run_machine_id;
         _cleanup_close_ int fd = -1;
         bool writable;
@@ -143,13 +144,31 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
                 if (ftruncate(fd, 0) < 0)
                         return log_error_errno(errno, "Failed to truncate %s: %m", etc_machine_id);
 
-                if (id128_write_fd(fd, ID128_PLAIN, machine_id, true) >= 0)
-                        goto finish;
+                /* If the caller requested a transient machine-id, write the string "uninitialized\n" to
+                 * disk and overmount it with a transient file.
+                 *
+                 * Otherwise write the machine-id directly to disk. */
+                if (force_transient) {
+                        r = loop_write(fd, "uninitialized\n", strlen("uninitialized\n"), false);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to write uninitialized %s: %m", etc_machine_id);
+
+                        r = fsync_full(fd);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to sync %s: %m", etc_machine_id);
+                } else {
+                        r = id128_write_fd(fd, ID128_PLAIN, machine_id, true);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to write %s: %m", etc_machine_id);
+                        else
+                                goto finish;
+                }
         }
 
         fd = safe_close(fd);
 
-        /* Hmm, we couldn't write it? So let's write it to /run/machine-id as a replacement */
+        /* Hmm, we couldn't or shouldn't write the machine-id to /etc?
+         * So let's write it to /run/machine-id as a replacement */
 
         run_machine_id = prefix_roota(root, "/run/machine-id");
 
@@ -167,7 +186,7 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
                 return r;
         }
 
-        log_info("Installed transient %s file.", etc_machine_id);
+        log_full(force_transient ? LOG_DEBUG : LOG_INFO, "Installed transient %s file.", etc_machine_id);
 
         /* Mark the mount read-only */
         r = mount_follow_verbose(LOG_WARNING, NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL);
index d6ac62a88243f3f763ccd9706a5242ee00426f84..e207ccf9c11a578de9a836021eef0c274bd7c685 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <stdbool.h>
+
 int machine_id_commit(const char *root);
-int machine_id_setup(const char *root, sd_id128_t requested, sd_id128_t *ret);
+int machine_id_setup(const char *root, bool force_transient, sd_id128_t requested, sd_id128_t *ret);
index a8a48db2a08d2d508c5ee5f56379c1f1f1f54b05..728e1578b1ae52bf521a98e2994a45ee063c6e63 100644 (file)
@@ -2037,6 +2037,7 @@ static void log_execution_mode(bool *ret_first_boot) {
 
 static int initialize_runtime(
                 bool skip_setup,
+                bool first_boot,
                 struct rlimit *saved_rlimit_nofile,
                 struct rlimit *saved_rlimit_memlock,
                 const char **ret_error_message) {
@@ -2070,7 +2071,8 @@ static int initialize_runtime(
 
                         status_welcome();
                         hostname_setup();
-                        machine_id_setup(NULL, arg_machine_id, NULL);
+                        /* Force transient machine-id on first boot. */
+                        machine_id_setup(NULL, first_boot, arg_machine_id, NULL);
                         (void) loopback_setup();
                         bump_unix_max_dgram_qlen();
                         bump_file_max_and_nr_open();
@@ -2798,6 +2800,7 @@ int main(int argc, char *argv[]) {
         log_execution_mode(&first_boot);
 
         r = initialize_runtime(skip_setup,
+                               first_boot,
                                &saved_rlimit_nofile,
                                &saved_rlimit_memlock,
                                &error_message);
index 872b00c158e4df42a0a37b8fc3652bbc34503d7e..2bcd99109eb1a8014dbf4ca8fb96a910fde1146a 100644 (file)
@@ -128,7 +128,7 @@ static int run(int argc, char *argv[]) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to read machine ID back: %m");
         } else {
-                r = machine_id_setup(arg_root, SD_ID128_NULL, &id);
+                r = machine_id_setup(arg_root, false, SD_ID128_NULL, &id);
                 if (r < 0)
                         return r;
         }