• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 18251268710

04 Oct 2025 09:35PM UTC coverage: 72.225% (-0.06%) from 72.28%
18251268710

push

github

web-flow
shared/bootspec: don't warn for new `loader.conf` options and correctly parse new `uki` and `profile` boot entry options (#39165)

Commit e2a3d5621 added the `uki` option
to sd-boot, and 1e9c9773b added
`profile`, but because these were not added in src/shared/bootspec,
bootctl still shows warnings like `Unknown line 'uki', ignoring.` when
parsing the config. This PR allows parsing and displaying them correctly
in `bootctl` output. It also stops it from printing a warning for any of
the new `loader.conf` options (`log-level`, `reboot-on-error`, etc.).
Note that `uki-url` is still not handled as I can't easily test it.

4 of 12 new or added lines in 2 files covered. (33.33%)

3065 existing lines in 68 files now uncovered.

303282 of 419915 relevant lines covered (72.22%)

1059441.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.74
/src/bootctl/bootctl-status.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <fnmatch.h>
4
#include <unistd.h>
5

6
#include "sd-varlink.h"
7

8
#include "alloc-util.h"
9
#include "bootctl.h"
10
#include "bootctl-status.h"
11
#include "bootctl-util.h"
12
#include "bootspec.h"
13
#include "chase.h"
14
#include "devnum-util.h"
15
#include "dirent-util.h"
16
#include "efi-api.h"
17
#include "efi-loader.h"
18
#include "efivars.h"
19
#include "errno-util.h"
20
#include "fd-util.h"
21
#include "hashmap.h"
22
#include "log.h"
23
#include "pager.h"
24
#include "path-util.h"
25
#include "pretty-print.h"
26
#include "recurse-dir.h"
27
#include "string-util.h"
28
#include "strv.h"
29
#include "tpm2-util.h"
30

31
static int boot_config_load_and_select(
31✔
32
                BootConfig *config,
33
                const char *esp_path,
34
                dev_t esp_devid,
35
                const char *xbootldr_path,
36
                dev_t xbootldr_devid) {
37

38
        int r;
31✔
39

40
        /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would
41
         * find the same entries twice. */
42
        bool same = esp_path && xbootldr_path && devnum_set_and_equal(esp_devid, xbootldr_devid);
31✔
43

44
        r = boot_config_load(config, esp_path, same ? NULL : xbootldr_path);
31✔
45
        if (r < 0)
31✔
46
                return r;
47

48
        if (!arg_root) {
31✔
49
                _cleanup_strv_free_ char **efi_entries = NULL;
×
50

51
                r = efi_loader_get_entries(&efi_entries);
17✔
52
                if (r == -ENOENT || ERRNO_IS_NEG_NOT_SUPPORTED(r))
17✔
53
                        log_debug_errno(r, "Boot loader reported no entries.");
×
54
                else if (r < 0)
17✔
55
                        log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m");
17✔
56
                else
57
                        (void) boot_config_augment_from_loader(config, efi_entries, /* auto_only= */ false);
17✔
58
        }
59

60
        return boot_config_select_special_entries(config, /* skip_efivars= */ !!arg_root);
31✔
61
}
62

63
static int status_entries(
18✔
64
                const BootConfig *config,
65
                const char *esp_path,
66
                sd_id128_t esp_partition_uuid,
67
                const char *xbootldr_path,
68
                sd_id128_t xbootldr_partition_uuid) {
69

70
        int r;
18✔
71

72
        assert(config);
18✔
73
        assert(esp_path || xbootldr_path);
18✔
74

75
        printf("%sBoot Loader Entry Locations:%s\n", ansi_underline(), ansi_normal());
36✔
76

77
        printf("          ESP: %s (", esp_path);
18✔
78
        if (!sd_id128_is_null(esp_partition_uuid))
21✔
79
                printf("/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "",
15✔
80
                       SD_ID128_FORMAT_VAL(esp_partition_uuid));
15✔
81
        if (!xbootldr_path)
18✔
82
                /* ESP is $BOOT if XBOOTLDR not present. */
83
                printf(", %s$BOOT%s", ansi_green(), ansi_normal());
24✔
84
        printf(")");
18✔
85

86
        if (config->loader_conf_status != 0) {
18✔
87
                assert(esp_path);
18✔
88
                printf("\n       config: %s%s/%s%s",
36✔
89
                       ansi_grey(), esp_path, ansi_normal(), "/loader/loader.conf");
90
                if (config->loader_conf_status < 0)
18✔
91
                        printf(": %s%s%s",
×
92
                               config->loader_conf_status == -ENOENT ? ansi_grey() : ansi_highlight_yellow(),
×
93
                               STRERROR(config->loader_conf_status),
×
94
                               ansi_normal());
95
        }
96

97
        if (xbootldr_path) {
18✔
98
                printf("\n     XBOOTLDR: %s (", xbootldr_path);
6✔
99
                if (!sd_id128_is_null(xbootldr_partition_uuid))
9✔
100
                        printf("/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ", ",
3✔
101
                               SD_ID128_FORMAT_VAL(xbootldr_partition_uuid));
3✔
102
                /* XBOOTLDR is always $BOOT if present. */
103
                printf("%s$BOOT%s)", ansi_green(), ansi_normal());
12✔
104
        }
105

106
        if (settle_entry_token() >= 0)
18✔
107
                printf("\n        token: %s", arg_entry_token);
18✔
108
        printf("\n\n");
18✔
109

110
        if (config->default_entry < 0)
18✔
111
                printf("%zu entries, no entry could be determined as default.\n", config->n_entries);
6✔
112
        else {
113
                printf("%sDefault Boot Loader Entry:%s\n", ansi_underline(), ansi_normal());
24✔
114

115
                r = show_boot_entry(
12✔
116
                                boot_config_default_entry(config),
117
                                /* show_as_default= */ false,
118
                                /* show_as_selected= */ false,
119
                                /* show_reported= */ false);
120
                if (r > 0)
12✔
121
                        /* < 0 is already logged by the function itself, let's just emit an extra warning if
122
                           the default entry is broken */
123
                        printf("\nWARNING: default boot entry is broken\n");
×
124
        }
125

126
        return 0;
18✔
127
}
128

