diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 18d554ab1a..24b4ff6cd4 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -2,10 +2,10 @@ #include +#include "sd-json.h" + #include "argv-util.h" #include "dlopen-note.h" -#include "format-table.h" -#include "help-util.h" #include "label-util.h" #include "main-func.h" #include "options.h" @@ -14,51 +14,33 @@ #include "udevd.h" #include "verbs.h" -static int help(void) { - _cleanup_(table_unrefp) Table *verbs = NULL, *options = NULL; - int r; +COMMAND( + "udevadm\0", + "Send control commands or test the device manager.", + .argspec = "COMMAND [COMMAND OPTION…]\0", + .man_pages = "udevadm(8)\0", + .option_namespace = "udevadm", +); - r = verbs_get_help_table(&verbs); - if (r < 0) - return r; +/* All verbs are defined here, right after the COMMAND, so that they are attributed to it. Each + * subcommand parses its own options from the "udevadm-" namespace, see udevadm-*.c. */ +VERB_COMMON_HELP_AUTO_PROGRAM("udevadm"); - r = option_parser_get_help_table_ns("udevadm", &options); - if (r < 0) - return r; +#define UDEVADM_VERB(fn, name, args, help) \ + VERB_SCOPE_NS(, fn, name, "udevadm-" name, args, VERB_ANY, VERB_ANY, 0, help) - (void) table_sync_column_widths(0, verbs, options); - - help_cmdline("[OPTIONS…] COMMAND [COMMAND OPTIONS…]"); - help_abstract("Send control commands or test the device manager."); - - help_section("Commands"); - r = table_print_or_warn(verbs); - if (r < 0) - return r; - - help_section("Options"); - r = table_print_or_warn(options); - if (r < 0) - return r; - - help_man_page_reference("udevadm", "8"); - return 0; -} - -VERB_COMMON_HELP(help); - -VERB_SCOPE(, verb_info_main, "info", "[DEVPATH|FILE]\0", VERB_ANY, VERB_ANY, 0, "Query sysfs or the udev database"); -VERB_SCOPE(, verb_trigger_main, "trigger", "DEVPATH\0", VERB_ANY, VERB_ANY, 0, "Request events from the kernel"); -VERB_SCOPE(, verb_settle_main, "settle", NULL, VERB_ANY, VERB_ANY, 0, "Wait for pending udev events"); -VERB_SCOPE(, verb_control_main, "control", "OPTION\0", VERB_ANY, VERB_ANY, 0, "Control the udev daemon"); -VERB_SCOPE(, verb_monitor_main, "monitor", NULL, VERB_ANY, VERB_ANY, 0, "Listen to kernel and udev events"); -VERB_SCOPE(, verb_test_main, "test", "DEVPATH\0", VERB_ANY, VERB_ANY, 0, "Test an event run"); -VERB_SCOPE(, verb_builtin_main, "test-builtin", "COMMAND DEVPATH\0", VERB_ANY, VERB_ANY, 0, "Test a built-in command"); -VERB_SCOPE(, verb_verify_main, "verify", "[FILE…]\0", VERB_ANY, VERB_ANY, 0, "Verify udev rules files"); -VERB_SCOPE(, verb_cat_main, "cat", "[FILE…]\0", VERB_ANY, VERB_ANY, 0, "Show udev rules files"); -VERB_SCOPE(, verb_wait_main, "wait", "DEVICE [DEVICE…]\0", VERB_ANY, VERB_ANY, 0, "Wait for device or device symlink"); -VERB_SCOPE(, verb_lock_main, "lock", "[OPTIONS…] COMMAND\0", VERB_ANY, VERB_ANY, 0, "Lock a block device"); -VERB_SCOPE(, verb_hwdb_main, "hwdb", NULL, VERB_ANY, VERB_ANY, 0, /* help= */ NULL); /* deprecated */ +UDEVADM_VERB(verb_info_main, "info", "[DEVPATH|FILE]\0", "Query sysfs or the udev database"); +UDEVADM_VERB(verb_trigger_main, "trigger", "DEVPATH\0", "Request events from the kernel"); +UDEVADM_VERB(verb_settle_main, "settle", NULL, "Wait for pending udev events"); +UDEVADM_VERB(verb_control_main, "control", "OPTION\0", "Control the udev daemon"); +UDEVADM_VERB(verb_monitor_main, "monitor", NULL, "Listen to kernel and udev events"); +UDEVADM_VERB(verb_test_main, "test", "DEVPATH\0", "Test an event run"); +UDEVADM_VERB(verb_builtin_main, "test-builtin", "COMMAND DEVPATH\0", "Test a built-in command"); +UDEVADM_VERB(verb_verify_main, "verify", "[FILE…]\0", "Verify udev rules files"); +UDEVADM_VERB(verb_cat_main, "cat", "[FILE…]\0", "Show udev rules files"); +UDEVADM_VERB(verb_wait_main, "wait", "DEVICE [DEVICE…]\0", "Wait for device or device symlink"); +UDEVADM_VERB(verb_lock_main, "lock", "COMMAND\0", "Lock a block device"); +UDEVADM_VERB(verb_hwdb_main, "hwdb", NULL, /* help= */ NULL); /* deprecated */ VERB_NOARG(verb_version_main, "version", /* help= */ NULL); static int verb_version_main(int argc, char *argv[], uintptr_t _data, void *userdata) { @@ -78,7 +60,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { OPTION_NAMESPACE("udevadm"): {} OPTION_COMMON_HELP: - return help(); + return command_print_help_name("udevadm"); OPTION_COMMON_VERSION_WITH_HIDDEN_V: return print_version(); @@ -86,6 +68,9 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { OPTION('d', "debug", NULL, "Enable debug logging"): log_set_max_level(LOG_DEBUG); break; + + OPTION_COMMON_INTROSPECT_CLI: + return introspect_cli(SD_JSON_FORMAT_OFF); } *remaining_args = option_parser_get_args(&opts); diff --git a/test/units/TEST-74-AUX-UTILS.introspect-cli.sh b/test/units/TEST-74-AUX-UTILS.introspect-cli.sh index c80b1c41eb..30c8762905 100755 --- a/test/units/TEST-74-AUX-UTILS.introspect-cli.sh +++ b/test/units/TEST-74-AUX-UTILS.introspect-cli.sh @@ -143,6 +143,7 @@ INTROSPECTABLE=( systemd-vmspawn systemd-vpick timedatectl + udevadm updatectl userdbctl v4l_id @@ -208,6 +209,11 @@ fi systemd-id128 --introspect-cli | jq -e \ '.commands[0].verbs | map(.names[0]) | contains(["new", "machine-id", "show", "help"])' +# udevadm's verbs carry their own options, reported recursively +udevadm --introspect-cli | jq -e \ + '.commands[] | select(.names[0] == "udevadm") | .verbs[] | select(.names[0] == "info") | + [.options[].names[-1]] | contains(["--query", "--json", "--no-pager"])' + # systemd is optionally a multicall binary that also provides systemd-executor if [[ "$(readlink "$(command -v systemd-executor)" 2>/dev/null)" == systemd ]]; then systemd --introspect-cli | jq -e \