From: Zbigniew Jędrzejewski-Szmek Date: Wed, 29 Apr 2026 21:22:45 +0000 (+0200) Subject: various: convert "services" to option macros X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e71074f761a9a9ab984f96f530fce20eb8fbc171;p=thirdparty%2Fsystemd.git various: convert "services" to option macros Here we have the unusual situation that the option list is conditionalized. I thought about embedding some "tag" information in individual options to allow the options to be filtered by some arbitrary conditions. But it seems that using groups works quite well. It wouldn't scale well if there was a lot more options and conditions, but for the current set it's good enough. For options that are not supported in a given service, we print a custom message ("This service does not support [this] option"), instead of the generic "Unknown option …". I think this is actually better: we don't have to pretent that we don't know about the option, and can directly say that the it's a valid option in general but this service does not support it (yet). This converts systemd-homed, systemd-hostnamed, systemd-importd, systemd-localed, systemd-logind, systemd-machined, systemd-networkd, systemd-portabled, systemd-resolved, systemd-sysupdated, systemd-timedated, and systemd-timesyncd. When we add introspection of the option data, we'll somehow have to deal with conditionalization. But let's cross that bridge when we need to. --- diff --git a/src/shared/service-util.c b/src/shared/service-util.c index 70d59af6c51..7c1df8e73ad 100644 --- a/src/shared/service-util.c +++ b/src/shared/service-util.c @@ -1,53 +1,53 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include #include -#include "alloc-util.h" #include "build.h" #include "bus-object.h" +#include "format-table.h" +#include "help-util.h" #include "log.h" -#include "pretty-print.h" +#include "options.h" #include "runtime-scope.h" #include "service-util.h" -typedef enum HelpFlags { - HELP_WITH_BUS_INTROSPECT = 1 << 0, - HELP_WITH_RUNTIME_SCOPE = 1 << 1, -} HelpFlags; - -static int help(const char *program_path, - const char *service, +static int help(const char *service, const char *description, - HelpFlags flags) { + bool with_bus_introspect, + bool with_runtime_scope) { - _cleanup_free_ char *link = NULL; + static const char* const groups[] = { + NULL, + "Bus introspection", + "Runtime scope", + }; + + bool conds[ELEMENTSOF(groups)] = { true, with_bus_introspect, with_runtime_scope }; + Table* tables[ELEMENTSOF(groups)] = {}; + CLEANUP_ELEMENTS(tables, table_unref_array_clear); int r; - r = terminal_urlify_man(service, "8", &link); - if (r < 0) - return log_oom(); - - printf("%1$s [OPTIONS...]\n" - "\n%5$s%7$s%6$s\n" - "\nThis program takes no positional arguments.\n" - "\n%3$sOptions:%4$s\n" - " -h --help Show this help\n" - " --version Show package version\n" - "%8$s" - "%9$s" - "\nSee the %2$s for details.\n", - program_path, - link, - ansi_underline(), - ansi_normal(), - ansi_highlight(), - ansi_normal(), - description, - FLAGS_SET(flags, HELP_WITH_BUS_INTROSPECT) ? " --bus-introspect=PATH Write D-Bus XML introspection data\n" : "", - FLAGS_SET(flags, HELP_WITH_RUNTIME_SCOPE) ? " --system Start service in system mode\n" - " --user Start service in user mode\n" : ""); + for (size_t i = 0; i < ELEMENTSOF(groups); i++) + if (conds[i]) { + r = option_parser_get_help_table_group(groups[i], &tables[i]); + if (r < 0) + return r; + } + + (void) table_sync_column_widths(0, tables[0], tables[1] ?: tables[2], tables[1] ? tables[2] : NULL); + + help_cmdline("[OPTIONS...]"); + help_abstract(description); + help_section("Options"); + for (size_t i = 0; i < ELEMENTSOF(groups); i++) + if (conds[i]) { + r = table_print_or_warn(tables[i]); + if (r < 0) + return r; + } + + help_man_page_reference(service, "8"); return 0; /* No further action */ } @@ -58,64 +58,50 @@ int service_parse_argv( RuntimeScope *runtime_scope, int argc, char *argv[]) { - enum { - ARG_VERSION = 0x100, - ARG_BUS_INTROSPECT, - ARG_SYSTEM, - ARG_USER, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT }, - { "system", no_argument, NULL, ARG_SYSTEM }, - { "user", no_argument, NULL, ARG_USER }, - {} - }; - - int c; - assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) + OptionParser opts = { argc, argv }; + + FOREACH_OPTION_OR_RETURN(c, &opts) switch (c) { - case 'h': - return help(argv[0], - service, + OPTION_COMMON_HELP: + return help(service, description, - (bus_objects ? HELP_WITH_BUS_INTROSPECT : 0) | - (runtime_scope ? HELP_WITH_RUNTIME_SCOPE : 0)); + /* with_bus_introspect= */ bus_objects, + /* with_runtime_scope= */ runtime_scope); - case ARG_VERSION: + OPTION_COMMON_VERSION: return version(); - case ARG_BUS_INTROSPECT: - return bus_introspect_implementations( - stdout, - optarg, - bus_objects); + OPTION_GROUP("Bus introspection"): {} - case ARG_SYSTEM: - case ARG_USER: - if (!runtime_scope) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This service cannot be run in --system or --user mode, refusing."); + OPTION_LONG("bus-introspect", "PATH", "Write D-Bus XML introspection data"): + /* The option is defined in the shared option table, but it's not supported in this binary, + * so we pretend it doesn't exist. */ + if (!bus_objects) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "This service does not support the --bus-introspect= option."); - *runtime_scope = c == ARG_SYSTEM ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER; - break; + return bus_introspect_implementations(stdout, opts.arg, bus_objects); - case '?': - return -EINVAL; + OPTION_GROUP("Runtime scope"): {} - default: - assert_not_reached(); + OPTION_LONG_DATA("system", NULL, /* data= */ RUNTIME_SCOPE_SYSTEM, + "Start service in system mode"): {} + OPTION_LONG_DATA("user", NULL, /* data= */ RUNTIME_SCOPE_USER, + "Start service in user mode"): + if (!runtime_scope) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "This service does not support the --system/--user options."); + + *runtime_scope = opts.opt->data; + break; } - if (optind < argc) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "This program takes no arguments."); + if (option_parser_get_n_args(&opts) > 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments."); return 1; /* Further action */ }