diff options
author | Daan De Meyer <daan.j.demeyer@gmail.com> | 2022-10-11 10:50:58 +0200 |
---|---|---|
committer | Daan De Meyer <daan.j.demeyer@gmail.com> | 2022-11-15 20:07:54 +0100 |
commit | bf3598befff0137592834465ef728fdaabf1e778 (patch) | |
tree | ab0bb5ac836eeaf651f02fc2c9fe17c3a585fc76 /src/shared/mkfs-util.c | |
parent | 68665704dc9bb706d2b993808839d59dbabd7a9d (diff) | |
download | systemd-bf3598befff0137592834465ef728fdaabf1e778.tar.gz |
mkfs-util: Add support to populate vfat without mounting using mcopy
mkfs.vfat doesn't support specifying a root directory to bootstrap
the filesystem from (see https://github.com/dosfstools/dosfstools/issues/183).
Instead, we can use the mcopy tool from the mtools package to copy
files into the vfat filesystem after creating it without needing to
mount the vfat filesystem.
Diffstat (limited to 'src/shared/mkfs-util.c')
-rw-r--r-- | src/shared/mkfs-util.c | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/src/shared/mkfs-util.c b/src/shared/mkfs-util.c index f7f4a35212..2adb2a25c7 100644 --- a/src/shared/mkfs-util.c +++ b/src/shared/mkfs-util.c @@ -2,11 +2,14 @@ #include <unistd.h> +#include "dirent-util.h" +#include "fd-util.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" @@ -34,7 +37,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) { @@ -91,6 +94,59 @@ static int mangle_fat_label(const char *s, char **ret) { return 0; } +static int do_mcopy(const char *node, const char *root) { + _cleanup_strv_free_ char **argv = NULL; + _cleanup_closedir_ DIR *rootdir = NULL; + 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(); + + 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) { + /* Avoid failures caused by mismatch in expectations between mkfs.vfat and mcopy by disabling + * the stricter mcopy checks using MTOOLS_SKIP_CHECK. */ + execvpe("mcopy", argv, STRV_MAKE("MTOOLS_SKIP_CHECK=1")); + + log_error_errno(errno, "Failed to execute mcopy: %m"); + + _exit(EXIT_FAILURE); + } + + return 0; +} + int make_filesystem( const char *node, const char *fstype, @@ -304,6 +360,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); |