mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #24753 from DaanDeMeyer/repart-squashfs
repart: Add squashfs support
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user