]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bootctl: optionally, output entries in JSON format
authorLennart Poettering <lennart@poettering.net>
Wed, 23 Mar 2022 15:08:36 +0000 (16:08 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 28 Mar 2022 14:00:25 +0000 (16:00 +0200)
Replaces: #18387
Fixes: #18094
man/bootctl.xml
src/boot/bootctl.c

index ff49a8043c8eb38c2c74ec2d41ace80dc501b07a..8d5b1d3d2c3ae393e2cdd5313947e045bc77a996 100644 (file)
         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>
       </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>
index cc79f51655f257a093ac3726c36b1d5340dfb0df..8596939ff35dec3345a4289d6639ba68c1ccb9e5 100644 (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);