diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/base-filesystem.c | 2 | ||||
-rw-r--r-- | src/shared/dissect-image.c | 116 | ||||
-rw-r--r-- | src/shared/dissect-image.h | 5 | ||||
-rw-r--r-- | src/shared/fstab-util.c | 2 | ||||
-rw-r--r-- | src/shared/machine-image.c | 49 | ||||
-rw-r--r-- | src/shared/switch-root.c | 139 | ||||
-rw-r--r-- | src/shared/volatile-util.c | 68 | ||||
-rw-r--r-- | src/shared/volatile-util.h | 32 |
8 files changed, 275 insertions, 138 deletions
diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c index f1fbce9dca..127cbe44e3 100644 --- a/src/shared/base-filesystem.c +++ b/src/shared/base-filesystem.c @@ -101,7 +101,7 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) { if (r < 0 && errno != EEXIST) return log_error_errno(errno, "Failed to create symlink at %s/%s: %m", root, table[i].dir); - if (uid != UID_INVALID || gid != UID_INVALID) { + if (uid_is_valid(uid) || gid_is_valid(gid)) { if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0) return log_error_errno(errno, "Failed to chown symlink at %s/%s: %m", root, table[i].dir); } diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index d3ba9b9dde..878cb008aa 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -84,7 +84,7 @@ not_found: #endif } -int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectedImage **ret) { +int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret) { #ifdef HAVE_BLKID sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL; @@ -95,7 +95,8 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte _cleanup_blkid_free_probe_ blkid_probe b = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; _cleanup_free_ char *generic_node = NULL; - const char *pttype = NULL, *usage = NULL; + sd_id128_t generic_uuid = SD_ID128_NULL; + const char *pttype = NULL; struct udev_list_entry *first, *item; blkid_partlist pl; int r, generic_nr; @@ -147,8 +148,12 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte return -errno; } - blkid_probe_enable_superblocks(b, 1); - blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE); + if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) { + /* Look for file system superblocks, unless we only shall look for GPT partition tables */ + blkid_probe_enable_superblocks(b, 1); + blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE); + } + blkid_probe_enable_partitions(b, 1); blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS); @@ -169,40 +174,45 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte if (!m) return -ENOMEM; - (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL); - if (STRPTR_IN_SET(usage, "filesystem", "crypto")) { - _cleanup_free_ char *t = NULL, *n = NULL; - const char *fstype = NULL; + if (!(flags & DISSECT_IMAGE_GPT_ONLY) && + (flags & DISSECT_IMAGE_REQUIRE_ROOT)) { + const char *usage = NULL; - /* OK, we have found a file system, that's our root partition then. */ - (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); + (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL); + if (STRPTR_IN_SET(usage, "filesystem", "crypto")) { + _cleanup_free_ char *t = NULL, *n = NULL; + const char *fstype = NULL; - if (fstype) { - t = strdup(fstype); - if (!t) - return -ENOMEM; - } + /* OK, we have found a file system, that's our root partition then. */ + (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); - if (asprintf(&n, "/dev/block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) - return -ENOMEM; + if (fstype) { + t = strdup(fstype); + if (!t) + return -ENOMEM; + } + + if (asprintf(&n, "/dev/block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) + return -ENOMEM; - m->partitions[PARTITION_ROOT] = (DissectedPartition) { - .found = true, - .rw = true, - .partno = -1, - .architecture = _ARCHITECTURE_INVALID, - .fstype = t, - .node = n, - }; + m->partitions[PARTITION_ROOT] = (DissectedPartition) { + .found = true, + .rw = true, + .partno = -1, + .architecture = _ARCHITECTURE_INVALID, + .fstype = t, + .node = n, + }; - t = n = NULL; + t = n = NULL; - m->encrypted = streq(fstype, "crypto_LUKS"); + m->encrypted = streq(fstype, "crypto_LUKS"); - *ret = m; - m = NULL; + *ret = m; + m = NULL; - return 0; + return 0; + } } (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); @@ -212,7 +222,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte is_gpt = streq_ptr(pttype, "gpt"); is_mbr = streq_ptr(pttype, "dos"); - if (!is_gpt && !is_mbr) + if (!is_gpt && ((flags & DISSECT_IMAGE_GPT_ONLY) || !is_mbr)) return -ENOPKG; errno = 0; @@ -300,7 +310,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte first = udev_enumerate_get_list_entry(e); udev_list_entry_foreach(item, first) { _cleanup_udev_device_unref_ struct udev_device *q; - unsigned long long flags; + unsigned long long pflags; blkid_partition pp; const char *node; dev_t qn; @@ -325,7 +335,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte if (!pp) continue; - flags = blkid_partition_get_flags(pp); + pflags = blkid_partition_get_flags(pp); nr = blkid_partition_get_partno(pp); if (nr < 0) @@ -337,7 +347,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte sd_id128_t type_id, id; bool rw = true; - if (flags & GPT_FLAG_NO_AUTO) + if (pflags & GPT_FLAG_NO_AUTO) continue; sid = blkid_partition_get_uuid(pp); @@ -354,10 +364,10 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte if (sd_id128_equal(type_id, GPT_HOME)) { designator = PARTITION_HOME; - rw = !(flags & GPT_FLAG_READ_ONLY); + rw = !(pflags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_SRV)) { designator = PARTITION_SRV; - rw = !(flags & GPT_FLAG_READ_ONLY); + rw = !(pflags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ESP)) { designator = PARTITION_ESP; fstype = "vfat"; @@ -371,7 +381,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte designator = PARTITION_ROOT; architecture = native_architecture(); - rw = !(flags & GPT_FLAG_READ_ONLY); + rw = !(pflags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) { m->can_verity = true; @@ -395,9 +405,8 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte designator = PARTITION_ROOT_SECONDARY; architecture = SECONDARY_ARCHITECTURE; - rw = !(flags & GPT_FLAG_READ_ONLY); + rw = !(pflags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) { - m->can_verity = true; /* Ignore verity unless root has is specified */ @@ -419,7 +428,8 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte multiple_generic = true; else { generic_nr = nr; - generic_rw = !(flags & GPT_FLAG_READ_ONLY); + generic_rw = !(pflags & GPT_FLAG_READ_ONLY); + generic_uuid = id; generic_node = strdup(node); if (!generic_node) return -ENOMEM; @@ -450,6 +460,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte .architecture = architecture, .node = n, .fstype = t, + .uuid = id, }; n = t = NULL; @@ -457,7 +468,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte } else if (is_mbr) { - if (flags != 0x80) /* Bootable flag */ + if (pflags != 0x80) /* Bootable flag */ continue; if (blkid_partition_get_type(pp) != 0x83) /* Linux partition */ @@ -480,7 +491,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte * either, then check if there's a single generic one, and use that. */ if (m->partitions[PARTITION_ROOT_VERITY].found) - return -ENXIO; + return -EADDRNOTAVAIL; if (m->partitions[PARTITION_ROOT_SECONDARY].found) { m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY]; @@ -489,8 +500,19 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY]; zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]); - } else if (generic_node && !root_hash) { + } else if (flags & DISSECT_IMAGE_REQUIRE_ROOT) { + + /* If the root has was set, then we won't fallback to a generic node, because the root hash + * decides */ + if (root_hash) + return -EADDRNOTAVAIL; + + /* If we didn't find a generic node, then we can't fix this up either */ + if (!generic_node) + return -ENXIO; + /* If we didn't find a properly marked root partition, but we did find a single suitable + * generic Linux partition, then use this as root partition, if the caller asked for it. */ if (multiple_generic) return -ENOTUNIQ; @@ -500,17 +522,15 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte .partno = generic_nr, .architecture = _ARCHITECTURE_INVALID, .node = generic_node, + .uuid = generic_uuid, }; generic_node = NULL; - } else - return -ENXIO; + } } - assert(m->partitions[PARTITION_ROOT].found); - if (root_hash) { - if (!m->partitions[PARTITION_ROOT_VERITY].found) + if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found) return -EADDRNOTAVAIL; /* If we found the primary root with the hash, then we definitely want to suppress any secondary root diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 175ddd8ea0..26319bd8e7 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -32,6 +32,7 @@ struct DissectedPartition { bool rw:1; int partno; /* -1 if there was no partition and the images contains a file system directly */ int architecture; /* Intended architecture: either native, secondary or unset (-1). */ + sd_id128_t uuid; /* Partition entry UUID as reported by the GPT */ char *fstype; char *node; char *decrypted_node; @@ -67,6 +68,8 @@ typedef enum DissectImageFlags { DISSECT_IMAGE_DISCARD_ANY = DISSECT_IMAGE_DISCARD_ON_LOOP | DISSECT_IMAGE_DISCARD | DISSECT_IMAGE_DISCARD_ON_CRYPTO, + DISSECT_IMAGE_GPT_ONLY = 16, /* Only recognize images with GPT partition tables */ + DISSECT_IMAGE_REQUIRE_ROOT = 32, /* Don't accept disks without root partition */ } DissectImageFlags; struct DissectedImage { @@ -76,7 +79,7 @@ struct DissectedImage { DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX]; }; -int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectedImage **ret); +int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret); DissectedImage* dissected_image_unref(DissectedImage *m); DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref); diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index f0bfb30bb5..87b520b540 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -38,7 +38,7 @@ bool fstab_is_mount_point(const char *mount) { _cleanup_endmntent_ FILE *f = NULL; struct mntent *m; - f = setmntent("/etc/fstab", "r"); + f = setmntent("/etc/fstab", "re"); if (!f) return false; diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 712aff65b9..7bc5c0a128 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -99,6 +99,16 @@ static char **image_settings_path(Image *image) { return ret; } +static char *image_roothash_path(Image *image) { + const char *fn; + + assert(image); + + fn = strjoina(image->name, ".roothash"); + + return file_in_same_dir(image->path, fn); +} + static int image_new( ImageType t, const char *pretty, @@ -397,6 +407,7 @@ void image_hashmap_free(Hashmap *map) { int image_remove(Image *i) { _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT; _cleanup_strv_free_ char **settings = NULL; + _cleanup_free_ char *roothash = NULL; char **j; int r; @@ -409,6 +420,10 @@ int image_remove(Image *i) { if (!settings) return -ENOMEM; + roothash = image_roothash_path(i); + if (!roothash) + return -ENOMEM; + /* Make sure we don't interfere with a running nspawn */ r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock); if (r < 0) @@ -445,14 +460,17 @@ int image_remove(Image *i) { log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", *j); } + if (unlink(roothash) < 0 && errno != ENOENT) + log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", roothash); + return 0; } -static int rename_settings_file(const char *path, const char *new_name) { +static int rename_auxiliary_file(const char *path, const char *new_name, const char *suffix) { _cleanup_free_ char *rs = NULL; const char *fn; - fn = strjoina(new_name, ".nspawn"); + fn = strjoina(new_name, suffix); rs = file_in_same_dir(path, fn); if (!rs) @@ -463,7 +481,7 @@ static int rename_settings_file(const char *path, const char *new_name) { int image_rename(Image *i, const char *new_name) { _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT; - _cleanup_free_ char *new_path = NULL, *nn = NULL; + _cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL; _cleanup_strv_free_ char **settings = NULL; unsigned file_attr = 0; char **j; @@ -481,6 +499,10 @@ int image_rename(Image *i, const char *new_name) { if (!settings) return -ENOMEM; + roothash = image_roothash_path(i); + if (!roothash) + return -ENOMEM; + /* Make sure we don't interfere with a running nspawn */ r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock); if (r < 0) @@ -550,19 +572,23 @@ int image_rename(Image *i, const char *new_name) { nn = NULL; STRV_FOREACH(j, settings) { - r = rename_settings_file(*j, new_name); + r = rename_auxiliary_file(*j, new_name, ".nspawn"); if (r < 0 && r != -ENOENT) log_debug_errno(r, "Failed to rename settings file %s, ignoring: %m", *j); } + r = rename_auxiliary_file(roothash, new_name, ".roothash"); + if (r < 0 && r != -ENOENT) + log_debug_errno(r, "Failed to rename roothash file %s, ignoring: %m", roothash); + return 0; } -static int clone_settings_file(const char *path, const char *new_name) { +static int clone_auxiliary_file(const char *path, const char *new_name, const char *suffix) { _cleanup_free_ char *rs = NULL; const char *fn; - fn = strjoina(new_name, ".nspawn"); + fn = strjoina(new_name, suffix); rs = file_in_same_dir(path, fn); if (!rs) @@ -574,6 +600,7 @@ static int clone_settings_file(const char *path, const char *new_name) { int image_clone(Image *i, const char *new_name, bool read_only) { _cleanup_release_lock_file_ LockFile name_lock = LOCK_FILE_INIT; _cleanup_strv_free_ char **settings = NULL; + _cleanup_free_ char *roothash = NULL; const char *new_path; char **j; int r; @@ -587,6 +614,10 @@ int image_clone(Image *i, const char *new_name, bool read_only) { if (!settings) return -ENOMEM; + roothash = image_roothash_path(i); + if (!roothash) + return -ENOMEM; + /* Make sure nobody takes the new name, between the time we * checked it is currently unused in all search paths, and the * time we take possession of it */ @@ -636,11 +667,15 @@ int image_clone(Image *i, const char *new_name, bool read_only) { return r; STRV_FOREACH(j, settings) { - r = clone_settings_file(*j, new_name); + r = clone_auxiliary_file(*j, new_name, ".nspawn"); if (r < 0 && r != -ENOENT) log_debug_errno(r, "Failed to clone settings %s, ignoring: %m", *j); } + r = clone_auxiliary_file(roothash, new_name, ".roothash"); + if (r < 0 && r != -ENOENT) + log_debug_errno(r, "Failed to clone root hash file %s, ignoring: %m", roothash); + return 0; } diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index 4eff4f692e..afdf1ab5ad 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -28,123 +28,102 @@ #include "base-filesystem.h" #include "fd-util.h" +#include "fs-util.h" #include "log.h" #include "missing.h" #include "mkdir.h" +#include "mount-util.h" #include "path-util.h" #include "rm-rf.h" #include "stdio-util.h" #include "string-util.h" +#include "strv.h" #include "switch-root.h" #include "user-util.h" #include "util.h" -int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags) { - - /* Don't try to unmount/move the old "/", there's no way to do it. */ - static const char move_mounts[] = - "/dev\0" - "/proc\0" - "/sys\0" - "/run\0"; +int switch_root(const char *new_root, + const char *old_root_after, /* path below the new root, where to place the old root after the transition */ + bool unmount_old_root, + unsigned long mount_flags) { /* MS_MOVE or MS_BIND */ + _cleanup_free_ char *resolved_old_root_after = NULL; _cleanup_close_ int old_root_fd = -1; - struct stat new_root_stat; bool old_root_remove; - const char *i, *temporary_old_root; + const char *i; + int r; + + assert(new_root); + assert(old_root_after); if (path_equal(new_root, "/")) return 0; - temporary_old_root = strjoina(new_root, oldroot); - mkdir_p_label(temporary_old_root, 0755); - + /* Check if we shall remove the contents of the old root */ old_root_remove = in_initrd(); + if (old_root_remove) { + old_root_fd = open("/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY|O_DIRECTORY); + if (old_root_fd < 0) + return log_error_errno(errno, "Failed to open root directory: %m"); + } - if (stat(new_root, &new_root_stat) < 0) - return log_error_errno(errno, "Failed to stat directory %s: %m", new_root); + /* Determine where we shall place the old root after the transition */ + r = chase_symlinks(old_root_after, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved_old_root_after); + if (r < 0) + return log_error_errno(r, "Failed to resolve %s/%s: %m", new_root, old_root_after); + if (r == 0) /* Doesn't exist yet. Let's create it */ + (void) mkdir_p_label(resolved_old_root_after, 0755); - /* Work-around for kernel design: the kernel refuses switching - * root if any file systems are mounted MS_SHARED. Hence + /* Work-around for kernel design: the kernel refuses MS_MOVE if any file systems are mounted MS_SHARED. Hence * remount them MS_PRIVATE here as a work-around. * * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */ if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0) - log_warning_errno(errno, "Failed to make \"/\" private mount: %m"); - - NULSTR_FOREACH(i, move_mounts) { - char new_mount[PATH_MAX]; - struct stat sb; - size_t n; - - n = snprintf(new_mount, sizeof new_mount, "%s%s", new_root, i); - if (n >= sizeof new_mount) { - bool move = mountflags & MS_MOVE; - - log_warning("New path is too long, %s: %s%s", - move ? "forcing unmount instead" : "ignoring", - new_root, i); - - if (move) - if (umount2(i, MNT_FORCE) < 0) - log_warning_errno(errno, "Failed to unmount %s: %m", i); - continue; - } - - mkdir_p_label(new_mount, 0755); - - if (stat(new_mount, &sb) < 0 || - sb.st_dev != new_root_stat.st_dev) { - - /* Mount point seems to be mounted already or - * stat failed. Unmount the old mount point. */ - if (umount2(i, MNT_DETACH) < 0) - log_warning_errno(errno, "Failed to unmount %s: %m", i); - continue; - } - - if (mount(i, new_mount, NULL, mountflags, NULL) < 0) { - if (mountflags & MS_MOVE) { - log_error_errno(errno, "Failed to move mount %s to %s, forcing unmount: %m", i, new_mount); - - if (umount2(i, MNT_FORCE) < 0) - log_warning_errno(errno, "Failed to unmount %s: %m", i); - - } else if (mountflags & MS_BIND) - log_error_errno(errno, "Failed to bind mount %s to %s: %m", i, new_mount); - } + return log_error_errno(errno, "Failed to set \"/\" mount propagation to private: %m"); + + FOREACH_STRING(i, "/sys", "/dev", "/run", "/proc") { + _cleanup_free_ char *chased = NULL; + + r = chase_symlinks(i, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &chased); + if (r < 0) + return log_error_errno(r, "Failed to resolve %s/%s: %m", new_root, i); + if (r > 0) { + /* Already exists. Let's see if it is a mount point already. */ + r = path_is_mount_point(chased, NULL, 0); + if (r < 0) + return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", chased); + if (r > 0) /* If it is already mounted, then do nothing */ + continue; + } else + /* Doesn't exist yet? */ + (void) mkdir_p_label(chased, 0755); + + if (mount(i, chased, NULL, mount_flags, NULL) < 0) + return log_error_errno(r, "Failed to mount %s to %s: %m", i, chased); } - /* Do not fail, if base_filesystem_create() fails. Not all - * switch roots are like base_filesystem_create() wants them - * to look like. They might even boot, if they are RO and - * don't have the FS layout. Just ignore the error and - * switch_root() nevertheless. */ + /* Do not fail if base_filesystem_create() fails. Not all switch roots are like base_filesystem_create() wants + * them to look like. They might even boot, if they are RO and don't have the FS layout. Just ignore the error + * and switch_root() nevertheless. */ (void) base_filesystem_create(new_root, UID_INVALID, GID_INVALID); if (chdir(new_root) < 0) return log_error_errno(errno, "Failed to change directory to %s: %m", new_root); - if (old_root_remove) { - old_root_fd = open("/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY|O_DIRECTORY); - if (old_root_fd < 0) - log_warning_errno(errno, "Failed to open root directory: %m"); - } - - /* We first try a pivot_root() so that we can umount the old - * root dir. In many cases (i.e. where rootfs is /), that's - * not possible however, and hence we simply overmount root */ - if (pivot_root(new_root, temporary_old_root) >= 0) { + /* We first try a pivot_root() so that we can umount the old root dir. In many cases (i.e. where rootfs is /), + * that's not possible however, and hence we simply overmount root */ + if (pivot_root(new_root, resolved_old_root_after) >= 0) { /* Immediately get rid of the old root, if detach_oldroot is set. * Since we are running off it we need to do this lazily. */ - if (detach_oldroot && umount2(oldroot, MNT_DETACH) < 0) - log_error_errno(errno, "Failed to lazily umount old root dir %s, %s: %m", - oldroot, - errno == ENOENT ? "ignoring" : "leaving it around"); + if (unmount_old_root) { + r = umount_recursive(old_root_after, MNT_DETACH); + if (r < 0) + log_warning_errno(r, "Failed to unmount old root directory tree, ignoring: %m"); + } } else if (mount(new_root, "/", NULL, MS_MOVE, NULL) < 0) - return log_error_errno(errno, "Failed to mount moving %s to /: %m", new_root); + return log_error_errno(errno, "Failed to move %s to /: %m", new_root); if (chroot(".") < 0) return log_error_errno(errno, "Failed to change root: %m"); diff --git a/src/shared/volatile-util.c b/src/shared/volatile-util.c new file mode 100644 index 0000000000..e7e9721411 --- /dev/null +++ b/src/shared/volatile-util.c @@ -0,0 +1,68 @@ +/*** + This file is part of systemd. + + Copyright 2015 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "macro.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "string-util.h" +#include "volatile-util.h" + +VolatileMode volatile_mode_from_string(const char *s) { + int b; + + if (isempty(s)) + return _VOLATILE_MODE_INVALID; + + b = parse_boolean(s); + if (b > 0) + return VOLATILE_YES; + if (b == 0) + return VOLATILE_NO; + + if (streq(s, "state")) + return VOLATILE_STATE; + + return _VOLATILE_MODE_INVALID; +} + +int query_volatile_mode(VolatileMode *ret) { + _cleanup_free_ char *mode = NULL; + VolatileMode m = VOLATILE_NO; + int r; + + r = proc_cmdline_get_key("systemd.volatile", PROC_CMDLINE_VALUE_OPTIONAL, &mode); + if (r < 0) + return r; + if (r == 0) + goto finish; + + if (mode) { + m = volatile_mode_from_string(mode); + if (m < 0) + return -EINVAL; + } else + m = VOLATILE_YES; + + r = 1; + +finish: + *ret = m; + return r; +} diff --git a/src/shared/volatile-util.h b/src/shared/volatile-util.h new file mode 100644 index 0000000000..17930ba6ae --- /dev/null +++ b/src/shared/volatile-util.h @@ -0,0 +1,32 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +typedef enum VolatileMode { + VOLATILE_NO, + VOLATILE_YES, + VOLATILE_STATE, + _VOLATILE_MODE_MAX, + _VOLATILE_MODE_INVALID = -1 +} VolatileMode; + +VolatileMode volatile_mode_from_string(const char *s); + +int query_volatile_mode(VolatileMode *ret); |