Skip to content

Commit

Permalink
mkfs-util: Add support to populate vfat without mounting using mcopy
Browse files Browse the repository at this point in the history
mkfs.vfat doesn't support specifying a root directory to bootstrap
the filesystem from (see dosfstools/dosfstools#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.
  • Loading branch information
DaanDeMeyer committed Nov 11, 2022
1 parent 116ed54 commit 700b05c
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 1 deletion.
2 changes: 2 additions & 0 deletions mkosi.conf.d/10-systemd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Packages=
coreutils
diffutils
dnsmasq
dosfstools
e2fsprogs
findutils
gcc # For sanitizer libraries
Expand All @@ -30,6 +31,7 @@ Packages=
kexec-tools
kmod
less
mtools
nano
nftables
openssl
Expand Down
70 changes: 69 additions & 1 deletion src/shared/mkfs-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

#include <unistd.h>

#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"
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions test/TEST-58-REPART/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 700b05c

Please sign in to comment.