bootctl: optionally, output entries in JSON format

Replaces: #18387
Fixes: #18094
This commit is contained in:
Lennart Poettering 2022-03-23 16:08:36 +01:00
parent 53350c7bba
commit 0d1506d4a8
2 changed files with 55 additions and 2 deletions

View file

@ -92,7 +92,10 @@
url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>, as well as any
other entries discovered or automatically generated by a boot loader implementing the <ulink
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader
Interface</ulink>.</para></listitem>
Interface</ulink>.</para>
<para>JSON output may be requested with <option>--json=</option>.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -315,6 +318,7 @@
</varlistentry>
<xi:include href="standard-options.xml" xpointer="no-pager"/>
<xi:include href="standard-options.xml" xpointer="json" />
<xi:include href="standard-options.xml" xpointer="help"/>
<xi:include href="standard-options.xml" xpointer="version"/>
</variablelist>

View file

@ -70,6 +70,7 @@ static enum {
ARG_ENTRY_TOKEN_AUTO,
} arg_entry_token_type = ARG_ENTRY_TOKEN_AUTO;
static char *arg_entry_token = NULL;
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
@ -1420,6 +1421,8 @@ static int help(int argc, char *argv[], void *userdata) {
" 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"
" --json=pretty|short|off\n"
" Generate JSON output\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@ -1441,6 +1444,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_GRACEFUL,
ARG_MAKE_ENTRY_DIRECTORY,
ARG_ENTRY_TOKEN,
ARG_JSON,
};
static const struct option options[] = {
@ -1458,6 +1462,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "make-entry-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY },
{ "make-machine-id-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY }, /* Compatibility alias */
{ "entry-token", required_argument, NULL, ARG_ENTRY_TOKEN },
{ "json", required_argument, NULL, ARG_JSON },
{}
};
@ -1552,6 +1557,13 @@ static int parse_argv(int argc, char *argv[]) {
}
break;
case ARG_JSON:
r = parse_json_argument(optarg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
case '?':
return -EINVAL;
@ -1812,7 +1824,44 @@ static int verb_list(int argc, char *argv[], void *userdata) {
else
(void) boot_entries_augment_from_loader(&config, efi_entries, /* only_auto= */ false);
if (config.n_entries == 0)
if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
pager_open(arg_pager_flags);
for (size_t i = 0; i < config.n_entries; i++) {
_cleanup_free_ char *opts = NULL;
BootEntry *e = config.entries + i;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
if (!strv_isempty(e->options)) {
opts = strv_join(e->options, " ");
if (!opts)
return log_oom();
}
r = json_build(&v, JSON_BUILD_OBJECT(
JSON_BUILD_PAIR_CONDITION(e->id, "id", JSON_BUILD_STRING(e->id)),
JSON_BUILD_PAIR_CONDITION(e->path, "path", JSON_BUILD_STRING(e->path)),
JSON_BUILD_PAIR_CONDITION(e->root, "root", JSON_BUILD_STRING(e->root)),
JSON_BUILD_PAIR_CONDITION(e->title, "title", JSON_BUILD_STRING(e->title)),
JSON_BUILD_PAIR_CONDITION(boot_entry_title(e), "showTitle", JSON_BUILD_STRING(boot_entry_title(e))),
JSON_BUILD_PAIR_CONDITION(e->sort_key, "sortKey", JSON_BUILD_STRING(e->sort_key)),
JSON_BUILD_PAIR_CONDITION(e->version, "version", JSON_BUILD_STRING(e->version)),
JSON_BUILD_PAIR_CONDITION(e->machine_id, "machineId", JSON_BUILD_STRING(e->machine_id)),
JSON_BUILD_PAIR_CONDITION(e->architecture, "architecture", JSON_BUILD_STRING(e->architecture)),
JSON_BUILD_PAIR_CONDITION(opts, "options", JSON_BUILD_STRING(opts)),
JSON_BUILD_PAIR_CONDITION(e->kernel, "linux", JSON_BUILD_STRING(e->kernel)),
JSON_BUILD_PAIR_CONDITION(e->efi, "efi", JSON_BUILD_STRING(e->efi)),
JSON_BUILD_PAIR_CONDITION(!strv_isempty(e->initrd), "initrd", JSON_BUILD_STRV(e->initrd)),
JSON_BUILD_PAIR_CONDITION(e->device_tree, "devicetree", JSON_BUILD_STRING(e->device_tree)),
JSON_BUILD_PAIR_CONDITION(!strv_isempty(e->device_tree_overlay), "devicetreeOverlay", JSON_BUILD_STRV(e->device_tree_overlay))));
if (r < 0)
return log_oom();
json_variant_dump(v, arg_json_format_flags, stdout, NULL);
}
} else if (config.n_entries == 0)
log_info("No boot loader entries found.");
else {
pager_open(arg_pager_flags);