Skip to content

JSON output support#190

Open
pvxe wants to merge 2 commits into
rhboot:mainfrom
pvxe:main
Open

JSON output support#190
pvxe wants to merge 2 commits into
rhboot:mainfrom
pvxe:main

Conversation

@pvxe

@pvxe pvxe commented Jul 28, 2023

Copy link
Copy Markdown

(JSON output support has been discussed in the past. #70)

Add --json option to enable JSON output support when compiling efibootmgr with it.
This output is compact and intended to be fed to other programs that want to interface with efibootmgr.

To enable JSON support, simply compile with make ... JSON=1 compilation flag.

Adds a new optional dependency with libjansson.

If the user runs efibootmgr --json without json support being compiled, it will print the following message:

JSON support is not built-in

The rationale behind this change is that I'd like to avoid parsing textual output from efibootmgr.

As additional context for these changes: I'm working on the development of a python program used for remote management of computers. This python program needs to retrieve BootOrder, BootNext and the boot entries of the machine it's running on. The program runs an efibootmgr subprocess for such tasks.


Example:

./src/efibootmgr --json | python -m json.tool
{
    "BootCurrent": "000D",
    "Timeout": 1,
    "BootOrder": [
        "0000",
        "000D",
        "0001",
        "000F",
        "0010",
    ],
    "vars": [
        {
            "name": "Boot0000",
            "active": true,
            "description": "Windows Boot Manager"
        },
        {
            "name": "Boot0001",
            "active": true,
            "description": "UEFI iPXE"
        },
        {
            "name": "Boot000D",
            "active": true,
            "description": "UEFI OS"
        },
        {
            "name": "Boot000F",
            "active": true,
            "description": "UEFI: IP4 Qualcomm Atheros PCIe Network Controller"
        },
        {
            "name": "Boot0010",
            "active": true,
            "description": "UEFI: IP6 Qualcomm Atheros PCIe Network Controller"
        },
    ]
}

@pvxe

pvxe commented Feb 27, 2024

Copy link
Copy Markdown
Author

I've decided to temporarily revert commit 5ce076c, while issue #204 is still present.

I will rebase my changes as soon as a fix is pushed into efibootmgr tree or a new efivar release is pushed with rhboot/efivar#217 merged.

Make read_u16 and read_order available to call outside efibootmgr.c.

Make var_entry_t public to be used by other source files.

Prepare efibootmgr for JSON output support by making required utility
functions and types publicly available to other source files.

Signed-off-by: Jose M. Guisado <jguisado@soleta.eu>
@stephen-mw

stephen-mw commented Jul 31, 2024

Copy link
Copy Markdown

Any update on this? Json output will be very useful to all of us who are building complicated regex parsing of the output at the moment.

@lupoDharkael

Copy link
Copy Markdown

I've been using these changes in a production environment and it works great, would be nice to have it upstream.

@socketpair

Copy link
Copy Markdown

Bumping PR. I also need it.

Comment thread src/json.h Outdated
void print_json(list_t __unused *entry_list, ebm_mode __unused mode,
char __unused **prefices, char __unused **order_name)
{
printf("JSON support is not built-in\n");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exit with error would be better. Also, all warnings and messages that are not expected to be parsed should go to stderr instead of stdout

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the message gets printed in stderr. Now it also exits with returncode 1.

Comment thread src/efibootmgr.c
printf("\t-g | --gpt Force disk with invalid PMBR to be treated as GPT.\n");
printf("\t-i | --iface name Create a netboot entry for the named interface.\n");
printf("\t-I | --index number When creating an entry, insert it in bootorder at specified position (default: 0).\n");
printf("\t-j | --json Enable JSON output\n");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer #ifdef here instead of stub function that does nothing in case of JSON compile option was not set.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an #ifdef JSON

Comment thread src/json.c
"Could not read variable 'BootNext'");
if (num >= 0) {
snprintf(s, sizeof(s), "%04X", num);
value = json_string(s);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possibly dump here num as number, not as hex string ?

Comment thread src/json.c
if (num >= 0) {
snprintf(s, sizeof(s), "%04X", num);
value = json_string(s);
json_object_set_new(root, "BootNext", value);

@socketpair socketpair Aug 18, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer (as opposed to golang style) JSON formats where keys in dicts always exist, but refer to null instead of value. It's easier to interpret, actually.

@graingert

Copy link
Copy Markdown

Thanks for working on this — landing a structured output would let downstream tools stop screen-scraping -v.

One gap worth flagging while the schema is still in flux: per-entry output currently emits only name / active / description. Consumers that need to identify which OS/loader an entry boots — i.e. the File(\EFI\…) path that -v already prints — would still have to fall back to text parsing.

Concrete use case: GRUB's grub-mkconfig is gaining a 31_efi_bootnext script (on the efibootnext branch) that generates menu entries for setting BootNext. To avoid surfacing non-OS entries (e.g. fwupd's firmware-update shim, PXE/HTTP-boot stubs), it cross-references each entry's File() component against os-prober output. Today it does that by sed-ing efibootmgr -v; with --json it would still need to, unless the loader path is exposed.

Two options that would close the gap, in order of preference:

  1. A structured device_path array of typed nodes ({"type":"HD","uuid":"…"}, {"type":"File","path":"\\EFI\\…"}, {"type":"MAC",…}, etc.) — the most useful long-term shape, and a natural fit for efidp_format_device_path()'s output.
  2. At minimum, a device_path string equal to what -v already prints, plus an optional convenience loader_path field for the File() component when present (absent for PXE/HTTP entries).

Either would let GRUB (and similar consumers) drop the -v parser entirely. Happy to test on the GRUB side once a shape is settled.

@pvxe

pvxe commented Jun 3, 2026

Copy link
Copy Markdown
Author

Added @lupoDharkael as collaborator of my fork so he's able to contribute to this same PR. He's got more time than me to continue efforts around this right now, that way we can keep the discussion in the same place.

@lupoDharkael lupoDharkael force-pushed the main branch 2 times, most recently from 1acf3c1 to b535b07 Compare June 3, 2026 13:03
@lupoDharkael

Copy link
Copy Markdown

@graingert I updated the code to add a "device_path" field with the raw path -v returns. The structured nodes approach sounds convenient but requires a lot more work by parsing the EFI nodes. When I find some time for that I'm evaluate the implementation.

Enable JSON output for efibootmgr. This provides an interface for third
party tools so they do not need to scrap the existing textual output.

This feature is optional and is enabled by using JSON=1 when compiling:

	make ... JSON=1

Add parameter '-j'/--json' to use JSON output. If efibootmgr is not
built with JSON output support it will print the following to stderr:

	"JSON support is not built-in"

This feature adds a new optional dependency with libjansson.

Signed-off-by: Jose M. Guisado <jguisado@soleta.eu>
Co-authored-by: Alejandro Sirgo Rica <asirgo@soleta.eu>
@lupoDharkael

lupoDharkael commented Jun 16, 2026

Copy link
Copy Markdown

I removed the device path code from the original json commit to keep the base functionality simple. This might help accelerate a merge if the device path logic requires a more extensive review in a separate PR.

The new commit adds a "dp" field to every entry with the corresponding structured json device path data. Still a WIP and contains commented code from efivar as placeholder for the uncompleted parts. This implementation corresponds to @graingert 's proposal number 1 and I took the parsing code used by efivar to produce the string when you run efibootmgr -v as reference for the implementation.

Also, I wanted to ask about the format of numeric values. Right now values such as offsets and some ids produce an integer json value, but the original efivar code shows lots of those values as hex values. I've added a comment to everyone of those with the corresponding formatter used in efivar. Would it be better to keep the json value as an integer or should I turn them into strings with the proper hex formatting?

Even if the patch is uncompleted it can be compiled and should be functional. It won't generate all the json fields for those still not implemented dp subtypes.

@lupoDharkael

lupoDharkael commented Jun 26, 2026

Copy link
Copy Markdown

I kept the original patches with some fixes for this PR to reduce friction for the merge process, I moved the dp related code to a branch to keep working on the WIP separately. I might create an issue to gather feedback before I open a PR for that feature too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants