sysext: convert to VERB_COMMAND and add --introspect-cli

The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. --help now goes through the pager, like other
commands with --no-pager.

Also, previously, -h/--help/--version were listed in the "Commands"
section. This was cute, but recreating this in the new scheme would
be complicated. Also, it seems unnecessary. --help/--version and some
other commands terminate the program in all binaries, so they could
be considered "commands" in all cases. But we printed them together
with verbs only in a few cases. So I think it's fine to move them
back to the "Options" section. This makes the description of options
much more consistent between different programs.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2026-08-25 09:33:58 +02:00
parent b62d32c7b5
commit dfe557dc7c
2 changed files with 38 additions and 49 deletions
+26 -49
View File
@@ -38,7 +38,6 @@
#include "format-table.h"
#include "fs-util.h"
#include "hashmap.h"
#include "help-util.h"
#include "image-policy.h"
#include "initrd-util.h"
#include "label-util.h" /* IWYU pragma: keep */
@@ -49,7 +48,6 @@
#include "mkdir.h"
#include "mount-util.h"
#include "mountpoint-util.h"
#include "options.h"
#include "os-util.h"
#include "pager.h"
#include "parse-argument.h"
@@ -133,14 +131,27 @@ static ImageClass arg_image_class = IMAGE_SYSEXT;
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
COMMAND(
"systemd-sysext\0",
"Merge system extension images into /usr/ and /opt/.",
.man_pages = "systemd-sysext.8\0",
.flags = COMMAND_VERBS_SHARED,
.pager_flags = &arg_pager_flags,
);
COMMAND(
"systemd-confext\0",
"Merge configuration extension images into /etc/.",
.man_pages = "systemd-confext.8\0",
.flags = COMMAND_VERBS_SHARED,
.pager_flags = &arg_pager_flags,
);
/* Helper struct for naming simplicity and reusability */
static const struct {
const char *full_identifier;
const char *short_identifier;
const char *short_identifier_plural;
const char *polkit_rw_action_id;
const char *polkit_ro_action_id;
const char *blurb;
const char *dot_directory_name;
const char *directory_name;
const char *level_env;
@@ -152,12 +163,10 @@ static const struct {
unsigned long default_mount_flags;
} image_class_info[_IMAGE_CLASS_MAX] = {
[IMAGE_SYSEXT] = {
.full_identifier = "systemd-sysext",
.short_identifier = "sysext",
.short_identifier_plural = "extensions",
.polkit_rw_action_id = "io.systemd.sysext.manage",
.polkit_ro_action_id = "io.systemd.sysext.read",
.blurb = "Merge system extension images into /usr/ and /opt/.",
.dot_directory_name = ".systemd-sysext",
.level_env = "SYSEXT_LEVEL",
.scope_env = "SYSEXT_SCOPE",
@@ -168,12 +177,10 @@ static const struct {
.default_mount_flags = MS_RDONLY|MS_NODEV,
},
[IMAGE_CONFEXT] = {
.full_identifier = "systemd-confext",
.short_identifier = "confext",
.short_identifier_plural = "confexts",
.polkit_rw_action_id = "io.systemd.confext.manage",
.polkit_ro_action_id = "io.systemd.confext.read",
.blurb = "Merge configuration extension images into /etc/.",
.dot_directory_name = ".systemd-confext",
.level_env = "CONFEXT_LEVEL",
.scope_env = "CONFEXT_SCOPE",
@@ -3129,46 +3136,13 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
return 0;
}
static int help(void) {
_cleanup_(table_unrefp) Table *verbs = NULL, *commands = NULL, *options = NULL;
int r;
r = verbs_get_help_table(&verbs);
if (r < 0)
return r;
r = option_parser_get_help_table(&commands);
if (r < 0)
return r;
r = option_parser_get_help_table_group("Options", &options);
if (r < 0)
return r;
(void) table_sync_column_widths(0, verbs, commands, options);
help_cmdline("[OPTIONS...] COMMAND");
help_abstract(image_class_info[arg_image_class].blurb);
help_section("Commands");
r = table_print_or_warn(verbs);
if (r < 0)
return r;
r = table_print_or_warn(commands);
if (r < 0)
return r;
help_section("Options");
r = table_print_or_warn(options);
if (r < 0)
return r;
help_man_page_reference(image_class_info[arg_image_class].full_identifier, "8");
return 0;
VERB_FULL(verb_help, "help", NULL, VERB_ANY, VERB_ANY, 0, /* dat= */ 0u, /* help= */ NULL);
static int verb_help(int argc, char **argv, uintptr_t data, void *userdata) {
return command_print_help_full(
arg_image_class == IMAGE_SYSEXT ? "systemd-sysext" : "systemd-confext",
/* footer_ansi_seq= */ NULL);
}
VERB_COMMON_HELP_HIDDEN(help);
static int parse_argv(int argc, char *argv[], char ***ret_args) {
int r;
@@ -3182,13 +3156,13 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
switch (c) {
OPTION_COMMON_HELP:
return help();
return command_print_help_full(
arg_image_class == IMAGE_SYSEXT ? "systemd-sysext" : "systemd-confext",
/* footer_ansi_seq= */ NULL);
OPTION_COMMON_VERSION:
return version();
OPTION_GROUP("Options"): {}
OPTION_LONG("root", "PATH", "Operate relative to root PATH"):
r = parse_path_argument(opts.arg, false, &arg_root);
if (r < 0)
@@ -3255,6 +3229,9 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
if (r <= 0)
return r;
break;
OPTION_COMMON_INTROSPECT_CLI:
return introspect_cli(arg_json_format_flags);
}
r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT);
@@ -53,6 +53,7 @@ INTROSPECTABLE=(
systemd-cgls
systemd-cgtop
systemd-clonesetup
systemd-confext
systemd-creds
systemd-cryptenroll
systemd-cryptsetup
@@ -110,6 +111,7 @@ INTROSPECTABLE=(
systemd-storage-fs
systemd-storagetm
systemd-sysctl
systemd-sysext
systemd-sysinstall
systemd-sysupdate
systemd-sysusers
@@ -185,5 +187,15 @@ systemd-mstack --introspect-cli | jq -e \
systemd-run --introspect-cli | jq -e \
'[.commands[].names[0]] | sort == ["run0", "systemd-run"]'
if command -v systemd-sysext >/dev/null; then
systemd-sysext --introspect-cli | jq -e \
'[.commands[].names[0]] | sort == ["systemd-confext", "systemd-sysext"]'
systemd-sysext --introspect-cli | jq -e \
'.commands[0].verbs | map(.names[0]) | contains(["status", "merge", "unmerge"])'
systemd-confext --introspect-cli | jq -e \
'.commands[0].verbs | map(.names[0]) | contains(["status", "merge", "unmerge"])'
fi
systemctl --introspect-cli | jq -e \
'[.commands[].names[0]] | sort == ["halt", "poweroff", "reboot", "shutdown", "systemctl"]'