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.
This commit is contained in:
Daan De Meyer
2022-09-21 14:16:13 +02:00
parent 7f55ad775d
commit 95bfd3cd50
2 changed files with 78 additions and 10 deletions
+72 -4
View File
@@ -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);