Another batch of conversions to COMMAND and additions of --introspect-cli (#43512)

This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2026-08-26 15:22:50 +02:00
committed by GitHub
34 changed files with 365 additions and 255 deletions
-27
View File
@@ -13,7 +13,6 @@
#include "path-util.h"
#include "process-util.h"
#include "string-util.h"
#include "strv.h"
int saved_argc = 0;
char **saved_argv = NULL;
@@ -69,32 +68,6 @@ bool invoked_by_systemd(void) {
return cached;
}
bool argv_looks_like_help(int argc, char **argv) {
char **l;
/* Scans the command line for indications the user asks for help. This is supposed to be called by
* tools that do not implement getopt()-style command line parsing because they are not primarily
* user-facing. Detects four ways of asking for help:
*
* 1. Passing zero arguments
* 2. Passing "help" as first argument
* 3. Passing --help as any argument
* 4. Passing -h as any argument
*/
assert(argc == 0 || argv);
if (argc <= 1)
return true;
if (streq_ptr(argv[1], "help"))
return true;
l = strv_skip(argv, 1);
return strv_contains(l, "--help") ||
strv_contains(l, "-h");
}
static int update_argv(const char name[], size_t l) {
static int can_do = -1;
int r;
-1
View File
@@ -10,7 +10,6 @@ void save_argc_argv(int argc, char **argv);
bool invoked_as(char *argv[], const char *token);
bool invoked_by_systemd(void) _const_;
bool argv_looks_like_help(int argc, char **argv);
int rename_process_full(const char *comm, const char *invocation);
static inline int rename_process(const char *name) {
+1
View File
@@ -37,6 +37,7 @@ int proc_cmdline_filter_pid1_args(char **argv, char ***ret) {
{ "no-pager", no_argument, },
{ "help", no_argument, },
{ "version", no_argument, },
{ "introspect-cli", no_argument, },
{ "dump-configuration-items", no_argument, },
{ "dump-bus-properties", no_argument, },
{ "bus-introspect", required_argument },
+12 -30
View File
@@ -2,9 +2,9 @@
#include <stdlib.h>
#include "sd-json.h"
#include "sd-messages.h"
#include "alloc-util.h"
#include "argv-util.h"
#include "build.h"
#include "capability-util.h"
@@ -18,45 +18,24 @@
#include "exit-status.h"
#include "fd-util.h"
#include "fdset.h"
#include "format-table.h"
#include "label-util.h"
#include "log.h"
#include "options.h"
#include "parse-util.h"
#include "pretty-print.h"
#include "selinux-util.h"
#include "static-destruct.h"
#include "verbs.h"
static FILE *arg_serialization = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_serialization, fclosep);
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = terminal_urlify_man("systemd", "1", &link);
if (r < 0)
return log_oom();
r = option_parser_get_help_table_ns("systemd-executor", &options);
if (r < 0)
return r;
printf("%s [OPTIONS...]\n\n"
"%sSandbox and execute processes.%s\n\n",
program_invocation_short_name,
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;
}
COMMAND(
"systemd-executor\0",
"Sandbox and execute processes.",
.man_pages = "systemd.1\0",
.option_namespace = "systemd-executor",
);
static int parse_argv(int argc, char *argv[]) {
int r;
@@ -72,7 +51,7 @@ static int parse_argv(int argc, char *argv[]) {
OPTION_NAMESPACE("systemd-executor"): {}
OPTION_COMMON_HELP:
return help();
return command_print_help_name("systemd-executor");
OPTION_COMMON_VERSION:
return version();
@@ -128,6 +107,9 @@ static int parse_argv(int argc, char *argv[]) {
arg_serialization = f;
break;
}
OPTION_COMMON_INTROSPECT_CLI:
return introspect_cli(SD_JSON_FORMAT_OFF);
}
if (!arg_serialization)
+22 -26
View File
@@ -51,13 +51,11 @@
#include "fd-util.h"
#include "fdset.h"
#include "fileio.h"
#include "format-table.h"
#include "format-util.h"
#include "fs-util.h"
#include "glyph-util.h"
#include "hash-funcs.h"
#include "hashmap.h"
#include "help-util.h"
#include "hexdecoct.h"
#include "hostname-setup.h"
#include "id128-util.h"
@@ -119,6 +117,7 @@
#include "unit-name.h"
#include "user-util.h"
#include "utf8.h"
#include "verbs.h"
#include "version.h"
#include "virt.h"
#include "watchdog.h"
@@ -131,6 +130,7 @@ static enum {
ACTION_RUN,
ACTION_HELP,
ACTION_VERSION,
ACTION_INTROSPECT_CLI,
ACTION_TEST,
ACTION_DUMP_CONFIGURATION_ITEMS,
ACTION_DUMP_BUS_PROPERTIES,
@@ -1039,6 +1039,14 @@ static int redirect_telinit(char *argv[], char **args) {
strnull(a), strnull(b), strnull(c));
}
COMMAND(
"systemd\0",
"Start and monitor system and user services.",
.man_pages = "systemd.1\0",
.option_namespace = "systemd",
.pager_flags = &arg_pager_flags,
);
static int parse_argv(int argc, char *argv[]) {
bool user_arg_seen = false;
int r;
@@ -1068,6 +1076,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_VERSION;
break;
OPTION_COMMON_INTROSPECT_CLI:
arg_action = ACTION_INTROSPECT_CLI;
break;
OPTION_LONG("test", NULL, "Determine initial transaction, dump it and exit"):
arg_action = ACTION_TEST;
break;
@@ -1268,6 +1280,7 @@ static int parse_argv(int argc, char *argv[]) {
"Switch -%c is only supported when running as PID 1.", opts.opt->short_code);
/* In PID1, do nothing and continue with option parsing. */
break;
OPTION_ERROR:
if (getpid_cached() != 1)
return -EINVAL;
@@ -1290,28 +1303,6 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
}
static int help(void) {
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = option_parser_get_help_table_ns("systemd", &options);
if (r < 0)
return r;
help_cmdline("[OPTIONS...]");
help_abstract("Starts and monitors system and user services.");
printf("\nThis program takes no positional arguments.\n");
help_section("Options");
r = table_print_or_warn(options);
if (r < 0)
return r;
help_man_page_reference("systemd", "1");
return 0;
}
static int prepare_reexecute(
Manager *m,
FILE **ret_f,
@@ -3745,18 +3736,23 @@ static int run_systemd(int argc, char *argv[]) {
if (r < 0)
goto finish;
if (IN_SET(arg_action, ACTION_TEST, ACTION_HELP, ACTION_DUMP_CONFIGURATION_ITEMS, ACTION_DUMP_BUS_PROPERTIES, ACTION_BUS_INTROSPECT))
if (IN_SET(arg_action, ACTION_TEST, ACTION_DUMP_CONFIGURATION_ITEMS, ACTION_DUMP_BUS_PROPERTIES, ACTION_BUS_INTROSPECT))
pager_open(arg_pager_flags);
if (arg_action != ACTION_RUN)
skip_setup = true;
if (arg_action == ACTION_HELP) {
retval = help() < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
r = command_print_help_name("systemd");
retval = r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
goto finish;
} else if (arg_action == ACTION_VERSION) {
retval = version();
goto finish;
} else if (arg_action == ACTION_INTROSPECT_CLI) {
r = introspect_cli(SD_JSON_FORMAT_OFF);
retval = r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
goto finish;
} else if (arg_action == ACTION_DUMP_CONFIGURATION_ITEMS) {
unit_dump_config_items(stdout);
retval = EXIT_SUCCESS;
+12 -3
View File
@@ -13,6 +13,17 @@
#include "log.h"
#include "main-func.h"
#include "service-util.h"
#include "verbs.h"
COMMAND(
"systemd-homed\0",
"Create, remove, change or inspect home areas.",
.man_pages = "systemd-homed.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
@@ -25,9 +36,7 @@ static int run(int argc, char *argv[]) {
log_setup();
r = service_parse_argv("systemd-homed.service",
"A service to create, remove, change or inspect home areas.",
BUS_IMPLEMENTATIONS(&manager_object,
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
/* runtime_scope= */ NULL,
argc, argv);
+12 -3
View File
@@ -46,6 +46,7 @@
#include "varlink-io.systemd.Hostname.h"
#include "varlink-io.systemd.service.h"
#include "varlink-util.h"
#include "verbs.h"
#include "virt.h"
#include "vsock-util.h"
@@ -2662,6 +2663,16 @@ static bool context_check_idle(void *userdata) {
hashmap_isempty(c->polkit_registry);
}
COMMAND(
"systemd-hostnamed\0",
"Manage the system hostname and related metadata.",
.man_pages = "systemd-hostnamed.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(context_destroy) Context context = {
.hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
@@ -2672,9 +2683,7 @@ static int run(int argc, char *argv[]) {
log_setup();
r = service_parse_argv("systemd-hostnamed.service",
"Manage the system hostname and related metadata.",
BUS_IMPLEMENTATIONS(&manager_object,
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
/* runtime_scope= */ NULL,
argc, argv);
+13 -3
View File
@@ -48,6 +48,7 @@
#include "varlink-io.systemd.Import.h"
#include "varlink-io.systemd.service.h"
#include "varlink-util.h"
#include "verbs.h"
#include "web-util.h"
typedef struct Manager Manager;
@@ -2080,6 +2081,17 @@ static void manager_parse_env(Manager *m) {
log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_QUOTA: %m");
}
COMMAND(
"systemd-importd\0",
"Import and export VM and container images.",
.man_pages = "systemd-importd.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0"
"Runtime scope\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(manager_unrefp) Manager *m = NULL;
RuntimeScope scope = RUNTIME_SCOPE_SYSTEM;
@@ -2089,9 +2101,7 @@ static int run(int argc, char *argv[]) {
log_setup();
r = service_parse_argv("systemd-importd.service",
"VM and container image import and export service.",
BUS_IMPLEMENTATIONS(&manager_object,
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
&scope,
argc, argv);
+41 -29
View File
@@ -1,22 +1,20 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdio.h>
#include <sys/stat.h>
#include "sd-json.h"
#include "alloc-util.h"
#include "argv-util.h"
#include "build.h"
#include "cryptsetup-util.h"
#include "dlopen-note.h"
#include "fileio.h"
#include "format-table.h"
#include "help-util.h"
#include "integrity-util.h"
#include "log.h"
#include "main-func.h"
#include "path-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
#include "verbs.h"
@@ -43,25 +41,11 @@ static const char* const dm_integrity_algorithm_table[_INTEGRITY_ALGORITHM_MAX]
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(dm_integrity_algorithm, IntegrityAlgorithm);
static int help(void) {
_cleanup_(table_unrefp) Table *verbs = NULL;
int r;
r = verbs_get_help_table(&verbs);
if (r < 0)
return r;
help_cmdline("COMMAND ...");
help_abstract("Attach or detach an integrity protected block device.");
help_section("Commands");
r = table_print_or_warn(verbs);
if (r < 0)
return r;
help_man_page_reference("systemd-integritysetup@.service", "8");
return 0;
}
COMMAND(
"systemd-integritysetup\0",
"Attach or detach an integrity protected block device.",
.man_pages = "systemd-integritysetup@.service.8\0",
);
static int load_key_file(
const char *key_file,
@@ -197,23 +181,51 @@ static int verb_detach(int argc, char *argv[], uintptr_t _data, void *userdata)
return 0;
}
VERB_COMMON_HELP_AUTO_HIDDEN();
static int parse_argv(int argc, char *argv[], char ***ret_args) {
assert(argc >= 0);
assert(argv);
assert(ret_args);
OptionParser opts = { argc, argv };
FOREACH_OPTION_OR_RETURN(c, &opts)
switch (c) {
OPTION_COMMON_HELP:
return command_print_help();
OPTION_COMMON_VERSION:
return version();
OPTION_COMMON_INTROSPECT_CLI:
return introspect_cli(SD_JSON_FORMAT_OFF);
}
*ret_args = option_parser_get_args(&opts);
return 1;
}
static int run(int argc, char *argv[]) {
int r;
LIBCRYPTSETUP_NOTE(required);
if (argv_looks_like_help(argc, argv))
return help();
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
log_setup();
LIBCRYPTSETUP_NOTE(required);
r = dlopen_cryptsetup(LOG_ERR);
if (r < 0)
return r;
umask(0022);
return dispatch_verb(strv_skip(argv, 1), /* userdata= */ NULL);
return dispatch_verb(args, /* userdata= */ NULL);
}
DEFINE_MAIN_FUNCTION(run);
+1
View File
@@ -7,6 +7,7 @@ endif
executables += [
libexec_template + {
'name' : 'systemd-integritysetup',
'public' : true,
'sources' : files('integritysetup.c'),
'export' : files('integrity-util.c'),
'dependencies' : libcryptsetup_cflags,
+1 -1
View File
@@ -1624,7 +1624,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) {
switch (c) {
OPTION_COMMON_HELP:
return command_print_help_full("kernel-install", /* footer_ansi_seq= */ NULL);
return command_print_help_name("kernel-install");
OPTION_COMMON_VERSION:
return version();
+12 -3
View File
@@ -24,6 +24,7 @@
#include "service-util.h"
#include "string-util.h"
#include "strv.h"
#include "verbs.h"
static int vconsole_reload(sd_bus *bus) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -627,6 +628,16 @@ static bool context_check_idle(void *userdata) {
return hashmap_isempty(c->polkit_registry);
}
COMMAND(
"systemd-localed\0",
"Manage system locale settings and key mappings.",
.man_pages = "systemd-localed.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(context_clear) Context context = {};
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
@@ -637,9 +648,7 @@ static int run(int argc, char *argv[]) {
log_setup();
r = service_parse_argv("systemd-localed.service",
"Manage system locale settings and key mappings.",
BUS_IMPLEMENTATIONS(&manager_object,
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
/* runtime_scope= */ NULL,
argc, argv);
+12 -3
View File
@@ -46,6 +46,7 @@
#include "terminal-util.h"
#include "udev-util.h"
#include "user-util.h"
#include "verbs.h"
static Manager* manager_free(Manager *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
@@ -1347,6 +1348,16 @@ static int manager_run(Manager *m) {
}
}
COMMAND(
"systemd-logind\0",
"Manage user logins and devices and privileged operations.",
.man_pages = "systemd-logind.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
@@ -1359,9 +1370,7 @@ static int run(int argc, char *argv[]) {
log_set_facility(LOG_AUTH);
log_setup();
r = service_parse_argv("systemd-logind.service",
"Manager for user logins and devices and privileged operations.",
BUS_IMPLEMENTATIONS(&manager_object,
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
/* runtime_scope= */ NULL,
argc, argv);
+13 -3
View File
@@ -35,6 +35,7 @@
#include "signal-util.h"
#include "special.h"
#include "string-util.h"
#include "verbs.h"
#include "vsock-util.h"
static Manager* manager_unref(Manager *m);
@@ -343,6 +344,17 @@ static bool check_idle(void *userdata) {
return hashmap_isempty(m->machines);
}
COMMAND(
"systemd-machined\0",
"Manage registrations of local VMs and containers.",
.man_pages = "systemd-machined.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0"
"Runtime scope\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(manager_unrefp) Manager *m = NULL;
RuntimeScope scope = RUNTIME_SCOPE_SYSTEM;
@@ -357,9 +369,7 @@ static int run(int argc, char *argv[]) {
log_set_facility(LOG_AUTH);
log_setup();
r = service_parse_argv("systemd-machined.service",
"Manage registrations of local VMs and containers.",
BUS_IMPLEMENTATIONS(&manager_object,
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
&scope,
argc, argv);
+1 -1
View File
@@ -163,7 +163,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) {
OPTION_GROUP("Common options"): {}
OPTION_COMMON_HELP:
return command_print_help_full(cmd->names, /* footer_ansi_seq= */ NULL);
return command_print_help_name(cmd->names);
OPTION_COMMON_VERSION:
return version();
+12 -3
View File
@@ -19,6 +19,17 @@
#include "service-util.h"
#include "strv.h"
#include "user-util.h"
#include "verbs.h"
COMMAND(
"systemd-networkd\0",
"Manage and configure network devices, create virtual network devices.",
.man_pages = "systemd-networkd.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
@@ -31,9 +42,7 @@ static int run(int argc, char *argv[]) {
log_setup();
r = service_parse_argv("systemd-networkd.service",
"Manage and configure network devices, create virtual network devices",
BUS_IMPLEMENTATIONS(&manager_object, &log_control_object),
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object, &log_control_object),
/* runtime_scope= */ NULL,
argc, argv);
if (r <= 0)
+13 -3
View File
@@ -20,6 +20,7 @@
#include "portabled.h"
#include "service-util.h"
#include "signal-util.h"
#include "verbs.h"
static Manager* manager_unref(Manager *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
@@ -139,6 +140,17 @@ static bool check_idle(void *userdata) {
hashmap_isempty(m->polkit_registry);
}
COMMAND(
"systemd-portabled\0",
"Manage registrations of portable images.",
.man_pages = "systemd-portabled.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0"
"Runtime scope\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(manager_unrefp) Manager *m = NULL;
RuntimeScope scope = RUNTIME_SCOPE_SYSTEM;
@@ -152,9 +164,7 @@ static int run(int argc, char *argv[]) {
log_setup();
r = service_parse_argv("systemd-portabled.service",
"Manage registrations of portable images.",
BUS_IMPLEMENTATIONS(&manager_object,
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
&scope,
argc, argv);
+1 -1
View File
@@ -181,7 +181,7 @@ int resolvconf_parse_argv(int argc, char *argv[]) {
OPTION_NAMESPACE("resolvconf"): {}
OPTION_COMMON_HELP:
return command_print_help_full("resolvconf", /* footer_ansi_seq= */ NULL);
return command_print_help_name("resolvconf");
OPTION_COMMON_VERSION:
return version();
+1 -1
View File
@@ -3515,7 +3515,7 @@ static int native_parse_argv(int argc, char *argv[], char ***remaining_args) {
OPTION_NAMESPACE("resolvectl"): {}
OPTION_COMMON_HELP:
return command_print_help_full("resolvectl", /* footer_ansi_seq= */ NULL);
return command_print_help_name("resolvectl");
OPTION_COMMON_VERSION:
return version();
+12 -3
View File
@@ -19,6 +19,17 @@
#include "resolved-resolv-conf.h"
#include "service-util.h"
#include "user-util.h"
#include "verbs.h"
COMMAND(
"systemd-resolved\0",
"Provide name resolution with caching using DNS, mDNS, LLMNR.",
.man_pages = "systemd-resolved.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
@@ -32,9 +43,7 @@ static int run(int argc, char *argv[]) {
log_setup();
r = service_parse_argv("systemd-resolved.service",
"Provide name resolution with caching using DNS, mDNS, LLMNR.",
BUS_IMPLEMENTATIONS(&manager_object,
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
/* runtime_scope= */ NULL,
argc, argv);
+2 -2
View File
@@ -208,7 +208,7 @@ static int parse_argv(int argc, char *argv[]) {
OPTION_NAMESPACE("systemd-run"): {}
OPTION_COMMON_HELP:
return command_print_help_full("systemd-run", /* footer_ansi_seq= */ NULL);
return command_print_help_name("systemd-run");
OPTION_COMMON_VERSION:
return version();
@@ -784,7 +784,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
OPTION_NAMESPACE("run0"): {}
OPTION_COMMON_HELP:
return command_print_help_full("run0", /* footer_ansi_seq= */ NULL);
return command_print_help_name("run0");
OPTION('V', "version", NULL, "Show package version"):
return version();
+39 -63
View File
@@ -1,59 +1,19 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdio.h>
#include "sd-json.h"
#include "build.h"
#include "bus-object.h"
#include "format-table.h"
#include "help-util.h"
#include "log.h"
#include "nulstr-util.h"
#include "options.h"
#include "runtime-scope.h"
#include "service-util.h"
#include "string-util.h"
static int help(const char *service,
const char *description,
bool with_bus_introspect,
bool with_runtime_scope) {
static const char* const groups[] = {
NULL,
"Bus introspection",
"Runtime scope",
};
bool conds[ELEMENTSOF(groups)] = { true, with_bus_introspect, with_runtime_scope };
Table* tables[ELEMENTSOF(groups)] = {};
CLEANUP_ELEMENTS(tables, table_unref_array_clear);
int r;
for (size_t i = 0; i < ELEMENTSOF(groups); i++)
if (conds[i]) {
r = option_parser_get_help_table_group(groups[i], &tables[i]);
if (r < 0)
return r;
}
(void) table_sync_column_widths(0, tables[0], tables[1] ?: tables[2], tables[1] ? tables[2] : NULL);
help_cmdline("[OPTIONS...]");
help_abstract(description);
help_section("Options");
for (size_t i = 0; i < ELEMENTSOF(groups); i++)
if (conds[i]) {
r = table_print_or_warn(tables[i]);
if (r < 0)
return r;
}
help_man_page_reference(service, "8");
return 0; /* No further action */
}
int service_parse_argv(
const char *service,
const char *description,
int _service_parse_argv(
const Verb *verbs,
const Verb *verbs_end,
const BusObjectImplementation* const* bus_objects,
RuntimeScope *runtime_scope,
int argc, char *argv[]) {
@@ -61,30 +21,50 @@ int service_parse_argv(
assert(argc >= 0);
assert(argv);
OptionParser opts = { argc, argv };
const CommandDescription *cmd = NULL;
assert_se(_verbs_find_command(verbs, verbs_end, /* name= */ NULL, &cmd));
/* The COMMAND description must reference the option namespace defined below, and list
* exactly the option groups matching the features the service supports. Options outside of
* the listed groups are treated as unknown. */
assert(streq_ptr(cmd->option_namespace, "service"));
assert(nulstr_contains(cmd->option_groups, "Options"));
assert(!!bus_objects == nulstr_contains(cmd->option_groups, "Bus introspection"));
assert(!!runtime_scope == nulstr_contains(cmd->option_groups, "Runtime scope"));
OptionParser opts = {
argc, argv,
.namespace = "service",
.option_groups = cmd->option_groups,
};
FOREACH_OPTION_OR_RETURN(c, &opts)
switch (c) {
OPTION_NAMESPACE("service"): {}
OPTION_GROUP("Options"): {}
OPTION_COMMON_HELP:
return help(service,
description,
/* with_bus_introspect= */ bus_objects,
/* with_runtime_scope= */ runtime_scope);
return _command_print_help_full(
verbs, verbs_end,
__start_SYSTEMD_OPTIONS, __stop_SYSTEMD_OPTIONS,
cmd->names,
/* footer_ansi_seq= */ NULL);
OPTION_COMMON_VERSION:
return version();
OPTION_COMMON_INTROSPECT_CLI:
return _introspect_cli(
verbs, verbs_end,
__start_SYSTEMD_OPTIONS, __stop_SYSTEMD_OPTIONS,
SD_JSON_FORMAT_OFF);
OPTION_GROUP("Bus introspection"): {}
OPTION_LONG("bus-introspect", "PATH", "Write D-Bus XML introspection data"):
/* The option is defined in the shared option table, but it's not supported in this binary,
* so we pretend it doesn't exist. */
if (!bus_objects)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"This service does not support the --bus-introspect= option.");
return bus_introspect_implementations(stdout, opts.arg, bus_objects);
return bus_introspect_implementations(stdout, opts.arg, ASSERT_PTR(bus_objects));
OPTION_GROUP("Runtime scope"): {}
@@ -92,11 +72,7 @@ int service_parse_argv(
"Start service in system mode"): {}
OPTION_LONG_DATA("user", NULL, /* data= */ RUNTIME_SCOPE_USER,
"Start service in user mode"):
if (!runtime_scope)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"This service does not support the --system/--user options.");
*runtime_scope = opts.opt->data;
*ASSERT_PTR(runtime_scope) = opts.opt->data;
break;
}
+14 -3
View File
@@ -2,10 +2,21 @@
#pragma once
#include "forward.h"
#include "verbs.h"
int service_parse_argv(
const char *service,
const char *description,
int _service_parse_argv(
const Verb *verbs,
const Verb *verbs_end,
const BusObjectImplementation* const* bus_objects,
RuntimeScope *runtime_scope,
int argc, char *argv[]);
/* The service is expected to define a COMMAND() with .option_namespace = "service" and the option
* groups matching the features it supports: "Options" always, "Bus introspection" iff bus_objects
* is passed, "Runtime scope" iff runtime_scope is passed. The macro captures the calling binary's
* verb section, where that COMMAND is found, while the options are defined in
* service_parse_argv_full() itself. */
#define service_parse_argv(bus_objects, runtime_scope, argc, argv) \
_service_parse_argv( \
__start_SYSTEMD_VERBS, __stop_SYSTEMD_VERBS, \
bus_objects, runtime_scope, argc, argv)
+3 -2
View File
@@ -162,10 +162,11 @@ int _command_print_help_full(
__start_SYSTEMD_VERBS, __stop_SYSTEMD_VERBS, \
__start_SYSTEMD_OPTIONS, __stop_SYSTEMD_OPTIONS, \
name, footer_ansi_seq)
#define command_print_help() command_print_help_full(/* name= */ NULL, /* footer_ansi_seq= */ NULL)
#define command_print_help_name(name) command_print_help_full(name, /* footer_ansi_seq= */ NULL)
#define command_print_help() command_print_help_name(/* name= */ NULL)
static inline int verb_help_auto(int argc, char **argv, uintptr_t data, void *userdata) {
return command_print_help_full((const char*) data, /* footer_ansi_seq= */ NULL);
return command_print_help_name((const char*) data);
}
/* Print a machine-readable description of the program's commands, verbs, and options in the format
+1
View File
@@ -12,6 +12,7 @@ shutdown_detach_sources = files(
executables += [
libexec_template + {
'name' : 'systemd-shutdown',
'public' : true,
'export' : files(
'detach-dm.c',
'detach-loopback.c',
+42 -11
View File
@@ -16,6 +16,7 @@
#include "alloc-util.h"
#include "async.h"
#include "binfmt-util.h"
#include "build.h"
#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "constants.h"
@@ -34,6 +35,7 @@
#include "killall.h"
#include "log.h"
#include "luo-util.h"
#include "main-func.h"
#include "options.h"
#include "parse-util.h"
#include "pidref.h"
@@ -48,6 +50,7 @@
#include "terminal-util.h"
#include "time-util.h"
#include "umount.h"
#include "verbs.h"
#include "virt.h"
#include "watchdog.h"
@@ -59,6 +62,13 @@ static const char *arg_verb = NULL;
static uint8_t arg_exit_code = 0;
static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
COMMAND(
"systemd-shutdown\0",
"Execute the final phase of system shutdown.",
.argspec = "reboot|poweroff|halt|kexec|exit\0",
.man_pages = "systemd-shutdown.8\0",
);
static int parse_argv(int argc, char *argv[]) {
assert(argc >= 1);
assert(argv);
@@ -74,6 +84,15 @@ static int parse_argv(int argc, char *argv[]) {
FOREACH_OPTION_OR_RETURN(c, &opts)
switch (c) {
OPTION_COMMON_HELP:
return command_print_help();
OPTION_COMMON_VERSION:
return version();
OPTION_COMMON_INTROSPECT_CLI:
return introspect_cli(SD_JSON_FORMAT_OFF);
OPTION_COMMON_LOG_LEVEL:
r = log_set_max_level_from_string(opts.arg);
if (r < 0)
@@ -148,7 +167,7 @@ static int parse_argv(int argc, char *argv[]) {
if (!arg_verb)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Verb argument missing.");
return 0;
return 1; /* Further action */
}
static int switch_root_initramfs(void) {
@@ -366,7 +385,7 @@ static void sleep_until_minimum_uptime(void) {
}
}
int main(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
static const char* const dirs[] = {
SYSTEM_SHUTDOWN_PATH,
NULL
@@ -402,9 +421,16 @@ int main(int argc, char *argv[]) {
log_set_prohibit_ipc(true);
log_parse_environment();
r = parse_argv(argc, argv);
if (getpid_cached() != 1) {
log_error("Not executed by init (PID 1). Refusing to operate.");
return EXIT_FAILURE;
/* If we're a normal user space process, our work is done. Either we hit an error, or were
* called with --help, --version, or another option that was handled by parse_argv(), or it
* looks like we're being asked to do some real work, but we should do that only as part of
* the real shutdown sequence. */
if (r <= 0)
return r;
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Not executed by init (PID 1). Refusing to operate.");
}
log_set_always_reopen_console(true);
@@ -414,8 +440,7 @@ int main(int argc, char *argv[]) {
* through kernel. */
(void) reboot(RB_ENABLE_CAD);
r = parse_argv(argc, argv);
if (r < 0)
if (r <= 0)
goto error;
log_open();
@@ -668,7 +693,6 @@ int main(int argc, char *argv[]) {
switch (cmd) {
case LINUX_REBOOT_CMD_KEXEC:
if (!in_container) {
/* Preserve fd stores via the kernel Live Update Orchestrator before kexec.
* The session fd must stay open until the kexec syscall. */
@@ -706,14 +730,21 @@ int main(int argc, char *argv[]) {
/* If we are in a container, and we lacked CAP_SYS_BOOT just exit, this will kill our
* container for good. */
log_info("Exiting container.");
return EXIT_SUCCESS;
return 0;
}
r = log_error_errno(errno, "Failed to invoke reboot(): %m");
error:
log_struct_errno(LOG_EMERG, r,
LOG_MESSAGE("Critical error while doing system shutdown: %m"),
LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN_ERROR_STR));
if (r == 0)
log_struct(LOG_EMERG,
LOG_MESSAGE("Non-shutdown operation requested, cannot operate."),
LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN_ERROR_STR));
else
log_struct_errno(LOG_EMERG, r,
LOG_MESSAGE("Critical error while doing system shutdown: %m"),
LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN_ERROR_STR));
freeze();
}
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
+3 -6
View File
@@ -3138,9 +3138,8 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
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);
return command_print_help_name(
arg_image_class == IMAGE_SYSEXT ? "systemd-sysext" : "systemd-confext");
}
static int parse_argv(int argc, char *argv[], char ***ret_args) {
@@ -3156,9 +3155,7 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
switch (c) {
OPTION_COMMON_HELP:
return command_print_help_full(
arg_image_class == IMAGE_SYSEXT ? "systemd-sysext" : "systemd-confext",
/* footer_ansi_seq= */ NULL);
return verb_help(argc, argv, /* data= */ 0u, /* userdata= */ NULL);
OPTION_COMMON_VERSION:
return version();
+1 -1
View File
@@ -351,7 +351,7 @@ static int systemctl_parse_argv(int argc, char *argv[], int log_level_shift, cha
OPTION_NAMESPACE("systemctl"): {}
OPTION_COMMON_HELP:
return command_print_help_full("systemctl", /* footer_ansi_seq= */ NULL);
return command_print_help_name("systemctl");
OPTION_COMMON_VERSION:
return version();
+12 -3
View File
@@ -41,6 +41,7 @@
#include "strv.h"
#include "sysupdate-target.h"
#include "sysupdate-util.h"
#include "verbs.h"
#define FEATURES_DROPIN_NAME "systemd-sysupdate-enabled"
@@ -2160,15 +2161,23 @@ static int manager_run(Manager *m) {
m);
}
COMMAND(
"systemd-sysupdated\0",
"Manage system updates.",
.man_pages = "systemd-sysupdated.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
log_setup();
r = service_parse_argv("systemd-sysupdated.service",
"System update management service.",
BUS_IMPLEMENTATIONS(&manager_object,
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
/* runtime_scope= */ NULL,
argc, argv);
-13
View File
@@ -99,19 +99,6 @@ TEST(rename_process) {
test_rename_process_one("1234567", 1); /* should always fit */
}
TEST(argv_help) {
assert_se(argv_looks_like_help(1, STRV_MAKE("program")));
assert_se(argv_looks_like_help(2, STRV_MAKE("program", "help")));
assert_se(argv_looks_like_help(3, STRV_MAKE("program", "arg1", "--help")));
assert_se(argv_looks_like_help(4, STRV_MAKE("program", "arg1", "arg2", "-h")));
assert_se(!argv_looks_like_help(2, STRV_MAKE("program", "arg1")));
assert_se(!argv_looks_like_help(4, STRV_MAKE("program", "arg1", "arg2", "--h")));
assert_se(!argv_looks_like_help(3, STRV_MAKE("program", "Help", "arg2")));
assert_se(argv_looks_like_help(5, STRV_MAKE("program", "--help", "arg1", "-h", "--help")));
assert_se(!argv_looks_like_help(4, STRV_MAKE("program","arg1", "arg2", "-H")));
assert_se(!argv_looks_like_help(3, STRV_MAKE("program", "--Help", "arg2")));
}
static int intro(void) {
log_show_color(true);
return EXIT_SUCCESS;
+2 -1
View File
@@ -271,9 +271,10 @@ TEST(proc_cmdline_filter_pid1_args) {
"--log-color\0--log-level\0drop3\0" /* optional argument ("--log-level" is handled as another option) */
"--log-color\0accept5\0" /* optional argument (separated with space) */
"--log-color=drop4\0accept6\0" /* optional argument (concatenated with '=') */
"--introspect-cli\0accept7\0" /* no argument */
"--log-color\0--\0" /* "--" is _not_ handled as argument, and remaining strings are accepted */
"remaining\0-x\0--foo\0",
STRV_MAKE("accept1", "accept2", "accept3", "accept4", "accept5", "accept6", "remaining", "-x", "--foo"));
STRV_MAKE("accept1", "accept2", "accept3", "accept4", "accept5", "accept6", "accept7", "remaining", "-x", "--foo"));
/* test for "--" */
test_proc_cmdline_filter_pid1_args_one("systemd\0"
+12 -3
View File
@@ -46,6 +46,7 @@
#include "time-util.h"
#include "unit-def.h"
#include "unit-name.h"
#include "verbs.h"
#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
@@ -1167,6 +1168,16 @@ static bool context_check_idle(void *userdata) {
return hashmap_isempty(c->polkit_registry);
}
COMMAND(
"systemd-timedated\0",
"Manage the system clock and timezone and NTP enablement.",
.man_pages = "systemd-timedated.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(context_clear) Context context = {};
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
@@ -1177,9 +1188,7 @@ static int run(int argc, char *argv[]) {
log_setup();
r = service_parse_argv("systemd-timedated.service",
"Manage the system clock and timezone and NTP enablement.",
BUS_IMPLEMENTATIONS(&manager_object,
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
/* runtime_scope= */ NULL,
argc, argv);
+12 -3
View File
@@ -22,6 +22,7 @@
#include "timesyncd-bus.h"
#include "timesyncd-conf.h"
#include "timesyncd-manager.h"
#include "verbs.h"
static int advance_tstamp(int fd, usec_t epoch) {
assert(fd >= 0);
@@ -122,6 +123,16 @@ static int load_clock_timestamp(void) {
return 0;
}
COMMAND(
"systemd-timesyncd\0",
"Synchronize the system clock across the network.",
.man_pages = "systemd-timesyncd.service.8\0",
.option_namespace = "service",
.option_groups =
"Options\0"
"Bus introspection\0",
);
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
@@ -130,9 +141,7 @@ static int run(int argc, char *argv[]) {
log_set_facility(LOG_CRON);
log_setup();
r = service_parse_argv("systemd-timesyncd.service",
"Network time synchronization",
BUS_IMPLEMENTATIONS(&manager_object, &log_control_object),
r = service_parse_argv(BUS_IMPLEMENTATIONS(&manager_object, &log_control_object),
/* runtime_scope= */ NULL,
argc, argv);
if (r <= 0)
@@ -40,6 +40,7 @@ INTROSPECTABLE=(
shutdown
storagectl
systemctl
systemd
systemd-ac-power
systemd-analyze
systemd-ask-password
@@ -61,29 +62,38 @@ INTROSPECTABLE=(
systemd-detect-virt
systemd-dissect
systemd-escape
systemd-executor
systemd-export
systemd-factory-reset
systemd-firstboot
systemd-growfs
systemd-hibernate-resume
systemd-homed
systemd-hostnamed
systemd-hwdb
systemd-id128
systemd-imds
systemd-imdsd
systemd-import
systemd-import-fs
systemd-importd
systemd-inhibit
systemd-integritysetup
systemd-journal-gatewayd
systemd-journal-remote
systemd-journal-upload
systemd-keyutil
systemd-localed
systemd-logind
systemd-machine-id-setup
systemd-machined
systemd-measure
systemd-modules-load
systemd-mount
systemd-mstack
systemd-mute-console
systemd-network-generator
systemd-networkd
systemd-networkd-wait-online
systemd-notify
systemd-nspawn
@@ -91,6 +101,7 @@ INTROSPECTABLE=(
systemd-path
systemd-pcrextend
systemd-pcrlock
systemd-portabled
systemd-pty-forward
systemd-pull
systemd-random-seed
@@ -101,8 +112,10 @@ INTROSPECTABLE=(
systemd-report-files
systemd-report-sign-plain
systemd-report-sign-tsm
systemd-resolved
systemd-run
systemd-sbsign
systemd-shutdown
systemd-sleep
systemd-socket-activate
systemd-socket-proxyd
@@ -115,7 +128,10 @@ INTROSPECTABLE=(
systemd-sysext
systemd-sysinstall
systemd-sysupdate
systemd-sysupdated
systemd-sysusers
systemd-timedated
systemd-timesyncd
systemd-tmpfiles
systemd-tpm2-clear
systemd-tpm2-setup
@@ -180,9 +196,23 @@ systemd-clonesetup --introspect-cli | jq -e \
systemd-dissect --introspect-cli | jq -e \
'[.commands[].names[0]] | sort == ["mount.ddi", "systemd-dissect"]'
# systemd-hostnamed does not support --system/--user: options from groups not listed by the
# command must be rejected as unknown and hidden from the introspection (option group filtering)
if command -v systemd-hostnamed >/dev/null; then
(! systemd-hostnamed --system 2>&1) | grep "unrecognized option" >/dev/null
systemd-hostnamed --introspect-cli | jq -e \
'all(.commands[]; all(.options[]; .names[-1] != "--system"))'
fi
systemd-id128 --introspect-cli | jq -e \
'.commands[0].verbs | map(.names[0]) | contains(["new", "machine-id", "show", "help"])'
# 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 \
'[.commands[].names[0]] | sort == ["systemd", "systemd-executor"]'
fi
if command -v systemd-mount >/dev/null; then
systemd-mount --introspect-cli | jq -e \
'[.commands[].names[0]] | sort == ["systemd-mount", "systemd-umount"]'