From: Zbigniew Jędrzejewski-Szmek Date: Sat, 4 Apr 2026 18:16:28 +0000 (+0200) Subject: varlinkctl: convert to the new option parser X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e1eae0cf7816db8c7d3eca8d0d64b2705b37b153;p=thirdparty%2Fsystemd.git varlinkctl: convert to the new option parser The -E short option previously used fallthrough into the --more case; since macro-generated case labels don't support fallthrough (with some older compilers), the --more logic is now duplicated inline in the -E handler. Co-developed-by: Claude Opus 4.6 --- diff --git a/src/varlinkctl/varlinkctl.c b/src/varlinkctl/varlinkctl.c index 4124d0d5707..2dc191bff32 100644 --- a/src/varlinkctl/varlinkctl.c +++ b/src/varlinkctl/varlinkctl.c @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include #include #include #include @@ -20,6 +19,7 @@ #include "log.h" #include "main-func.h" #include "memfd-util.h" +#include "options.h" #include "pager.h" #include "parse-argument.h" #include "parse-util.h" @@ -72,17 +72,22 @@ STATIC_DESTRUCTOR_REGISTER(arg_push_fds, push_fds_done); static int help(void) { _cleanup_free_ char *link = NULL; + _cleanup_(table_unrefp) Table *options = NULL; int r; r = terminal_urlify_man("varlinkctl", "1", &link); if (r < 0) return log_oom(); + r = option_parser_get_help_table(&options); + if (r < 0) + return r; + pager_open(arg_pager_flags); printf("%1$s [OPTIONS...] COMMAND ...\n\n" - "%5$sIntrospect Varlink Services.%6$s\n" - "\n%3$sCommands:%4$s\n" + "%3$sIntrospect Varlink Services.%4$s\n" + "\n%2$sCommands:%4$s\n" " info ADDRESS Show service information\n" " list-interfaces ADDRESS\n" " List interfaces implemented by service\n" @@ -98,33 +103,17 @@ static int help(void) { " list-registry Show list of services in the service registry\n" " validate-idl [FILE] Validate interface description\n" " help Show this help\n" - "\n%3$sOptions:%4$s\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --no-ask-password Do not prompt for password\n" - " --no-pager Do not pipe output into a pager\n" - " --system Enumerate system registry\n" - " --user Enumerate user registry\n" - " --more Request multiple responses\n" - " --collect Collect multiple responses in a JSON array\n" - " --oneway Do not request response\n" - " --json=MODE Output as JSON\n" - " -j Same as --json=pretty on tty, --json=short otherwise\n" - " -q --quiet Do not output method reply\n" - " --graceful=ERROR Treat specified Varlink error as success\n" - " --timeout=SECS Maximum time to wait for method call completion\n" - " -E Short for --more --timeout=infinity\n" - " --upgrade Request protocol upgrade (connection becomes raw\n" - " bidirectional pipe on stdin/stdout after reply)\n" - " --push-fd=FD Pass the specified fd along with method call\n" - "\nSee the %2$s for details.\n", + "\n%2$sOptions:%4$s\n", program_invocation_short_name, - link, ansi_underline(), - ansi_normal(), ansi_highlight(), ansi_normal()); + r = table_print_or_warn(options); + if (r < 0) + return r; + + printf("\nSee the %s for details.\n", link); return 0; } @@ -133,145 +122,121 @@ static int verb_help(int argc, char *argv[], uintptr_t _data, void *userdata) { } static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_NO_PAGER, - ARG_MORE, - ARG_ONEWAY, - ARG_JSON, - ARG_COLLECT, - ARG_GRACEFUL, - ARG_TIMEOUT, - ARG_EXEC, - ARG_UPGRADE, - ARG_PUSH_FD, - ARG_NO_ASK_PASSWORD, - ARG_USER, - ARG_SYSTEM, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "more", no_argument, NULL, ARG_MORE }, - { "oneway", no_argument, NULL, ARG_ONEWAY }, - { "json", required_argument, NULL, ARG_JSON }, - { "collect", no_argument, NULL, ARG_COLLECT }, - { "quiet", no_argument, NULL, 'q' }, - { "graceful", required_argument, NULL, ARG_GRACEFUL }, - { "timeout", required_argument, NULL, ARG_TIMEOUT }, - { "exec", no_argument, NULL, ARG_EXEC }, - { "upgrade", no_argument, NULL, ARG_UPGRADE }, - { "push-fd", required_argument, NULL, ARG_PUSH_FD }, - { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, - { "user", no_argument, NULL, ARG_USER }, - { "system", no_argument, NULL, ARG_SYSTEM }, - {}, - }; - - int c, r; + int r; assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hjqE", options, NULL)) >= 0) + OptionParser state = { argc, argv }; + const char *arg; + FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c) switch (c) { - case 'h': + OPTION_COMMON_HELP: return help(); - case ARG_VERSION: + OPTION_COMMON_VERSION: return version(); - case ARG_NO_PAGER: + OPTION_COMMON_NO_ASK_PASSWORD: + arg_ask_password = false; + break; + + OPTION_COMMON_NO_PAGER: arg_pager_flags |= PAGER_DISABLE; break; - case 'E': - arg_timeout = USEC_INFINITY; - _fallthrough_; + OPTION_LONG("system", NULL, "Enumerate system registry"): + arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; + break; - case ARG_MORE: - arg_method_flags = (arg_method_flags & ~SD_VARLINK_METHOD_ONEWAY) | SD_VARLINK_METHOD_MORE; + OPTION_LONG("user", NULL, "Enumerate user registry"): + arg_runtime_scope = RUNTIME_SCOPE_USER; break; - case ARG_ONEWAY: - arg_method_flags = (arg_method_flags & ~SD_VARLINK_METHOD_MORE) | SD_VARLINK_METHOD_ONEWAY; + OPTION_LONG("more", NULL, "Request multiple responses"): + arg_method_flags = (arg_method_flags & ~SD_VARLINK_METHOD_ONEWAY) | SD_VARLINK_METHOD_MORE; break; - case ARG_COLLECT: + OPTION_LONG("collect", NULL, "Collect multiple responses in a JSON array"): arg_collect = true; break; - case ARG_JSON: - r = parse_json_argument(optarg, &arg_json_format_flags); + OPTION_LONG("oneway", NULL, "Do not request response"): + arg_method_flags = (arg_method_flags & ~SD_VARLINK_METHOD_MORE) | SD_VARLINK_METHOD_ONEWAY; + break; + + OPTION_COMMON_JSON: + r = parse_json_argument(arg, &arg_json_format_flags); if (r <= 0) return r; - break; - case 'j': + OPTION_COMMON_LOWERCASE_J: arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO; break; - case 'q': + OPTION('q', "quiet", NULL, "Do not output method reply"): arg_quiet = true; break; - case ARG_GRACEFUL: - r = varlink_idl_qualified_symbol_name_is_valid(optarg); + OPTION_LONG("graceful", "ERROR", "Treat specified Varlink error as success"): + r = varlink_idl_qualified_symbol_name_is_valid(arg); if (r < 0) - return log_error_errno(r, "Failed to validate Varlink error name '%s': %m", optarg); + return log_error_errno(r, "Failed to validate Varlink error name '%s': %m", arg); if (r == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid Varlink error name: %s", optarg); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid Varlink error name: %s", arg); - if (strv_extend(&arg_graceful, optarg) < 0) + if (strv_extend(&arg_graceful, arg) < 0) return log_oom(); - break; - case ARG_TIMEOUT: - if (isempty(optarg)) { + OPTION_LONG("timeout", "SECS", "Maximum time to wait for method call completion"): + if (isempty(arg)) { arg_timeout = USEC_INFINITY; break; } - r = parse_sec(optarg, &arg_timeout); + r = parse_sec(arg, &arg_timeout); if (r < 0) - return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", optarg); + return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", arg); if (arg_timeout == 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Timeout cannot be zero."); - break; - case ARG_EXEC: - arg_exec = true; + OPTION_SHORT('E', NULL, "Short for --more --timeout=infinity"): + arg_timeout = USEC_INFINITY; + arg_method_flags = (arg_method_flags & ~SD_VARLINK_METHOD_ONEWAY) | SD_VARLINK_METHOD_MORE; break; - case ARG_UPGRADE: + OPTION_LONG("upgrade", NULL, + "Request protocol upgrade (connection becomes raw" + " bidirectional pipe on stdin/stdout after reply)"): arg_upgrade = true; break; - case ARG_PUSH_FD: { + OPTION_LONG("exec", NULL, "Invoke method and pass response and fds to command"): + arg_exec = true; + break; + + OPTION_LONG("push-fd", "FD", "Pass the specified fd along with method call"): { if (!GREEDY_REALLOC(arg_push_fds.fds, arg_push_fds.n_fds + 1)) return log_oom(); _cleanup_close_ int add_fd = -EBADF; - if (STARTSWITH_SET(optarg, "/", "./")) { + if (STARTSWITH_SET(arg, "/", "./")) { /* We usually expect a numeric fd spec, but as an extension let's treat this * as a path to open in read-only mode in case this is clearly an absolute or * relative path */ - add_fd = open(optarg, O_CLOEXEC|O_RDONLY|O_NOCTTY); + add_fd = open(arg, O_CLOEXEC|O_RDONLY|O_NOCTTY); if (add_fd < 0) - return log_error_errno(errno, "Failed to open '%s': %m", optarg); + return log_error_errno(errno, "Failed to open '%s': %m", arg); } else { - int parsed_fd = parse_fd(optarg); + int parsed_fd = parse_fd(arg); if (parsed_fd < 0) - return log_error_errno(parsed_fd, "Failed to parse --push-fd= parameter: %s", optarg); + return log_error_errno(parsed_fd, "Failed to parse --push-fd= parameter: %s", arg); /* Make a copy, so that the same fd could be used multiple times in a reasonable * way. This also validates the fd early */ @@ -283,24 +248,6 @@ static int parse_argv(int argc, char *argv[]) { arg_push_fds.fds[arg_push_fds.n_fds++] = TAKE_FD(add_fd); break; } - - case ARG_NO_ASK_PASSWORD: - arg_ask_password = false; - break; - - case ARG_USER: - arg_runtime_scope = RUNTIME_SCOPE_USER; - break; - - case ARG_SYSTEM: - arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; - break; - - case '?': - return -EINVAL; - - default: - assert_not_reached(); } /* If more than one reply is expected, imply JSON-SEQ output, and set SD_JSON_FORMAT_FLUSH */