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"
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
;
47 bool searching
= FLAGS_SET(flags
, VERIFY_ESP_SEARCHING
);
51 r
= devname_from_devnum(S_IFBLK
, devid
, &node
);
53 return log_error_errno(r
, "Failed to get device path for " DEVNUM_FORMAT_STR
": %m", DEVNUM_FORMAT_VAL(devid
));
56 b
= blkid_new_probe_from_filename(node
);
58 return log_error_errno(errno
?: SYNTHETIC_ERRNO(ENOMEM
), "Failed to open file system \"%s\": %m", node
);
60 blkid_probe_enable_superblocks(b
, 1);
61 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
62 blkid_probe_enable_partitions(b
, 1);
63 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
66 r
= blkid_do_safeprobe(b
);
68 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" is ambiguous.", node
);
70 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" does not contain a label.", node
);
72 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe file system \"%s\": %m", node
);
74 r
= blkid_probe_lookup_value(b
, "TYPE", &v
, NULL
);
76 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
77 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
78 "No filesystem found on \"%s\": %m", node
);
79 if (!streq(v
, "vfat"))
80 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
81 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
82 "File system \"%s\" is not FAT.", node
);
84 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
86 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
87 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
88 "File system \"%s\" is not located on a partitioned block device.", node
);
90 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
91 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
92 "File system \"%s\" is not on a GPT partition table.", node
);
95 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
97 return log_error_errno(errno
?: EIO
, "Failed to probe partition type UUID of \"%s\": %m", node
);
98 if (sd_id128_string_equal(v
, SD_GPT_ESP
) <= 0)
99 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
100 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
101 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node
);
104 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
106 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition entry UUID of \"%s\": %m", node
);
107 r
= sd_id128_from_string(v
, &uuid
);
109 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
112 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_NUMBER", &v
, NULL
);
114 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition number of \"%s\": %m", node
);
115 r
= safe_atou32(v
, &part
);
117 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
120 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_OFFSET", &v
, NULL
);
122 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition offset of \"%s\": %m", node
);
123 r
= safe_atou64(v
, &pstart
);
125 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
128 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SIZE", &v
, NULL
);
130 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition size of \"%s\": %m", node
);
131 r
= safe_atou64(v
, &psize
);
133 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
139 *ret_pstart
= pstart
;
148 static int verify_esp_udev(
150 VerifyESPFlags flags
,
152 uint64_t *ret_pstart
,
154 sd_id128_t
*ret_uuid
) {
156 bool searching
= FLAGS_SET(flags
, VERIFY_ESP_SEARCHING
);
157 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
158 sd_id128_t uuid
= SD_ID128_NULL
;
159 uint64_t pstart
= 0, psize
= 0;
161 const char *node
, *v
;
164 r
= sd_device_new_from_devnum(&d
, 'b', devid
);
166 return log_error_errno(r
, "Failed to get device from device number: %m");
168 r
= sd_device_get_devname(d
, &node
);
170 return log_device_error_errno(d
, r
, "Failed to get device node: %m");
172 r
= sd_device_get_property_value(d
, "ID_FS_TYPE", &v
);
174 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
175 if (!streq(v
, "vfat"))
176 return log_device_full_errno(d
,
177 searching
? LOG_DEBUG
: LOG_ERR
,
178 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
179 "File system \"%s\" is not FAT.", node
);
181 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SCHEME", &v
);
183 return log_device_full_errno(d
,
184 searching
&& r
== -ENOENT
? LOG_DEBUG
: LOG_ERR
,
185 searching
&& r
== -ENOENT
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : r
,
186 "Failed to get device property: %m");
187 if (!streq(v
, "gpt"))
188 return log_device_full_errno(d
,
189 searching
? LOG_DEBUG
: LOG_ERR
,
190 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
191 "File system \"%s\" is not on a GPT partition table.", node
);
193 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
195 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
196 if (sd_id128_string_equal(v
, SD_GPT_ESP
) <= 0)
197 return log_device_full_errno(d
,
198 searching
? LOG_DEBUG
: LOG_ERR
,
199 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
200 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node
);
202 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_UUID", &v
);
204 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
205 r
= sd_id128_from_string(v
, &uuid
);
207 return log_device_error_errno(d
, r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
209 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_NUMBER", &v
);
211 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
212 r
= safe_atou32(v
, &part
);
214 return log_device_error_errno(d
, r
, "Failed to parse PART_ENTRY_NUMBER field.");
216 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_OFFSET", &v
);
218 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
219 r
= safe_atou64(v
, &pstart
);
221 return log_device_error_errno(d
, r
, "Failed to parse PART_ENTRY_OFFSET field.");
223 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SIZE", &v
);
225 return log_device_error_errno(d
, r
, "Failed to get device property: %m");
226 r
= safe_atou64(v
, &psize
);
228 return log_device_error_errno(d
, r
, "Failed to parse PART_ENTRY_SIZE field.");
233 *ret_pstart
= pstart
;
242 static int verify_fsroot_dir(
245 VerifyESPFlags flags
,
248 bool searching
= FLAGS_SET(flags
, VERIFY_ESP_SEARCHING
),
249 unprivileged_mode
= FLAGS_SET(flags
, VERIFY_ESP_UNPRIVILEGED_MODE
);
250 _cleanup_free_
char *f
= NULL
;
251 STRUCT_NEW_STATX_DEFINE(sxa
);
252 STRUCT_NEW_STATX_DEFINE(sxb
);
255 /* Checks if the specified directory is at the root of its file system, and returns device
256 * major/minor of the device, if it is. */
261 /* We pass the full path from the root directory file descriptor so we can use it for logging, but
262 * dir_fd points to the parent directory of the final component of the given path, so we extract the
263 * filename and operate on that. */
265 r
= path_extract_filename(path
, &f
);
266 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
267 return log_error_errno(r
, "Failed to extract filename of %s: %m", path
);
269 r
= statx_fallback(dir_fd
, strempty(f
), AT_SYMLINK_NOFOLLOW
|(isempty(f
) ? AT_EMPTY_PATH
: 0),
270 STATX_TYPE
|STATX_INO
|STATX_MNT_ID
, &sxa
.sx
);
272 return log_full_errno((searching
&& r
== -ENOENT
) ||
273 (unprivileged_mode
&& ERRNO_IS_PRIVILEGE(r
)) ? LOG_DEBUG
: LOG_ERR
, r
,
274 "Failed to determine block device node of \"%s\": %m", path
);
276 assert(S_ISDIR(sxa
.sx
.stx_mode
)); /* We used O_DIRECTORY above, when opening, so this must hold */
278 if (FLAGS_SET(sxa
.sx
.stx_attributes_mask
, STATX_ATTR_MOUNT_ROOT
)) {
280 /* If we have STATX_ATTR_MOUNT_ROOT, we are happy, that's all we need. We operate under the
281 * assumption that a top of a mount point is also the top of the file system. (Which of
282 * course is strictly speaking not always true...) */
284 if (!FLAGS_SET(sxa
.sx
.stx_attributes
, STATX_ATTR_MOUNT_ROOT
))
285 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
286 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
287 "Directory \"%s\" is not the root of the file system.", path
);
292 /* Now let's look at the parent */
293 r
= statx_fallback(dir_fd
, "", AT_EMPTY_PATH
, STATX_TYPE
|STATX_INO
|STATX_MNT_ID
, &sxb
.sx
);
295 return log_full_errno(unprivileged_mode
&& ERRNO_IS_PRIVILEGE(r
) ? LOG_DEBUG
: LOG_ERR
, r
,
296 "Failed to determine block device node of parent of \"%s\": %m", path
);
298 if (statx_inode_same(&sxa
.sx
, &sxb
.sx
)) /* for the root dir inode nr for both inodes will be the same */
301 if (statx_mount_same(&sxa
.nsx
, &sxb
.nsx
))
302 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
303 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
304 "Directory \"%s\" is not the root of the file system.", path
);
310 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. */
311 return btrfs_get_block_device_at(dir_fd
, strempty(f
), ret_dev
);
313 *ret_dev
= makedev(sxa
.sx
.stx_dev_major
, sxa
.sx
.stx_dev_minor
);
317 static int verify_esp(
322 uint64_t *ret_pstart
,
324 sd_id128_t
*ret_uuid
,
326 VerifyESPFlags flags
) {
328 bool relax_checks
, searching
= FLAGS_SET(flags
, VERIFY_ESP_SEARCHING
),
329 unprivileged_mode
= FLAGS_SET(flags
, VERIFY_ESP_UNPRIVILEGED_MODE
);
330 _cleanup_free_
char *p
= NULL
;
331 _cleanup_close_
int pfd
= -EBADF
;
335 assert(rfd
>= 0 || rfd
== AT_FDCWD
);
338 /* This logs about all errors, except:
340 * -ENOENT → if 'searching' is set, and the dir doesn't exist
341 * -EADDRNOTAVAIL → if 'searching' is set, and the dir doesn't look like an ESP
342 * -EACESS → if 'unprivileged_mode' is set, and we have trouble accessing the thing
346 getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0 ||
347 FLAGS_SET(flags
, VERIFY_ESP_RELAX_CHECKS
);
349 /* Non-root user can only check the status, so if an error occurred in the following, it does not cause any
350 * issues. Let's also, silence the error messages. */
352 r
= chaseat(rfd
, path
, CHASE_AT_RESOLVE_IN_ROOT
|CHASE_PARENT
, &p
, &pfd
);
354 return log_full_errno((searching
&& r
== -ENOENT
) ||
355 (unprivileged_mode
&& ERRNO_IS_PRIVILEGE(r
)) ? LOG_DEBUG
: LOG_ERR
,
356 r
, "Failed to open parent directory of \"%s\": %m", path
);
359 _cleanup_free_
char *f
= NULL
;
362 r
= path_extract_filename(p
, &f
);
363 if (r
< 0 && r
!= -EADDRNOTAVAIL
)
364 return log_error_errno(r
, "Failed to extract filename of %s: %m", p
);
366 r
= xstatfsat(pfd
, strempty(f
), &sfs
);
368 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
369 return log_full_errno((searching
&& r
== -ENOENT
) ||
370 (unprivileged_mode
&& r
== -EACCES
) ? LOG_DEBUG
: LOG_ERR
, r
,
371 "Failed to check file system type of \"%s\": %m", p
);
373 if (!F_TYPE_EQUAL(sfs
.f_type
, MSDOS_SUPER_MAGIC
))
374 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
375 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
376 "File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p
);
381 detect_container() > 0;
383 r
= verify_fsroot_dir(pfd
, p
, flags
, relax_checks
? NULL
: &devid
);
387 /* In a container we don't have access to block devices, skip this part of the verification, we trust
388 * the container manager set everything up correctly on its own. */
392 /* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
393 * use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
394 * emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
395 * however blkid can't work if we have no privileges to access block devices directly, which is why
396 * we use udev in that case. */
397 if (unprivileged_mode
)
398 r
= verify_esp_udev(devid
, flags
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
400 r
= verify_esp_blkid(devid
, flags
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
405 *ret_path
= TAKE_PTR(p
);
413 *ret_path
= TAKE_PTR(p
);
421 *ret_uuid
= SD_ID128_NULL
;
428 int find_esp_and_warn_at(
431 int unprivileged_mode
,
434 uint64_t *ret_pstart
,
436 sd_id128_t
*ret_uuid
,
439 VerifyESPFlags flags
;
442 /* This logs about all errors except:
444 * -ENOKEY → when we can't find the partition
445 * -EACCESS → when unprivileged_mode is true, and we can't access something
448 assert(rfd
>= 0 || rfd
== AT_FDCWD
);
450 if (unprivileged_mode
< 0)
451 unprivileged_mode
= geteuid() != 0;
452 flags
= unprivileged_mode
> 0 ? VERIFY_ESP_UNPRIVILEGED_MODE
: 0;
454 r
= dir_fd_is_root_or_cwd(rfd
);
456 return log_error_errno(r
, "Failed to check if directory file descriptor is root: %m");
458 flags
|= VERIFY_ESP_RELAX_CHECKS
;
461 return verify_esp(rfd
, path
, ret_path
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
, ret_devid
, flags
);
463 path
= getenv("SYSTEMD_ESP_PATH");
465 _cleanup_free_
char *p
= NULL
;
466 _cleanup_close_
int fd
= -EBADF
;
469 if (!path_is_valid(path
) || !path_is_absolute(path
))
470 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
471 "$SYSTEMD_ESP_PATH does not refer to an absolute path, refusing to use it: %s",
474 r
= chaseat(rfd
, path
, CHASE_AT_RESOLVE_IN_ROOT
, &p
, &fd
);
476 return log_error_errno(r
, "Failed to resolve path %s: %m", path
);
478 /* Note: when the user explicitly configured things with an env var we won't validate the
479 * path beyond checking it refers to a directory. After all we want this to be useful for
482 if (fstat(fd
, &st
) < 0)
483 return log_error_errno(errno
, "Failed to stat '%s': %m", p
);
484 if (!S_ISDIR(st
.st_mode
))
485 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR
), "ESP path '%s' is not a directory.", p
);
488 *ret_path
= TAKE_PTR(p
);
496 *ret_uuid
= SD_ID128_NULL
;
498 *ret_devid
= st
.st_dev
;
503 FOREACH_STRING(dir
, "/efi", "/boot", "/boot/efi") {
504 r
= verify_esp(rfd
, dir
, ret_path
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
, ret_devid
,
505 flags
| VERIFY_ESP_SEARCHING
);
508 if (!IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
, -ENOTDIR
, -ENOTTY
)) /* This one is not it */
512 /* No logging here */
516 int find_esp_and_warn(
519 int unprivileged_mode
,
522 uint64_t *ret_pstart
,
524 sd_id128_t
*ret_uuid
,
527 _cleanup_close_
int rfd
= -EBADF
;
528 _cleanup_free_
char *p
= NULL
;
530 uint64_t pstart
, psize
;
535 rfd
= open(empty_to_root(root
), O_PATH
|O_DIRECTORY
|O_CLOEXEC
);
539 r
= find_esp_and_warn_at(rfd
, path
, unprivileged_mode
,
540 ret_path
? &p
: NULL
,
541 ret_part
? &part
: NULL
,
542 ret_pstart
? &pstart
: NULL
,
543 ret_psize
? &psize
: NULL
,
544 ret_uuid
? &uuid
: NULL
,
545 ret_devid
? &devid
: NULL
);
550 r
= chaseat_prefix_root(p
, root
, ret_path
);
557 *ret_pstart
= pstart
;
568 static int verify_xbootldr_blkid(
570 VerifyESPFlags flags
,
571 sd_id128_t
*ret_uuid
) {
573 sd_id128_t uuid
= SD_ID128_NULL
;
576 bool searching
= FLAGS_SET(flags
, VERIFY_ESP_SEARCHING
);
577 _cleanup_(blkid_free_probep
) blkid_probe b
= NULL
;
578 _cleanup_free_
char *node
= NULL
;
579 const char *type
, *v
;
582 r
= devname_from_devnum(S_IFBLK
, devid
, &node
);
584 return log_error_errno(r
, "Failed to get block device path for " DEVNUM_FORMAT_STR
": %m",
585 DEVNUM_FORMAT_VAL(devid
));
588 b
= blkid_new_probe_from_filename(node
);
590 return log_error_errno(errno_or_else(ENOMEM
), "%s: Failed to create blkid probe: %m", node
);
592 blkid_probe_enable_partitions(b
, 1);
593 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
596 r
= blkid_do_safeprobe(b
);
597 if (r
== _BLKID_SAFEPROBE_AMBIGUOUS
)
598 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "%s: File system is ambiguous.", node
);
599 if (r
== _BLKID_SAFEPROBE_NOT_FOUND
)
600 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "%s: File system does not contain a label.", node
);
601 if (r
== _BLKID_SAFEPROBE_ERROR
)
602 return log_error_errno(errno_or_else(EIO
), "%s: Failed to probe file system: %m", node
);
604 assert(r
== _BLKID_SAFEPROBE_FOUND
);
606 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &type
, NULL
);
608 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
609 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(EIO
),
610 "%s: Failed to probe PART_ENTRY_SCHEME: %m", node
);
611 if (streq(type
, "gpt")) {
614 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
616 return log_error_errno(errno_or_else(EIO
), "%s: Failed to probe PART_ENTRY_TYPE: %m", node
);
617 if (sd_id128_string_equal(v
, SD_GPT_XBOOTLDR
) <= 0)
618 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
619 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
620 "%s: Partitition has wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node
, v
);
623 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
625 return log_error_errno(errno_or_else(EIO
), "%s: Failed to probe PART_ENTRY_UUID: %m", node
);
626 r
= sd_id128_from_string(v
, &uuid
);
628 return log_error_errno(r
, "%s: Partition has invalid UUID PART_ENTRY_TYPE=%s: %m", node
, v
);
630 } else if (streq(type
, "dos")) {
633 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
635 return log_error_errno(errno_or_else(EIO
), "%s: Failed to probe PART_ENTRY_TYPE: %m", node
);
636 if (!streq(v
, "0xea"))
637 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
638 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
639 "%s: Wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node
, v
);
642 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
643 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
644 "%s: Not on a GPT or DOS partition table (PART_ENTRY_SCHEME=%s).", node
, type
);
653 static int verify_xbootldr_udev(
655 VerifyESPFlags flags
,
656 sd_id128_t
*ret_uuid
) {
658 bool searching
= FLAGS_SET(flags
, VERIFY_ESP_SEARCHING
);
659 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
660 sd_id128_t uuid
= SD_ID128_NULL
;
661 const char *node
, *type
, *v
;
664 r
= sd_device_new_from_devnum(&d
, 'b', devid
);
666 return log_error_errno(r
, "Failed to get block device for " DEVNUM_FORMAT_STR
": %m", DEVNUM_FORMAT_VAL(devid
));
668 r
= sd_device_get_devname(d
, &node
);
670 return log_device_error_errno(d
, r
, "Failed to get device node: %m");
672 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SCHEME", &type
);
674 return log_device_full_errno(d
,
675 searching
&& r
== -ENOENT
? LOG_DEBUG
: LOG_ERR
,
676 searching
&& r
== -ENOENT
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : r
,
677 "Failed to query ID_PART_ENTRY_SCHEME: %m");
679 if (streq(type
, "gpt")) {
681 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
683 return log_device_error_errno(d
, r
, "Failed to query ID_PART_ENTRY_TYPE: %m");
685 r
= sd_id128_string_equal(v
, SD_GPT_XBOOTLDR
);
687 return log_device_error_errno(d
, r
, "Failed to parse ID_PART_ENTRY_TYPE=%s: %m", v
);
689 return log_device_full_errno(
691 searching
? LOG_DEBUG
: LOG_ERR
,
692 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
693 "Partition has wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v
);
695 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_UUID", &v
);
697 return log_device_error_errno(d
, r
, "Failed to query ID_PART_ENTRY_UUID: %m");
698 r
= sd_id128_from_string(v
, &uuid
);
700 return log_device_error_errno(d
, r
, "Partition has invalid UUID ID_PART_ENTRY_TYPE=%s: %m", v
);
702 } else if (streq(type
, "dos")) {
704 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
706 return log_device_error_errno(d
, r
, "Failed to query ID_PART_ENTRY_TYPE: %m");
707 if (!streq(v
, "0xea"))
708 return log_device_full_errno(
710 searching
? LOG_DEBUG
: LOG_ERR
,
711 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
712 "Wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v
);
715 return log_device_full_errno(
717 searching
? LOG_DEBUG
: LOG_ERR
,
718 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
719 "Not on a GPT or DOS partition table (ID_PART_ENTRY_SCHEME=%s).", type
);
727 static int verify_xbootldr(
730 VerifyESPFlags flags
,
732 sd_id128_t
*ret_uuid
,
735 _cleanup_free_
char *p
= NULL
;
736 _cleanup_close_
int pfd
= -EBADF
;
737 bool searching
= FLAGS_SET(flags
, VERIFY_ESP_SEARCHING
),
738 unprivileged_mode
= FLAGS_SET(flags
, VERIFY_ESP_UNPRIVILEGED_MODE
),
743 assert(rfd
>= 0 || rfd
== AT_FDCWD
);
746 r
= chaseat(rfd
, path
, CHASE_AT_RESOLVE_IN_ROOT
|CHASE_PARENT
, &p
, &pfd
);
748 return log_full_errno((searching
&& r
== -ENOENT
) ||
749 (unprivileged_mode
&& ERRNO_IS_PRIVILEGE(r
)) ? LOG_DEBUG
: LOG_ERR
,
750 r
, "Failed to open parent directory of \"%s\": %m", path
);
753 getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0 ||
754 detect_container() > 0;
756 r
= verify_fsroot_dir(pfd
, p
, flags
, relax_checks
? NULL
: &devid
);
763 if (unprivileged_mode
)
764 r
= verify_xbootldr_udev(devid
, flags
, ret_uuid
);
766 r
= verify_xbootldr_blkid(devid
, flags
, ret_uuid
);
771 *ret_path
= TAKE_PTR(p
);
779 *ret_path
= TAKE_PTR(p
);
781 *ret_uuid
= SD_ID128_NULL
;
788 int find_xbootldr_and_warn_at(
791 int unprivileged_mode
,
793 sd_id128_t
*ret_uuid
,
796 VerifyESPFlags flags
= 0;
799 /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
801 assert(rfd
>= 0 || rfd
== AT_FDCWD
);
803 if (unprivileged_mode
< 0)
804 unprivileged_mode
= geteuid() != 0;
805 if (unprivileged_mode
)
806 flags
|= VERIFY_ESP_UNPRIVILEGED_MODE
;
809 return verify_xbootldr(rfd
, path
, flags
, ret_path
, ret_uuid
, ret_devid
);
811 path
= getenv("SYSTEMD_XBOOTLDR_PATH");
813 _cleanup_free_
char *p
= NULL
;
814 _cleanup_close_
int fd
= -EBADF
;
817 if (!path_is_valid(path
) || !path_is_absolute(path
))
818 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
819 "$SYSTEMD_XBOOTLDR_PATH does not refer to an absolute path, refusing to use it: %s",
822 r
= chaseat(rfd
, path
, CHASE_AT_RESOLVE_IN_ROOT
, &p
, &fd
);
824 return log_error_errno(r
, "Failed to resolve path %s: %m", p
);
826 if (fstat(fd
, &st
) < 0)
827 return log_error_errno(errno
, "Failed to stat '%s': %m", p
);
828 if (!S_ISDIR(st
.st_mode
))
829 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR
), "XBOOTLDR path '%s' is not a directory.", p
);
832 *ret_path
= TAKE_PTR(p
);
834 *ret_uuid
= SD_ID128_NULL
;
836 *ret_devid
= st
.st_dev
;
841 r
= verify_xbootldr(rfd
, "/boot", flags
| VERIFY_ESP_SEARCHING
, ret_path
, ret_uuid
, ret_devid
);
843 if (!IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
, -ENOTDIR
, -ENOTTY
)) /* This one is not it */
852 int find_xbootldr_and_warn(
855 int unprivileged_mode
,
857 sd_id128_t
*ret_uuid
,
860 _cleanup_close_
int rfd
= -EBADF
;
861 _cleanup_free_
char *p
= NULL
;
866 rfd
= open(empty_to_root(root
), O_PATH
|O_DIRECTORY
|O_CLOEXEC
);
870 r
= find_xbootldr_and_warn_at(rfd
, path
, unprivileged_mode
,
871 ret_path
? &p
: NULL
,
872 ret_uuid
? &uuid
: NULL
,
873 ret_devid
? &devid
: NULL
);
878 r
= chaseat_prefix_root(p
, root
, ret_path
);