1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "bootctl-status.h"
8 #include "bootctl-util.h"
11 #include "devnum-util.h"
12 #include "dirent-util.h"
14 #include "efi-loader.h"
15 #include "errno-util.h"
19 #include "path-util.h"
20 #include "pretty-print.h"
21 #include "recurse-dir.h"
22 #include "terminal-util.h"
23 #include "tpm2-util.h"
25 static int boot_config_load_and_select(
29 const char *xbootldr_path
,
30 dev_t xbootldr_devid
) {
34 /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would
35 * find the same entries twice. */
36 bool same
= esp_path
&& xbootldr_path
&& devnum_set_and_equal(esp_devid
, xbootldr_devid
);
38 r
= boot_config_load(config
, esp_path
, same
? NULL
: xbootldr_path
);
43 _cleanup_strv_free_
char **efi_entries
= NULL
;
45 r
= efi_loader_get_entries(&efi_entries
);
46 if (r
== -ENOENT
|| ERRNO_IS_NEG_NOT_SUPPORTED(r
))
47 log_debug_errno(r
, "Boot loader reported no entries.");
49 log_warning_errno(r
, "Failed to determine entries reported by boot loader, ignoring: %m");
51 (void) boot_config_augment_from_loader(config
, efi_entries
, /* only_auto= */ false);
54 return boot_config_select_special_entries(config
, /* skip_efivars= */ !!arg_root
);
57 static int status_entries(
58 const BootConfig
*config
,
60 sd_id128_t esp_partition_uuid
,
61 const char *xbootldr_path
,
62 sd_id128_t xbootldr_partition_uuid
) {
64 sd_id128_t dollar_boot_partition_uuid
;
65 const char *dollar_boot_path
;
69 assert(esp_path
|| xbootldr_path
);
72 dollar_boot_path
= xbootldr_path
;
73 dollar_boot_partition_uuid
= xbootldr_partition_uuid
;
75 dollar_boot_path
= esp_path
;
76 dollar_boot_partition_uuid
= esp_partition_uuid
;
79 printf("%sBoot Loader Entries:%s\n"
80 " $BOOT: %s", ansi_underline(), ansi_normal(), dollar_boot_path
);
81 if (!sd_id128_is_null(dollar_boot_partition_uuid
))
82 printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
")",
83 SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid
));
84 if (settle_entry_token() >= 0)
85 printf("\n token: %s", arg_entry_token
);
88 if (config
->default_entry
< 0)
89 printf("%zu entries, no entry could be determined as default.\n", config
->n_entries
);
91 printf("%sDefault Boot Loader Entry:%s\n", ansi_underline(), ansi_normal());
94 boot_config_default_entry(config
),
95 /* show_as_default= */ false,
96 /* show_as_selected= */ false,
97 /* show_discovered= */ false);
99 /* < 0 is already logged by the function itself, let's just emit an extra warning if
100 the default entry is broken */
101 printf("\nWARNING: default boot entry is broken\n");
107 static int print_efi_option(uint16_t id
, int *n_printed
, bool in_order
) {
108 _cleanup_free_
char *title
= NULL
;
109 _cleanup_free_
char *path
= NULL
;
110 sd_id128_t partition
;
116 r
= efi_get_boot_option(id
, &title
, &partition
, &path
, &active
);
118 log_debug_errno(r
, "Boot option 0x%04X referenced but missing, ignoring: %m", id
);
122 return log_error_errno(r
, "Failed to read boot option 0x%04X: %m", id
);
124 /* print only configured entries with partition information */
125 if (!path
|| sd_id128_is_null(partition
)) {
126 log_debug("Ignoring boot entry 0x%04X without partition information.", id
);
130 efi_tilt_backslashes(path
);
132 if (*n_printed
== 0) /* Print section title before first entry */
133 printf("%sBoot Loaders Listed in EFI Variables:%s\n", ansi_underline(), ansi_normal());
135 printf(" Title: %s%s%s\n", ansi_highlight(), strna(title
), ansi_normal());
136 printf(" ID: 0x%04X\n", id
);
137 printf(" Status: %sactive%s\n", active
? "" : "in", in_order
? ", boot-order" : "");
138 printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
"\n",
139 SD_ID128_FORMAT_VAL(partition
));
140 printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT
), path
);
147 static int status_variables(void) {
148 _cleanup_free_
uint16_t *options
= NULL
, *order
= NULL
;
149 int n_options
, n_order
, n_printed
= 0;
151 n_options
= efi_get_boot_options(&options
);
152 if (n_options
== -ENOENT
)
153 return log_error_errno(n_options
,
154 "Failed to access EFI variables, efivarfs"
155 " needs to be available at /sys/firmware/efi/efivars/.");
157 return log_error_errno(n_options
, "Failed to read EFI boot entries: %m");
159 n_order
= efi_get_boot_order(&order
);
160 if (n_order
== -ENOENT
)
162 else if (n_order
< 0)
163 return log_error_errno(n_order
, "Failed to read EFI boot order: %m");
165 /* print entries in BootOrder first */
166 for (int i
= 0; i
< n_order
; i
++)
167 (void) print_efi_option(order
[i
], &n_printed
, /* in_order= */ true);
169 /* print remaining entries */
170 for (int i
= 0; i
< n_options
; i
++) {
171 for (int j
= 0; j
< n_order
; j
++)
172 if (options
[i
] == order
[j
])
175 (void) print_efi_option(options
[i
], &n_printed
, /* in_order= */ false);
182 printf("No boot loaders listed in EFI Variables.\n\n");
187 static int enumerate_binaries(
188 const char *esp_path
,
194 _cleanup_closedir_
DIR *d
= NULL
;
195 _cleanup_free_
char *p
= NULL
;
203 r
= chase_and_opendir(path
, esp_path
, CHASE_PREFIX_ROOT
|CHASE_PROHIBIT_SYMLINKS
, &p
, &d
);
207 return log_error_errno(r
, "Failed to read \"%s/%s\": %m", esp_path
, path
);
209 FOREACH_DIRENT(de
, d
, break) {
210 _cleanup_free_
char *v
= NULL
, *filename
= NULL
;
211 _cleanup_close_
int fd
= -EBADF
;
213 if (!endswith_no_case(de
->d_name
, ".efi"))
216 if (prefix
&& !startswith_no_case(de
->d_name
, prefix
))
219 filename
= path_join(p
, de
->d_name
);
222 LOG_SET_PREFIX(filename
);
224 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
);
226 return log_error_errno(errno
, "Failed to open file for reading: %m");
228 r
= get_file_version(fd
, &v
);
230 if (r
< 0 && r
!= -ESRCH
)
233 if (*previous
) { /* Let's output the previous entry now, since now we know that there will be
234 * one more, and can draw the tree glyph properly. */
236 *is_first
? "File:" : " ",
237 special_glyph(SPECIAL_GLYPH_TREE_BRANCH
), *previous
);
239 *previous
= mfree(*previous
);
242 /* Do not output this entry immediately, but store what should be printed in a state
243 * variable, because we only will know the tree glyph to print (branch or final edge) once we
244 * read one more entry */
245 if (r
== -ESRCH
) /* No systemd-owned file but still interesting to print */
246 r
= asprintf(previous
, "/%s/%s", path
, de
->d_name
);
247 else /* if (r >= 0) */
248 r
= asprintf(previous
, "/%s/%s (%s%s%s)", path
, de
->d_name
, ansi_highlight(), v
, ansi_normal());
258 static int status_binaries(const char *esp_path
, sd_id128_t partition
) {
259 _cleanup_free_
char *last
= NULL
;
260 bool is_first
= true;
263 printf("%sAvailable Boot Loaders on ESP:%s\n", ansi_underline(), ansi_normal());
266 printf(" ESP: Cannot find or access mount point of ESP.\n\n");
270 printf(" ESP: %s", esp_path
);
271 if (!sd_id128_is_null(partition
))
272 printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
")", SD_ID128_FORMAT_VAL(partition
));
275 r
= enumerate_binaries(esp_path
, "EFI/systemd", NULL
, &last
, &is_first
);
281 k
= enumerate_binaries(esp_path
, "EFI/BOOT", "boot", &last
, &is_first
);
287 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 */
289 is_first
? "File:" : " ",
290 special_glyph(SPECIAL_GLYPH_TREE_RIGHT
), last
);
292 if (r
== 0 && !arg_quiet
)
293 log_info("systemd-boot not installed in ESP.");
294 if (k
== 0 && !arg_quiet
)
295 log_info("No default/fallback boot loader installed in ESP.");
301 static void read_efi_var(const char *variable
, char **ret
) {
304 r
= efi_get_variable_string(variable
, ret
);
305 if (r
< 0 && r
!= -ENOENT
)
306 log_warning_errno(r
, "Failed to read EFI variable %s: %m", variable
);
309 static void print_yes_no_line(bool first
, bool good
, const char *name
) {
311 first
? " Features: " : " ",
312 COLOR_MARK_BOOL(good
),
316 int verb_status(int argc
, char *argv
[], void *userdata
) {
317 sd_id128_t esp_uuid
= SD_ID128_NULL
, xbootldr_uuid
= SD_ID128_NULL
;
318 dev_t esp_devid
= 0, xbootldr_devid
= 0;
321 r
= acquire_esp(/* unprivileged_mode= */ -1, /* graceful= */ false, NULL
, NULL
, NULL
, &esp_uuid
, &esp_devid
);
322 if (arg_print_esp_path
) {
323 if (r
== -EACCES
) /* If we couldn't acquire the ESP path, log about access errors (which is the only
324 * error the find_esp_and_warn() won't log on its own) */
325 return log_error_errno(r
, "Failed to determine ESP location: %m");
332 r
= acquire_xbootldr(/* unprivileged_mode= */ -1, &xbootldr_uuid
, &xbootldr_devid
);
333 if (arg_print_dollar_boot_path
) {
335 return log_error_errno(r
, "Failed to determine XBOOTLDR partition: %m");
339 const char *path
= arg_dollar_boot_path();
341 return log_error_errno(SYNTHETIC_ERRNO(EACCES
), "Failed to determine XBOOTLDR location: %m");
346 if (arg_print_esp_path
|| arg_print_dollar_boot_path
)
349 r
= 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just
350 * show what we can show */
352 pager_open(arg_pager_flags
);
354 if (!arg_root
&& is_efi_boot()) {
355 static const struct {
359 { EFI_LOADER_FEATURE_BOOT_COUNTING
, "Boot counting" },
360 { EFI_LOADER_FEATURE_CONFIG_TIMEOUT
, "Menu timeout control" },
361 { EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT
, "One-shot menu timeout control" },
362 { EFI_LOADER_FEATURE_ENTRY_DEFAULT
, "Default entry control" },
363 { EFI_LOADER_FEATURE_ENTRY_ONESHOT
, "One-shot entry control" },
364 { EFI_LOADER_FEATURE_XBOOTLDR
, "Support for XBOOTLDR partition" },
365 { EFI_LOADER_FEATURE_RANDOM_SEED
, "Support for passing random seed to OS" },
366 { EFI_LOADER_FEATURE_LOAD_DRIVER
, "Load drop-in drivers" },
367 { EFI_LOADER_FEATURE_SORT_KEY
, "Support Type #1 sort-key field" },
368 { EFI_LOADER_FEATURE_SAVED_ENTRY
, "Support @saved pseudo-entry" },
369 { EFI_LOADER_FEATURE_DEVICETREE
, "Support Type #1 devicetree field" },
370 { EFI_LOADER_FEATURE_SECUREBOOT_ENROLL
, "Enroll SecureBoot keys" },
371 { EFI_LOADER_FEATURE_RETAIN_SHIM
, "Retain SHIM protocols" },
373 static const struct {
377 { EFI_STUB_FEATURE_REPORT_BOOT_PARTITION
, "Stub sets ESP information" },
378 { EFI_STUB_FEATURE_PICK_UP_CREDENTIALS
, "Picks up credentials from boot partition" },
379 { EFI_STUB_FEATURE_PICK_UP_SYSEXTS
, "Picks up system extension images from boot partition" },
380 { EFI_STUB_FEATURE_THREE_PCRS
, "Measures kernel+command line+sysexts" },
381 { EFI_STUB_FEATURE_RANDOM_SEED
, "Support for passing random seed to OS" },
382 { EFI_STUB_FEATURE_CMDLINE_ADDONS
, "Pick up .cmdline from addons" },
383 { EFI_STUB_FEATURE_CMDLINE_SMBIOS
, "Pick up .cmdline from SMBIOS Type 11" },
385 _cleanup_free_
char *fw_type
= NULL
, *fw_info
= NULL
, *loader
= NULL
, *loader_path
= NULL
, *stub
= NULL
;
386 sd_id128_t loader_part_uuid
= SD_ID128_NULL
;
387 uint64_t loader_features
= 0, stub_features
= 0;
391 read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareType
), &fw_type
);
392 read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareInfo
), &fw_info
);
393 read_efi_var(EFI_LOADER_VARIABLE(LoaderInfo
), &loader
);
394 read_efi_var(EFI_LOADER_VARIABLE(StubInfo
), &stub
);
395 read_efi_var(EFI_LOADER_VARIABLE(LoaderImageIdentifier
), &loader_path
);
396 (void) efi_loader_get_features(&loader_features
);
397 (void) efi_stub_get_features(&stub_features
);
400 efi_tilt_backslashes(loader_path
);
402 k
= efi_loader_get_device_part_uuid(&loader_part_uuid
);
403 if (k
< 0 && k
!= -ENOENT
)
404 r
= log_warning_errno(k
, "Failed to read EFI variable LoaderDevicePartUUID: %m");
406 SecureBootMode secure
= efi_get_secure_boot_mode();
407 printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
408 printf(" Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type
), strna(fw_info
), ansi_normal());
409 printf(" Firmware Arch: %s\n", get_efi_arch());
410 printf(" Secure Boot: %sd (%s)\n",
411 enable_disable(IN_SET(secure
, SECURE_BOOT_USER
, SECURE_BOOT_DEPLOYED
)),
412 secure_boot_mode_to_string(secure
));
415 printf(" TPM2 Support: %s%s%s\n",
416 FLAGS_SET(s
, TPM2_SUPPORT_FIRMWARE
|TPM2_SUPPORT_DRIVER
) ? ansi_highlight_green() :
417 (s
& (TPM2_SUPPORT_FIRMWARE
|TPM2_SUPPORT_DRIVER
)) != 0 ? ansi_highlight_red() : ansi_highlight_yellow(),
418 FLAGS_SET(s
, TPM2_SUPPORT_FIRMWARE
|TPM2_SUPPORT_DRIVER
) ? "yes" :
419 (s
& TPM2_SUPPORT_FIRMWARE
) ? "firmware only, driver unavailable" :
420 (s
& TPM2_SUPPORT_DRIVER
) ? "driver only, firmware unavailable" : "no",
423 k
= efi_get_reboot_to_firmware();
425 printf(" Boot into FW: %sactive%s\n", ansi_highlight_yellow(), ansi_normal());
427 printf(" Boot into FW: supported\n");
428 else if (k
== -EOPNOTSUPP
)
429 printf(" Boot into FW: not supported\n");
432 printf(" Boot into FW: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal());
436 printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
437 printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader
), ansi_normal());
439 for (size_t i
= 0; i
< ELEMENTSOF(loader_flags
); i
++)
440 print_yes_no_line(i
== 0, FLAGS_SET(loader_features
, loader_flags
[i
].flag
), loader_flags
[i
].name
);
442 sd_id128_t bootloader_esp_uuid
;
443 bool have_bootloader_esp_uuid
= efi_loader_get_device_part_uuid(&bootloader_esp_uuid
) >= 0;
445 print_yes_no_line(false, have_bootloader_esp_uuid
, "Boot loader sets ESP information");
446 if (have_bootloader_esp_uuid
&& !sd_id128_is_null(esp_uuid
) &&
447 !sd_id128_equal(esp_uuid
, bootloader_esp_uuid
))
448 printf("WARNING: The boot loader reports a different ESP UUID than detected ("SD_ID128_UUID_FORMAT_STR
" vs. "SD_ID128_UUID_FORMAT_STR
")!\n",
449 SD_ID128_FORMAT_VAL(bootloader_esp_uuid
),
450 SD_ID128_FORMAT_VAL(esp_uuid
));
453 printf(" Stub: %s\n", stub
);
454 for (size_t i
= 0; i
< ELEMENTSOF(stub_flags
); i
++)
455 print_yes_no_line(i
== 0, FLAGS_SET(stub_features
, stub_flags
[i
].flag
), stub_flags
[i
].name
);
457 if (!sd_id128_is_null(loader_part_uuid
))
458 printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR
"\n",
459 SD_ID128_FORMAT_VAL(loader_part_uuid
));
461 printf(" ESP: n/a\n");
462 printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT
), strna(loader_path
));
465 printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
466 have
= access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken
)), F_OK
) >= 0;
467 printf(" System Token: %s\n", have
? "set" : "not set");
470 _cleanup_free_
char *p
= NULL
;
472 p
= path_join(arg_esp_path
, "/loader/random-seed");
476 have
= access(p
, F_OK
) >= 0;
477 printf(" Exists: %s\n", yes_no(have
));
482 printf("%sSystem:%s\n"
483 "Not booted with EFI\n\n",
484 ansi_underline(), ansi_normal());
487 RET_GATHER(r
, status_binaries(arg_esp_path
, esp_uuid
));
489 if (!arg_root
&& is_efi_boot())
490 RET_GATHER(r
, status_variables());
492 if (arg_esp_path
|| arg_xbootldr_path
) {
493 _cleanup_(boot_config_free
) BootConfig config
= BOOT_CONFIG_NULL
;
495 k
= boot_config_load_and_select(&config
,
496 arg_esp_path
, esp_devid
,
497 arg_xbootldr_path
, xbootldr_devid
);
502 status_entries(&config
,
503 arg_esp_path
, esp_uuid
,
504 arg_xbootldr_path
, xbootldr_uuid
));
510 static int ref_file(Hashmap
*known_files
, const char *fn
, int increment
) {
516 /* just gracefully ignore this. This way the caller doesn't
517 have to verify whether the bootloader entry is relevant */
521 n
= PTR_TO_INT(hashmap_get2(known_files
, fn
, (void**)&k
));
527 (void) hashmap_remove(known_files
, fn
);
530 _cleanup_free_
char *t
= NULL
;
535 r
= hashmap_put(known_files
, t
, INT_TO_PTR(n
));
540 r
= hashmap_update(known_files
, fn
, INT_TO_PTR(n
));
548 static void deref_unlink_file(Hashmap
*known_files
, const char *fn
, const char *root
) {
549 _cleanup_free_
char *path
= NULL
;
554 /* just gracefully ignore this. This way the caller doesn't
555 have to verify whether the bootloader entry is relevant */
559 r
= ref_file(known_files
, fn
, -1);
561 return (void) log_warning_errno(r
, "Failed to deref \"%s\", ignoring: %m", fn
);
566 r
= chase_and_access(fn
, root
, CHASE_PREFIX_ROOT
|CHASE_PROHIBIT_SYMLINKS
, F_OK
, &path
);
568 log_info_errno(r
, "Unable to determine whether \"%s\" exists, ignoring: %m", fn
);
570 log_info("Would remove \"%s\"", path
);
574 r
= chase_and_unlink(fn
, root
, CHASE_PREFIX_ROOT
|CHASE_PROHIBIT_SYMLINKS
, 0, &path
);
576 log_info("Removed \"%s\"", path
);
577 else if (r
!= -ENOENT
)
578 return (void) log_warning_errno(r
, "Failed to remove \"%s\", ignoring: %m", fn
);
580 _cleanup_free_
char *d
= NULL
;
581 if (path_extract_directory(fn
, &d
) >= 0 && !path_equal(d
, "/")) {
582 r
= chase_and_unlink(d
, root
, CHASE_PREFIX_ROOT
|CHASE_PROHIBIT_SYMLINKS
, AT_REMOVEDIR
, NULL
);
583 if (r
< 0 && !IN_SET(r
, -ENOTEMPTY
, -ENOENT
))
584 log_warning_errno(r
, "Failed to remove directory \"%s\", ignoring: %m", d
);
588 static int count_known_files(const BootConfig
*config
, const char* root
, Hashmap
**ret_known_files
) {
589 _cleanup_(hashmap_free_free_keyp
) Hashmap
*known_files
= NULL
;
593 assert(ret_known_files
);
595 known_files
= hashmap_new(&path_hash_ops
);
599 for (size_t i
= 0; i
< config
->n_entries
; i
++) {
600 const BootEntry
*e
= config
->entries
+ i
;
602 if (!path_equal(e
->root
, root
))
605 r
= ref_file(known_files
, e
->kernel
, +1);
608 r
= ref_file(known_files
, e
->efi
, +1);
611 STRV_FOREACH(s
, e
->initrd
) {
612 r
= ref_file(known_files
, *s
, +1);
616 r
= ref_file(known_files
, e
->device_tree
, +1);
619 STRV_FOREACH(s
, e
->device_tree_overlay
) {
620 r
= ref_file(known_files
, *s
, +1);
626 *ret_known_files
= TAKE_PTR(known_files
);
631 static int boot_config_find_in(const BootConfig
*config
, const char *root
, const char *id
) {
637 for (size_t i
= 0; i
< config
->n_entries
; i
++)
638 if (path_equal(config
->entries
[i
].root
, root
) &&
639 fnmatch(id
, config
->entries
[i
].id
, FNM_CASEFOLD
) == 0)
645 static int unlink_entry(const BootConfig
*config
, const char *root
, const char *id
) {
646 _cleanup_(hashmap_free_free_keyp
) Hashmap
*known_files
= NULL
;
647 const BootEntry
*e
= NULL
;
652 r
= count_known_files(config
, root
, &known_files
);
654 return log_error_errno(r
, "Failed to count files in %s: %m", root
);
656 r
= boot_config_find_in(config
, root
, id
);
660 if (r
== config
->default_entry
)
661 log_warning("%s is the default boot entry", id
);
662 if (r
== config
->selected_entry
)
663 log_warning("%s is the selected boot entry", id
);
665 e
= &config
->entries
[r
];
667 deref_unlink_file(known_files
, e
->kernel
, e
->root
);
668 deref_unlink_file(known_files
, e
->efi
, e
->root
);
669 STRV_FOREACH(s
, e
->initrd
)
670 deref_unlink_file(known_files
, *s
, e
->root
);
671 deref_unlink_file(known_files
, e
->device_tree
, e
->root
);
672 STRV_FOREACH(s
, e
->device_tree_overlay
)
673 deref_unlink_file(known_files
, *s
, e
->root
);
676 log_info("Would remove \"%s\"", e
->path
);
678 r
= chase_and_unlink(e
->path
, root
, CHASE_PROHIBIT_SYMLINKS
, 0, NULL
);
680 return log_error_errno(r
, "Failed to remove \"%s\": %m", e
->path
);
682 log_info("Removed %s", e
->path
);
688 static int list_remove_orphaned_file(
689 RecurseDirEvent event
,
693 const struct dirent
*de
,
694 const struct statx
*sx
,
697 Hashmap
*known_files
= userdata
;
702 if (event
!= RECURSE_DIR_ENTRY
)
703 return RECURSE_DIR_CONTINUE
;
705 if (hashmap_get(known_files
, path
))
706 return RECURSE_DIR_CONTINUE
; /* keep! */
709 log_info("Would remove %s", path
);
710 else if (unlinkat(dir_fd
, de
->d_name
, 0) < 0)
711 log_warning_errno(errno
, "Failed to remove \"%s\", ignoring: %m", path
);
713 log_info("Removed %s", path
);
715 return RECURSE_DIR_CONTINUE
;
718 static int cleanup_orphaned_files(
719 const BootConfig
*config
,
722 _cleanup_(hashmap_free_free_keyp
) Hashmap
*known_files
= NULL
;
723 _cleanup_free_
char *full
= NULL
, *p
= NULL
;
724 _cleanup_close_
int dir_fd
= -EBADF
;
730 log_info("Cleaning %s", root
);
732 r
= settle_entry_token();
736 r
= count_known_files(config
, root
, &known_files
);
738 return log_error_errno(r
, "Failed to count files in %s: %m", root
);
740 dir_fd
= chase_and_open(arg_entry_token
, root
, CHASE_PREFIX_ROOT
|CHASE_PROHIBIT_SYMLINKS
,
741 O_DIRECTORY
|O_CLOEXEC
, &full
);
742 if (dir_fd
== -ENOENT
)
745 return log_error_errno(dir_fd
, "Failed to open '%s/%s': %m", root
, arg_entry_token
);
747 p
= path_join("/", arg_entry_token
);
751 r
= recurse_dir(dir_fd
, p
, 0, UINT_MAX
, RECURSE_DIR_SORT
, list_remove_orphaned_file
, known_files
);
753 return log_error_errno(r
, "Failed to cleanup %s: %m", full
);
758 int verb_list(int argc
, char *argv
[], void *userdata
) {
759 _cleanup_(boot_config_free
) BootConfig config
= BOOT_CONFIG_NULL
;
760 dev_t esp_devid
= 0, xbootldr_devid
= 0;
763 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two
764 * things: turn off logging about access errors and turn off potentially privileged device probing.
765 * Here we're interested in the latter but not the former, hence request the mode, and log about
768 r
= acquire_esp(/* unprivileged_mode= */ -1, /* graceful= */ false, NULL
, NULL
, NULL
, NULL
, &esp_devid
);
769 if (r
== -EACCES
) /* We really need the ESP path for this call, hence also log about access errors */
770 return log_error_errno(r
, "Failed to determine ESP location: %m");
774 r
= acquire_xbootldr(/* unprivileged_mode= */ -1, NULL
, &xbootldr_devid
);
776 return log_error_errno(r
, "Failed to determine XBOOTLDR partition: %m");
780 r
= boot_config_load_and_select(&config
, arg_esp_path
, esp_devid
, arg_xbootldr_path
, xbootldr_devid
);
784 if (config
.n_entries
== 0 && FLAGS_SET(arg_json_format_flags
, JSON_FORMAT_OFF
)) {
785 log_info("No boot loader entries found.");
789 if (streq(argv
[0], "list")) {
790 pager_open(arg_pager_flags
);
791 return show_boot_entries(&config
, arg_json_format_flags
);
792 } else if (streq(argv
[0], "cleanup")) {
793 if (arg_xbootldr_path
&& xbootldr_devid
!= esp_devid
)
794 cleanup_orphaned_files(&config
, arg_xbootldr_path
);
795 return cleanup_orphaned_files(&config
, arg_esp_path
);
797 assert(streq(argv
[0], "unlink"));
798 if (arg_xbootldr_path
&& xbootldr_devid
!= esp_devid
) {
799 r
= unlink_entry(&config
, arg_xbootldr_path
, argv
[1]);
800 if (r
== 0 || r
!= -ENOENT
)
803 return unlink_entry(&config
, arg_esp_path
, argv
[1]);
807 int verb_unlink(int argc
, char *argv
[], void *userdata
) {
808 return verb_list(argc
, argv
, userdata
);