A few more conversions of options and verbs (#41795)

I had those prepared before but I didn't submit them because the
automatic layout didn't work well. In two cases now the sync of widths
between verbs and options is disabled and one case is left with the
automatic alignment. I think it'd good enough to merge.
This commit is contained in:
Yu Watanabe
2026-05-15 02:47:23 +09:00
committed by GitHub
12 changed files with 415 additions and 547 deletions
+1 -1
View File
@@ -1509,7 +1509,7 @@ static int load_secure_boot_auto_enroll(
if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key);
if (r < 0)
return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
return r;
}
r = openssl_load_private_key(
+2 -4
View File
@@ -554,15 +554,13 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
arg_quiet = true;
break;
OPTION_LONG("entry-token", "TOKEN",
"Entry token to use for this installation"
" (machine-id, os-id, os-image-id, auto, literal:…)"):
OPTION_COMMON_ENTRY_TOKEN:
r = parse_boot_entry_token_type(opts.arg, &arg_entry_token_type, &arg_entry_token);
if (r < 0)
return r;
break;
OPTION_LONG("make-entry-directory", "yes|no|auto", "Create $BOOT/ENTRY-TOKEN/ directory"): {}
OPTION_COMMON_MAKE_ENTRY_DIRECTORY: {}
OPTION_LONG("make-machine-id-directory", "BOOL", /* help= */ NULL): /* Compatibility alias */
if (streq(opts.arg, "auto")) /* retained for backwards compatibility */
arg_make_entry_directory = -1; /* yes if machine-id is permanent */
+145 -248
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <unistd.h>
#include "sd-bus.h"
@@ -9,6 +8,7 @@
#include "sd-json.h"
#include "alloc-util.h"
#include "ansi-color.h"
#include "bitfield.h"
#include "build.h"
#include "bus-dump.h"
@@ -26,16 +26,17 @@
#include "fileio.h"
#include "format-table.h"
#include "glyph-util.h"
#include "help-util.h"
#include "log.h"
#include "logarithm.h"
#include "main-func.h"
#include "memstream-util.h"
#include "options.h"
#include "os-util.h"
#include "pager.h"
#include "parse-argument.h"
#include "parse-util.h"
#include "path-util.h"
#include "pretty-print.h"
#include "runtime-scope.h"
#include "set.h"
#include "string-util.h"
@@ -175,7 +176,9 @@ static void notify_bus_error(const sd_bus_error *error) {
(void) sd_notifyf(/* unset_environment= */ false, "BUSERROR=%s", error->name);
}
static int verb_list_bus_names(int argc, char *argv[], uintptr_t _data, void *userdata) {
VERB(verb_list, "list", NULL, VERB_ANY, 1, VERB_DEFAULT,
"List bus names");
static int verb_list(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_hashmap_free_ Hashmap *names = NULL;
@@ -537,6 +540,8 @@ static int tree_one(sd_bus *bus, const char *service) {
return r;
}
VERB(verb_tree, "tree", "[SERVICE…]", VERB_ANY, VERB_ANY, 0,
"Show object tree of service");
static int verb_tree(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
@@ -996,6 +1001,8 @@ static int members_flags_to_string(const Member *m, char **ret) {
return 0;
}
VERB(verb_introspect, "introspect", "SERVICE OBJECT [INTERFACE]", 3, 4, 0,
"Introspect an object");
static int verb_introspect(int argc, char *argv[], uintptr_t _data, void *userdata) {
static const XMLIntrospectOps ops = {
.on_interface = on_interface,
@@ -1377,10 +1384,14 @@ static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f
}
}
VERB(verb_monitor, "monitor", "[SERVICE…]", VERB_ANY, VERB_ANY, 0,
"Show bus traffic");
static int verb_monitor(int argc, char *argv[], uintptr_t _data, void *userdata) {
return monitor(argc, argv, sd_json_format_enabled(arg_json_format_flags) ? message_json : message_dump);
}
VERB(verb_capture, "capture", "[SERVICE…]", VERB_ANY, VERB_ANY, 0,
"Capture bus traffic as pcap");
static int verb_capture(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_free_ char *osname = NULL;
static const char info[] =
@@ -1408,6 +1419,8 @@ static int verb_capture(int argc, char *argv[], uintptr_t _data, void *userdata)
return r;
}
VERB(verb_status, "status", "[SERVICE]", VERB_ANY, 2, 0,
"Show bus service, process, or bus owner credentials");
static int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
@@ -1778,6 +1791,8 @@ static int bus_message_dump(sd_bus_message *m, uint64_t flags) {
return 0;
}
VERB(verb_call, "call", "SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT…]]", 5, VERB_ANY, 0,
"Call a method");
static int verb_call(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -1845,7 +1860,9 @@ static int verb_call(int argc, char *argv[], uintptr_t _data, void *userdata) {
return bus_message_dump(reply, /* flags= */ 0);
}
static int verb_emit_signal(int argc, char *argv[], uintptr_t _data, void *userdata) {
VERB(verb_emit, "emit", "OBJECT INTERFACE SIGNAL [SIGNATURE [ARGUMENT…]]", 4, VERB_ANY, 0,
"Emit a signal");
static int verb_emit(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_fdset_free_ FDSet *passed_fdset = NULL;
@@ -1890,6 +1907,8 @@ static int verb_emit_signal(int argc, char *argv[], uintptr_t _data, void *userd
return 0;
}
VERB(verb_get_property, "get-property", "SERVICE OBJECT INTERFACE PROPERTY…", 5, VERB_ANY, 0,
"Get property value");
static int verb_get_property(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -1948,7 +1967,9 @@ static int on_bus_signal(sd_bus_message *msg, void *userdata, sd_bus_error *ret_
return 0;
}
static int verb_wait_signal(int argc, char *argv[], uintptr_t _data, void *userdata) {
VERB(verb_wait, "wait", "[SERVICE] OBJECT INTERFACE SIGNAL", 4, 5, 0,
"Wait for a signal");
static int verb_wait(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL;
@@ -1996,6 +2017,8 @@ static int verb_wait_signal(int argc, char *argv[], uintptr_t _data, void *userd
return sd_event_loop(e);
}
VERB(verb_set_property, "set-property", "SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT…", 6, VERB_ANY, 0,
"Set property value");
static int verb_set_property(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
@@ -2052,213 +2075,131 @@ static int verb_set_property(int argc, char *argv[], uintptr_t _data, void *user
}
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL, *verbs = NULL;
int r;
r = terminal_urlify_man("busctl", "1", &link);
if (r < 0)
return log_oom();
pager_open(arg_pager_flags);
printf("%1$s [OPTIONS...] COMMAND ...\n\n"
"%5$sIntrospect the D-Bus IPC bus.%6$s\n"
"\n%3$sCommands%4$s:\n"
" list List bus names\n"
" status [SERVICE] Show bus service, process or bus owner credentials\n"
" monitor [SERVICE...] Show bus traffic\n"
" capture [SERVICE...] Capture bus traffic as pcap\n"
" tree [SERVICE...] Show object tree of service\n"
" introspect SERVICE OBJECT [INTERFACE]\n"
" call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
" Call a method\n"
" emit OBJECT INTERFACE SIGNAL [SIGNATURE [ARGUMENT...]]\n"
" Emit a signal\n"
" wait OBJECT INTERFACE SIGNAL\n"
" Wait for a signal\n"
" get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
" Get property value\n"
" set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
" Set property value\n"
" help Show this help\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
" -l --full Do not ellipsize output\n"
" --system Connect to system bus\n"
" --user Connect to user bus\n"
" -H --host=[USER@]HOST Operate on remote host\n"
" -M --machine=CONTAINER Operate on local container\n"
" --address=ADDRESS Connect to bus specified by address\n"
" --show-machine Show machine ID column in list\n"
" --unique Only show unique names\n"
" --acquired Only show acquired names\n"
" --activatable Only show activatable names\n"
" --match=MATCH Only show matching messages\n"
" --size=SIZE Maximum length of captured packet\n"
" --list Don't show tree, but simple object path list\n"
" -q --quiet Don't show method call reply\n"
" --verbose Show result values in long format\n"
" --json=MODE Output as JSON\n"
" -j Same as --json=pretty on tty, --json=short otherwise\n"
" --xml-interface Dump the XML description in introspect command\n"
" --expect-reply=BOOL Expect a method call reply\n"
" --auto-start=BOOL Auto-start destination service\n"
" --allow-interactive-authorization=BOOL\n"
" Allow interactive authorization for operation\n"
" --timeout=SECS Maximum time to wait for method call completion\n"
" --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n"
" --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n"
" system\n"
" --destination=SERVICE Destination service of a signal\n"
" -N --limit-messages=NUMBER\n"
" Stop monitoring after receiving the specified number\n"
" of messages\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
ansi_underline(),
ansi_normal(),
ansi_highlight(),
ansi_normal());
r = verbs_get_help_table(&verbs);
if (r < 0)
return r;
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
/* Note: column widths are not synced, because the verbs table is very wide. */
help_cmdline("[OPTIONS…] COMMAND …");
help_abstract("Introspect the D-Bus IPC bus.");
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("busctl", "1");
return 0;
}
static int verb_help(int argc, char *argv[], uintptr_t _data, void *userdata) {
return help();
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_NO_LEGEND,
ARG_SYSTEM,
ARG_USER,
ARG_ADDRESS,
ARG_MATCH,
ARG_SHOW_MACHINE,
ARG_UNIQUE,
ARG_ACQUIRED,
ARG_ACTIVATABLE,
ARG_SIZE,
ARG_LIST,
ARG_VERBOSE,
ARG_XML_INTERFACE,
ARG_EXPECT_REPLY,
ARG_AUTO_START,
ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
ARG_TIMEOUT,
ARG_AUGMENT_CREDS,
ARG_WATCH_BIND,
ARG_JSON,
ARG_DESTINATION,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "full", no_argument, NULL, 'l' },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "user", no_argument, NULL, ARG_USER },
{ "address", required_argument, NULL, ARG_ADDRESS },
{ "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
{ "unique", no_argument, NULL, ARG_UNIQUE },
{ "acquired", no_argument, NULL, ARG_ACQUIRED },
{ "activatable", no_argument, NULL, ARG_ACTIVATABLE },
{ "match", required_argument, NULL, ARG_MATCH },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
{ "capsule", required_argument, NULL, 'C' },
{ "size", required_argument, NULL, ARG_SIZE },
{ "list", no_argument, NULL, ARG_LIST },
{ "quiet", no_argument, NULL, 'q' },
{ "verbose", no_argument, NULL, ARG_VERBOSE },
{ "xml-interface", no_argument, NULL, ARG_XML_INTERFACE },
{ "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
{ "auto-start", required_argument, NULL, ARG_AUTO_START },
{ "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
{ "augment-creds", required_argument, NULL, ARG_AUGMENT_CREDS },
{ "watch-bind", required_argument, NULL, ARG_WATCH_BIND },
{ "json", required_argument, NULL, ARG_JSON },
{ "destination", required_argument, NULL, ARG_DESTINATION },
{ "limit-messages", required_argument, NULL, 'N' },
{},
};
int c, r;
VERB_COMMON_HELP(help);
static int parse_argv(int argc, char *argv[], char ***remaining_args) {
assert(argc >= 0);
assert(argv);
assert(remaining_args);
while ((c = getopt_long(argc, argv, "hH:M:C:J:qjlN:", options, NULL)) >= 0)
OptionParser opts = { argc, argv };
int r;
FOREACH_OPTION_OR_RETURN(c, &opts)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_NO_PAGER:
OPTION_COMMON_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
case ARG_NO_LEGEND:
OPTION_COMMON_NO_LEGEND:
arg_legend = false;
break;
case 'l':
OPTION('l', "full", NULL, "Do not ellipsize output"):
arg_full = true;
break;
case ARG_USER:
arg_runtime_scope = RUNTIME_SCOPE_USER;
break;
case ARG_SYSTEM:
OPTION_LONG("system", NULL, "Connect to system bus"):
arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
break;
case ARG_ADDRESS:
arg_address = optarg;
OPTION_LONG("user", NULL, "Connect to user bus"):
arg_runtime_scope = RUNTIME_SCOPE_USER;
break;
case ARG_SHOW_MACHINE:
OPTION_COMMON_HOST:
arg_transport = BUS_TRANSPORT_REMOTE;
arg_host = opts.arg;
break;
OPTION_COMMON_MACHINE:
r = parse_machine_argument(opts.arg, &arg_host, &arg_transport);
if (r < 0)
return r;
break;
OPTION('C', "capsule", "NAME", "Operate on capsule"):
r = capsule_name_is_valid(opts.arg);
if (r < 0)
return log_error_errno(r, "Unable to validate capsule name '%s': %m", opts.arg);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capsule name: %s", opts.arg);
arg_host = opts.arg;
arg_transport = BUS_TRANSPORT_CAPSULE;
break;
OPTION_LONG("address", "ADDRESS", "Connect to bus specified by address"):
arg_address = opts.arg;
break;
OPTION_LONG("show-machine", NULL, "Show machine ID column in list"):
arg_show_machine = true;
break;
case ARG_UNIQUE:
OPTION_LONG("unique", NULL, "Only show unique names"):
arg_unique = true;
break;
case ARG_ACQUIRED:
OPTION_LONG("acquired", NULL, "Only show acquired names"):
arg_acquired = true;
break;
case ARG_ACTIVATABLE:
OPTION_LONG("activatable", NULL, "Only show activatable names"):
arg_activatable = true;
break;
case ARG_MATCH:
if (strv_extend(&arg_matches, optarg) < 0)
OPTION_LONG("match", "MATCH", "Only show matching messages"):
if (strv_extend(&arg_matches, opts.arg) < 0)
return log_oom();
break;
case ARG_SIZE: {
OPTION_LONG("size", "SIZE", "Maximum length of captured packet"): {
uint64_t sz;
r = parse_size(optarg, 1024, &sz);
r = parse_size(opts.arg, 1024, &sz);
if (r < 0)
return log_error_errno(r, "Failed to parse size '%s': %m", optarg);
return log_error_errno(r, "Failed to parse size '%s': %m", opts.arg);
if ((uint64_t) (size_t) sz != sz)
return log_error_errno(SYNTHETIC_ERRNO(E2BIG),
@@ -2268,167 +2209,123 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
case ARG_LIST:
OPTION_LONG("list", NULL, "Don't show tree, but simple object path list"):
arg_list = true;
break;
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
arg_host = optarg;
break;
case 'M':
r = parse_machine_argument(optarg, &arg_host, &arg_transport);
if (r < 0)
return r;
break;
case 'C':
r = capsule_name_is_valid(optarg);
if (r < 0)
return log_error_errno(r, "Unable to validate capsule name '%s': %m", optarg);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capsule name: %s", optarg);
arg_host = optarg;
arg_transport = BUS_TRANSPORT_CAPSULE;
break;
case 'q':
OPTION('q', "quiet", NULL, "Don't show method call reply"):
arg_quiet = true;
break;
case ARG_VERBOSE:
OPTION_LONG("verbose", NULL, "Show result values in long format"):
arg_verbose = true;
break;
case ARG_XML_INTERFACE:
OPTION_COMMON_JSON:
r = parse_json_argument(opts.arg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
OPTION_COMMON_LOWERCASE_J:
arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO;
break;
OPTION_LONG("xml-interface", NULL, "Dump the XML description in introspect command"):
arg_xml_interface = true;
break;
case ARG_EXPECT_REPLY:
r = parse_boolean_argument("--expect-reply=", optarg, &arg_expect_reply);
OPTION_LONG("expect-reply", "BOOL", "Expect a method call reply"):
r = parse_boolean_argument("--expect-reply=", opts.arg, &arg_expect_reply);
if (r < 0)
return r;
break;
case ARG_AUTO_START:
r = parse_boolean_argument("--auto-start=", optarg, &arg_auto_start);
OPTION_LONG("auto-start", "BOOL", "Auto-start destination service"):
r = parse_boolean_argument("--auto-start=", opts.arg, &arg_auto_start);
if (r < 0)
return r;
break;
case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
r = parse_boolean_argument("--allow-interactive-authorization=", optarg,
OPTION_LONG("allow-interactive-authorization", "",
"Allow interactive authorization for operation"):
r = parse_boolean_argument("--allow-interactive-authorization=", opts.arg,
&arg_allow_interactive_authorization);
if (r < 0)
return r;
break;
case ARG_TIMEOUT:
if (isempty(optarg)) {
OPTION_LONG("timeout", "SECS", "Maximum time to wait for method call completion"):
if (isempty(opts.arg)) {
arg_timeout = 0; /* Reset to default */
break;
}
r = parse_sec(optarg, &arg_timeout);
r = parse_sec(opts.arg, &arg_timeout);
if (r < 0)
return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", optarg);
return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", opts.arg);
break;
case ARG_AUGMENT_CREDS:
r = parse_boolean_argument("--augment-creds=", optarg, &arg_augment_creds);
OPTION_LONG("augment-creds", "BOOL",
"Extend credential data with data read from /proc/$PID"):
r = parse_boolean_argument("--augment-creds=", opts.arg, &arg_augment_creds);
if (r < 0)
return r;
break;
case ARG_WATCH_BIND:
r = parse_boolean_argument("--watch-bind=", optarg, &arg_watch_bind);
OPTION_LONG("watch-bind", "BOOL",
"Wait for bus AF_UNIX socket to be bound in the file system"):
r = parse_boolean_argument("--watch-bind=", opts.arg, &arg_watch_bind);
if (r < 0)
return r;
break;
case 'j':
arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO;
OPTION_LONG("destination", "SERVICE", "Destination service of a signal"):
arg_destination = opts.arg;
break;
case ARG_JSON:
r = parse_json_argument(optarg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
case ARG_DESTINATION:
arg_destination = optarg;
break;
case 'N':
if (isempty(optarg)) {
OPTION('N', "limit-messages", "NUMBER",
"Stop monitoring after receiving the specified number of messages"):
if (isempty(opts.arg)) {
/* Reset to default */
arg_limit_messages = UINT64_MAX;
arg_limit_signals = 1;
break;
}
if (streq(optarg, "infinity")) {
if (streq(opts.arg, "infinity")) {
arg_limit_signals = arg_limit_messages = UINT64_MAX;
break;
}
r = safe_atou64(optarg, &arg_limit_messages);
r = safe_atou64(opts.arg, &arg_limit_messages);
if (r < 0)
return log_error_errno(r, "Failed to parse --limit-messages= parameter: %s", optarg);
return log_error_errno(r, "Failed to parse --limit-messages= parameter: %s", opts.arg);
if (arg_limit_messages == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--limit-messages= parameter cannot be 0");
arg_limit_signals = arg_limit_messages;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (arg_full < 0)
arg_full = terminal_is_dumb();
*remaining_args = option_parser_get_args(&opts);
return 1;
}
static int busctl_main(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "list", VERB_ANY, 1, VERB_DEFAULT, verb_list_bus_names },
{ "status", VERB_ANY, 2, 0, verb_status },
{ "monitor", VERB_ANY, VERB_ANY, 0, verb_monitor },
{ "capture", VERB_ANY, VERB_ANY, 0, verb_capture },
{ "tree", VERB_ANY, VERB_ANY, 0, verb_tree },
{ "introspect", 3, 4, 0, verb_introspect },
{ "call", 5, VERB_ANY, 0, verb_call },
{ "emit", 4, VERB_ANY, 0, verb_emit_signal },
{ "wait", 4, 5, 0, verb_wait_signal },
{ "get-property", 5, VERB_ANY, 0, verb_get_property },
{ "set-property", 6, VERB_ANY, 0, verb_set_property },
{ "help", VERB_ANY, VERB_ANY, 0, verb_help },
{}
};
return dispatch_verb(argc, argv, verbs, NULL);
}
static int run(int argc, char *argv[]) {
int r;
log_setup();
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
return busctl_main(argc, argv);
return dispatch_verb_with_args(args, NULL);
}
DEFINE_MAIN_FUNCTION(run);
+3 -3
View File
@@ -4648,7 +4648,7 @@ static int parse_argv(int argc, char *argv[]) {
if (!eq) { /* --blob=/some/path replaces the blob dir */
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_blob_dir);
if (r < 0)
return log_error_errno(r, "Failed to parse path %s: %m", optarg);
return r;
break;
}
@@ -4664,7 +4664,7 @@ static int parse_argv(int argc, char *argv[]) {
r = parse_path_argument(eq + 1, /* suppress_root= */ false, &path);
if (r < 0)
return log_error_errno(r, "Failed to parse path %s: %m", eq + 1);
return r;
} else {
const char *well_known_filename =
c == ARG_AVATAR ? "avatar" :
@@ -4678,7 +4678,7 @@ static int parse_argv(int argc, char *argv[]) {
r = parse_path_argument(optarg, /* suppress_root= */ false, &path);
if (r < 0)
return log_error_errno(r, "Failed to parse path %s: %m", optarg);
return r;
}
if (path) {
+105 -150
View File
@@ -1,10 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>
#include "ansi-color.h"
#include "argv-util.h"
#include "boot-entry.h"
#include "bootspec.h"
@@ -22,6 +22,7 @@
#include "find-esp.h"
#include "format-table.h"
#include "fs-util.h"
#include "help-util.h"
#include "id128-util.h"
#include "image-policy.h"
#include "kernel-config.h"
@@ -29,9 +30,9 @@
#include "loop-util.h"
#include "main-func.h"
#include "mount-util.h"
#include "options.h"
#include "parse-argument.h"
#include "path-util.h"
#include "pretty-print.h"
#include "recurse-dir.h"
#include "rm-rf.h"
#include "stat-util.h"
@@ -1190,6 +1191,8 @@ static int do_add(
return context_execute(c);
}
VERB(verb_add, "add", "[[[KERNEL-VERSION] KERNEL-IMAGE] [INITRD ...]]", 1, VERB_ANY, 0,
"Add a kernel and initrd images to the boot partition");
static int verb_add(int argc, char *argv[], uintptr_t _data, void *userdata) {
const char *version, *kernel;
char **initrds;
@@ -1219,6 +1222,8 @@ static int verb_add(int argc, char *argv[], uintptr_t _data, void *userdata) {
return do_add(&c, version, kernel, initrds);
}
VERB_NOARG(verb_add_all, "add-all",
"Add all kernels found in /usr/lib/modules/");
static int verb_add_all(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_close_ int fd = -EBADF;
size_t n = 0;
@@ -1299,16 +1304,18 @@ static int verb_add_all(int argc, char *argv[], uintptr_t _data, void *userdata)
return ret;
}
static int run_as_installkernel(int argc, char *argv[]) {
static int run_as_installkernel(char **args) {
/* kernel's install.sh invokes us as
* /sbin/installkernel <version> <vmlinuz> <map> <installation-dir>
* We ignore the last two arguments. */
if (optind + 2 > argc)
if (strv_length(args) < 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "'installkernel' command requires at least two arguments.");
return verb_add(3, STRV_MAKE("add", argv[optind], argv[optind+1]), /* data= */ 0, /* userdata= */ NULL);
return verb_add(3, STRV_MAKE("add", args[0], args[1]), /* data= */ 0, /* userdata= */ NULL);
}
VERB(verb_remove, "remove", "KERNEL-VERSION", 2, VERB_ANY, 0,
"Remove a kernel from the boot partition");
static int verb_remove(int argc, char *argv[], uintptr_t _data, void *userdata) {
int r;
@@ -1345,6 +1352,8 @@ static int verb_remove(int argc, char *argv[], uintptr_t _data, void *userdata)
return context_execute(&c);
}
VERB(verb_inspect, "inspect", "[[[KERNEL-VERSION] KERNEL-IMAGE] [INITRD ...]]", 1, VERB_ANY, VERB_DEFAULT,
"Print details about the installation");
static int verb_inspect(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(table_unrefp) Table *t = NULL;
_cleanup_free_ char *vmlinuz = NULL;
@@ -1458,6 +1467,8 @@ static int verb_inspect(int argc, char *argv[], uintptr_t _data, void *userdata)
return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, /* show_header= */ false);
}
VERB_NOARG(verb_list, "list",
"List installed kernels");
static int verb_list(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_close_ int fd = -EBADF;
int r;
@@ -1526,128 +1537,87 @@ static int verb_list(int argc, char *argv[], uintptr_t _data, void *userdata) {
}
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL, *verbs = NULL;
int r;
r = terminal_urlify_man("kernel-install", "8", &link);
r = verbs_get_help_table(&verbs);
if (r < 0)
return log_oom();
return r;
printf("%1$s [OPTIONS...] COMMAND ...\n\n"
"%5$sAdd and remove kernel and initrd images to and from the boot partition.%6$s\n"
"\n%3$sUsage:%4$s\n"
" kernel-install [OPTIONS...] add [[[KERNEL-VERSION] KERNEL-IMAGE] [INITRD ...]]\n"
" kernel-install [OPTIONS...] add-all\n"
" kernel-install [OPTIONS...] remove KERNEL-VERSION\n"
" kernel-install [OPTIONS...] inspect [[[KERNEL-VERSION] KERNEL-IMAGE]\n"
" [INITRD ...]]\n"
" kernel-install [OPTIONS...] list\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -v --verbose Increase verbosity\n"
" --esp-path=PATH Path to the EFI System Partition (ESP)\n"
" --boot-path=PATH Path to the $BOOT partition\n"
" --make-entry-directory=yes|no|auto\n"
" Create $BOOT/ENTRY-TOKEN/ directory\n"
" --entry-type=type1|type2|all\n"
" Operate only on the specified bootloader\n"
" entry type\n"
" --entry-token=machine-id|os-id|os-image-id|auto|literal:…\n"
" Entry token to be used for this installation\n"
" --no-pager Do not pipe inspect output into a pager\n"
" --json=pretty|short|off Generate JSON output\n"
" --no-legend Do not show the headers and footers\n"
" --root=PATH Operate on an alternate filesystem root\n"
" --image=PATH Operate on disk image as filesystem root\n"
" --image-policy=POLICY Specify disk image dissection policy\n"
"\n"
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
/* Note: column widths are not synced, because the verbs table is very wide. */
help_cmdline("[OPTIONS…] COMMAND …");
help_abstract("Add and remove kernel and initrd images to and from the boot partition.");
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;
printf("\n"
"This program may also be invoked as 'installkernel':\n"
" installkernel [OPTIONS...] VERSION VMLINUZ [MAP] [INSTALLATION-DIR]\n"
"(The optional arguments are passed by kernel build system, but ignored.)\n"
"\n"
"See the %2$s for details.\n",
program_invocation_short_name,
link,
ansi_underline(),
ansi_normal(),
ansi_highlight(),
ansi_normal());
" installkernel [OPTIONS...] VERSION VMLINUZ [MAP] [INSTALLATION-DIR]\n"
"(The optional arguments are passed by kernel build system, but ignored.)\n");
help_man_page_reference("kernel-install", "8");
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_LEGEND,
ARG_ESP_PATH,
ARG_BOOT_PATH,
ARG_MAKE_ENTRY_DIRECTORY,
ARG_ENTRY_TOKEN,
ARG_NO_PAGER,
ARG_JSON,
ARG_ROOT,
ARG_IMAGE,
ARG_IMAGE_POLICY,
ARG_BOOT_ENTRY_TYPE,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "verbose", no_argument, NULL, 'v' },
{ "esp-path", required_argument, NULL, ARG_ESP_PATH },
{ "boot-path", required_argument, NULL, ARG_BOOT_PATH },
{ "make-entry-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY },
{ "entry-token", required_argument, NULL, ARG_ENTRY_TOKEN },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "json", required_argument, NULL, ARG_JSON },
{ "root", required_argument, NULL, ARG_ROOT },
{ "image", required_argument, NULL, ARG_IMAGE },
{ "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "entry-type", required_argument, NULL, ARG_BOOT_ENTRY_TYPE },
{}
};
int t, r;
VERB_COMMON_HELP(help);
static int parse_argv(int argc, char *argv[], char ***remaining_args) {
assert(argc >= 0);
assert(argv);
assert(remaining_args);
while ((t = getopt_long(argc, argv, "hv", options, NULL)) >= 0)
switch (t) {
case 'h':
OptionParser opts = { argc, argv };
int r;
FOREACH_OPTION_OR_RETURN(c, &opts)
switch (c) {
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_NO_LEGEND:
OPTION_COMMON_NO_LEGEND:
arg_legend = false;
break;
case 'v':
OPTION('v', "verbose", NULL, "Increase verbosity"):
log_set_max_level(LOG_DEBUG);
arg_verbose = true;
break;
case ARG_ESP_PATH:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_esp_path);
OPTION_LONG("esp-path", "PATH", "Path to the EFI System Partition (ESP)"):
r = parse_path_argument(opts.arg, /* suppress_root= */ false, &arg_esp_path);
if (r < 0)
return log_oom();
return r;
break;
case ARG_BOOT_PATH:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_xbootldr_path);
OPTION_LONG("boot-path", "PATH", "Path to the $BOOT partition"):
r = parse_path_argument(opts.arg, /* suppress_root= */ false, &arg_xbootldr_path);
if (r < 0)
return log_oom();
return r;
break;
case ARG_MAKE_ENTRY_DIRECTORY:
if (streq(optarg, "auto"))
OPTION_COMMON_MAKE_ENTRY_DIRECTORY:
if (streq(opts.arg, "auto"))
arg_make_entry_directory = -1;
else {
r = parse_boolean_argument("--make-entry-directory=", optarg, NULL);
r = parse_boolean_argument("--make-entry-directory=", opts.arg, NULL);
if (r < 0)
return r;
@@ -1655,85 +1625,70 @@ static int parse_argv(int argc, char *argv[]) {
}
break;
case ARG_ENTRY_TOKEN:
r = parse_boot_entry_token_type(optarg, &arg_entry_token_type, &arg_entry_token);
OPTION_COMMON_ENTRY_TOKEN:
r = parse_boot_entry_token_type(opts.arg, &arg_entry_token_type, &arg_entry_token);
if (r < 0)
return r;
break;
case ARG_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
case ARG_JSON:
r = parse_json_argument(optarg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
case ARG_ROOT:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_root);
if (r < 0)
return r;
break;
case ARG_IMAGE:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image);
if (r < 0)
return r;
break;
case ARG_IMAGE_POLICY:
r = parse_image_policy_argument(optarg, &arg_image_policy);
if (r < 0)
return r;
break;
case ARG_BOOT_ENTRY_TYPE: {
if (isempty(optarg) || streq(optarg, "all")) {
OPTION_LONG("entry-type", "TYPE",
"Operate only on the specified bootloader entry type (type1, type2, all)"): {
if (isempty(opts.arg) || streq(opts.arg, "all")) {
arg_boot_entry_type = _BOOT_ENTRY_TYPE_INVALID;
break;
}
BootEntryType e = boot_entry_type_from_string(optarg);
BootEntryType e = boot_entry_type_from_string(opts.arg);
if (e < 0)
return log_error_errno(e, "Invalid entry type: %s", optarg);
return log_error_errno(e, "Invalid entry type: %s", opts.arg);
arg_boot_entry_type = e;
break;
}
case '?':
return -EINVAL;
OPTION_COMMON_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
default:
assert_not_reached();
OPTION_COMMON_JSON:
r = parse_json_argument(opts.arg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
OPTION_LONG("root", "PATH", "Operate on an alternate filesystem root"):
r = parse_path_argument(opts.arg, /* suppress_root= */ false, &arg_root);
if (r < 0)
return r;
break;
OPTION_LONG("image", "PATH", "Operate on disk image as filesystem root"):
r = parse_path_argument(opts.arg, /* suppress_root= */ false, &arg_image);
if (r < 0)
return r;
break;
OPTION_LONG("image-policy", "POLICY", "Specify disk image dissection policy"):
r = parse_image_policy_argument(opts.arg, &arg_image_policy);
if (r < 0)
return r;
break;
}
if (arg_image && arg_root)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Please specify either --root= or --image=, the combination of both is not supported.");
*remaining_args = option_parser_get_args(&opts);
return 1;
}
static int kernel_install_main(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "add", 1, VERB_ANY, 0, verb_add },
{ "add-all", 1, 1, 0, verb_add_all },
{ "remove", 2, VERB_ANY, 0, verb_remove },
{ "inspect", 1, VERB_ANY, VERB_DEFAULT, verb_inspect },
{ "list", 1, 1, 0, verb_list },
{}
};
return dispatch_verb(argc, argv, verbs, /* userdata= */ NULL);
}
static int run(int argc, char* argv[]) {
int r;
log_setup();
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
@@ -1762,9 +1717,9 @@ static int run(int argc, char* argv[]) {
}
if (invoked_as(argv, "installkernel"))
return run_as_installkernel(argc, argv);
return run_as_installkernel(args);
return kernel_install_main(argc, argv);
return dispatch_verb_with_args(args, /* userdata= */ NULL);
}
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
+2 -2
View File
@@ -193,7 +193,7 @@ static int verb_validate(int argc, char *argv[], uintptr_t _data, void *userdata
if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key);
if (r < 0)
return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
return r;
}
r = openssl_load_private_key(
@@ -259,7 +259,7 @@ static int verb_extract_public(int argc, char *argv[], uintptr_t _data, void *us
if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key);
if (r < 0)
return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
return r;
}
r = openssl_load_private_key(
+68 -102
View File
@@ -1,9 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include "sd-bus.h"
#include "ansi-color.h"
#include "alloc-util.h"
#include "build.h"
#include "bus-error.h"
@@ -13,15 +12,16 @@
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
#include "help-util.h"
#include "kbd-util.h"
#include "locale-setup.h"
#include "main-func.h"
#include "memory-util.h"
#include "options.h"
#include "pager.h"
#include "parse-argument.h"
#include "path-util.h"
#include "polkit-agent.h"
#include "pretty-print.h"
#include "runtime-scope.h"
#include "string-util.h"
#include "strv.h"
@@ -147,6 +147,8 @@ static int print_status_info(StatusInfo *i) {
return table_print_or_warn(table);
}
VERB(verb_show_status, "status", NULL, VERB_ANY, 1, VERB_DEFAULT,
"Show current locale settings");
static int verb_show_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(status_info_clear) StatusInfo info = {};
static const struct bus_properties_map map[] = {
@@ -179,6 +181,8 @@ static int verb_show_status(int argc, char *argv[], uintptr_t _data, void *userd
return print_status_info(&info);
}
VERB(verb_set_locale, "set-locale", "LOCALE...", 2, VERB_ANY, 0,
"Set system locale");
static int verb_set_locale(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -207,6 +211,8 @@ static int verb_set_locale(int argc, char *argv[], uintptr_t _data, void *userda
return 0;
}
VERB_NOARG(verb_list_locales, "list-locales",
"Show known locales");
static int verb_list_locales(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_strv_free_ char **l = NULL;
int r;
@@ -221,6 +227,8 @@ static int verb_list_locales(int argc, char *argv[], uintptr_t _data, void *user
return 0;
}
VERB(verb_set_vconsole_keymap, "set-keymap", "MAP [MAP]", 2, 3, 0,
"Set console and X11 keyboard mappings");
static int verb_set_vconsole_keymap(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
const char *map, *toggle_map;
@@ -245,6 +253,8 @@ static int verb_set_vconsole_keymap(int argc, char *argv[], uintptr_t _data, voi
return 0;
}
VERB_NOARG(verb_list_vconsole_keymaps, "list-keymaps",
"Show known virtual console keyboard mappings");
static int verb_list_vconsole_keymaps(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_strv_free_ char **l = NULL;
int r;
@@ -260,6 +270,8 @@ static int verb_list_vconsole_keymaps(int argc, char *argv[], uintptr_t _data, v
return 0;
}
VERB(verb_set_x11_keymap, "set-x11-keymap", "LAYOUT [MODEL [VARIANT [OPTIONS]]]", 2, 5, 0,
"Set X11 and console keyboard mappings");
static int verb_set_x11_keymap(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
const char *layout, *model, *variant, *options;
@@ -295,6 +307,14 @@ static const char* xkb_directory(void) {
return cached;
}
VERB_NOARG(verb_list_x11_keymaps, "list-x11-keymap-models",
"Show known X11 keyboard mapping models");
VERB_NOARG(verb_list_x11_keymaps, "list-x11-keymap-layouts",
"Show known X11 keyboard mapping layouts");
VERB(verb_list_x11_keymaps, "list-x11-keymap-variants", "[LAYOUT]", VERB_ANY, 2, 0,
"Show known X11 keyboard mapping variants");
VERB_NOARG(verb_list_x11_keymaps, "list-x11-keymap-options",
"Show known X11 keyboard mapping options");
static int verb_list_x11_keymaps(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_strv_free_ char **list = NULL;
@@ -402,143 +422,88 @@ static int verb_list_x11_keymaps(int argc, char *argv[], uintptr_t _data, void *
}
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL, *verbs = NULL;
int r;
r = terminal_urlify_man("localectl", "1", &link);
r = verbs_get_help_table(&verbs);
if (r < 0)
return log_oom();
return r;
printf("%s [OPTIONS...] COMMAND ...\n\n"
"%sQuery or change system locale and keyboard settings.%s\n"
"\nCommands:\n"
" status Show current locale settings\n"
" set-locale LOCALE... Set system locale\n"
" list-locales Show known locales\n"
" set-keymap MAP [MAP] Set console and X11 keyboard mappings\n"
" list-keymaps Show known virtual console keyboard mappings\n"
" set-x11-keymap LAYOUT [MODEL [VARIANT [OPTIONS]]]\n"
" Set X11 and console keyboard mappings\n"
" list-x11-keymap-models Show known X11 keyboard mapping models\n"
" list-x11-keymap-layouts Show known X11 keyboard mapping layouts\n"
" list-x11-keymap-variants [LAYOUT]\n"
" Show known X11 keyboard mapping variants\n"
" list-x11-keymap-options Show known X11 keyboard mapping options\n"
"\nOptions:\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -l --full Do not ellipsize output\n"
" --no-pager Do not pipe output into a pager\n"
" --no-ask-password Do not prompt for password\n"
" -H --host=[USER@]HOST Operate on remote host\n"
" -M --machine=CONTAINER Operate on local container\n"
" --no-convert Don't convert keyboard mappings\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
(void) table_sync_column_widths(0, verbs, options);
help_cmdline("[OPTIONS…] COMMAND …");
help_abstract("Query or change system locale and keyboard settings.");
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("localectl", "1");
return 0;
}
static int verb_help(int argc, char *argv[], uintptr_t _data, void *userdata) {
return help();
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_NO_CONVERT,
ARG_NO_ASK_PASSWORD
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "full", no_argument, NULL, 'l' },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ "no-convert", no_argument, NULL, ARG_NO_CONVERT },
{}
};
int r, c;
VERB_COMMON_HELP_HIDDEN(help);
static int parse_argv(int argc, char *argv[], char ***remaining_args) {
assert(argc >= 0);
assert(argv);
assert(remaining_args);
while ((c = getopt_long(argc, argv, "hlH:M:", options, NULL)) >= 0)
OptionParser opts = { argc, argv };
int r;
FOREACH_OPTION_OR_RETURN(c, &opts)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case 'l':
OPTION('l', "full", NULL, "Do not ellipsize output"):
arg_full = true;
break;
case ARG_NO_CONVERT:
arg_convert = false;
break;
case ARG_NO_PAGER:
OPTION_COMMON_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
case ARG_NO_ASK_PASSWORD:
OPTION_COMMON_NO_ASK_PASSWORD:
arg_ask_password = false;
break;
case 'H':
OPTION_COMMON_HOST:
arg_transport = BUS_TRANSPORT_REMOTE;
arg_host = optarg;
arg_host = opts.arg;
break;
case 'M':
r = parse_machine_argument(optarg, &arg_host, &arg_transport);
OPTION_COMMON_MACHINE:
r = parse_machine_argument(opts.arg, &arg_host, &arg_transport);
if (r < 0)
return r;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
OPTION_LONG("no-convert", NULL, "Don't convert keyboard mappings"):
arg_convert = false;
break;
}
*remaining_args = option_parser_get_args(&opts);
return 1;
}
static int localectl_main(sd_bus *bus, int argc, char *argv[]) {
static const Verb verbs[] = {
{ "status", VERB_ANY, 1, VERB_DEFAULT, verb_show_status },
{ "set-locale", 2, VERB_ANY, 0, verb_set_locale },
{ "list-locales", VERB_ANY, 1, 0, verb_list_locales },
{ "set-keymap", 2, 3, 0, verb_set_vconsole_keymap },
{ "list-keymaps", VERB_ANY, 1, 0, verb_list_vconsole_keymaps },
{ "set-x11-keymap", 2, 5, 0, verb_set_x11_keymap },
{ "list-x11-keymap-models", VERB_ANY, 1, 0, verb_list_x11_keymaps },
{ "list-x11-keymap-layouts", VERB_ANY, 1, 0, verb_list_x11_keymaps },
{ "list-x11-keymap-variants", VERB_ANY, 2, 0, verb_list_x11_keymaps },
{ "list-x11-keymap-options", VERB_ANY, 1, 0, verb_list_x11_keymaps },
{ "help", VERB_ANY, VERB_ANY, 0, verb_help }, /* Not documented, but supported since it has been created. */
{}
};
return dispatch_verb(argc, argv, verbs, bus);
}
static int run(int argc, char *argv[]) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
@@ -546,7 +511,8 @@ static int run(int argc, char *argv[]) {
setlocale(LC_ALL, "");
log_setup();
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
@@ -554,7 +520,7 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return bus_log_connect_error(r, arg_transport, RUNTIME_SCOPE_SYSTEM);
return localectl_main(bus, argc, argv);
return dispatch_verb_with_args(args, bus);
}
DEFINE_MAIN_FUNCTION(run);
+1 -1
View File
@@ -960,7 +960,7 @@ static int build_policy_digest(bool sign) {
if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key);
if (r < 0)
return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
return r;
}
r = openssl_load_private_key(
+1 -1
View File
@@ -461,7 +461,7 @@ static int verb_sign(int argc, char *argv[], uintptr_t _data, void *userdata) {
if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key);
if (r < 0)
return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
return r;
}
r = openssl_load_private_key(
+9 -15
View File
@@ -2249,11 +2249,7 @@ int _table_sync_column_widths(size_t column, Table *a, ...) {
}
int table_print_full(Table *t, FILE *f, bool flush) {
size_t n_rows, *minimum_width, *maximum_width, display_columns, *requested_width,
table_minimum_width, table_maximum_width, table_requested_width, table_effective_width,
*width = NULL;
_cleanup_free_ size_t *sorted = NULL;
uint64_t *column_weight, weight_sum;
int r;
assert(t);
@@ -2264,7 +2260,7 @@ int table_print_full(Table *t, FILE *f, bool flush) {
/* Ensure we have no incomplete rows */
assert(t->n_cells % t->n_columns == 0);
n_rows = t->n_cells / t->n_columns;
size_t n_rows = t->n_cells / t->n_columns;
assert(n_rows > 0); /* at least the header row must be complete */
if (t->sort_map) {
@@ -2280,17 +2276,14 @@ int table_print_full(Table *t, FILE *f, bool flush) {
typesafe_qsort_r(sorted, n_rows, table_data_compare, t);
}
if (t->display_map)
display_columns = t->n_display_map;
else
display_columns = t->n_columns;
size_t display_columns = t->display_map ? t->n_display_map : t->n_columns;
assert(display_columns > 0);
minimum_width = newa(size_t, display_columns);
maximum_width = newa(size_t, display_columns);
requested_width = newa(size_t, display_columns);
column_weight = newa0(uint64_t, display_columns);
size_t *minimum_width = newa(size_t, display_columns),
*maximum_width = newa(size_t, display_columns),
*requested_width = newa(size_t, display_columns),
*width = NULL;
uint64_t *column_weight = newa0(uint64_t, display_columns);
for (size_t j = 0; j < display_columns; j++) {
minimum_width[j] = 1;
@@ -2373,10 +2366,11 @@ int table_print_full(Table *t, FILE *f, bool flush) {
}
/* One space between each column */
size_t table_requested_width, table_minimum_width, table_maximum_width, table_effective_width;
table_requested_width = table_minimum_width = table_maximum_width = display_columns - 1;
/* Calculate the total weight for all columns, plus the minimum, maximum and requested width for the table. */
weight_sum = 0;
uint64_t weight_sum = 0;
for (size_t j = 0; j < display_columns; j++) {
weight_sum += column_weight[j];
+9
View File
@@ -137,6 +137,15 @@ typedef struct Option {
OPTION_SHORT('j', NULL, \
"Equivalent to --json=pretty (on TTY) or --json=short (otherwise)")
#define OPTION_COMMON_ENTRY_TOKEN \
OPTION_LONG("entry-token", "TOKEN", \
"Entry token to use for this installation " \
"(machine-id, os-id, os-image-id, auto, literal:…)")
#define OPTION_COMMON_MAKE_ENTRY_DIRECTORY \
OPTION_LONG("make-entry-directory", \
"BOOL|auto", "Create $BOOT/ENTRY-TOKEN/ directory")
#define OPTION_COMMON_PRIVATE_KEY(purpose) \
OPTION_LONG("private-key", "PATH|URI", purpose)
+69 -20
View File
@@ -7,6 +7,7 @@
#include "log.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "verbs.h"
#include "virt.h"
@@ -160,6 +161,72 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
return _dispatch_verb_with_args(strv_skip(argv, optind), verbs, verbs + n, userdata);
}
#define VERB_SYNOPSIS_WIDTH_SANE 25
static const char* find_point_to_break(const char *s, size_t max_width) {
/* Locate the first space, preferably after max_width, or the last space otherwise.
* Return the part after the space. */
if (strlen(s) <= max_width)
return NULL;
const char *p = strchr(s + max_width, ' ') ?: strrchr(s, ' ');
return p ? p + 1 : NULL;
}
static int verb_add_help_one(Table *table, const Verb *verb) {
assert(table);
assert(verb);
bool is_default = FLAGS_SET(verb->flags, VERB_DEFAULT);
int r;
/* We indent the option string by two spaces. We could set the minimum cell width and
* right-align for a similar result, but that'd be more work. This is only used for
* display. */
_cleanup_free_ char *s = strjoin(" ",
is_default ? "[" : "",
verb->verb,
verb->argspec ? " " : "",
strempty(verb->argspec),
is_default ? "]" : "");
if (!s)
return log_oom();
const char *ss = NULL;
if (columns() < VERB_SYNOPSIS_WIDTH_SANE * 4) {
/* If the synopsis is very wide, try to split it up. But do this only if the terminal
* is not very wide. If it _is_ wide, the broken up synopsis would look silly. */
const char *p = find_point_to_break(s, VERB_SYNOPSIS_WIDTH_SANE), *p2 = NULL;
if (p) {
const char *s1 = strndupa_safe(s, p - s), *s2 = NULL;
p2 = find_point_to_break(p, VERB_SYNOPSIS_WIDTH_SANE - 4); /* we indent by two spaces more */
if (p2)
s2 = strndupa_safe(p, p2 - p);
if (s2)
ss = strjoina(s1, "\n ", s2, "\n ", p2);
else
ss = strjoina(s1, "\n ", p);
}
}
r = table_add_cell(table, NULL, TABLE_STRING, ss ?: s);
if (r < 0)
return table_log_add_error(r);
_cleanup_strv_free_ char **t = strv_split(verb->help, /* separators= */ NULL);
if (!t)
return log_oom();
r = table_add_many(table, TABLE_STRV_WRAPPED, t);
if (r < 0)
return table_log_add_error(r);
return 0;
}
int _verbs_get_help_table(
const Verb verbs[],
const Verb verbs_end[],
@@ -192,27 +259,9 @@ int _verbs_get_help_table(
/* No help string — we do not show the verb */
continue;
bool is_default = FLAGS_SET(verb->flags, VERB_DEFAULT);
/* We indent the option string by two spaces. We could set the minimum cell width and
* right-align for a similar result, but that'd be more work. This is only used for
* display. */
r = table_add_cell_stringf(table, NULL, " %s%s%s%s%s",
is_default ? "[" : "",
verb->verb,
verb->argspec ? " " : "",
strempty(verb->argspec),
is_default ? "]" : "");
r = verb_add_help_one(table, verb);
if (r < 0)
return table_log_add_error(r);
_cleanup_strv_free_ char **s = strv_split(verb->help, /* separators= */ NULL);
if (!s)
return log_oom();
r = table_add_many(table, TABLE_STRV_WRAPPED, s);
if (r < 0)
return table_log_add_error(r);
return r;
}
table_set_header(table, false);