]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/find-esp.c
bootctl: add --root and --image
[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 "chase-symlinks.h"
12 #include "device-util.h"
13 #include "devnum-util.h"
14 #include "env-util.h"
15 #include "errno-util.h"
16 #include "find-esp.h"
17 #include "gpt.h"
18 #include "parse-util.h"
19 #include "path-util.h"
20 #include "stat-util.h"
21 #include "string-util.h"
22 #include "virt.h"
23
24 typedef enum VerifyESPFlags {
25 VERIFY_ESP_SEARCHING = 1 << 0, /* Downgrade various "not found" logs to debug level */
26 VERIFY_ESP_UNPRIVILEGED_MODE = 1 << 1, /* Call into udev rather than blkid */
27 VERIFY_ESP_RELAX_CHECKS = 1 << 2, /* Do not validate ESP partition */
28 } VerifyESPFlags;
29
30 static int verify_esp_blkid(
31 dev_t devid,
32 bool searching,
33 uint32_t *ret_part,
34 uint64_t *ret_pstart,
35 uint64_t *ret_psize,
36 sd_id128_t *ret_uuid) {
37
38 sd_id128_t uuid = SD_ID128_NULL;
39 uint64_t pstart = 0, psize = 0;
40 uint32_t part = 0;
41
42 #if HAVE_BLKID
43 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
44 _cleanup_free_ char *node = NULL;
45 const char *v;
46 int r;
47
48 r = device_path_make_major_minor(S_IFBLK, devid, &node);
49 if (r < 0)
50 return log_error_errno(r, "Failed to format major/minor device path: %m");
51
52 errno = 0;
53 b = blkid_new_probe_from_filename(node);
54 if (!b)
55 return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
56
57 blkid_probe_enable_superblocks(b, 1);
58 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
59 blkid_probe_enable_partitions(b, 1);
60 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
61
62 errno = 0;
63 r = blkid_do_safeprobe(b);
64 if (r == -2)
65 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
66 else if (r == 1)
67 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" does not contain a label.", node);
68 else if (r != 0)
69 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
70
71 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
72 if (r != 0)
73 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
74 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
75 "No filesystem found on \"%s\": %m", node);
76 if (!streq(v, "vfat"))
77 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
78 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
79 "File system \"%s\" is not FAT.", node);
80
81 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
82 if (r != 0)
83 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
84 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
85 "File system \"%s\" is not located on a partitioned block device.", node);
86 if (!streq(v, "gpt"))
87 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
88 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
89 "File system \"%s\" is not on a GPT partition table.", node);
90
91 errno = 0;
92 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
93 if (r != 0)
94 return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID of \"%s\": %m", node);
95 if (sd_id128_string_equal(v, GPT_ESP) <= 0)
96 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
97 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
98 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
99
100 errno = 0;
101 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
102 if (r != 0)
103 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition entry UUID of \"%s\": %m", node);
104 r = sd_id128_from_string(v, &uuid);
105 if (r < 0)
106 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
107
108 errno = 0;
109 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
110 if (r != 0)
111 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": %m", node);
112 r = safe_atou32(v, &part);
113 if (r < 0)
114 return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
115
116 errno = 0;
117 r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
118 if (r != 0)
119 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition offset of \"%s\": %m", node);
120 r = safe_atou64(v, &pstart);
121 if (r < 0)
122 return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
123
124 errno = 0;
125 r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
126 if (r != 0)
127 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition size of \"%s\": %m", node);
128 r = safe_atou64(v, &psize);
129 if (r < 0)
130 return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
131 #endif
132
133 if (ret_part)
134 *ret_part = part;
135 if (ret_pstart)
136 *ret_pstart = pstart;
137 if (ret_psize)
138 *ret_psize = psize;
139 if (ret_uuid)
140 *ret_uuid = uuid;
141
142 return 0;
143 }
144
145 static int verify_esp_udev(
146 dev_t devid,
147 bool searching,
148 uint32_t *ret_part,
149 uint64_t *ret_pstart,
150 uint64_t *ret_psize,
151 sd_id128_t *ret_uuid) {
152
153 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
154 _cleanup_free_ char *node = NULL;
155 sd_id128_t uuid = SD_ID128_NULL;
156 uint64_t pstart = 0, psize = 0;
157 uint32_t part = 0;
158 const char *v;
159 int r;
160
161 r = device_path_make_major_minor(S_IFBLK, devid, &node);
162 if (r < 0)
163 return log_error_errno(r, "Failed to format major/minor device path: %m");
164
165 r = sd_device_new_from_devnum(&d, 'b', devid);
166 if (r < 0)
167 return log_error_errno(r, "Failed to get device from device number: %m");
168
169 r = sd_device_get_property_value(d, "ID_FS_TYPE", &v);
170 if (r < 0)
171 return log_error_errno(r, "Failed to get device property: %m");
172 if (!streq(v, "vfat"))
173 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
174 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
175 "File system \"%s\" is not FAT.", node );
176
177 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
178 if (r < 0)
179 return log_error_errno(r, "Failed to get device property: %m");
180 if (!streq(v, "gpt"))
181 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
182 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
183 "File system \"%s\" is not on a GPT partition table.", node);
184
185 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
186 if (r < 0)
187 return log_error_errno(r, "Failed to get device property: %m");
188 if (sd_id128_string_equal(v, GPT_ESP) <= 0)
189 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
190 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
191 "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
192
193 r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
194 if (r < 0)
195 return log_error_errno(r, "Failed to get device property: %m");
196 r = sd_id128_from_string(v, &uuid);
197 if (r < 0)
198 return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
199
200 r = sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &v);
201 if (r < 0)
202 return log_error_errno(r, "Failed to get device property: %m");
203 r = safe_atou32(v, &part);
204 if (r < 0)
205 return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
206
207 r = sd_device_get_property_value(d, "ID_PART_ENTRY_OFFSET", &v);
208 if (r < 0)
209 return log_error_errno(r, "Failed to get device property: %m");
210 r = safe_atou64(v, &pstart);
211 if (r < 0)
212 return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
213
214 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SIZE", &v);
215 if (r < 0)
216 return log_error_errno(r, "Failed to get device property: %m");
217 r = safe_atou64(v, &psize);
218 if (r < 0)
219 return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
220
221 if (ret_part)
222 *ret_part = part;
223 if (ret_pstart)
224 *ret_pstart = pstart;
225 if (ret_psize)
226 *ret_psize = psize;
227 if (ret_uuid)
228 *ret_uuid = uuid;
229
230 return 0;
231 }
232
233 static int verify_fsroot_dir(
234 const char *path,
235 bool searching,
236 bool unprivileged_mode,
237 dev_t *ret_dev) {
238
239 struct stat st, st2;
240 const char *t2, *trigger;
241 int r;
242
243 assert(path);
244 assert(ret_dev);
245
246 /* So, the ESP and XBOOTLDR partition are commonly located on an autofs mount. stat() on the
247 * directory won't trigger it, if it is not mounted yet. Let's hence explicitly trigger it here,
248 * before stat()ing */
249 trigger = strjoina(path, "/trigger"); /* Filename doesn't matter... */
250 (void) access(trigger, F_OK);
251
252 if (stat(path, &st) < 0)
253 return log_full_errno((searching && errno == ENOENT) ||
254 (unprivileged_mode && errno == EACCES) ? LOG_DEBUG : LOG_ERR, errno,
255 "Failed to determine block device node of \"%s\": %m", path);
256
257 if (major(st.st_dev) == 0)
258 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
259 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
260 "Block device node of \"%s\" is invalid.", path);
261
262 if (path_equal(path, "/")) {
263 /* Let's assume that the root directory of the OS is always the root of its file system
264 * (which technically doesn't have to be the case, but it's close enough, and it's not easy
265 * to be fully correct for it, since we can't look further up than the root dir easily.) */
266 if (ret_dev)
267 *ret_dev = st.st_dev;
268
269 return 0;
270 }
271
272 t2 = strjoina(path, "/..");
273 if (stat(t2, &st2) < 0) {
274 if (errno != EACCES)
275 r = -errno;
276 else {
277 _cleanup_free_ char *parent = NULL;
278
279 /* If going via ".." didn't work due to EACCESS, then let's determine the parent path
280 * directly instead. It's not as good, due to symlinks and such, but we can't do
281 * anything better here. */
282
283 parent = dirname_malloc(path);
284 if (!parent)
285 return log_oom();
286
287 r = RET_NERRNO(stat(parent, &st2));
288 }
289
290 if (r < 0)
291 return log_full_errno(unprivileged_mode && r == -EACCES ? LOG_DEBUG : LOG_ERR, r,
292 "Failed to determine block device node of parent of \"%s\": %m", path);
293 }
294
295 if (st.st_dev == st2.st_dev)
296 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
297 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
298 "Directory \"%s\" is not the root of the file system.", path);
299
300 if (ret_dev)
301 *ret_dev = st.st_dev;
302
303 return 0;
304 }
305
306 static int verify_esp(
307 const char *p,
308 uint32_t *ret_part,
309 uint64_t *ret_pstart,
310 uint64_t *ret_psize,
311 sd_id128_t *ret_uuid,
312 dev_t *ret_devid,
313 VerifyESPFlags flags) {
314
315 bool relax_checks, searching = FLAGS_SET(flags, VERIFY_ESP_SEARCHING),
316 unprivileged_mode = FLAGS_SET(flags, VERIFY_ESP_UNPRIVILEGED_MODE);
317 dev_t devid;
318 int r;
319
320 assert(p);
321
322 /* This logs about all errors, except:
323 *
324 * -ENOENT → if 'searching' is set, and the dir doesn't exist
325 * -EADDRNOTAVAIL → if 'searching' is set, and the dir doesn't look like an ESP
326 * -EACESS → if 'unprivileged_mode' is set, and we have trouble accessing the thing
327 */
328
329 relax_checks = getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0 || FLAGS_SET(flags, VERIFY_ESP_RELAX_CHECKS);
330
331 /* Non-root user can only check the status, so if an error occurred in the following, it does not cause any
332 * issues. Let's also, silence the error messages. */
333
334 if (!relax_checks) {
335 struct statfs sfs;
336
337 if (statfs(p, &sfs) < 0)
338 /* If we are searching for the mount point, don't generate a log message if we can't find the path */
339 return log_full_errno((searching && errno == ENOENT) ||
340 (unprivileged_mode && errno == EACCES) ? LOG_DEBUG : LOG_ERR, errno,
341 "Failed to check file system type of \"%s\": %m", p);
342
343 if (!F_TYPE_EQUAL(sfs.f_type, MSDOS_SUPER_MAGIC))
344 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
345 SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
346 "File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
347 }
348
349 r = verify_fsroot_dir(p, searching, unprivileged_mode, &devid);
350 if (r < 0)
351 return r;
352
353 /* In a container we don't have access to block devices, skip this part of the verification, we trust
354 * the container manager set everything up correctly on its own. */
355 if (detect_container() > 0 || relax_checks)
356 goto finish;
357
358 /* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
359 * use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
360 * emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
361 * however blkid can't work if we have no privileges to access block devices directly, which is why
362 * we use udev in that case. */
363 if (unprivileged_mode)
364 r = verify_esp_udev(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
365 else
366 r = verify_esp_blkid(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
367 if (r < 0)
368 return r;
369
370 if (ret_devid)
371 *ret_devid = devid;
372
373 return 0;
374
375 finish:
376 if (ret_part)
377 *ret_part = 0;
378 if (ret_pstart)
379 *ret_pstart = 0;
380 if (ret_psize)
381 *ret_psize = 0;
382 if (ret_uuid)
383 *ret_uuid = SD_ID128_NULL;
384 if (ret_devid)
385 *ret_devid = 0;
386
387 return 0;
388 }
389
390 int find_esp_and_warn(
391 const char *root,
392 const char *path,
393 bool unprivileged_mode,
394 char **ret_path,
395 uint32_t *ret_part,
396 uint64_t *ret_pstart,
397 uint64_t *ret_psize,
398 sd_id128_t *ret_uuid,
399 dev_t *ret_devid) {
400
401 VerifyESPFlags flags = (unprivileged_mode ? VERIFY_ESP_UNPRIVILEGED_MODE : 0) |
402 (root ? VERIFY_ESP_RELAX_CHECKS : 0);
403 _cleanup_free_ char *p = NULL;
404 int r;
405
406 /* This logs about all errors except:
407 *
408 * -ENOKEY → when we can't find the partition
409 * -EACCESS → when unprivileged_mode is true, and we can't access something
410 */
411
412 if (path) {
413 r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL);
414 if (r < 0)
415 return log_error_errno(r,
416 "Failed to resolve path %s%s%s: %m",
417 path,
418 root ? " under directory " : "",
419 root ?: "");
420
421 r = verify_esp(p, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid, flags);
422 if (r < 0)
423 return r;
424
425 goto found;
426 }
427
428 path = getenv("SYSTEMD_ESP_PATH");
429 if (path) {
430 struct stat st;
431
432 r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL);
433 if (r < 0)
434 return log_error_errno(r,
435 "Failed to resolve path %s%s%s: %m",
436 path,
437 root ? " under directory " : "",
438 root ?: "");
439
440 if (!path_is_valid(p) || !path_is_absolute(p))
441 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
442 "$SYSTEMD_ESP_PATH does not refer to absolute path, refusing to use it: %s",
443 p);
444
445 /* Note: when the user explicitly configured things with an env var we won't validate the
446 * path beyond checking it refers to a directory. After all we want this to be useful for
447 * testing. */
448
449 if (stat(p, &st) < 0)
450 return log_error_errno(errno, "Failed to stat '%s': %m", p);
451 if (!S_ISDIR(st.st_mode))
452 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "ESP path '%s' is not a directory.", p);
453
454 if (ret_part)
455 *ret_part = 0;
456 if (ret_pstart)
457 *ret_pstart = 0;
458 if (ret_psize)
459 *ret_psize = 0;
460 if (ret_uuid)
461 *ret_uuid = SD_ID128_NULL;
462 if (ret_devid)
463 *ret_devid = st.st_dev;
464
465 goto found;
466 }
467
468 FOREACH_STRING(dir, "/efi", "/boot", "/boot/efi") {
469 r = chase_symlinks(dir, root, CHASE_PREFIX_ROOT, &p, NULL);
470 if (r == -ENOENT)
471 continue;
472 if (r < 0)
473 return log_error_errno(r,
474 "Failed to resolve path %s%s%s: %m",
475 dir,
476 root ? " under directory " : "",
477 root ?: "");
478
479 r = verify_esp(p, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid,
480 flags | VERIFY_ESP_SEARCHING);
481 if (r >= 0)
482 goto found;
483 if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
484 return r;
485
486 p = mfree(p);
487 }
488
489 /* No logging here */
490 return -ENOKEY;
491
492 found:
493 if (ret_path)
494 *ret_path = TAKE_PTR(p);
495
496 return 0;
497 }
498
499 static int verify_xbootldr_blkid(
500 dev_t devid,
501 bool searching,
502 sd_id128_t *ret_uuid) {
503
504 sd_id128_t uuid = SD_ID128_NULL;
505
506 #if HAVE_BLKID
507 _cleanup_(blkid_free_probep) blkid_probe b = NULL;
508 _cleanup_free_ char *node = NULL;
509 const char *type, *v;
510 int r;
511
512 r = device_path_make_major_minor(S_IFBLK, devid, &node);
513 if (r < 0)
514 return log_error_errno(r, "Failed to format block device path for %u:%u: %m",
515 major(devid), minor(devid));
516
517 errno = 0;
518 b = blkid_new_probe_from_filename(node);
519 if (!b)
520 return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "%s: Failed to create blkid probe: %m", node);
521
522 blkid_probe_enable_partitions(b, 1);
523 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
524
525 errno = 0;
526 r = blkid_do_safeprobe(b);
527 if (r == -2)
528 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system is ambiguous.", node);
529 else if (r == 1)
530 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system does not contain a label.", node);
531 else if (r != 0)
532 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe file system: %m", node);
533
534 errno = 0;
535 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &type, NULL);
536 if (r != 0)
537 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_SCHEME: %m", node);
538 if (streq(type, "gpt")) {
539
540 errno = 0;
541 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
542 if (r != 0)
543 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
544 if (sd_id128_string_equal(v, GPT_XBOOTLDR) <= 0)
545 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
546 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
547 "%s: Partitition has wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node, v);
548
549 errno = 0;
550 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
551 if (r != 0)
552 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_UUID: %m", node);
553 r = sd_id128_from_string(v, &uuid);
554 if (r < 0)
555 return log_error_errno(r, "%s: Partition has invalid UUID PART_ENTRY_TYPE=%s: %m", node, v);
556
557 } else if (streq(type, "dos")) {
558
559 errno = 0;
560 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
561 if (r != 0)
562 return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
563 if (!streq(v, "0xea"))
564 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
565 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
566 "%s: Wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node, v);
567
568 } else
569 return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
570 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
571 "%s: Not on a GPT or DOS partition table (PART_ENTRY_SCHEME=%s).", node, type);
572 #endif
573
574 if (ret_uuid)
575 *ret_uuid = uuid;
576
577 return 0;
578 }
579
580 static int verify_xbootldr_udev(
581 dev_t devid,
582 bool searching,
583 sd_id128_t *ret_uuid) {
584
585 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
586 _cleanup_free_ char *node = NULL;
587 sd_id128_t uuid = SD_ID128_NULL;
588 const char *type, *v;
589 int r;
590
591 r = device_path_make_major_minor(S_IFBLK, devid, &node);
592 if (r < 0)
593 return log_error_errno(r, "Failed to format block device path for %u:%u: %m",
594 major(devid), minor(devid));
595
596 r = sd_device_new_from_devnum(&d, 'b', devid);
597 if (r < 0)
598 return log_error_errno(r, "%s: Failed to get block device: %m", node);
599
600 r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &type);
601 if (r < 0)
602 return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_SCHEME: %m");
603
604 if (streq(type, "gpt")) {
605
606 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
607 if (r < 0)
608 return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_TYPE: %m");
609
610 r = sd_id128_string_equal(v, GPT_XBOOTLDR);
611 if (r < 0)
612 return log_device_error_errno(d, r, "Failed to parse ID_PART_ENTRY_TYPE=%s: %m", v);
613 if (r == 0)
614 return log_device_full_errno(
615 d,
616 searching ? LOG_DEBUG : LOG_ERR,
617 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
618 "Partition has wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v);
619
620 r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
621 if (r < 0)
622 return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_UUID: %m");
623 r = sd_id128_from_string(v, &uuid);
624 if (r < 0)
625 return log_device_error_errno(d, r, "Partition has invalid UUID ID_PART_ENTRY_TYPE=%s: %m", v);
626
627 } else if (streq(type, "dos")) {
628
629 r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
630 if (r < 0)
631 return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_TYPE: %m");
632 if (!streq(v, "0xea"))
633 return log_device_full_errno(
634 d,
635 searching ? LOG_DEBUG : LOG_ERR,
636 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
637 "Wrong ID_PART_ENTRY_TYPE=%s for XBOOTLDR partition.", v);
638
639 } else
640 return log_device_full_errno(
641 d,
642 searching ? LOG_DEBUG : LOG_ERR,
643 searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
644 "Not on a GPT or DOS partition table (ID_PART_ENTRY_SCHEME=%s).", type);
645
646 if (ret_uuid)
647 *ret_uuid = uuid;
648
649 return 0;
650 }
651
652 static int verify_xbootldr(
653 const char *p,
654 bool searching,
655 bool unprivileged_mode,
656 sd_id128_t *ret_uuid,
657 dev_t *ret_devid) {
658
659 bool relax_checks;
660 dev_t devid;
661 int r;
662
663 assert(p);
664
665 relax_checks = getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0;
666
667 r = verify_fsroot_dir(p, searching, unprivileged_mode, &devid);
668 if (r < 0)
669 return r;
670
671 if (detect_container() > 0 || relax_checks)
672 goto finish;
673
674 if (unprivileged_mode)
675 r = verify_xbootldr_udev(devid, searching, ret_uuid);
676 else
677 r = verify_xbootldr_blkid(devid, searching, ret_uuid);
678 if (r < 0)
679 return r;
680
681 if (ret_devid)
682 *ret_devid = devid;
683
684 return 0;
685
686 finish:
687 if (ret_uuid)
688 *ret_uuid = SD_ID128_NULL;
689 if (ret_devid)
690 *ret_devid = 0;
691
692 return 0;
693 }
694
695 int find_xbootldr_and_warn(
696 const char *root,
697 const char *path,
698 bool unprivileged_mode,
699 char **ret_path,
700 sd_id128_t *ret_uuid,
701 dev_t *ret_devid) {
702
703 _cleanup_free_ char *p = NULL;
704 int r;
705
706 /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
707
708 if (path) {
709 r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL);
710 if (r < 0)
711 return log_error_errno(r,
712 "Failed to resolve path %s%s%s: %m",
713 path,
714 root ? " under directory " : "",
715 root ?: "");
716
717 r = verify_xbootldr(p, /* searching= */ false, unprivileged_mode, ret_uuid, ret_devid);
718 if (r < 0)
719 return r;
720
721 goto found;
722 }
723
724 path = getenv("SYSTEMD_XBOOTLDR_PATH");
725 if (path) {
726 struct stat st;
727
728 r = chase_symlinks(path, root, CHASE_PREFIX_ROOT, &p, NULL);
729 if (r < 0)
730 return log_error_errno(r,
731 "Failed to resolve path %s%s%s: %m",
732 path,
733 root ? " under directory " : "",
734 root ?: "");
735
736 if (!path_is_valid(p) || !path_is_absolute(p))
737 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
738 "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s",
739 p);
740
741 if (stat(p, &st) < 0)
742 return log_error_errno(errno, "Failed to stat '%s': %m", p);
743 if (!S_ISDIR(st.st_mode))
744 return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "XBOOTLDR path '%s' is not a directory.", p);
745
746 if (ret_uuid)
747 *ret_uuid = SD_ID128_NULL;
748 if (ret_devid)
749 *ret_devid = st.st_dev;
750
751 goto found;
752 }
753
754 r = chase_symlinks("/boot", root, CHASE_PREFIX_ROOT, &p, NULL);
755 if (r == -ENOENT)
756 return -ENOKEY;
757 if (r < 0)
758 return log_error_errno(r,
759 "Failed to resolve path /boot%s%s: %m",
760 root ? " under directory " : "",
761 root ?: "");
762
763 r = verify_xbootldr(p, true, unprivileged_mode, ret_uuid, ret_devid);
764 if (r >= 0)
765 goto found;
766 if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
767 return r;
768
769 return -ENOKEY;
770
771 found:
772 if (ret_path)
773 *ret_path = TAKE_PTR(p);
774
775 return 0;
776 }