]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/blockdev-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/statfs.h>
24 #include "alloc-util.h"
25 #include "blockdev-util.h"
26 #include "btrfs-util.h"
27 #include "dirent-util.h"
31 #include "stat-util.h"
33 int block_get_whole_disk(dev_t d
, dev_t
*ret
) {
34 char p
[SYS_BLOCK_PATH_MAX("/partition")];
35 _cleanup_free_
char *s
= NULL
;
41 /* If it has a queue this is good enough for us */
42 xsprintf_sys_block_path(p
, "/queue", d
);
43 if (access(p
, F_OK
) >= 0) {
48 /* If it is a partition find the originating device */
49 xsprintf_sys_block_path(p
, "/partition", d
);
50 if (access(p
, F_OK
) < 0)
53 /* Get parent dev_t */
54 xsprintf_sys_block_path(p
, "/../dev", d
);
55 r
= read_one_line_file(p
, &s
);
59 r
= sscanf(s
, "%u:%u", &m
, &n
);
63 /* Only return this if it is really good enough for us. */
64 xsprintf_sys_block_path(p
, "/queue", makedev(m
, n
));
65 if (access(p
, F_OK
) < 0)
72 int get_block_device(const char *path
, dev_t
*dev
) {
79 /* Get's the block device directly backing a file system. If
80 * the block device is encrypted, returns the device mapper
86 if (major(st
.st_dev
) != 0) {
91 if (statfs(path
, &sfs
) < 0)
94 if (F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
))
95 return btrfs_get_block_device(path
, dev
);
100 int get_block_device_harder(const char *path
, dev_t
*dev
) {
101 _cleanup_closedir_
DIR *d
= NULL
;
102 _cleanup_free_
char *t
= NULL
;
103 char p
[SYS_BLOCK_PATH_MAX("/slaves")];
104 struct dirent
*de
, *found
= NULL
;
113 /* Gets the backing block device for a file system, and
114 * handles LUKS encrypted file systems, looking for its
115 * immediate parent, if there is one. */
117 r
= get_block_device(path
, &dt
);
121 xsprintf_sys_block_path(p
, "/slaves", dt
);
130 FOREACH_DIRENT_ALL(de
, d
, return -errno
) {
132 if (dot_or_dot_dot(de
->d_name
))
135 if (!IN_SET(de
->d_type
, DT_LNK
, DT_UNKNOWN
))
139 _cleanup_free_
char *u
= NULL
, *v
= NULL
, *a
= NULL
, *b
= NULL
;
141 /* We found a device backed by multiple other devices. We don't really support automatic
142 * discovery on such setups, with the exception of dm-verity partitions. In this case there are
143 * two backing devices: the data partition and the hash partition. We are fine with such
144 * setups, however, only if both partitions are on the same physical device. Hence, let's
147 u
= strjoin(p
, "/", de
->d_name
, "/../dev");
151 v
= strjoin(p
, "/", found
->d_name
, "/../dev");
155 r
= read_one_line_file(u
, &a
);
157 log_debug_errno(r
, "Failed to read %s: %m", u
);
161 r
= read_one_line_file(v
, &b
);
163 log_debug_errno(r
, "Failed to read %s: %m", v
);
167 /* Check if the parent device is the same. If not, then the two backing devices are on
168 * different physical devices, and we don't support that. */
179 q
= strjoina(p
, "/", found
->d_name
, "/dev");
181 r
= read_one_line_file(q
, &t
);
187 if (sscanf(t
, "%u:%u", &maj
, &min
) != 2)
193 *dev
= makedev(maj
, min
);