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
+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