diff --git a/mkosi.conf.d/10-systemd.conf b/mkosi.conf.d/10-systemd.conf index 0915e713570ea..f9e4d086160ed 100644 --- a/mkosi.conf.d/10-systemd.conf +++ b/mkosi.conf.d/10-systemd.conf @@ -21,6 +21,7 @@ Packages= coreutils diffutils dnsmasq + dosfstools e2fsprogs findutils gcc # For sanitizer libraries @@ -30,6 +31,7 @@ Packages= kexec-tools kmod less + mtools nano nftables openssl diff --git a/src/shared/mkfs-util.c b/src/shared/mkfs-util.c index 8fb270083a751..21e87b6dc2de7 100644 --- a/src/shared/mkfs-util.c +++ b/src/shared/mkfs-util.c @@ -2,12 +2,15 @@ #include +#include "dirent-util.h" +#include "fd-util.h" #include "fileio.h" #include "id128-util.h" #include "mkfs-util.h" #include "mountpoint-util.h" #include "path-util.h" #include "process-util.h" +#include "stat-util.h" #include "stdio-util.h" #include "string-util.h" #include "utf8.h" @@ -35,7 +38,7 @@ int mkfs_exists(const char *fstype) { } int mkfs_supports_root_option(const char *fstype) { - return fstype_is_ro(fstype) || STR_IN_SET(fstype, "ext2", "ext3", "ext4", "btrfs"); + return fstype_is_ro(fstype) || STR_IN_SET(fstype, "ext2", "ext3", "ext4", "btrfs", "vfat"); } static int mangle_linux_fs_label(const char *s, size_t max_len, char **ret) { @@ -121,6 +124,65 @@ static int setup_userns(uid_t uid, gid_t gid) { return 0; } +static int do_mcopy(const char *node, const char *root) { + _cleanup_strv_free_ char **argv = NULL; + _cleanup_closedir_ DIR *rootdir = NULL; + struct stat st; + int r; + + assert(node); + assert(root); + + /* Return early if there's nothing to copy. */ + if (dir_is_empty(root, /*ignore_hidden_or_backup=*/ false)) + return 0; + + argv = strv_new("mcopy", "-b", "-s", "-p", "-Q", "-n", "-m", "-i", node); + if (!argv) + return log_oom(); + + /* mcopy copies the top level directory instead of everything in it so we have to pass all + * the subdirectories to mcopy instead to end up with the correct directory structure. */ + + rootdir = opendir(root); + if (!rootdir) + return log_error_errno(errno, "Failed to open directory '%s'", root); + + FOREACH_DIRENT(de, rootdir, return -errno) { + char *p = path_join(root, de->d_name); + if (!p) + return log_oom(); + + r = strv_consume(&argv, TAKE_PTR(p)); + if (r < 0) + return log_oom(); + } + + r = strv_extend(&argv, "::"); + if (r < 0) + return log_oom(); + + if (stat(root, &st) < 0) + return log_error_errno(errno, "Failed to stat %s: %m", root); + + r = safe_fork("(mcopy)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR|FORK_NEW_USERNS, NULL); + if (r < 0) + return r; + if (r == 0) { + r = setup_userns(st.st_uid, st.st_gid); + if (r < 0) + _exit(EXIT_FAILURE); + + execvp("mcopy", argv); + + log_error_errno(errno, "Failed to execute mcopy: %m"); + + _exit(EXIT_FAILURE); + } + + return 0; +} + int make_filesystem( const char *node, const char *fstype, @@ -344,6 +406,12 @@ int make_filesystem( _exit(EXIT_FAILURE); } + if (root && streq(fstype, "vfat")) { + r = do_mcopy(node, root); + if (r < 0) + return r; + } + if (STR_IN_SET(fstype, "ext2", "ext3", "ext4", "btrfs", "f2fs", "xfs", "vfat", "swap")) log_info("%s successfully formatted as %s (label \"%s\", uuid %s)", node, fstype, label, vol_id); diff --git a/test/TEST-58-REPART/test.sh b/test/TEST-58-REPART/test.sh index 31c5e67e6a048..1aacfc3c6b5c4 100755 --- a/test/TEST-58-REPART/test.sh +++ b/test/TEST-58-REPART/test.sh @@ -13,6 +13,7 @@ test_append_files() { if command -v openssl >/dev/null 2>&1; then inst_binary openssl fi + inst_binary mcopy instmods dm_verity =md generate_module_dependencies fi