1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/magic.h>
7 #include "alloc-util.h"
8 #include "blkid-util.h"
10 #include "errno-util.h"
13 #include "id128-util.h"
14 #include "parse-util.h"
15 #include "path-util.h"
16 #include "stat-util.h"
17 #include "string-util.h"
20 static int verify_esp_blkid(
26 sd_id128_t
*ret_uuid
) {
28 sd_id128_t uuid
= SD_ID128_NULL
;
29 uint64_t pstart
= 0, psize
= 0;
33 _cleanup_(blkid_free_probep
) blkid_probe b
= NULL
;
34 _cleanup_free_
char *node
= NULL
;
38 r
= device_path_make_major_minor(S_IFBLK
, devid
, &node
);
40 return log_error_errno(r
, "Failed to format major/minor device path: %m");
43 b
= blkid_new_probe_from_filename(node
);
45 return log_error_errno(errno
?: SYNTHETIC_ERRNO(ENOMEM
), "Failed to open file system \"%s\": %m", node
);
47 blkid_probe_enable_superblocks(b
, 1);
48 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
49 blkid_probe_enable_partitions(b
, 1);
50 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
53 r
= blkid_do_safeprobe(b
);
55 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" is ambiguous.", node
);
57 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" does not contain a label.", node
);
59 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe file system \"%s\": %m", node
);
61 r
= blkid_probe_lookup_value(b
, "TYPE", &v
, NULL
);
63 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
64 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
65 "No filesystem found on \"%s\": %m", node
);
66 if (!streq(v
, "vfat"))
67 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
68 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
69 "File system \"%s\" is not FAT.", node
);
71 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
73 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
74 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
75 "File system \"%s\" is not located on a partitioned block device.", node
);
77 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
78 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
79 "File system \"%s\" is not on a GPT partition table.", node
);
82 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
84 return log_error_errno(errno
?: EIO
, "Failed to probe partition type UUID of \"%s\": %m", node
);
85 if (id128_equal_string(v
, GPT_ESP
) <= 0)
86 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
87 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
88 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node
);
91 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
93 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition entry UUID of \"%s\": %m", node
);
94 r
= sd_id128_from_string(v
, &uuid
);
96 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
99 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_NUMBER", &v
, NULL
);
101 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition number of \"%s\": %m", node
);
102 r
= safe_atou32(v
, &part
);
104 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
107 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_OFFSET", &v
, NULL
);
109 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition offset of \"%s\": %m", node
);
110 r
= safe_atou64(v
, &pstart
);
112 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
115 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SIZE", &v
, NULL
);
117 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition size of \"%s\": %m", node
);
118 r
= safe_atou64(v
, &psize
);
120 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
126 *ret_pstart
= pstart
;
135 static int verify_esp_udev(
139 uint64_t *ret_pstart
,
141 sd_id128_t
*ret_uuid
) {
143 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
144 _cleanup_free_
char *node
= NULL
;
145 sd_id128_t uuid
= SD_ID128_NULL
;
146 uint64_t pstart
= 0, psize
= 0;
151 r
= device_path_make_major_minor(S_IFBLK
, devid
, &node
);
153 return log_error_errno(r
, "Failed to format major/minor device path: %m");
155 r
= sd_device_new_from_devnum(&d
, 'b', devid
);
157 return log_error_errno(r
, "Failed to get device from device number: %m");
159 r
= sd_device_get_property_value(d
, "ID_FS_TYPE", &v
);
161 return log_error_errno(r
, "Failed to get device property: %m");
162 if (!streq(v
, "vfat"))
163 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
164 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
165 "File system \"%s\" is not FAT.", node
);
167 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SCHEME", &v
);
169 return log_error_errno(r
, "Failed to get device property: %m");
170 if (!streq(v
, "gpt"))
171 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
172 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
173 "File system \"%s\" is not on a GPT partition table.", node
);
175 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
177 return log_error_errno(r
, "Failed to get device property: %m");
178 if (id128_equal_string(v
, GPT_ESP
) <= 0)
179 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
180 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
181 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node
);
183 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_UUID", &v
);
185 return log_error_errno(r
, "Failed to get device property: %m");
186 r
= sd_id128_from_string(v
, &uuid
);
188 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
190 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_NUMBER", &v
);
192 return log_error_errno(r
, "Failed to get device property: %m");
193 r
= safe_atou32(v
, &part
);
195 return log_error_errno(r
, "Failed to parse PART_ENTRY_NUMBER field.");
197 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_OFFSET", &v
);
199 return log_error_errno(r
, "Failed to get device property: %m");
200 r
= safe_atou64(v
, &pstart
);
202 return log_error_errno(r
, "Failed to parse PART_ENTRY_OFFSET field.");
204 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SIZE", &v
);
206 return log_error_errno(r
, "Failed to get device property: %m");
207 r
= safe_atou64(v
, &psize
);
209 return log_error_errno(r
, "Failed to parse PART_ENTRY_SIZE field.");
214 *ret_pstart
= pstart
;
223 static int verify_fsroot_dir(
226 bool unprivileged_mode
,
230 const char *t2
, *trigger
;
236 /* So, the ESP and XBOOTLDR partition are commonly located on an autofs mount. stat() on the
237 * directory won't trigger it, if it is not mounted yet. Let's hence explicitly trigger it here,
238 * before stat()ing */
239 trigger
= strjoina(path
, "/trigger"); /* Filename doesn't matter... */
240 (void) access(trigger
, F_OK
);
242 if (stat(path
, &st
) < 0)
243 return log_full_errno((searching
&& errno
== ENOENT
) ||
244 (unprivileged_mode
&& errno
== EACCES
) ? LOG_DEBUG
: LOG_ERR
, errno
,
245 "Failed to determine block device node of \"%s\": %m", path
);
247 if (major(st
.st_dev
) == 0)
248 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
249 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
250 "Block device node of \"%s\" is invalid.", path
);
252 if (path_equal(path
, "/")) {
253 /* Let's assume that the root directory of the OS is always the root of its file system
254 * (which technically doesn't have to be the case, but it's close enough, and it's not easy
255 * to be fully correct for it, since we can't look further up than the root dir easily.) */
257 *ret_dev
= st
.st_dev
;
262 t2
= strjoina(path
, "/..");
263 if (stat(t2
, &st2
) < 0) {
267 _cleanup_free_
char *parent
= NULL
;
269 /* If going via ".." didn't work due to EACCESS, then let's determine the parent path
270 * directly instead. It's not as good, due to symlinks and such, but we can't do
271 * anything better here. */
273 parent
= dirname_malloc(path
);
277 r
= RET_NERRNO(stat(parent
, &st2
));
281 return log_full_errno(unprivileged_mode
&& r
== -EACCES
? LOG_DEBUG
: LOG_ERR
, r
,
282 "Failed to determine block device node of parent of \"%s\": %m", path
);
285 if (st
.st_dev
== st2
.st_dev
)
286 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
287 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
288 "Directory \"%s\" is not the root of the file system.", path
);
291 *ret_dev
= st
.st_dev
;
296 static int verify_esp(
299 bool unprivileged_mode
,
301 uint64_t *ret_pstart
,
303 sd_id128_t
*ret_uuid
,
312 /* This logs about all errors, except:
314 * -ENOENT → if 'searching' is set, and the dir doesn't exist
315 * -EADDRNOTAVAIL → if 'searching' is set, and the dir doesn't look like an ESP
316 * -EACESS → if 'unprivileged_mode' is set, and we have trouble accessing the thing
319 relax_checks
= getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0;
321 /* Non-root user can only check the status, so if an error occurred in the following, it does not cause any
322 * issues. Let's also, silence the error messages. */
327 if (statfs(p
, &sfs
) < 0)
328 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
329 return log_full_errno((searching
&& errno
== ENOENT
) ||
330 (unprivileged_mode
&& errno
== EACCES
) ? LOG_DEBUG
: LOG_ERR
, errno
,
331 "Failed to check file system type of \"%s\": %m", p
);
333 if (!F_TYPE_EQUAL(sfs
.f_type
, MSDOS_SUPER_MAGIC
))
334 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
335 SYNTHETIC_ERRNO(searching
? EADDRNOTAVAIL
: ENODEV
),
336 "File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p
);
339 r
= verify_fsroot_dir(p
, searching
, unprivileged_mode
, &devid
);
343 /* In a container we don't have access to block devices, skip this part of the verification, we trust
344 * the container manager set everything up correctly on its own. */
345 if (detect_container() > 0 || relax_checks
)
348 /* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
349 * use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
350 * emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
351 * however blkid can't work if we have no privileges to access block devices directly, which is why
352 * we use udev in that case. */
353 if (unprivileged_mode
)
354 r
= verify_esp_udev(devid
, searching
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
356 r
= verify_esp_blkid(devid
, searching
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
);
373 *ret_uuid
= SD_ID128_NULL
;
380 int find_esp_and_warn(
382 bool unprivileged_mode
,
385 uint64_t *ret_pstart
,
387 sd_id128_t
*ret_uuid
,
392 /* This logs about all errors except:
394 * -ENOKEY → when we can't find the partition
395 * -EACCESS → when unprivileged_mode is true, and we can't access something
399 r
= verify_esp(path
, /* searching= */ false, unprivileged_mode
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
, ret_devid
);
406 path
= getenv("SYSTEMD_ESP_PATH");
410 if (!path_is_valid(path
) || !path_is_absolute(path
))
411 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
412 "$SYSTEMD_ESP_PATH does not refer to absolute path, refusing to use it: %s",
415 /* Note: when the user explicitly configured things with an env var we won't validate the
416 * path beyond checking it refers to a directory. After all we want this to be useful for
419 if (stat(path
, &st
) < 0)
420 return log_error_errno(errno
, "Failed to stat '%s': %m", path
);
421 if (!S_ISDIR(st
.st_mode
))
422 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR
), "ESP path '%s' is not a directory.", path
);
431 *ret_uuid
= SD_ID128_NULL
;
433 *ret_devid
= st
.st_dev
;
438 FOREACH_STRING(path
, "/efi", "/boot", "/boot/efi") {
440 r
= verify_esp(path
, /* searching= */ true, unprivileged_mode
, ret_part
, ret_pstart
, ret_psize
, ret_uuid
, ret_devid
);
443 if (!IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
)) /* This one is not it */
447 /* No logging here */
464 static int verify_xbootldr_blkid(
467 sd_id128_t
*ret_uuid
) {
469 sd_id128_t uuid
= SD_ID128_NULL
;
472 _cleanup_(blkid_free_probep
) blkid_probe b
= NULL
;
473 _cleanup_free_
char *node
= NULL
;
477 r
= device_path_make_major_minor(S_IFBLK
, devid
, &node
);
479 return log_error_errno(r
, "Failed to format major/minor device path: %m");
481 b
= blkid_new_probe_from_filename(node
);
483 return log_error_errno(errno
?: SYNTHETIC_ERRNO(ENOMEM
), "Failed to open file system \"%s\": %m", node
);
485 blkid_probe_enable_partitions(b
, 1);
486 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
489 r
= blkid_do_safeprobe(b
);
491 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" is ambiguous.", node
);
493 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "File system \"%s\" does not contain a label.", node
);
495 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe file system \"%s\": %m", node
);
498 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_SCHEME", &v
, NULL
);
500 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition scheme of \"%s\": %m", node
);
501 if (streq(v
, "gpt")) {
504 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
506 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition type UUID of \"%s\": %m", node
);
507 if (id128_equal_string(v
, GPT_XBOOTLDR
) <= 0)
508 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
509 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
510 "File system \"%s\" has wrong type for extended boot loader partition.", node
);
513 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_UUID", &v
, NULL
);
515 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition entry UUID of \"%s\": %m", node
);
516 r
= sd_id128_from_string(v
, &uuid
);
518 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
520 } else if (streq(v
, "dos")) {
523 r
= blkid_probe_lookup_value(b
, "PART_ENTRY_TYPE", &v
, NULL
);
525 return log_error_errno(errno
?: SYNTHETIC_ERRNO(EIO
), "Failed to probe partition type UUID of \"%s\": %m", node
);
526 if (!streq(v
, "0xea"))
527 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
528 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
529 "File system \"%s\" has wrong type for extended boot loader partition.", node
);
532 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
533 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
534 "File system \"%s\" is not on a GPT or DOS partition table.", node
);
543 static int verify_xbootldr_udev(
546 sd_id128_t
*ret_uuid
) {
548 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
549 _cleanup_free_
char *node
= NULL
;
550 sd_id128_t uuid
= SD_ID128_NULL
;
554 r
= device_path_make_major_minor(S_IFBLK
, devid
, &node
);
556 return log_error_errno(r
, "Failed to format major/minor device path: %m");
558 r
= sd_device_new_from_devnum(&d
, 'b', devid
);
560 return log_error_errno(r
, "Failed to get device from device number: %m");
562 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_SCHEME", &v
);
564 return log_error_errno(r
, "Failed to get device property: %m");
566 if (streq(v
, "gpt")) {
568 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
570 return log_error_errno(r
, "Failed to get device property: %m");
571 if (id128_equal_string(v
, GPT_XBOOTLDR
))
572 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
573 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
574 "File system \"%s\" has wrong type for extended boot loader partition.", node
);
576 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_UUID", &v
);
578 return log_error_errno(r
, "Failed to get device property: %m");
579 r
= sd_id128_from_string(v
, &uuid
);
581 return log_error_errno(r
, "Partition \"%s\" has invalid UUID \"%s\".", node
, v
);
583 } else if (streq(v
, "dos")) {
585 r
= sd_device_get_property_value(d
, "ID_PART_ENTRY_TYPE", &v
);
587 return log_error_errno(r
, "Failed to get device property: %m");
588 if (!streq(v
, "0xea"))
589 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
590 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
591 "File system \"%s\" has wrong type for extended boot loader partition.", node
);
593 return log_full_errno(searching
? LOG_DEBUG
: LOG_ERR
,
594 searching
? SYNTHETIC_ERRNO(EADDRNOTAVAIL
) : SYNTHETIC_ERRNO(ENODEV
),
595 "File system \"%s\" is not on a GPT or DOS partition table.", node
);
603 static int verify_xbootldr(
606 bool unprivileged_mode
,
607 sd_id128_t
*ret_uuid
,
616 relax_checks
= getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0;
618 r
= verify_fsroot_dir(p
, searching
, unprivileged_mode
, &devid
);
622 if (detect_container() > 0 || relax_checks
)
625 if (unprivileged_mode
)
626 r
= verify_xbootldr_udev(devid
, searching
, ret_uuid
);
628 r
= verify_xbootldr_blkid(devid
, searching
, ret_uuid
);
639 *ret_uuid
= SD_ID128_NULL
;
646 int find_xbootldr_and_warn(
648 bool unprivileged_mode
,
650 sd_id128_t
*ret_uuid
,
655 /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
658 r
= verify_xbootldr(path
, /* searching= */ false, unprivileged_mode
, ret_uuid
, ret_devid
);
665 path
= getenv("SYSTEMD_XBOOTLDR_PATH");
669 if (!path_is_valid(path
) || !path_is_absolute(path
))
670 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
671 "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s",
674 if (stat(path
, &st
) < 0)
675 return log_error_errno(errno
, "Failed to stat '%s': %m", path
);
676 if (!S_ISDIR(st
.st_mode
))
677 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR
), "XBOOTLDR path '%s' is not a directory.", path
);
680 *ret_uuid
= SD_ID128_NULL
;
682 *ret_devid
= st
.st_dev
;
687 r
= verify_xbootldr("/boot", true, unprivileged_mode
, ret_uuid
, ret_devid
);
692 if (!IN_SET(r
, -ENOENT
, -EADDRNOTAVAIL
)) /* This one is not it */