diff --git a/man/kernel-install.xml b/man/kernel-install.xml
index 64137ce61c2..822c2892598 100644
--- a/man/kernel-install.xml
+++ b/man/kernel-install.xml
@@ -40,7 +40,9 @@
kernel-install
OPTIONS
inspect
+ KERNEL-VERSION
KERNEL-IMAGE
+ INITRD-FILE
@@ -176,11 +178,14 @@
- inspect [KERNEL-IMAGE]
+
+ inspect [[KERNEL-VERSION] KERNEL-IMAGE] [INITRD-FILE ...]
+
Shows the various paths and parameters configured or auto-detected. In particular shows the
values of the various $KERNEL_INSTALL_* environment variables listed
- below.
+ below. The option can be used to get the output of this verb as a JSON
+ object.
@@ -298,6 +303,8 @@
+
+
diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c
index b72e2ac79a0..1c5621e6c86 100644
--- a/src/kernel-install/kernel-install.c
+++ b/src/kernel-install/kernel-install.c
@@ -13,6 +13,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "find-esp.h"
+#include "format-table.h"
#include "id128-util.h"
#include "kernel-image.h"
#include "main-func.h"
@@ -32,6 +33,8 @@ static bool arg_verbose = false;
static char *arg_esp_path = NULL;
static char *arg_xbootldr_path = NULL;
static int arg_make_entry_directory = -1; /* tristate */
+static PagerFlags arg_pager_flags = 0;
+static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
@@ -860,8 +863,6 @@ static int context_build_arguments(Context *c) {
break;
case ACTION_INSPECT:
- assert(!c->version);
- assert(!c->initrds);
verb = "add|remove";
break;
@@ -1081,39 +1082,92 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
static int verb_inspect(int argc, char *argv[], void *userdata) {
Context *c = ASSERT_PTR(userdata);
- _cleanup_free_ char *joined = NULL;
+ _cleanup_(table_unrefp) Table *t = NULL;
int r;
c->action = ACTION_INSPECT;
- if (argc >= 2) {
+ if (argc == 2) {
r = context_set_kernel(c, argv[1]);
if (r < 0)
return r;
+ } else if (argc >= 3) {
+ r = context_set_version(c, argv[1]);
+ if (r < 0)
+ return r;
+
+ r = context_set_kernel(c, argv[2]);
+ if (r < 0)
+ return r;
+
+ r = context_set_initrds(c, strv_skip(argv, 3));
+ if (r < 0)
+ return r;
}
r = context_prepare_execution(c);
if (r < 0)
return r;
- printf("%sBoot Loader Entries:%s\n", ansi_underline(), ansi_normal());
- printf(" $BOOT: %s\n", c->boot_root);
- printf(" Token: %s\n", c->entry_token);
- puts("");
+ t = table_new_vertical();
+ if (!t)
+ return log_oom();
- printf("%sUsing plugins:%s\n", ansi_underline(), ansi_normal());
- strv_print_full(c->plugins, " ");
- puts("");
+ r = table_add_many(t,
+ TABLE_FIELD, "Machine ID",
+ TABLE_ID128, c->machine_id,
+ TABLE_FIELD, "Kernel Image Type",
+ TABLE_STRING, kernel_image_type_to_string(c->kernel_image_type),
+ TABLE_FIELD, "Layout",
+ TABLE_STRING, context_get_layout(c),
+ TABLE_FIELD, "Boot Root",
+ TABLE_STRING, c->boot_root,
+ TABLE_FIELD, "Entry Token Type",
+ TABLE_STRING, boot_entry_token_type_to_string(c->entry_token_type),
+ TABLE_FIELD, "Entry Token",
+ TABLE_STRING, c->entry_token,
+ TABLE_FIELD, "Entry Directory",
+ TABLE_STRING, c->entry_dir,
+ TABLE_FIELD, "Kernel Version",
+ TABLE_STRING, c->version,
+ TABLE_FIELD, "Kernel",
+ TABLE_STRING, c->kernel,
+ TABLE_FIELD, "Initrds",
+ TABLE_STRV, c->initrds,
+ TABLE_FIELD, "Initrd Generator",
+ TABLE_STRING, c->initrd_generator,
+ TABLE_FIELD, "UKI Generator",
+ TABLE_STRING, c->uki_generator,
+ TABLE_FIELD, "Plugins",
+ TABLE_STRV, c->plugins,
+ TABLE_FIELD, "Plugin Environment",
+ TABLE_STRV, c->envp);
+ if (r < 0)
+ return table_log_add_error(r);
- printf("%sPlugin environment:%s\n", ansi_underline(), ansi_normal());
- strv_print_full(c->envp, " ");
- puts("");
+ if (arg_json_format_flags & JSON_FORMAT_OFF) {
+ r = table_add_many(t,
+ TABLE_FIELD, "Plugin Arguments",
+ TABLE_STRV, strv_skip(c->argv, 1));
+ if (r < 0)
+ return table_log_add_error(r);
+ }
- printf("%sPlugin arguments:%s\n", ansi_underline(), ansi_normal());
- joined = strv_join(strv_skip(c->argv, 1), " ");
- printf(" %s\n", strna(joined));
+ table_set_ersatz_string(t, TABLE_ERSATZ_UNSET);
- return 0;
+ for (size_t row = 1; row < table_get_rows(t); row++) {
+ _cleanup_free_ char *name = NULL;
+
+ name = strdup(table_get_at(t, row, 0));
+ if (!name)
+ return log_oom();
+
+ r = table_set_json_field_name(t, row - 1, delete_chars(name, " "));
+ if (r < 0)
+ return log_error_errno(r, "Failed to set JSON field name: %m");
+ }
+
+ return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, /* show_header= */ false);
}
static int help(void) {
@@ -1127,9 +1181,9 @@ static int help(void) {
printf("%1$s [OPTIONS...] COMMAND ...\n\n"
"%2$sAdd and remove kernel and initrd images to and from /boot%3$s\n"
"\nUsage:\n"
- " kernel-install [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE...]\n"
+ " kernel-install [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD ...]\n"
" kernel-install [OPTIONS...] remove KERNEL-VERSION\n"
- " kernel-install [OPTIONS...] inspect [KERNEL-IMAGE]\n"
+ " kernel-install [OPTIONS...] inspect [KERNEL-VERSION] KERNEL-IMAGE [INITRD ...]\n"
"\n"
"Options:\n"
" -h --help Show this help\n"
@@ -1141,6 +1195,9 @@ static int help(void) {
" Create $BOOT/ENTRY-TOKEN/ directory\n"
" --entry-token=machine-id|os-id|os-image-id|auto|literal:…\n"
" Entry token to use for this installation\n"
+ " --no-pager Do not pipe inspect output into a pager\n"
+ " --json=pretty|short|off\n"
+ " Generate JSON output\n"
"\n"
"This program may also be invoked as 'installkernel':\n"
" installkernel [OPTIONS...] VERSION VMLINUZ [MAP] [INSTALLATION-DIR]\n"
@@ -1162,6 +1219,8 @@ static int parse_argv(int argc, char *argv[], Context *c) {
ARG_BOOT_PATH,
ARG_MAKE_ENTRY_DIRECTORY,
ARG_ENTRY_TOKEN,
+ ARG_NO_PAGER,
+ ARG_JSON,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
@@ -1171,6 +1230,8 @@ static int parse_argv(int argc, char *argv[], Context *c) {
{ "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 },
{}
};
int t, r;
@@ -1222,6 +1283,16 @@ static int parse_argv(int argc, char *argv[], Context *c) {
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 '?':
return -EINVAL;
@@ -1236,7 +1307,7 @@ static int run(int argc, char* argv[]) {
static const Verb verbs[] = {
{ "add", 3, VERB_ANY, 0, verb_add },
{ "remove", 2, VERB_ANY, 0, verb_remove },
- { "inspect", 1, 2, VERB_DEFAULT, verb_inspect },
+ { "inspect", 1, VERB_ANY, VERB_DEFAULT, verb_inspect },
{}
};
_cleanup_(context_done) Context c = {
diff --git a/src/kernel-install/test-kernel-install.sh b/src/kernel-install/test-kernel-install.sh
index 30bee06b533..931fae5372f 100755
--- a/src/kernel-install/test-kernel-install.sh
+++ b/src/kernel-install/test-kernel-install.sh
@@ -269,3 +269,40 @@ test -d "$BOOT_ROOT/hoge/1.1.1"
test ! -e "$BOOT_ROOT/hoge/1.1.1"
test -d "$BOOT_ROOT/hoge"
rmdir "$BOOT_ROOT/hoge"
+
+###########################################
+# tests for --json=
+###########################################
+output="$("$kernel_install" -v --json=pretty inspect 1.1.1 "$D/sources/linux")"
+
+diff -u <(echo "$output") - <