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