/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#include <getopt.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#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"
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"
" 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;
}
}
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 */
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 */