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