]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/machine-id-setup.c
Merge pull request #17732 from yuwata/core-use-synthetic_errno
[thirdparty/systemd.git] / src / core / machine-id-setup.c
index 248a83847eeedf97e79f21e35ef9f5d2ec40d004..6d15f9cd09cf7647e0195e73122b14533b745453 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <fcntl.h>
 #include <sched.h>
 #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"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
+#include "namespace-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "stat-util.h"
@@ -43,7 +46,7 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) {
                 fd = safe_close(fd);
         }
 
-        if (isempty(root)) {
+        if (isempty(root) && running_in_chroot() <= 0) {
                 /* If that didn't work, see if we are running in a container,
                  * and a machine ID was passed in via $container_uuid the way
                  * libvirt/LXC does it */
@@ -67,6 +70,11 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) {
                                 log_info("Initializing machine ID from KVM UUID.");
                                 return 0;
                         }
+                        /* on POWER, it's exported here instead */
+                        if (id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, ret) >= 0) {
+                                log_info("Initializing machine ID from KVM UUID.");
+                                return 0;
+                        }
                 }
         }
 
@@ -79,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;
@@ -136,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");
 
@@ -154,16 +180,18 @@ int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
         }
 
         /* And now, let's mount it over */
-        if (mount(run_machine_id, etc_machine_id, NULL, MS_BIND, NULL) < 0) {
-                (void) unlink_noerrno(run_machine_id);
-                return log_error_errno(errno, "Failed to mount %s: %m", etc_machine_id);
+        r = mount_follow_verbose(LOG_ERR, run_machine_id, etc_machine_id, NULL, MS_BIND, NULL);
+        if (r < 0) {
+                (void) unlink(run_machine_id);
+                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 */
-        if (mount(NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0)
-                log_warning_errno(errno, "Failed to make transient %s read-only, ignoring: %m", etc_machine_id);
+        r = mount_follow_verbose(LOG_WARNING, NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL);
+        if (r < 0)
+                return r;
 
 finish:
         if (ret)
@@ -174,10 +202,22 @@ finish:
 
 int machine_id_commit(const char *root) {
         _cleanup_close_ int fd = -1, initial_mntns_fd = -1;
-        const char *etc_machine_id;
+        const char *etc_machine_id, *sync_path;
         sd_id128_t id;
         int r;
 
+        /* Before doing anything, sync everything to ensure any changes by first-boot units are persisted.
+         *
+         * First, explicitly sync the file systems we care about and check if it worked. */
+        FOREACH_STRING(sync_path, "/etc/", "/var/") {
+                r = syncfs_path(AT_FDCWD, sync_path);
+                if (r < 0)
+                        return log_error_errno(r, "Cannot sync %s: %m", sync_path);
+        }
+
+        /* Afterwards, sync() the rest too, but we can't check the return value for these. */
+        sync();
+
         /* Replaces a tmpfs bind mount of /etc/machine-id by a proper file, atomically. For this, the umount is removed
          * in a mount namespace, a new file is created at the right place. Afterwards the mount is also removed in the
          * original mount namespace, thus revealing the file that was just created. */
@@ -200,10 +240,10 @@ int machine_id_commit(const char *root) {
         r = fd_is_temporary_fs(fd);
         if (r < 0)
                 return log_error_errno(r, "Failed to determine whether %s is on a temporary file system: %m", etc_machine_id);
-        if (r == 0) {
-                log_error("%s is not on a temporary file system.", etc_machine_id);
-                return -EROFS;
-        }
+        if (r == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EROFS),
+                                       "%s is not on a temporary file system.",
+                                       etc_machine_id);
 
         r = id128_read_fd(fd, ID128_PLAIN, &id);
         if (r < 0)
@@ -217,14 +257,13 @@ int machine_id_commit(const char *root) {
                 return log_error_errno(r, "Can't fetch current mount namespace: %m");
 
         /* Switch to a new mount namespace, isolate ourself and unmount etc_machine_id in our new namespace */
-        if (unshare(CLONE_NEWNS) < 0)
-                return log_error_errno(errno, "Failed to enter new namespace: %m");
-
-        if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0)
-                return log_error_errno(errno, "Couldn't make-rslave / mountpoint in our private namespace: %m");
+        r = detach_mount_namespace();
+        if (r < 0)
+                return log_error_errno(r, "Failed to set up new mount namespace: %m");
 
-        if (umount(etc_machine_id) < 0)
-                return log_error_errno(errno, "Failed to unmount transient %s file in our private namespace: %m", etc_machine_id);
+        r = umount_verbose(LOG_ERR, etc_machine_id, 0);
+        if (r < 0)
+                return r;
 
         /* Update a persistent version of etc_machine_id */
         r = id128_write(etc_machine_id, ID128_PLAIN, id, true);