kernel-install: convert to the new option and verb parsers
The verb synopses are very long because of the many parameters. Previously were shown without help and occupied all available columns. With the autogenerated help format, this doesn't work great. So the verbs and options tables are not synced, so that help for options can use more columns. I think in this case this is better than the alternatives. Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+103
-148
@@ -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();
|
||||
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();
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user