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 "btrfs-util.h"
12 #include "chase-symlinks.h"
13 #include "device-util.h"
14 #include "devnum-util.h"
16 #include "errno-util.h"
20 #include "parse-util.h"
21 #include "path-util.h"
22 #include "stat-util.h"
23 #include "string-util.h"
26 typedef enum VerifyESPFlags
{
27 VERIFY_ESP_SEARCHING
= 1 << 0, /* Downgrade various "not found" logs to debug level */
28 VERIFY_ESP_UNPRIVILEGED_MODE
= 1 << 1, /* Call into udev rather than blkid */
29 VERIFY_ESP_RELAX_CHECKS
= 1 << 2, /* Do not validate ESP partition */
32 static int verify_esp_blkid(
38 sd_id128_t
*ret_uuid
) {
40 sd_id128_t uuid
= SD_ID128_NULL
;
41 uint64_t pstart
= 0, psize
= 0;
45 _cleanup_(blkid_free_probep
) blkid_probe b
= NULL
;
46 _cleanup_free_
char *node
= NULL
;
50 r
= devname_from_devnum(S_IFBLK
, devid
, &node
);
52 return log_error_errno(r
, "Failed to get device path for " DEVNUM_FORMAT_STR
": %m", DEVNUM_FORMAT_VAL(devid
));
55 b
= blkid_new_probe_from_filename(node
);
57 return log_error_errno(errno
?: SYNTHETIC_ERRNO(ENOMEM
), "Failed to open file system \"%s\": %m", node
);
59 blkid_probe_enable_superblocks(b
, 1);
60 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
61 blkid_probe_enable_partitions(b
, 1);
62 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
65 r
= blkid_do_safeprobe(b
);
67 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" is ambiguous.", node
);
69 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" does not contain a label.", node
);
71 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe file system \"%s\": %m", node
);
73 r
= blkid_probe_lookup_value(b
, "TYPE", &v
, NULL
);
75 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
76 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
77 "No filesystem found on \"%s\": %m", node
);
78 if (!streq(v
, "vfat"))
79 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
80 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
81 "File system \"%s\" is not FAT.", node
);
83 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
85 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
86 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
87 "File system \"%s\" is not located on a partitioned block device.", node
);
89 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
90 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
91 "File system \"%s\" is not on a GPT partition table.", node
);
94 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
96 return log_error_errno(errno
?: EIO
, "Failed to probe partition type UUID of \"%s\": %m", node
);
97 if (sd_id128_string_equal(v
, SD_GPT_ESP
) <= 0)
98 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
99 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
100 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node
);
103 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
105 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition entry UUID of \"%s\": %m", node
);
106 r
= sd_id128_from_string(v
, &uuid
);
108 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
111 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_NUMBER", &v
, NULL
);
113 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition number of \"%s\": %m", node
);
114 r
= safe_atou32(v
, &part
);
116 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
119 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_OFFSET", &v
, NULL
);
121 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition offset of \"%s\": %m", node
);
122 r
= safe_atou64(v
, &pstart
);
124 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
127 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SIZE", &v
, NULL
);
129 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition size of \"%s\": %m", node
);
130 r
= safe_atou64(v
, &psize
);
132 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
138 *ret_pstart
= pstart
;
147 static int verify_esp_udev(
151 uint64_t *ret_pstart
,
153 sd_id128_t
*ret_uuid
) {
155 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
156 sd_id128_t uuid
= SD_ID128_NULL
;
157 uint64_t pstart
= 0, psize
= 0;
159 const char *node
, *v
;
162 r
= sd_device_new_from_devnum(&d
, 'b', devid
);
164 return log_error_errno(r
, "Failed to get device from device number: %m");
166 r
= sd_device_get_devname(d
, &node
);
168 return log_device_error_errno(d
, r
, "Failed to get device node: %m");
170 r
= sd_device_get_property_value(d
, "ID_FS_TYPE", &v
);
172 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
173 if (!streq(v
, "vfat"))
174 return log_device_full_errno(d
,
175 searching
? LOG_DEBUG
: LOG_ERR
,
176 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
177 "File system \"%s\" is not FAT.", node
);
179 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SCHEME", &v
);
181 return log_device_full_errno(d
,
182 searching
&& r
== -ENOENT
? LOG_DEBUG
: LOG_ERR
,
183 searching
&& r
== -ENOENT
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : r
,
184 "Failed to get device property: %m");
185 if (!streq(v
, "gpt"))
186 return log_device_full_errno(d
,
187 searching
? LOG_DEBUG
: LOG_ERR
,
188 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
189 "File system \"%s\" is not on a GPT partition table.", node
);
191 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
193 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
194 if (sd_id128_string_equal(v
, SD_GPT_ESP
) <= 0)
195 return log_device_full_errno(d
,
196 searching
? LOG_DEBUG
: LOG_ERR
,
197 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
198 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node
);
200 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_UUID", &v
);
202 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
203 r
= sd_id128_from_string(v
, &uuid
);
205 return log_device_error_errno(d
, r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
207 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_NUMBER", &v
);
209 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
210 r
= safe_atou32(v
, &part
);
212 return log_device_error_errno(d
, r
, "Failed to parse PART_ENTRY_NUMBER field.");
214 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_OFFSET", &v
);
216 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
217 r
= safe_atou64(v
, &pstart
);
219 return log_device_error_errno(d
, r
, "Failed to parse PART_ENTRY_OFFSET field.");
221 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SIZE", &v
);
223 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
224 r
= safe_atou64(v
, &psize
);
226 return log_device_error_errno(d
, r
, "Failed to parse PART_ENTRY_SIZE field.");
231 *ret_pstart
= pstart
;
240 static int verify_fsroot_dir(
243 bool unprivileged_mode
,
246 _cleanup_close_
int fd
= -1;
247 STRUCT_NEW_STATX_DEFINE(sxa
);
248 STRUCT_NEW_STATX_DEFINE(sxb
);
251 /* Checks if the specified directory is at the root of its file system, and returns device
252 * major/minor of the device, if it is. */
256 /* We are using O_PATH here, since that way we can operate on directory inodes we cannot look into,
257 * which is quite likely if we run unprivileged */
258 fd
= open(path
, O_CLOEXEC
|O_DIRECTORY
|O_PATH
);
260 return log_full_errno((searching
&& errno
== ENOENT
) ||
261 (unprivileged_mode
&& ERRNO_IS_PRIVILEGE(errno
)) ? LOG_DEBUG
: LOG_ERR
, errno
,
262 "Failed to open directory \"%s\": %m", path
);
264 /* So, the ESP and XBOOTLDR partition are commonly located on an autofs mount. stat() on the
265 * directory won't trigger it, if it is not mounted yet. Let's hence explicitly trigger it here,
266 * before stat()ing */
267 (void) faccessat(fd
, "trigger", F_OK
, AT_SYMLINK_NOFOLLOW
); /* Filename doesn't matter... */
269 r
= statx_fallback(fd
, "", AT_EMPTY_PATH
, STATX_TYPE
|STATX_INO
|STATX_MNT_ID
, &sxa
.sx
);
271 return log_full_errno((unprivileged_mode
&& ERRNO_IS_PRIVILEGE(r
)) ? LOG_DEBUG
: LOG_ERR
, r
,
272 "Failed to determine block device node of \"%s\": %m", path
);
274 assert(S_ISDIR(sxa
.sx
.stx_mode
)); /* We used O_DIRECTORY above, when opening, so this must hold */
276 if (FLAGS_SET(sxa
.sx
.stx_attributes_mask
, STATX_ATTR_MOUNT_ROOT
)) {
278 /* If we have STATX_ATTR_MOUNT_ROOT, we are happy, that's all we need. We operate under the
279 * assumption that a top of a mount point is also the top of the file system. (Which of
280 * course is strictly speaking not always true...) */
282 if (!FLAGS_SET(sxa
.sx
.stx_attributes
, STATX_ATTR_MOUNT_ROOT
))
283 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
284 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
285 "Directory \"%s\" is not the root of the file system.", path
);
290 /* Now let's look at the parent */
291 r
= statx_fallback(fd
, "..", 0, STATX_TYPE
|STATX_INO
|STATX_MNT_ID
, &sxb
.sx
);
292 if (r
< 0 && ERRNO_IS_PRIVILEGE(r
)) {
293 _cleanup_free_
char *parent
= NULL
;
295 /* If going via ".." didn't work due to EACCESS, then let's determine the parent path
296 * directly instead. It's not as good, due to symlinks and such, but we can't do anything
299 * (In case you wonder where this fallback is useful: consider a classic Fedora setup with
300 * /boot/ being an ext4 partition and /boot/efi/ being the VFAT ESP. The latter is mounted
301 * inaccessible for regular users via the dmask= mount option. In that case as unprivileged
302 * user we can stat() /boot/efi/, and we can stat()/enumerate /boot/. But we cannot look into
303 * /boot/efi/, and in particular not use /boot/efi/../ – hence this work-around.) */
305 if (path_equal(path
, "/"))
308 r
= path_extract_directory(path
, &parent
);
310 return log_error_errno(r
, "Failed to extract parent path from '%s': %m", path
);
312 r
= statx_fallback(AT_FDCWD
, parent
, AT_SYMLINK_NOFOLLOW
, STATX_TYPE
|STATX_INO
|STATX_MNT_ID
, &sxb
.sx
);
315 return log_full_errno(unprivileged_mode
&& ERRNO_IS_PRIVILEGE(r
) ? LOG_DEBUG
: LOG_ERR
, r
,
316 "Failed to determine block device node of parent of \"%s\": %m", path
);
318 if (statx_inode_same(&sxa
.sx
, &sxb
.sx
)) /* for the root dir inode nr for both inodes will be the same */
321 if (statx_mount_same(&sxa
.nsx
, &sxb
.nsx
))
322 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
323 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
324 "Directory \"%s\" is not the root of the file system.", path
);
330 if (sxa
.sx
.stx_dev_major
== 0) { /* Hmm, maybe a btrfs device, and the caller asked for the backing device? Then let's try to get it. */
331 _cleanup_close_
int real_fd
= -1;
333 /* The statx() above we can execute on an O_PATH fd. But the btrfs ioctl we cannot. Hence
334 * acquire a "real" fd first, without the O_PATH flag. */
336 real_fd
= fd_reopen(fd
, O_DIRECTORY
|O_CLOEXEC
);
340 return btrfs_get_block_device_fd(real_fd
, ret_dev
);
343 *ret_dev
= makedev(sxa
.sx
.stx_dev_major
, sxa
.sx
.stx_dev_minor
);
347 static int verify_esp(
350 uint64_t *ret_pstart
,
352 sd_id128_t
*ret_uuid
,
354 VerifyESPFlags flags
) {
356 bool relax_checks
, searching
= FLAGS_SET(flags
, VERIFY_ESP_SEARCHING
),
357 unprivileged_mode
= FLAGS_SET(flags
, VERIFY_ESP_UNPRIVILEGED_MODE
);
363 /* This logs about all errors, except:
365 * -ENOENT → if 'searching' is set, and the dir doesn't exist
366 * -EADDRNOTAVAIL → if 'searching' is set, and the dir doesn't look like an ESP
367 * -EACESS → if 'unprivileged_mode' is set, and we have trouble accessing the thing
371 getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0 ||
372 FLAGS_SET(flags
, VERIFY_ESP_RELAX_CHECKS
);
374 /* Non-root user can only check the status, so if an error occurred in the following, it does not cause any
375 * issues. Let's also, silence the error messages. */
380 if (statfs(p
, &sfs
) < 0)
381 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
382 return log_full_errno((searching
&& errno
== ENOENT
) ||
383 (unprivileged_mode
&& errno
== EACCES
) ? LOG_DEBUG
: LOG_ERR
, errno
,
384 "Failed to check file system type of \"%s\": %m", p
);
386 if (!F_TYPE_EQUAL(sfs
.f_type
, MSDOS_SUPER_MAGIC
))
387 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
388 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
389 "File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p
);
394 detect_container() > 0;
396 r
= verify_fsroot_dir(p
, searching
, unprivileged_mode
, relax_checks
? NULL
: &devid
);
400 /* In a container we don't have access to block devices, skip this part of the verification, we trust
401 * the container manager set everything up correctly on its own. */
405 /* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
406 * use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
407 * emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
408 * however blkid can't work if we have no privileges to access block devices directly, which is why
409 * we use udev in that case. */
410 if (unprivileged_mode
)
411 r
= verify_esp_udev(devid
, searching
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
413 r
= verify_esp_blkid(devid
, searching
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
430 *ret_uuid
= SD_ID128_NULL
;
437 int find_esp_and_warn(
440 bool unprivileged_mode
,
443 uint64_t *ret_pstart
,
445 sd_id128_t
*ret_uuid
,
448 VerifyESPFlags flags
= (unprivileged_mode
? VERIFY_ESP_UNPRIVILEGED_MODE
: 0) |
449 (root
? VERIFY_ESP_RELAX_CHECKS
: 0);
450 _cleanup_free_
char *p
= NULL
;
453 /* This logs about all errors except:
455 * -ENOKEY → when we can't find the partition
456 * -EACCESS → when unprivileged_mode is true, and we can't access something
460 r
= chase_symlinks(path
, root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
462 return log_error_errno(r
,
463 "Failed to resolve path %s%s%s: %m",
465 root
? " under directory " : "",
468 r
= verify_esp(p
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
, ret_devid
, flags
);
475 path
= getenv("SYSTEMD_ESP_PATH");
479 r
= chase_symlinks(path
, root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
481 return log_error_errno(r
,
482 "Failed to resolve path %s%s%s: %m",
484 root
? " under directory " : "",
487 if (!path_is_valid(p
) || !path_is_absolute(p
))
488 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
489 "$SYSTEMD_ESP_PATH does not refer to absolute path, refusing to use it: %s",
492 /* Note: when the user explicitly configured things with an env var we won't validate the
493 * path beyond checking it refers to a directory. After all we want this to be useful for
496 if (stat(p
, &st
) < 0)
497 return log_error_errno(errno
, "Failed to stat '%s': %m", p
);
498 if (!S_ISDIR(st
.st_mode
))
499 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR
), "ESP path '%s' is not a directory.", p
);
508 *ret_uuid
= SD_ID128_NULL
;
510 *ret_devid
= st
.st_dev
;
515 FOREACH_STRING(dir
, "/efi", "/boot", "/boot/efi") {
516 r
= chase_symlinks(dir
, root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
520 return log_error_errno(r
,
521 "Failed to resolve path %s%s%s: %m",
523 root
? " under directory " : "",
526 r
= verify_esp(p
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
, ret_devid
,
527 flags
| VERIFY_ESP_SEARCHING
);
530 if (!IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
, -ENOTDIR
)) /* This one is not it */
536 /* No logging here */
541 *ret_path
= TAKE_PTR(p
);
546 static int verify_xbootldr_blkid(
549 sd_id128_t
*ret_uuid
) {
551 sd_id128_t uuid
= SD_ID128_NULL
;
554 _cleanup_(blkid_free_probep
) blkid_probe b
= NULL
;
555 _cleanup_free_
char *node
= NULL
;
556 const char *type
, *v
;
559 r
= devname_from_devnum(S_IFBLK
, devid
, &node
);
561 return log_error_errno(r
, "Failed to get block device path for " DEVNUM_FORMAT_STR
": %m",
562 DEVNUM_FORMAT_VAL(devid
));
565 b
= blkid_new_probe_from_filename(node
);
567 return log_error_errno(errno
?: SYNTHETIC_ERRNO(ENOMEM
), "%s: Failed to create blkid probe: %m", node
);
569 blkid_probe_enable_partitions(b
, 1);
570 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
573 r
= blkid_do_safeprobe(b
);
575 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "%s: File system is ambiguous.", node
);
577 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "%s: File system does not contain a label.", node
);
579 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "%s: Failed to probe file system: %m", node
);
581 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &type
, NULL
);
583 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
584 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(EIO
),
585 "%s: Failed to probe PART_ENTRY_SCHEME: %m", node
);
586 if (streq(type
, "gpt")) {
589 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
591 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "%s: Failed to probe PART_ENTRY_TYPE: %m", node
);
592 if (sd_id128_string_equal(v
, SD_GPT_XBOOTLDR
) <= 0)
593 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
594 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
595 "%s: Partitition has wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node
, v
);
598 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
600 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "%s: Failed to probe PART_ENTRY_UUID: %m", node
);
601 r
= sd_id128_from_string(v
, &uuid
);
603 return log_error_errno(r
, "%s: Partition has invalid UUID PART_ENTRY_TYPE=%s: %m", node
, v
);
605 } else if (streq(type
, "dos")) {
608 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
610 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "%s: Failed to probe PART_ENTRY_TYPE: %m", node
);
611 if (!streq(v
, "0xea"))
612 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
613 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
614 "%s: Wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node
, v
);
617 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
618 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
619 "%s: Not on a GPT or DOS partition table (PART_ENTRY_SCHEME=%s).", node
, type
);
628 static int verify_xbootldr_udev(
631 sd_id128_t
*ret_uuid
) {
633 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
634 sd_id128_t uuid
= SD_ID128_NULL
;
635 const char *node
, *type
, *v
;
638 r
= sd_device_new_from_devnum(&d
, 'b', devid
);
640 return log_error_errno(r
, "Failed to get block device for " DEVNUM_FORMAT_STR
": %m", DEVNUM_FORMAT_VAL(devid
));
642 r
= sd_device_get_devname(d
, &node
);
644 return log_device_error_errno(d
, r
, "Failed to get device node: %m");
646 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SCHEME", &type
);
648 return log_device_full_errno(d
,
649 searching
&& r
== -ENOENT
? LOG_DEBUG
: LOG_ERR
,
650 searching
&& r
== -ENOENT
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : r
,
651 "Failed to query ID_PART_ENTRY_SCHEME: %m");
653 if (streq(type
, "gpt")) {
655 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
657 return log_device_error_errno(d
, r
, "Failed to query ID_PART_ENTRY_TYPE: %m");
659 r
= sd_id128_string_equal(v
, SD_GPT_XBOOTLDR
);
661 return log_device_error_errno(d
, r
, "Failed to parse ID_PART_ENTRY_TYPE=%s: %m", v
);
663 return log_device_full_errno(
665 searching
? LOG_DEBUG
: LOG_ERR
,
666 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
667 "Partition has wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v
);
669 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_UUID", &v
);
671 return log_device_error_errno(d
, r
, "Failed to query ID_PART_ENTRY_UUID: %m");
672 r
= sd_id128_from_string(v
, &uuid
);
674 return log_device_error_errno(d
, r
, "Partition has invalid UUID ID_PART_ENTRY_TYPE=%s: %m", v
);
676 } else if (streq(type
, "dos")) {
678 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
680 return log_device_error_errno(d
, r
, "Failed to query ID_PART_ENTRY_TYPE: %m");
681 if (!streq(v
, "0xea"))
682 return log_device_full_errno(
684 searching
? LOG_DEBUG
: LOG_ERR
,
685 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
686 "Wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v
);
689 return log_device_full_errno(
691 searching
? LOG_DEBUG
: LOG_ERR
,
692 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
693 "Not on a GPT or DOS partition table (ID_PART_ENTRY_SCHEME=%s).", type
);
701 static int verify_xbootldr(
704 bool unprivileged_mode
,
705 sd_id128_t
*ret_uuid
,
715 getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0 ||
716 detect_container() > 0;
718 r
= verify_fsroot_dir(p
, searching
, unprivileged_mode
, relax_checks
? NULL
: &devid
);
725 if (unprivileged_mode
)
726 r
= verify_xbootldr_udev(devid
, searching
, ret_uuid
);
728 r
= verify_xbootldr_blkid(devid
, searching
, ret_uuid
);
739 *ret_uuid
= SD_ID128_NULL
;
746 int find_xbootldr_and_warn(
749 bool unprivileged_mode
,
751 sd_id128_t
*ret_uuid
,
754 _cleanup_free_
char *p
= NULL
;
757 /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
760 r
= chase_symlinks(path
, root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
762 return log_error_errno(r
,
763 "Failed to resolve path %s%s%s: %m",
765 root
? " under directory " : "",
768 r
= verify_xbootldr(p
, /* searching= */ false, unprivileged_mode
, ret_uuid
, ret_devid
);
775 path
= getenv("SYSTEMD_XBOOTLDR_PATH");
779 r
= chase_symlinks(path
, root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
781 return log_error_errno(r
,
782 "Failed to resolve path %s%s%s: %m",
784 root
? " under directory " : "",
787 if (!path_is_valid(p
) || !path_is_absolute(p
))
788 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
789 "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s",
792 if (stat(p
, &st
) < 0)
793 return log_error_errno(errno
, "Failed to stat '%s': %m", p
);
794 if (!S_ISDIR(st
.st_mode
))
795 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR
), "XBOOTLDR path '%s' is not a directory.", p
);
798 *ret_uuid
= SD_ID128_NULL
;
800 *ret_devid
= st
.st_dev
;
805 r
= chase_symlinks("/boot", root
, CHASE_PREFIX_ROOT
, &p
, NULL
);
809 return log_error_errno(r
,
810 "Failed to resolve path /boot%s%s: %m",
811 root
? " under directory " : "",
814 r
= verify_xbootldr(p
, /* searching= */ true, unprivileged_mode
, ret_uuid
, ret_devid
);
817 if (!IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
, -ENOTDIR
)) /* This one is not it */
824 *ret_path
= TAKE_PTR(p
);