]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/find-esp.c
Merge pull request #25568 from yuwata/network-tiny-cleanups
[thirdparty/systemd.git] / src / shared / find-esp.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <linux/magic.h>
4 #include <sys/vfs.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 "btrfs-util.h"
12 #include "chase-symlinks.h"
13 #include "device-util.h"
14 #include "devnum-util.h"
15 #include "env-util.h"
16 #include "errno-util.h"
17 #include "fd-util.h"
18 #include "find-esp.h"
19 #include "gpt.h"
20 #include "parse-util.h"
21 #include "path-util.h"
22 #include "stat-util.h"
23 #include "string-util.h"
24 #include "virt.h"
25
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 */
30 } VerifyESPFlags;
31
32 static int verify_esp_blkid(
33 dev_t devid,
34 bool searching,
35 uint32_t *ret_part,
36 uint64_t *ret_pstart,
37 uint64_t *ret_psize,
38 sd_id128_t *ret_uuid) {
39
40 sd_id128_t uuid = SD_ID128_NULL;
41 uint64_t pstart = 0, psize = 0;
42 uint32_t part = 0;
43
44 #if HAVE_BLKID
45 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
46 _cleanup_free_ char *node = NULL;
47 const char *v;
48 int r;
49
50 r = devname_from_devnum(S_IFBLK, devid, &node);
51 if (r < 0)
52 return log_error_errno(r, "Failed to get device path for " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(devid));
53
54 errno = 0;
55 b = blkid_new_probe_from_filename(node);
56 if (!b)
57 return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
58
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);
63
64 errno = 0;
65 r = blkid_do_safeprobe(b);
66 if (r == -2)
67 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
68 else if (r == 1)
69 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" does not contain a label.", node);
70 else if (r != 0)
71 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
72
73 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
74 if (r != 0)
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);
82
83 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
84 if (r != 0)
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);
88 if (!streq(v, "gpt"))
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);
92
93 errno = 0;
94 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
95 if (r != 0)
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);
101
102 errno = 0;
103 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
104 if (r != 0)
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);
107 if (r < 0)
108 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
109
110 errno = 0;
111 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
112 if (r != 0)
113 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": %m", node);
114 r = safe_atou32(v, &part);
115 if (r < 0)
116 return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
117
118 errno = 0;
119 r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
120 if (r != 0)
121 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition offset of \"%s\": %m", node);
122 r = safe_atou64(v, &pstart);
123 if (r < 0)
124 return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
125
126 errno = 0;
127 r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
128 if (r != 0)
129 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition size of \"%s\": %m", node);
130 r = safe_atou64(v, &psize);
131 if (r < 0)
132 return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
133 #endif
134
135 if (ret_part)
136 *ret_part = part;
137 if (ret_pstart)
138 *ret_pstart = pstart;
139 if (ret_psize)
140 *ret_psize = psize;
141 if (ret_uuid)
142 *ret_uuid = uuid;
143
144 return 0;
145 }
146
147 static int verify_esp_udev(
148 dev_t devid,
149 bool searching,
150 uint32_t *ret_part,
151 uint64_t *ret_pstart,
152 uint64_t *ret_psize,
153 sd_id128_t *ret_uuid) {
154
155 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
156 sd_id128_t uuid = SD_ID128_NULL;
157 uint64_t pstart = 0, psize = 0;
158 uint32_t part = 0;
159 const char *node, *v;
160 int r;
161
162 r = sd_device_new_from_devnum(&d, 'b', devid);
163 if (r < 0)
164 return log_error_errno(r, "Failed to get device from device number: %m");
165
166 r = sd_device_get_devname(d, &node);
167 if (r < 0)
168 return log_device_error_errno(d, r, "Failed to get device node: %m");
169
170 r = sd_device_get_property_value(d, "ID_FS_TYPE", &v);
171 if (r < 0)
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 );
178
179 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
180 if (r < 0)
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);
190
191 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
192 if (r < 0)
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);
199
200 r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
201 if (r < 0)
202 return log_device_error_errno(d, r, "Failed to get device property: %m");
203 r = sd_id128_from_string(v, &uuid);
204 if (r < 0)
205 return log_device_error_errno(d, r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
206
207 r = sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &v);
208 if (r < 0)
209 return log_device_error_errno(d, r, "Failed to get device property: %m");
210 r = safe_atou32(v, &part);
211 if (r < 0)
212 return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_NUMBER field.");
213
214 r = sd_device_get_property_value(d, "ID_PART_ENTRY_OFFSET", &v);
215 if (r < 0)
216 return log_device_error_errno(d, r, "Failed to get device property: %m");
217 r = safe_atou64(v, &pstart);
218 if (r < 0)
219 return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_OFFSET field.");
220
221 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SIZE", &v);
222 if (r < 0)
223 return log_device_error_errno(d, r, "Failed to get device property: %m");
224 r = safe_atou64(v, &psize);
225 if (r < 0)
226 return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_SIZE field.");
227
228 if (ret_part)
229 *ret_part = part;
230 if (ret_pstart)
231 *ret_pstart = pstart;
232 if (ret_psize)
233 *ret_psize = psize;
234 if (ret_uuid)
235 *ret_uuid = uuid;
236
237 return 0;
238 }
239
240 static int verify_fsroot_dir(
241 const char *path,
242 bool searching,
243 bool unprivileged_mode,
244 dev_t *ret_dev) {
245
246 _cleanup_close_ int fd = -1;
247 STRUCT_NEW_STATX_DEFINE(sxa);
248 STRUCT_NEW_STATX_DEFINE(sxb);
249 int r;
250
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. */
253
254 assert(path);
255
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);
259 if (fd < 0)
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);
263
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... */
268
269 r = statx_fallback(fd, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxa.sx);
270 if (r < 0)
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);
273
274 assert(S_ISDIR(sxa.sx.stx_mode)); /* We used O_DIRECTORY above, when opening, so this must hold */
275
276 if (FLAGS_SET(sxa.sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) {
277
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...) */
281
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);
286
287 goto success;
288 }
289
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;
294
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
297 * better here.
298 *
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.) */
304
305 if (path_equal(path, "/"))
306 goto success;
307
308 r = path_extract_directory(path, &parent);
309 if (r < 0)
310 return log_error_errno(r, "Failed to extract parent path from '%s': %m", path);
311
312 r = statx_fallback(AT_FDCWD, parent, AT_SYMLINK_NOFOLLOW, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sxb.sx);
313 }
314 if (r < 0)
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);
317
318 if (statx_inode_same(&sxa.sx, &sxb.sx)) /* for the root dir inode nr for both inodes will be the same */
319 goto success;
320
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);
325
326 success:
327 if (!ret_dev)
328 return 0;
329
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;
332
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. */
335
336 real_fd = fd_reopen(fd, O_DIRECTORY|O_CLOEXEC);
337 if (real_fd < 0)
338 return real_fd;
339
340 return btrfs_get_block_device_fd(real_fd, ret_dev);
341 }
342
343 *ret_dev = makedev(sxa.sx.stx_dev_major, sxa.sx.stx_dev_minor);
344 return 0;
345 }
346
347 static int verify_esp(
348 const char *p,
349 uint32_t *ret_part,
350 uint64_t *ret_pstart,
351 uint64_t *ret_psize,
352 sd_id128_t *ret_uuid,
353 dev_t *ret_devid,
354 VerifyESPFlags flags) {
355
356 bool relax_checks, searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING),
357 unprivileged_mode = FLAGS_SET(flags, VERIFY_ESP_UNPRIVILEGED_MODE);
358 dev_t devid = 0;
359 int r;
360
361 assert(p);
362
363 /* This logs about all errors, except:
364 *
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
368 */
369
370 relax_checks =
371 getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0 ||
372 FLAGS_SET(flags, VERIFY_ESP_RELAX_CHECKS);
373
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. */
376
377 if (!relax_checks) {
378 struct statfs sfs;
379
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);
385
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);
390 }
391
392 relax_checks =
393 relax_checks ||
394 detect_container() > 0;
395
396 r = verify_fsroot_dir(p, searching, unprivileged_mode, relax_checks ? NULL : &devid);
397 if (r < 0)
398 return r;
399
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. */
402 if (relax_checks)
403 goto finish;
404
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);
412 else
413 r = verify_esp_blkid(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
414 if (r < 0)
415 return r;
416
417 if (ret_devid)
418 *ret_devid = devid;
419
420 return 0;
421
422 finish:
423 if (ret_part)
424 *ret_part = 0;
425 if (ret_pstart)
426 *ret_pstart = 0;
427 if (ret_psize)
428 *ret_psize = 0;
429 if (ret_uuid)
430 *ret_uuid = SD_ID128_NULL;
431 if (ret_devid)
432 *ret_devid = 0;
433
434 return 0;
435 }
436
437 int find_esp_and_warn(
438 const char *root,
439 const char *path,
440 bool unprivileged_mode,
441 char **ret_path,
442 uint32_t *ret_part,
443 uint64_t *ret_pstart,
444 uint64_t *ret_psize,
445 sd_id128_t *ret_uuid,
446 dev_t *ret_devid) {
447
448 VerifyESPFlags flags = (unprivileged_mode ? VERIFY_ESP_UNPRIVILEGED_MODE : 0) |
449 (root ? VERIFY_ESP_RELAX_CHECKS : 0);
450 _cleanup_free_ char *p = NULL;
451 int r;
452
453 /* This logs about all errors except:
454 *
455 * -ENOKEY → when we can't find the partition
456 * -EACCESS → when unprivileged_mode is true, and we can't access something
457 */
458
459 if (path) {
460 r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL);
461 if (r < 0)
462 return log_error_errno(r,
463 "Failed to resolve path %s%s%s: %m",
464 path,
465 root ? " under directory " : "",
466 strempty(root));
467
468 r = verify_esp(p, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid, flags);
469 if (r < 0)
470 return r;
471
472 goto found;
473 }
474
475 path = getenv("SYSTEMD_ESP_PATH");
476 if (path) {
477 struct stat st;
478
479 r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL);
480 if (r < 0)
481 return log_error_errno(r,
482 "Failed to resolve path %s%s%s: %m",
483 path,
484 root ? " under directory " : "",
485 strempty(root));
486
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",
490 p);
491
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
494 * testing. */
495
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);
500
501 if (ret_part)
502 *ret_part = 0;
503 if (ret_pstart)
504 *ret_pstart = 0;
505 if (ret_psize)
506 *ret_psize = 0;
507 if (ret_uuid)
508 *ret_uuid = SD_ID128_NULL;
509 if (ret_devid)
510 *ret_devid = st.st_dev;
511
512 goto found;
513 }
514
515 FOREACH_STRING(dir, "/efi", "/boot", "/boot/efi") {
516 r = chase_symlinks(dir, root, CHASE_PREFIX_ROOT, &p, NULL);
517 if (r == -ENOENT)
518 continue;
519 if (r < 0)
520 return log_error_errno(r,
521 "Failed to resolve path %s%s%s: %m",
522 dir,
523 root ? " under directory " : "",
524 strempty(root));
525
526 r = verify_esp(p, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid,
527 flags | VERIFY_ESP_SEARCHING);
528 if (r >= 0)
529 goto found;
530 if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL, -ENOTDIR)) /* This one is not it */
531 return r;
532
533 p = mfree(p);
534 }
535
536 /* No logging here */
537 return -ENOKEY;
538
539 found:
540 if (ret_path)
541 *ret_path = TAKE_PTR(p);
542
543 return 0;
544 }
545
546 static int verify_xbootldr_blkid(
547 dev_t devid,
548 bool searching,
549 sd_id128_t *ret_uuid) {
550
551 sd_id128_t uuid = SD_ID128_NULL;
552
553 #if HAVE_BLKID
554 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
555 _cleanup_free_ char *node = NULL;
556 const char *type, *v;
557 int r;
558
559 r = devname_from_devnum(S_IFBLK, devid, &node);
560 if (r < 0)
561 return log_error_errno(r, "Failed to get block device path for " DEVNUM_FORMAT_STR ": %m",
562 DEVNUM_FORMAT_VAL(devid));
563
564 errno = 0;
565 b = blkid_new_probe_from_filename(node);
566 if (!b)
567 return log_error_errno(errno_or_else(ENOMEM), "%s: Failed to create blkid probe: %m", node);
568
569 blkid_probe_enable_partitions(b, 1);
570 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
571
572 errno = 0;
573 r = blkid_do_safeprobe(b);
574 if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
575 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system is ambiguous.", node);
576 if (r == _BLKID_SAFEPROBE_NOT_FOUND)
577 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system does not contain a label.", node);
578 if (r == _BLKID_SAFEPROBE_ERROR)
579 return log_error_errno(errno_or_else(EIO), "%s: Failed to probe file system: %m", node);
580
581 assert(r == _BLKID_SAFEPROBE_FOUND);
582
583 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &type, NULL);
584 if (r != 0)
585 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
586 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(EIO),
587 "%s: Failed to probe PART_ENTRY_SCHEME: %m", node);
588 if (streq(type, "gpt")) {
589
590 errno = 0;
591 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
592 if (r != 0)
593 return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
594 if (sd_id128_string_equal(v, SD_GPT_XBOOTLDR) <= 0)
595 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
596 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
597 "%s: Partitition has wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node, v);
598
599 errno = 0;
600 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
601 if (r != 0)
602 return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_UUID: %m", node);
603 r = sd_id128_from_string(v, &uuid);
604 if (r < 0)
605 return log_error_errno(r, "%s: Partition has invalid UUID PART_ENTRY_TYPE=%s: %m", node, v);
606
607 } else if (streq(type, "dos")) {
608
609 errno = 0;
610 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
611 if (r != 0)
612 return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
613 if (!streq(v, "0xea"))
614 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
615 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
616 "%s: Wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node, v);
617
618 } else
619 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
620 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
621 "%s: Not on a GPT or DOS partition table (PART_ENTRY_SCHEME=%s).", node, type);
622 #endif
623
624 if (ret_uuid)
625 *ret_uuid = uuid;
626
627 return 0;
628 }
629
630 static int verify_xbootldr_udev(
631 dev_t devid,
632 bool searching,
633 sd_id128_t *ret_uuid) {
634
635 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
636 sd_id128_t uuid = SD_ID128_NULL;
637 const char *node, *type, *v;
638 int r;
639
640 r = sd_device_new_from_devnum(&d, 'b', devid);
641 if (r < 0)
642 return log_error_errno(r, "Failed to get block device for " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(devid));
643
644 r = sd_device_get_devname(d, &node);
645 if (r < 0)
646 return log_device_error_errno(d, r, "Failed to get device node: %m");
647
648 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &type);
649 if (r < 0)
650 return log_device_full_errno(d,
651 searching && r == -ENOENT ? LOG_DEBUG : LOG_ERR,
652 searching && r == -ENOENT ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : r,
653 "Failed to query ID_PART_ENTRY_SCHEME: %m");
654
655 if (streq(type, "gpt")) {
656
657 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
658 if (r < 0)
659 return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_TYPE: %m");
660
661 r = sd_id128_string_equal(v, SD_GPT_XBOOTLDR);
662 if (r < 0)
663 return log_device_error_errno(d, r, "Failed to parse ID_PART_ENTRY_TYPE=%s: %m", v);
664 if (r == 0)
665 return log_device_full_errno(
666 d,
667 searching ? LOG_DEBUG : LOG_ERR,
668 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
669 "Partition has wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v);
670
671 r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
672 if (r < 0)
673 return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_UUID: %m");
674 r = sd_id128_from_string(v, &uuid);
675 if (r < 0)
676 return log_device_error_errno(d, r, "Partition has invalid UUID ID_PART_ENTRY_TYPE=%s: %m", v);
677
678 } else if (streq(type, "dos")) {
679
680 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
681 if (r < 0)
682 return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_TYPE: %m");
683 if (!streq(v, "0xea"))
684 return log_device_full_errno(
685 d,
686 searching ? LOG_DEBUG : LOG_ERR,
687 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
688 "Wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v);
689
690 } else
691 return log_device_full_errno(
692 d,
693 searching ? LOG_DEBUG : LOG_ERR,
694 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
695 "Not on a GPT or DOS partition table (ID_PART_ENTRY_SCHEME=%s).", type);
696
697 if (ret_uuid)
698 *ret_uuid = uuid;
699
700 return 0;
701 }
702
703 static int verify_xbootldr(
704 const char *p,
705 bool searching,
706 bool unprivileged_mode,
707 sd_id128_t *ret_uuid,
708 dev_t *ret_devid) {
709
710 bool relax_checks;
711 dev_t devid = 0;
712 int r;
713
714 assert(p);
715
716 relax_checks =
717 getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0 ||
718 detect_container() > 0;
719
720 r = verify_fsroot_dir(p, searching, unprivileged_mode, relax_checks ? NULL : &devid);
721 if (r < 0)
722 return r;
723
724 if (relax_checks)
725 goto finish;
726
727 if (unprivileged_mode)
728 r = verify_xbootldr_udev(devid, searching, ret_uuid);
729 else
730 r = verify_xbootldr_blkid(devid, searching, ret_uuid);
731 if (r < 0)
732 return r;
733
734 if (ret_devid)
735 *ret_devid = devid;
736
737 return 0;
738
739 finish:
740 if (ret_uuid)
741 *ret_uuid = SD_ID128_NULL;
742 if (ret_devid)
743 *ret_devid = 0;
744
745 return 0;
746 }
747
748 int find_xbootldr_and_warn(
749 const char *root,
750 const char *path,
751 bool unprivileged_mode,
752 char **ret_path,
753 sd_id128_t *ret_uuid,
754 dev_t *ret_devid) {
755
756 _cleanup_free_ char *p = NULL;
757 int r;
758
759 /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
760
761 if (path) {
762 r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL);
763 if (r < 0)
764 return log_error_errno(r,
765 "Failed to resolve path %s%s%s: %m",
766 path,
767 root ? " under directory " : "",
768 strempty(root));
769
770 r = verify_xbootldr(p, /* searching= */ false, unprivileged_mode, ret_uuid, ret_devid);
771 if (r < 0)
772 return r;
773
774 goto found;
775 }
776
777 path = getenv("SYSTEMD_XBOOTLDR_PATH");
778 if (path) {
779 struct stat st;
780
781 r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL);
782 if (r < 0)
783 return log_error_errno(r,
784 "Failed to resolve path %s%s%s: %m",
785 path,
786 root ? " under directory " : "",
787 strempty(root));
788
789 if (!path_is_valid(p) || !path_is_absolute(p))
790 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
791 "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s",
792 p);
793
794 if (stat(p, &st) < 0)
795 return log_error_errno(errno, "Failed to stat '%s': %m", p);
796 if (!S_ISDIR(st.st_mode))
797 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "XBOOTLDR path '%s' is not a directory.", p);
798
799 if (ret_uuid)
800 *ret_uuid = SD_ID128_NULL;
801 if (ret_devid)
802 *ret_devid = st.st_dev;
803
804 goto found;
805 }
806
807 r = chase_symlinks("/boot", root, CHASE_PREFIX_ROOT, &p, NULL);
808 if (r == -ENOENT)
809 return -ENOKEY;
810 if (r < 0)
811 return log_error_errno(r,
812 "Failed to resolve path /boot%s%s: %m",
813 root ? " under directory " : "",
814 strempty(root));
815
816 r = verify_xbootldr(p, /* searching= */ true, unprivileged_mode, ret_uuid, ret_devid);
817 if (r >= 0)
818 goto found;
819 if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL, -ENOTDIR)) /* This one is not it */
820 return r;
821
822 return -ENOKEY;
823
824 found:
825 if (ret_path)
826 *ret_path = TAKE_PTR(p);
827
828 return 0;
829 }