]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/bootspec.c
bootspec: only sort entries list once
[thirdparty/systemd.git] / src / shared / bootspec.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <stdio.h>
4 #include <linux/magic.h>
5
6 #include "sd-device.h"
7 #include "sd-id128.h"
8
9 #include "alloc-util.h"
10 #include "blkid-util.h"
11 #include "bootspec.h"
12 #include "conf-files.h"
13 #include "def.h"
14 #include "device-nodes.h"
15 #include "dirent-util.h"
16 #include "efivars.h"
17 #include "env-file.h"
18 #include "env-util.h"
19 #include "fd-util.h"
20 #include "fileio.h"
21 #include "parse-util.h"
22 #include "path-util.h"
23 #include "pe-header.h"
24 #include "stat-util.h"
25 #include "string-util.h"
26 #include "strv.h"
27 #include "unaligned.h"
28 #include "virt.h"
29
30 static void boot_entry_free(BootEntry *entry) {
31 assert(entry);
32
33 free(entry->id);
34 free(entry->path);
35 free(entry->root);
36 free(entry->title);
37 free(entry->show_title);
38 free(entry->version);
39 free(entry->machine_id);
40 free(entry->architecture);
41 strv_free(entry->options);
42 free(entry->kernel);
43 free(entry->efi);
44 strv_free(entry->initrd);
45 free(entry->device_tree);
46 }
47
48 static int boot_entry_load(
49 const char *root,
50 const char *path,
51 BootEntry *entry) {
52
53 _cleanup_(boot_entry_free) BootEntry tmp = {};
54 _cleanup_fclose_ FILE *f = NULL;
55 unsigned line = 1;
56 char *b, *c;
57 int r;
58
59 assert(root);
60 assert(path);
61 assert(entry);
62
63 c = endswith_no_case(path, ".conf");
64 if (!c)
65 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry filename: %s", path);
66
67 b = basename(path);
68 tmp.id = strndup(b, c - b);
69 if (!tmp.id)
70 return log_oom();
71
72 tmp.path = strdup(path);
73 if (!tmp.path)
74 return log_oom();
75
76 tmp.root = strdup(root);
77 if (!tmp.root)
78 return log_oom();
79
80 f = fopen(path, "re");
81 if (!f)
82 return log_error_errno(errno, "Failed to open \"%s\": %m", path);
83
84 for (;;) {
85 _cleanup_free_ char *buf = NULL, *field = NULL;
86 const char *p;
87
88 r = read_line(f, LONG_LINE_MAX, &buf);
89 if (r == 0)
90 break;
91 if (r == -ENOBUFS)
92 return log_error_errno(r, "%s:%u: Line too long", path, line);
93 if (r < 0)
94 return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
95
96 line++;
97
98 if (IN_SET(*strstrip(buf), '#', '\0'))
99 continue;
100
101 p = buf;
102 r = extract_first_word(&p, &field, " \t", 0);
103 if (r < 0) {
104 log_error_errno(r, "Failed to parse config file %s line %u: %m", path, line);
105 continue;
106 }
107 if (r == 0) {
108 log_warning("%s:%u: Bad syntax", path, line);
109 continue;
110 }
111
112 if (streq(field, "title"))
113 r = free_and_strdup(&tmp.title, p);
114 else if (streq(field, "version"))
115 r = free_and_strdup(&tmp.version, p);
116 else if (streq(field, "machine-id"))
117 r = free_and_strdup(&tmp.machine_id, p);
118 else if (streq(field, "architecture"))
119 r = free_and_strdup(&tmp.architecture, p);
120 else if (streq(field, "options"))
121 r = strv_extend(&tmp.options, p);
122 else if (streq(field, "linux"))
123 r = free_and_strdup(&tmp.kernel, p);
124 else if (streq(field, "efi"))
125 r = free_and_strdup(&tmp.efi, p);
126 else if (streq(field, "initrd"))
127 r = strv_extend(&tmp.initrd, p);
128 else if (streq(field, "devicetree"))
129 r = free_and_strdup(&tmp.device_tree, p);
130 else {
131 log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field);
132 continue;
133 }
134 if (r < 0)
135 return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
136 }
137
138 *entry = tmp;
139 tmp = (BootEntry) {};
140 return 0;
141 }
142
143 void boot_config_free(BootConfig *config) {
144 size_t i;
145
146 assert(config);
147
148 free(config->default_pattern);
149 free(config->timeout);
150 free(config->editor);
151 free(config->auto_entries);
152 free(config->auto_firmware);
153
154 free(config->entry_oneshot);
155 free(config->entry_default);
156
157 for (i = 0; i < config->n_entries; i++)
158 boot_entry_free(config->entries + i);
159 free(config->entries);
160 }
161
162 static int boot_loader_read_conf(const char *path, BootConfig *config) {
163 _cleanup_fclose_ FILE *f = NULL;
164 unsigned line = 1;
165 int r;
166
167 assert(path);
168 assert(config);
169
170 f = fopen(path, "re");
171 if (!f) {
172 if (errno == ENOENT)
173 return 0;
174
175 return log_error_errno(errno, "Failed to open \"%s\": %m", path);
176 }
177
178 for (;;) {
179 _cleanup_free_ char *buf = NULL, *field = NULL;
180 const char *p;
181
182 r = read_line(f, LONG_LINE_MAX, &buf);
183 if (r == 0)
184 break;
185 if (r == -ENOBUFS)
186 return log_error_errno(r, "%s:%u: Line too long", path, line);
187 if (r < 0)
188 return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
189
190 line++;
191
192 if (IN_SET(*strstrip(buf), '#', '\0'))
193 continue;
194
195 p = buf;
196 r = extract_first_word(&p, &field, " \t", 0);
197 if (r < 0) {
198 log_error_errno(r, "Failed to parse config file %s line %u: %m", path, line);
199 continue;
200 }
201 if (r == 0) {
202 log_warning("%s:%u: Bad syntax", path, line);
203 continue;
204 }
205
206 if (streq(field, "default"))
207 r = free_and_strdup(&config->default_pattern, p);
208 else if (streq(field, "timeout"))
209 r = free_and_strdup(&config->timeout, p);
210 else if (streq(field, "editor"))
211 r = free_and_strdup(&config->editor, p);
212 else if (streq(field, "auto-entries"))
213 r = free_and_strdup(&config->auto_entries, p);
214 else if (streq(field, "auto-firmware"))
215 r = free_and_strdup(&config->auto_firmware, p);
216 else if (streq(field, "console-mode"))
217 r = free_and_strdup(&config->console_mode, p);
218 else {
219 log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field);
220 continue;
221 }
222 if (r < 0)
223 return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
224 }
225
226 return 1;
227 }
228
229 static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
230 return str_verscmp(a->id, b->id);
231 }
232
233 static int boot_entries_find(
234 const char *root,
235 const char *dir,
236 BootEntry **entries,
237 size_t *n_entries) {
238
239 _cleanup_strv_free_ char **files = NULL;
240 size_t n_allocated = *n_entries;
241 char **f;
242 int r;
243
244 assert(root);
245 assert(dir);
246 assert(entries);
247 assert(n_entries);
248
249 r = conf_files_list(&files, ".conf", NULL, 0, dir, NULL);
250 if (r < 0)
251 return log_error_errno(r, "Failed to list files in \"%s\": %m", dir);
252
253 STRV_FOREACH(f, files) {
254 if (!GREEDY_REALLOC0(*entries, n_allocated, *n_entries + 1))
255 return log_oom();
256
257 r = boot_entry_load(root, *f, *entries + *n_entries);
258 if (r < 0)
259 continue;
260
261 (*n_entries) ++;
262 }
263
264 return 0;
265 }
266
267 static int boot_entry_load_unified(
268 const char *root,
269 const char *path,
270 const char *osrelease,
271 const char *cmdline,
272 BootEntry *ret) {
273
274 _cleanup_free_ char *os_pretty_name = NULL, *os_id = NULL, *version_id = NULL, *build_id = NULL;
275 _cleanup_(boot_entry_free) BootEntry tmp = {};
276 _cleanup_fclose_ FILE *f = NULL;
277 const char *k;
278 int r;
279
280 assert(root);
281 assert(path);
282 assert(osrelease);
283
284 k = path_startswith(path, root);
285 if (!k)
286 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Path is not below root: %s", path);
287
288 f = fmemopen((void*) osrelease, strlen(osrelease), "r");
289 if (!f)
290 return log_error_errno(errno, "Failed to open os-release buffer: %m");
291
292 r = parse_env_file(f, "os-release",
293 "PRETTY_NAME", &os_pretty_name,
294 "ID", &os_id,
295 "VERSION_ID", &version_id,
296 "BUILD_ID", &build_id);
297 if (r < 0)
298 return log_error_errno(r, "Failed to parse os-release data from unified kernel image %s: %m", path);
299
300 if (!os_pretty_name || !os_id || !(version_id || build_id))
301 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Missing fields in os-release data from unified kernel image %s, refusing.", path);
302
303 tmp.id = strjoin(os_id, "-", version_id ?: build_id);
304 if (!tmp.id)
305 return log_oom();
306
307 tmp.path = strdup(path);
308 if (!tmp.path)
309 return log_oom();
310
311 tmp.root = strdup(root);
312 if (!tmp.root)
313 return log_oom();
314
315 tmp.kernel = strdup(skip_leading_chars(k, "/"));
316 if (!tmp.kernel)
317 return log_oom();
318
319 tmp.options = strv_new(skip_leading_chars(cmdline, WHITESPACE));
320 if (!tmp.options)
321 return log_oom();
322
323 delete_trailing_chars(tmp.options[0], WHITESPACE);
324
325 tmp.title = TAKE_PTR(os_pretty_name);
326
327 *ret = tmp;
328 tmp = (BootEntry) {};
329 return 0;
330 }
331
332 /* Maximum PE section we are willing to load (Note that sections we are not interested in may be larger, but
333 * the ones we do care about and we are willing to load into memory have this size limit.) */
334 #define PE_SECTION_SIZE_MAX (4U*1024U*1024U)
335
336 static int find_sections(
337 int fd,
338 char **ret_osrelease,
339 char **ret_cmdline) {
340
341 _cleanup_free_ struct PeSectionHeader *sections = NULL;
342 _cleanup_free_ char *osrelease = NULL, *cmdline = NULL;
343 size_t i, n_sections;
344 struct DosFileHeader dos;
345 struct PeHeader pe;
346 uint64_t start;
347 ssize_t n;
348
349 n = pread(fd, &dos, sizeof(dos), 0);
350 if (n < 0)
351 return log_error_errno(errno, "Failed read DOS header: %m");
352 if (n != sizeof(dos))
353 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading DOS header, refusing.");
354
355 if (dos.Magic[0] != 'M' || dos.Magic[1] != 'Z')
356 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "DOS executable magic missing, refusing.");
357
358 start = unaligned_read_le32(&dos.ExeHeader);
359 n = pread(fd, &pe, sizeof(pe), start);
360 if (n < 0)
361 return log_error_errno(errno, "Failed to read PE header: %m");
362 if (n != sizeof(pe))
363 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading PE header, refusing.");
364
365 if (pe.Magic[0] != 'P' || pe.Magic[1] != 'E' || pe.Magic[2] != 0 || pe.Magic[3] != 0)
366 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "PE executable magic missing, refusing.");
367
368 n_sections = unaligned_read_le16(&pe.FileHeader.NumberOfSections);
369 if (n_sections > 96)
370 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "PE header has too many sections, refusing.");
371
372 sections = new(struct PeSectionHeader, n_sections);
373 if (!sections)
374 return log_oom();
375
376 n = pread(fd, sections,
377 n_sections * sizeof(struct PeSectionHeader),
378 start + sizeof(pe) + unaligned_read_le16(&pe.FileHeader.SizeOfOptionalHeader));
379 if (n < 0)
380 return log_error_errno(errno, "Failed to read section data: %m");
381 if ((size_t) n != n_sections * sizeof(struct PeSectionHeader))
382 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading sections, refusing.");
383
384 for (i = 0; i < n_sections; i++) {
385 _cleanup_free_ char *k = NULL;
386 uint32_t offset, size;
387 char **b;
388
389 if (strneq((char*) sections[i].Name, ".osrel", sizeof(sections[i].Name)))
390 b = &osrelease;
391 else if (strneq((char*) sections[i].Name, ".cmdline", sizeof(sections[i].Name)))
392 b = &cmdline;
393 else
394 continue;
395
396 if (*b)
397 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Duplicate section %s, refusing.", sections[i].Name);
398
399 offset = unaligned_read_le32(&sections[i].PointerToRawData);
400 size = unaligned_read_le32(&sections[i].VirtualSize);
401
402 if (size > PE_SECTION_SIZE_MAX)
403 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Section %s too large, refusing.", sections[i].Name);
404
405 k = new(char, size+1);
406 if (!k)
407 return log_oom();
408
409 n = pread(fd, k, size, offset);
410 if (n < 0)
411 return log_error_errno(errno, "Failed to read section payload: %m");
412 if (n != size)
413 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading section payload, refusing:");
414
415 /* Allow one trailing NUL byte, but nothing more. */
416 if (size > 0 && memchr(k, 0, size - 1))
417 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Section contains embedded NUL byte: %m");
418
419 k[size] = 0;
420 *b = TAKE_PTR(k);
421 }
422
423 if (!osrelease)
424 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Image lacks .osrel section, refusing.");
425
426 if (ret_osrelease)
427 *ret_osrelease = TAKE_PTR(osrelease);
428 if (ret_cmdline)
429 *ret_cmdline = TAKE_PTR(cmdline);
430
431 return 0;
432 }
433
434 static int boot_entries_find_unified(
435 const char *root,
436 const char *dir,
437 BootEntry **entries,
438 size_t *n_entries) {
439
440 _cleanup_(closedirp) DIR *d = NULL;
441 size_t n_allocated = *n_entries;
442 struct dirent *de;
443 int r;
444
445 assert(root);
446 assert(dir);
447 assert(entries);
448 assert(n_entries);
449
450 d = opendir(dir);
451 if (!d) {
452 if (errno == ENOENT)
453 return 0;
454
455 return log_error_errno(errno, "Failed to open %s: %m", dir);
456 }
457
458 FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read %s: %m", dir)) {
459 _cleanup_free_ char *j = NULL, *osrelease = NULL, *cmdline = NULL;
460 _cleanup_close_ int fd = -1;
461
462 if (!dirent_is_file(de))
463 continue;
464
465 if (!endswith_no_case(de->d_name, ".efi"))
466 continue;
467
468 if (!GREEDY_REALLOC0(*entries, n_allocated, *n_entries + 1))
469 return log_oom();
470
471 fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
472 if (fd < 0) {
473 log_warning_errno(errno, "Failed to open %s/%s, ignoring: %m", dir, de->d_name);
474 continue;
475 }
476
477 r = fd_verify_regular(fd);
478 if (r < 0) {
479 log_warning_errno(errno, "File %s/%s is not regular, ignoring: %m", dir, de->d_name);
480 continue;
481 }
482
483 r = find_sections(fd, &osrelease, &cmdline);
484 if (r < 0)
485 continue;
486
487 j = path_join(dir, de->d_name);
488 if (!j)
489 return log_oom();
490
491 r = boot_entry_load_unified(root, j, osrelease, cmdline, *entries + *n_entries);
492 if (r < 0)
493 continue;
494
495 (*n_entries) ++;
496 }
497
498 return 0;
499 }
500
501 static bool find_nonunique(BootEntry *entries, size_t n_entries, bool *arr) {
502 size_t i, j;
503 bool non_unique = false;
504
505 assert(entries || n_entries == 0);
506 assert(arr || n_entries == 0);
507
508 for (i = 0; i < n_entries; i++)
509 arr[i] = false;
510
511 for (i = 0; i < n_entries; i++)
512 for (j = 0; j < n_entries; j++)
513 if (i != j && streq(boot_entry_title(entries + i),
514 boot_entry_title(entries + j)))
515 non_unique = arr[i] = arr[j] = true;
516
517 return non_unique;
518 }
519
520 static int boot_entries_uniquify(BootEntry *entries, size_t n_entries) {
521 char *s;
522 size_t i;
523 int r;
524 bool arr[n_entries];
525
526 assert(entries || n_entries == 0);
527
528 /* Find _all_ non-unique titles */
529 if (!find_nonunique(entries, n_entries, arr))
530 return 0;
531
532 /* Add version to non-unique titles */
533 for (i = 0; i < n_entries; i++)
534 if (arr[i] && entries[i].version) {
535 r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].version);
536 if (r < 0)
537 return -ENOMEM;
538
539 free_and_replace(entries[i].show_title, s);
540 }
541
542 if (!find_nonunique(entries, n_entries, arr))
543 return 0;
544
545 /* Add machine-id to non-unique titles */
546 for (i = 0; i < n_entries; i++)
547 if (arr[i] && entries[i].machine_id) {
548 r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].machine_id);
549 if (r < 0)
550 return -ENOMEM;
551
552 free_and_replace(entries[i].show_title, s);
553 }
554
555 if (!find_nonunique(entries, n_entries, arr))
556 return 0;
557
558 /* Add file name to non-unique titles */
559 for (i = 0; i < n_entries; i++)
560 if (arr[i]) {
561 r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].id);
562 if (r < 0)
563 return -ENOMEM;
564
565 free_and_replace(entries[i].show_title, s);
566 }
567
568 return 0;
569 }
570
571 static int boot_entries_select_default(const BootConfig *config) {
572 int i;
573
574 assert(config);
575
576 if (config->entry_oneshot)
577 for (i = config->n_entries - 1; i >= 0; i--)
578 if (streq(config->entry_oneshot, config->entries[i].id)) {
579 log_debug("Found default: id \"%s\" is matched by LoaderEntryOneShot",
580 config->entries[i].id);
581 return i;
582 }
583
584 if (config->entry_default)
585 for (i = config->n_entries - 1; i >= 0; i--)
586 if (streq(config->entry_default, config->entries[i].id)) {
587 log_debug("Found default: id \"%s\" is matched by LoaderEntryDefault",
588 config->entries[i].id);
589 return i;
590 }
591
592 if (config->default_pattern)
593 for (i = config->n_entries - 1; i >= 0; i--)
594 if (fnmatch(config->default_pattern, config->entries[i].id, FNM_CASEFOLD) == 0) {
595 log_debug("Found default: id \"%s\" is matched by pattern \"%s\"",
596 config->entries[i].id, config->default_pattern);
597 return i;
598 }
599
600 if (config->n_entries > 0)
601 log_debug("Found default: last entry \"%s\"", config->entries[config->n_entries - 1].id);
602 else
603 log_debug("Found no default boot entry :(");
604
605 return config->n_entries - 1; /* -1 means "no default" */
606 }
607
608 int boot_entries_load_config(
609 const char *esp_path,
610 const char *xbootldr_path,
611 BootConfig *config) {
612
613 const char *p;
614 int r;
615
616 assert(config);
617
618 if (esp_path) {
619 p = strjoina(esp_path, "/loader/loader.conf");
620 r = boot_loader_read_conf(p, config);
621 if (r < 0)
622 return r;
623
624 p = strjoina(esp_path, "/loader/entries");
625 r = boot_entries_find(esp_path, p, &config->entries, &config->n_entries);
626 if (r < 0)
627 return r;
628
629 p = strjoina(esp_path, "/EFI/Linux/");
630 r = boot_entries_find_unified(esp_path, p, &config->entries, &config->n_entries);
631 if (r < 0)
632 return r;
633 }
634
635 if (xbootldr_path) {
636 p = strjoina(xbootldr_path, "/loader/entries");
637 r = boot_entries_find(xbootldr_path, p, &config->entries, &config->n_entries);
638 if (r < 0)
639 return r;
640
641 p = strjoina(xbootldr_path, "/EFI/Linux/");
642 r = boot_entries_find_unified(xbootldr_path, p, &config->entries, &config->n_entries);
643 if (r < 0)
644 return r;
645 }
646
647 typesafe_qsort(config->entries, config->n_entries, boot_entry_compare);
648
649 r = boot_entries_uniquify(config->entries, config->n_entries);
650 if (r < 0)
651 return log_error_errno(r, "Failed to uniquify boot entries: %m");
652
653 if (is_efi_boot()) {
654 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", &config->entry_oneshot);
655 if (r < 0 && r != -ENOENT)
656 return log_error_errno(r, "Failed to read EFI var \"LoaderEntryOneShot\": %m");
657
658 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryDefault", &config->entry_default);
659 if (r < 0 && r != -ENOENT)
660 return log_error_errno(r, "Failed to read EFI var \"LoaderEntryDefault\": %m");
661 }
662
663 config->default_entry = boot_entries_select_default(config);
664 return 0;
665 }
666
667 /********************************************************************************/
668
669 static int verify_esp_blkid(
670 dev_t devid,
671 bool searching,
672 uint32_t *ret_part,
673 uint64_t *ret_pstart,
674 uint64_t *ret_psize,
675 sd_id128_t *ret_uuid) {
676
677 sd_id128_t uuid = SD_ID128_NULL;
678 uint64_t pstart = 0, psize = 0;
679 uint32_t part = 0;
680
681 #if HAVE_BLKID
682 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
683 _cleanup_free_ char *node = NULL;
684 const char *v;
685 int r;
686
687 r = device_path_make_major_minor(S_IFBLK, devid, &node);
688 if (r < 0)
689 return log_error_errno(r, "Failed to format major/minor device path: %m");
690
691 errno = 0;
692 b = blkid_new_probe_from_filename(node);
693 if (!b)
694 return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
695
696 blkid_probe_enable_superblocks(b, 1);
697 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
698 blkid_probe_enable_partitions(b, 1);
699 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
700
701 errno = 0;
702 r = blkid_do_safeprobe(b);
703 if (r == -2)
704 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
705 else if (r == 1)
706 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" does not contain a label.", node);
707 else if (r != 0)
708 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
709
710 errno = 0;
711 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
712 if (r != 0)
713 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system type of \"%s\": %m", node);
714 if (!streq(v, "vfat"))
715 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
716 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
717 "File system \"%s\" is not FAT.", node);
718
719 errno = 0;
720 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
721 if (r != 0)
722 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition scheme of \"%s\": %m", node);
723 if (!streq(v, "gpt"))
724 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
725 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
726 "File system \"%s\" is not on a GPT partition table.", node);
727
728 errno = 0;
729 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
730 if (r != 0)
731 return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID of \"%s\": %m", node);
732 if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"))
733 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
734 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
735 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
736
737 errno = 0;
738 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
739 if (r != 0)
740 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition entry UUID of \"%s\": %m", node);
741 r = sd_id128_from_string(v, &uuid);
742 if (r < 0)
743 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
744
745 errno = 0;
746 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
747 if (r != 0)
748 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": m", node);
749 r = safe_atou32(v, &part);
750 if (r < 0)
751 return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
752
753 errno = 0;
754 r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
755 if (r != 0)
756 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition offset of \"%s\": %m", node);
757 r = safe_atou64(v, &pstart);
758 if (r < 0)
759 return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
760
761 errno = 0;
762 r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
763 if (r != 0)
764 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition size of \"%s\": %m", node);
765 r = safe_atou64(v, &psize);
766 if (r < 0)
767 return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
768 #endif
769
770 if (ret_part)
771 *ret_part = part;
772 if (ret_pstart)
773 *ret_pstart = pstart;
774 if (ret_psize)
775 *ret_psize = psize;
776 if (ret_uuid)
777 *ret_uuid = uuid;
778
779 return 0;
780 }
781
782 static int verify_esp_udev(
783 dev_t devid,
784 bool searching,
785 uint32_t *ret_part,
786 uint64_t *ret_pstart,
787 uint64_t *ret_psize,
788 sd_id128_t *ret_uuid) {
789
790 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
791 _cleanup_free_ char *node = NULL;
792 sd_id128_t uuid = SD_ID128_NULL;
793 uint64_t pstart = 0, psize = 0;
794 uint32_t part = 0;
795 const char *v;
796 int r;
797
798 r = device_path_make_major_minor(S_IFBLK, devid, &node);
799 if (r < 0)
800 return log_error_errno(r, "Failed to format major/minor device path: %m");
801
802 r = sd_device_new_from_devnum(&d, 'b', devid);
803 if (r < 0)
804 return log_error_errno(r, "Failed to get device from device number: %m");
805
806 r = sd_device_get_property_value(d, "ID_FS_TYPE", &v);
807 if (r < 0)
808 return log_error_errno(r, "Failed to get device property: %m");
809 if (!streq(v, "vfat"))
810 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
811 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
812 "File system \"%s\" is not FAT.", node );
813
814 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
815 if (r < 0)
816 return log_error_errno(r, "Failed to get device property: %m");
817 if (!streq(v, "gpt"))
818 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
819 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
820 "File system \"%s\" is not on a GPT partition table.", node);
821
822 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
823 if (r < 0)
824 return log_error_errno(r, "Failed to get device property: %m");
825 if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"))
826 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
827 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
828 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
829
830 r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
831 if (r < 0)
832 return log_error_errno(r, "Failed to get device property: %m");
833 r = sd_id128_from_string(v, &uuid);
834 if (r < 0)
835 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
836
837 r = sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &v);
838 if (r < 0)
839 return log_error_errno(r, "Failed to get device property: %m");
840 r = safe_atou32(v, &part);
841 if (r < 0)
842 return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
843
844 r = sd_device_get_property_value(d, "ID_PART_ENTRY_OFFSET", &v);
845 if (r < 0)
846 return log_error_errno(r, "Failed to get device property: %m");
847 r = safe_atou64(v, &pstart);
848 if (r < 0)
849 return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
850
851 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SIZE", &v);
852 if (r < 0)
853 return log_error_errno(r, "Failed to get device property: %m");
854 r = safe_atou64(v, &psize);
855 if (r < 0)
856 return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
857
858 if (ret_part)
859 *ret_part = part;
860 if (ret_pstart)
861 *ret_pstart = pstart;
862 if (ret_psize)
863 *ret_psize = psize;
864 if (ret_uuid)
865 *ret_uuid = uuid;
866
867 return 0;
868 }
869
870 static int verify_fsroot_dir(
871 const char *path,
872 bool searching,
873 bool unprivileged_mode,
874 dev_t *ret_dev) {
875
876 struct stat st, st2;
877 const char *t2;
878 int r;
879
880 assert(path);
881 assert(ret_dev);
882
883 if (stat(path, &st) < 0)
884 return log_full_errno((searching && errno == ENOENT) ||
885 (unprivileged_mode && errno == EACCES) ? LOG_DEBUG : LOG_ERR, errno,
886 "Failed to determine block device node of \"%s\": %m", path);
887
888 if (major(st.st_dev) == 0)
889 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
890 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
891 "Block device node of \"%s\" is invalid.", path);
892
893 t2 = strjoina(path, "/..");
894 if (stat(t2, &st2) < 0) {
895 if (errno != EACCES)
896 r = -errno;
897 else {
898 _cleanup_free_ char *parent = NULL;
899
900 /* If going via ".." didn't work due to EACCESS, then let's determine the parent path
901 * directly instead. It's not as good, due to symlinks and such, but we can't do
902 * anything better here. */
903
904 parent = dirname_malloc(path);
905 if (!parent)
906 return log_oom();
907
908 if (stat(parent, &st2) < 0)
909 r = -errno;
910 else
911 r = 0;
912 }
913
914 if (r < 0)
915 return log_full_errno(unprivileged_mode && r == -EACCES ? LOG_DEBUG : LOG_ERR, r,
916 "Failed to determine block device node of parent of \"%s\": %m", path);
917 }
918
919 if (st.st_dev == st2.st_dev)
920 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
921 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
922 "Directory \"%s\" is not the root of the file system.", path);
923
924 if (ret_dev)
925 *ret_dev = st.st_dev;
926
927 return 0;
928 }
929
930 static int verify_esp(
931 const char *p,
932 bool searching,
933 bool unprivileged_mode,
934 uint32_t *ret_part,
935 uint64_t *ret_pstart,
936 uint64_t *ret_psize,
937 sd_id128_t *ret_uuid) {
938
939 bool relax_checks;
940 dev_t devid;
941 int r;
942
943 assert(p);
944
945 /* This logs about all errors, except:
946 *
947 * -ENOENT → if 'searching' is set, and the dir doesn't exist
948 * -EADDRNOTAVAIL → if 'searching' is set, and the dir doesn't look like an ESP
949 * -EACESS → if 'unprivileged_mode' is set, and we have trouble acessing the thing
950 */
951
952 relax_checks = getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0;
953
954 /* Non-root user can only check the status, so if an error occured in the following, it does not cause any
955 * issues. Let's also, silence the error messages. */
956
957 if (!relax_checks) {
958 struct statfs sfs;
959
960 if (statfs(p, &sfs) < 0)
961 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
962 return log_full_errno((searching && errno == ENOENT) ||
963 (unprivileged_mode && errno == EACCES) ? LOG_DEBUG : LOG_ERR, errno,
964 "Failed to check file system type of \"%s\": %m", p);
965
966 if (!F_TYPE_EQUAL(sfs.f_type, MSDOS_SUPER_MAGIC))
967 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
968 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
969 "File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
970 }
971
972 r = verify_fsroot_dir(p, searching, unprivileged_mode, &devid);
973 if (r < 0)
974 return r;
975
976 /* In a container we don't have access to block devices, skip this part of the verification, we trust
977 * the container manager set everything up correctly on its own. */
978 if (detect_container() > 0 || relax_checks)
979 goto finish;
980
981 /* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
982 * use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
983 * emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
984 * however blkid can't work if we have no privileges to access block devices directly, which is why
985 * we use udev in that case. */
986 if (unprivileged_mode)
987 return verify_esp_udev(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
988 else
989 return verify_esp_blkid(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
990
991 finish:
992 if (ret_part)
993 *ret_part = 0;
994 if (ret_pstart)
995 *ret_pstart = 0;
996 if (ret_psize)
997 *ret_psize = 0;
998 if (ret_uuid)
999 *ret_uuid = SD_ID128_NULL;
1000
1001 return 0;
1002 }
1003
1004 int find_esp_and_warn(
1005 const char *path,
1006 bool unprivileged_mode,
1007 char **ret_path,
1008 uint32_t *ret_part,
1009 uint64_t *ret_pstart,
1010 uint64_t *ret_psize,
1011 sd_id128_t *ret_uuid) {
1012
1013 int r;
1014
1015 /* This logs about all errors except:
1016 *
1017 * -ENOKEY → when we can't find the partition
1018 * -EACCESS → when unprivileged_mode is true, and we can't access something
1019 */
1020
1021 if (path) {
1022 r = verify_esp(path, false, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid);
1023 if (r < 0)
1024 return r;
1025
1026 goto found;
1027 }
1028
1029 path = getenv("SYSTEMD_ESP_PATH");
1030 if (path) {
1031 if (!path_is_valid(path) || !path_is_absolute(path))
1032 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1033 "$SYSTEMD_ESP_PATH does not refer to absolute path, refusing to use it: %s",
1034 path);
1035
1036 /* Note: when the user explicitly configured things with an env var we won't validate the mount
1037 * point. After all we want this to be useful for testing. */
1038 goto found;
1039 }
1040
1041 FOREACH_STRING(path, "/efi", "/boot", "/boot/efi") {
1042
1043 r = verify_esp(path, true, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid);
1044 if (r >= 0)
1045 goto found;
1046 if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
1047 return r;
1048 }
1049
1050 /* No logging here */
1051 return -ENOKEY;
1052
1053 found:
1054 if (ret_path) {
1055 char *c;
1056
1057 c = strdup(path);
1058 if (!c)
1059 return log_oom();
1060
1061 *ret_path = c;
1062 }
1063
1064 return 0;
1065 }
1066
1067 static int verify_xbootldr_blkid(
1068 dev_t devid,
1069 bool searching,
1070 sd_id128_t *ret_uuid) {
1071
1072 sd_id128_t uuid = SD_ID128_NULL;
1073
1074 #if HAVE_BLKID
1075 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
1076 _cleanup_free_ char *node = NULL;
1077 const char *v;
1078 int r;
1079
1080 r = device_path_make_major_minor(S_IFBLK, devid, &node);
1081 if (r < 0)
1082 return log_error_errno(r, "Failed to format major/minor device path: %m");
1083 errno = 0;
1084 b = blkid_new_probe_from_filename(node);
1085 if (!b)
1086 return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
1087
1088 blkid_probe_enable_partitions(b, 1);
1089 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
1090
1091 errno = 0;
1092 r = blkid_do_safeprobe(b);
1093 if (r == -2)
1094 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
1095 else if (r == 1)
1096 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" does not contain a label.", node);
1097 else if (r != 0)
1098 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
1099
1100 errno = 0;
1101 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
1102 if (r != 0)
1103 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition scheme of \"%s\": %m", node);
1104 if (streq(v, "gpt")) {
1105
1106 errno = 0;
1107 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
1108 if (r != 0)
1109 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition type UUID of \"%s\": %m", node);
1110 if (!streq(v, "bc13c2ff-59e6-4262-a352-b275fd6f7172"))
1111 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
1112 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
1113 "File system \"%s\" has wrong type for extended boot loader partition.", node);
1114
1115 errno = 0;
1116 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
1117 if (r != 0)
1118 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition entry UUID of \"%s\": %m", node);
1119 r = sd_id128_from_string(v, &uuid);
1120 if (r < 0)
1121 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
1122
1123 } else if (streq(v, "dos")) {
1124
1125 errno = 0;
1126 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
1127 if (r != 0)
1128 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition type UUID of \"%s\": %m", node);
1129 if (!streq(v, "0xea"))
1130 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
1131 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
1132 "File system \"%s\" has wrong type for extended boot loader partition.", node);
1133
1134 } else
1135 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
1136 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
1137 "File system \"%s\" is not on a GPT or DOS partition table.", node);
1138 #endif
1139
1140 if (ret_uuid)
1141 *ret_uuid = uuid;
1142
1143 return 0;
1144 }
1145
1146 static int verify_xbootldr_udev(
1147 dev_t devid,
1148 bool searching,
1149 sd_id128_t *ret_uuid) {
1150
1151 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
1152 _cleanup_free_ char *node = NULL;
1153 sd_id128_t uuid = SD_ID128_NULL;
1154 const char *v;
1155 int r;
1156
1157 r = device_path_make_major_minor(S_IFBLK, devid, &node);
1158 if (r < 0)
1159 return log_error_errno(r, "Failed to format major/minor device path: %m");
1160
1161 r = sd_device_new_from_devnum(&d, 'b', devid);
1162 if (r < 0)
1163 return log_error_errno(r, "Failed to get device from device number: %m");
1164
1165 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
1166 if (r < 0)
1167 return log_error_errno(r, "Failed to get device property: %m");
1168
1169 if (streq(v, "gpt")) {
1170
1171 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
1172 if (r < 0)
1173 return log_error_errno(r, "Failed to get device property: %m");
1174 if (!streq(v, "bc13c2ff-59e6-4262-a352-b275fd6f7172"))
1175 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
1176 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
1177 "File system \"%s\" has wrong type for extended boot loader partition.", node);
1178
1179 r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
1180 if (r < 0)
1181 return log_error_errno(r, "Failed to get device property: %m");
1182 r = sd_id128_from_string(v, &uuid);
1183 if (r < 0)
1184 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
1185
1186 } else if (streq(v, "dos")) {
1187
1188 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
1189 if (r < 0)
1190 return log_error_errno(r, "Failed to get device property: %m");
1191 if (!streq(v, "0xea"))
1192 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
1193 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
1194 "File system \"%s\" has wrong type for extended boot loader partition.", node);
1195 } else
1196 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
1197 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
1198 "File system \"%s\" is not on a GPT or DOS partition table.", node);
1199
1200 if (ret_uuid)
1201 *ret_uuid = uuid;
1202
1203 return 0;
1204 }
1205
1206 static int verify_xbootldr(
1207 const char *p,
1208 bool searching,
1209 bool unprivileged_mode,
1210 sd_id128_t *ret_uuid) {
1211
1212 bool relax_checks;
1213 dev_t devid;
1214 int r;
1215
1216 assert(p);
1217
1218 relax_checks = getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0;
1219
1220 r = verify_fsroot_dir(p, searching, unprivileged_mode, &devid);
1221 if (r < 0)
1222 return r;
1223
1224 if (detect_container() > 0 || relax_checks)
1225 goto finish;
1226
1227 if (unprivileged_mode)
1228 return verify_xbootldr_udev(devid, searching, ret_uuid);
1229 else
1230 return verify_xbootldr_blkid(devid, searching, ret_uuid);
1231
1232 finish:
1233 if (ret_uuid)
1234 *ret_uuid = SD_ID128_NULL;
1235
1236 return 0;
1237 }
1238
1239 int find_xbootldr_and_warn(
1240 const char *path,
1241 bool unprivileged_mode,
1242 char **ret_path,
1243 sd_id128_t *ret_uuid) {
1244
1245 int r;
1246
1247 /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
1248
1249 if (path) {
1250 r = verify_xbootldr(path, false, unprivileged_mode, ret_uuid);
1251 if (r < 0)
1252 return r;
1253
1254 goto found;
1255 }
1256
1257 path = getenv("SYSTEMD_XBOOTLDR_PATH");
1258 if (path) {
1259 if (!path_is_valid(path) || !path_is_absolute(path))
1260 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1261 "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s",
1262 path);
1263
1264 goto found;
1265 }
1266
1267 r = verify_xbootldr("/boot", true, unprivileged_mode, ret_uuid);
1268 if (r >= 0) {
1269 path = "/boot";
1270 goto found;
1271 }
1272 if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
1273 return r;
1274
1275 return -ENOKEY;
1276
1277 found:
1278 if (ret_path) {
1279 char *c;
1280
1281 c = strdup(path);
1282 if (!c)
1283 return log_oom();
1284
1285 *ret_path = c;
1286 }
1287
1288 return 0;
1289 }
1290
1291 int find_default_boot_entry(
1292 const char *esp_path,
1293 const char *xbootldr_path,
1294 BootConfig *config,
1295 const BootEntry **e) {
1296
1297 _cleanup_free_ char *esp_where = NULL, *xbootldr_where = NULL;
1298 int r;
1299
1300 assert(config);
1301 assert(e);
1302
1303 r = find_esp_and_warn(esp_path, false, &esp_where, NULL, NULL, NULL, NULL);
1304 if (r < 0)
1305 return r;
1306
1307 r = find_xbootldr_and_warn(xbootldr_path, false, &xbootldr_where, NULL);
1308 if (r < 0 && r != -ENOKEY)
1309 return r;
1310
1311 r = boot_entries_load_config(esp_where, xbootldr_where, config);
1312 if (r < 0)
1313 return log_error_errno(r, "Failed to load boot loader entries: %m");
1314
1315 if (config->default_entry < 0)
1316 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
1317 "No boot loader entry suitable as default, refusing to guess.");
1318
1319 *e = &config->entries[config->default_entry];
1320 log_debug("Found default boot loader entry in file \"%s\"", (*e)->path);
1321
1322 return 0;
1323 }