From: Lennart Poettering Date: Tue, 28 Jul 2020 16:16:19 +0000 (+0200) Subject: firstboot: move --image= logic into common code X-Git-Tag: v247-rc1~441^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6aa05ebdd8eb97a852b475de2f80c5707efef64e;p=thirdparty%2Fsystemd.git firstboot: move --image= logic into common code That way we can reuse it in tmpfiles/sysusers/journalctl and so on. --- diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 78abcbeff6c..d56de0bb259 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -19,7 +19,6 @@ #include "kbd-util.h" #include "libcrypt-util.h" #include "locale-util.h" -#include "loop-util.h" #include "main-func.h" #include "memory-util.h" #include "mkdir.h" @@ -907,75 +906,6 @@ static int process_kernel_cmdline(void) { return 0; } -static int setup_image(char **ret_mount_dir, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image) { - DissectImageFlags f = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK; - _cleanup_(loop_device_unrefp) LoopDevice *d = NULL; - _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL; - _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL; - _cleanup_(rmdir_and_freep) char *mount_dir = NULL; - _cleanup_free_ char *temp = NULL; - int r; - - if (!arg_image) { - *ret_mount_dir = NULL; - *ret_decrypted_image = NULL; - *ret_loop_device = NULL; - return 0; - } - - assert(!arg_root); - - r = tempfn_random_child(NULL, "firstboot", &temp); - if (r < 0) - return log_error_errno(r, "Failed to generate temporary mount directory: %m"); - - r = loop_device_make_by_path(arg_image, O_RDWR, LO_FLAGS_PARTSCAN, &d); - if (r < 0) - return log_error_errno(r, "Failed to set up loopback device: %m"); - - r = dissect_image_and_warn(d->fd, arg_image, NULL, 0, NULL, NULL, f, &dissected_image); - if (r < 0) - return r; - - r = dissected_image_decrypt_interactively(dissected_image, NULL, NULL, 0, NULL, NULL, NULL, 0, f, &decrypted_image); - if (r < 0) - return r; - - r = detach_mount_namespace(); - if (r < 0) - return log_error_errno(r, "Failed to detach mount namespace: %m"); - - mount_dir = strdup(temp); - if (!mount_dir) - return log_oom(); - - r = mkdir_p(mount_dir, 0700); - if (r < 0) { - mount_dir = mfree(mount_dir); - return log_error_errno(r, "Failed to create mount point: %m"); - } - - r = dissected_image_mount(dissected_image, mount_dir, UID_INVALID, f); - if (r < 0) - return log_error_errno(r, "Failed to mount image: %m"); - - if (decrypted_image) { - r = decrypted_image_relinquish(decrypted_image); - if (r < 0) - return log_error_errno(r, "Failed to relinquish DM devices: %m"); - } - - loop_device_relinquish(d); - - arg_root = TAKE_PTR(temp); - - *ret_mount_dir = TAKE_PTR(mount_dir); - *ret_decrypted_image = TAKE_PTR(decrypted_image); - *ret_loop_device = TAKE_PTR(d); - - return 1; -} - static int help(void) { _cleanup_free_ char *link = NULL; int r; @@ -1353,9 +1283,22 @@ static int run(int argc, char *argv[]) { return 0; /* disabled */ } - r = setup_image(&unlink_dir, &loop_device, &decrypted_image); - if (r < 0) - return r; + if (arg_image) { + assert(!arg_root); + + r = mount_image_privately_interactively( + arg_image, + DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK, + &unlink_dir, + &loop_device, + &decrypted_image); + if (r < 0) + return r; + + arg_root = strdup(unlink_dir); + if (!arg_root) + return log_oom(); + } r = process_locale(); if (r < 0) diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index e96658ca669..c98c84993e2 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -33,8 +33,10 @@ #include "hexdecoct.h" #include "hostname-util.h" #include "id128-util.h" +#include "mkdir.h" #include "mount-util.h" #include "mountpoint-util.h" +#include "namespace-util.h" #include "nulstr-util.h" #include "os-util.h" #include "path-util.h" @@ -1940,9 +1942,84 @@ const char* mount_options_from_part(const MountOptions *options, unsigned int pa LIST_FOREACH(mount_options, m, (MountOptions *)options) if (partition_number == m->partition_number && !isempty(m->options)) return m->options; + return NULL; } +int mount_image_privately_interactively( + const char *image, + DissectImageFlags flags, + char **ret_directory, + LoopDevice **ret_loop_device, + DecryptedImage **ret_decrypted_image) { + + _cleanup_(loop_device_unrefp) LoopDevice *d = NULL; + _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL; + _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL; + _cleanup_(rmdir_and_freep) char *created_dir = NULL; + _cleanup_free_ char *temp = NULL; + int r; + + /* Mounts an OS image at a temporary place, inside a newly created mount namespace of our own. This + * is used by tools such as systemd-tmpfiles or systemd-firstboot to operate on some disk image + * easily. */ + + assert(image); + assert(ret_directory); + assert(ret_loop_device); + assert(ret_decrypted_image); + + r = tempfn_random_child(NULL, program_invocation_short_name, &temp); + if (r < 0) + return log_error_errno(r, "Failed to generate temporary mount directory: %m"); + + r = loop_device_make_by_path( + image, + FLAGS_SET(flags, DISSECT_IMAGE_READ_ONLY) ? O_RDONLY : O_RDWR, + FLAGS_SET(flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN, + &d); + if (r < 0) + return log_error_errno(r, "Failed to set up loopback device: %m"); + + r = dissect_image_and_warn(d->fd, image, NULL, 0, NULL, NULL, flags, &dissected_image); + if (r < 0) + return r; + + r = dissected_image_decrypt_interactively(dissected_image, NULL, NULL, 0, NULL, NULL, NULL, 0, flags, &decrypted_image); + if (r < 0) + return r; + + r = detach_mount_namespace(); + if (r < 0) + return log_error_errno(r, "Failed to detach mount namespace: %m"); + + r = mkdir_p(temp, 0700); + if (r < 0) + return log_error_errno(r, "Failed to create mount point: %m"); + + created_dir = TAKE_PTR(temp); + + r = dissected_image_mount(dissected_image, created_dir, UID_INVALID, flags); + if (r == -EUCLEAN) + return log_error_errno(r, "File system check on image failed: %m"); + if (r < 0) + return log_error_errno(r, "Failed to mount image: %m"); + + if (decrypted_image) { + r = decrypted_image_relinquish(decrypted_image); + if (r < 0) + return log_error_errno(r, "Failed to relinquish DM devices: %m"); + } + + loop_device_relinquish(d); + + *ret_directory = TAKE_PTR(created_dir); + *ret_loop_device = TAKE_PTR(d); + *ret_decrypted_image = TAKE_PTR(decrypted_image); + + return 0; +} + static const char *const partition_designator_table[] = { [PARTITION_ROOT] = "root", [PARTITION_ROOT_SECONDARY] = "root-secondary", diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 52aa377a671..7f67c8745e8 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -6,6 +6,7 @@ #include "sd-id128.h" #include "list.h" +#include "loop-util.h" #include "macro.h" typedef struct DissectedImage DissectedImage; @@ -117,3 +118,5 @@ int partition_designator_from_string(const char *name) _pure_; int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data, char **ret_roothashsig); bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator); bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator); + +int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);