From fc5c6eccb4bdd5fa22c2f1118fc57a230409470a Mon Sep 17 00:00:00 2001 From: Thomas Blume Date: Mon, 19 Sep 2022 16:57:48 +0200 Subject: [PATCH] units: make templates for quotaon and systemd-quotacheck service --- src/basic/special.h | 6 +- src/core/mount.c | 46 ------------ src/fstab-generator/fstab-generator.c | 17 ++++- src/quotacheck/quotacheck.c | 19 +++-- src/shared/generator.c | 72 +++++++++++++++++++ src/shared/generator.h | 10 +++ units/meson.build | 12 +++- units/quotaon-root.service.in | 24 +++++++ ...quotaon.service.in => quotaon@.service.in} | 8 ++- units/systemd-journal-flush.service | 2 +- units/systemd-quotacheck-root.service.in | 25 +++++++ ...vice.in => systemd-quotacheck@.service.in} | 7 +- 12 files changed, 186 insertions(+), 62 deletions(-) create mode 100644 units/quotaon-root.service.in rename units/{quotaon.service.in => quotaon@.service.in} (78%) create mode 100644 units/systemd-quotacheck-root.service.in rename units/{systemd-quotacheck.service.in => systemd-quotacheck@.service.in} (81%) diff --git a/src/basic/special.h b/src/basic/special.h index 27d2c26e48e..166737a9ca8 100644 --- a/src/basic/special.h +++ b/src/basic/special.h @@ -84,8 +84,10 @@ #define SPECIAL_FSCK_SERVICE "systemd-fsck@.service" #define SPECIAL_FSCK_ROOT_SERVICE "systemd-fsck-root.service" #define SPECIAL_FSCK_USR_SERVICE "systemd-fsck-usr.service" -#define SPECIAL_QUOTACHECK_SERVICE "systemd-quotacheck.service" -#define SPECIAL_QUOTAON_SERVICE "quotaon.service" +#define SPECIAL_QUOTACHECK_SERVICE "systemd-quotacheck@.service" +#define SPECIAL_QUOTACHECK_ROOT_SERVICE "systemd-quotacheck-root.service" +#define SPECIAL_QUOTAON_SERVICE "quotaon@.service" +#define SPECIAL_QUOTAON_ROOT_SERVICE "quotaon-root.service" #define SPECIAL_REMOUNT_FS_SERVICE "systemd-remount-fs.service" #define SPECIAL_VOLATILE_ROOT_SERVICE "systemd-volatile-root.service" #define SPECIAL_UDEVD_SERVICE "systemd-udevd.service" diff --git a/src/core/mount.c b/src/core/mount.c index 5090465f936..7dbf5f48f97 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -171,19 +171,6 @@ static bool mount_propagate_stop(Mount *m) { * otherwise let's not bother. */ } -static bool mount_needs_quota(const MountParameters *p) { - assert(p); - - if (p->fstype && !fstype_needs_quota(p->fstype)) - return false; - - if (mount_is_bind(p)) - return false; - - return fstab_test_option(p->options, - "usrquota\0" "grpquota\0" "quota\0" "usrjquota\0" "grpjquota\0"); -} - static void mount_init(Unit *u) { Mount *m = MOUNT(u); @@ -420,35 +407,6 @@ static int mount_add_device_dependencies(Mount *m) { return 0; } -static int mount_add_quota_dependencies(Mount *m) { - MountParameters *p; - int r; - - assert(m); - - if (!MANAGER_IS_SYSTEM(UNIT(m)->manager)) - return 0; - - p = get_mount_parameters_fragment(m); - if (!p) - return 0; - - if (!mount_needs_quota(p)) - return 0; - - r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, - /* add_reference= */ true, UNIT_DEPENDENCY_FILE); - if (r < 0) - return r; - - r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, - /* add_reference= */true, UNIT_DEPENDENCY_FILE); - if (r < 0) - return r; - - return 0; -} - static bool mount_is_extrinsic(Unit *u) { MountParameters *p; Mount *m = MOUNT(u); @@ -663,10 +621,6 @@ static int mount_add_non_exec_dependencies(Mount *m) { if (r < 0) return r; - r = mount_add_quota_dependencies(m); - if (r < 0) - return r; - r = mount_add_default_dependencies(m); if (r < 0) return r; diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 4d65289befc..e4c8c9674c0 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -46,6 +46,7 @@ typedef enum MountPointFlags { MOUNT_GROWFS = 1 << 4, MOUNT_RW_ONLY = 1 << 5, MOUNT_PCRFS = 1 << 6, + MOUNT_QUOTA = 1 << 7, } MountPointFlags; typedef struct Mount { @@ -717,6 +718,18 @@ static int add_mount( } } + if (flags & MOUNT_QUOTA) { + r = generator_hook_up_quotacheck(dest, what, where, target_unit, fstype); + if (r < 0) { + if (r != -EOPNOTSUPP) + return r; + } else { + r = generator_hook_up_quotaon(dest, where, target_unit); + if (r < 0) + return r; + } + } + if (FLAGS_SET(flags, MOUNT_AUTOMOUNT)) { r = unit_name_from_path(where, ".automount", &automount_name); if (r < 0) @@ -858,6 +871,8 @@ static MountPointFlags fstab_options_to_flags(const char *options, bool is_swap) flags |= MOUNT_GROWFS; if (fstab_test_option(options, "x-systemd.pcrfs\0")) flags |= MOUNT_PCRFS; + if (fstab_test_option(options, "usrquota\0" "grpquota\0" "quota\0" "usrjquota\0" "grpjquota\0" "prjquota\0")) + flags |= MOUNT_QUOTA; if (fstab_test_yes_no_option(options, "noauto\0" "auto\0")) flags |= MOUNT_NOAUTO; if (fstab_test_yes_no_option(options, "nofail\0" "fail\0")) @@ -1210,7 +1225,7 @@ static int add_sysroot_mount(void) { fstype, opts, is_device_path(what) ? 1 : 0, /* passno */ - flags, /* makefs off, pcrfs off, noauto off, nofail off, automount off */ + flags, /* makefs off, pcrfs off, quota off, noauto off, nofail off, automount off */ SPECIAL_INITRD_ROOT_FS_TARGET); } diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c index 27a914d737a..c77e0d6143a 100644 --- a/src/quotacheck/quotacheck.c +++ b/src/quotacheck/quotacheck.c @@ -56,12 +56,14 @@ static void test_files(void) { static int run(int argc, char *argv[]) { int r; + _cleanup_free_ char *fspath = NULL; + bool quota_check_all = false; log_setup(); - if (argc > 1) + if (argc > 2) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "This program takes no arguments."); + "This program expects one or no arguments."); umask(0022); @@ -79,13 +81,22 @@ static int run(int argc, char *argv[]) { return 0; } + if (argc == 2) { + fspath = strdup(argv[1]); + if (!fspath) + return log_oom(); + } else + quota_check_all = true; + r = safe_fork("(quotacheck)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_RLIMIT_NOFILE_SAFE|FORK_WAIT|FORK_LOG, NULL); if (r < 0) return r; + if (r == 0) { - static const char * const cmdline[] = { + const char *cmdline[] = { QUOTACHECK, - "-anug", + quota_check_all ? "-anug" : "-nug", + fspath, NULL }; diff --git a/src/shared/generator.c b/src/shared/generator.c index b96715c59cc..e03ed4b29fc 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -15,6 +15,7 @@ #include "log.h" #include "macro.h" #include "mkdir-label.h" +#include "mountpoint-util.h" #include "path-util.h" #include "process-util.h" #include "special.h" @@ -708,6 +709,77 @@ int generator_hook_up_pcrfs( return generator_add_symlink_full(dir, where_unit, "wants", pcrfs_unit_path, instance); } +int generator_hook_up_quotacheck( + const char *dir, + const char *what, + const char *where, + const char *target, + const char *fstype) { + + _cleanup_free_ char *where_unit = NULL, *instance = NULL; + int r; + + assert(dir); + assert(where); + + if (isempty(fstype) || streq(fstype, "auto")) + return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Couldn't determine filesystem type for %s, quota cannot be activated", what); + if (!fstype_needs_quota(fstype)) + return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Quota was requested for %s, but not supported, ignoring: %s", what, fstype); + + /* quotacheck unit for system root */ + if (path_equal(where, "/")) + return generator_add_symlink(dir, SPECIAL_LOCAL_FS_TARGET, "wants", SYSTEM_DATA_UNIT_DIR "/" SPECIAL_QUOTACHECK_ROOT_SERVICE); + + r = unit_name_path_escape(where, &instance); + if (r < 0) + return log_error_errno(r, "Failed to escape path '%s': %m", where); + + if (target) { + r = generator_add_ordering(dir, target, "After", SPECIAL_QUOTACHECK_SERVICE, instance); + if (r < 0) + return r; + } + + 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); + + return generator_add_symlink_full(dir, where_unit, "wants", SYSTEM_DATA_UNIT_DIR "/" SPECIAL_QUOTACHECK_SERVICE, instance); +} + +int generator_hook_up_quotaon( + const char *dir, + const char *where, + const char *target) { + + _cleanup_free_ char *where_unit = NULL, *instance = NULL; + int r; + + assert(dir); + assert(where); + + /* quotaon unit for system root is not instantiated */ + if (path_equal(where, "/")) + return generator_add_symlink(dir, SPECIAL_LOCAL_FS_TARGET, "wants", SYSTEM_DATA_UNIT_DIR "/" SPECIAL_QUOTAON_ROOT_SERVICE); + + r = unit_name_path_escape(where, &instance); + if (r < 0) + return log_error_errno(r, "Failed to escape path '%s': %m", where); + + if (target) { + r = generator_add_ordering(dir, target, "After", SPECIAL_QUOTAON_SERVICE, instance); + if (r < 0) + return r; + } + + 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); + + return generator_add_symlink_full(dir, where_unit, "wants", SYSTEM_DATA_UNIT_DIR "/" SPECIAL_QUOTAON_SERVICE, instance); +} + int generator_enable_remount_fs_service(const char *dir) { /* Pull in systemd-remount-fs.service */ return generator_add_symlink(dir, SPECIAL_LOCAL_FS_TARGET, "wants", diff --git a/src/shared/generator.h b/src/shared/generator.h index e5db1c17ce0..baf1dafca3f 100644 --- a/src/shared/generator.h +++ b/src/shared/generator.h @@ -85,6 +85,16 @@ int generator_hook_up_pcrfs( const char *dir, const char *where, const char *target); +int generator_hook_up_quotacheck( + const char *dir, + const char *what, + const char *where, + const char *target, + const char *fstype); +int generator_hook_up_quotaon( + const char *dir, + const char *where, + const char *target); int generator_enable_remount_fs_service(const char *dir); diff --git a/units/meson.build b/units/meson.build index 936ebf78374..afe9ec7d1d9 100644 --- a/units/meson.build +++ b/units/meson.build @@ -161,7 +161,11 @@ units = [ 'conditions' : ['ENABLE_BINFMT'], }, { - 'file' : 'quotaon.service.in', + 'file' : 'quotaon@.service.in', + 'conditions' : ['ENABLE_QUOTACHECK'], + }, + { + 'file' : 'quotaon-root.service.in', 'conditions' : ['ENABLE_QUOTACHECK'], }, { @@ -552,7 +556,11 @@ units = [ 'conditions' : ['ENABLE_PSTORE'], }, { - 'file' : 'systemd-quotacheck.service.in', + 'file' : 'systemd-quotacheck@.service.in', + 'conditions' : ['ENABLE_QUOTACHECK'], + }, + { + 'file' : 'systemd-quotacheck-root.service.in', 'conditions' : ['ENABLE_QUOTACHECK'], }, { diff --git a/units/quotaon-root.service.in b/units/quotaon-root.service.in new file mode 100644 index 00000000000..cd308f43d9b --- /dev/null +++ b/units/quotaon-root.service.in @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Enable Root File System Quotas +Documentation=man:quotaon(8) + +ConditionPathExists=!/etc/initrd-release + +DefaultDependencies=no +After=systemd-quotacheck-root.service +Before=local-fs.target shutdown.target +Conflicts=shutdown.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart={{QUOTAON}} -ug / diff --git a/units/quotaon.service.in b/units/quotaon@.service.in similarity index 78% rename from units/quotaon.service.in rename to units/quotaon@.service.in index 7fa7061eeae..136060a9a17 100644 --- a/units/quotaon.service.in +++ b/units/quotaon@.service.in @@ -12,13 +12,15 @@ Description=Enable File System Quotas Documentation=man:quotaon(8) ConditionPathExists={{QUOTAON}} +ConditionPathExists=!/etc/initrd-release +After=%i.mount +After=systemd-quotacheck@%i.service DefaultDependencies=no -After=systemd-quotacheck.service -Before=remote-fs.target Before=shutdown.target +Conflicts=shutdown.target [Service] Type=oneshot RemainAfterExit=yes -ExecStart={{QUOTAON}} -aug +ExecStart={{QUOTAON}} -ug %f diff --git a/units/systemd-journal-flush.service b/units/systemd-journal-flush.service index 8c01587cad8..13c3985ed3c 100644 --- a/units/systemd-journal-flush.service +++ b/units/systemd-journal-flush.service @@ -14,7 +14,7 @@ Documentation=man:systemd-journald.service(8) man:journald.conf(5) ConditionPathExists=!/etc/initrd-release DefaultDependencies=no -After=systemd-remount-fs.service +After=systemd-remount-fs.service systemd-quotacheck-root.service Before=systemd-tmpfiles-setup.service Wants=systemd-journald.service After=systemd-journald.service diff --git a/units/systemd-quotacheck-root.service.in b/units/systemd-quotacheck-root.service.in new file mode 100644 index 00000000000..a182059376f --- /dev/null +++ b/units/systemd-quotacheck-root.service.in @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Root File System Quota Check +Documentation=man:systemd-quotacheck.service(8) + +ConditionPathExists=!/etc/initrd-release + +DefaultDependencies=no +After=systemd-remount-fs.service +Before=local-fs.target shutdown.target +Conflicts=shutdown.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart={{LIBEXECDIR}}/systemd-quotacheck / +TimeoutSec=infinity diff --git a/units/systemd-quotacheck.service.in b/units/systemd-quotacheck@.service.in similarity index 81% rename from units/systemd-quotacheck.service.in rename to units/systemd-quotacheck@.service.in index 0f94e382863..dddce2ee832 100644 --- a/units/systemd-quotacheck.service.in +++ b/units/systemd-quotacheck@.service.in @@ -12,14 +12,15 @@ Description=File System Quota Check Documentation=man:systemd-quotacheck.service(8) ConditionPathExists={{QUOTACHECK}} +ConditionPathExists=!/etc/initrd-release DefaultDependencies=no -After=systemd-remount-fs.service -Before=remote-fs.target +After=%i.mount Before=shutdown.target +Conflicts=shutdown.target [Service] Type=oneshot RemainAfterExit=yes -ExecStart={{LIBEXECDIR}}/systemd-quotacheck +ExecStart={{LIBEXECDIR}}/systemd-quotacheck %f TimeoutSec=infinity