1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/magic.h>
9 #include "alloc-util.h"
10 #include "blkid-util.h"
11 #include "chase-symlinks.h"
12 #include "device-util.h"
13 #include "devnum-util.h"
15 #include "errno-util.h"
18 #include "parse-util.h"
19 #include "path-util.h"
20 #include "stat-util.h"
21 #include "string-util.h"
24 typedef enum VerifyESPFlags
{
25 VERIFY_ESP_SEARCHING
= 1 << 0, /* Downgrade various "not found" logs to debug level */
26 VERIFY_ESP_UNPRIVILEGED_MODE
= 1 << 1, /* Call into udev rather than blkid */
27 VERIFY_ESP_RELAX_CHECKS
= 1 << 2, /* Do not validate ESP partition */
30 static int verify_esp_blkid(
36 sd_id128_t
*ret_uuid
) {
38 sd_id128_t uuid
= SD_ID128_NULL
;
39 uint64_t pstart
= 0, psize
= 0;
43 _cleanup_(blkid_free_probep
) blkid_probe b
= NULL
;
44 _cleanup_free_
char *node
= NULL
;
48 r
= devname_from_devnum(S_IFBLK
, devid
, &node
);
50 return log_error_errno(r
, "Failed to get device path for " DEVNUM_FORMAT_STR
": %m", DEVNUM_FORMAT_VAL(devid
));
53 b
= blkid_new_probe_from_filename(node
);
55 return log_error_errno(errno
?: SYNTHETIC_ERRNO(ENOMEM
), "Failed to open file system \"%s\": %m", node
);
57 blkid_probe_enable_superblocks(b
, 1);
58 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
59 blkid_probe_enable_partitions(b
, 1);
60 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
63 r
= blkid_do_safeprobe(b
);
65 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" is ambiguous.", node
);
67 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" does not contain a label.", node
);
69 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe file system \"%s\": %m", node
);
71 r
= blkid_probe_lookup_value(b
, "TYPE", &v
, NULL
);
73 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
74 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
75 "No filesystem found on \"%s\": %m", node
);
76 if (!streq(v
, "vfat"))
77 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
78 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
79 "File system \"%s\" is not FAT.", node
);
81 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
83 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
84 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
85 "File system \"%s\" is not located on a partitioned block device.", node
);
87 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
88 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
89 "File system \"%s\" is not on a GPT partition table.", node
);
92 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
94 return log_error_errno(errno
?: EIO
, "Failed to probe partition type UUID of \"%s\": %m", node
);
95 if (sd_id128_string_equal(v
, GPT_ESP
) <= 0)
96 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
97 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
98 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node
);
101 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
103 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition entry UUID of \"%s\": %m", node
);
104 r
= sd_id128_from_string(v
, &uuid
);
106 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
109 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_NUMBER", &v
, NULL
);
111 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition number of \"%s\": %m", node
);
112 r
= safe_atou32(v
, &part
);
114 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
117 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_OFFSET", &v
, NULL
);
119 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition offset of \"%s\": %m", node
);
120 r
= safe_atou64(v
, &pstart
);
122 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
125 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SIZE", &v
, NULL
);
127 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition size of \"%s\": %m", node
);
128 r
= safe_atou64(v
, &psize
);
130 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
136 *ret_pstart
= pstart
;
145 static int verify_esp_udev(
149 uint64_t *ret_pstart
,
151 sd_id128_t
*ret_uuid
) {
153 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
154 sd_id128_t uuid
= SD_ID128_NULL
;
155 uint64_t pstart
= 0, psize
= 0;
157 const char *node
, *v
;
160 r
= sd_device_new_from_devnum(&d
, 'b', devid
);
162 return log_error_errno(r
, "Failed to get device from device number: %m");
164 r
= sd_device_get_devname(d
, &node
);
166 return log_error_errno(r
, "Failed to get device node: %m");
168 r
= sd_device_get_property_value(d
, "ID_FS_TYPE", &v
);
170 return log_error_errno(r
, "Failed to get device property: %m");
171 if (!streq(v
, "vfat"))
172 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
173 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
174 "File system \"%s\" is not FAT.", node
);
176 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SCHEME", &v
);
178 return log_error_errno(r
, "Failed to get device property: %m");
179 if (!streq(v
, "gpt"))
180 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
181 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
182 "File system \"%s\" is not on a GPT partition table.", node
);
184 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
186 return log_error_errno(r
, "Failed to get device property: %m");
187 if (sd_id128_string_equal(v
, GPT_ESP
) <= 0)
188 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
189 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
190 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node
);
192 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_UUID", &v
);
194 return log_error_errno(r
, "Failed to get device property: %m");
195 r
= sd_id128_from_string(v
, &uuid
);
197 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
199 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_NUMBER", &v
);
201 return log_error_errno(r
, "Failed to get device property: %m");
202 r
= safe_atou32(v
, &part
);
204 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
206 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_OFFSET", &v
);
208 return log_error_errno(r
, "Failed to get device property: %m");
209 r
= safe_atou64(v
, &pstart
);
211 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
213 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SIZE", &v
);
215 return log_error_errno(r
, "Failed to get device property: %m");
216 r
= safe_atou64(v
, &psize
);
218 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
223 *ret_pstart
= pstart
;
232 static int verify_fsroot_dir(
235 bool unprivileged_mode
,
239 const char *t2
, *trigger
;
245 /* So, the ESP and XBOOTLDR partition are commonly located on an autofs mount. stat() on the
246 * directory won't trigger it, if it is not mounted yet. Let's hence explicitly trigger it here,
247 * before stat()ing */
248 trigger
= strjoina(path
, "/trigger"); /* Filename doesn't matter... */
249 (void) access(trigger
, F_OK
);
251 if (stat(path
, &st
) < 0)
252 return log_full_errno((searching
&& errno
== ENOENT
) ||
253 (unprivileged_mode
&& errno
== EACCES
) ? LOG_DEBUG
: LOG_ERR
, errno
,
254 "Failed to determine block device node of \"%s\": %m", path
);
256 if (major(st
.st_dev
) == 0)
257 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
258 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
259 "Block device node of \"%s\" is invalid.", path
);
261 if (path_equal(path
, "/")) {
262 /* Let's assume that the root directory of the OS is always the root of its file system
263 * (which technically doesn't have to be the case, but it's close enough, and it's not easy
264 * to be fully correct for it, since we can't look further up than the root dir easily.) */
266 *ret_dev
= st
.st_dev
;
271 t2
= strjoina(path
, "/..");
272 if (stat(t2
, &st2
) < 0) {
276 _cleanup_free_
char *parent
= NULL
;
278 /* If going via ".." didn't work due to EACCESS, then let's determine the parent path
279 * directly instead. It's not as good, due to symlinks and such, but we can't do
280 * anything better here. */
282 r
= path_extract_directory(path
, &parent
);
284 return log_error_errno(r
, "Failed to extract parent path from '%s': %m", path
);
286 r
= RET_NERRNO(stat(parent
, &st2
));
290 return log_full_errno(unprivileged_mode
&& r
== -EACCES
? LOG_DEBUG
: LOG_ERR
, r
,
291 "Failed to determine block device node of parent of \"%s\": %m", path
);
294 if (st
.st_dev
== st2
.st_dev
)
295 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
296 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
297 "Directory \"%s\" is not the root of the file system.", path
);
300 *ret_dev
= st
.st_dev
;
305 static int verify_esp(
308 uint64_t *ret_pstart
,
310 sd_id128_t
*ret_uuid
,
312 VerifyESPFlags flags
) {
314 bool relax_checks
, searching
= FLAGS_SET(flags
, VERIFY_ESP_SEARCHING
),
315 unprivileged_mode
= FLAGS_SET(flags
, VERIFY_ESP_UNPRIVILEGED_MODE
);
321 /* This logs about all errors, except:
323 * -ENOENT → if 'searching' is set, and the dir doesn't exist
324 * -EADDRNOTAVAIL → if 'searching' is set, and the dir doesn't look like an ESP
325 * -EACESS → if 'unprivileged_mode' is set, and we have trouble accessing the thing
328 relax_checks
= getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0 || FLAGS_SET(flags
, VERIFY_ESP_RELAX_CHECKS
);
330 /* Non-root user can only check the status, so if an error occurred in the following, it does not cause any
331 * issues. Let's also, silence the error messages. */
336 if (statfs(p
, &sfs
) < 0)
337 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
338 return log_full_errno((searching
&& errno
== ENOENT
) ||
339 (unprivileged_mode
&& errno
== EACCES
) ? LOG_DEBUG
: LOG_ERR
, errno
,
340 "Failed to check file system type of \"%s\": %m", p
);
342 if (!F_TYPE_EQUAL(sfs
.f_type
, MSDOS_SUPER_MAGIC
))
343 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
344 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
345 "File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p
);
348 r
= verify_fsroot_dir(p
, searching
, unprivileged_mode
, &devid
);
352 /* In a container we don't have access to block devices, skip this part of the verification, we trust
353 * the container manager set everything up correctly on its own. */
354 if (detect_container() > 0 || relax_checks
)
357 /* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
358 * use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
359 * emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
360 * however blkid can't work if we have no privileges to access block devices directly, which is why
361 * we use udev in that case. */
362 if (unprivileged_mode
)
363 r
= verify_esp_udev(devid
, searching
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
365 r
= verify_esp_blkid(devid
, searching
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
382 *ret_uuid
= SD_ID128_NULL
;
389 int find_esp_and_warn(
392 bool unprivileged_mode
,
395 uint64_t *ret_pstart
,
397 sd_id128_t
*ret_uuid
,
400 VerifyESPFlags flags
= (unprivileged_mode
? VERIFY_ESP_UNPRIVILEGED_MODE
: 0) |
401 (root
? VERIFY_ESP_RELAX_CHECKS
: 0);
402 _cleanup_free_
char *p
= NULL
;
405 /* This logs about all errors except:
407 * -ENOKEY → when we can't find the partition
408 * -EACCESS → when unprivileged_mode is true, and we can't access something
412 r
= chase_symlinks(path
, root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
414 return log_error_errno(r
,
415 "Failed to resolve path %s%s%s: %m",
417 root
? " under directory " : "",
420 r
= verify_esp(p
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
, ret_devid
, flags
);
427 path
= getenv("SYSTEMD_ESP_PATH");
431 r
= chase_symlinks(path
, root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
433 return log_error_errno(r
,
434 "Failed to resolve path %s%s%s: %m",
436 root
? " under directory " : "",
439 if (!path_is_valid(p
) || !path_is_absolute(p
))
440 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
441 "$SYSTEMD_ESP_PATH does not refer to absolute path, refusing to use it: %s",
444 /* Note: when the user explicitly configured things with an env var we won't validate the
445 * path beyond checking it refers to a directory. After all we want this to be useful for
448 if (stat(p
, &st
) < 0)
449 return log_error_errno(errno
, "Failed to stat '%s': %m", p
);
450 if (!S_ISDIR(st
.st_mode
))
451 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR
), "ESP path '%s' is not a directory.", p
);
460 *ret_uuid
= SD_ID128_NULL
;
462 *ret_devid
= st
.st_dev
;
467 FOREACH_STRING(dir
, "/efi", "/boot", "/boot/efi") {
468 r
= chase_symlinks(dir
, root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
472 return log_error_errno(r
,
473 "Failed to resolve path %s%s%s: %m",
475 root
? " under directory " : "",
478 r
= verify_esp(p
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
, ret_devid
,
479 flags
| VERIFY_ESP_SEARCHING
);
482 if (!IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
)) /* This one is not it */
488 /* No logging here */
493 *ret_path
= TAKE_PTR(p
);
498 static int verify_xbootldr_blkid(
501 sd_id128_t
*ret_uuid
) {
503 sd_id128_t uuid
= SD_ID128_NULL
;
506 _cleanup_(blkid_free_probep
) blkid_probe b
= NULL
;
507 _cleanup_free_
char *node
= NULL
;
508 const char *type
, *v
;
511 r
= devname_from_devnum(S_IFBLK
, devid
, &node
);
513 return log_error_errno(r
, "Failed to get block device path for " DEVNUM_FORMAT_STR
": %m",
514 DEVNUM_FORMAT_VAL(devid
));
517 b
= blkid_new_probe_from_filename(node
);
519 return log_error_errno(errno
?: SYNTHETIC_ERRNO(ENOMEM
), "%s: Failed to create blkid probe: %m", node
);
521 blkid_probe_enable_partitions(b
, 1);
522 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
525 r
= blkid_do_safeprobe(b
);
527 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "%s: File system is ambiguous.", node
);
529 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "%s: File system does not contain a label.", node
);
531 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "%s: Failed to probe file system: %m", node
);
534 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &type
, NULL
);
536 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "%s: Failed to probe PART_ENTRY_SCHEME: %m", node
);
537 if (streq(type
, "gpt")) {
540 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
542 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "%s: Failed to probe PART_ENTRY_TYPE: %m", node
);
543 if (sd_id128_string_equal(v
, GPT_XBOOTLDR
) <= 0)
544 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
545 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
546 "%s: Partitition has wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node
, v
);
549 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
551 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "%s: Failed to probe PART_ENTRY_UUID: %m", node
);
552 r
= sd_id128_from_string(v
, &uuid
);
554 return log_error_errno(r
, "%s: Partition has invalid UUID PART_ENTRY_TYPE=%s: %m", node
, v
);
556 } else if (streq(type
, "dos")) {
559 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
561 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "%s: Failed to probe PART_ENTRY_TYPE: %m", node
);
562 if (!streq(v
, "0xea"))
563 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
564 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
565 "%s: Wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node
, v
);
568 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
569 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
570 "%s: Not on a GPT or DOS partition table (PART_ENTRY_SCHEME=%s).", node
, type
);
579 static int verify_xbootldr_udev(
582 sd_id128_t
*ret_uuid
) {
584 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
585 sd_id128_t uuid
= SD_ID128_NULL
;
586 const char *node
, *type
, *v
;
589 r
= sd_device_new_from_devnum(&d
, 'b', devid
);
591 return log_error_errno(r
, "Failed to get block device for " DEVNUM_FORMAT_STR
": %m", DEVNUM_FORMAT_VAL(devid
));
593 r
= sd_device_get_devname(d
, &node
);
595 return log_error_errno(r
, "Failed to get device node: %m");
597 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SCHEME", &type
);
599 return log_device_error_errno(d
, r
, "Failed to query ID_PART_ENTRY_SCHEME: %m");
601 if (streq(type
, "gpt")) {
603 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
605 return log_device_error_errno(d
, r
, "Failed to query ID_PART_ENTRY_TYPE: %m");
607 r
= sd_id128_string_equal(v
, GPT_XBOOTLDR
);
609 return log_device_error_errno(d
, r
, "Failed to parse ID_PART_ENTRY_TYPE=%s: %m", v
);
611 return log_device_full_errno(
613 searching
? LOG_DEBUG
: LOG_ERR
,
614 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
615 "Partition has wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v
);
617 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_UUID", &v
);
619 return log_device_error_errno(d
, r
, "Failed to query ID_PART_ENTRY_UUID: %m");
620 r
= sd_id128_from_string(v
, &uuid
);
622 return log_device_error_errno(d
, r
, "Partition has invalid UUID ID_PART_ENTRY_TYPE=%s: %m", v
);
624 } else if (streq(type
, "dos")) {
626 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
628 return log_device_error_errno(d
, r
, "Failed to query ID_PART_ENTRY_TYPE: %m");
629 if (!streq(v
, "0xea"))
630 return log_device_full_errno(
632 searching
? LOG_DEBUG
: LOG_ERR
,
633 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
634 "Wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v
);
637 return log_device_full_errno(
639 searching
? LOG_DEBUG
: LOG_ERR
,
640 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
641 "Not on a GPT or DOS partition table (ID_PART_ENTRY_SCHEME=%s).", type
);
649 static int verify_xbootldr(
652 bool unprivileged_mode
,
653 sd_id128_t
*ret_uuid
,
662 relax_checks
= getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0;
664 r
= verify_fsroot_dir(p
, searching
, unprivileged_mode
, &devid
);
668 if (detect_container() > 0 || relax_checks
)
671 if (unprivileged_mode
)
672 r
= verify_xbootldr_udev(devid
, searching
, ret_uuid
);
674 r
= verify_xbootldr_blkid(devid
, searching
, ret_uuid
);
685 *ret_uuid
= SD_ID128_NULL
;
692 int find_xbootldr_and_warn(
695 bool unprivileged_mode
,
697 sd_id128_t
*ret_uuid
,
700 _cleanup_free_
char *p
= NULL
;
703 /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
706 r
= chase_symlinks(path
, root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
708 return log_error_errno(r
,
709 "Failed to resolve path %s%s%s: %m",
711 root
? " under directory " : "",
714 r
= verify_xbootldr(p
, /* searching= */ false, unprivileged_mode
, ret_uuid
, ret_devid
);
721 path
= getenv("SYSTEMD_XBOOTLDR_PATH");
725 r
= chase_symlinks(path
, root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
727 return log_error_errno(r
,
728 "Failed to resolve path %s%s%s: %m",
730 root
? " under directory " : "",
733 if (!path_is_valid(p
) || !path_is_absolute(p
))
734 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
735 "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s",
738 if (stat(p
, &st
) < 0)
739 return log_error_errno(errno
, "Failed to stat '%s': %m", p
);
740 if (!S_ISDIR(st
.st_mode
))
741 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR
), "XBOOTLDR path '%s' is not a directory.", p
);
744 *ret_uuid
= SD_ID128_NULL
;
746 *ret_devid
= st
.st_dev
;
751 r
= chase_symlinks("/boot", root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
755 return log_error_errno(r
,
756 "Failed to resolve path /boot%s%s: %m",
757 root
? " under directory " : "",
760 r
= verify_xbootldr(p
, true, unprivileged_mode
, ret_uuid
, ret_devid
);
763 if (!IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
)) /* This one is not it */
770 *ret_path
= TAKE_PTR(p
);