]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/blockdev-util.c
seccomp: add arm_fadvise64_64 to system-service group
[thirdparty/systemd.git] / src / shared / blockdev-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <linux/blkpg.h>
4 #include <sys/file.h>
5 #include <sys/ioctl.h>
6 #include <sys/mount.h>
7 #include <unistd.h>
8
9 #include "sd-device.h"
10
11 #include "alloc-util.h"
12 #include "blockdev-util.h"
13 #include "btrfs-util.h"
14 #include "device-util.h"
15 #include "devnum-util.h"
16 #include "dirent-util.h"
17 #include "errno-util.h"
18 #include "fd-util.h"
19 #include "fileio.h"
20 #include "fs-util.h"
21 #include "missing_magic.h"
22 #include "parse-util.h"
23
24 static int fd_get_devnum(int fd, BlockDeviceLookupFlag flags, dev_t *ret) {
25 struct stat st;
26 dev_t devnum;
27 int r;
28
29 assert(fd >= 0);
30 assert(ret);
31
32 if (fstat(fd, &st) < 0)
33 return -errno;
34
35 if (S_ISBLK(st.st_mode))
36 devnum = st.st_rdev;
37 else if (!FLAGS_SET(flags, BLOCK_DEVICE_LOOKUP_BACKING))
38 return -ENOTBLK;
39 else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
40 return -ENOTBLK;
41 else if (major(st.st_dev) != 0)
42 devnum = st.st_dev;
43 else {
44 /* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special
45 * handing, to get the backing device node. */
46
47 r = btrfs_get_block_device_fd(fd, &devnum);
48 if (r == -ENOTTY) /* not btrfs */
49 return -ENOTBLK;
50 if (r < 0)
51 return r;
52 }
53
54 *ret = devnum;
55 return 0;
56 }
57
58 int block_device_is_whole_disk(sd_device *dev) {
59 const char *s;
60 int r;
61
62 assert(dev);
63
64 r = sd_device_get_subsystem(dev, &s);
65 if (r < 0)
66 return r;
67
68 if (!streq(s, "block"))
69 return -ENOTBLK;
70
71 r = sd_device_get_devtype(dev, &s);
72 if (r < 0)
73 return r;
74
75 return streq(s, "disk");
76 }
77
78 int block_device_get_whole_disk(sd_device *dev, sd_device **ret) {
79 int r;
80
81 assert(dev);
82 assert(ret);
83
84 /* Do not unref returned sd_device object. */
85
86 r = block_device_is_whole_disk(dev);
87 if (r < 0)
88 return r;
89 if (r == 0) {
90 r = sd_device_get_parent(dev, &dev);
91 if (r == -ENOENT) /* Already removed? Let's return a recognizable error. */
92 return -ENODEV;
93 if (r < 0)
94 return r;
95
96 r = block_device_is_whole_disk(dev);
97 if (r < 0)
98 return r;
99 if (r == 0)
100 return -ENXIO;
101 }
102
103 *ret = dev;
104 return 0;
105 }
106
107 static int block_device_get_originating(sd_device *dev, sd_device **ret) {
108 _cleanup_(sd_device_unrefp) sd_device *first_found = NULL;
109 const char *suffix;
110 sd_device *child;
111 dev_t devnum = 0; /* avoid false maybe-uninitialized warning */
112
113 /* For the specified block device tries to chase it through the layers, in case LUKS-style DM
114 * stacking is used, trying to find the next underlying layer. */
115
116 assert(dev);
117 assert(ret);
118
119 FOREACH_DEVICE_CHILD_WITH_SUFFIX(dev, child, suffix) {
120 sd_device *child_whole_disk;
121 dev_t n;
122
123 if (!path_startswith(suffix, "slaves"))
124 continue;
125
126 if (block_device_get_whole_disk(child, &child_whole_disk) < 0)
127 continue;
128
129 if (sd_device_get_devnum(child_whole_disk, &n) < 0)
130 continue;
131
132 if (!first_found) {
133 first_found = sd_device_ref(child);
134 devnum = n;
135 continue;
136 }
137
138 /* We found a device backed by multiple other devices. We don't really support automatic
139 * discovery on such setups, with the exception of dm-verity partitions. In this case there
140 * are two backing devices: the data partition and the hash partition. We are fine with such
141 * setups, however, only if both partitions are on the same physical device. Hence, let's
142 * verify this by iterating over every node in the 'slaves/' directory and comparing them with
143 * the first that gets returned by readdir(), to ensure they all point to the same device. */
144 if (n != devnum)
145 return -ENOTUNIQ;
146 }
147
148 if (!first_found)
149 return -ENOENT;
150
151 *ret = TAKE_PTR(first_found);
152 return 1; /* found */
153 }
154
155 int block_device_new_from_fd(int fd, BlockDeviceLookupFlag flags, sd_device **ret) {
156 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
157 dev_t devnum;
158 int r;
159
160 assert(fd >= 0);
161 assert(ret);
162
163 r = fd_get_devnum(fd, flags, &devnum);
164 if (r < 0)
165 return r;
166
167 r = sd_device_new_from_devnum(&dev, 'b', devnum);
168 if (r < 0)
169 return r;
170
171 if (FLAGS_SET(flags, BLOCK_DEVICE_LOOKUP_ORIGINATING)) {
172 _cleanup_(sd_device_unrefp) sd_device *dev_origin = NULL;
173 sd_device *dev_whole_disk;
174
175 r = block_device_get_whole_disk(dev, &dev_whole_disk);
176 if (r < 0)
177 return r;
178
179 r = block_device_get_originating(dev_whole_disk, &dev_origin);
180 if (r < 0 && r != -ENOENT)
181 return r;
182 if (r > 0)
183 device_unref_and_replace(dev, dev_origin);
184 }
185
186 if (FLAGS_SET(flags, BLOCK_DEVICE_LOOKUP_WHOLE_DISK)) {
187 sd_device *dev_whole_disk;
188
189 r = block_device_get_whole_disk(dev, &dev_whole_disk);
190 if (r < 0)
191 return r;
192
193 *ret = sd_device_ref(dev_whole_disk);
194 return 0;
195 }
196
197 *ret = sd_device_ref(dev);
198 return 0;
199 }
200
201 int block_device_new_from_path(const char *path, BlockDeviceLookupFlag flags, sd_device **ret) {
202 _cleanup_close_ int fd = -EBADF;
203
204 assert(path);
205 assert(ret);
206
207 fd = open(path, O_CLOEXEC|O_PATH);
208 if (fd < 0)
209 return -errno;
210
211 return block_device_new_from_fd(fd, flags, ret);
212 }
213
214 int block_get_whole_disk(dev_t d, dev_t *ret) {
215 char p[SYS_BLOCK_PATH_MAX("/partition")];
216 _cleanup_free_ char *s = NULL;
217 dev_t devt;
218 int r;
219
220 assert(ret);
221
222 if (major(d) == 0)
223 return -ENODEV;
224
225 /* If it has a queue this is good enough for us */
226 xsprintf_sys_block_path(p, "/queue", d);
227 if (access(p, F_OK) >= 0) {
228 *ret = d;
229 return 0;
230 }
231 if (errno != ENOENT)
232 return -errno;
233
234 /* If it is a partition find the originating device */
235 xsprintf_sys_block_path(p, "/partition", d);
236 if (access(p, F_OK) < 0)
237 return -errno;
238
239 /* Get parent dev_t */
240 xsprintf_sys_block_path(p, "/../dev", d);
241 r = read_one_line_file(p, &s);
242 if (r < 0)
243 return r;
244
245 r = parse_devnum(s, &devt);
246 if (r < 0)
247 return r;
248
249 /* Only return this if it is really good enough for us. */
250 xsprintf_sys_block_path(p, "/queue", devt);
251 if (access(p, F_OK) < 0)
252 return -errno;
253
254 *ret = devt;
255 return 1;
256 }
257
258 int get_block_device_fd(int fd, dev_t *ret) {
259 struct stat st;
260 int r;
261
262 assert(fd >= 0);
263 assert(ret);
264
265 /* Gets the block device directly backing a file system. If the block device is encrypted, returns
266 * the device mapper block device. */
267
268 if (fstat(fd, &st))
269 return -errno;
270
271 if (major(st.st_dev) != 0) {
272 *ret = st.st_dev;
273 return 1;
274 }
275
276 r = btrfs_get_block_device_fd(fd, ret);
277 if (r > 0)
278 return 1;
279 if (r != -ENOTTY) /* not btrfs */
280 return r;
281
282 *ret = 0;
283 return 0;
284 }
285
286 int get_block_device(const char *path, dev_t *ret) {
287 _cleanup_close_ int fd = -EBADF;
288
289 assert(path);
290 assert(ret);
291
292 fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC);
293 if (fd < 0)
294 return -errno;
295
296 return get_block_device_fd(fd, ret);
297 }
298
299 int block_get_originating(dev_t dt, dev_t *ret) {
300 _cleanup_(sd_device_unrefp) sd_device *dev = NULL, *origin = NULL;
301 int r;
302
303 assert(ret);
304
305 r = sd_device_new_from_devnum(&dev, 'b', dt);
306 if (r < 0)
307 return r;
308
309 r = block_device_get_originating(dev, &origin);
310 if (r < 0)
311 return r;
312
313 return sd_device_get_devnum(origin, ret);
314 }
315
316 int get_block_device_harder_fd(int fd, dev_t *ret) {
317 int r;
318
319 assert(fd >= 0);
320 assert(ret);
321
322 /* Gets the backing block device for a file system, and handles LUKS encrypted file systems, looking for its
323 * immediate parent, if there is one. */
324
325 r = get_block_device_fd(fd, ret);
326 if (r <= 0)
327 return r;
328
329 r = block_get_originating(*ret, ret);
330 if (r < 0)
331 log_debug_errno(r, "Failed to chase block device, ignoring: %m");
332
333 return 1;
334 }
335
336 int get_block_device_harder(const char *path, dev_t *ret) {
337 _cleanup_close_ int fd = -EBADF;
338
339 assert(path);
340 assert(ret);
341
342 fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC);
343 if (fd < 0)
344 return -errno;
345
346 return get_block_device_harder_fd(fd, ret);
347 }
348
349 int lock_whole_block_device(dev_t devt, int operation) {
350 _cleanup_close_ int lock_fd = -EBADF;
351 dev_t whole_devt;
352 int r;
353
354 /* Let's get a BSD file lock on the whole block device, as per: https://systemd.io/BLOCK_DEVICE_LOCKING */
355
356 r = block_get_whole_disk(devt, &whole_devt);
357 if (r < 0)
358 return r;
359
360 lock_fd = r = device_open_from_devnum(S_IFBLK, whole_devt, O_RDONLY|O_CLOEXEC|O_NONBLOCK, NULL);
361 if (r < 0)
362 return r;
363
364 if (flock(lock_fd, operation) < 0)
365 return -errno;
366
367 return TAKE_FD(lock_fd);
368 }
369
370 int blockdev_partscan_enabled(int fd) {
371 _cleanup_free_ char *p = NULL, *buf = NULL;
372 unsigned long long ull;
373 struct stat st;
374 int r;
375
376 /* Checks if partition scanning is correctly enabled on the block device */
377
378 if (fstat(fd, &st) < 0)
379 return -errno;
380
381 if (!S_ISBLK(st.st_mode))
382 return -ENOTBLK;
383
384 if (asprintf(&p, "/sys/dev/block/%u:%u/capability", major(st.st_rdev), minor(st.st_rdev)) < 0)
385 return -ENOMEM;
386
387 r = read_one_line_file(p, &buf);
388 if (r == -ENOENT) /* If the capability file doesn't exist then we are most likely looking at a
389 * partition block device, not the whole block device. And that means we have no
390 * partition scanning on for it (we do for its parent, but not for the partition
391 * itself). */
392 return false;
393 if (r < 0)
394 return r;
395
396 r = safe_atollu_full(buf, 16, &ull);
397 if (r < 0)
398 return r;
399
400 #ifndef GENHD_FL_NO_PART_SCAN
401 #define GENHD_FL_NO_PART_SCAN (0x0200)
402 #endif
403
404 return !FLAGS_SET(ull, GENHD_FL_NO_PART_SCAN);
405 }
406
407 static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
408 _cleanup_free_ char *p = NULL, *uuids = NULL;
409 _cleanup_closedir_ DIR *d = NULL;
410 int r, found_encrypted = false;
411
412 assert(sysfs_path);
413
414 if (depth_left == 0)
415 return -EINVAL;
416
417 p = path_join(sysfs_path, "dm/uuid");
418 if (!p)
419 return -ENOMEM;
420
421 r = read_one_line_file(p, &uuids);
422 if (r != -ENOENT) {
423 if (r < 0)
424 return r;
425
426 /* The DM device's uuid attribute is prefixed with "CRYPT-" if this is a dm-crypt device. */
427 if (startswith(uuids, "CRYPT-"))
428 return true;
429 }
430
431 /* Not a dm-crypt device itself. But maybe it is on top of one? Follow the links in the "slaves/"
432 * subdir. */
433
434 p = mfree(p);
435 p = path_join(sysfs_path, "slaves");
436 if (!p)
437 return -ENOMEM;
438
439 d = opendir(p);
440 if (!d) {
441 if (errno == ENOENT) /* Doesn't have underlying devices */
442 return false;
443
444 return -errno;
445 }
446
447 for (;;) {
448 _cleanup_free_ char *q = NULL;
449 struct dirent *de;
450
451 errno = 0;
452 de = readdir_no_dot(d);
453 if (!de) {
454 if (errno != 0)
455 return -errno;
456
457 break; /* No more underlying devices */
458 }
459
460 q = path_join(p, de->d_name);
461 if (!q)
462 return -ENOMEM;
463
464 r = blockdev_is_encrypted(q, depth_left - 1);
465 if (r < 0)
466 return r;
467 if (r == 0) /* we found one that is not encrypted? then propagate that immediately */
468 return false;
469
470 found_encrypted = true;
471 }
472
473 return found_encrypted;
474 }
475
476 int fd_is_encrypted(int fd) {
477 char p[SYS_BLOCK_PATH_MAX(NULL)];
478 dev_t devt;
479 int r;
480
481 r = get_block_device_fd(fd, &devt);
482 if (r < 0)
483 return r;
484 if (r == 0) /* doesn't have a block device */
485 return false;
486
487 xsprintf_sys_block_path(p, NULL, devt);
488
489 return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
490 }
491
492 int path_is_encrypted(const char *path) {
493 char p[SYS_BLOCK_PATH_MAX(NULL)];
494 dev_t devt;
495 int r;
496
497 r = get_block_device(path, &devt);
498 if (r < 0)
499 return r;
500 if (r == 0) /* doesn't have a block device */
501 return false;
502
503 xsprintf_sys_block_path(p, NULL, devt);
504
505 return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
506 }
507
508 int fd_get_whole_disk(int fd, bool backing, dev_t *ret) {
509 dev_t devt;
510 int r;
511
512 assert(fd >= 0);
513 assert(ret);
514
515 r = fd_get_devnum(fd, backing ? BLOCK_DEVICE_LOOKUP_BACKING : 0, &devt);
516 if (r < 0)
517 return r;
518
519 return block_get_whole_disk(devt, ret);
520 }
521
522 int path_get_whole_disk(const char *path, bool backing, dev_t *ret) {
523 _cleanup_close_ int fd = -EBADF;
524
525 fd = open(path, O_CLOEXEC|O_PATH);
526 if (fd < 0)
527 return -errno;
528
529 return fd_get_whole_disk(fd, backing, ret);
530 }
531
532 int block_device_add_partition(
533 int fd,
534 const char *name,
535 int nr,
536 uint64_t start,
537 uint64_t size) {
538
539 assert(fd >= 0);
540 assert(name);
541 assert(nr > 0);
542
543 struct blkpg_partition bp = {
544 .pno = nr,
545 .start = start,
546 .length = size,
547 };
548
549 struct blkpg_ioctl_arg ba = {
550 .op = BLKPG_ADD_PARTITION,
551 .data = &bp,
552 .datalen = sizeof(bp),
553 };
554
555 if (strlen(name) >= sizeof(bp.devname))
556 return -EINVAL;
557
558 strcpy(bp.devname, name);
559
560 return RET_NERRNO(ioctl(fd, BLKPG, &ba));
561 }
562
563 int block_device_remove_partition(
564 int fd,
565 const char *name,
566 int nr) {
567
568 assert(fd >= 0);
569 assert(name);
570 assert(nr > 0);
571
572 struct blkpg_partition bp = {
573 .pno = nr,
574 };
575
576 struct blkpg_ioctl_arg ba = {
577 .op = BLKPG_DEL_PARTITION,
578 .data = &bp,
579 .datalen = sizeof(bp),
580 };
581
582 if (strlen(name) >= sizeof(bp.devname))
583 return -EINVAL;
584
585 strcpy(bp.devname, name);
586
587 return RET_NERRNO(ioctl(fd, BLKPG, &ba));
588 }
589
590 int block_device_resize_partition(
591 int fd,
592 int nr,
593 uint64_t start,
594 uint64_t size) {
595
596 assert(fd >= 0);
597 assert(nr > 0);
598
599 struct blkpg_partition bp = {
600 .pno = nr,
601 .start = start,
602 .length = size,
603 };
604
605 struct blkpg_ioctl_arg ba = {
606 .op = BLKPG_RESIZE_PARTITION,
607 .data = &bp,
608 .datalen = sizeof(bp),
609 };
610
611 return RET_NERRNO(ioctl(fd, BLKPG, &ba));
612 }
613
614 int partition_enumerator_new(sd_device *dev, sd_device_enumerator **ret) {
615 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
616 const char *s;
617 int r;
618
619 assert(dev);
620 assert(ret);
621
622 /* Refuse invocation on partition block device, insist on "whole" device */
623 r = block_device_is_whole_disk(dev);
624 if (r < 0)
625 return r;
626 if (r == 0)
627 return -ENXIO; /* return a recognizable error */
628
629 r = sd_device_enumerator_new(&e);
630 if (r < 0)
631 return r;
632
633 r = sd_device_enumerator_allow_uninitialized(e);
634 if (r < 0)
635 return r;
636
637 r = sd_device_enumerator_add_match_parent(e, dev);
638 if (r < 0)
639 return r;
640
641 r = sd_device_get_sysname(dev, &s);
642 if (r < 0)
643 return r;
644
645 /* Also add sysname check for safety. Hopefully, this also improves performance. */
646 s = strjoina(s, "*");
647 r = sd_device_enumerator_add_match_sysname(e, s);
648 if (r < 0)
649 return r;
650
651 r = sd_device_enumerator_add_match_subsystem(e, "block", /* match = */ true);
652 if (r < 0)
653 return r;
654
655 r = sd_device_enumerator_add_match_property(e, "DEVTYPE", "partition");
656 if (r < 0)
657 return r;
658
659 *ret = TAKE_PTR(e);
660 return 0;
661 }
662
663 int block_device_remove_all_partitions(sd_device *dev, int fd) {
664 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
665 _cleanup_(sd_device_unrefp) sd_device *dev_unref = NULL;
666 _cleanup_close_ int fd_close = -EBADF;
667 bool has_partitions = false;
668 sd_device *part;
669 int r, k = 0;
670
671 assert(dev || fd >= 0);
672
673 if (!dev) {
674 r = block_device_new_from_fd(fd, 0, &dev_unref);
675 if (r < 0)
676 return r;
677
678 dev = dev_unref;
679 }
680
681 r = partition_enumerator_new(dev, &e);
682 if (r < 0)
683 return r;
684
685 if (fd < 0) {
686 fd_close = sd_device_open(dev, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_RDONLY);
687 if (fd_close < 0)
688 return fd_close;
689
690 fd = fd_close;
691 }
692
693 FOREACH_DEVICE(e, part) {
694 const char *v, *devname;
695 int nr;
696
697 has_partitions = true;
698
699 r = sd_device_get_devname(part, &devname);
700 if (r < 0)
701 return r;
702
703 r = sd_device_get_property_value(part, "PARTN", &v);
704 if (r < 0)
705 return r;
706
707 r = safe_atoi(v, &nr);
708 if (r < 0)
709 return r;
710
711 r = btrfs_forget_device(devname);
712 if (r < 0 && r != -ENOENT)
713 log_debug_errno(r, "Failed to forget btrfs device %s, ignoring: %m", devname);
714
715 r = block_device_remove_partition(fd, devname, nr);
716 if (r == -ENODEV) {
717 log_debug("Kernel removed partition %s before us, ignoring", devname);
718 continue;
719 }
720 if (r < 0) {
721 log_debug_errno(r, "Failed to remove partition %s: %m", devname);
722 k = k < 0 ? k : r;
723 continue;
724 }
725
726 log_debug("Removed partition %s", devname);
727 }
728
729 return k < 0 ? k : has_partitions;
730 }
731
732 int block_device_has_partitions(sd_device *dev) {
733 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
734 int r;
735
736 assert(dev);
737
738 /* Checks if the specified device currently has partitions. */
739
740 r = partition_enumerator_new(dev, &e);
741 if (r < 0)
742 return r;
743
744 return !!sd_device_enumerator_get_device_first(e);
745 }
746
747 int blockdev_reread_partition_table(sd_device *dev) {
748 _cleanup_close_ int fd = -EBADF;
749
750 assert(dev);
751
752 /* Try to re-read the partition table. This only succeeds if none of the devices is busy. */
753
754 fd = sd_device_open(dev, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
755 if (fd < 0)
756 return fd;
757
758 if (flock(fd, LOCK_EX|LOCK_NB) < 0)
759 return -errno;
760
761 if (ioctl(fd, BLKRRPART, 0) < 0)
762 return -errno;
763
764 return 0;
765 }
766
767 int blockdev_get_sector_size(int fd, uint32_t *ret) {
768 int ssz = 0;
769
770 assert(fd >= 0);
771 assert(ret);
772
773 if (ioctl(fd, BLKSSZGET, &ssz) < 0)
774 return -errno;
775 if (ssz <= 0) /* make sure the field is initialized */
776 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Block device reported invalid sector size %i.", ssz);
777
778 *ret = ssz;
779 return 0;
780 }
781
782 int blockdev_get_root(int level, dev_t *ret) {
783 _cleanup_free_ char *p = NULL;
784 dev_t devno;
785 int r;
786
787 /* Returns the device node backing the root file system. Traces through
788 * dm-crypt/dm-verity/... Returns > 0 and the devno of the device on success. If there's no block
789 * device (or multiple) returns 0 and a devno of 0. Failure otherwise.
790 *
791 * If the root mount has been replaced by some form of volatile file system (overlayfs), the original
792 * root block device node is symlinked in /run/systemd/volatile-root. Let's read that here. */
793 r = readlink_malloc("/run/systemd/volatile-root", &p);
794 if (r == -ENOENT) { /* volatile-root not found */
795 r = get_block_device_harder("/", &devno);
796 if (r == -EUCLEAN)
797 return btrfs_log_dev_root(level, r, "root file system");
798 if (r < 0)
799 return log_full_errno(level, r, "Failed to determine block device of root file system: %m");
800 if (r == 0) { /* Not backed by a single block device. (Could be NFS or so, or could be multi-device RAID or so) */
801 r = get_block_device_harder("/usr", &devno);
802 if (r == -EUCLEAN)
803 return btrfs_log_dev_root(level, r, "/usr");
804 if (r < 0)
805 return log_full_errno(level, r, "Failed to determine block device of /usr/ file system: %m");
806 if (r == 0) { /* /usr/ not backed by single block device, either. */
807 log_debug("Neither root nor /usr/ file system are on a (single) block device.");
808
809 if (ret)
810 *ret = 0;
811
812 return 0;
813 }
814 }
815 } else if (r < 0)
816 return log_full_errno(level, r, "Failed to read symlink /run/systemd/volatile-root: %m");
817 else {
818 mode_t m;
819 r = device_path_parse_major_minor(p, &m, &devno);
820 if (r < 0)
821 return log_full_errno(level, r, "Failed to parse major/minor device node: %m");
822 if (!S_ISBLK(m))
823 return log_full_errno(level, SYNTHETIC_ERRNO(ENOTBLK), "Volatile root device is of wrong type.");
824 }
825
826 if (ret)
827 *ret = devno;
828
829 return 1;
830 }