1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-12 13:18:14 +03:00

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-19 20:26:15 +02:00
parent 7f55ad775d
commit 95bfd3cd50
2 changed files with 78 additions and 10 deletions

View File

@ -484,12 +484,12 @@
<term><varname>Format=</varname></term>
<listitem><para>Takes a file system name, such as <literal>ext4</literal>, <literal>btrfs</literal>,
<literal>xfs</literal> or <literal>vfat</literal>, or the special value <literal>swap</literal>. 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).</para>
<literal>xfs</literal>, <literal>vfat</literal>, <literal>squashfs</literal>, or the special value
<literal>swap</literal>. 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).</para>
<para>This option has no effect if the partition already exists.</para>

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);