]>
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 | 26 | #include <stdint.h> |
8c0dc071 KZ |
27 | #include <stdarg.h> |
28 | ||
51410fc6 | 29 | #ifdef HAVE_LIBUUID |
8c0dc071 KZ |
30 | # ifdef HAVE_UUID_UUID_H |
31 | # include <uuid/uuid.h> | |
e5127179 KZ |
32 | # else |
33 | # include <uuid.h> | |
8c0dc071 | 34 | # endif |
51410fc6 | 35 | #endif |
a0948ffe | 36 | |
dc61d909 | 37 | #include "blkdev.h" |
51410fc6 | 38 | #include "blkidP.h" |
219227c2 KZ |
39 | |
40 | #include "superblocks/superblocks.h" | |
a0948ffe | 41 | |
51410fc6 | 42 | static const struct blkid_idinfo *idinfos[] = |
a0948ffe | 43 | { |
3402fff1 KZ |
44 | /* RAIDs */ |
45 | &linuxraid_idinfo, | |
f8504a4e | 46 | &ddfraid_idinfo, |
56ad7426 | 47 | &iswraid_idinfo, |
dc61d909 | 48 | &lsiraid_idinfo, |
3402fff1 KZ |
49 | &viaraid_idinfo, |
50 | &silraid_idinfo, | |
e86961ba | 51 | &nvraid_idinfo, |
b9938904 | 52 | &pdcraid_idinfo, |
5784db20 KZ |
53 | &highpoint45x_idinfo, |
54 | &highpoint37x_idinfo, | |
3402fff1 KZ |
55 | &adraid_idinfo, |
56 | &jmraid_idinfo, | |
57 | &lvm2_idinfo, | |
f19f9872 | 58 | &lvm1_idinfo, |
c8d20dc1 | 59 | &snapcow_idinfo, |
06da6d00 | 60 | &luks_idinfo, |
3402fff1 KZ |
61 | |
62 | /* Filesystems */ | |
63 | &vfat_idinfo, | |
64 | &swsuspend_idinfo, | |
65 | &swap_idinfo, | |
66 | &xfs_idinfo, | |
8e7e30e4 KZ |
67 | &ext4dev_idinfo, |
68 | &ext4_idinfo, | |
69 | &ext3_idinfo, | |
70 | &ext2_idinfo, | |
3402fff1 KZ |
71 | &jbd_idinfo, |
72 | &reiser_idinfo, | |
73 | &reiser4_idinfo, | |
80f26373 | 74 | &jfs_idinfo, |
3402fff1 KZ |
75 | &udf_idinfo, |
76 | &iso9660_idinfo, | |
1f4da8d2 | 77 | &zfs_idinfo, |
3402fff1 KZ |
78 | &hfsplus_idinfo, |
79 | &hfs_idinfo, | |
83b935ae | 80 | &ufs_idinfo, |
e134f470 | 81 | &hpfs_idinfo, |
d1e9e1e4 KZ |
82 | &sysv_idinfo, |
83 | &xenix_idinfo, | |
3402fff1 KZ |
84 | &ntfs_idinfo, |
85 | &cramfs_idinfo, | |
86 | &romfs_idinfo, | |
681ff570 | 87 | &minix_idinfo, |
81f81873 KZ |
88 | &gfs_idinfo, |
89 | &gfs2_idinfo, | |
7fd65bed KZ |
90 | &ocfs_idinfo, |
91 | &ocfs2_idinfo, | |
92 | &oracleasm_idinfo, | |
c29368b4 | 93 | &vxfs_idinfo, |
fc954eb5 | 94 | &squashfs_idinfo, |
990b429a KZ |
95 | &netware_idinfo, |
96 | &btrfs_idinfo | |
51410fc6 | 97 | }; |
a0948ffe | 98 | |
51410fc6 KZ |
99 | #ifndef ARRAY_SIZE |
100 | # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | |
101 | #endif | |
a0948ffe | 102 | |
51410fc6 | 103 | #define BLKID_FLTR_ITEMS ARRAY_SIZE(idinfos) |
f23e0557 | 104 | #define BLKID_FLTR_SIZE blkid_bmp_nwords(BLKID_FLTR_ITEMS) |
a0948ffe | 105 | |
51410fc6 | 106 | static int blkid_probe_set_usage(blkid_probe pr, int usage); |
a0948ffe | 107 | |
a0948ffe | 108 | /* |
51410fc6 | 109 | * Returns a pointer to the newly allocated probe struct |
a0948ffe | 110 | */ |
51410fc6 | 111 | blkid_probe blkid_new_probe(void) |
a0948ffe | 112 | { |
7a458332 | 113 | blkid_init_debug(0); |
51410fc6 | 114 | return calloc(1, sizeof(struct blkid_struct_probe)); |
a0948ffe KZ |
115 | } |
116 | ||
117 | /* | |
51410fc6 KZ |
118 | * Deallocates probe struct, buffers and all allocated |
119 | * data that are associated with this probing control struct. | |
a0948ffe | 120 | */ |
51410fc6 | 121 | void blkid_free_probe(blkid_probe pr) |
a0948ffe | 122 | { |
51410fc6 KZ |
123 | if (!pr) |
124 | return; | |
125 | free(pr->fltr); | |
126 | free(pr->buf); | |
127 | free(pr->sbbuf); | |
128 | free(pr); | |
a0948ffe KZ |
129 | } |
130 | ||
9bdf6885 KZ |
131 | /* |
132 | * Removes chain values from probing result. | |
133 | */ | |
134 | void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn) | |
135 | { | |
136 | int nvals = pr->nvals; | |
137 | int i, x; | |
138 | ||
139 | for (x = 0, i = 0; i < pr->nvals; i++) { | |
140 | struct blkid_prval *v = &pr->vals[i]; | |
141 | ||
142 | if (v->chain != chn && x == i) { | |
143 | x++; | |
144 | continue; | |
145 | } | |
146 | if (v->chain == chn) { | |
147 | --nvals; | |
148 | continue; | |
149 | } | |
150 | memcpy(&pr->vals[x++], v, sizeof(struct blkid_prval)); | |
151 | } | |
152 | pr->nvals = nvals; | |
153 | } | |
154 | ||
155 | /* | |
156 | * Copies chain values from probing result to @vals, the max size of @vals is | |
157 | * @nvals and returns real number of values. | |
158 | */ | |
159 | int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn, | |
160 | struct blkid_prval *vals, int nvals) | |
161 | { | |
162 | int i, x; | |
163 | ||
164 | for (x = 0, i = 0; i < pr->nvals && x < nvals; i++) { | |
165 | struct blkid_prval *v = &pr->vals[i]; | |
166 | ||
167 | if (v->chain != chn) | |
168 | continue; | |
169 | memcpy(&vals[x++], v, sizeof(struct blkid_prval)); | |
170 | } | |
171 | return x; | |
172 | } | |
173 | ||
174 | /* | |
175 | * Appends values from @vals to the probing result | |
176 | */ | |
177 | void blkid_probe_append_vals(blkid_probe pr, struct blkid_prval *vals, int nvals) | |
178 | { | |
179 | int i = 0; | |
180 | ||
181 | while (i < nvals && pr->nvals < BLKID_NVALS) { | |
182 | memcpy(&pr->vals[pr->nvals++], &vals[i++], | |
183 | sizeof(struct blkid_prval)); | |
184 | } | |
185 | } | |
186 | ||
51410fc6 | 187 | static void blkid_probe_reset_vals(blkid_probe pr) |
a0948ffe | 188 | { |
51410fc6 KZ |
189 | memset(pr->vals, 0, sizeof(pr->vals)); |
190 | pr->nvals = 0; | |
a0948ffe KZ |
191 | } |
192 | ||
1c1726a7 KZ |
193 | struct blkid_chain *blkid_probe_get_chain(blkid_probe pr) |
194 | { | |
195 | return pr->cur_chain; | |
196 | } | |
197 | ||
4ce48a97 KZ |
198 | static void blkid_probe_reset_idx(blkid_probe pr) |
199 | { | |
200 | pr->idx = -1; | |
201 | } | |
202 | ||
51410fc6 | 203 | void blkid_reset_probe(blkid_probe pr) |
a0948ffe | 204 | { |
51410fc6 KZ |
205 | if (!pr) |
206 | return; | |
6644688a | 207 | DBG(DEBUG_LOWPROBE, printf("reseting blkid_probe\n")); |
51410fc6 KZ |
208 | if (pr->buf) |
209 | memset(pr->buf, 0, pr->buf_max); | |
210 | pr->buf_off = 0; | |
211 | pr->buf_len = 0; | |
212 | if (pr->sbbuf) | |
213 | memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ); | |
214 | pr->sbbuf_len = 0; | |
215 | blkid_probe_reset_vals(pr); | |
4ce48a97 | 216 | blkid_probe_reset_idx(pr); |
a0948ffe KZ |
217 | } |
218 | ||
46a734fd KZ |
219 | /*** |
220 | static int blkid_probe_dump_filter(blkid_probe pr, int chain) | |
221 | { | |
222 | struct blkid_chain *chn; | |
223 | int i; | |
224 | ||
225 | if (!pr || chain < 0 || chain >= BLKID_NCHAINS) | |
226 | return -1; | |
227 | ||
228 | chn = &pr->chains[chain]; | |
229 | ||
230 | if (!chn->fltr) | |
231 | return -1; | |
232 | ||
233 | for (i = 0; i < chn->driver->nidinfos; i++) { | |
234 | const struct blkid_idinfo *id = chn->driver->idinfos[i]; | |
235 | ||
236 | DBG(DEBUG_LOWPROBE, printf("%d: %s: %s\n", | |
237 | i, | |
238 | id->name, | |
239 | blkid_bmp_get_item(chn->fltr, i) | |
240 | ? "disabled" : "enabled <--")); | |
241 | ||
242 | } | |
243 | return 0; | |
244 | } | |
245 | ***/ | |
246 | ||
247 | /* | |
248 | * Returns properly initialized chain filter | |
249 | */ | |
250 | unsigned long *blkid_probe_get_filter(blkid_probe pr, int chain, int create) | |
251 | { | |
252 | struct blkid_chain *chn; | |
253 | ||
254 | if (!pr || chain < 0 || chain >= BLKID_NCHAINS) | |
255 | return NULL; | |
256 | ||
257 | chn = &pr->chains[chain]; | |
258 | ||
259 | /* always when you touch the chain filter all indexes are reseted and | |
260 | * probing starts from scratch | |
261 | */ | |
262 | chn->idx = -1; | |
263 | pr->cur_chain = NULL; | |
264 | ||
265 | if (!chn->driver->has_fltr || (!chn->fltr && !create)) | |
266 | return NULL; | |
267 | ||
268 | if (!chn->fltr) | |
269 | chn->fltr = calloc(1, blkid_bmp_nbytes(chn->driver->nidinfos)); | |
270 | else | |
271 | memset(chn->fltr, 0, blkid_bmp_nbytes(chn->driver->nidinfos)); | |
272 | ||
273 | /* blkid_probe_dump_filter(pr, chain); */ | |
274 | return chn->fltr; | |
275 | } | |
276 | ||
277 | /* | |
278 | * Generic private functions for filter setting | |
279 | */ | |
280 | int __blkid_probe_invert_filter(blkid_probe pr, int chain) | |
281 | { | |
282 | int i; | |
283 | struct blkid_chain *chn; | |
284 | unsigned long *fltr; | |
285 | ||
286 | fltr = blkid_probe_get_filter(pr, chain, FALSE); | |
287 | if (!fltr) | |
288 | return -1; | |
289 | ||
290 | chn = &pr->chains[chain]; | |
291 | ||
292 | for (i = 0; i < blkid_bmp_nwords(chn->driver->nidinfos); i++) | |
293 | fltr[i] = ~fltr[i]; | |
294 | ||
295 | DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n")); | |
296 | /* blkid_probe_dump_filter(pr, chain); */ | |
297 | return 0; | |
298 | } | |
299 | ||
300 | int __blkid_probe_reset_filter(blkid_probe pr, int chain) | |
301 | { | |
302 | return blkid_probe_get_filter(pr, chain, FALSE) ? 0 : -1; | |
303 | } | |
304 | ||
305 | int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[]) | |
306 | { | |
307 | unsigned long *fltr; | |
308 | struct blkid_chain *chn; | |
309 | int i; | |
310 | ||
311 | fltr = blkid_probe_get_filter(pr, chain, TRUE); | |
312 | if (!fltr) | |
313 | return -1; | |
314 | ||
315 | chn = &pr->chains[chain]; | |
316 | ||
317 | for (i = 0; i < chn->driver->nidinfos; i++) { | |
318 | int has = 0; | |
319 | const struct blkid_idinfo *id = chn->driver->idinfos[i]; | |
320 | char **n; | |
321 | ||
322 | for (n = names; *n; n++) { | |
323 | if (!strcmp(id->name, *n)) { | |
324 | has = 1; | |
325 | break; | |
326 | } | |
327 | } | |
328 | if (flag & BLKID_FLTR_ONLYIN) { | |
329 | if (!has) | |
330 | blkid_bmp_set_item(fltr, i); | |
331 | } else if (flag & BLKID_FLTR_NOTIN) { | |
332 | if (has) | |
333 | blkid_bmp_set_item(fltr, i); | |
334 | } | |
335 | } | |
336 | ||
337 | DBG(DEBUG_LOWPROBE, | |
338 | printf("%s: a new probing type-filter initialized\n", | |
339 | chn->driver->name)); | |
340 | /* blkid_probe_dump_filter(pr, chain); */ | |
341 | return 0; | |
342 | } | |
343 | ||
51410fc6 KZ |
344 | /* |
345 | * Note that we have two offsets: | |
346 | * | |
347 | * 1/ general device offset (pr->off), that's useful for example when we | |
348 | * probe a partition from whole disk image: | |
349 | * blkid-low --offset <partition_position> disk.img | |
350 | * | |
351 | * 2/ buffer offset (the 'off' argument), that useful for offsets in | |
352 | * superbloks, ... | |
353 | * | |
354 | * That means never use lseek(fd, 0, SEEK_SET), the zero position is always | |
355 | * pr->off, so lseek(fd, pr->off, SEEK_SET). | |
356 | * | |
357 | */ | |
358 | unsigned char *blkid_probe_get_buffer(blkid_probe pr, | |
359 | blkid_loff_t off, blkid_loff_t len) | |
a0948ffe | 360 | { |
51410fc6 | 361 | ssize_t ret_read = 0; |
a0948ffe | 362 | |
4884729a KZ |
363 | if (off < 0 || len < 0) { |
364 | DBG(DEBUG_LOWPROBE, | |
365 | printf("unexpected offset or length of buffer requested\n")); | |
366 | return NULL; | |
367 | } | |
51410fc6 KZ |
368 | if (off + len <= BLKID_SB_BUFSIZ) { |
369 | if (!pr->sbbuf) { | |
370 | pr->sbbuf = malloc(BLKID_SB_BUFSIZ); | |
371 | if (!pr->sbbuf) | |
372 | return NULL; | |
373 | } | |
374 | if (!pr->sbbuf_len) { | |
375 | if (lseek(pr->fd, pr->off, SEEK_SET) < 0) | |
376 | return NULL; | |
377 | ret_read = read(pr->fd, pr->sbbuf, BLKID_SB_BUFSIZ); | |
378 | if (ret_read < 0) | |
379 | ret_read = 0; | |
380 | pr->sbbuf_len = ret_read; | |
381 | } | |
382 | if (off + len > pr->sbbuf_len) | |
383 | return NULL; | |
384 | return pr->sbbuf + off; | |
385 | } else { | |
386 | unsigned char *newbuf = NULL; | |
387 | ||
388 | if (len > pr->buf_max) { | |
389 | newbuf = realloc(pr->buf, len); | |
390 | if (!newbuf) | |
391 | return NULL; | |
392 | pr->buf = newbuf; | |
393 | pr->buf_max = len; | |
394 | pr->buf_off = 0; | |
395 | pr->buf_len = 0; | |
396 | } | |
397 | if (newbuf || off < pr->buf_off || | |
398 | off + len > pr->buf_off + pr->buf_len) { | |
399 | ||
400 | if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) | |
401 | return NULL; | |
402 | ||
403 | ret_read = read(pr->fd, pr->buf, len); | |
404 | if (ret_read != (ssize_t) len) | |
405 | return NULL; | |
406 | pr->buf_off = off; | |
407 | pr->buf_len = len; | |
408 | } | |
409 | return off ? pr->buf + (off - pr->buf_off) : pr->buf; | |
410 | } | |
a0948ffe KZ |
411 | } |
412 | ||
51410fc6 KZ |
413 | /* |
414 | * Assignes the device to probe control struct, resets internal buffers and | |
415 | * reads 512 bytes from device to the buffers. | |
416 | * | |
417 | * Returns -1 in case of failure, or 0 on success. | |
418 | */ | |
419 | int blkid_probe_set_device(blkid_probe pr, int fd, | |
420 | blkid_loff_t off, blkid_loff_t size) | |
a0948ffe | 421 | { |
51410fc6 KZ |
422 | if (!pr) |
423 | return -1; | |
a0948ffe | 424 | |
51410fc6 | 425 | blkid_reset_probe(pr); |
a0948ffe | 426 | |
51410fc6 KZ |
427 | pr->fd = fd; |
428 | pr->off = off; | |
bb6c6673 | 429 | pr->size = 0; |
dc61d909 | 430 | |
bb6c6673 | 431 | if (size) |
dc61d909 | 432 | pr->size = size; |
bb6c6673 KZ |
433 | else { |
434 | struct stat sb; | |
435 | ||
436 | if (fstat(fd, &sb)) | |
437 | return -1; | |
438 | ||
439 | if (S_ISBLK(sb.st_mode)) | |
440 | blkdev_get_size(fd, (unsigned long long *) &pr->size); | |
441 | else | |
442 | pr->size = sb.st_size; | |
443 | } | |
444 | if (!pr->size) | |
445 | return -1; | |
a0948ffe | 446 | |
51410fc6 | 447 | /* read SB to test if the device is readable */ |
6644688a KZ |
448 | if (!blkid_probe_get_buffer(pr, 0, 0x200)) { |
449 | DBG(DEBUG_LOWPROBE, | |
450 | printf("failed to prepare a device for low-probing\n")); | |
51410fc6 | 451 | return -1; |
6644688a | 452 | } |
a0948ffe | 453 | |
bb6c6673 KZ |
454 | DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n", |
455 | pr->off, pr->size)); | |
a0948ffe KZ |
456 | return 0; |
457 | } | |
458 | ||
a0fc685c KZ |
459 | /* |
460 | * The blkid_do_probe() calls the probe functions. This routine could be used | |
461 | * in a loop when you need to probe for all possible filesystems/raids. | |
462 | * | |
463 | * 1/ basic case -- use the first result: | |
464 | * | |
465 | * if (blkid_do_probe(pr) == 0) { | |
466 | * int nvals = blkid_probe_numof_values(pr); | |
467 | * for (n = 0; n < nvals; n++) { | |
468 | * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0) | |
469 | * printf("%s = %s\n", name, data); | |
470 | * } | |
471 | * } | |
472 | * | |
473 | * 2/ advanced case -- probe for all signatures (don't forget that some | |
474 | * filesystems can co-exist on one volume (e.g. CD-ROM). | |
475 | * | |
476 | * while (blkid_do_probe(pr) == 0) { | |
477 | * int nvals = blkid_probe_numof_values(pr); | |
478 | * ... | |
479 | * } | |
480 | * | |
481 | * The internal probing index (pointer to the last probing function) is | |
482 | * always reseted when you touch probing filter or set a new device. It | |
483 | * means you cannot use: | |
484 | * | |
485 | * blkid_probe_invert_filter() | |
486 | * blkid_probe_filter_usage() | |
487 | * blkid_probe_filter_types() | |
488 | * blkid_probe_reset_filter() | |
489 | * blkid_probe_set_device() | |
490 | * | |
491 | * in the loop (e.g while()) when you iterate on all signatures. | |
492 | */ | |
51410fc6 | 493 | int blkid_do_probe(blkid_probe pr) |
a0948ffe | 494 | { |
a0fc685c | 495 | int i = 0; |
a0948ffe | 496 | |
4bf7d601 | 497 | if (!pr || pr->idx < -1) |
51410fc6 | 498 | return -1; |
a0948ffe | 499 | |
51410fc6 | 500 | blkid_probe_reset_vals(pr); |
a0948ffe | 501 | |
4bf7d601 KZ |
502 | DBG(DEBUG_LOWPROBE, |
503 | printf("--> starting probing loop [idx=%d]\n", | |
504 | pr->idx)); | |
a0fc685c | 505 | |
4bf7d601 | 506 | i = pr->idx + 1; |
6644688a | 507 | |
a2f01a1c | 508 | for ( ; i < ARRAY_SIZE(idinfos); i++) { |
51410fc6 KZ |
509 | const struct blkid_idinfo *id; |
510 | const struct blkid_idmag *mag; | |
2d4f7576 | 511 | int hasmag = 0; |
a0948ffe | 512 | |
a0fc685c KZ |
513 | pr->idx = i; |
514 | ||
51410fc6 KZ |
515 | if (pr->fltr && blkid_bmp_get_item(pr->fltr, i)) |
516 | continue; | |
a0948ffe | 517 | |
51410fc6 KZ |
518 | id = idinfos[i]; |
519 | mag = id->magics ? &id->magics[0] : NULL; | |
a0948ffe | 520 | |
51410fc6 KZ |
521 | /* try to detect by magic string */ |
522 | while(mag && mag->magic) { | |
523 | int idx; | |
524 | unsigned char *buf; | |
a0948ffe | 525 | |
51410fc6 KZ |
526 | idx = mag->kboff + (mag->sboff >> 10); |
527 | buf = blkid_probe_get_buffer(pr, idx << 10, 1024); | |
a0948ffe | 528 | |
51410fc6 | 529 | if (buf && !memcmp(mag->magic, |
6644688a KZ |
530 | buf + (mag->sboff & 0x3ff), mag->len)) { |
531 | DBG(DEBUG_LOWPROBE, printf( | |
92163c45 KZ |
532 | "%s: magic sboff=%u, kboff=%ld\n", |
533 | id->name, mag->sboff, mag->kboff)); | |
2d4f7576 | 534 | hasmag = 1; |
51410fc6 | 535 | break; |
6644688a | 536 | } |
51410fc6 KZ |
537 | mag++; |
538 | } | |
a0948ffe | 539 | |
2d4f7576 | 540 | if (hasmag == 0 && id->magics && id->magics[0].magic) |
51410fc6 KZ |
541 | /* magic string(s) defined, but not found */ |
542 | continue; | |
a0948ffe | 543 | |
51410fc6 | 544 | /* final check by probing function */ |
6644688a KZ |
545 | if (id->probefunc) { |
546 | DBG(DEBUG_LOWPROBE, printf( | |
92163c45 | 547 | "%s: call probefunc()\n", id->name)); |
6644688a KZ |
548 | if (id->probefunc(pr, mag) != 0) |
549 | continue; | |
550 | } | |
a0948ffe | 551 | |
51410fc6 KZ |
552 | /* all cheks passed */ |
553 | if (pr->probreq & BLKID_PROBREQ_TYPE) | |
554 | blkid_probe_set_value(pr, "TYPE", | |
555 | (unsigned char *) id->name, | |
556 | strlen(id->name) + 1); | |
51410fc6 KZ |
557 | if (pr->probreq & BLKID_PROBREQ_USAGE) |
558 | blkid_probe_set_usage(pr, id->usage); | |
a0948ffe | 559 | |
5b6215b5 | 560 | DBG(DEBUG_LOWPROBE, |
4bf7d601 KZ |
561 | printf("<-- leaving probing loop (type=%s) [idx=%d]\n", |
562 | id->name, pr->idx)); | |
51410fc6 KZ |
563 | return 0; |
564 | } | |
4bf7d601 KZ |
565 | DBG(DEBUG_LOWPROBE, |
566 | printf("<-- leaving probing loop (failed) [idx=%d]\n", | |
567 | pr->idx)); | |
51410fc6 | 568 | return 1; |
a0948ffe KZ |
569 | } |
570 | ||
a2f01a1c KZ |
571 | /* |
572 | * This is the same function as blkid_do_probe(), but returns only one result | |
573 | * (cannot be used in while()) and checks for ambivalen results (more | |
574 | * filesystems on the device) -- in such case returns -2. | |
7103157c KZ |
575 | * |
576 | * The function does not check for filesystems when a RAID signature is | |
577 | * detected. The function also does not check for collision between RAIDs. The | |
578 | * first detected RAID is returned. | |
a2f01a1c KZ |
579 | */ |
580 | int blkid_do_safeprobe(blkid_probe pr) | |
581 | { | |
582 | struct blkid_struct_probe first; | |
583 | int count = 0; | |
584 | int intol = 0; | |
585 | int rc; | |
586 | ||
587 | while ((rc = blkid_do_probe(pr)) == 0) { | |
588 | if (!count) { | |
589 | /* store the fist result */ | |
590 | memcpy(first.vals, pr->vals, sizeof(first.vals)); | |
591 | first.nvals = pr->nvals; | |
592 | first.idx = pr->idx; | |
593 | } | |
7103157c KZ |
594 | count++; |
595 | ||
596 | if (idinfos[pr->idx]->usage & BLKID_USAGE_RAID) | |
597 | break; | |
a2f01a1c KZ |
598 | if (!(idinfos[pr->idx]->flags & BLKID_IDINFO_TOLERANT)) |
599 | intol++; | |
a2f01a1c KZ |
600 | } |
601 | if (rc < 0) | |
602 | return rc; /* error */ | |
92163c45 KZ |
603 | if (count > 1 && intol) { |
604 | DBG(DEBUG_LOWPROBE, | |
605 | printf("ERROR: ambivalent result detected (%d filesystems)!\n", | |
606 | count)); | |
a2f01a1c | 607 | return -2; /* error, ambivalent result (more FS) */ |
92163c45 | 608 | } |
a2f01a1c KZ |
609 | if (!count) |
610 | return 1; /* nothing detected */ | |
611 | ||
612 | /* restore the first result */ | |
613 | memcpy(pr->vals, first.vals, sizeof(first.vals)); | |
614 | pr->nvals = first.nvals; | |
615 | pr->idx = first.idx; | |
616 | ||
617 | return 0; | |
618 | } | |
619 | ||
51410fc6 | 620 | int blkid_probe_numof_values(blkid_probe pr) |
a0948ffe | 621 | { |
51410fc6 KZ |
622 | if (!pr) |
623 | return -1; | |
624 | return pr->nvals; | |
a0948ffe KZ |
625 | } |
626 | ||
9bdf6885 | 627 | struct blkid_prval *blkid_probe_assign_value( |
51410fc6 | 628 | blkid_probe pr, const char *name) |
a0948ffe | 629 | { |
51410fc6 | 630 | struct blkid_prval *v; |
a0948ffe | 631 | |
51410fc6 KZ |
632 | if (!name) |
633 | return NULL; | |
924fe747 | 634 | if (pr->nvals >= BLKID_NVALS) |
51410fc6 | 635 | return NULL; |
a0948ffe | 636 | |
51410fc6 KZ |
637 | v = &pr->vals[pr->nvals]; |
638 | v->name = name; | |
9bdf6885 | 639 | v->chain = pr->cur_chain; |
51410fc6 | 640 | pr->nvals++; |
6644688a | 641 | |
9bdf6885 KZ |
642 | DBG(DEBUG_LOWPROBE, |
643 | printf("assigning %s [%s]\n", name, v->chain->driver->name)); | |
51410fc6 | 644 | return v; |
a0948ffe KZ |
645 | } |
646 | ||
51410fc6 KZ |
647 | int blkid_probe_set_value(blkid_probe pr, const char *name, |
648 | unsigned char *data, size_t len) | |
a0948ffe | 649 | { |
51410fc6 | 650 | struct blkid_prval *v; |
a0948ffe | 651 | |
51410fc6 KZ |
652 | if (len > BLKID_PROBVAL_BUFSIZ) |
653 | len = BLKID_PROBVAL_BUFSIZ; | |
a0948ffe | 654 | |
51410fc6 KZ |
655 | v = blkid_probe_assign_value(pr, name); |
656 | if (!v) | |
657 | return -1; | |
a0948ffe | 658 | |
51410fc6 KZ |
659 | memcpy(v->data, data, len); |
660 | v->len = len; | |
a0948ffe KZ |
661 | return 0; |
662 | } | |
663 | ||
51410fc6 KZ |
664 | int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, |
665 | const char *fmt, va_list ap) | |
a0948ffe | 666 | { |
51410fc6 KZ |
667 | struct blkid_prval *v; |
668 | size_t len; | |
a0948ffe | 669 | |
51410fc6 KZ |
670 | v = blkid_probe_assign_value(pr, name); |
671 | if (!v) | |
672 | return -1; | |
a0948ffe | 673 | |
51410fc6 | 674 | len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap); |
a0948ffe | 675 | |
51410fc6 KZ |
676 | if (len <= 0) { |
677 | pr->nvals--; /* reset the latest assigned value */ | |
678 | return -1; | |
a0948ffe | 679 | } |
51410fc6 | 680 | v->len = len + 1; |
a0948ffe KZ |
681 | return 0; |
682 | } | |
683 | ||
51410fc6 | 684 | static int blkid_probe_set_usage(blkid_probe pr, int usage) |
a0948ffe | 685 | { |
51410fc6 | 686 | char *u = NULL; |
a0948ffe | 687 | |
51410fc6 KZ |
688 | if (usage & BLKID_USAGE_FILESYSTEM) |
689 | u = "filesystem"; | |
690 | else if (usage & BLKID_USAGE_RAID) | |
691 | u = "raid"; | |
692 | else if (usage & BLKID_USAGE_CRYPTO) | |
693 | u = "crypto"; | |
694 | else if (usage & BLKID_USAGE_OTHER) | |
695 | u = "other"; | |
696 | else | |
697 | u = "unknown"; | |
a0948ffe | 698 | |
51410fc6 | 699 | return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1); |
a0948ffe KZ |
700 | } |
701 | ||
51410fc6 | 702 | int blkid_probe_get_value(blkid_probe pr, int num, const char **name, |
6d042d0d | 703 | const char **data, size_t *len) |
a0948ffe | 704 | { |
51410fc6 | 705 | struct blkid_prval *v; |
a0948ffe | 706 | |
51410fc6 KZ |
707 | if (pr == NULL || num < 0 || num >= pr->nvals) |
708 | return -1; | |
a0948ffe | 709 | |
51410fc6 KZ |
710 | v = &pr->vals[num]; |
711 | if (name) | |
712 | *name = v->name; | |
713 | if (data) | |
6d042d0d | 714 | *data = (char *) v->data; |
51410fc6 KZ |
715 | if (len) |
716 | *len = v->len; | |
6644688a KZ |
717 | |
718 | DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); | |
a0948ffe KZ |
719 | return 0; |
720 | } | |
a0948ffe | 721 | |
51410fc6 | 722 | int blkid_probe_lookup_value(blkid_probe pr, const char *name, |
6d042d0d | 723 | const char **data, size_t *len) |
a0948ffe | 724 | { |
51410fc6 | 725 | int i; |
a0948ffe | 726 | |
51410fc6 KZ |
727 | if (pr == NULL || pr->nvals == 0 || name == NULL) |
728 | return -1; | |
a0948ffe | 729 | |
51410fc6 KZ |
730 | for (i = 0; i < pr->nvals; i++) { |
731 | struct blkid_prval *v = &pr->vals[i]; | |
a0948ffe | 732 | |
51410fc6 KZ |
733 | if (v->name && strcmp(name, v->name) == 0) { |
734 | if (data) | |
6d042d0d | 735 | *data = (char *) v->data; |
51410fc6 KZ |
736 | if (len) |
737 | *len = v->len; | |
6644688a | 738 | DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); |
51410fc6 | 739 | return 0; |
a0948ffe KZ |
740 | } |
741 | } | |
51410fc6 | 742 | return -1; |
a0948ffe KZ |
743 | } |
744 | ||
51410fc6 | 745 | int blkid_probe_has_value(blkid_probe pr, const char *name) |
a0948ffe | 746 | { |
51410fc6 KZ |
747 | if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0) |
748 | return 1; | |
a0948ffe KZ |
749 | return 0; |
750 | } | |
751 | ||
1c1726a7 KZ |
752 | struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num) |
753 | { | |
754 | if (pr == NULL || num < 0 || num >= pr->nvals) | |
755 | return NULL; | |
756 | ||
757 | return &pr->vals[num]; | |
758 | } | |
759 | ||
760 | struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name) | |
761 | { | |
762 | int i; | |
763 | ||
764 | if (pr == NULL || pr->nvals == 0 || name == NULL) | |
765 | return NULL; | |
766 | ||
767 | for (i = 0; i < pr->nvals; i++) { | |
768 | struct blkid_prval *v = &pr->vals[i]; | |
769 | ||
770 | if (v->name && strcmp(name, v->name) == 0) { | |
771 | DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); | |
772 | return v; | |
773 | } | |
774 | } | |
775 | return NULL; | |
776 | } | |
777 | ||
201529bd KZ |
778 | |
779 | /* converts DCE UUID (uuid[16]) to human readable string | |
780 | * - the @len should be always 37 */ | |
781 | void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len) | |
782 | { | |
783 | #ifdef HAVE_LIBUUID | |
784 | uuid_unparse(uuid, str); | |
785 | #else | |
786 | snprintf(str, len, | |
787 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", | |
788 | uuid[0], uuid[1], uuid[2], uuid[3], | |
789 | uuid[4], uuid[5], | |
790 | uuid[6], uuid[7], | |
791 | uuid[8], uuid[9], | |
792 | uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]); | |
793 | #endif | |
794 | } | |
795 |