From cf889036377092cbec6c5ec86fdf0dc1c9326032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sat, 16 May 2026 18:32:14 +0200 Subject: [PATCH 01/11] tree-wide: get rid of most uses of ALIGN_PTR This bothered me for a while, but I didn't think too much about it and just copied the existing usage pattern. But it really doesn't make sense. We expect the compiler to align the section properly. But if it didn't align it, applying alignment after the fact would just cause our pointer to point to the middle of the structure. That'd be even worse than a misaligned pointer. Similarly, when doing pointer arithmetic, p++ should really result in a value with the appropriate alignment. This is the basic principle of C pointer addition. So we really shouldn't try to adjust the pointer ourselves. At most, we can assert that it is indeed aligned in tests. --- src/basic/static-destruct.c | 3 +-- src/basic/static-destruct.h | 2 ++ src/libsystemd/sd-bus/bus-error.c | 21 ++++++++------------- src/libsystemd/sd-bus/test-bus-error.c | 15 ++++----------- src/shared/options.h | 7 +++---- src/shared/tests.c | 6 ++---- src/shared/verbs.c | 8 ++++++++ src/shared/verbs.h | 4 ++-- src/systemctl/systemctl.c | 6 +++--- 9 files changed, 33 insertions(+), 39 deletions(-) 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/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/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/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..bd665fc7fa 100644 --- a/src/shared/verbs.c +++ b/src/shared/verbs.c @@ -66,6 +66,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)) @@ -84,6 +87,7 @@ int _dispatch_verb_with_args(char **args, const Verb verbs[], const Verb verbs_e assert(verbs); assert(verbs_end > verbs); + assert((uintptr_t) verbs % sizeof(void*) == 0); assert(verbs[0].verb); const char *name = args ? args[0] : NULL; @@ -150,6 +154,7 @@ 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((uintptr_t) verbs % sizeof(void*) == 0); assert(argc >= 0); assert(argv); assert(argc >= optind); @@ -234,6 +239,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..a5d210c893 100644 --- a/src/shared/verbs.h +++ b/src/shared/verbs.h @@ -81,7 +81,7 @@ const Verb* verbs_find_verb(const char *name, const Verb verbs[], const Verb ver 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) + _dispatch_verb_with_args(args, __start_SYSTEMD_VERBS, __stop_SYSTEMD_VERBS, userdata) int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata); @@ -91,7 +91,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/systemctl/systemctl.c b/src/systemctl/systemctl.c index d5473cdc0a..6ea4e50fb4 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1112,9 +1112,9 @@ 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=.", From 8bc7cf64d1a8bbcc4a1f0ee2e08134f47265c59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 14 May 2026 00:51:33 +0200 Subject: [PATCH 02/11] udev: drop leftover includes of getopt.h Not sure why those were left and why clang-tidy didn't complain. --- src/udev/udev-builtin-path_id.c | 1 - src/udev/udev-builtin.c | 1 - src/udev/udevadm-util.c | 2 -- 3 files changed, 4 deletions(-) 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..80a8700a62 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" 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" From 59ce15c406ab9b2cbee93b4de37c65c16d7c0f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 14 May 2026 09:28:56 +0200 Subject: [PATCH 03/11] storagectl: convert run_as_mount_helper to OPTION macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the util-linux mount-helper interface (mount.storage), so all options stay hidden via help=NULL — they are not user-facing. The namespace "mount.storage" is distinct from the storagectl namespace used for the user-facing CLI. Co-developed-by: Claude Opus 4.7 --- src/storage/storagectl.c | 59 ++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/storage/storagectl.c b/src/storage/storagectl.c index 1a10a09794..e33d00bb64 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; From 59db1f482a77860bbce73ee1b780dabf4ae2557b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 15 May 2026 20:39:23 +0200 Subject: [PATCH 04/11] dissect: convert the other parser to option macros --- src/dissect/dissect.c | 55 +++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 25 deletions(-) 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; From 1bf6be01c09c475024b06f279e58a986af1c960b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 15 May 2026 21:00:51 +0200 Subject: [PATCH 05/11] backlight: convert verbs to VERB macros Place VERB() declarations directly above each dispatch function and use verbs_get_help_table() in help() so the command listing stays in sync. run() switches to dispatch_verb_with_args(); the argv_looks_like_help() shortcut is preserved since this is an internal tool with no proper option parsing. Co-developed-by: Claude Opus 4.7 (1M context) --- src/backlight/backlight.c | 40 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c index 69bd42ebcc..3c2a601403 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_with_args(strv_skip(argv, 1), /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run); From 062f6892b3777d1714784b3a4c4f0fa9f82d16d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 15 May 2026 21:11:40 +0200 Subject: [PATCH 06/11] integritysetup: convert verbs to VERB macros Place VERB() declarations above each dispatch function and use verbs_get_help_table() in help() so the command listing stays in sync. run() switches to dispatch_verb_with_args(); the argv_looks_like_help() shortcut is preserved since this is an internal tool with no proper option parsing. Co-developed-by: Claude Opus 4.7 (1M context) --- src/integritysetup/integritysetup.c | 37 +++++++++++++++-------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/integritysetup/integritysetup.c b/src/integritysetup/integritysetup.c index 9a373e124b..7126db6d66 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_with_args(strv_skip(argv, 1), /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run); From 65f83b0352d495ecccc914188c95f1bf17d4ab52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 15 May 2026 21:19:28 +0200 Subject: [PATCH 07/11] update-utmp: convert verbs to VERB macros There is no --help implemented, so both verbs don't get help strings. We should probably add --help + --version, and a proper description of the program, but I'm leaving that for later. Co-developed-by: Claude Opus 4.7 (1M context) --- src/update-utmp/update-utmp.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c index 875ae9a09b..bd10f42ea5 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_with_args(strv_skip(argv, 1), &c); } DEFINE_MAIN_FUNCTION(run); From e934c6209ac3d4dc9c273b6bc814d0d8b59be5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 15 May 2026 21:24:34 +0200 Subject: [PATCH 08/11] veritysetup: convert verbs to VERB macros Place VERB() declarations above each dispatch function and use verbs_get_help_table() in help(). run() switches to dispatch_verb_with_args(); the argv_looks_like_help() shortcut is preserved since this is an internal tool with no proper option parsing. Co-developed-by: Claude Opus 4.7 (1M context) --- src/veritysetup/veritysetup.c | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c index b5d57fd1fe..5f413cb83f 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_with_args(strv_skip(argv, 1), /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run); From 40fed88f8e0210815175dd01e9e50a98682d5754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 15 May 2026 21:29:37 +0200 Subject: [PATCH 09/11] test-verbs: dispatch via _dispatch_verb_with_args() directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops the global-optind dependency from the test helper. Verb fixtures stay inline as static const Verb[] — the section-based VERB() macro would force unique verb names across the three test cases, which they deliberately share to exercise overlap. Co-developed-by: Claude Opus 4.7 (1M context) --- src/test/test-verbs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/test-verbs.c b/src/test/test-verbs.c index 41ae5a87f3..cfff6ec728 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_with_args(argv, verbs, verbs + ELEMENTSOF(verbs) - 1, NULL) == expected); TEST(verbs) { static const Verb verbs[] = { From 39a36475394fc88da405d435c6bc94db935948c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 15 May 2026 21:37:04 +0200 Subject: [PATCH 10/11] tree-wide: get rid of old dispatch_verb Also rename dispatch_verb_with_args to dispatch_verb. --- src/analyze/analyze.c | 2 +- src/backlight/backlight.c | 2 +- src/bless-boot/bless-boot.c | 2 +- src/bootctl/bootctl.c | 2 +- src/busctl/busctl.c | 2 +- src/coredump/coredumpctl.c | 2 +- src/creds/creds.c | 2 +- src/cryptsetup/cryptsetup.c | 2 +- src/factory-reset/factory-reset-tool.c | 2 +- src/home/homectl.c | 2 +- src/home/test-homectl-prompts.c | 2 +- src/hostname/hostnamectl.c | 2 +- src/hwdb/hwdb.c | 2 +- src/id128/id128.c | 2 +- src/import/export.c | 2 +- src/import/import-fs.c | 2 +- src/import/import.c | 2 +- src/import/importctl.c | 2 +- src/import/pull.c | 2 +- src/integritysetup/integritysetup.c | 2 +- src/kernel-install/kernel-install.c | 2 +- src/keyutil/keyutil.c | 2 +- src/locale/localectl.c | 2 +- src/login/loginctl.c | 2 +- src/machine/machinectl.c | 2 +- src/measure/measure-tool.c | 2 +- src/network/networkctl.c | 2 +- src/oom/oomctl.c | 2 +- src/pcrlock/pcrlock.c | 2 +- src/portable/portablectl.c | 2 +- src/random-seed/random-seed-tool.c | 2 +- src/report/report.c | 2 +- src/resolve/resolvectl.c | 4 ++-- src/sbsign/sbsign.c | 2 +- src/shared/verbs.c | 18 +----------------- src/shared/verbs.h | 8 +++----- src/sleep/sleep.c | 2 +- src/ssh-generator/ssh-issue.c | 2 +- src/storage/storagectl.c | 2 +- src/sysext/sysext.c | 2 +- src/systemctl/systemctl.c | 2 +- src/sysupdate/sysupdate.c | 2 +- src/sysupdate/updatectl.c | 2 +- src/test/test-verbs.c | 2 +- src/timedate/timedatectl.c | 2 +- src/udev/iocost/iocost.c | 2 +- src/udev/udevadm.c | 2 +- src/update-utmp/update-utmp.c | 2 +- src/userdb/userdbctl.c | 2 +- src/varlinkctl/varlinkctl.c | 2 +- src/veritysetup/veritysetup.c | 2 +- 51 files changed, 54 insertions(+), 72 deletions(-) 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 3c2a601403..7e296c9ffc 100644 --- a/src/backlight/backlight.c +++ b/src/backlight/backlight.c @@ -656,7 +656,7 @@ static int run(int argc, char *argv[]) { umask(0022); - return dispatch_verb_with_args(strv_skip(argv, 1), /* userdata= */ NULL); + return dispatch_verb(strv_skip(argv, 1), /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run); 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/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/integritysetup/integritysetup.c b/src/integritysetup/integritysetup.c index 7126db6d66..bdf1b25473 100644 --- a/src/integritysetup/integritysetup.c +++ b/src/integritysetup/integritysetup.c @@ -210,7 +210,7 @@ static int run(int argc, char *argv[]) { umask(0022); - return dispatch_verb_with_args(strv_skip(argv, 1), /* userdata= */ 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/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/verbs.c b/src/shared/verbs.c index bd665fc7fa..e9e78c5b72 100644 --- a/src/shared/verbs.c +++ b/src/shared/verbs.c @@ -82,7 +82,7 @@ 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); @@ -150,22 +150,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((uintptr_t) verbs % sizeof(void*) == 0); - 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) { diff --git a/src/shared/verbs.h b/src/shared/verbs.h index a5d210c893..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, __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[], 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 e33d00bb64..7e366c11a9 100644 --- a/src/storage/storagectl.c +++ b/src/storage/storagectl.c @@ -740,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 6ea4e50fb4..99244de767 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1120,5 +1120,5 @@ int systemctl_main(char **args) { "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/test-verbs.c b/src/test/test-verbs.c index cfff6ec728..56062b0bd6 100644 --- a/src/test/test-verbs.c +++ b/src/test/test-verbs.c @@ -9,7 +9,7 @@ static int noop_dispatcher(int argc, char *argv[], uintptr_t _data, void *userda } #define test_dispatch_one(argv, verbs, expected) \ - assert_se(_dispatch_verb_with_args(argv, verbs, verbs + ELEMENTSOF(verbs) - 1, 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/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 bd10f42ea5..d27616c2cd 100644 --- a/src/update-utmp/update-utmp.c +++ b/src/update-utmp/update-utmp.c @@ -115,7 +115,7 @@ static int run(int argc, char *argv[]) { c.audit_fd = open_audit_fd_or_warn(); - return dispatch_verb_with_args(strv_skip(argv, 1), &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 5f413cb83f..e9ce2bdfec 100644 --- a/src/veritysetup/veritysetup.c +++ b/src/veritysetup/veritysetup.c @@ -497,7 +497,7 @@ static int run(int argc, char *argv[]) { umask(0022); - return dispatch_verb_with_args(strv_skip(argv, 1), /* userdata= */ NULL); + return dispatch_verb(strv_skip(argv, 1), /* userdata= */ NULL); } DEFINE_MAIN_FUNCTION(run); From d512d3c6d30be6697f36bf042f95816cb6ad36c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 15 May 2026 20:32:29 +0200 Subject: [PATCH 11/11] treewide: get rid of remaing getopt/getopt_long stuff --- .clang-tidy | 1 - src/basic/argv-util.c | 2 +- src/include/musl/getopt.h | 29 -- src/include/musl/unistd.h | 8 - src/libc/musl/getopt.c | 100 ------- src/libc/musl/meson.build | 1 - src/shared/parse-argument.c | 10 +- src/shared/verbs.c | 2 - src/test/meson.build | 1 - src/test/test-getopt.c | 516 ------------------------------------ src/udev/udev-builtin.c | 2 - 11 files changed, 6 insertions(+), 666 deletions(-) delete mode 100644 src/include/musl/getopt.h delete mode 100644 src/libc/musl/getopt.c delete mode 100644 src/test/test-getopt.c 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/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/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/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/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/verbs.c b/src/shared/verbs.c index e9e78c5b72..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" 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/udev/udev-builtin.c b/src/udev/udev-builtin.c index 80a8700a62..fbed496c4e 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -127,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); }