"Fossies" - the Fresh Open Source Software Archive 
Member "cryptsetup-2.4.3/src/utils_blockdev.c" (13 Jan 2022, 7606 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "utils_blockdev.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
2.4.1_vs_2.4.2.
1 /*
2 * Linux block devices helpers
3 *
4 * Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2018-2021 Ondrej Kozina
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include "cryptsetup.h"
23 #include <dirent.h>
24 #ifdef HAVE_SYS_SYSMACROS_H
25 # include <sys/sysmacros.h> /* for major, minor */
26 #endif
27 #include <uuid/uuid.h>
28
29 #define UUID_LEN 37 /* 36 + \0, libuuid ... */
30
31 static int dm_prepare_uuid(const char *type, const char *uuid, char *buf, size_t buflen)
32 {
33 char *ptr, uuid2[UUID_LEN] = {0};
34 uuid_t uu;
35 unsigned i = 0;
36
37 /* Remove '-' chars */
38 if (uuid) {
39 if (uuid_parse(uuid, uu) < 0) {
40 log_dbg("Requested UUID %s has invalid format.", uuid);
41 return 0;
42 }
43
44 for (ptr = uuid2, i = 0; i < UUID_LEN; i++)
45 if (uuid[i] != '-') {
46 *ptr = uuid[i];
47 ptr++;
48 }
49 }
50
51 snprintf(buf, buflen, DM_UUID_PREFIX "%s%s%s%s",
52 type ?: "", type ? "-" : "",
53 uuid2[0] ? uuid2 : "", uuid2[0] ? "-" : "");
54
55 return 1;
56 }
57
58 /* return number of holders in general, if matched dm_uuid prefix it's returned via dm_name */
59 /* negative value is error */
60 static int lookup_holder_dm_name(const char *dm_uuid, dev_t devno, char *dm_name, size_t dm_name_length)
61 {
62 struct dirent *entry;
63 char dm_subpath[PATH_MAX], data_dev_dir[PATH_MAX], uuid[DM_UUID_LEN];
64 ssize_t s;
65 struct stat st;
66 int dmfd, fd, len, r = 0; /* not found */
67 DIR *dir;
68
69 if (!dm_name || !dm_name_length)
70 return -EINVAL;
71
72 *dm_name = '\0';
73
74 len = snprintf(data_dev_dir, PATH_MAX, "/sys/dev/block/%u:%u/holders", major(devno), minor(devno));
75 if (len < 0 || len >= PATH_MAX)
76 return -EINVAL;
77
78 if (!(dir = opendir(data_dev_dir)))
79 /* map ENOTDIR to ENOENT we'll handle both errors same */
80 return errno == ENOTDIR ? -ENOENT : -errno;
81
82 while (r != 1 && (entry = readdir(dir))) {
83 if (entry->d_name[0] == '.' ||
84 !strncmp(entry->d_name, "..", 2))
85 continue;
86
87 /* there's a holder */
88 r++;
89
90 /* we already have a dm_name, just count remaining holders */
91 if (*dm_name != '\0')
92 continue;
93
94 len = snprintf(dm_subpath, PATH_MAX, "%s/%s", entry->d_name, "dm");
95 if (len < 0 || len >= PATH_MAX) {
96 r = -EINVAL;
97 break;
98 }
99
100 /* looking for dm-X/dm directory, symlinks are fine */
101 dmfd = openat(dirfd(dir), dm_subpath, O_DIRECTORY | O_RDONLY);
102 if (dmfd < 0)
103 continue;
104
105 fd = openat(dmfd, "uuid", O_RDONLY);
106 if (fd < 0) {
107 close(dmfd);
108 continue;
109 }
110
111 if (fstat(fd, &st) || !S_ISREG(st.st_mode)) {
112 close(fd);
113 close(dmfd);
114 continue;
115 }
116
117 /* reads binary data */
118 s = read_buffer(fd, uuid, sizeof(uuid) - 1);
119 close(fd);
120 uuid[s > 0 ? s : 0] = '\0';
121 if (!strncmp(uuid, dm_uuid, strlen(dm_uuid)))
122 log_dbg("Found candidate device %s", entry->d_name);
123 else {
124 close(dmfd);
125 continue;
126 }
127
128 fd = openat(dmfd, "name", O_RDONLY);
129 if (fd < 0) {
130 close(dmfd);
131 continue;
132 }
133
134 if (fstat(fd, &st) || !S_ISREG(st.st_mode)) {
135 close(fd);
136 close(dmfd);
137 continue;
138 }
139
140 /* reads binary data */
141 s = read_buffer(fd, dm_name, dm_name_length - 1);
142 close(fd);
143 close(dmfd);
144 if (s > 1) {
145 dm_name[s-1] = '\0';
146 log_dbg("Found dm device %s", dm_name);
147 }
148 }
149
150 closedir(dir);
151
152 return r;
153 }
154
155 int tools_lookup_crypt_device(struct crypt_device *cd, const char *type,
156 const char *data_device_path, char *name, size_t name_length)
157 {
158 int r;
159 char *c;
160 struct stat st;
161 char dev_uuid[DM_UUID_LEN + DM_BY_ID_PREFIX_LEN] = DM_BY_ID_PREFIX;
162
163 if (!dm_prepare_uuid(type, crypt_get_uuid(cd), dev_uuid + DM_BY_ID_PREFIX_LEN, DM_UUID_LEN))
164 return -EINVAL;
165
166 c = strrchr(dev_uuid, '-');
167 if (!c)
168 return -EINVAL;
169
170 /* cut of dm name */
171 *c = '\0';
172
173 log_dbg("Looking for any dm device with prefix: %s", dev_uuid);
174
175 if (stat(data_device_path, &st) < 0)
176 return -ENODEV;
177
178 if (!S_ISBLK(st.st_mode))
179 return -ENOTBLK;
180
181 r = lookup_holder_dm_name(dev_uuid + DM_BY_ID_PREFIX_LEN,
182 st.st_rdev, name, name_length);
183 return r;
184 }
185
186
187 static void report_partition(const char *value, const char *device, bool batch_mode)
188 {
189 if (batch_mode)
190 log_dbg("Device %s already contains a '%s' partition signature.", device, value);
191 else
192 log_std(_("WARNING: Device %s already contains a '%s' partition signature.\n"), device, value);
193 }
194
195 static void report_superblock(const char *value, const char *device, bool batch_mode)
196 {
197 if (batch_mode)
198 log_dbg("Device %s already contains a '%s' superblock signature.", device, value);
199 else
200 log_std(_("WARNING: Device %s already contains a '%s' superblock signature.\n"), device, value);
201 }
202
203 int tools_detect_signatures(const char *device, int ignore_luks, size_t *count, bool batch_mode)
204 {
205 int r;
206 size_t tmp_count;
207 struct blkid_handle *h;
208 blk_probe_status pr;
209
210 if (!count)
211 count = &tmp_count;
212
213 *count = 0;
214
215 if (!blk_supported()) {
216 log_dbg("Blkid support disabled.");
217 return 0;
218 }
219
220 if ((r = blk_init_by_path(&h, device))) {
221 log_err(_("Failed to initialize device signature probes."));
222 return -EINVAL;
223 }
224
225 blk_set_chains_for_full_print(h);
226
227 if (ignore_luks && blk_superblocks_filter_luks(h)) {
228 r = -EINVAL;
229 goto out;
230 }
231
232 while ((pr = blk_probe(h)) < PRB_EMPTY) {
233 if (blk_is_partition(h))
234 report_partition(blk_get_partition_type(h), device, batch_mode);
235 else if (blk_is_superblock(h))
236 report_superblock(blk_get_superblock_type(h), device, batch_mode);
237 else {
238 log_dbg("Internal tools_detect_signatures() error.");
239 r = -EINVAL;
240 goto out;
241 }
242 (*count)++;
243 }
244
245 if (pr == PRB_FAIL)
246 r = -EINVAL;
247 out:
248 blk_free(h);
249 return r;
250 }
251
252 int tools_wipe_all_signatures(const char *path)
253 {
254 int fd, flags, r;
255 blk_probe_status pr;
256 struct stat st;
257 struct blkid_handle *h = NULL;
258
259 if (!blk_supported()) {
260 log_dbg("Blkid support disabled.");
261 return 0;
262 }
263
264 if (stat(path, &st)) {
265 log_err(_("Failed to stat device %s."), path);
266 return -EINVAL;
267 }
268
269 flags = O_RDWR;
270 if (S_ISBLK(st.st_mode))
271 flags |= O_EXCL;
272
273 /* better than opening regular file with O_EXCL (undefined) */
274 /* coverity[toctou] */
275 fd = open(path, flags);
276 if (fd < 0) {
277 if (errno == EBUSY)
278 log_err(_("Device %s is in use. Cannot proceed with format operation."), path);
279 else
280 log_err(_("Failed to open file %s in read/write mode."), path);
281 return -EINVAL;
282 }
283
284 if ((r = blk_init_by_fd(&h, fd))) {
285 log_err(_("Failed to initialize device signature probes."));
286 r = -EINVAL;
287 goto out;
288 }
289
290 blk_set_chains_for_wipes(h);
291
292 while ((pr = blk_probe(h)) < PRB_EMPTY) {
293 if (blk_is_partition(h))
294 log_verbose(_("Existing '%s' partition signature on device %s will be wiped."),
295 blk_get_partition_type(h), path);
296 if (blk_is_superblock(h))
297 log_verbose(_("Existing '%s' superblock signature on device %s will be wiped."),
298 blk_get_superblock_type(h), path);
299 if (blk_do_wipe(h)) {
300 log_err(_("Failed to wipe device signature."));
301 r = -EINVAL;
302 goto out;
303 }
304 }
305
306 if (pr != PRB_EMPTY) {
307 log_err(_("Failed to probe device %s for a signature."), path);
308 r = -EINVAL;
309 }
310 out:
311 close(fd);
312 blk_free(h);
313 return r;
314 }