From 95bfd3cd50dacb7eb6557786daa5d1f90bd78d10 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 19 Sep 2022 20:26:15 +0200 Subject: [PATCH] repart: Add squashfs support To make this work, we have to set up everything in a temporary directory tree that we can pass to mksquashfs as a single directory. To make the most common scenario more efficient, we skip the temporary setup directory if we only get a single source tree destined to root in the squashfs filesystem. --- man/repart.d.xml | 12 +++---- src/partition/repart.c | 76 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/man/repart.d.xml b/man/repart.d.xml index bdbf054fcf6..df5338c92af 100644 --- a/man/repart.d.xml +++ b/man/repart.d.xml @@ -484,12 +484,12 @@ Format= Takes a file system name, such as ext4, btrfs, - xfs or vfat, or the special value swap. If - specified and the partition is newly created it is formatted with the specified file system (or as - swap device). The file system UUID and label are automatically derived from the partition UUID and - label. If this option is used, the size allocation algorithm is slightly altered: the partition is - created as least as big as required for the minimal file system of the specified type (or 4KiB if the - minimal size is not known). + xfs, vfat, squashfs, or the special value + swap. If specified and the partition is newly created it is formatted with the + specified file system (or as swap device). The file system UUID and label are automatically derived + from the partition UUID and label. If this option is used, the size allocation algorithm is slightly + altered: the partition is created as least as big as required for the minimal file system of the + specified type (or 4KiB if the minimal size is not known). This option has no effect if the partition already exists. diff --git a/src/partition/repart.c b/src/partition/repart.c index db37a3ee3a6..c35183861f7 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -55,6 +55,7 @@ #include "process-util.h" #include "random-util.h" #include "resize-fs.h" +#include "rm-rf.h" #include "sort-util.h" #include "specifier.h" #include "stdio-util.h" @@ -62,6 +63,7 @@ #include "string-util.h" #include "strv.h" #include "sync-util.h" +#include "tmpfile-util.h" #include "terminal-util.h" #include "tpm-pcr.h" #include "tpm2-util.h" @@ -3280,12 +3282,67 @@ static int do_make_directories(Partition *p, const char *root) { return 0; } -static int partition_populate(Partition *p, const char *node) { +static int partition_populate_directory(Partition *p, char **ret_root, char **ret_tmp_root) { + _cleanup_(rm_rf_physical_and_freep) char *root = NULL; + int r; + + assert(ret_root); + assert(ret_tmp_root); + + /* When generating squashfs, we need the source tree to be available when we generate the squashfs + * filesystem. Because we might have multiple source trees, we build a temporary source tree + * beforehand where we merge all our inputs. We then use this merged source tree to create the + * squashfs filesystem. */ + + if (!streq(p->format, "squashfs")) { + *ret_root = NULL; + *ret_tmp_root = NULL; + return 0; + } + + /* If we only have a single directory that's meant to become the root directory of the filesystem, + * we can shortcut this function and just use that directory as the root directory instead. If we + * allocate a temporary directory, it's stored in "ret_tmp_root" to indicate it should be removed. + * Otherwise, we return the directory to use in "root" to indicate it should not be removed. */ + + if (strv_length(p->copy_files) == 2 && strv_length(p->make_directories) == 0 && streq(p->copy_files[1], "/")) { + _cleanup_free_ char *s = NULL; + + s = strdup(p->copy_files[0]); + if (!s) + return log_oom(); + + *ret_root = TAKE_PTR(s); + *ret_tmp_root = NULL; + return 0; + } + + r = mkdtemp_malloc("/var/tmp/repart-XXXXXX", &root); + if (r < 0) + return log_error_errno(r, "Failed to create temporary directory: %m"); + + r = do_copy_files(p, root); + if (r < 0) + return r; + + r = do_make_directories(p, root); + if (r < 0) + return r; + + *ret_root = NULL; + *ret_tmp_root = TAKE_PTR(root); + return 0; +} + +static int partition_populate_filesystem(Partition *p, const char *node) { int r; assert(p); assert(node); + if (streq(p->format, "squashfs")) + return 0; + if (strv_isempty(p->copy_files) && strv_isempty(p->make_directories)) return 0; @@ -3340,7 +3397,8 @@ static int context_mkfs(Context *context) { LIST_FOREACH(partitions, p, context->partitions) { _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL; _cleanup_(loop_device_unrefp) LoopDevice *d = NULL; - _cleanup_free_ char *encrypted = NULL; + _cleanup_(rm_rf_physical_and_freep) char *tmp_root = NULL; + _cleanup_free_ char *encrypted = NULL, *root = NULL; _cleanup_close_ int encrypted_dev_fd = -1; const char *fsdev; sd_id128_t fs_uuid; @@ -3387,7 +3445,16 @@ static int context_mkfs(Context *context) { if (r < 0) return r; - r = make_filesystem(fsdev, p->format, strempty(p->new_label), NULL, fs_uuid, arg_discard); + /* Ideally, we populate filesystems using our own code after creating the filesystem to + * ensure consistent handling of chattrs, xattrs and other similar things. However, when + * using squashfs, we can't populate after creating the filesystem because it's read-only, so + * instead we create a temporary root to use as the source tree when generating the squashfs + * filesystem. */ + r = partition_populate_directory(p, &root, &tmp_root); + if (r < 0) + return r; + + r = make_filesystem(fsdev, p->format, strempty(p->new_label), root ?: tmp_root, fs_uuid, arg_discard); if (r < 0) { encrypted_dev_fd = safe_close(encrypted_dev_fd); (void) deactivate_luks(cd, encrypted); @@ -3401,7 +3468,8 @@ static int context_mkfs(Context *context) { if (flock(encrypted_dev_fd, LOCK_UN) < 0) return log_error_errno(errno, "Failed to unlock LUKS device: %m"); - r = partition_populate(p, fsdev); + /* Now, we can populate all the other filesystems that aren't squashfs. */ + r = partition_populate_filesystem(p, fsdev); if (r < 0) { encrypted_dev_fd = safe_close(encrypted_dev_fd); (void) deactivate_luks(cd, encrypted); -- 2.47.3