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