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