diff --git a/.clang-tidy b/.clang-tidy index 8d69a69cbf..c784c9532b 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -38,7 +38,6 @@ CheckOptions: # of them related to musl). misc-include-cleaner.IgnoreHeaders: ' endian\.h; - getopt\.h; sys/stat\.h; sys/statvfs\.h; sys/syscall\.h; diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 759c5600ad..67a9135767 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -716,7 +716,7 @@ static int run(int argc, char *argv[]) { return log_oom(); } - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c index 69bd42ebcc..7e296c9ffc 100644 --- a/src/backlight/backlight.c +++ b/src/backlight/backlight.c @@ -11,10 +11,11 @@ #include "device-util.h" #include "escape.h" #include "fileio.h" +#include "format-table.h" +#include "help-util.h" #include "main-func.h" #include "parse-util.h" #include "percent-util.h" -#include "pretty-print.h" #include "reboot-util.h" #include "string-util.h" #include "strv.h" @@ -23,25 +24,22 @@ #define PCI_CLASS_GRAPHICS_CARD 0x30000 static int help(void) { - _cleanup_free_ char *link = NULL; + _cleanup_(table_unrefp) Table *verbs = NULL; int r; - r = terminal_urlify_man("systemd-backlight", "8", &link); + r = verbs_get_help_table(&verbs); if (r < 0) - return log_oom(); + return r; - printf("%s save [backlight|leds]:DEVICE\n" - "%s load [backlight|leds]:DEVICE\n" - "\n%sSave and restore backlight brightness at shutdown and boot.%s\n\n" - " save Save current brightness\n" - " load Set brightness to be the previously saved value\n" - "\nSee the %s for details.\n", - program_invocation_short_name, - program_invocation_short_name, - ansi_highlight(), - ansi_normal(), - link); + help_cmdline("COMMAND [backlight|leds]:DEVICE"); + help_abstract("Save and restore backlight brightness at shutdown and boot."); + help_section("Commands"); + r = table_print_or_warn(verbs); + if (r < 0) + return r; + + help_man_page_reference("systemd-backlight", "8"); return 0; } @@ -555,6 +553,8 @@ static int device_new_from_arg(const char *s, sd_device **ret) { return 1; /* Found. */ } +VERB(verb_load, "load", "[backlight|leds]:DEVICE", 2, 2, VERB_ONLINE_ONLY, + "Set brightness to be the previously saved value"); static int verb_load(int argc, char *argv[], uintptr_t _data, void *userdata) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; unsigned max_brightness, brightness, percent; @@ -605,6 +605,8 @@ static int verb_load(int argc, char *argv[], uintptr_t _data, void *userdata) { return 0; } +VERB(verb_save, "save", "[backlight|leds]:DEVICE", 2, 2, VERB_ONLINE_ONLY, + "Save current brightness"); static int verb_save(int argc, char *argv[], uintptr_t _data, void *userdata) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; _cleanup_free_ char *path = NULL; @@ -647,12 +649,6 @@ static int verb_save(int argc, char *argv[], uintptr_t _data, void *userdata) { } static int run(int argc, char *argv[]) { - static const Verb verbs[] = { - { "load", 2, 2, VERB_ONLINE_ONLY, verb_load }, - { "save", 2, 2, VERB_ONLINE_ONLY, verb_save }, - {} - }; - log_setup(); if (argv_looks_like_help(argc, argv)) @@ -660,7 +656,7 @@ static int run(int argc, char *argv[]) { umask(0022); - return dispatch_verb(argc, argv, verbs, NULL); + return dispatch_verb(strv_skip(argv, 1), /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/basic/argv-util.c b/src/basic/argv-util.c index 0ff2fd9bcb..10f8cd86f4 100644 --- a/src/basic/argv-util.c +++ b/src/basic/argv-util.c @@ -71,7 +71,7 @@ bool argv_looks_like_help(int argc, char **argv) { char **l; /* Scans the command line for indications the user asks for help. This is supposed to be called by - * tools that do not implement getopt() style command line parsing because they are not primarily + * tools that do not implement getopt()-style command line parsing because they are not primarily * user-facing. Detects four ways of asking for help: * * 1. Passing zero arguments diff --git a/src/basic/static-destruct.c b/src/basic/static-destruct.c index c39a1b3816..442f5fe7ba 100644 --- a/src/basic/static-destruct.c +++ b/src/basic/static-destruct.c @@ -1,13 +1,12 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "memory-util.h" #include "static-destruct.h" void static_destruct_impl(const StaticDestructor *start, const StaticDestructor *end) { if (!start) return; - for (const StaticDestructor *d = ALIGN_PTR(start); d < end; d = ALIGN_PTR(d + 1)) + for (const StaticDestructor *d = start; d < end; d++) switch (d->type) { case STATIC_DESTRUCTOR_SIMPLE: d->simple.destroy(d->simple.data); diff --git a/src/basic/static-destruct.h b/src/basic/static-destruct.h index 00087ad779..fdc4c7c41e 100644 --- a/src/basic/static-destruct.h +++ b/src/basic/static-destruct.h @@ -44,6 +44,8 @@ typedef struct StaticDestructor { }; } StaticDestructor; +assert_cc(sizeof(StaticDestructor) % sizeof(void*) == 0); + #define STATIC_DESTRUCTOR_REGISTER(variable, func) \ _STATIC_DESTRUCTOR_REGISTER(UNIQ, variable, func) diff --git a/src/bless-boot/bless-boot.c b/src/bless-boot/bless-boot.c index 3680dfdc18..43fb72cddb 100644 --- a/src/bless-boot/bless-boot.c +++ b/src/bless-boot/bless-boot.c @@ -580,7 +580,7 @@ static int run(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Marking a boot is only supported on EFI systems."); - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/bootctl/bootctl.c b/src/bootctl/bootctl.c index 4bb9742a47..b5cca6d222 100644 --- a/src/bootctl/bootctl.c +++ b/src/bootctl/bootctl.c @@ -917,7 +917,7 @@ static int run(int argc, char *argv[]) { return log_oom(); } - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 9bf990d3db..edba5748e8 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -2324,7 +2324,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index 7bb1fd1752..3b31471ab4 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -1501,7 +1501,7 @@ static int run(int argc, char *argv[]) { return log_oom(); } - r = dispatch_verb_with_args(args, NULL); + r = dispatch_verb(args, NULL); if (units_active > 0) printf("%s-- Notice: %d systemd-coredump@.service %s, output may be incomplete.%s\n", diff --git a/src/creds/creds.c b/src/creds/creds.c index a4087fc2be..77f7442ab5 100644 --- a/src/creds/creds.c +++ b/src/creds/creds.c @@ -1478,7 +1478,7 @@ static int run(int argc, char *argv[]) { if (arg_varlink) return vl_server(); - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index fffecd3573..b6ee120e5e 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -2883,7 +2883,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index 280d1ada5f..c79609f583 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include -#include #include #include #include @@ -132,11 +131,11 @@ static int help(void) { if (r < 0) return log_oom(); - r = option_parser_get_help_table(&options); + r = option_parser_get_help_table_ns("systemd-dissect", &options); if (r < 0) return r; - r = option_parser_get_help_table_group("Commands", &commands); + r = option_parser_get_help_table_full("systemd-dissect", "Commands", &commands); if (r < 0) return r; @@ -230,11 +229,13 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - OptionParser opts = { argc, argv }; + OptionParser opts = { argc, argv, .namespace = "systemd-dissect" }; FOREACH_OPTION_OR_RETURN(c, &opts) switch (c) { + OPTION_NAMESPACE("systemd-dissect"): {} + OPTION_COMMON_NO_PAGER: arg_pager_flags |= PAGER_DISABLE; break; @@ -745,41 +746,45 @@ static int parse_argv(int argc, char *argv[]) { static int parse_argv_as_mount_helper(int argc, char *argv[]) { const char *options = NULL; bool fake = false; - int c, r; + int r; /* Implements util-linux "external helper" command line interface, as per mount(8) man page. */ - while ((c = getopt(argc, argv, "sfnvN:o:t:")) >= 0) { + OptionParser opts = { argc, argv, .namespace = "mount.ddi" }; + FOREACH_OPTION_OR_RETURN(c, &opts) switch (c) { - case 'f': + OPTION_NAMESPACE("mount.ddi"): {} + + OPTION_SHORT('f', NULL, /* help= */ NULL): fake = true; break; - case 'o': - options = optarg; + OPTION_SHORT('o', "OPTIONS", /* help= */ NULL): + options = opts.arg; break; - case 't': - if (!streq(optarg, "ddi")) - log_debug("Unexpected file system type '%s', ignoring.", optarg); + OPTION_SHORT('t', "FSTYPE", /* help= */ NULL): + if (!streq(opts.arg, "ddi")) + log_debug("Unexpected file system type '%s', ignoring.", opts.arg); break; - case 's': /* sloppy mount options */ - case 'n': /* aka --no-mtab */ - case 'v': /* aka --verbose */ - log_debug("Ignoring option -%c, not implemented.", c); + OPTION_SHORT('s', NULL, /* help= */ NULL): {} /* sloppy mount options */ + OPTION_SHORT('n', NULL, /* help= */ NULL): {} /* aka --no-mtab */ + OPTION_SHORT('v', NULL, /* help= */ NULL): /* aka --verbose */ + log_debug("Ignoring option -%c, not implemented.", opts.opt->short_code); break; - case 'N': /* aka --namespace= */ - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Option -%c is not implemented, refusing.", c); - - case '?': - return -EINVAL; + OPTION_SHORT('N', "NS", /* help= */ NULL): /* aka --namespace= */ + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Option -%c is not implemented, refusing.", + opts.opt->short_code); } - } - if (optind + 2 != argc) + char **args = option_parser_get_args(&opts); + size_t n_args = option_parser_get_n_args(&opts); + + if (n_args != 2) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected an image file path and target directory as only argument."); @@ -808,11 +813,11 @@ static int parse_argv_as_mount_helper(int argc, char *argv[]) { if (fake) return 0; - r = parse_path_argument(argv[optind], /* suppress_root= */ false, &arg_image); + r = parse_path_argument(args[0], /* suppress_root= */ false, &arg_image); if (r < 0) return r; - r = parse_path_argument(argv[optind+1], /* suppress_root= */ false, &arg_path); + r = parse_path_argument(args[1], /* suppress_root= */ false, &arg_path); if (r < 0) return r; diff --git a/src/factory-reset/factory-reset-tool.c b/src/factory-reset/factory-reset-tool.c index c21e84c2ef..d3019396c3 100644 --- a/src/factory-reset/factory-reset-tool.c +++ b/src/factory-reset/factory-reset-tool.c @@ -365,7 +365,7 @@ static int run(int argc, char *argv[]) { if (arg_varlink) return varlink_service(); - return dispatch_verb_with_args(args, /* userdata= */ NULL); + return dispatch_verb(args, /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/home/homectl.c b/src/home/homectl.c index 75339d93c8..ab81efbed6 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -5165,7 +5165,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, /* userdata= */ NULL); + return dispatch_verb(args, /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/home/test-homectl-prompts.c b/src/home/test-homectl-prompts.c index aaa81cc78a..59bff32c44 100644 --- a/src/home/test-homectl-prompts.c +++ b/src/home/test-homectl-prompts.c @@ -100,7 +100,7 @@ static int run(int argc, char **argv) { if (r <= 0) return r; - return dispatch_verb_with_args(args, /* userdata= */ NULL); + return dispatch_verb(args, /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index ab21fcca1f..282a16d83c 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -833,7 +833,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return bus_log_connect_error(r, arg_transport, RUNTIME_SCOPE_SYSTEM); - return dispatch_verb_with_args(args, bus); + return dispatch_verb(args, bus); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c index 5ad3bac321..4d2d6fe8c4 100644 --- a/src/hwdb/hwdb.c +++ b/src/hwdb/hwdb.c @@ -125,7 +125,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/id128/id128.c b/src/id128/id128.c index ceac8a832e..e66acd33e5 100644 --- a/src/id128/id128.c +++ b/src/id128/id128.c @@ -304,7 +304,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/import/export.c b/src/import/export.c index 8b64b9cad9..0b6d27b9ff 100644 --- a/src/import/export.c +++ b/src/import/export.c @@ -292,7 +292,7 @@ static int run(int argc, char *argv[]) { (void) ignore_signals(SIGPIPE); - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/import/import-fs.c b/src/import/import-fs.c index cc6e14c995..1e6d8beff2 100644 --- a/src/import/import-fs.c +++ b/src/import/import-fs.c @@ -400,7 +400,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/import/import.c b/src/import/import.c index 9ddc4469c1..18276fa72d 100644 --- a/src/import/import.c +++ b/src/import/import.c @@ -481,7 +481,7 @@ static int run(int argc, char *argv[]) { (void) ignore_signals(SIGPIPE); - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/import/importctl.c b/src/import/importctl.c index 0140d0f67d..58d996e8d7 100644 --- a/src/import/importctl.c +++ b/src/import/importctl.c @@ -1260,7 +1260,7 @@ static int run(int argc, char *argv[]) { (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password); - return dispatch_verb_with_args(args, bus); + return dispatch_verb(args, bus); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/import/pull.c b/src/import/pull.c index ac9492f177..09294bc6fc 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -620,7 +620,7 @@ static int run(int argc, char *argv[]) { (void) ignore_signals(SIGPIPE); - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/include/musl/getopt.h b/src/include/musl/getopt.h deleted file mode 100644 index 6aed1dfd26..0000000000 --- a/src/include/musl/getopt.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/* getopt() is provided both in getopt.h and unistd.h. Hence, we need to tentatively undefine it. */ -#undef getopt - -#include_next - -/* musl's getopt() always behaves POSIXLY_CORRECT mode, and stops parsing arguments when a non-option string - * found. Let's always use getopt_long(). */ -int getopt_fix(int argc, char * const *argv, const char *optstring); -#define getopt(argc, argv, optstring) getopt_fix(argc, argv, optstring) - -/* musl's getopt_long() behaves something different in handling optional arguments. - * ======== - * $ journalctl _PID=1 _COMM=systemd --since 19:19:01 -n all --follow - * Failed to add match 'all': Invalid argument - * ======== - * Here, we introduce getopt_long_fix() that reorders the passed arguments to make getopt_long() provided by - * musl works as what we expect. */ -int getopt_long_fix( - int argc, - char * const *argv, - const char *optstring, - const struct option *longopts, - int *longindex); - -#define getopt_long(argc, argv, optstring, longopts, longindex) \ - getopt_long_fix(argc, argv, optstring, longopts, longindex) diff --git a/src/include/musl/unistd.h b/src/include/musl/unistd.h index e58fee356a..175661442d 100644 --- a/src/include/musl/unistd.h +++ b/src/include/musl/unistd.h @@ -1,16 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -/* getopt() is provided both in getopt.h and unistd.h. Hence, we need to tentatively undefine it. */ -#undef getopt - #include_next -/* musl's getopt() always behaves POSIXLY_CORRECT mode, and stops parsing arguments when a non-option string - * found. Let's always use getopt_long(). */ -int getopt_fix(int argc, char * const *argv, const char *optstring); -#define getopt(argc, argv, optstring) getopt_fix(argc, argv, optstring) - int missing_close_range(unsigned first_fd, unsigned end_fd, unsigned flags); #define close_range missing_close_range diff --git a/src/integritysetup/integritysetup.c b/src/integritysetup/integritysetup.c index 9a373e124b..bdf1b25473 100644 --- a/src/integritysetup/integritysetup.c +++ b/src/integritysetup/integritysetup.c @@ -7,13 +7,15 @@ #include "argv-util.h" #include "cryptsetup-util.h" #include "fileio.h" +#include "format-table.h" +#include "help-util.h" #include "integrity-util.h" #include "log.h" #include "main-func.h" #include "path-util.h" -#include "pretty-print.h" #include "string-table.h" #include "string-util.h" +#include "strv.h" #include "time-util.h" #include "verbs.h" @@ -41,21 +43,22 @@ static const char* const dm_integrity_algorithm_table[_INTEGRITY_ALGORITHM_MAX] DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(dm_integrity_algorithm, IntegrityAlgorithm); static int help(void) { - _cleanup_free_ char *link = NULL; + _cleanup_(table_unrefp) Table *verbs = NULL; int r; - r = terminal_urlify_man("systemd-integritysetup@.service", "8", &link); + r = verbs_get_help_table(&verbs); if (r < 0) - return log_oom(); + return r; - printf("%s attach VOLUME DEVICE [HMAC_KEY_FILE|-] [OPTIONS]\n" - "%s detach VOLUME\n\n" - "Attach or detach an integrity protected block device.\n" - "\nSee the %s for details.\n", - program_invocation_short_name, - program_invocation_short_name, - link); + help_cmdline("COMMAND ..."); + help_abstract("Attach or detach an integrity protected block device."); + help_section("Commands"); + r = table_print_or_warn(verbs); + if (r < 0) + return r; + + help_man_page_reference("systemd-integritysetup@.service", "8"); return 0; } @@ -94,6 +97,8 @@ static const char *integrity_algorithm_select(const void *key_file_buf) { return dm_integrity_algorithm_to_string(a); } +VERB(verb_attach, "attach", "VOLUME DEVICE [HMAC_KEY_FILE|-] [OPTIONS]", 3, 5, 0, + "Attach an integrity protected block device"); static int verb_attach(int argc, char *argv[], uintptr_t _data, void *userdata) { _cleanup_(crypt_freep) struct crypt_device *cd = NULL; crypt_status_info status; @@ -161,6 +166,8 @@ static int verb_attach(int argc, char *argv[], uintptr_t _data, void *userdata) return 0; } +VERB(verb_detach, "detach", "VOLUME", 2, 2, 0, + "Detach an integrity protected block device"); static int verb_detach(int argc, char *argv[], uintptr_t _data, void *userdata) { _cleanup_(crypt_freep) struct crypt_device *cd = NULL; int r; @@ -203,13 +210,7 @@ static int run(int argc, char *argv[]) { umask(0022); - static const Verb verbs[] = { - { "attach", 3, 5, 0, verb_attach }, - { "detach", 2, 2, 0, verb_detach }, - {} - }; - - return dispatch_verb(argc, argv, verbs, NULL); + return dispatch_verb(strv_skip(argv, 1), /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c index 27e1a7426e..ff93a80c08 100644 --- a/src/kernel-install/kernel-install.c +++ b/src/kernel-install/kernel-install.c @@ -1719,7 +1719,7 @@ static int run(int argc, char* argv[]) { if (invoked_as(argv, "installkernel")) return run_as_installkernel(args); - return dispatch_verb_with_args(args, /* userdata= */ NULL); + return dispatch_verb(args, /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/keyutil/keyutil.c b/src/keyutil/keyutil.c index abdec1591d..ab8e3eee98 100644 --- a/src/keyutil/keyutil.c +++ b/src/keyutil/keyutil.c @@ -415,7 +415,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/libc/musl/getopt.c b/src/libc/musl/getopt.c deleted file mode 100644 index 15c3afa49b..0000000000 --- a/src/libc/musl/getopt.c +++ /dev/null @@ -1,100 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include -#include -#include - -static int first_non_opt = 0, last_non_opt = 0; -static bool non_opt_found = false, dash_dash = false; - -static void shift(char * const *argv, int start, int end) { - char **av = (char**) argv; - char *saved = av[end]; - - for (int i = end; i > start; i--) - av[i] = av[i - 1]; - - av[start] = saved; -} - -static void exchange(int argc, char * const *argv) { - /* input: - * - * first_non_opt last_non_opt optind - * | | | - * v v v - * aaaaa bbbbb ccccc --prev-opt prev-opt-arg ddddd --next-opt - * - * output: - * first_non_opt last_non_opt optind - * | | | - * v v v - * --prev-opt prev-opt-arg aaaaa bbbbb ccccc ddddd --next-opt - */ - - /* First, move previous arguments. */ - int c = optind - 1 - last_non_opt; - if (c > 0) { - for (int i = 0; i < c; i++) - shift(argv, first_non_opt, optind - 1); - first_non_opt += c; - last_non_opt += c; - } - - /* Then, skip entries that do not start with '-'. */ - while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0')) { - if (!non_opt_found) { - first_non_opt = optind; - non_opt_found = true; - } - last_non_opt = optind; - optind++; - } -} - -int getopt_long_fix( - int argc, - char * const *argv, - const char *optstring, - const struct option *longopts, - int *longindex) { - - int r; - - if (optind == 0 || first_non_opt == 0 || last_non_opt == 0) { - /* initialize musl's internal variables. */ - (void) (getopt_long)(/* argc= */ -1, /* argv= */ NULL, /* optstring= */ NULL, /* longopts= */ NULL, /* longindex= */ NULL); - first_non_opt = last_non_opt = 1; - non_opt_found = dash_dash = false; - } - - if (first_non_opt >= argc || last_non_opt >= argc || optind > argc || dash_dash) - return -1; - - /* Do not shuffle arguments when optstring starts with '+' or '-'. */ - if (!optstring || optstring[0] == '+' || optstring[0] == '-') - return (getopt_long)(argc, argv, optstring, longopts, longindex); - - exchange(argc, argv); - - if (optind < argc && strcmp(argv[optind], "--") == 0) { - if (first_non_opt < optind) - shift(argv, first_non_opt, optind); - first_non_opt++; - optind++; - dash_dash = true; - if (non_opt_found) - optind = first_non_opt; - return -1; - } - - r = (getopt_long)(argc, argv, optstring, longopts, longindex); - if (r < 0 && non_opt_found) - optind = first_non_opt; - - return r; -} - -int getopt_fix(int argc, char * const *argv, const char *optstring) { - return getopt_long_fix(argc, argv, optstring, /* longopts= */ NULL, /* longindex= */ NULL); -} diff --git a/src/libc/musl/meson.build b/src/libc/musl/meson.build index acda973b8d..a06216f063 100644 --- a/src/libc/musl/meson.build +++ b/src/libc/musl/meson.build @@ -6,7 +6,6 @@ endif libc_wrapper_sources += files( 'crypt.c', - 'getopt.c', 'printf.c', 'stdio.c', 'stdlib.c', diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c index be64e4a6c8..bee843e338 100644 --- a/src/libsystemd/sd-bus/bus-error.c +++ b/src/libsystemd/sd-bus/bus-error.c @@ -83,22 +83,17 @@ static int bus_error_name_to_errno(const char *name) { } } - const sd_bus_error_map *elf_map = ALIGN_PTR(__start_SYSTEMD_BUS_ERROR_MAP); - while (elf_map < __stop_SYSTEMD_BUS_ERROR_MAP) { + assert_cc(sizeof(sd_bus_error_map) % sizeof(void*) == 0); + + for (const sd_bus_error_map *m = __start_SYSTEMD_BUS_ERROR_MAP; m < __stop_SYSTEMD_BUS_ERROR_MAP; m++) { /* For magic ELF error maps, the end marker might appear in the middle of things, since - * multiple maps might appear in the same section. Hence, let's skip over it, but realign - * the pointer to the next 8 byte boundary, which is the selected alignment for the arrays. */ - if (elf_map->code == BUS_ERROR_MAP_END_MARKER) { - elf_map = ALIGN_PTR(elf_map + 1); - continue; - } + * multiple maps might appear in the same section. Skip over it. */ - if (streq(elf_map->name, name)) { - assert(elf_map->code > 0); - return elf_map->code; + if (m->code != BUS_ERROR_MAP_END_MARKER && + streq(m->name, name)) { + assert(m->code > 0); + return m->code; } - - elf_map++; } return EIO; diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c index 3f89a907eb..a91a014a38 100644 --- a/src/libsystemd/sd-bus/test-bus-error.c +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -128,19 +128,12 @@ extern const sd_bus_error_map __start_SYSTEMD_BUS_ERROR_MAP[]; extern const sd_bus_error_map __stop_SYSTEMD_BUS_ERROR_MAP[]; static int dump_mapping_table(void) { - const sd_bus_error_map *m; - printf("----- errno mappings ------\n"); - m = ALIGN_PTR(__start_SYSTEMD_BUS_ERROR_MAP); - while (m < __stop_SYSTEMD_BUS_ERROR_MAP) { + for (const sd_bus_error_map *m = __start_SYSTEMD_BUS_ERROR_MAP; m < __stop_SYSTEMD_BUS_ERROR_MAP; m++) { + assert((uintptr_t) m % sizeof(void*) == 0); - if (m->code == BUS_ERROR_MAP_END_MARKER) { - m = ALIGN_PTR(m + 1); - continue; - } - - printf("%s -> %i/%s\n", strna(m->name), m->code, ERRNO_NAME(m->code)); - m++; + if (m->code != BUS_ERROR_MAP_END_MARKER) + printf("%s -> %i/%s\n", strna(m->name), m->code, ERRNO_NAME(m->code)); } printf("---------------------------\n"); diff --git a/src/locale/localectl.c b/src/locale/localectl.c index f1f9ffbce0..ff7afa6c84 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -519,7 +519,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return bus_log_connect_error(r, arg_transport, RUNTIME_SCOPE_SYSTEM); - return dispatch_verb_with_args(args, bus); + return dispatch_verb(args, bus); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 39c048e708..63eafdceb4 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -1680,7 +1680,7 @@ static int run(int argc, char *argv[]) { (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password); - return dispatch_verb_with_args(args, bus); + return dispatch_verb(args, bus); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index c0f9fd51e0..b0efb6ec02 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2656,7 +2656,7 @@ static int run(int argc, char *argv[]) { (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password); - return dispatch_verb_with_args(args, bus); + return dispatch_verb(args, bus); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/measure/measure-tool.c b/src/measure/measure-tool.c index b8acd6d4b0..e7a3be6d64 100644 --- a/src/measure/measure-tool.c +++ b/src/measure/measure-tool.c @@ -1126,7 +1126,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/network/networkctl.c b/src/network/networkctl.c index b64c8b17fc..bdf487bf2e 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -213,7 +213,7 @@ static int run(int argc, char* argv[]) { journal_browse_prepare(); - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/oom/oomctl.c b/src/oom/oomctl.c index f6d451612b..8b5051ebd0 100644 --- a/src/oom/oomctl.c +++ b/src/oom/oomctl.c @@ -120,7 +120,7 @@ static int run(int argc, char* argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/pcrlock/pcrlock.c b/src/pcrlock/pcrlock.c index 8315384b4d..9ce991262e 100644 --- a/src/pcrlock/pcrlock.c +++ b/src/pcrlock/pcrlock.c @@ -5505,7 +5505,7 @@ static int run(int argc, char *argv[]) { return EXIT_SUCCESS; } - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c index 763acfc258..9286a6fbb3 100644 --- a/src/portable/portablectl.c +++ b/src/portable/portablectl.c @@ -1455,7 +1455,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/random-seed/random-seed-tool.c b/src/random-seed/random-seed-tool.c index f573e84412..514176ef5d 100644 --- a/src/random-seed/random-seed-tool.c +++ b/src/random-seed/random-seed-tool.c @@ -362,7 +362,7 @@ static int parse_argv(int argc, char *argv[]) { return version(); } - r = dispatch_verb_with_args(option_parser_get_args(&opts), NULL); + r = dispatch_verb(option_parser_get_args(&opts), NULL); if (r < 0) return r; diff --git a/src/report/report.c b/src/report/report.c index 4031d91543..9cb0e053e0 100644 --- a/src/report/report.c +++ b/src/report/report.c @@ -886,7 +886,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index e8ae7c5412..67be81195a 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -3761,7 +3761,7 @@ static int translate(const char *verb, const char *single_arg, char **args) { STRV_FOREACH(a, args) *p++ = *a; - return dispatch_verb_with_args(fake, /* userdata= */ NULL); + return dispatch_verb(fake, /* userdata= */ NULL); } static int compat_main(char **args) { @@ -3883,7 +3883,7 @@ static int run(int argc, char **argv) { if (compat) return compat_main(args); - return dispatch_verb_with_args(args, /* userdata= */ NULL); + return dispatch_verb(args, /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/sbsign/sbsign.c b/src/sbsign/sbsign.c index 9d163624a4..f845bcdf42 100644 --- a/src/sbsign/sbsign.c +++ b/src/sbsign/sbsign.c @@ -730,7 +730,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/shared/options.h b/src/shared/options.h index c2283dc406..fd3ab008d3 100644 --- a/src/shared/options.h +++ b/src/shared/options.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include "memory-util.h" #include "shared-forward.h" /* Option namespace/group explanation: @@ -240,10 +239,10 @@ int option_parse( /* Iterate over options. Don't forget to handle errors (negative c)! */ #define FOREACH_OPTION(c, state) \ - for (int c; (c = option_parse(ALIGN_PTR(__start_SYSTEMD_OPTIONS), __stop_SYSTEMD_OPTIONS, state)) != 0; ) + for (int c; (c = option_parse(__start_SYSTEMD_OPTIONS, __stop_SYSTEMD_OPTIONS, state)) != 0; ) #define FOREACH_OPTION_OR_RETURN(c, state) \ - for (int c; (c = option_parse(ALIGN_PTR(__start_SYSTEMD_OPTIONS), __stop_SYSTEMD_OPTIONS, state)) != 0; ) \ + for (int c; (c = option_parse(__start_SYSTEMD_OPTIONS, __stop_SYSTEMD_OPTIONS, state)) != 0; ) \ if (c < 0) \ return c; \ else @@ -268,7 +267,7 @@ int _option_parser_get_help_table_full( const char *group, Table **ret); #define option_parser_get_help_table_full(namespace, group, ret) \ - _option_parser_get_help_table_full(ALIGN_PTR(__start_SYSTEMD_OPTIONS), __stop_SYSTEMD_OPTIONS, namespace, group, ret) + _option_parser_get_help_table_full(__start_SYSTEMD_OPTIONS, __stop_SYSTEMD_OPTIONS, namespace, group, ret) #define option_parser_get_help_table_ns(ns, ret) \ option_parser_get_help_table_full(ns, /* group= */ NULL, ret) #define option_parser_get_help_table_group(group, ret) \ diff --git a/src/shared/parse-argument.c b/src/shared/parse-argument.c index 0d4bfa4c91..bfd21a910e 100644 --- a/src/shared/parse-argument.c +++ b/src/shared/parse-argument.c @@ -31,7 +31,7 @@ int parse_boolean_argument(const char *optname, const char *s, bool *ret) { *ret = r; return r; } else { - /* s may be NULL. This is controlled by getopt_long() parameters. */ + /* s may be NULL. This is controlled by OPTION flags. */ if (ret) *ret = true; return true; @@ -42,10 +42,10 @@ int parse_tristate_argument_with_auto(const char *optname, const char *s, int *r int r; assert(optname); - assert(s); /* We refuse NULL optarg here, since that would be ambiguous on cmdline: - for --enable-a[=BOOL], --enable-a is intuitively interpreted as true rather than "auto" - (parse_boolean_argument() does exactly that). IOW, tristate options should require - arguments. */ + assert(s); /* We refuse NULL arg here, since that would be ambiguous on cmdline: for + * --enable-a[=BOOL], --enable-a is intuitively interpreted as true rather than "auto" + * (parse_boolean_argument() does exactly that). IOW, tristate options should require + * arguments. */ r = parse_tristate_full(s, "auto", ret); if (r < 0) diff --git a/src/shared/tests.c b/src/shared/tests.c index 84945343a4..176c7fb13f 100644 --- a/src/shared/tests.c +++ b/src/shared/tests.c @@ -380,20 +380,18 @@ int run_test_table(const TestFunc *start, const TestFunc *end) { _cleanup_strv_free_ char **tests = NULL; int r = EXIT_SUCCESS; bool ran = false; - const char *e; if (!start) return r; - e = getenv("TESTFUNCS"); + const char *e = getenv("TESTFUNCS"); if (e) { r = strv_split_full(&tests, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS); if (r < 0) return log_error_errno(r, "Failed to parse $TESTFUNCS: %m"); } - for (const TestFunc *t = ALIGN_PTR(start); t + 1 <= end; t = ALIGN_PTR(t + 1)) { - + for (const TestFunc *t = start; t + 1 <= end; t++) { if (tests && !strv_contains(tests, t->name)) continue; diff --git a/src/shared/verbs.c b/src/shared/verbs.c index aab24c0681..34e8a897d6 100644 --- a/src/shared/verbs.c +++ b/src/shared/verbs.c @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - #include "env-util.h" #include "format-table.h" #include "log.h" @@ -66,6 +64,9 @@ static bool verb_is_metadata(const Verb *verb) { const Verb* verbs_find_verb(const char *name, const Verb verbs[], const Verb verbs_end[]) { assert(verbs); + assert(verbs_end > verbs); + assert((uintptr_t) verbs % sizeof(void*) == 0); + assert(verbs[0].verb); for (const Verb *verb = verbs; verb < verbs_end; verb++) { if (verb_is_metadata(verb)) @@ -79,11 +80,12 @@ const Verb* verbs_find_verb(const char *name, const Verb verbs[], const Verb ver return NULL; } -int _dispatch_verb_with_args(char **args, const Verb verbs[], const Verb verbs_end[], void *userdata) { +int _dispatch_verb(char **args, const Verb verbs[], const Verb verbs_end[], void *userdata) { int r; assert(verbs); assert(verbs_end > verbs); + assert((uintptr_t) verbs % sizeof(void*) == 0); assert(verbs[0].verb); const char *name = args ? args[0] : NULL; @@ -146,21 +148,6 @@ int _dispatch_verb_with_args(char **args, const Verb verbs[], const Verb verbs_e return verb->dispatch(left, args, verb->data, userdata); } -int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) { - /* getopt wrapper for _dispatch_verb_with_args. - * TBD: remove this function when all programs with verbs have been converted. */ - - assert(argc >= 0); - assert(argv); - assert(argc >= optind); - - size_t n = 0; - while (verbs[n].verb) - n++; - - return _dispatch_verb_with_args(strv_skip(argv, optind), verbs, verbs + n, userdata); -} - #define VERB_SYNOPSIS_WIDTH_SANE 25 static const char* find_point_to_break(const char *s, size_t max_width) { @@ -234,6 +221,9 @@ int _verbs_get_help_table( Table **ret) { int r; + assert(verbs); + assert(verbs_end > verbs); + assert((uintptr_t) verbs % sizeof(void*) == 0); assert(ret); _cleanup_(table_unrefp) Table *table = table_new("verb", "help"); diff --git a/src/shared/verbs.h b/src/shared/verbs.h index e071cc5d89..2a9df84e0c 100644 --- a/src/shared/verbs.h +++ b/src/shared/verbs.h @@ -79,11 +79,9 @@ bool should_bypass(const char *env_prefix); const Verb* verbs_find_verb(const char *name, const Verb verbs[], const Verb verbs_end[]); -int _dispatch_verb_with_args(char **args, const Verb verbs[], const Verb verbs_end[], void *userdata); -#define dispatch_verb_with_args(args, userdata) \ - _dispatch_verb_with_args(args, ALIGN_PTR(__start_SYSTEMD_VERBS), __stop_SYSTEMD_VERBS, userdata) - -int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata); +int _dispatch_verb(char **args, const Verb verbs[], const Verb verbs_end[], void *userdata); +#define dispatch_verb(args, userdata) \ + _dispatch_verb(args, __start_SYSTEMD_VERBS, __stop_SYSTEMD_VERBS, userdata) int _verbs_get_help_table( const Verb verbs[], @@ -91,7 +89,7 @@ int _verbs_get_help_table( const char *group, Table **ret); #define verbs_get_help_table_group(group, ret) \ - _verbs_get_help_table(ALIGN_PTR(__start_SYSTEMD_VERBS), __stop_SYSTEMD_VERBS, group, ret) + _verbs_get_help_table(__start_SYSTEMD_VERBS, __stop_SYSTEMD_VERBS, group, ret) #define verbs_get_help_table(ret) \ verbs_get_help_table_group(/* group= */ NULL, ret) diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 53f306a8fa..24cd632111 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -760,7 +760,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return r; - return dispatch_verb_with_args(args, sleep_config); + return dispatch_verb(args, sleep_config); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/ssh-generator/ssh-issue.c b/src/ssh-generator/ssh-issue.c index 2028d3f942..dd2b2370b4 100644 --- a/src/ssh-generator/ssh-issue.c +++ b/src/ssh-generator/ssh-issue.c @@ -224,7 +224,7 @@ static int run(int argc, char* argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/storage/storagectl.c b/src/storage/storagectl.c index 1a10a09794..7e366c11a9 100644 --- a/src/storage/storagectl.c +++ b/src/storage/storagectl.c @@ -2,7 +2,6 @@ #include "sd-varlink.h" -#include #include #include #include @@ -59,7 +58,7 @@ static int help(void) { return r; _cleanup_(table_unrefp) Table *options = NULL; - r = option_parser_get_help_table(&options); + r = option_parser_get_help_table_ns("storagectl", &options); if (r < 0) return r; @@ -406,10 +405,12 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { assert(argv); assert(remaining_args); - OptionParser opts = { argc, argv }; + OptionParser opts = { argc, argv, .namespace = "storagectl" }; FOREACH_OPTION_OR_RETURN(c, &opts) switch (c) { + OPTION_NAMESPACE("storagectl"): {} + OPTION_COMMON_HELP: return help(); @@ -448,7 +449,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { } static int run_as_mount_helper(int argc, char *argv[]) { - int c, r; + int r; /* Implements util-linux "external helper" command line interface, as per mount(8) man page. * @@ -461,51 +462,55 @@ static int run_as_mount_helper(int argc, char *argv[]) { const char *fstype = NULL, *options = NULL; bool fake = false; - while ((c = getopt(argc, argv, "sfnvN:o:t:")) >= 0) { + OptionParser opts = { argc, argv, .namespace = "mount.storage" }; + FOREACH_OPTION_OR_RETURN(c, &opts) switch (c) { - case 'f': + OPTION_NAMESPACE("mount.storage"): {} + + OPTION_SHORT('f', NULL, /* help= */ NULL): fake = true; break; - case 'o': - options = optarg; + OPTION_SHORT('o', "OPTIONS", /* help= */ NULL): + options = opts.arg; break; - case 't': - fstype = startswith(optarg, "storage."); + OPTION_SHORT('t', "FSTYPE", /* help= */ NULL): + fstype = startswith(opts.arg, "storage."); if (fstype) { /* Paranoia: don't allow "storage.storage.storage.…" chains... */ if (startswith(fstype, "storage.") || streq(fstype, "storage")) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Refusing nested storage volumes."); - } else if (!streq(optarg, "storage")) - log_warning("Unexpected file system type '%s', ignoring.", optarg); + } else if (!streq(opts.arg, "storage")) + log_warning("Unexpected file system type '%s', ignoring.", opts.arg); break; - case 's': /* sloppy mount options */ - case 'n': /* aka --no-mtab */ - case 'v': /* aka --verbose */ - log_debug("Ignoring option -%c, not implemented.", c); + OPTION_SHORT('s', NULL, /* help= */ NULL): {} /* sloppy mount options */ + OPTION_SHORT('n', NULL, /* help= */ NULL): {} /* aka --no-mtab */ + OPTION_SHORT('v', NULL, /* help= */ NULL): /* aka --verbose */ + log_debug("Ignoring option -%c, not implemented.", opts.opt->short_code); break; - case 'N': /* aka --namespace= */ - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Option -%c is not implemented, refusing.", c); - - case '?': - return -EINVAL; + OPTION_SHORT('N', "NS", /* help= */ NULL): /* aka --namespace= */ + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Option -%c is not implemented, refusing.", + opts.opt->short_code); } - } - if (optind + 2 != argc) + char **args = option_parser_get_args(&opts); + size_t n_args = option_parser_get_n_args(&opts); + + if (n_args != 2) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected a storage volume specification and target directory as only arguments."); - const char *colon = strchr(argv[optind], ':'); + const char *colon = strchr(args[0], ':'); if (!colon) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid storage volume specification, refusing: %s", argv[optind]); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid storage volume specification, refusing: %s", args[0]); - _cleanup_free_ char *provider = strndup(argv[optind], colon - argv[optind]); + _cleanup_free_ char *provider = strndup(args[0], colon - args[0]); if (!provider) return log_oom(); if (!storage_provider_name_is_valid(provider)) @@ -518,7 +523,7 @@ static int run_as_mount_helper(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid storage volume name: %s", name); _cleanup_free_ char *path = NULL; - r = parse_path_argument(argv[optind+1], /* suppress_root= */ false, &path); + r = parse_path_argument(args[1], /* suppress_root= */ false, &path); if (r < 0) return r; @@ -735,7 +740,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, /* userdata= */ NULL); + return dispatch_verb(args, /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index ff00196cc6..a3b1ba6221 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -3048,7 +3048,7 @@ static int run(int argc, char *argv[]) { return EXIT_SUCCESS; } - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index d5473cdc0a..99244de767 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1112,13 +1112,13 @@ VERB_SCOPE(, verb_start, "condrestart", NULL, 2, VERB_ANY, VERB_SCOPE(, verb_is_active, "check", NULL, 2, VERB_ANY, VERB_ONLINE_ONLY, /* help= */ NULL); /* deprecated alias of is-active */ int systemctl_main(char **args) { - const Verb *verb = verbs_find_verb(args[0], - ALIGN_PTR(__start_SYSTEMD_VERBS), - __stop_SYSTEMD_VERBS); + assert((uintptr_t) __start_SYSTEMD_VERBS % sizeof(void*) == 0); + const Verb *verb = verbs_find_verb(args[0], __start_SYSTEMD_VERBS, __stop_SYSTEMD_VERBS); + if (verb && (verb->flags & VERB_ONLINE_ONLY) && arg_root) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Verb '%s' cannot be used with --root= or --image=.", args[0] ?: verb->verb); - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c index c64c5a9b95..425460a319 100644 --- a/src/sysupdate/sysupdate.c +++ b/src/sysupdate/sysupdate.c @@ -2010,7 +2010,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/sysupdate/updatectl.c b/src/sysupdate/updatectl.c index a256dc19c8..cf574a86e9 100644 --- a/src/sysupdate/updatectl.c +++ b/src/sysupdate/updatectl.c @@ -1757,7 +1757,7 @@ static int run(int argc, char *argv[]) { (void) sd_bus_set_allow_interactive_authorization(bus, true); - return dispatch_verb_with_args(args, bus); + return dispatch_verb(args, bus); } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/test/meson.build b/src/test/meson.build index 20960d0b95..4871c5517f 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -111,7 +111,6 @@ simple_tests += files( 'test-format-util.c', 'test-fs-util.c', 'test-fstab-util.c', - 'test-getopt.c', 'test-glob-util.c', 'test-gpt.c', 'test-gunicode.c', diff --git a/src/test/test-getopt.c b/src/test/test-getopt.c deleted file mode 100644 index 0ba1c678f2..0000000000 --- a/src/test/test-getopt.c +++ /dev/null @@ -1,516 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include - -#include "strv.h" -#include "tests.h" - -typedef struct Entry { - int opt; - const char *argument; - const char *nextarg; -} Entry; - -static void test_getopt_long_one( - char **argv, - const char *optstring, - const struct option *longopts, - const Entry *entries, - char **remaining) { - - _cleanup_free_ char *joined = strv_join(argv, ", "); - log_debug("/* %s(%s) */", __func__, joined); - - _cleanup_free_ char *saved_argv0 = NULL; - ASSERT_NOT_NULL(saved_argv0 = strdup(argv[0])); - - int c, argc = strv_length(argv); - size_t i = 0, n_entries = 0; - - for (const Entry *e = entries; e && e->opt != 0; e++) - n_entries++; - - optind = 0; - while ((c = getopt_long(argc, argv, optstring, longopts, NULL)) >= 0) { - if (c < 0x100) - log_debug("%c: %s", c, strna(optarg)); - else - log_debug("0x%x: %s", (unsigned) c, strna(optarg)); - - ASSERT_LT(i, n_entries); - ASSERT_EQ(c, entries[i].opt); - ASSERT_STREQ(optarg, entries[i].argument); - if (entries[i].nextarg) - ASSERT_STREQ(argv[optind], entries[i].nextarg); - i++; - } - - ASSERT_EQ(i, n_entries); - ASSERT_LE(optind, argc); - ASSERT_EQ(argc - optind, (int) strv_length(remaining)); - for (int j = optind; j < argc; j++) - ASSERT_STREQ(argv[j], remaining[j - optind]); - ASSERT_STREQ(argv[0], saved_argv0); -} - -TEST(getopt_long) { - enum { - ARG_VERSION = 0x100, - ARG_REQUIRED, - ARG_OPTIONAL, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version" , no_argument, NULL, ARG_VERSION }, - { "required1", required_argument, NULL, 'r' }, - { "required2", required_argument, NULL, ARG_REQUIRED }, - { "optional1", optional_argument, NULL, 'o' }, - { "optional2", optional_argument, NULL, ARG_OPTIONAL }, - {}, - }; - - test_getopt_long_one(STRV_MAKE("arg0"), - "hr:o::", options, - NULL, - NULL); - - test_getopt_long_one(STRV_MAKE("arg0", - "string1", - "string2", - "string3", - "string4"), - "hr:o::", options, - NULL, - STRV_MAKE("string1", - "string2", - "string3", - "string4")); - - test_getopt_long_one(STRV_MAKE("arg0", - "--", - "string1", - "--help", - "-h", - "string4"), - "hr:o::", options, - NULL, - STRV_MAKE("string1", - "--help", - "-h", - "string4")); - - test_getopt_long_one(STRV_MAKE("arg0", - "string1", - "string2", - "--", - "--", - "string4"), - "hr:o::", options, - NULL, - STRV_MAKE("string1", - "string2", - "--", - "string4")); - - test_getopt_long_one(STRV_MAKE("arg0", - "string1", - "string2", - "string3", - "string4", - "--"), - "hr:o::", options, - NULL, - STRV_MAKE("string1", - "string2", - "string3", - "string4")); - - test_getopt_long_one(STRV_MAKE("arg0", - "--help"), - "hr:o::", options, - (Entry[]) { - { 'h', NULL }, - {} - }, - NULL); - - test_getopt_long_one(STRV_MAKE("arg0", - "-h"), - "hr:o::", options, - (Entry[]) { - { 'h', NULL }, - {} - }, - NULL); - - test_getopt_long_one(STRV_MAKE("arg0", - "--help", - "string1", - "string2", - "string3", - "string4"), - "hr:o::", options, - (Entry[]) { - { 'h', NULL }, - {} - }, - STRV_MAKE("string1", - "string2", - "string3", - "string4")); - - test_getopt_long_one(STRV_MAKE("arg0", - "-h", - "string1", - "string2", - "string3", - "string4"), - "hr:o::", options, - (Entry[]) { - { 'h', NULL }, - {} - }, - STRV_MAKE("string1", - "string2", - "string3", - "string4")); - - test_getopt_long_one(STRV_MAKE("arg0", - "string1", - "string2", - "--help", - "string3", - "string4"), - "hr:o::", options, - (Entry[]) { - { 'h', NULL }, - {} - }, - STRV_MAKE("string1", - "string2", - "string3", - "string4")); - - test_getopt_long_one(STRV_MAKE("arg0", - "string1", - "string2", - "-h", - "string3", - "string4"), - "hr:o::", options, - (Entry[]) { - { 'h', NULL }, - {} - }, - STRV_MAKE("string1", - "string2", - "string3", - "string4")); - - test_getopt_long_one(STRV_MAKE("arg0", - "string1", - "string2", - "string3", - "string4", - "--help"), - "hr:o::", options, - (Entry[]) { - { 'h', NULL }, - {} - }, - STRV_MAKE("string1", - "string2", - "string3", - "string4")); - - test_getopt_long_one(STRV_MAKE("arg0", - "string1", - "string2", - "string3", - "string4", - "-h"), - "hr:o::", options, - (Entry[]) { - { 'h', NULL }, - {} - }, - STRV_MAKE("string1", - "string2", - "string3", - "string4")); - - test_getopt_long_one(STRV_MAKE("arg0", - "--required1", "reqarg1"), - "hr:o::", options, - (Entry[]) { - { 'r', "reqarg1" }, - {} - }, - NULL); - - test_getopt_long_one(STRV_MAKE("arg0", - "-r", "reqarg1"), - "hr:o::", options, - (Entry[]) { - { 'r', "reqarg1" }, - {} - }, - NULL); - - test_getopt_long_one(STRV_MAKE("arg0", - "string1", - "string2", - "-r", "reqarg1"), - "hr:o::", options, - (Entry[]) { - { 'r', "reqarg1" }, - {} - }, - STRV_MAKE("string1", - "string2")); - - test_getopt_long_one(STRV_MAKE("arg0", - "--optional1=optarg1"), - "hr:o::", options, - (Entry[]) { - { 'o', "optarg1" }, - {} - }, - NULL); - - test_getopt_long_one(STRV_MAKE("arg0", - "--optional1", "string1"), - "hr:o::", options, - (Entry[]) { - { 'o', NULL, "string1" }, - {} - }, - STRV_MAKE("string1")); - - test_getopt_long_one(STRV_MAKE("arg0", - "-ooptarg1"), - "hr:o::", options, - (Entry[]) { - { 'o', "optarg1" }, - {} - }, NULL); - - test_getopt_long_one(STRV_MAKE("arg0", - "-o", "string1"), - "hr:o::", options, - (Entry[]) { - { 'o', NULL, "string1" }, - {} - }, - STRV_MAKE("string1")); - - test_getopt_long_one(STRV_MAKE("arg0", - "string1", - "--help", - "--version", - "string2", - "--required1", "reqarg1", - "--required2", "reqarg2", - "--required1=reqarg3", - "--required2=reqarg4", - "string3", - "--optional1", "string4", - "--optional2", "string5", - "--optional1=optarg1", - "--optional2=optarg2", - "-h", - "-r", "reqarg5", - "-rreqarg6", - "-ooptarg3", - "-o", - "string6", - "-o", - "-h", - "-o", - "--help", - "string7", - "-hooptarg4", - "-hrreqarg6", - "--", - "--help", - "--required1", - "--optional1"), - "hr:o::", options, - (Entry[]) { - { 'h' }, - { ARG_VERSION }, - { 'r', "reqarg1" }, - { ARG_REQUIRED, "reqarg2" }, - { 'r', "reqarg3" }, - { ARG_REQUIRED, "reqarg4" }, - { 'o', NULL, "string4" }, - { ARG_OPTIONAL, NULL, "string5" }, - { 'o', "optarg1" }, - { ARG_OPTIONAL, "optarg2" }, - { 'h' }, - { 'r', "reqarg5" }, - { 'r', "reqarg6" }, - { 'o', "optarg3" }, - { 'o', NULL, "string6" }, - { 'o', NULL, "-h" }, - { 'h' }, - { 'o', NULL, "--help" }, - { 'h' }, - { 'h' }, - { 'o', "optarg4" }, - { 'h' }, - { 'r', "reqarg6" }, - {} - }, - STRV_MAKE("string1", - "string2", - "string3", - "string4", - "string5", - "string6", - "string7", - "--help", - "--required1", - "--optional1")); -} -static void test_getopt_one( - char **argv, - const char *optstring, - const Entry *entries, - char **remaining) { - - _cleanup_free_ char *joined = strv_join(argv, ", "); - log_debug("/* %s(%s) */", __func__, joined); - - _cleanup_free_ char *saved_argv0 = NULL; - ASSERT_NOT_NULL(saved_argv0 = strdup(argv[0])); - - int c, argc = strv_length(argv); - size_t i = 0, n_entries = 0; - - for (const Entry *e = entries; e && e->opt != 0; e++) - n_entries++; - - optind = 0; - while ((c = getopt(argc, argv, optstring)) >= 0) { - log_debug("%c: %s", c, strna(optarg)); - - ASSERT_LT(i, n_entries); - ASSERT_EQ(c, entries[i].opt); - ASSERT_STREQ(optarg, entries[i].argument); - if (entries[i].nextarg) - ASSERT_STREQ(argv[optind], entries[i].nextarg); - i++; - } - - ASSERT_EQ(i, n_entries); - ASSERT_LE(optind, argc); - ASSERT_EQ(argc - optind, (int) strv_length(remaining)); - for (int j = optind; j < argc; j++) - ASSERT_STREQ(argv[j], remaining[j - optind]); - ASSERT_STREQ(argv[0], saved_argv0); -} - -TEST(getopt) { - test_getopt_one(STRV_MAKE("arg0"), - "hr:o::", - NULL, - NULL); - - test_getopt_one(STRV_MAKE("arg0", - "string1", - "string2"), - "hr:o::", - NULL, - STRV_MAKE("string1", - "string2")); - - test_getopt_one(STRV_MAKE("arg0", - "-h"), - "hr:o::", - (Entry[]) { - { 'h', NULL }, - {} - }, - NULL); - - test_getopt_one(STRV_MAKE("arg0", - "-r", "reqarg1"), - "hr:o::", - (Entry[]) { - { 'r', "reqarg1" }, - {} - }, - NULL); - - test_getopt_one(STRV_MAKE("arg0", - "string1", - "string2", - "-r", "reqarg1"), - "hr:o::", - (Entry[]) { - { 'r', "reqarg1" }, - {} - }, - STRV_MAKE("string1", - "string2")); - - test_getopt_one(STRV_MAKE("arg0", - "-ooptarg1"), - "hr:o::", - (Entry[]) { - { 'o', "optarg1" }, - {} - }, - NULL); - - test_getopt_one(STRV_MAKE("arg0", - "-o", "string1"), - "hr:o::", - (Entry[]) { - { 'o', NULL, "string1" }, - {} - }, - STRV_MAKE("string1")); - - test_getopt_one(STRV_MAKE("arg0", - "string1", - "string2", - "string3", - "-h", - "-r", "reqarg5", - "-rreqarg6", - "-ooptarg3", - "-o", - "string6", - "-o", - "-h", - "-o", - "string7", - "-hooptarg4", - "-hrreqarg6"), - "hr:o::", - (Entry[]) { - { 'h' }, - { 'r', "reqarg5" }, - { 'r', "reqarg6" }, - { 'o', "optarg3" }, - { 'o', NULL, "string6" }, - { 'o', NULL, "-h" }, - { 'h' }, - { 'o', NULL, "string7" }, - { 'h' }, - { 'o', "optarg4" }, - { 'h' }, - { 'r', "reqarg6" }, - {} - }, - STRV_MAKE("string1", - "string2", - "string3", - "string6", - "string7")); -} - -DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/test/test-verbs.c b/src/test/test-verbs.c index 41ae5a87f3..56062b0bd6 100644 --- a/src/test/test-verbs.c +++ b/src/test/test-verbs.c @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - #include "strv.h" #include "tests.h" #include "verbs.h" @@ -11,8 +9,7 @@ static int noop_dispatcher(int argc, char *argv[], uintptr_t _data, void *userda } #define test_dispatch_one(argv, verbs, expected) \ - optind = 0; \ - assert_se(dispatch_verb(strv_length(argv), argv, verbs, NULL) == expected); + assert_se(_dispatch_verb(argv, verbs, verbs + ELEMENTSOF(verbs) - 1, NULL) == expected); TEST(verbs) { static const Verb verbs[] = { diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 7607b1ac4b..2c9ab9b6fd 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -1028,7 +1028,7 @@ static int run(int argc, char *argv[]) { (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password); - return dispatch_verb_with_args(args, bus); + return dispatch_verb(args, bus); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/udev/iocost/iocost.c b/src/udev/iocost/iocost.c index 1efd4a5365..a591ba40c0 100644 --- a/src/udev/iocost/iocost.c +++ b/src/udev/iocost/iocost.c @@ -308,7 +308,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index a252ec99dd..6d6108ee01 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -5,7 +5,6 @@ * Logic based on Hannes Reinecke's shell script. */ -#include #include #include #include diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c index f3c8936cad..fbed496c4e 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include #include #include "alloc-util.h" @@ -128,8 +127,6 @@ int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *comma if (r < 0) return r; - /* we need '0' here to reset the internal state */ - optind = 0; return builtins[cmd]->cmd(event, strv_length(argv), argv); } diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c index 7e2420a77e..8e90946960 100644 --- a/src/udev/udevadm-util.c +++ b/src/udev/udevadm-util.c @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include - #include "sd-bus.h" #include "alloc-util.h" diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index cdc1080274..9b7b09370a 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -115,7 +115,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c index 875ae9a09b..d27616c2cd 100644 --- a/src/update-utmp/update-utmp.c +++ b/src/update-utmp/update-utmp.c @@ -10,6 +10,7 @@ #include "libaudit-util.h" #include "log.h" #include "main-func.h" +#include "strv.h" #include "time-util.h" #include "utmp-wtmp.h" #include "verbs.h" @@ -51,6 +52,7 @@ static int get_startup_monotonic_time(Context *c, usec_t *ret) { return 0; } +VERB_NOARG(verb_on_reboot, "reboot", /* help= */ NULL); static int verb_on_reboot(int argc, char *argv[], uintptr_t _data, void *userdata) { Context *c = ASSERT_PTR(userdata); usec_t t = 0, boottime; @@ -80,6 +82,7 @@ static int verb_on_reboot(int argc, char *argv[], uintptr_t _data, void *userdat return q; } +VERB_NOARG(verb_on_shutdown, "shutdown", /* help= */ NULL); static int verb_on_shutdown(int argc, char *argv[], uintptr_t _data, void *userdata) { int r, q = 0; @@ -102,12 +105,6 @@ static int verb_on_shutdown(int argc, char *argv[], uintptr_t _data, void *userd } static int run(int argc, char *argv[]) { - static const Verb verbs[] = { - { "reboot", 1, 1, 0, verb_on_reboot }, - { "shutdown", 1, 1, 0, verb_on_shutdown }, - {} - }; - _cleanup_(context_clear) Context c = { .audit_fd = -EBADF, }; @@ -118,7 +115,7 @@ static int run(int argc, char *argv[]) { c.audit_fd = open_audit_fd_or_warn(); - return dispatch_verb(argc, argv, verbs, &c); + return dispatch_verb(strv_skip(argv, 1), &c); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index dd6fc0f5c1..fd349b2826 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -1874,7 +1874,7 @@ static int run(int argc, char *argv[]) { } else assert_se(unsetenv("SYSTEMD_ONLY_USERDB") == 0); - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/varlinkctl/varlinkctl.c b/src/varlinkctl/varlinkctl.c index fbd5e2499a..94a4bc40b3 100644 --- a/src/varlinkctl/varlinkctl.c +++ b/src/varlinkctl/varlinkctl.c @@ -1318,7 +1318,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - return dispatch_verb_with_args(args, NULL); + return dispatch_verb(args, NULL); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c index b5d57fd1fe..e9ce2bdfec 100644 --- a/src/veritysetup/veritysetup.c +++ b/src/veritysetup/veritysetup.c @@ -10,14 +10,15 @@ #include "cryptsetup-util.h" #include "extract-word.h" #include "fileio.h" +#include "format-table.h" #include "fstab-util.h" +#include "help-util.h" #include "hexdecoct.h" #include "log.h" #include "main-func.h" #include "parse-util.h" #include "path-util.h" #include "pcrextend-util.h" -#include "pretty-print.h" #include "string-util.h" #include "strv.h" #include "tpm2-util.h" @@ -50,21 +51,22 @@ STATIC_DESTRUCTOR_REGISTER(arg_root_hash_signature, freep); STATIC_DESTRUCTOR_REGISTER(arg_tpm2_measure_nvpcr, freep); static int help(void) { - _cleanup_free_ char *link = NULL; + _cleanup_(table_unrefp) Table *verbs = NULL; int r; - r = terminal_urlify_man("systemd-veritysetup@.service", "8", &link); + r = verbs_get_help_table(&verbs); if (r < 0) - return log_oom(); + return r; - printf("%s attach VOLUME DATADEVICE HASHDEVICE ROOTHASH [OPTIONS]\n" - "%s detach VOLUME\n\n" - "Attach or detach a verity protected block device.\n" - "\nSee the %s for details.\n", - program_invocation_short_name, - program_invocation_short_name, - link); + help_cmdline("COMMAND ..."); + help_abstract("Attach or detach a verity protected block device."); + help_section("Commands"); + r = table_print_or_warn(verbs); + if (r < 0) + return r; + + help_man_page_reference("systemd-veritysetup@.service", "8"); return 0; } @@ -315,6 +317,8 @@ static int parse_options(const char *options) { return r; } +VERB(verb_attach, "attach", "VOLUME DATADEVICE HASHDEVICE ROOTHASH [OPTIONS]", 5, 6, 0, + "Attach a verity protected block device"); static int verb_attach(int argc, char *argv[], uintptr_t _data, void *userdata) { _cleanup_(crypt_freep) struct crypt_device *cd = NULL; _cleanup_free_ void *rh = NULL; @@ -449,6 +453,8 @@ static int verb_attach(int argc, char *argv[], uintptr_t _data, void *userdata) return 0; } +VERB(verb_detach, "detach", "VOLUME", 2, 2, 0, + "Detach a verity protected block device"); static int verb_detach(int argc, char *argv[], uintptr_t _data, void *userdata) { _cleanup_(crypt_freep) struct crypt_device *cd = NULL; int r; @@ -491,13 +497,7 @@ static int run(int argc, char *argv[]) { umask(0022); - static const Verb verbs[] = { - { "attach", 5, 6, 0, verb_attach }, - { "detach", 2, 2, 0, verb_detach }, - {} - }; - - return dispatch_verb(argc, argv, verbs, NULL); + return dispatch_verb(strv_skip(argv, 1), /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run);