1 /* SPDX-License-Identifier: LGPL-2.1+ */
4 #include <linux/magic.h>
9 #include "alloc-util.h"
10 #include "blkid-util.h"
12 #include "conf-files.h"
14 #include "device-nodes.h"
15 #include "dirent-util.h"
21 #include "parse-util.h"
22 #include "path-util.h"
23 #include "pe-header.h"
24 #include "sort-util.h"
25 #include "stat-util.h"
26 #include "string-table.h"
27 #include "string-util.h"
29 #include "unaligned.h"
32 static void boot_entry_free(BootEntry
*entry
) {
39 free(entry
->show_title
);
41 free(entry
->machine_id
);
42 free(entry
->architecture
);
43 strv_free(entry
->options
);
46 strv_free(entry
->initrd
);
47 free(entry
->device_tree
);
50 static int boot_entry_load(
55 _cleanup_(boot_entry_free
) BootEntry tmp
= {
56 .type
= BOOT_ENTRY_CONF
,
59 _cleanup_fclose_
FILE *f
= NULL
;
68 c
= endswith_no_case(path
, ".conf");
70 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid loader entry file suffix: %s", path
);
73 tmp
.id
= strndup(b
, c
- b
);
77 if (!efi_loader_entry_name_valid(tmp
.id
))
78 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid loader entry filename: %s", path
);
80 tmp
.path
= strdup(path
);
84 tmp
.root
= strdup(root
);
88 f
= fopen(path
, "re");
90 return log_error_errno(errno
, "Failed to open \"%s\": %m", path
);
93 _cleanup_free_
char *buf
= NULL
, *field
= NULL
;
96 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
100 return log_error_errno(r
, "%s:%u: Line too long", path
, line
);
102 return log_error_errno(r
, "%s:%u: Error while reading: %m", path
, line
);
106 if (IN_SET(*strstrip(buf
), '#', '\0'))
110 r
= extract_first_word(&p
, &field
, " \t", 0);
112 log_error_errno(r
, "Failed to parse config file %s line %u: %m", path
, line
);
116 log_warning("%s:%u: Bad syntax", path
, line
);
120 if (streq(field
, "title"))
121 r
= free_and_strdup(&tmp
.title
, p
);
122 else if (streq(field
, "version"))
123 r
= free_and_strdup(&tmp
.version
, p
);
124 else if (streq(field
, "machine-id"))
125 r
= free_and_strdup(&tmp
.machine_id
, p
);
126 else if (streq(field
, "architecture"))
127 r
= free_and_strdup(&tmp
.architecture
, p
);
128 else if (streq(field
, "options"))
129 r
= strv_extend(&tmp
.options
, p
);
130 else if (streq(field
, "linux"))
131 r
= free_and_strdup(&tmp
.kernel
, p
);
132 else if (streq(field
, "efi"))
133 r
= free_and_strdup(&tmp
.efi
, p
);
134 else if (streq(field
, "initrd"))
135 r
= strv_extend(&tmp
.initrd
, p
);
136 else if (streq(field
, "devicetree"))
137 r
= free_and_strdup(&tmp
.device_tree
, p
);
139 log_notice("%s:%u: Unknown line \"%s\", ignoring.", path
, line
, field
);
143 return log_error_errno(r
, "%s:%u: Error while reading: %m", path
, line
);
147 tmp
= (BootEntry
) {};
151 void boot_config_free(BootConfig
*config
) {
156 free(config
->default_pattern
);
157 free(config
->timeout
);
158 free(config
->editor
);
159 free(config
->auto_entries
);
160 free(config
->auto_firmware
);
162 free(config
->entry_oneshot
);
163 free(config
->entry_default
);
165 for (i
= 0; i
< config
->n_entries
; i
++)
166 boot_entry_free(config
->entries
+ i
);
167 free(config
->entries
);
170 static int boot_loader_read_conf(const char *path
, BootConfig
*config
) {
171 _cleanup_fclose_
FILE *f
= NULL
;
178 f
= fopen(path
, "re");
183 return log_error_errno(errno
, "Failed to open \"%s\": %m", path
);
187 _cleanup_free_
char *buf
= NULL
, *field
= NULL
;
190 r
= read_line(f
, LONG_LINE_MAX
, &buf
);
194 return log_error_errno(r
, "%s:%u: Line too long", path
, line
);
196 return log_error_errno(r
, "%s:%u: Error while reading: %m", path
, line
);
200 if (IN_SET(*strstrip(buf
), '#', '\0'))
204 r
= extract_first_word(&p
, &field
, " \t", 0);
206 log_error_errno(r
, "Failed to parse config file %s line %u: %m", path
, line
);
210 log_warning("%s:%u: Bad syntax", path
, line
);
214 if (streq(field
, "default"))
215 r
= free_and_strdup(&config
->default_pattern
, p
);
216 else if (streq(field
, "timeout"))
217 r
= free_and_strdup(&config
->timeout
, p
);
218 else if (streq(field
, "editor"))
219 r
= free_and_strdup(&config
->editor
, p
);
220 else if (streq(field
, "auto-entries"))
221 r
= free_and_strdup(&config
->auto_entries
, p
);
222 else if (streq(field
, "auto-firmware"))
223 r
= free_and_strdup(&config
->auto_firmware
, p
);
224 else if (streq(field
, "console-mode"))
225 r
= free_and_strdup(&config
->console_mode
, p
);
227 log_notice("%s:%u: Unknown line \"%s\", ignoring.", path
, line
, field
);
231 return log_error_errno(r
, "%s:%u: Error while reading: %m", path
, line
);
237 static int boot_entry_compare(const BootEntry
*a
, const BootEntry
*b
) {
238 return str_verscmp(a
->id
, b
->id
);
241 static int boot_entries_find(
247 _cleanup_strv_free_
char **files
= NULL
;
248 size_t n_allocated
= *n_entries
;
257 r
= conf_files_list(&files
, ".conf", NULL
, 0, dir
, NULL
);
259 return log_error_errno(r
, "Failed to list files in \"%s\": %m", dir
);
261 STRV_FOREACH(f
, files
) {
262 if (!GREEDY_REALLOC0(*entries
, n_allocated
, *n_entries
+ 1))
265 r
= boot_entry_load(root
, *f
, *entries
+ *n_entries
);
275 static int boot_entry_load_unified(
278 const char *osrelease
,
282 _cleanup_free_
char *os_pretty_name
= NULL
, *os_id
= NULL
, *version_id
= NULL
, *build_id
= NULL
;
283 _cleanup_(boot_entry_free
) BootEntry tmp
= {
284 .type
= BOOT_ENTRY_UNIFIED
,
286 _cleanup_fclose_
FILE *f
= NULL
;
294 k
= path_startswith(path
, root
);
296 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Path is not below root: %s", path
);
298 f
= fmemopen((void*) osrelease
, strlen(osrelease
), "r");
300 return log_error_errno(errno
, "Failed to open os-release buffer: %m");
302 r
= parse_env_file(f
, "os-release",
303 "PRETTY_NAME", &os_pretty_name
,
305 "VERSION_ID", &version_id
,
306 "BUILD_ID", &build_id
);
308 return log_error_errno(r
, "Failed to parse os-release data from unified kernel image %s: %m", path
);
310 if (!os_pretty_name
|| !os_id
|| !(version_id
|| build_id
))
311 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG
), "Missing fields in os-release data from unified kernel image %s, refusing.", path
);
313 tmp
.id
= strjoin(os_id
, "-", version_id
?: build_id
);
317 if (!efi_loader_entry_name_valid(tmp
.id
))
318 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid loader entry: %s", tmp
.id
);
320 tmp
.path
= strdup(path
);
324 tmp
.root
= strdup(root
);
328 tmp
.kernel
= strdup(skip_leading_chars(k
, "/"));
332 tmp
.options
= strv_new(skip_leading_chars(cmdline
, WHITESPACE
));
336 delete_trailing_chars(tmp
.options
[0], WHITESPACE
);
338 tmp
.title
= TAKE_PTR(os_pretty_name
);
341 tmp
= (BootEntry
) {};
345 /* Maximum PE section we are willing to load (Note that sections we are not interested in may be larger, but
346 * the ones we do care about and we are willing to load into memory have this size limit.) */
347 #define PE_SECTION_SIZE_MAX (4U*1024U*1024U)
349 static int find_sections(
351 char **ret_osrelease
,
352 char **ret_cmdline
) {
354 _cleanup_free_
struct PeSectionHeader
*sections
= NULL
;
355 _cleanup_free_
char *osrelease
= NULL
, *cmdline
= NULL
;
356 size_t i
, n_sections
;
357 struct DosFileHeader dos
;
362 n
= pread(fd
, &dos
, sizeof(dos
), 0);
364 return log_error_errno(errno
, "Failed read DOS header: %m");
365 if (n
!= sizeof(dos
))
366 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Short read while reading DOS header, refusing.");
368 if (dos
.Magic
[0] != 'M' || dos
.Magic
[1] != 'Z')
369 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG
), "DOS executable magic missing, refusing.");
371 start
= unaligned_read_le32(&dos
.ExeHeader
);
372 n
= pread(fd
, &pe
, sizeof(pe
), start
);
374 return log_error_errno(errno
, "Failed to read PE header: %m");
376 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Short read while reading PE header, refusing.");
378 if (pe
.Magic
[0] != 'P' || pe
.Magic
[1] != 'E' || pe
.Magic
[2] != 0 || pe
.Magic
[3] != 0)
379 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG
), "PE executable magic missing, refusing.");
381 n_sections
= unaligned_read_le16(&pe
.FileHeader
.NumberOfSections
);
383 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG
), "PE header has too many sections, refusing.");
385 sections
= new(struct PeSectionHeader
, n_sections
);
389 n
= pread(fd
, sections
,
390 n_sections
* sizeof(struct PeSectionHeader
),
391 start
+ sizeof(pe
) + unaligned_read_le16(&pe
.FileHeader
.SizeOfOptionalHeader
));
393 return log_error_errno(errno
, "Failed to read section data: %m");
394 if ((size_t) n
!= n_sections
* sizeof(struct PeSectionHeader
))
395 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Short read while reading sections, refusing.");
397 for (i
= 0; i
< n_sections
; i
++) {
398 _cleanup_free_
char *k
= NULL
;
399 uint32_t offset
, size
;
402 if (strneq((char*) sections
[i
].Name
, ".osrel", sizeof(sections
[i
].Name
)))
404 else if (strneq((char*) sections
[i
].Name
, ".cmdline", sizeof(sections
[i
].Name
)))
410 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG
), "Duplicate section %s, refusing.", sections
[i
].Name
);
412 offset
= unaligned_read_le32(§ions
[i
].PointerToRawData
);
413 size
= unaligned_read_le32(§ions
[i
].VirtualSize
);
415 if (size
> PE_SECTION_SIZE_MAX
)
416 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG
), "Section %s too large, refusing.", sections
[i
].Name
);
418 k
= new(char, size
+1);
422 n
= pread(fd
, k
, size
, offset
);
424 return log_error_errno(errno
, "Failed to read section payload: %m");
425 if ((size_t) n
!= size
)
426 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Short read while reading section payload, refusing:");
428 /* Allow one trailing NUL byte, but nothing more. */
429 if (size
> 0 && memchr(k
, 0, size
- 1))
430 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG
), "Section contains embedded NUL byte: %m");
437 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG
), "Image lacks .osrel section, refusing.");
440 *ret_osrelease
= TAKE_PTR(osrelease
);
442 *ret_cmdline
= TAKE_PTR(cmdline
);
447 static int boot_entries_find_unified(
453 _cleanup_(closedirp
) DIR *d
= NULL
;
454 size_t n_allocated
= *n_entries
;
468 return log_error_errno(errno
, "Failed to open %s: %m", dir
);
471 FOREACH_DIRENT(de
, d
, return log_error_errno(errno
, "Failed to read %s: %m", dir
)) {
472 _cleanup_free_
char *j
= NULL
, *osrelease
= NULL
, *cmdline
= NULL
;
473 _cleanup_close_
int fd
= -1;
475 if (!dirent_is_file(de
))
478 if (!endswith_no_case(de
->d_name
, ".efi"))
481 if (!GREEDY_REALLOC0(*entries
, n_allocated
, *n_entries
+ 1))
484 fd
= openat(dirfd(d
), de
->d_name
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
);
486 log_warning_errno(errno
, "Failed to open %s/%s, ignoring: %m", dir
, de
->d_name
);
490 r
= fd_verify_regular(fd
);
492 log_warning_errno(r
, "File %s/%s is not regular, ignoring: %m", dir
, de
->d_name
);
496 r
= find_sections(fd
, &osrelease
, &cmdline
);
500 j
= path_join(dir
, de
->d_name
);
504 r
= boot_entry_load_unified(root
, j
, osrelease
, cmdline
, *entries
+ *n_entries
);
514 static bool find_nonunique(BootEntry
*entries
, size_t n_entries
, bool *arr
) {
516 bool non_unique
= false;
518 assert(entries
|| n_entries
== 0);
519 assert(arr
|| n_entries
== 0);
521 for (i
= 0; i
< n_entries
; i
++)
524 for (i
= 0; i
< n_entries
; i
++)
525 for (j
= 0; j
< n_entries
; j
++)
526 if (i
!= j
&& streq(boot_entry_title(entries
+ i
),
527 boot_entry_title(entries
+ j
)))
528 non_unique
= arr
[i
] = arr
[j
] = true;
533 static int boot_entries_uniquify(BootEntry
*entries
, size_t n_entries
) {
539 assert(entries
|| n_entries
== 0);
541 /* Find _all_ non-unique titles */
542 if (!find_nonunique(entries
, n_entries
, arr
))
545 /* Add version to non-unique titles */
546 for (i
= 0; i
< n_entries
; i
++)
547 if (arr
[i
] && entries
[i
].version
) {
548 r
= asprintf(&s
, "%s (%s)", boot_entry_title(entries
+ i
), entries
[i
].version
);
552 free_and_replace(entries
[i
].show_title
, s
);
555 if (!find_nonunique(entries
, n_entries
, arr
))
558 /* Add machine-id to non-unique titles */
559 for (i
= 0; i
< n_entries
; i
++)
560 if (arr
[i
] && entries
[i
].machine_id
) {
561 r
= asprintf(&s
, "%s (%s)", boot_entry_title(entries
+ i
), entries
[i
].machine_id
);
565 free_and_replace(entries
[i
].show_title
, s
);
568 if (!find_nonunique(entries
, n_entries
, arr
))
571 /* Add file name to non-unique titles */
572 for (i
= 0; i
< n_entries
; i
++)
574 r
= asprintf(&s
, "%s (%s)", boot_entry_title(entries
+ i
), entries
[i
].id
);
578 free_and_replace(entries
[i
].show_title
, s
);
584 static int boot_entries_select_default(const BootConfig
*config
) {
588 assert(config
->entries
|| config
->n_entries
== 0);
590 if (config
->n_entries
== 0) {
591 log_debug("Found no default boot entry :(");
592 return -1; /* -1 means "no default" */
595 if (config
->entry_oneshot
)
596 for (i
= config
->n_entries
- 1; i
>= 0; i
--)
597 if (streq(config
->entry_oneshot
, config
->entries
[i
].id
)) {
598 log_debug("Found default: id \"%s\" is matched by LoaderEntryOneShot",
599 config
->entries
[i
].id
);
603 if (config
->entry_default
)
604 for (i
= config
->n_entries
- 1; i
>= 0; i
--)
605 if (streq(config
->entry_default
, config
->entries
[i
].id
)) {
606 log_debug("Found default: id \"%s\" is matched by LoaderEntryDefault",
607 config
->entries
[i
].id
);
611 if (config
->default_pattern
)
612 for (i
= config
->n_entries
- 1; i
>= 0; i
--)
613 if (fnmatch(config
->default_pattern
, config
->entries
[i
].id
, FNM_CASEFOLD
) == 0) {
614 log_debug("Found default: id \"%s\" is matched by pattern \"%s\"",
615 config
->entries
[i
].id
, config
->default_pattern
);
619 log_debug("Found default: last entry \"%s\"", config
->entries
[config
->n_entries
- 1].id
);
620 return config
->n_entries
- 1;
623 int boot_entries_load_config(
624 const char *esp_path
,
625 const char *xbootldr_path
,
626 BootConfig
*config
) {
634 p
= strjoina(esp_path
, "/loader/loader.conf");
635 r
= boot_loader_read_conf(p
, config
);
639 p
= strjoina(esp_path
, "/loader/entries");
640 r
= boot_entries_find(esp_path
, p
, &config
->entries
, &config
->n_entries
);
644 p
= strjoina(esp_path
, "/EFI/Linux/");
645 r
= boot_entries_find_unified(esp_path
, p
, &config
->entries
, &config
->n_entries
);
651 p
= strjoina(xbootldr_path
, "/loader/entries");
652 r
= boot_entries_find(xbootldr_path
, p
, &config
->entries
, &config
->n_entries
);
656 p
= strjoina(xbootldr_path
, "/EFI/Linux/");
657 r
= boot_entries_find_unified(xbootldr_path
, p
, &config
->entries
, &config
->n_entries
);
662 typesafe_qsort(config
->entries
, config
->n_entries
, boot_entry_compare
);
664 r
= boot_entries_uniquify(config
->entries
, config
->n_entries
);
666 return log_error_errno(r
, "Failed to uniquify boot entries: %m");
669 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, "LoaderEntryOneShot", &config
->entry_oneshot
);
670 if (r
< 0 && !IN_SET(r
, -ENOENT
, -ENODATA
)) {
671 log_warning_errno(r
, "Failed to read EFI variable \"LoaderEntryOneShot\": %m");
676 r
= efi_get_variable_string(EFI_VENDOR_LOADER
, "LoaderEntryDefault", &config
->entry_default
);
677 if (r
< 0 && !IN_SET(r
, -ENOENT
, -ENODATA
)) {
678 log_warning_errno(r
, "Failed to read EFI variable \"LoaderEntryDefault\": %m");
684 config
->default_entry
= boot_entries_select_default(config
);
688 int boot_entries_load_config_auto(
689 const char *override_esp_path
,
690 const char *override_xbootldr_path
,
691 BootConfig
*config
) {
693 _cleanup_free_
char *esp_where
= NULL
, *xbootldr_where
= NULL
;
698 /* This function is similar to boot_entries_load_config(), however we automatically search for the
699 * ESP and the XBOOTLDR partition unless it is explicitly specified. Also, if the user did not pass
700 * an ESP or XBOOTLDR path directly, let's see if /run/boot-loader-entries/ exists. If so, let's
701 * read data from there, as if it was an ESP (i.e. loading both entries and loader.conf data from
702 * it). This allows other boot loaders to pass boot loader entry information to our tools if they
705 if (!override_esp_path
&& !override_xbootldr_path
) {
706 if (access("/run/boot-loader-entries/", F_OK
) >= 0)
707 return boot_entries_load_config("/run/boot-loader-entries/", NULL
, config
);
710 return log_error_errno(errno
,
711 "Failed to determine whether /run/boot-loader-entries/ exists: %m");
714 r
= find_esp_and_warn(override_esp_path
, false, &esp_where
, NULL
, NULL
, NULL
, NULL
);
715 if (r
< 0) /* we don't log about ENOKEY here, but propagate it, leaving it to the caller to log */
718 r
= find_xbootldr_and_warn(override_xbootldr_path
, false, &xbootldr_where
, NULL
);
719 if (r
< 0 && r
!= -ENOKEY
)
720 return r
; /* It's fine if the XBOOTLDR partition doesn't exist, hence we ignore ENOKEY here */
722 return boot_entries_load_config(esp_where
, xbootldr_where
, config
);
725 int boot_entries_augment_from_loader(BootConfig
*config
, bool only_auto
) {
727 static const char * const title_table
[] = {
728 /* Pretty names for a few well-known automatically discovered entries. */
730 "auto-windows", "Windows Boot Manager",
731 "auto-efi-shell", "EFI Shell",
732 "auto-efi-default", "EFI Default Loader",
733 "auto-reboot-to-firmware-setup", "Reboot Into Firmware Interface",
736 _cleanup_free_
char **found_by_loader
= NULL
;
743 /* Let's add the entries discovered by the boot loader to the end of our list, unless they are
744 * already included there. */
746 r
= efi_loader_get_entries(&found_by_loader
);
747 if (IN_SET(r
, -ENOENT
, -EOPNOTSUPP
))
748 return log_debug_errno(r
, "Boot loader reported no entries.");
750 return log_error_errno(r
, "Failed to determine entries reported by boot loader: %m");
752 n_allocated
= config
->n_entries
;
754 STRV_FOREACH(i
, found_by_loader
) {
755 _cleanup_free_
char *c
= NULL
, *t
= NULL
;
758 if (boot_config_has_entry(config
, *i
))
761 if (only_auto
&& !startswith(*i
, "auto-"))
768 STRV_FOREACH_PAIR(a
, b
, (char**) title_table
)
776 if (!GREEDY_REALLOC0(config
->entries
, n_allocated
, config
->n_entries
+ 1))
779 config
->entries
[config
->n_entries
++] = (BootEntry
) {
780 .type
= BOOT_ENTRY_LOADER
,
782 .title
= TAKE_PTR(t
),
789 /********************************************************************************/
791 static int verify_esp_blkid(
795 uint64_t *ret_pstart
,
797 sd_id128_t
*ret_uuid
) {
799 sd_id128_t uuid
= SD_ID128_NULL
;
800 uint64_t pstart
= 0, psize
= 0;
804 _cleanup_(blkid_free_probep
) blkid_probe b
= NULL
;
805 _cleanup_free_
char *node
= NULL
;
809 r
= device_path_make_major_minor(S_IFBLK
, devid
, &node
);
811 return log_error_errno(r
, "Failed to format major/minor device path: %m");
814 b
= blkid_new_probe_from_filename(node
);
816 return log_error_errno(errno
?: SYNTHETIC_ERRNO(ENOMEM
), "Failed to open file system \"%s\": %m", node
);
818 blkid_probe_enable_superblocks(b
, 1);
819 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
820 blkid_probe_enable_partitions(b
, 1);
821 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
824 r
= blkid_do_safeprobe(b
);
826 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" is ambiguous.", node
);
828 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" does not contain a label.", node
);
830 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe file system \"%s\": %m", node
);
833 r
= blkid_probe_lookup_value(b
, "TYPE", &v
, NULL
);
835 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe file system type of \"%s\": %m", node
);
836 if (!streq(v
, "vfat"))
837 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
838 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
839 "File system \"%s\" is not FAT.", node
);
842 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
844 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition scheme of \"%s\": %m", node
);
845 if (!streq(v
, "gpt"))
846 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
847 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
848 "File system \"%s\" is not on a GPT partition table.", node
);
851 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
853 return log_error_errno(errno
?: EIO
, "Failed to probe partition type UUID of \"%s\": %m", node
);
854 if (!streq(v
, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"))
855 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
856 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
857 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node
);
860 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
862 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition entry UUID of \"%s\": %m", node
);
863 r
= sd_id128_from_string(v
, &uuid
);
865 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
868 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_NUMBER", &v
, NULL
);
870 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition number of \"%s\": m", node
);
871 r
= safe_atou32(v
, &part
);
873 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
876 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_OFFSET", &v
, NULL
);
878 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition offset of \"%s\": %m", node
);
879 r
= safe_atou64(v
, &pstart
);
881 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
884 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SIZE", &v
, NULL
);
886 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition size of \"%s\": %m", node
);
887 r
= safe_atou64(v
, &psize
);
889 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
895 *ret_pstart
= pstart
;
904 static int verify_esp_udev(
908 uint64_t *ret_pstart
,
910 sd_id128_t
*ret_uuid
) {
912 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
913 _cleanup_free_
char *node
= NULL
;
914 sd_id128_t uuid
= SD_ID128_NULL
;
915 uint64_t pstart
= 0, psize
= 0;
920 r
= device_path_make_major_minor(S_IFBLK
, devid
, &node
);
922 return log_error_errno(r
, "Failed to format major/minor device path: %m");
924 r
= sd_device_new_from_devnum(&d
, 'b', devid
);
926 return log_error_errno(r
, "Failed to get device from device number: %m");
928 r
= sd_device_get_property_value(d
, "ID_FS_TYPE", &v
);
930 return log_error_errno(r
, "Failed to get device property: %m");
931 if (!streq(v
, "vfat"))
932 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
933 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
934 "File system \"%s\" is not FAT.", node
);
936 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SCHEME", &v
);
938 return log_error_errno(r
, "Failed to get device property: %m");
939 if (!streq(v
, "gpt"))
940 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
941 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
942 "File system \"%s\" is not on a GPT partition table.", node
);
944 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
946 return log_error_errno(r
, "Failed to get device property: %m");
947 if (!streq(v
, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"))
948 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
949 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
950 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node
);
952 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_UUID", &v
);
954 return log_error_errno(r
, "Failed to get device property: %m");
955 r
= sd_id128_from_string(v
, &uuid
);
957 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
959 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_NUMBER", &v
);
961 return log_error_errno(r
, "Failed to get device property: %m");
962 r
= safe_atou32(v
, &part
);
964 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
966 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_OFFSET", &v
);
968 return log_error_errno(r
, "Failed to get device property: %m");
969 r
= safe_atou64(v
, &pstart
);
971 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
973 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SIZE", &v
);
975 return log_error_errno(r
, "Failed to get device property: %m");
976 r
= safe_atou64(v
, &psize
);
978 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
983 *ret_pstart
= pstart
;
992 static int verify_fsroot_dir(
995 bool unprivileged_mode
,
999 const char *t2
, *trigger
;
1005 /* So, the ESP and XBOOTLDR partition are commonly located on an autofs mount. stat() on the
1006 * directory won't trigger it, if it is not mounted yet. Let's hence explicitly trigger it here,
1007 * before stat()ing */
1008 trigger
= strjoina(path
, "/trigger"); /* Filename doesn't matter... */
1009 (void) access(trigger
, F_OK
);
1011 if (stat(path
, &st
) < 0)
1012 return log_full_errno((searching
&& errno
== ENOENT
) ||
1013 (unprivileged_mode
&& errno
== EACCES
) ? LOG_DEBUG
: LOG_ERR
, errno
,
1014 "Failed to determine block device node of \"%s\": %m", path
);
1016 if (major(st
.st_dev
) == 0)
1017 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
1018 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
1019 "Block device node of \"%s\" is invalid.", path
);
1021 t2
= strjoina(path
, "/..");
1022 if (stat(t2
, &st2
) < 0) {
1023 if (errno
!= EACCES
)
1026 _cleanup_free_
char *parent
= NULL
;
1028 /* If going via ".." didn't work due to EACCESS, then let's determine the parent path
1029 * directly instead. It's not as good, due to symlinks and such, but we can't do
1030 * anything better here. */
1032 parent
= dirname_malloc(path
);
1036 if (stat(parent
, &st2
) < 0)
1043 return log_full_errno(unprivileged_mode
&& r
== -EACCES
? LOG_DEBUG
: LOG_ERR
, r
,
1044 "Failed to determine block device node of parent of \"%s\": %m", path
);
1047 if (st
.st_dev
== st2
.st_dev
)
1048 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
1049 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
1050 "Directory \"%s\" is not the root of the file system.", path
);
1053 *ret_dev
= st
.st_dev
;
1058 static int verify_esp(
1061 bool unprivileged_mode
,
1063 uint64_t *ret_pstart
,
1064 uint64_t *ret_psize
,
1065 sd_id128_t
*ret_uuid
) {
1073 /* This logs about all errors, except:
1075 * -ENOENT → if 'searching' is set, and the dir doesn't exist
1076 * -EADDRNOTAVAIL → if 'searching' is set, and the dir doesn't look like an ESP
1077 * -EACESS → if 'unprivileged_mode' is set, and we have trouble acessing the thing
1080 relax_checks
= getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0;
1082 /* Non-root user can only check the status, so if an error occured in the following, it does not cause any
1083 * issues. Let's also, silence the error messages. */
1085 if (!relax_checks
) {
1088 if (statfs(p
, &sfs
) < 0)
1089 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
1090 return log_full_errno((searching
&& errno
== ENOENT
) ||
1091 (unprivileged_mode
&& errno
== EACCES
) ? LOG_DEBUG
: LOG_ERR
, errno
,
1092 "Failed to check file system type of \"%s\": %m", p
);
1094 if (!F_TYPE_EQUAL(sfs
.f_type
, MSDOS_SUPER_MAGIC
))
1095 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
1096 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
1097 "File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p
);
1100 r
= verify_fsroot_dir(p
, searching
, unprivileged_mode
, &devid
);
1104 /* In a container we don't have access to block devices, skip this part of the verification, we trust
1105 * the container manager set everything up correctly on its own. */
1106 if (detect_container() > 0 || relax_checks
)
1109 /* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
1110 * use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
1111 * emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
1112 * however blkid can't work if we have no privileges to access block devices directly, which is why
1113 * we use udev in that case. */
1114 if (unprivileged_mode
)
1115 return verify_esp_udev(devid
, searching
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
1117 return verify_esp_blkid(devid
, searching
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
1127 *ret_uuid
= SD_ID128_NULL
;
1132 int find_esp_and_warn(
1134 bool unprivileged_mode
,
1137 uint64_t *ret_pstart
,
1138 uint64_t *ret_psize
,
1139 sd_id128_t
*ret_uuid
) {
1143 /* This logs about all errors except:
1145 * -ENOKEY → when we can't find the partition
1146 * -EACCESS → when unprivileged_mode is true, and we can't access something
1150 r
= verify_esp(path
, false, unprivileged_mode
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
1157 path
= getenv("SYSTEMD_ESP_PATH");
1159 if (!path_is_valid(path
) || !path_is_absolute(path
))
1160 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1161 "$SYSTEMD_ESP_PATH does not refer to absolute path, refusing to use it: %s",
1164 /* Note: when the user explicitly configured things with an env var we won't validate the mount
1165 * point. After all we want this to be useful for testing. */
1169 FOREACH_STRING(path
, "/efi", "/boot", "/boot/efi") {
1171 r
= verify_esp(path
, true, unprivileged_mode
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
1174 if (!IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
)) /* This one is not it */
1178 /* No logging here */
1195 static int verify_xbootldr_blkid(
1198 sd_id128_t
*ret_uuid
) {
1200 sd_id128_t uuid
= SD_ID128_NULL
;
1203 _cleanup_(blkid_free_probep
) blkid_probe b
= NULL
;
1204 _cleanup_free_
char *node
= NULL
;
1208 r
= device_path_make_major_minor(S_IFBLK
, devid
, &node
);
1210 return log_error_errno(r
, "Failed to format major/minor device path: %m");
1212 b
= blkid_new_probe_from_filename(node
);
1214 return log_error_errno(errno
?: SYNTHETIC_ERRNO(ENOMEM
), "Failed to open file system \"%s\": %m", node
);
1216 blkid_probe_enable_partitions(b
, 1);
1217 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
1220 r
= blkid_do_safeprobe(b
);
1222 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" is ambiguous.", node
);
1224 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" does not contain a label.", node
);
1226 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe file system \"%s\": %m", node
);
1229 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
1231 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition scheme of \"%s\": %m", node
);
1232 if (streq(v
, "gpt")) {
1235 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
1237 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition type UUID of \"%s\": %m", node
);
1238 if (!streq(v
, "bc13c2ff-59e6-4262-a352-b275fd6f7172"))
1239 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
1240 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
1241 "File system \"%s\" has wrong type for extended boot loader partition.", node
);
1244 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
1246 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition entry UUID of \"%s\": %m", node
);
1247 r
= sd_id128_from_string(v
, &uuid
);
1249 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
1251 } else if (streq(v
, "dos")) {
1254 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
1256 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition type UUID of \"%s\": %m", node
);
1257 if (!streq(v
, "0xea"))
1258 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
1259 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
1260 "File system \"%s\" has wrong type for extended boot loader partition.", node
);
1263 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
1264 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
1265 "File system \"%s\" is not on a GPT or DOS partition table.", node
);
1274 static int verify_xbootldr_udev(
1277 sd_id128_t
*ret_uuid
) {
1279 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
1280 _cleanup_free_
char *node
= NULL
;
1281 sd_id128_t uuid
= SD_ID128_NULL
;
1285 r
= device_path_make_major_minor(S_IFBLK
, devid
, &node
);
1287 return log_error_errno(r
, "Failed to format major/minor device path: %m");
1289 r
= sd_device_new_from_devnum(&d
, 'b', devid
);
1291 return log_error_errno(r
, "Failed to get device from device number: %m");
1293 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SCHEME", &v
);
1295 return log_error_errno(r
, "Failed to get device property: %m");
1297 if (streq(v
, "gpt")) {
1299 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
1301 return log_error_errno(r
, "Failed to get device property: %m");
1302 if (!streq(v
, "bc13c2ff-59e6-4262-a352-b275fd6f7172"))
1303 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
1304 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
1305 "File system \"%s\" has wrong type for extended boot loader partition.", node
);
1307 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_UUID", &v
);
1309 return log_error_errno(r
, "Failed to get device property: %m");
1310 r
= sd_id128_from_string(v
, &uuid
);
1312 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
1314 } else if (streq(v
, "dos")) {
1316 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
1318 return log_error_errno(r
, "Failed to get device property: %m");
1319 if (!streq(v
, "0xea"))
1320 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
1321 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
1322 "File system \"%s\" has wrong type for extended boot loader partition.", node
);
1324 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
1325 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
1326 "File system \"%s\" is not on a GPT or DOS partition table.", node
);
1334 static int verify_xbootldr(
1337 bool unprivileged_mode
,
1338 sd_id128_t
*ret_uuid
) {
1346 relax_checks
= getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0;
1348 r
= verify_fsroot_dir(p
, searching
, unprivileged_mode
, &devid
);
1352 if (detect_container() > 0 || relax_checks
)
1355 if (unprivileged_mode
)
1356 return verify_xbootldr_udev(devid
, searching
, ret_uuid
);
1358 return verify_xbootldr_blkid(devid
, searching
, ret_uuid
);
1362 *ret_uuid
= SD_ID128_NULL
;
1367 int find_xbootldr_and_warn(
1369 bool unprivileged_mode
,
1371 sd_id128_t
*ret_uuid
) {
1375 /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
1378 r
= verify_xbootldr(path
, false, unprivileged_mode
, ret_uuid
);
1385 path
= getenv("SYSTEMD_XBOOTLDR_PATH");
1387 if (!path_is_valid(path
) || !path_is_absolute(path
))
1388 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1389 "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s",
1395 r
= verify_xbootldr("/boot", true, unprivileged_mode
, ret_uuid
);
1400 if (!IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
)) /* This one is not it */
1419 static const char* const boot_entry_type_table
[_BOOT_ENTRY_MAX
] = {
1420 [BOOT_ENTRY_CONF
] = "conf",
1421 [BOOT_ENTRY_UNIFIED
] = "unified",
1422 [BOOT_ENTRY_LOADER
] = "loader",
1425 DEFINE_STRING_TABLE_LOOKUP(boot_entry_type
, BootEntryType
);