129
static int print_efi_option(uint16_t id, int *n_printed, bool in_order) {
39✔
130
        _cleanup_free_ char *title = NULL;
78✔
131
        _cleanup_free_ char *path = NULL;
39✔
132
        sd_id128_t partition;
39✔
133
        bool active;
39✔
134
        int r;
39✔
135

136
        assert(n_printed);
39✔
137

138
        r = efi_get_boot_option(id, &title, &partition, &path, &active);
39✔
139
        if (r == -ENOENT) {
39✔
140
                log_debug_errno(r, "Boot option 0x%04X referenced but missing, ignoring: %m", id);
×
141
                return 0;
×
142
        }
143
        if (r < 0)
39✔
144
                return log_error_errno(r, "Failed to read boot option 0x%04X: %m", id);
×
145

146
        /* print only configured entries with partition information */
147
        if (!path || sd_id128_is_null(partition)) {
39✔
148
                log_debug("Ignoring boot entry 0x%04X without partition information.", id);
36✔
149
                return 0;
36✔
150
        }
151

152
        efi_tilt_backslashes(path);
3✔
153

154
        if (*n_printed == 0) /* Print section title before first entry */
3✔
155
                printf("%sBoot Loaders Listed in EFI Variables:%s\n", ansi_underline(), ansi_normal());
6✔
156

157
        printf("        Title: %s%s%s\n", ansi_highlight(), strna(title), ansi_normal());
9✔
158
        printf("           ID: 0x%04X\n", id);
3✔
159
        printf("       Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
3✔
160
        printf("    Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
3✔
161
               SD_ID128_FORMAT_VAL(partition));
3✔
162
        printf("         File: %s%s%s/%s%s\n",
6✔
163
               glyph(GLYPH_TREE_RIGHT), ansi_grey(), arg_esp_path, ansi_normal(), path);
164
        printf("\n");
3✔
165

166
        (*n_printed)++;
3✔
167
        return 1;
3✔
168
}
169

170
static int status_variables(void) {
12✔
171
        _cleanup_free_ uint16_t *options = NULL, *order = NULL;
12✔
172
        int n_options, n_order, n_printed = 0;
12✔
173

174
        n_options = efi_get_boot_options(&options);
12✔
175
        if (n_options == -ENOENT)
12✔
176
                return log_error_errno(n_options,
×
177
                                       "Failed to access EFI variables, efivarfs"
178
                                       " needs to be available at /sys/firmware/efi/efivars/.");
179
        if (n_options < 0)
12✔
180
                return log_error_errno(n_options, "Failed to read EFI boot entries: %m");
×
181

182
        n_order = efi_get_boot_order(&order);
12✔
183
        if (n_order == -ENOENT)
12✔
184
                n_order = 0;
185
        else if (n_order < 0)
12✔
186
                return log_error_errno(n_order, "Failed to read EFI boot order: %m");
×
187

188
        /* print entries in BootOrder first */
189
        for (int i = 0; i < n_order; i++)
51✔
190
                (void) print_efi_option(order[i], &n_printed, /* in_order= */ true);
39✔
191

192
        /* print remaining entries */
193
        for (int i = 0; i < n_options; i++) {
51✔
194
                for (int j = 0; j < n_order; j++)
84✔
195
                        if (options[i] == order[j])
84✔
196
                                goto next_option;
39✔
197

198
                (void) print_efi_option(options[i], &n_printed, /* in_order= */ false);
×
199

200
        next_option:
39✔
201
                continue;
39✔
202
        }
203

204
        if (n_printed == 0)
12✔
205
                printf("No boot loaders listed in EFI Variables.\n\n");
9✔
206

207
        return 0;
208
}
209

210
static int enumerate_binaries(
36✔
211
                const char *esp_path,
212
                const char *path,
213
                char **previous,
214
                bool *is_first) {
215

216
        _cleanup_closedir_ DIR *d = NULL;
36✔
217
        _cleanup_free_ char *p = NULL;
36✔
218
        int c = 0, r;
36✔
219

220
        assert(esp_path);
36✔
221
        assert(path);
36✔
222
        assert(previous);
36✔
223
        assert(is_first);
36✔
224

225
        r = chase_and_opendir(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_TRIGGER_AUTOFS, &p, &d);
36✔
226
        if (r == -ENOENT)
36✔
227
                return 0;
228
        if (r < 0)
36✔
229
                return log_error_errno(r, "Failed to read \"%s/%s\": %m", esp_path, skip_leading_slash(path));
×
230

231
        FOREACH_DIRENT(de, d, break) {
171✔
232
                _cleanup_free_ char *v = NULL, *filename = NULL;
63✔
233
                _cleanup_close_ int fd = -EBADF;
63✔
234

235
                if (!endswith_no_case(de->d_name, ".efi"))
63✔
236
                        continue;
×
237

238
                filename = path_join(p, de->d_name);
63✔
239
                if (!filename)
63✔
240
                        return log_oom();
×
241
                LOG_SET_PREFIX(filename);
126✔
242

243
                fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
63✔
244
                if (fd < 0)
63✔
245
                        return log_error_errno(errno, "Failed to open file for reading: %m");
×
246

247
                r = get_file_version(fd, &v);
63✔
248
                if (r < 0 && r != -ESRCH)
63✔
249
                        return r;
250

251
                if (*previous) { /* Let's output the previous entry now, since now we know that there will be
63✔
252
                                  * one more, and can draw the tree glyph properly. */
253
                        printf("         %s %s%s\n",
90✔
254
                               *is_first ? "File:" : "     ",
45✔
255
                               glyph(GLYPH_TREE_BRANCH), *previous);
256
                        *is_first = false;
45✔
257
                        *previous = mfree(*previous);
45✔
258
                }
259

260
                /* Do not output this entry immediately, but store what should be printed in a state
261
                 * variable, because we only will know the tree glyph to print (branch or final edge) once we
262
                 * read one more entry */
263
                if (r == -ESRCH) /* No systemd-owned file but still interesting to print */
63✔
264
                        r = asprintf(previous, "%s%s/%s/%s/%s",
×
265
                                     ansi_grey(), esp_path, ansi_normal(), path, de->d_name);
266
                else /* if (r >= 0) */
267
                        r = asprintf(previous, "%s%s/%s/%s/%s (%s%s%s)",
189✔
268
                                     ansi_grey(), esp_path, ansi_normal(), path, de->d_name,
269
                                     ansi_highlight(), v, ansi_normal());
270
                if (r < 0)
63✔
271
                        return log_oom();
×
272

273
                c++;
63✔
274
        }
275

276
        return c;
277
}
278

279
static int status_binaries(const char *esp_path, sd_id128_t partition) {
18✔
280
        _cleanup_free_ char *last = NULL;
18✔
281
        bool is_first = true;
18✔
282
        int r, k;
18✔
283

284
        printf("%sAvailable Boot Loaders on ESP:%s\n", ansi_underline(), ansi_normal());
36✔
285

286
        if (!esp_path) {
18✔
287
                printf("          ESP: Cannot find or access mount point of ESP.\n\n");
×
288
                return -ENOENT;
289
        }
290

291
        printf("          ESP: %s", esp_path);
18✔
292
        if (!sd_id128_is_null(partition))
21✔
293
                printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")", SD_ID128_FORMAT_VAL(partition));
15✔
294
        printf("\n");
18✔
295

296
        r = enumerate_binaries(esp_path, "EFI/systemd", &last, &is_first);
18✔
297
        if (r < 0)
18✔
298
                goto fail;
×
299

300
        k = enumerate_binaries(esp_path, "EFI/BOOT", &last, &is_first);
18✔
301
        if (k < 0) {
18✔
302
                r = k;
×
303
                goto fail;
×
304
        }
305

306
        if (last) /* let's output the last entry now, since now we know that there will be no more, and can draw the tree glyph properly */
18✔
307
                printf("         %s %s%s\n",
36✔
308
                       is_first ? "File:" : "     ",
18✔
309
                       glyph(GLYPH_TREE_RIGHT), last);
310

311
        if (r == 0 && !arg_quiet)
18✔
312
                log_info("systemd-boot not installed in ESP.");
×
313
        if (k == 0 && !arg_quiet)
18✔
314
                log_info("No default/fallback boot loader installed in ESP.");
×
315

316
        printf("\n");
18✔
317
        return 0;
318

319
fail:
×
320
        errno = -r;
×
321
        printf("         File: (can't access %s: %m)\n\n", esp_path);
×
322
        return r;
323
}
324

