]>
Commit | Line | Data |
---|---|---|
a0948ffe | 1 | /* |
51410fc6 | 2 | * probe.c - reads tags (LABEL, UUID, FS type, ..) from a block device |
a0948ffe | 3 | * |
51410fc6 | 4 | * Copyright (C) 2008 Karel Zak <kzak@redhat.com> |
a0948ffe | 5 | * |
a0948ffe KZ |
6 | * This file may be redistributed under the terms of the |
7 | * GNU Lesser General Public License. | |
a0948ffe KZ |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
11 | #include <string.h> | |
12 | #include <stdlib.h> | |
13 | #include <unistd.h> | |
14 | #include <fcntl.h> | |
15 | #include <ctype.h> | |
16 | #include <sys/types.h> | |
17 | #ifdef HAVE_SYS_STAT_H | |
18 | #include <sys/stat.h> | |
19 | #endif | |
20 | #ifdef HAVE_SYS_MKDEV_H | |
21 | #include <sys/mkdev.h> | |
22 | #endif | |
a0948ffe KZ |
23 | #ifdef HAVE_ERRNO_H |
24 | #include <errno.h> | |
25 | #endif | |
51410fc6 KZ |
26 | #include <stdint.h> |
27 | #ifdef HAVE_LIBUUID | |
28 | #include <uuid/uuid.h> | |
29 | #endif | |
30 | #include <stdarg.h> | |
a0948ffe | 31 | |
dc61d909 | 32 | #include "blkdev.h" |
51410fc6 KZ |
33 | #include "blkidP.h" |
34 | #include "probers/probers.h" | |
a0948ffe | 35 | |
51410fc6 | 36 | static const struct blkid_idinfo *idinfos[] = |
a0948ffe | 37 | { |
3402fff1 KZ |
38 | /* RAIDs */ |
39 | &linuxraid_idinfo, | |
f8504a4e | 40 | &ddfraid_idinfo, |
56ad7426 | 41 | &iswraid_idinfo, |
dc61d909 | 42 | &lsiraid_idinfo, |
3402fff1 KZ |
43 | &viaraid_idinfo, |
44 | &silraid_idinfo, | |
e86961ba | 45 | &nvraid_idinfo, |
b9938904 | 46 | &pdcraid_idinfo, |
5784db20 KZ |
47 | &highpoint45x_idinfo, |
48 | &highpoint37x_idinfo, | |
3402fff1 KZ |
49 | &adraid_idinfo, |
50 | &jmraid_idinfo, | |
51 | &lvm2_idinfo, | |
f19f9872 | 52 | &lvm1_idinfo, |
06da6d00 | 53 | &luks_idinfo, |
3402fff1 KZ |
54 | |
55 | /* Filesystems */ | |
56 | &vfat_idinfo, | |
57 | &swsuspend_idinfo, | |
58 | &swap_idinfo, | |
59 | &xfs_idinfo, | |
8e7e30e4 KZ |
60 | &ext4dev_idinfo, |
61 | &ext4_idinfo, | |
62 | &ext3_idinfo, | |
63 | &ext2_idinfo, | |
3402fff1 KZ |
64 | &jbd_idinfo, |
65 | &reiser_idinfo, | |
66 | &reiser4_idinfo, | |
80f26373 | 67 | &jfs_idinfo, |
3402fff1 KZ |
68 | &udf_idinfo, |
69 | &iso9660_idinfo, | |
1f4da8d2 | 70 | &zfs_idinfo, |
3402fff1 KZ |
71 | &hfsplus_idinfo, |
72 | &hfs_idinfo, | |
83b935ae | 73 | &ufs_idinfo, |
e134f470 | 74 | &hpfs_idinfo, |
d1e9e1e4 KZ |
75 | &sysv_idinfo, |
76 | &xenix_idinfo, | |
3402fff1 KZ |
77 | &ntfs_idinfo, |
78 | &cramfs_idinfo, | |
79 | &romfs_idinfo, | |
681ff570 | 80 | &minix_idinfo, |
81f81873 KZ |
81 | &gfs_idinfo, |
82 | &gfs2_idinfo, | |
7fd65bed KZ |
83 | &ocfs_idinfo, |
84 | &ocfs2_idinfo, | |
85 | &oracleasm_idinfo, | |
c29368b4 | 86 | &vxfs_idinfo, |
fc954eb5 | 87 | &squashfs_idinfo, |
990b429a KZ |
88 | &netware_idinfo, |
89 | &btrfs_idinfo | |
51410fc6 | 90 | }; |
a0948ffe | 91 | |
51410fc6 KZ |
92 | #ifndef ARRAY_SIZE |
93 | # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | |
94 | #endif | |
a0948ffe | 95 | |
51410fc6 KZ |
96 | /* filter bitmap macros */ |
97 | #define blkid_bmp_wordsize (8 * sizeof(unsigned long)) | |
98 | #define blkid_bmp_idx_bit(item) (1UL << ((item) % blkid_bmp_wordsize)) | |
99 | #define blkid_bmp_idx_byte(item) ((item) / blkid_bmp_wordsize) | |
a0948ffe | 100 | |
51410fc6 KZ |
101 | #define blkid_bmp_set_item(bmp, item) \ |
102 | ((bmp)[ blkid_bmp_idx_byte(item) ] |= blkid_bmp_idx_bit(item)) | |
a0948ffe | 103 | |
51410fc6 KZ |
104 | #define blkid_bmp_unset_item(bmp, item) \ |
105 | ((bmp)[ bmp_idx_byte(item) ] &= ~bmp_idx_bit(item)) | |
a0948ffe | 106 | |
51410fc6 KZ |
107 | #define blkid_bmp_get_item(bmp, item) \ |
108 | ((bmp)[ blkid_bmp_idx_byte(item) ] & blkid_bmp_idx_bit(item)) | |
a0948ffe | 109 | |
51410fc6 KZ |
110 | #define blkid_bmp_size(max_items) \ |
111 | (((max_items) + blkid_bmp_wordsize) / blkid_bmp_wordsize) | |
a0948ffe | 112 | |
51410fc6 KZ |
113 | #define BLKID_FLTR_ITEMS ARRAY_SIZE(idinfos) |
114 | #define BLKID_FLTR_SIZE blkid_bmp_size(BLKID_FLTR_ITEMS) | |
a0948ffe | 115 | |
a0948ffe | 116 | |
51410fc6 | 117 | static int blkid_probe_set_usage(blkid_probe pr, int usage); |
a0948ffe | 118 | |
51410fc6 | 119 | int blkid_known_fstype(const char *fstype) |
a0948ffe | 120 | { |
51410fc6 | 121 | int i; |
a0948ffe | 122 | |
51410fc6 KZ |
123 | if (!fstype) |
124 | return 0; | |
a0948ffe | 125 | |
51410fc6 KZ |
126 | for (i = 0; i < ARRAY_SIZE(idinfos); i++) { |
127 | const struct blkid_idinfo *id = idinfos[i]; | |
128 | if (strcmp(id->name, fstype) == 0) | |
129 | return 1; | |
130 | } | |
131 | return 0; | |
a0948ffe KZ |
132 | } |
133 | ||
134 | /* | |
51410fc6 | 135 | * Returns a pointer to the newly allocated probe struct |
a0948ffe | 136 | */ |
51410fc6 | 137 | blkid_probe blkid_new_probe(void) |
a0948ffe | 138 | { |
7a458332 | 139 | blkid_init_debug(0); |
51410fc6 | 140 | return calloc(1, sizeof(struct blkid_struct_probe)); |
a0948ffe KZ |
141 | } |
142 | ||
143 | /* | |
51410fc6 KZ |
144 | * Deallocates probe struct, buffers and all allocated |
145 | * data that are associated with this probing control struct. | |
a0948ffe | 146 | */ |
51410fc6 | 147 | void blkid_free_probe(blkid_probe pr) |
a0948ffe | 148 | { |
51410fc6 KZ |
149 | if (!pr) |
150 | return; | |
151 | free(pr->fltr); | |
152 | free(pr->buf); | |
153 | free(pr->sbbuf); | |
154 | free(pr); | |
a0948ffe KZ |
155 | } |
156 | ||
51410fc6 | 157 | static void blkid_probe_reset_vals(blkid_probe pr) |
a0948ffe | 158 | { |
51410fc6 KZ |
159 | memset(pr->vals, 0, sizeof(pr->vals)); |
160 | pr->nvals = 0; | |
a0948ffe KZ |
161 | } |
162 | ||
4ce48a97 KZ |
163 | static void blkid_probe_reset_idx(blkid_probe pr) |
164 | { | |
165 | pr->idx = -1; | |
166 | } | |
167 | ||
51410fc6 | 168 | void blkid_reset_probe(blkid_probe pr) |
a0948ffe | 169 | { |
51410fc6 KZ |
170 | if (!pr) |
171 | return; | |
6644688a | 172 | DBG(DEBUG_LOWPROBE, printf("reseting blkid_probe\n")); |
51410fc6 KZ |
173 | if (pr->buf) |
174 | memset(pr->buf, 0, pr->buf_max); | |
175 | pr->buf_off = 0; | |
176 | pr->buf_len = 0; | |
177 | if (pr->sbbuf) | |
178 | memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ); | |
179 | pr->sbbuf_len = 0; | |
180 | blkid_probe_reset_vals(pr); | |
4ce48a97 | 181 | blkid_probe_reset_idx(pr); |
a0948ffe KZ |
182 | } |
183 | ||
51410fc6 KZ |
184 | /* |
185 | * Note that we have two offsets: | |
186 | * | |
187 | * 1/ general device offset (pr->off), that's useful for example when we | |
188 | * probe a partition from whole disk image: | |
189 | * blkid-low --offset <partition_position> disk.img | |
190 | * | |
191 | * 2/ buffer offset (the 'off' argument), that useful for offsets in | |
192 | * superbloks, ... | |
193 | * | |
194 | * That means never use lseek(fd, 0, SEEK_SET), the zero position is always | |
195 | * pr->off, so lseek(fd, pr->off, SEEK_SET). | |
196 | * | |
197 | */ | |
198 | unsigned char *blkid_probe_get_buffer(blkid_probe pr, | |
199 | blkid_loff_t off, blkid_loff_t len) | |
a0948ffe | 200 | { |
51410fc6 | 201 | ssize_t ret_read = 0; |
a0948ffe | 202 | |
4884729a KZ |
203 | if (off < 0 || len < 0) { |
204 | DBG(DEBUG_LOWPROBE, | |
205 | printf("unexpected offset or length of buffer requested\n")); | |
206 | return NULL; | |
207 | } | |
51410fc6 KZ |
208 | if (off + len <= BLKID_SB_BUFSIZ) { |
209 | if (!pr->sbbuf) { | |
210 | pr->sbbuf = malloc(BLKID_SB_BUFSIZ); | |
211 | if (!pr->sbbuf) | |
212 | return NULL; | |
213 | } | |
214 | if (!pr->sbbuf_len) { | |
215 | if (lseek(pr->fd, pr->off, SEEK_SET) < 0) | |
216 | return NULL; | |
217 | ret_read = read(pr->fd, pr->sbbuf, BLKID_SB_BUFSIZ); | |
218 | if (ret_read < 0) | |
219 | ret_read = 0; | |
220 | pr->sbbuf_len = ret_read; | |
221 | } | |
222 | if (off + len > pr->sbbuf_len) | |
223 | return NULL; | |
224 | return pr->sbbuf + off; | |
225 | } else { | |
226 | unsigned char *newbuf = NULL; | |
227 | ||
228 | if (len > pr->buf_max) { | |
229 | newbuf = realloc(pr->buf, len); | |
230 | if (!newbuf) | |
231 | return NULL; | |
232 | pr->buf = newbuf; | |
233 | pr->buf_max = len; | |
234 | pr->buf_off = 0; | |
235 | pr->buf_len = 0; | |
236 | } | |
237 | if (newbuf || off < pr->buf_off || | |
238 | off + len > pr->buf_off + pr->buf_len) { | |
239 | ||
240 | if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) | |
241 | return NULL; | |
242 | ||
243 | ret_read = read(pr->fd, pr->buf, len); | |
244 | if (ret_read != (ssize_t) len) | |
245 | return NULL; | |
246 | pr->buf_off = off; | |
247 | pr->buf_len = len; | |
248 | } | |
249 | return off ? pr->buf + (off - pr->buf_off) : pr->buf; | |
250 | } | |
a0948ffe KZ |
251 | } |
252 | ||
51410fc6 KZ |
253 | /* |
254 | * Assignes the device to probe control struct, resets internal buffers and | |
255 | * reads 512 bytes from device to the buffers. | |
256 | * | |
257 | * Returns -1 in case of failure, or 0 on success. | |
258 | */ | |
259 | int blkid_probe_set_device(blkid_probe pr, int fd, | |
260 | blkid_loff_t off, blkid_loff_t size) | |
a0948ffe | 261 | { |
51410fc6 KZ |
262 | if (!pr) |
263 | return -1; | |
a0948ffe | 264 | |
51410fc6 | 265 | blkid_reset_probe(pr); |
a0948ffe | 266 | |
51410fc6 KZ |
267 | pr->fd = fd; |
268 | pr->off = off; | |
bb6c6673 | 269 | pr->size = 0; |
dc61d909 | 270 | |
bb6c6673 | 271 | if (size) |
dc61d909 | 272 | pr->size = size; |
bb6c6673 KZ |
273 | else { |
274 | struct stat sb; | |
275 | ||
276 | if (fstat(fd, &sb)) | |
277 | return -1; | |
278 | ||
279 | if (S_ISBLK(sb.st_mode)) | |
280 | blkdev_get_size(fd, (unsigned long long *) &pr->size); | |
281 | else | |
282 | pr->size = sb.st_size; | |
283 | } | |
284 | if (!pr->size) | |
285 | return -1; | |
a0948ffe | 286 | |
51410fc6 | 287 | /* read SB to test if the device is readable */ |
6644688a KZ |
288 | if (!blkid_probe_get_buffer(pr, 0, 0x200)) { |
289 | DBG(DEBUG_LOWPROBE, | |
290 | printf("failed to prepare a device for low-probing\n")); | |
51410fc6 | 291 | return -1; |
6644688a | 292 | } |
a0948ffe | 293 | |
bb6c6673 KZ |
294 | DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n", |
295 | pr->off, pr->size)); | |
a0948ffe KZ |
296 | return 0; |
297 | } | |
298 | ||
51410fc6 | 299 | int blkid_probe_set_request(blkid_probe pr, int flags) |
a0948ffe | 300 | { |
51410fc6 KZ |
301 | if (!pr) |
302 | return -1; | |
303 | pr->probreq = flags; | |
a0948ffe KZ |
304 | return 0; |
305 | } | |
306 | ||
51410fc6 | 307 | int blkid_probe_reset_filter(blkid_probe pr) |
a0948ffe | 308 | { |
51410fc6 KZ |
309 | if (!pr) |
310 | return -1; | |
311 | if (pr->fltr) | |
312 | memset(pr->fltr, 0, BLKID_FLTR_SIZE * sizeof(unsigned long)); | |
4ce48a97 | 313 | blkid_probe_reset_idx(pr); |
a0948ffe KZ |
314 | return 0; |
315 | } | |
316 | ||
51410fc6 KZ |
317 | /* |
318 | * flag: | |
319 | * | |
320 | * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN names[] | |
321 | * | |
322 | * BLKID_FLTR_ONLYIN - probe filesystem which are IN names[] | |
323 | */ | |
324 | int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[]) | |
a0948ffe | 325 | { |
51410fc6 | 326 | int i; |
a0948ffe | 327 | |
51410fc6 KZ |
328 | if (!pr || !names) |
329 | return -1; | |
4ce48a97 | 330 | if (!pr->fltr) { |
51410fc6 | 331 | pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long)); |
4ce48a97 KZ |
332 | blkid_probe_reset_idx(pr); |
333 | } else | |
51410fc6 | 334 | blkid_probe_reset_filter(pr); |
a0948ffe | 335 | |
deedaa30 KZ |
336 | if (!pr->fltr) |
337 | return -1; | |
338 | ||
51410fc6 KZ |
339 | for (i = 0; i < ARRAY_SIZE(idinfos); i++) { |
340 | int has = 0; | |
341 | const struct blkid_idinfo *id = idinfos[i]; | |
342 | char **n; | |
a0948ffe | 343 | |
51410fc6 KZ |
344 | for (n = names; *n; n++) { |
345 | if (!strcmp(id->name, *n)) { | |
346 | has = 1; | |
a0948ffe | 347 | break; |
51410fc6 KZ |
348 | } |
349 | } | |
350 | /* The default is enable all filesystems, | |
351 | * set relevant bitmap bit means disable the filesystem. | |
352 | */ | |
353 | if (flag & BLKID_FLTR_ONLYIN) { | |
354 | if (!has) | |
355 | blkid_bmp_set_item(pr->fltr, i); | |
356 | } else if (flag & BLKID_FLTR_NOTIN) { | |
357 | if (has) | |
358 | blkid_bmp_set_item(pr->fltr, i); | |
a0948ffe | 359 | } |
a0948ffe | 360 | } |
6644688a | 361 | DBG(DEBUG_LOWPROBE, printf("a new probing type-filter initialized\n")); |
a0948ffe KZ |
362 | return 0; |
363 | } | |
364 | ||
365 | /* | |
51410fc6 KZ |
366 | * flag: |
367 | * | |
368 | * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN "usage" | |
369 | * | |
370 | * BLKID_FLTR_ONLYIN - probe filesystem which are IN "usage" | |
371 | * | |
372 | * where the "usage" is a set of filesystem according the usage flag (crypto, | |
373 | * raid, filesystem, ...) | |
a0948ffe | 374 | */ |
51410fc6 | 375 | int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage) |
a0948ffe | 376 | { |
51410fc6 | 377 | int i; |
a0948ffe | 378 | |
51410fc6 KZ |
379 | if (!pr || !usage) |
380 | return -1; | |
4ce48a97 | 381 | if (!pr->fltr) { |
51410fc6 | 382 | pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long)); |
4ce48a97 KZ |
383 | blkid_probe_reset_idx(pr); |
384 | } else | |
51410fc6 | 385 | blkid_probe_reset_filter(pr); |
a0948ffe | 386 | |
deedaa30 KZ |
387 | if (!pr->fltr) |
388 | return -1; | |
389 | ||
51410fc6 KZ |
390 | for (i = 0; i < ARRAY_SIZE(idinfos); i++) { |
391 | const struct blkid_idinfo *id = idinfos[i]; | |
a0948ffe | 392 | |
51410fc6 KZ |
393 | if (id->usage & usage) { |
394 | if (flag & BLKID_FLTR_NOTIN) | |
395 | blkid_bmp_set_item(pr->fltr, i); | |
396 | } else if (flag & BLKID_FLTR_ONLYIN) | |
397 | blkid_bmp_set_item(pr->fltr, i); | |
a0948ffe | 398 | } |
6644688a | 399 | DBG(DEBUG_LOWPROBE, printf("a new probing usage-filter initialized\n")); |
a0948ffe KZ |
400 | return 0; |
401 | } | |
402 | ||
403 | ||
51410fc6 | 404 | int blkid_probe_invert_filter(blkid_probe pr) |
a0948ffe | 405 | { |
51410fc6 | 406 | int i; |
a0948ffe | 407 | |
51410fc6 KZ |
408 | if (!pr || !pr->fltr) |
409 | return -1; | |
410 | for (i = 0; i < BLKID_FLTR_SIZE; i++) | |
411 | pr->fltr[i] = ~pr->fltr[i]; | |
a0fc685c | 412 | |
4ce48a97 | 413 | blkid_probe_reset_idx(pr); |
6644688a | 414 | DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n")); |
a0948ffe KZ |
415 | return 0; |
416 | } | |
417 | ||
a0fc685c KZ |
418 | /* |
419 | * The blkid_do_probe() calls the probe functions. This routine could be used | |
420 | * in a loop when you need to probe for all possible filesystems/raids. | |
421 | * | |
422 | * 1/ basic case -- use the first result: | |
423 | * | |
424 | * if (blkid_do_probe(pr) == 0) { | |
425 | * int nvals = blkid_probe_numof_values(pr); | |
426 | * for (n = 0; n < nvals; n++) { | |
427 | * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0) | |
428 | * printf("%s = %s\n", name, data); | |
429 | * } | |
430 | * } | |
431 | * | |
432 | * 2/ advanced case -- probe for all signatures (don't forget that some | |
433 | * filesystems can co-exist on one volume (e.g. CD-ROM). | |
434 | * | |
435 | * while (blkid_do_probe(pr) == 0) { | |
436 | * int nvals = blkid_probe_numof_values(pr); | |
437 | * ... | |
438 | * } | |
439 | * | |
440 | * The internal probing index (pointer to the last probing function) is | |
441 | * always reseted when you touch probing filter or set a new device. It | |
442 | * means you cannot use: | |
443 | * | |
444 | * blkid_probe_invert_filter() | |
445 | * blkid_probe_filter_usage() | |
446 | * blkid_probe_filter_types() | |
447 | * blkid_probe_reset_filter() | |
448 | * blkid_probe_set_device() | |
449 | * | |
450 | * in the loop (e.g while()) when you iterate on all signatures. | |
451 | */ | |
51410fc6 | 452 | int blkid_do_probe(blkid_probe pr) |
a0948ffe | 453 | { |
a0fc685c | 454 | int i = 0; |
a0948ffe | 455 | |
51410fc6 KZ |
456 | if (!pr) |
457 | return -1; | |
a0948ffe | 458 | |
51410fc6 | 459 | blkid_probe_reset_vals(pr); |
a0948ffe | 460 | |
4ce48a97 | 461 | i = pr->idx + 1; |
a0fc685c | 462 | |
87aab0e1 KZ |
463 | if (i < 0 && i >= ARRAY_SIZE(idinfos)) |
464 | return -1; | |
465 | ||
92163c45 | 466 | DBG(DEBUG_LOWPROBE, printf("--> starting probing loop\n")); |
6644688a | 467 | |
a2f01a1c | 468 | for ( ; i < ARRAY_SIZE(idinfos); i++) { |
51410fc6 KZ |
469 | const struct blkid_idinfo *id; |
470 | const struct blkid_idmag *mag; | |
2d4f7576 | 471 | int hasmag = 0; |
a0948ffe | 472 | |
a0fc685c KZ |
473 | pr->idx = i; |
474 | ||
51410fc6 KZ |
475 | if (pr->fltr && blkid_bmp_get_item(pr->fltr, i)) |
476 | continue; | |
a0948ffe | 477 | |
51410fc6 KZ |
478 | id = idinfos[i]; |
479 | mag = id->magics ? &id->magics[0] : NULL; | |
a0948ffe | 480 | |
51410fc6 KZ |
481 | /* try to detect by magic string */ |
482 | while(mag && mag->magic) { | |
483 | int idx; | |
484 | unsigned char *buf; | |
a0948ffe | 485 | |
51410fc6 KZ |
486 | idx = mag->kboff + (mag->sboff >> 10); |
487 | buf = blkid_probe_get_buffer(pr, idx << 10, 1024); | |
a0948ffe | 488 | |
51410fc6 | 489 | if (buf && !memcmp(mag->magic, |
6644688a KZ |
490 | buf + (mag->sboff & 0x3ff), mag->len)) { |
491 | DBG(DEBUG_LOWPROBE, printf( | |
92163c45 KZ |
492 | "%s: magic sboff=%u, kboff=%ld\n", |
493 | id->name, mag->sboff, mag->kboff)); | |
2d4f7576 | 494 | hasmag = 1; |
51410fc6 | 495 | break; |
6644688a | 496 | } |
51410fc6 KZ |
497 | mag++; |
498 | } | |
a0948ffe | 499 | |
2d4f7576 | 500 | if (hasmag == 0 && id->magics && id->magics[0].magic) |
51410fc6 KZ |
501 | /* magic string(s) defined, but not found */ |
502 | continue; | |
a0948ffe | 503 | |
51410fc6 | 504 | /* final check by probing function */ |
6644688a KZ |
505 | if (id->probefunc) { |
506 | DBG(DEBUG_LOWPROBE, printf( | |
92163c45 | 507 | "%s: call probefunc()\n", id->name)); |
6644688a KZ |
508 | if (id->probefunc(pr, mag) != 0) |
509 | continue; | |
510 | } | |
a0948ffe | 511 | |
51410fc6 KZ |
512 | /* all cheks passed */ |
513 | if (pr->probreq & BLKID_PROBREQ_TYPE) | |
514 | blkid_probe_set_value(pr, "TYPE", | |
515 | (unsigned char *) id->name, | |
516 | strlen(id->name) + 1); | |
51410fc6 KZ |
517 | if (pr->probreq & BLKID_PROBREQ_USAGE) |
518 | blkid_probe_set_usage(pr, id->usage); | |
a0948ffe | 519 | |
5b6215b5 | 520 | DBG(DEBUG_LOWPROBE, |
92163c45 | 521 | printf("<-- leaving probing loop (type=%s)\n", id->name)); |
51410fc6 KZ |
522 | return 0; |
523 | } | |
92163c45 | 524 | DBG(DEBUG_LOWPROBE, printf("<-- leaving probing loop (failed)\n")); |
51410fc6 | 525 | return 1; |
a0948ffe KZ |
526 | } |
527 | ||
a2f01a1c KZ |
528 | /* |
529 | * This is the same function as blkid_do_probe(), but returns only one result | |
530 | * (cannot be used in while()) and checks for ambivalen results (more | |
531 | * filesystems on the device) -- in such case returns -2. | |
532 | */ | |
533 | int blkid_do_safeprobe(blkid_probe pr) | |
534 | { | |
535 | struct blkid_struct_probe first; | |
536 | int count = 0; | |
537 | int intol = 0; | |
538 | int rc; | |
539 | ||
540 | while ((rc = blkid_do_probe(pr)) == 0) { | |
541 | if (!count) { | |
542 | /* store the fist result */ | |
543 | memcpy(first.vals, pr->vals, sizeof(first.vals)); | |
544 | first.nvals = pr->nvals; | |
545 | first.idx = pr->idx; | |
546 | } | |
547 | if (!(idinfos[pr->idx]->flags & BLKID_IDINFO_TOLERANT)) | |
548 | intol++; | |
549 | count++; | |
550 | } | |
551 | if (rc < 0) | |
552 | return rc; /* error */ | |
92163c45 KZ |
553 | if (count > 1 && intol) { |
554 | DBG(DEBUG_LOWPROBE, | |
555 | printf("ERROR: ambivalent result detected (%d filesystems)!\n", | |
556 | count)); | |
a2f01a1c | 557 | return -2; /* error, ambivalent result (more FS) */ |
92163c45 | 558 | } |
a2f01a1c KZ |
559 | if (!count) |
560 | return 1; /* nothing detected */ | |
561 | ||
562 | /* restore the first result */ | |
563 | memcpy(pr->vals, first.vals, sizeof(first.vals)); | |
564 | pr->nvals = first.nvals; | |
565 | pr->idx = first.idx; | |
566 | ||
567 | return 0; | |
568 | } | |
569 | ||
51410fc6 | 570 | int blkid_probe_numof_values(blkid_probe pr) |
a0948ffe | 571 | { |
51410fc6 KZ |
572 | if (!pr) |
573 | return -1; | |
574 | return pr->nvals; | |
a0948ffe KZ |
575 | } |
576 | ||
a0948ffe | 577 | |
51410fc6 KZ |
578 | static struct blkid_prval *blkid_probe_assign_value( |
579 | blkid_probe pr, const char *name) | |
a0948ffe | 580 | { |
51410fc6 | 581 | struct blkid_prval *v; |
a0948ffe | 582 | |
51410fc6 KZ |
583 | if (!name) |
584 | return NULL; | |
585 | if (pr->nvals >= BLKID_PROBVAL_NVALS) | |
586 | return NULL; | |
a0948ffe | 587 | |
51410fc6 KZ |
588 | v = &pr->vals[pr->nvals]; |
589 | v->name = name; | |
590 | pr->nvals++; | |
6644688a | 591 | |
5b6215b5 | 592 | DBG(DEBUG_LOWPROBE, printf("assigning %s\n", name)); |
51410fc6 | 593 | return v; |
a0948ffe KZ |
594 | } |
595 | ||
51410fc6 KZ |
596 | int blkid_probe_set_value(blkid_probe pr, const char *name, |
597 | unsigned char *data, size_t len) | |
a0948ffe | 598 | { |
51410fc6 | 599 | struct blkid_prval *v; |
a0948ffe | 600 | |
51410fc6 KZ |
601 | if (len > BLKID_PROBVAL_BUFSIZ) |
602 | len = BLKID_PROBVAL_BUFSIZ; | |
a0948ffe | 603 | |
51410fc6 KZ |
604 | v = blkid_probe_assign_value(pr, name); |
605 | if (!v) | |
606 | return -1; | |
a0948ffe | 607 | |
51410fc6 KZ |
608 | memcpy(v->data, data, len); |
609 | v->len = len; | |
a0948ffe KZ |
610 | return 0; |
611 | } | |
612 | ||
51410fc6 KZ |
613 | int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, |
614 | const char *fmt, va_list ap) | |
a0948ffe | 615 | { |
51410fc6 KZ |
616 | struct blkid_prval *v; |
617 | size_t len; | |
a0948ffe | 618 | |
51410fc6 KZ |
619 | v = blkid_probe_assign_value(pr, name); |
620 | if (!v) | |
621 | return -1; | |
a0948ffe | 622 | |
51410fc6 | 623 | len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap); |
a0948ffe | 624 | |
51410fc6 KZ |
625 | if (len <= 0) { |
626 | pr->nvals--; /* reset the latest assigned value */ | |
627 | return -1; | |
a0948ffe | 628 | } |
51410fc6 | 629 | v->len = len + 1; |
a0948ffe KZ |
630 | return 0; |
631 | } | |
632 | ||
51410fc6 | 633 | int blkid_probe_set_version(blkid_probe pr, const char *version) |
a0948ffe | 634 | { |
51410fc6 KZ |
635 | if (pr->probreq & BLKID_PROBREQ_VERSION) |
636 | return blkid_probe_set_value(pr, "VERSION", | |
637 | (unsigned char *) version, strlen(version) + 1); | |
a0948ffe KZ |
638 | return 0; |
639 | } | |
640 | ||
51410fc6 | 641 | int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...) |
a0948ffe | 642 | { |
51410fc6 | 643 | int rc = 0; |
a0948ffe | 644 | |
51410fc6 KZ |
645 | if (pr->probreq & BLKID_PROBREQ_VERSION) { |
646 | va_list ap; | |
a0948ffe | 647 | |
51410fc6 KZ |
648 | va_start(ap, fmt); |
649 | rc = blkid_probe_vsprintf_value(pr, "VERSION", fmt, ap); | |
650 | va_end(ap); | |
651 | } | |
652 | return rc; | |
a0948ffe KZ |
653 | } |
654 | ||
51410fc6 | 655 | static int blkid_probe_set_usage(blkid_probe pr, int usage) |
a0948ffe | 656 | { |
51410fc6 | 657 | char *u = NULL; |
a0948ffe | 658 | |
51410fc6 KZ |
659 | if (usage & BLKID_USAGE_FILESYSTEM) |
660 | u = "filesystem"; | |
661 | else if (usage & BLKID_USAGE_RAID) | |
662 | u = "raid"; | |
663 | else if (usage & BLKID_USAGE_CRYPTO) | |
664 | u = "crypto"; | |
665 | else if (usage & BLKID_USAGE_OTHER) | |
666 | u = "other"; | |
667 | else | |
668 | u = "unknown"; | |
a0948ffe | 669 | |
51410fc6 | 670 | return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1); |
a0948ffe KZ |
671 | } |
672 | ||
51410fc6 | 673 | int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len) |
a0948ffe | 674 | { |
51410fc6 KZ |
675 | struct blkid_prval *v; |
676 | int i; | |
a0948ffe | 677 | |
409b115d KZ |
678 | if (len > BLKID_PROBVAL_BUFSIZ) |
679 | len = BLKID_PROBVAL_BUFSIZ; | |
680 | ||
51410fc6 KZ |
681 | if ((pr->probreq & BLKID_PROBREQ_LABELRAW) && |
682 | blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0) | |
683 | return -1; | |
684 | if (!(pr->probreq & BLKID_PROBREQ_LABEL)) | |
685 | return 0; | |
686 | v = blkid_probe_assign_value(pr, "LABEL"); | |
687 | if (!v) | |
688 | return -1; | |
a0948ffe | 689 | |
51410fc6 KZ |
690 | memcpy(v->data, label, len); |
691 | v->data[len] = '\0'; | |
a0948ffe | 692 | |
51410fc6 KZ |
693 | /* remove trailing whitespace */ |
694 | i = strnlen((char *) v->data, len); | |
695 | while (i--) { | |
696 | if (!isspace(v->data[i])) | |
697 | break; | |
a0948ffe | 698 | } |
51410fc6 KZ |
699 | v->data[++i] = '\0'; |
700 | v->len = i + 1; | |
701 | return 0; | |
a0948ffe KZ |
702 | } |
703 | ||
51410fc6 KZ |
704 | static size_t encode_to_utf8(int enc, unsigned char *dest, size_t len, |
705 | unsigned char *src, size_t count) | |
a0948ffe | 706 | { |
51410fc6 KZ |
707 | size_t i, j; |
708 | uint16_t c; | |
a0948ffe | 709 | |
2a0f4c4e | 710 | for (j = i = 0; i + 2 <= count; i += 2) { |
51410fc6 KZ |
711 | if (enc == BLKID_ENC_UTF16LE) |
712 | c = (src[i+1] << 8) | src[i]; | |
713 | else /* BLKID_ENC_UTF16BE */ | |
714 | c = (src[i] << 8) | src[i+1]; | |
a0948ffe | 715 | if (c == 0) { |
51410fc6 | 716 | dest[j] = '\0'; |
a0948ffe KZ |
717 | break; |
718 | } else if (c < 0x80) { | |
51410fc6 | 719 | if (j+1 >= len) |
a0948ffe | 720 | break; |
51410fc6 | 721 | dest[j++] = (uint8_t) c; |
a0948ffe | 722 | } else if (c < 0x800) { |
51410fc6 | 723 | if (j+2 >= len) |
a0948ffe | 724 | break; |
51410fc6 KZ |
725 | dest[j++] = (uint8_t) (0xc0 | (c >> 6)); |
726 | dest[j++] = (uint8_t) (0x80 | (c & 0x3f)); | |
a0948ffe | 727 | } else { |
51410fc6 | 728 | if (j+3 >= len) |
a0948ffe | 729 | break; |
51410fc6 KZ |
730 | dest[j++] = (uint8_t) (0xe0 | (c >> 12)); |
731 | dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); | |
732 | dest[j++] = (uint8_t) (0x80 | (c & 0x3f)); | |
a0948ffe KZ |
733 | } |
734 | } | |
51410fc6 KZ |
735 | dest[j] = '\0'; |
736 | return j; | |
a0948ffe KZ |
737 | } |
738 | ||
51410fc6 KZ |
739 | int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label, |
740 | size_t len, int enc) | |
a0948ffe | 741 | { |
51410fc6 KZ |
742 | struct blkid_prval *v; |
743 | ||
744 | if ((pr->probreq & BLKID_PROBREQ_LABELRAW) && | |
745 | blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0) | |
746 | return -1; | |
747 | if (!(pr->probreq & BLKID_PROBREQ_LABEL)) | |
748 | return 0; | |
749 | v = blkid_probe_assign_value(pr, "LABEL"); | |
750 | if (!v) | |
751 | return -1; | |
2a0f4c4e | 752 | |
51410fc6 | 753 | v->len = encode_to_utf8(enc, v->data, sizeof(v->data), label, len); |
a0948ffe KZ |
754 | return 0; |
755 | } | |
756 | ||
51410fc6 KZ |
757 | /* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */ |
758 | static int uuid_is_empty(const unsigned char *buf, size_t len) | |
a0948ffe | 759 | { |
51410fc6 | 760 | int i; |
a0948ffe | 761 | |
51410fc6 KZ |
762 | for (i = 0; i < len; i++) |
763 | if (buf[i]) | |
764 | return 0; | |
765 | return 1; | |
766 | } | |
a0948ffe | 767 | |
51410fc6 KZ |
768 | int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid, |
769 | size_t len, const char *fmt, ...) | |
770 | { | |
409b115d | 771 | int rc = -1; |
51410fc6 | 772 | va_list ap; |
409b115d KZ |
773 | |
774 | if (len > BLKID_PROBVAL_BUFSIZ) | |
775 | len = BLKID_PROBVAL_BUFSIZ; | |
a0948ffe | 776 | |
51410fc6 | 777 | if (uuid_is_empty(uuid, len)) |
a0948ffe KZ |
778 | return 0; |
779 | ||
51410fc6 KZ |
780 | if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) && |
781 | blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0) | |
782 | return -1; | |
783 | if (!(pr->probreq & BLKID_PROBREQ_UUID)) | |
a0948ffe KZ |
784 | return 0; |
785 | ||
51410fc6 | 786 | va_start(ap, fmt); |
bb6c6673 | 787 | rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap); |
51410fc6 | 788 | va_end(ap); |
a0948ffe | 789 | |
51410fc6 KZ |
790 | /* convert to lower case (..be paranoid) */ |
791 | if (!rc) { | |
792 | int i; | |
793 | struct blkid_prval *v = &pr->vals[pr->nvals]; | |
a0948ffe | 794 | |
51410fc6 KZ |
795 | for (i = 0; i < v->len; i++) |
796 | if (v->data[i] >= 'A' && v->data[i] <= 'F') | |
797 | v->data[i] = (v->data[i] - 'A') + 'a'; | |
a0948ffe | 798 | } |
51410fc6 KZ |
799 | return rc; |
800 | } | |
a0948ffe | 801 | |
bb6c6673 KZ |
802 | /* function to set UUIDs that are in suberblocks stored as strings */ |
803 | int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len) | |
804 | { | |
805 | struct blkid_prval *v; | |
806 | ||
807 | if (str == NULL || *str == '\0') | |
808 | return -1; | |
809 | if (!len) | |
810 | len = strlen((char *) str); | |
811 | if (len > BLKID_PROBVAL_BUFSIZ) | |
812 | len = BLKID_PROBVAL_BUFSIZ; | |
813 | ||
814 | if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) && | |
815 | blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0) | |
816 | return -1; | |
817 | if (!(pr->probreq & BLKID_PROBREQ_UUID)) | |
818 | return 0; | |
819 | ||
820 | v = blkid_probe_assign_value(pr, "UUID"); | |
821 | if (v) { | |
822 | memcpy((char *) v->data, str, len); | |
22632603 | 823 | *(v->data + len) = '\0'; |
bb6c6673 KZ |
824 | v->len = len; |
825 | return 0; | |
826 | } | |
827 | return -1; | |
828 | } | |
829 | ||
51410fc6 | 830 | /* default _set_uuid function to set DCE UUIDs */ |
8e7e30e4 | 831 | int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name) |
51410fc6 KZ |
832 | { |
833 | struct blkid_prval *v; | |
a0948ffe | 834 | |
51410fc6 | 835 | if (uuid_is_empty(uuid, 16)) |
a0948ffe KZ |
836 | return 0; |
837 | ||
8e7e30e4 KZ |
838 | if (!name) { |
839 | if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) && | |
840 | blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0) | |
841 | return -1; | |
842 | if (!(pr->probreq & BLKID_PROBREQ_UUID)) | |
843 | return 0; | |
a0948ffe | 844 | |
8e7e30e4 KZ |
845 | v = blkid_probe_assign_value(pr, "UUID"); |
846 | } else | |
847 | v = blkid_probe_assign_value(pr, name); | |
a0948ffe | 848 | |
51410fc6 KZ |
849 | #ifdef HAVE_LIBUUID |
850 | { | |
851 | uuid_unparse(uuid, (char *) v->data); | |
852 | v->len = 37; | |
853 | } | |
854 | #else | |
855 | v->len = snprintf(v->data, sizeof(v->data), | |
856 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", | |
857 | uuid[0], uuid[1], uuid[2], uuid[3], | |
858 | uuid[4], uuid[5], | |
859 | uuid[6], uuid[7], | |
860 | uuid[8], uuid[9], | |
861 | uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]); | |
862 | v->len++; | |
863 | #endif | |
a0948ffe KZ |
864 | return 0; |
865 | } | |
866 | ||
8e7e30e4 KZ |
867 | int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid) |
868 | { | |
869 | return blkid_probe_set_uuid_as(pr, uuid, NULL); | |
870 | } | |
871 | ||
51410fc6 | 872 | int blkid_probe_get_value(blkid_probe pr, int num, const char **name, |
6d042d0d | 873 | const char **data, size_t *len) |
a0948ffe | 874 | { |
51410fc6 | 875 | struct blkid_prval *v; |
a0948ffe | 876 | |
51410fc6 KZ |
877 | if (pr == NULL || num < 0 || num >= pr->nvals) |
878 | return -1; | |
a0948ffe | 879 | |
51410fc6 KZ |
880 | v = &pr->vals[num]; |
881 | if (name) | |
882 | *name = v->name; | |
883 | if (data) | |
6d042d0d | 884 | *data = (char *) v->data; |
51410fc6 KZ |
885 | if (len) |
886 | *len = v->len; | |
6644688a KZ |
887 | |
888 | DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); | |
a0948ffe KZ |
889 | return 0; |
890 | } | |
a0948ffe | 891 | |
51410fc6 | 892 | int blkid_probe_lookup_value(blkid_probe pr, const char *name, |
6d042d0d | 893 | const char **data, size_t *len) |
a0948ffe | 894 | { |
51410fc6 | 895 | int i; |
a0948ffe | 896 | |
51410fc6 KZ |
897 | if (pr == NULL || pr->nvals == 0 || name == NULL) |
898 | return -1; | |
a0948ffe | 899 | |
51410fc6 KZ |
900 | for (i = 0; i < pr->nvals; i++) { |
901 | struct blkid_prval *v = &pr->vals[i]; | |
a0948ffe | 902 | |
51410fc6 KZ |
903 | if (v->name && strcmp(name, v->name) == 0) { |
904 | if (data) | |
6d042d0d | 905 | *data = (char *) v->data; |
51410fc6 KZ |
906 | if (len) |
907 | *len = v->len; | |
6644688a | 908 | DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); |
51410fc6 | 909 | return 0; |
a0948ffe KZ |
910 | } |
911 | } | |
51410fc6 | 912 | return -1; |
a0948ffe KZ |
913 | } |
914 | ||
51410fc6 | 915 | int blkid_probe_has_value(blkid_probe pr, const char *name) |
a0948ffe | 916 | { |
51410fc6 KZ |
917 | if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0) |
918 | return 1; | |
a0948ffe KZ |
919 | return 0; |
920 | } | |
921 |