diff --git a/src/shared/verbs.c b/src/shared/verbs.c index d65999dd70..8515dbecf7 100644 --- a/src/shared/verbs.c +++ b/src/shared/verbs.c @@ -175,10 +175,11 @@ static int verb_add_help_one(Table *table, const Verb *verb) { assert(table); assert(verb); - bool is_default = FLAGS_SET(verb->flags, VERB_DEFAULT); _cleanup_free_ char *cell = NULL; int r; + bool is_default = FLAGS_SET(verb->flags, VERB_DEFAULT); + /* The synopsis cell contains one line per entry in the argspec nulstr. An unset argspec is * equivalent to a single empty specification. */ for (const char *spec = empty_to_null(verb->argspec);;) { @@ -190,7 +191,8 @@ static int verb_add_help_one(Table *table, const Verb *verb) { verb->verb, spec ? " " : "", strempty(spec), - is_default ? "]" : ""); + is_default ? "]" : "", + FLAGS_SET(verb->flags, VERB_OPTION_REQUIRED) ? " OPTION" : ""); if (!s) return log_oom(); @@ -588,12 +590,16 @@ int _command_print_verb_help( if (cmd->pager_flags) pager_open(*cmd->pager_flags); + const char *optionspec = + FLAGS_SET(verb->flags, VERB_OPTION_REQUIRED) ? + " OPTION…" : verb->option_namespace ? " [OPTION…]" : ""; + /* If argspec is empty, print one line with no argspec. Use " " as placeholder for the empty spec. */ NULSTR_FOREACH(spec, verb->argspec ?: " \0") { bool some = !streq(spec, " "); _cleanup_free_ char *line = strjoin( "[OPTION…] ", verb->verb, - verb->option_namespace ? " [OPTION…]" : "", + optionspec, some ? " " : NULL, some ? spec : NULL); if (!line) diff --git a/src/shared/verbs.h b/src/shared/verbs.h index 0288548a8c..cd679f404e 100644 --- a/src/shared/verbs.h +++ b/src/shared/verbs.h @@ -28,10 +28,11 @@ typedef struct CommandDescription { } CommandDescription; typedef enum VerbFlags { - VERB_DEFAULT = 1 << 0, /* The verb to run if no verb is specified */ - VERB_ONLINE_ONLY = 1 << 1, /* Just do nothing when running in chroot or offline */ - VERB_COMMAND_MARKER = 1 << 2, /* Header entry with command description */ - VERB_GROUP_MARKER = 1 << 3, /* Fake verb entry to separate groups */ + VERB_DEFAULT = 1 << 0, /* The verb to run if no verb is specified */ + VERB_ONLINE_ONLY = 1 << 1, /* Just do nothing when running in chroot or offline */ + VERB_OPTION_REQUIRED = 1 << 2, /* The verb always requires an option to be present */ + VERB_COMMAND_MARKER = 1 << 3, /* Header entry with command description */ + VERB_GROUP_MARKER = 1 << 4, /* Fake verb entry to separate groups */ } VerbFlags; /* Note: see the comment on struct Option in options.h for why _alignptr_ is required here. */ diff --git a/src/test/test-verbs.c b/src/test/test-verbs.c index c255c5840c..42670c9593 100644 --- a/src/test/test-verbs.c +++ b/src/test/test-verbs.c @@ -99,6 +99,9 @@ static const Verb introspect_verbs[] = { .argspec = "FORM1\0FORM2…\0", .help = "Alpha verb", .option_namespace = "test-verbs-alpha" }, { .verb = "beta", .min_args = VERB_ANY, .max_args = VERB_ANY, .dispatch = noop_dispatcher, .help = "Beta verb" }, + { .verb = "gamma", .flags = VERB_OPTION_REQUIRED, + .min_args = VERB_ANY, .max_args = VERB_ANY, .dispatch = noop_dispatcher, + .help = "Gamma verb" }, {} }; @@ -121,6 +124,9 @@ TEST(command_print_verb_help) { ASSERT_OK(_command_print_verb_help(introspect_verbs, introspect_verbs + ELEMENTSOF(introspect_verbs) - 1, introspect_options, introspect_options + ELEMENTSOF(introspect_options) - 1, "beta")); + ASSERT_OK(_command_print_verb_help(introspect_verbs, introspect_verbs + ELEMENTSOF(introspect_verbs) - 1, + introspect_options, introspect_options + ELEMENTSOF(introspect_options) - 1, + "gamma")); } DEFINE_TEST_MAIN(LOG_INFO);