Merge pull request #24753 from DaanDeMeyer/repart-squashfs

repart: Add squashfs support
This commit is contained in:
Lennart Poettering
2022-09-21 19:49:10 +02:00
committed by GitHub
7 changed files with 119 additions and 27 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

@@ -2333,7 +2333,7 @@ int home_create_luks(
log_info("Setting up LUKS device %s completed.", setup->dm_node);
r = make_filesystem(setup->dm_node, fstype, user_record_user_name_and_realm(h), fs_uuid, user_record_luks_discard(h));
r = make_filesystem(setup->dm_node, fstype, user_record_user_name_and_realm(h), NULL, fs_uuid, user_record_luks_discard(h));
if (r < 0)
return r;

View File

@@ -65,7 +65,7 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to generate UUID for file system: %m");
return make_filesystem(device, fstype, basename(device), uuid, true);
return make_filesystem(device, fstype, basename(device), NULL, uuid, true);
}
DEFINE_MAIN_FUNCTION(run);

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"
@@ -3168,11 +3170,11 @@ static int context_copy_blocks(Context *context) {
return 0;
}
static int do_copy_files(Partition *p, const char *fs) {
static int do_copy_files(Partition *p, const char *root) {
int r;
assert(p);
assert(fs);
assert(root);
STRV_FOREACH_PAIR(source, target, p->copy_files) {
_cleanup_close_ int sfd = -1, pfd = -1, tfd = -1;
@@ -3187,7 +3189,7 @@ static int do_copy_files(Partition *p, const char *fs) {
return log_error_errno(r, "Failed to check type of source file '%s': %m", *source);
/* We are looking at a directory */
tfd = chase_symlinks_and_open(*target, fs, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
tfd = chase_symlinks_and_open(*target, root, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
if (tfd < 0) {
_cleanup_free_ char *dn = NULL, *fn = NULL;
@@ -3202,11 +3204,11 @@ static int do_copy_files(Partition *p, const char *fs) {
if (r < 0)
return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);
r = mkdir_p_root(fs, dn, UID_INVALID, GID_INVALID, 0755);
r = mkdir_p_root(root, dn, UID_INVALID, GID_INVALID, 0755);
if (r < 0)
return log_error_errno(r, "Failed to create parent directory '%s': %m", dn);
pfd = chase_symlinks_and_open(dn, fs, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
pfd = chase_symlinks_and_open(dn, root, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
if (pfd < 0)
return log_error_errno(pfd, "Failed to open parent directory of target: %m");
@@ -3239,11 +3241,11 @@ static int do_copy_files(Partition *p, const char *fs) {
if (r < 0)
return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);
r = mkdir_p_root(fs, dn, UID_INVALID, GID_INVALID, 0755);
r = mkdir_p_root(root, dn, UID_INVALID, GID_INVALID, 0755);
if (r < 0)
return log_error_errno(r, "Failed to create parent directory: %m");
pfd = chase_symlinks_and_open(dn, fs, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
pfd = chase_symlinks_and_open(dn, root, CHASE_PREFIX_ROOT|CHASE_WARN, O_RDONLY|O_DIRECTORY|O_CLOEXEC, NULL);
if (pfd < 0)
return log_error_errno(pfd, "Failed to open parent directory of target: %m");
@@ -3264,15 +3266,15 @@ static int do_copy_files(Partition *p, const char *fs) {
return 0;
}
static int do_make_directories(Partition *p, const char *fs) {
static int do_make_directories(Partition *p, const char *root) {
int r;
assert(p);
assert(fs);
assert(root);
STRV_FOREACH(d, p->make_directories) {
r = mkdir_p_root(fs, *d, UID_INVALID, GID_INVALID, 0755);
r = mkdir_p_root(root, *d, UID_INVALID, GID_INVALID, 0755);
if (r < 0)
return log_error_errno(r, "Failed to create directory '%s' in file system: %m", *d);
}
@@ -3280,12 +3282,67 @@ static int do_make_directories(Partition *p, const char *fs) {
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), 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);

View File

@@ -90,6 +90,7 @@ int make_filesystem(
const char *node,
const char *fstype,
const char *label,
const char *root,
sd_id128_t uuid,
bool discard) {
@@ -102,12 +103,28 @@ int make_filesystem(
assert(label);
if (streq(fstype, "swap")) {
if (root)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"A swap filesystem can't be populated, refusing");
r = find_executable("mkswap", &mkfs);
if (r == -ENOENT)
return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "mkswap binary not available.");
if (r < 0)
return log_error_errno(r, "Failed to determine whether mkswap binary exists: %m");
} else if (streq(fstype, "squashfs")) {
if (!root)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot generate squashfs filesystems without a source tree.");
r = find_executable("mksquashfs", &mkfs);
if (r == -ENOENT)
return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "mksquashfs binary not available.");
if (r < 0)
return log_error_errno(r, "Failed to determine whether mksquashfs binary exists: %m");
} else {
if (root)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Populating with source tree is only supported for squashfs");
r = mkfs_exists(fstype);
if (r < 0)
return log_error_errno(r, "Failed to determine whether mkfs binary for %s exists: %m", fstype);
@@ -225,6 +242,13 @@ int make_filesystem(
"-U", vol_id,
node, NULL);
else if (streq(fstype, "squashfs"))
(void) execlp(mkfs, mkfs,
root, node,
"-quiet",
"-noappend",
NULL);
else
/* Generic fallback for all other file systems */
(void) execlp(mkfs, mkfs, node, NULL);

View File

@@ -7,4 +7,4 @@
int mkfs_exists(const char *fstype);
int make_filesystem(const char *node, const char *fstype, const char *label, sd_id128_t uuid, bool discard);
int make_filesystem(const char *node, const char *fstype, const char *label, const char *root, sd_id128_t uuid, bool discard);

View File

@@ -234,16 +234,16 @@ static int run(int argc, char *argv[]) {
assert_se(dissected->partitions[PARTITION_HOME].node);
assert_se(sd_id128_randomize(&id) >= 0);
assert_se(make_filesystem(dissected->partitions[PARTITION_ESP].node, "vfat", "EFI", id, true) >= 0);
assert_se(make_filesystem(dissected->partitions[PARTITION_ESP].node, "vfat", "EFI", NULL, id, true) >= 0);
assert_se(sd_id128_randomize(&id) >= 0);
assert_se(make_filesystem(dissected->partitions[PARTITION_XBOOTLDR].node, "vfat", "xbootldr", id, true) >= 0);
assert_se(make_filesystem(dissected->partitions[PARTITION_XBOOTLDR].node, "vfat", "xbootldr", NULL, id, true) >= 0);
assert_se(sd_id128_randomize(&id) >= 0);
assert_se(make_filesystem(dissected->partitions[PARTITION_ROOT].node, "ext4", "root", id, true) >= 0);
assert_se(make_filesystem(dissected->partitions[PARTITION_ROOT].node, "ext4", "root", NULL, id, true) >= 0);
assert_se(sd_id128_randomize(&id) >= 0);
assert_se(make_filesystem(dissected->partitions[PARTITION_HOME].node, "ext4", "home", id, true) >= 0);
assert_se(make_filesystem(dissected->partitions[PARTITION_HOME].node, "ext4", "home", NULL, id, true) >= 0);
dissected = dissected_image_unref(dissected);
assert_se(dissect_loop_device(loop, NULL, NULL, 0, &dissected) >= 0);