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 <noreply@anthropic.com>
This commit is contained in:
+69
-122
@@ -1,6 +1,5 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@@ -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:
|
||||
OPTION_LONG("user", NULL, "Enumerate user registry"):
|
||||
arg_runtime_scope = RUNTIME_SCOPE_USER;
|
||||
break;
|
||||
|
||||
OPTION_LONG("more", NULL, "Request multiple responses"):
|
||||
arg_method_flags = (arg_method_flags & ~SD_VARLINK_METHOD_ONEWAY) | SD_VARLINK_METHOD_MORE;
|
||||
break;
|
||||
|
||||
case ARG_ONEWAY:
|
||||
arg_method_flags = (arg_method_flags & ~SD_VARLINK_METHOD_MORE) | SD_VARLINK_METHOD_ONEWAY;
|
||||
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);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
OPTION_LONG("oneway", NULL, "Do not request response"):
|
||||
arg_method_flags = (arg_method_flags & ~SD_VARLINK_METHOD_MORE) | SD_VARLINK_METHOD_ONEWAY;
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
OPTION_COMMON_JSON:
|
||||
r = parse_json_argument(arg, &arg_json_format_flags);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
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 */
|
||||
|
||||
Reference in New Issue
Block a user