325
static int efi_get_variable_string_and_warn(const char *variable, char **ret) {
132✔
326
        int r;
132✔
327

328
        r = efi_get_variable_string(variable, ret);
132✔
329
        if (r < 0 && r != -ENOENT)
132✔
330
                return log_warning_errno(r, "Failed to read EFI variable '%s', ignoring: %m", variable);
×
331

332
        return r;
333
}
334

335
static int efi_get_variable_path_and_warn(const char *variable, char **ret) {
24✔
336
        int r;
24✔
337

338
        r = efi_get_variable_path(variable, ret);
24✔
339
        if (r < 0 && r != -ENOENT)
24✔
340
                return log_warning_errno(r, "Failed to read EFI variable '%s', ignoring: %m", variable);
×
341

342
        return r;
343
}
344

345
static void print_yes_no_line(bool first, bool good, const char *name) {
372✔
346
        printf("%s%s %s\n",
1,092✔
347
               first ? "     Features: " : "               ",
348
               COLOR_MARK_BOOL(good),
372✔
349
               name);
350
}
372✔
351

352
int verb_status(int argc, char *argv[], void *userdata) {
49✔
353
        sd_id128_t esp_uuid = SD_ID128_NULL, xbootldr_uuid = SD_ID128_NULL;
49✔
354
        dev_t esp_devid = 0, xbootldr_devid = 0;
49✔
355
        int r, k;
49✔
356

357
        r = acquire_esp(/* unprivileged_mode= */ -1,
49✔
358
                        /* graceful= */ false,
359
                        /* ret_part= */ NULL,
360
                        /* ret_pstart= */ NULL,
361
                        /* ret_psize= */ NULL,
362
                        &esp_uuid,
363
                        &esp_devid);
364
        if (arg_print_esp_path) {
49✔
365
                if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
23✔
366
                                   * error the find_esp_and_warn() won't log on its own) */
367
                        return log_error_errno(r, "Failed to determine ESP location: %m");
49✔
368
                if (r < 0)
23✔
369
                        return r;
370

371
                puts(arg_esp_path);
21✔
372
                return 0;
21✔
373
        }
374

375
        r = acquire_xbootldr(
26✔
376
                        /* unprivileged_mode= */ -1,
377
                        &xbootldr_uuid,
378
                        &xbootldr_devid);
379
        if (arg_print_dollar_boot_path) {
26✔
380
                if (r == -EACCES)
8✔
381
                        return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
×
382
                if (r < 0)
8✔
383
                        return r;
384

385
                const char *path = arg_dollar_boot_path();
7✔
386
                if (!path)
3✔
387
                        return log_error_errno(SYNTHETIC_ERRNO(EACCES), "Failed to determine XBOOTLDR location.");
1✔
388

389
                puts(path);
6✔
390
                return 0;
6✔
391
        }
392

393
        r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just
18✔
394
                * show what we can show */
395

396
        pager_open(arg_pager_flags);
18✔
397

398
        if (arg_root)
18✔
399
                log_debug("Skipping 'System' section, operating offline.");
6✔
400
        else if (!is_efi_boot())
12✔
401
                printf("%sSystem:%s\n"
×
402
                       "Not booted with EFI\n\n",
403
                       ansi_underline(), ansi_normal());
404
        else {
405
                static const struct {
12✔
406
                        uint64_t flag;
407
                        const char *name;
408
                } loader_flags[] = {
409
                        { EFI_LOADER_FEATURE_BOOT_COUNTING,           "Boot counting"                         },
410
                        { EFI_LOADER_FEATURE_CONFIG_TIMEOUT,          "Menu timeout control"                  },
411
                        { EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT, "One-shot menu timeout control"         },
412
                        { EFI_LOADER_FEATURE_ENTRY_DEFAULT,           "Default entry control"                 },
413
                        { EFI_LOADER_FEATURE_ENTRY_ONESHOT,           "One-shot entry control"                },
414
                        { EFI_LOADER_FEATURE_XBOOTLDR,                "Support for XBOOTLDR partition"        },
415
                        { EFI_LOADER_FEATURE_RANDOM_SEED,             "Support for passing random seed to OS" },
416
                        { EFI_LOADER_FEATURE_LOAD_DRIVER,             "Load drop-in drivers"                  },
417
                        { EFI_LOADER_FEATURE_SORT_KEY,                "Support Type #1 sort-key field"        },
418
                        { EFI_LOADER_FEATURE_SAVED_ENTRY,             "Support @saved pseudo-entry"           },
419
                        { EFI_LOADER_FEATURE_DEVICETREE,              "Support Type #1 devicetree field"      },
420
                        { EFI_LOADER_FEATURE_SECUREBOOT_ENROLL,       "Enroll SecureBoot keys"                },
421
                        { EFI_LOADER_FEATURE_RETAIN_SHIM,             "Retain SHIM protocols"                 },
422
                        { EFI_LOADER_FEATURE_MENU_DISABLE,            "Menu can be disabled"                  },
423
                        { EFI_LOADER_FEATURE_MULTI_PROFILE_UKI,       "Multi-Profile UKIs are supported"      },
424
                        { EFI_LOADER_FEATURE_REPORT_URL,              "Loader reports network boot URL"       },
425
                        { EFI_LOADER_FEATURE_TYPE1_UKI,               "Support Type #1 uki field"             },
426
                        { EFI_LOADER_FEATURE_TYPE1_UKI_URL,           "Support Type #1 uki-url field"         },
427
                        { EFI_LOADER_FEATURE_TPM2_ACTIVE_PCR_BANKS,   "Loader reports TPM2 active PCR banks"  },
428
                };
429
                static const struct {
12✔
430
                        uint64_t flag;
431
                        const char *name;
432
                } stub_flags[] = {
433
                        { EFI_STUB_FEATURE_REPORT_BOOT_PARTITION,     "Stub reports loader partition information"                   },
434
                        { EFI_STUB_FEATURE_REPORT_STUB_PARTITION,     "Stub reports stub partition information"                     },
435
                        { EFI_STUB_FEATURE_REPORT_URL,                "Stub reports network boot URL"                               },
436
                        { EFI_STUB_FEATURE_PICK_UP_CREDENTIALS,       "Picks up credentials from boot partition"                    },
437
                        { EFI_STUB_FEATURE_PICK_UP_SYSEXTS,           "Picks up system extension images from boot partition"        },
438
                        { EFI_STUB_FEATURE_PICK_UP_CONFEXTS,          "Picks up configuration extension images from boot partition" },
439
                        { EFI_STUB_FEATURE_THREE_PCRS,                "Measures kernel+command line+sysexts"                        },
440
                        { EFI_STUB_FEATURE_RANDOM_SEED,               "Support for passing random seed to OS"                       },
441
                        { EFI_STUB_FEATURE_CMDLINE_ADDONS,            "Pick up .cmdline from addons"                                },
442
                        { EFI_STUB_FEATURE_CMDLINE_SMBIOS,            "Pick up .cmdline from SMBIOS Type 11"                        },
443
                        { EFI_STUB_FEATURE_DEVICETREE_ADDONS,         "Pick up .dtb from addons"                                    },
444
                        { EFI_STUB_FEATURE_MULTI_PROFILE_UKI,         "Stub understands profile selector"                           },
445
                };
446
                _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL,
×
447
                        *current_entry = NULL, *oneshot_entry = NULL, *default_entry = NULL, *sysfail_entry = NULL, *sysfail_reason = NULL;
12✔
448
                uint64_t loader_features = 0, stub_features = 0;
12✔
449
                int have;
12✔
450

451
                (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderFirmwareType"), &fw_type);
12✔
452
                (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderFirmwareInfo"), &fw_info);
12✔
453
                (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderInfo"), &loader);
12✔
454
                (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("StubInfo"), &stub);
12✔
455
                (void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE_STR("LoaderImageIdentifier"), &loader_path);
12✔
456
                (void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE_STR("StubImageIdentifier"), &stub_path);
12✔
457
                (void) efi_loader_get_features(&loader_features);
12✔
458
                (void) efi_stub_get_features(&stub_features);
12✔
459
                (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderEntrySelected"), &current_entry);
12✔
460
                (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"), &oneshot_entry);
12✔
461
                (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderEntryDefault"), &default_entry);
12✔
462
                (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderEntrySysFail"), &sysfail_entry);
12✔
463
                (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderSysFailReason"), &sysfail_reason);
12✔
464

465
                SecureBootMode secure = efi_get_secure_boot_mode();
12✔
466
                printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
24✔
467
                printf("      Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type), strna(fw_info), ansi_normal());
36✔
468
                printf(" Firmware Arch: %s\n", get_efi_arch());
12✔
469
                printf("   Secure Boot: %s%s%s",
24✔
470
                       IN_SET(secure, SECURE_BOOT_USER, SECURE_BOOT_DEPLOYED) ? ansi_highlight_green() : ansi_normal(),
12✔
471
                       enabled_disabled(IN_SET(secure, SECURE_BOOT_USER, SECURE_BOOT_DEPLOYED)),
12✔
472
                       ansi_normal());
473

474
                if (secure != SECURE_BOOT_DISABLED)
12✔
475
                        printf(" (%s)\n", secure_boot_mode_to_string(secure));
12✔
476
                else
477
                        printf("\n");
×
478

479
                Tpm2Support s = tpm2_support_full(TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER);
12✔
480
                printf("  TPM2 Support: %s%s%s\n",
36✔
481
                       FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER) ? ansi_highlight_green() :
482
                       (s & (TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER)) != 0 ? ansi_highlight_red() : ansi_highlight_yellow(),
6✔
483
                       FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER) ? "yes" :
12✔
484
                       (s & TPM2_SUPPORT_FIRMWARE) ? "firmware only, driver unavailable" :
6✔
485
                       (s & TPM2_SUPPORT_DRIVER) ? "driver only, firmware unavailable" : "no",
6✔
486
                       ansi_normal());
487

488
                k = efi_measured_uki(LOG_DEBUG);
12✔
489
                if (k > 0)
12✔
490
                        printf("  Measured UKI: %syes%s\n", ansi_highlight_green(), ansi_normal());
12✔
491
                else if (k == 0)
6✔
492
                        printf("  Measured UKI: no\n");
6✔
493
                else {
494
                        errno = -k;
×
495
                        printf("  Measured UKI: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal());
×
496
                }
497

498
                k = efi_get_reboot_to_firmware();
12✔
499
                if (k > 0)
12✔
500
                        printf("  Boot into FW: %sactive%s\n", ansi_highlight_yellow(), ansi_normal());
×
501
                else if (k == 0)
12✔
502
                        printf("  Boot into FW: supported\n");
12✔
503
                else if (k == -EOPNOTSUPP)
×
504
                        printf("  Boot into FW: not supported\n");
×
505
                else {
506
                        errno = -k;
×
507
                        printf("  Boot into FW: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal());
×
508
                }
509
                printf("\n");
12✔
510

511
                if (loader) {
12✔
512
                        printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
24✔
513
                        printf("       Product: %s%s%s\n", ansi_highlight(), loader, ansi_normal());
36✔
514
                        for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
240✔
515
                                print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
228✔
516

517
                        sd_id128_t loader_partition_uuid = SD_ID128_NULL;
12✔
518
                        (void) efi_loader_get_device_part_uuid(&loader_partition_uuid);
12✔
519

520
                        _cleanup_free_ char *loader_url = NULL;
12✔
521
                        (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("LoaderDeviceURL"), &loader_url);
12✔
522

523
                        if (!sd_id128_is_null(loader_partition_uuid)) {
12✔
524
                                /* If we know esp_uuid and loader_partition_uuid is not equal to it, print a warning. */
525
                                if (!sd_id128_is_null(esp_uuid) && !sd_id128_equal(loader_partition_uuid, esp_uuid))
24✔
526
                                        printf("WARNING: The boot loader reports a different partition UUID than the detected ESP "
×
527
                                               "("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
528
                                               SD_ID128_FORMAT_VAL(loader_partition_uuid),
×
529
                                               SD_ID128_FORMAT_VAL(esp_uuid));
×
530

531
                                printf("     Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
12✔
532
                                       SD_ID128_FORMAT_VAL(loader_partition_uuid));
12✔
533
                        } else if (loader_path)
×
534
                                printf("     Partition: n/a\n");
×
535

536
                        if (loader_path)
12✔
537
                                printf("        Loader: %s%s%s/%s%s\n",
24✔
538
                                       glyph(GLYPH_TREE_RIGHT), ansi_grey(), arg_esp_path, ansi_normal(), loader_path);
539

540
                        if (loader_url)
12✔
541
                                printf("  Net Boot URL: %s\n", loader_url);
×
542

543
                        if (sysfail_entry)
12✔
544
                                printf("SysFail Reason: %s\n", sysfail_reason);
×
545

546
                        if (current_entry)
12✔
547
                                printf(" Current Entry: %s\n", current_entry);
12✔
548
                        if (default_entry)
12✔
549
                                printf(" Default Entry: %s\n", default_entry);
3✔
550
                        if (oneshot_entry && !streq_ptr(oneshot_entry, default_entry))
12✔
551
                                printf(" OneShot Entry: %s\n", oneshot_entry);
×
552
                        if (sysfail_entry)
12✔
553
                                printf(" SysFail Entry: %s\n", sysfail_entry);
×
554

555
                        printf("\n");
12✔
556
                }
557

558
                if (stub) {
12✔
559
                        printf("%sCurrent Stub:%s\n", ansi_underline(), ansi_normal());
24✔
560
                        printf("      Product: %s%s%s\n", ansi_highlight(), stub, ansi_normal());
36✔
561
                        for (size_t i = 0; i < ELEMENTSOF(stub_flags); i++)
156✔
562
                                print_yes_no_line(i == 0, FLAGS_SET(stub_features, stub_flags[i].flag), stub_flags[i].name);
144✔
563

564
                        sd_id128_t stub_partition_uuid = SD_ID128_NULL;
12✔
565
                        (void) efi_stub_get_device_part_uuid(&stub_partition_uuid);
12✔
566

567
                        _cleanup_free_ char *stub_url = NULL;
12✔
568
                        (void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE_STR("StubDeviceURL"), &stub_url);
12✔
569

570
                        if (!sd_id128_is_null(stub_partition_uuid)) {
12✔
571
                                /* _If_ we know both esp_uuid and xbootldr_uuid and stub_partition_uuid is not equal
572
                                 * to _either_ of them, print a warning. */
573
                                if (!sd_id128_is_null(esp_uuid) && !sd_id128_equal(stub_partition_uuid, esp_uuid) &&
24✔
574
                                    !sd_id128_is_null(xbootldr_uuid) && !sd_id128_equal(stub_partition_uuid, xbootldr_uuid))
×
575
                                        printf("WARNING: The stub loader reports a different UUID than the detected ESP and XBOOTDLR partitions "
×
576
                                               "("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR"/"SD_ID128_UUID_FORMAT_STR")!\n",
577
                                               SD_ID128_FORMAT_VAL(stub_partition_uuid),
×
578
                                               SD_ID128_FORMAT_VAL(esp_uuid),
×
579
                                               SD_ID128_FORMAT_VAL(xbootldr_uuid));
×
580

581
                                printf("    Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
12✔
582
                                       SD_ID128_FORMAT_VAL(stub_partition_uuid));
12✔
583
                        } else if (stub_path)
×
584
                                printf("    Partition: n/a\n");
×
585

586
                        if (stub_path)
12✔
587
                                printf("         Stub: %s%s\n", glyph(GLYPH_TREE_RIGHT), strna(stub_path));
12✔
588

589
                        if (stub_url)
12✔
590
                                printf(" Net Boot URL: %s\n", stub_url);
×
591

592
                        printf("\n");
12✔
593
                }
594

595
                printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
24✔
596
                have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderSystemToken")), F_OK) >= 0;
12✔
597
                printf(" System Token: %s\n", have ? "set" : "not set");
15✔
598

599
                if (arg_esp_path) {
12✔
600
                        _cleanup_free_ char *p = NULL;
12✔
601

602
                        p = path_join(arg_esp_path, "/loader/random-seed");
12✔
603
                        if (!p)
12✔
604
                                return log_oom();
×
605

606
                        r = access(p, F_OK);
12✔
607
                        if (r < 0 && errno != ENOENT)
12✔
608
                                printf("       Exists: Can't access %s (%m)\n", p);
×
609
                        else
610
                                printf("       Exists: %s\n", yes_no(r >= 0));
12✔
611
                }
612

613
                printf("\n");
12✔
614
        }
615

616
        if (arg_esp_path)
18✔
617
                RET_GATHER(r, status_binaries(arg_esp_path, esp_uuid));
18✔
618

619
        if (!arg_root && is_efi_boot())
18✔
620
                RET_GATHER(r, status_variables());
12✔
621

622
        if (arg_esp_path || arg_xbootldr_path) {
18✔
623
                _cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
18✔
624

625
                k = boot_config_load_and_select(&config,
18✔
626
                                                arg_esp_path, esp_devid,
627
                                                arg_xbootldr_path, xbootldr_devid);
628
                RET_GATHER(r, k);
18✔
629

630
                if (k >= 0)
×
631
                        RET_GATHER(r,
18✔
632
                                   status_entries(&config,
633
                                                  arg_esp_path, esp_uuid,
634
                                                  arg_xbootldr_path, xbootldr_uuid));
635
        }
636

637
        return r;
638
}
639

640
static int ref_file(Hashmap **known_files, const char *fn, int increment) {
×
641
        char *k = NULL;
×
642
        int n, r;
×
643

644
        assert(known_files);
×
645

646
        /* just gracefully ignore this. This way the caller doesn't have to verify whether the bootloader
647
         * entry is relevant. */
648
        if (!fn)
×
649
                return 0;
×
650

651
        n = PTR_TO_INT(hashmap_get2(*known_files, fn, (void**)&k));
×
652
        n += increment;
×
653

654
        assert(n >= 0);
×
655

656
        if (n == 0) {
×
657
                (void) hashmap_remove(*known_files, fn);
×
658
                free(k);
×
659
        } else if (!k) {
×
660
                _cleanup_free_ char *t = NULL;
×
661

662
                t = strdup(fn);
×
663
                if (!t)
×
664
                        return -ENOMEM;
665
                r = hashmap_ensure_put(known_files, &path_hash_ops_free, t, INT_TO_PTR(n));
×
666
                if (r < 0)
×
667
                        return r;
668
                TAKE_PTR(t);
669
        } else {
670
                r = hashmap_update(*known_files, fn, INT_TO_PTR(n));
×
671
                if (r < 0)
×
672
                        return r;
×
673
        }
674

675
        return n;
676
}
677

678
static void deref_unlink_file(Hashmap **known_files, const char *fn, const char *root) {
×
679
        _cleanup_free_ char *path = NULL;
×
680
        int r;
×
681

682
        assert(known_files);
×
683

684
        /* just gracefully ignore this. This way the caller doesn't
685
           have to verify whether the bootloader entry is relevant */
686
        if (!fn || !root)
×
687
                return;
688

689
        r = ref_file(known_files, fn, -1);
×
690
        if (r < 0)
×
691
                return (void) log_warning_errno(r, "Failed to deref \"%s\", ignoring: %m", fn);
×
692
        if (r > 0)
×
693
                return;
694

695
        if (arg_dry_run) {
×
696
                r = chase_and_access(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_TRIGGER_AUTOFS, F_OK, &path);
×
697
                if (r < 0)
×
698
                        log_info_errno(r, "Unable to determine whether \"%s\" exists, ignoring: %m", fn);
×
699
                else
700
                        log_info("Would remove \"%s\"", path);
×
701
                return;
×
702
        }
703

704
        r = chase_and_unlink(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_TRIGGER_AUTOFS, 0, &path);
×
705
        if (r >= 0)
×
706
                log_info("Removed \"%s\"", path);
×
707
        else if (r != -ENOENT)
×
708
                return (void) log_warning_errno(r, "Failed to remove \"%s\", ignoring: %m", fn);
×
709

710
        _cleanup_free_ char *d = NULL;
×
711
        if (path_extract_directory(fn, &d) >= 0 && !path_equal(d, "/")) {
×
712
                r = chase_and_unlink(d, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_TRIGGER_AUTOFS, AT_REMOVEDIR, NULL);
×
713
                if (r < 0 && !IN_SET(r, -ENOTEMPTY, -ENOENT))
×
714
                        log_warning_errno(r, "Failed to remove directory \"%s\", ignoring: %m", d);
×
715
        }
716
}
717

718
static int count_known_files(const BootConfig *config, const char* root, Hashmap **ret_known_files) {
×
719
        _cleanup_hashmap_free_ Hashmap *known_files = NULL;
×
720
        int r;
×
721

722
        assert(config);
×
723
        assert(ret_known_files);
×
724

725
        for (size_t i = 0; i < config->n_entries; i++) {
×
726
                const BootEntry *e = config->entries + i;
×
727

728
                if (!path_equal(e->root, root))
×
729
                        continue;
×
730

731
                r = ref_file(&known_files, e->kernel, +1);
×
732
                if (r < 0)
×
733
                        return r;
734
                r = ref_file(&known_files, e->efi, +1);
×
NEW
735
                if (r < 0)
×
736
                        return r;
NEW
737
                r = ref_file(&known_files, e->uki, +1);
×
UNCOV
738
                if (r < 0)
×
739
                        return r;
740
                STRV_FOREACH(s, e->initrd) {
×
741
                        r = ref_file(&known_files, *s, +1);
×
742
                        if (r < 0)
×
743
                                return r;
744
                }
745
                r = ref_file(&known_files, e->device_tree, +1);
×
746
                if (r < 0)
×
747
                        return r;
748
                STRV_FOREACH(s, e->device_tree_overlay) {
×
749
                        r = ref_file(&known_files, *s, +1);
×
750
                        if (r < 0)
×
751
                                return r;
752
                }
753
        }
754

755
        *ret_known_files = TAKE_PTR(known_files);
×
756

757
        return 0;
×
758
}
759

760
static int boot_config_find_in(const BootConfig *config, const char *root, const char *id) {
×
761
        assert(config);
×
762

763
        if (!root || !id)
×
764
                return -ENOENT;
765

766
        for (size_t i = 0; i < config->n_entries; i++)
×
767
                if (path_equal(config->entries[i].root, root) &&
×
768
                    fnmatch(id, config->entries[i].id, FNM_CASEFOLD) == 0)
×
769
                        return i;
×
770

771
        return -ENOENT;
772
}
773

774
static int unlink_entry(const BootConfig *config, const char *root, const char *id) {
×
775
        _cleanup_hashmap_free_ Hashmap *known_files = NULL;
×
776
        const BootEntry *e = NULL;
×
777
        int r;
×
778

779
        assert(config);
×
780

781
        r = count_known_files(config, root, &known_files);
×
782
        if (r < 0)
×
783
                return log_error_errno(r, "Failed to count files in %s: %m", root);
×
784

785
        r = boot_config_find_in(config, root, id);
×
786
        if (r < 0)
×
787
                return 0; /* There is nothing to remove. */
788

789
        if (r == config->default_entry)
×
790
                log_warning("%s is the default boot entry", id);
×
791
        if (r == config->selected_entry)
×
792
                log_warning("%s is the selected boot entry", id);
×
793

794
        e = &config->entries[r];
×
795

796
        deref_unlink_file(&known_files, e->kernel, e->root);
×
797
        deref_unlink_file(&known_files, e->efi, e->root);
×
NEW
798
        deref_unlink_file(&known_files, e->uki, e->root);
×
799
        STRV_FOREACH(s, e->initrd)
×
800
                deref_unlink_file(&known_files, *s, e->root);
×
801
        deref_unlink_file(&known_files, e->device_tree, e->root);
×
802
        STRV_FOREACH(s, e->device_tree_overlay)
×
803
                deref_unlink_file(&known_files, *s, e->root);
×
804

805
        if (arg_dry_run)
×
806
                log_info("Would remove \"%s\"", e->path);
×
807
        else {
808
                r = chase_and_unlink(e->path, root, CHASE_PROHIBIT_SYMLINKS|CHASE_TRIGGER_AUTOFS, 0, NULL);
×
809
                if (r == -ENOENT)
×
810
                        return 0; /* Already removed? */
811
                if (r < 0)
×
812
                        return log_error_errno(r, "Failed to remove \"%s\": %m", e->path);
×
813

814
                log_info("Removed %s", e->path);
×
815
        }
816

817
        return 0;
818
}
819

820
static int list_remove_orphaned_file(
×
821
                RecurseDirEvent event,
822
                const char *path,
823
                int dir_fd,
824
                int inode_fd,
825
                const struct dirent *de,
826
                const struct statx *sx,
827
                void *userdata) {
828

829
        Hashmap *known_files = userdata;
×
830

831
        assert(path);
×
832

833
        if (event != RECURSE_DIR_ENTRY)
×
834
                return RECURSE_DIR_CONTINUE;
835

836
        if (hashmap_get(known_files, path))
×
837
                return RECURSE_DIR_CONTINUE; /* keep! */
838

839
        if (arg_dry_run)
×
840
                log_info("Would remove %s", path);
×
841
        else if (unlinkat(dir_fd, de->d_name, 0) < 0)
×
842
                log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
×
843
                               "Failed to remove \"%s\", ignoring: %m", path);
844
        else
845
                log_info("Removed %s", path);
×
846

847
        return RECURSE_DIR_CONTINUE;
848
}
849

850
static int cleanup_orphaned_files(
×
851
                const BootConfig *config,
852
                const char *root) {
853

854
        _cleanup_hashmap_free_ Hashmap *known_files = NULL;
×
855
        _cleanup_free_ char *full = NULL, *p = NULL;
×
856
        _cleanup_close_ int dir_fd = -EBADF;
×
857
        int r;
×
858

859
        assert(config);
×
860
        assert(root);
×
861

862
        log_info("Cleaning %s", root);
×
863

864
        r = settle_entry_token();
×
865
        if (r < 0)
×
866
                return r;
867

868
        r = count_known_files(config, root, &known_files);
×
869
        if (r < 0)
×
870
                return log_error_errno(r, "Failed to count files in %s: %m", root);
×
871

872
        dir_fd = chase_and_open(arg_entry_token, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_TRIGGER_AUTOFS,
×
873
                        O_DIRECTORY|O_CLOEXEC, &full);
874
        if (dir_fd == -ENOENT)
×
875
                return 0;
876
        if (dir_fd < 0)
×
877
                return log_error_errno(dir_fd, "Failed to open '%s/%s': %m", root, skip_leading_slash(arg_entry_token));
×
878

879
        p = path_join("/", arg_entry_token);
×
880
        if (!p)
×
881
                return log_oom();
×
882

883
        r = recurse_dir(dir_fd, p, 0, UINT_MAX, RECURSE_DIR_SORT, list_remove_orphaned_file, known_files);
×
884
        if (r < 0)
×
885
                return log_error_errno(r, "Failed to cleanup %s: %m", full);
×
886

887
        return r;
888
}
889

890
int verb_list(int argc, char *argv[], void *userdata) {
12✔
891
        _cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
12✔
892
        dev_t esp_devid = 0, xbootldr_devid = 0;
12✔
893
        int r;
12✔
894

895
        /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two
896
         * things: turn off logging about access errors and turn off potentially privileged device probing.
897
         * Here we're interested in the latter but not the former, hence request the mode, and log about
898
         * EACCES. */
899

900
        r = acquire_esp(/* unprivileged_mode= */ -1, /* graceful= */ false, NULL, NULL, NULL, NULL, &esp_devid);
12✔
901
        if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
12✔
902
                return log_error_errno(r, "Failed to determine ESP location: %m");
×
903
        if (r < 0)
12✔
904
                return r;
905

906
        r = acquire_xbootldr(/* unprivileged_mode= */ -1, NULL, &xbootldr_devid);
12✔
907
        if (r == -EACCES)
12✔
908
                return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
×
909
        if (r < 0)
12✔
910
                return r;
911

912
        r = boot_config_load_and_select(&config, arg_esp_path, esp_devid, arg_xbootldr_path, xbootldr_devid);
12✔
913
        if (r < 0)
12✔
914
                return r;
915

916
        if (config.n_entries == 0 && !sd_json_format_enabled(arg_json_format_flags)) {
12✔
917
                log_info("No boot loader entries found.");
4✔
918
                return 0;
4✔
919
        }
920

921
        if (streq(argv[0], "list")) {
8✔
922
                pager_open(arg_pager_flags);
8✔
923
                return show_boot_entries(&config, arg_json_format_flags);
8✔
924
        } else if (streq(argv[0], "cleanup")) {
×
925
                if (arg_xbootldr_path && xbootldr_devid != esp_devid)
×
926
                        cleanup_orphaned_files(&config, arg_xbootldr_path);
×
927
                return cleanup_orphaned_files(&config, arg_esp_path);
×
928
        } else {
929
                assert(streq(argv[0], "unlink"));
×
930
                if (arg_xbootldr_path && xbootldr_devid != esp_devid)
×
931
                        r = unlink_entry(&config, arg_xbootldr_path, argv[1]);
×
932
                return RET_GATHER(r, unlink_entry(&config, arg_esp_path, argv[1]));
×
933
        }
934
}
935

936
int vl_method_list_boot_entries(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
1✔
937
        _cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
×
938
        dev_t esp_devid = 0, xbootldr_devid = 0;
1✔
939
        int r;
1✔
940

941
        assert(link);
1✔
942

943
        r = sd_varlink_dispatch(link, parameters, /* dispatch_table = */ NULL, /* userdata = */ NULL);
1✔
944
        if (r != 0)
1✔
945
                return r;
946

947
        if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
1✔
948
                return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
×
949

950
        r = acquire_esp(/* unprivileged_mode= */ false,
1✔
951
                        /* graceful= */ false,
952
                        /* ret_part= */ NULL,
953
                        /* ret_pstart= */ NULL,
954
                        /* ret_psize= */ NULL,
955
                        /* ret_uuid=*/ NULL,
956
                        &esp_devid);
957
        if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
1✔
958
                return log_error_errno(r, "Failed to determine ESP location: %m");
×
959
        if (r < 0)
1✔
960
                return r;
961

962
        r = acquire_xbootldr(
1✔
963
                        /* unprivileged_mode= */ false,
964
                        /* ret_uuid= */ NULL,
965
                        &xbootldr_devid);
966
        if (r == -EACCES)
1✔
967
                return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
×
968
        if (r < 0)
1✔
969
                return r;
970

971
        r = boot_config_load_and_select(&config, arg_esp_path, esp_devid, arg_xbootldr_path, xbootldr_devid);
1✔
972
        if (r < 0)
1✔
973
                return r;
974

975
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *previous = NULL;
1✔
976
        for (size_t i = 0; i < config.n_entries; i++) {
6✔
977
                if (previous) {
5✔
978
                        r = sd_varlink_notifybo(link, SD_JSON_BUILD_PAIR_VARIANT("entry", previous));
4✔
979
                        if (r < 0)
4✔
980
                                return r;
981

982
                        previous = sd_json_variant_unref(previous);
4✔
983
                }
984

985
                r = boot_entry_to_json(&config, i, &previous);
5✔
986
                if (r < 0)
5✔
987
                        return r;
988
        }
989

990
        if (!previous)
1✔
991
                return sd_varlink_error(link, "io.systemd.BootControl.NoSuchBootEntry", NULL);
×
992

993
        return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_VARIANT("entry", previous));
1✔
994
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc