From da495a0385b4df0ed627153950edbc7f4c9faf57 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 21 Nov 2017 23:18:05 +0100 Subject: [PATCH] Add x-systemd.makefs option for fstab I opted to completely generate a unit for both mount points and swaps. For swaps, it would be possible to use fixed template unit like systemd-mkswap@.service, because there's no information passed except the device name. For mount points, that's not possible because both the device name and file system type need to be passed. Nevertheless, I expect that options will need to passed to both mkfs and mkswap, in which case it'll be necessary to create units of both types anyway. --- meson.build | 1 + src/fstab-generator/fstab-generator.c | 32 +++++-- src/shared/generator.c | 156 +++++++++++++++++++++++++++++++++- src/shared/generator.h | 17 +++- 4 files changed, 190 insertions(+), 16 deletions(-) diff --git a/meson.build b/meson.build index abb152a..b9015c8 100644 --- a/meson.build +++ b/meson.build @@ -182,6 +182,7 @@ conf.set_quoted('CATALOG_DATABASE', join_paths(catalog conf.set_quoted('SYSTEMD_CGROUP_AGENT_PATH', join_paths(rootlibexecdir, 'systemd-cgroups-agent')) conf.set_quoted('SYSTEMD_BINARY_PATH', join_paths(rootlibexecdir, 'systemd')) conf.set_quoted('SYSTEMD_FSCK_PATH', join_paths(rootlibexecdir, 'systemd-fsck')) +conf.set_quoted('SYSTEMD_MAKEFS_PATH', join_paths(rootlibexecdir, 'systemd-makefs')) conf.set_quoted('SYSTEMD_SHUTDOWN_BINARY_PATH', join_paths(rootlibexecdir, 'systemd-shutdown')) conf.set_quoted('SYSTEMD_SLEEP_BINARY_PATH', join_paths(rootlibexecdir, 'systemd-sleep')) conf.set_quoted('SYSTEMCTL_BINARY_PATH', join_paths(rootbindir, 'systemctl')) diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 913992e..5bdeae0 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -51,6 +51,7 @@ typedef enum MountpointFlags { NOAUTO = 1 << 0, NOFAIL = 1 << 1, AUTOMOUNT = 1 << 2, + MAKEFS = 1 << 3, } MountpointFlags; static const char *arg_dest = "/tmp"; @@ -155,6 +156,12 @@ static int add_swap( if (r < 0) return r; + if (flags & MAKEFS) { + r = generator_hook_up_mkswap(arg_dest, what); + if (r < 0) + return r; + } + if (!(flags & NOAUTO)) { r = generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET, (flags & NOFAIL) ? "wants" : "requires", name); @@ -307,10 +314,11 @@ static int add_mount( const char *source) { _cleanup_free_ char - *name = NULL, *unit = NULL, + *name = NULL, *automount_name = NULL, *automount_unit = NULL, *filtered = NULL, *where_escaped = NULL; + const char *unit; _cleanup_fclose_ FILE *f = NULL; int r; @@ -347,9 +355,7 @@ static int add_mount( if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); - unit = strjoin(dest, "/", name); - if (!unit) - return log_oom(); + unit = strjoina(dest, "/", name); f = fopen(unit, "wxe"); if (!f) @@ -447,6 +453,12 @@ static int add_mount( if (r < 0) return log_error_errno(r, "Failed to write unit file %s: %m", unit); + if (flags & MAKEFS) { + r = generator_hook_up_mkfs(dest, what, where, fstype); + if (r < 0) + return r; + } + if (!(flags & NOAUTO) && !(flags & AUTOMOUNT)) { r = generator_add_symlink(dest, post, (flags & NOFAIL) ? "wants" : "requires", name); @@ -532,7 +544,7 @@ static int parse_fstab(bool initrd) { while ((me = getmntent(f))) { _cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL; - bool noauto, nofail; + bool makefs, noauto, nofail; int k; if (initrd && !mount_in_initrd(me)) @@ -574,15 +586,17 @@ static int parse_fstab(bool initrd) { } } + makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0"); noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0"); nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0"); - log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s", + log_debug("Found entry what=%s where=%s type=%s makefs=%s nofail=%s noauto=%s", what, where, me->mnt_type, + yes_no(makefs), yes_no(noauto), yes_no(nofail)); if (streq(me->mnt_type, "swap")) k = add_swap(what, me, - noauto*NOAUTO | nofail*NOFAIL); + makefs*MAKEFS | noauto*NOAUTO | nofail*NOFAIL); else { bool automount; const char *post; @@ -604,7 +618,7 @@ static int parse_fstab(bool initrd) { me->mnt_type, me->mnt_opts, me->mnt_passno, - noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT, + makefs*MAKEFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT, post, fstab_path); } @@ -665,7 +679,7 @@ static int add_sysroot_mount(void) { arg_root_fstype, opts, is_device_path(what) ? 1 : 0, /* passno */ - 0, /* noauto off, nofail off, automount off */ + 0, /* makefs off, noauto off, nofail off, automount off */ SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline"); } diff --git a/src/shared/generator.c b/src/shared/generator.c index 462457e..7c76432 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -83,8 +83,8 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) { fprintf(f, "# Automatically generated by %1$s\n\n" "[Unit]\n" - "Documentation=man:systemd-fsck-root.service(8)\n" "Description=File System Check on %2$s\n" + "Documentation=man:systemd-fsck-root.service(8)\n" "DefaultDependencies=no\n" "BindsTo=%3$s\n" "After=initrd-root-device.target local-fs-pre.target %3$s\n" @@ -248,7 +248,8 @@ int generator_write_device_deps( r = unit_name_from_path(node, ".device", &unit); if (r < 0) - return log_error_errno(r, "Failed to make unit name from path: %m"); + return log_error_errno(r, "Failed to make unit name from path \"%s\": %m", + node); /* See mount_add_default_dependencies for explanation why we create such * dependencies. */ @@ -266,7 +267,8 @@ int generator_write_initrd_root_device_deps(const char *dir, const char *what) { r = unit_name_from_path(what, ".device", &unit); if (r < 0) - return log_error_errno(r, "Failed to make unit name from path: %m"); + return log_error_errno(r, "Failed to make unit name from path \"%s\": %m", + what); return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device", "# Automatically generated by %s\n\n" @@ -277,3 +279,151 @@ int generator_write_initrd_root_device_deps(const char *dir, const char *what) { unit, unit); } + +int generator_hook_up_mkswap( + const char *dir, + const char *what) { + + _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL; + _cleanup_fclose_ FILE *f = NULL; + const char *unit_file; + int r; + + node = fstab_node_to_udev_node(what); + if (!node) + return log_oom(); + + /* Nothing to work on. */ + if (!is_device_path(node)) { + log_error("Cannot format something that is not a device node: %s", node); + return -EINVAL; + } + + r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit); + if (r < 0) + return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m", + node); + + unit_file = strjoina(dir, "/", unit); + log_debug("Creating %s", unit_file); + + escaped = cescape(node); + if (!escaped) + return log_oom(); + + r = unit_name_from_path(what, ".swap", &where_unit); + if (r < 0) + return log_error_errno(r, "Failed to make unit name from path \"%s\": %m", + what); + + f = fopen(unit_file, "wxe"); + if (!f) + return log_error_errno(errno, "Failed to create unit file %s: %m", + unit_file); + + fprintf(f, + "# Automatically generated by %s\n\n" + "[Unit]\n" + "Description=Make Swap on %%f\n" + "Documentation=man:systemd-mkswap@.service(8)\n" + "DefaultDependencies=no\n" + "BindsTo=%%i.device\n" + "After=%%i.device\n" + "Before=%s\n" + "Before=shutdown.target\n" + "\n" + "[Service]\n" + "Type=oneshot\n" + "RemainAfterExit=yes\n" + "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n" + "TimeoutSec=0\n", + program_invocation_short_name, + where_unit, + escaped); + + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write unit file %s: %m", unit_file); + + return generator_add_symlink(dir, where_unit, "requires", unit); +} + +int generator_hook_up_mkfs( + const char *dir, + const char *what, + const char *where, + const char *type) { + + _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL; + _cleanup_fclose_ FILE *f = NULL; + const char *unit_file; + int r; + + node = fstab_node_to_udev_node(what); + if (!node) + return log_oom(); + + /* Nothing to work on. */ + if (!is_device_path(node)) { + log_error("Cannot format something that is not a device node: %s", node); + return -EINVAL; + } + + if (!type || streq(type, "auto")) { + log_error("Cannot format partition %s, filesystem type is not specified", node); + return -EINVAL; + } + + r = unit_name_from_path_instance("systemd-mkfs", node, ".service", &unit); + if (r < 0) + return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m", + node); + + unit_file = strjoina(dir, "/", unit); + log_debug("Creating %s", unit_file); + + escaped = cescape(node); + if (!escaped) + return log_oom(); + + r = unit_name_from_path(where, ".mount", &where_unit); + if (r < 0) + return log_error_errno(r, "Failed to make unit name from path \"%s\": %m", + where); + + f = fopen(unit_file, "wxe"); + if (!f) + return log_error_errno(errno, "Failed to create unit file %s: %m", + unit_file); + + fprintf(f, + "# Automatically generated by %s\n\n" + "[Unit]\n" + "Description=Make File System on %%f\n" + "Documentation=man:systemd-mkfs@.service(8)\n" + "DefaultDependencies=no\n" + "BindsTo=%%i.device\n" + "After=%%i.device\n" + /* fsck might or might not be used, so let's be safe and order + * ourselves before both systemd-fsck@.service and the mount unit. */ + "Before=systemd-fsck@%%i.service\n" + "Before=%s\n" + "Before=shutdown.target\n" + "\n" + "[Service]\n" + "Type=oneshot\n" + "RemainAfterExit=yes\n" + "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n" + "TimeoutSec=0\n", + program_invocation_short_name, + where_unit, + type, + escaped); + // XXX: what about local-fs-pre.target? + + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write unit file %s: %m", unit_file); + + return generator_add_symlink(dir, where_unit, "requires", unit); +} diff --git a/src/shared/generator.h b/src/shared/generator.h index 39dd520..f4109b9 100644 --- a/src/shared/generator.h +++ b/src/shared/generator.h @@ -39,11 +39,20 @@ int generator_write_timeouts( char **filtered); int generator_write_device_deps( - const char *dir, - const char *what, - const char *where, - const char *opts); + const char *dir, + const char *what, + const char *where, + const char *opts); int generator_write_initrd_root_device_deps( const char *dir, const char *what); + +int generator_hook_up_mkswap( + const char *dir, + const char *what); +int generator_hook_up_mkfs( + const char *dir, + const char *what, + const char *where, + const char *type); -- 2.7.4