]> git.ipfire.org Git - thirdparty/util-linux.git/blob - shlibs/blkid/src/probe.c
libblkid: read() optimization for small devices
[thirdparty/util-linux.git] / shlibs / blkid / src / probe.c
1 /*
2 * Low-level libblkid probing API
3 *
4 * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
5 *
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
8 */
9
10 /**
11 * SECTION: lowprobe
12 * @title: Low-level probing
13 * @short_description: low-level prober initialization
14 *
15 * The low-level probing routines always and directly read information from
16 * the selected (see blkid_probe_set_device()) device.
17 *
18 * The probing routines are grouped together into separate chains. Currently,
19 * the librray provides superblocks, partitions and topology chains.
20 *
21 * The probing routines is possible to filter (enable/disable) by type (e.g.
22 * fstype "vfat" or partype "gpt") or by usage flags (e.g. BLKID_USAGE_RAID).
23 * These filters are per-chain. Note that always when you touch the chain
24 * filter the current probing position is reseted and probing starts from
25 * scratch. It means that the chain filter should not be modified during
26 * probing, for example in loop where you call blkid_do_probe().
27 *
28 * For more details see the chain specific documentation.
29 *
30 * The low-level API provides two ways how access to probing results.
31 *
32 * 1. The NAME=value (tag) interface. This interface is older and returns all data
33 * as strings. This interface is generic for all chains.
34 *
35 * 2. The binary interfaces. These interfaces return data in the native formats.
36 * The interface is always specific to the probing chain.
37 *
38 */
39
40 /**
41 * SECTION: lowprobe-tags
42 * @title: Low-level tags
43 * @short_description: generic NAME=value interface.
44 *
45 * The probing routines inside the chain are mutually exclusive by default --
46 * only few probing routines are marked as "tolerant". The "tolerant" probing
47 * routines are used for filesystem which can share the same device with any
48 * other filesystem. The blkid_do_safeprobe() checks for the "tolerant" flag.
49 *
50 * The SUPERBLOCKS chain is enabled by default. The all others chains is
51 * necessary to enable by blkid_probe_enable_'CHAINNAME'(). See chains specific
52 * documentation.
53 *
54 * The blkid_do_probe() function returns a result from only one probing
55 * routine, and the next call from the next probing routine. It means you need
56 * to call the function in loop, for example:
57 *
58 * <informalexample>
59 * <programlisting>
60 * while((blkid_do_probe(pr) == 0)
61 * ... use result ...
62 * </programlisting>
63 * </informalexample>
64 *
65 * The blkid_do_safeprobe() is the same as blkid_do_probe(), but returns only
66 * first probing result for every enabled chain. This function checks for
67 * ambivalent results (e.g. more "intolerant" filesystems superblocks on the
68 * device).
69 *
70 * The probing result is set of NAME=value pairs (the NAME is always unique).
71 */
72
73 #include <stdio.h>
74 #include <string.h>
75 #include <stdlib.h>
76 #include <unistd.h>
77 #include <fcntl.h>
78 #include <ctype.h>
79 #include <sys/types.h>
80 #ifdef HAVE_SYS_STAT_H
81 #include <sys/stat.h>
82 #endif
83 #ifdef HAVE_SYS_MKDEV_H
84 #include <sys/mkdev.h>
85 #endif
86 #ifdef HAVE_ERRNO_H
87 #include <errno.h>
88 #endif
89 #include <stdint.h>
90 #include <stdarg.h>
91
92 #ifdef HAVE_LIBUUID
93 # ifdef HAVE_UUID_UUID_H
94 # include <uuid/uuid.h>
95 # else
96 # include <uuid.h>
97 # endif
98 #endif
99
100 #include "blkdev.h"
101 #include "blkidP.h"
102
103 /* chains */
104 extern const struct blkid_chaindrv superblocks_drv;
105 extern const struct blkid_chaindrv topology_drv;
106 extern const struct blkid_chaindrv partitions_drv;
107
108 /*
109 * All supported chains
110 */
111 static const struct blkid_chaindrv *chains_drvs[] = {
112 [BLKID_CHAIN_SUBLKS] = &superblocks_drv,
113 [BLKID_CHAIN_TOPLGY] = &topology_drv,
114 [BLKID_CHAIN_PARTS] = &partitions_drv
115 };
116
117 static void blkid_probe_reset_vals(blkid_probe pr);
118
119 /**
120 * blkid_new_probe:
121 *
122 * Returns: a pointer to the newly allocated probe struct.
123 */
124 blkid_probe blkid_new_probe(void)
125 {
126 int i;
127 blkid_probe pr;
128
129 blkid_init_debug(0);
130 pr = calloc(1, sizeof(struct blkid_struct_probe));
131 if (!pr)
132 return NULL;
133
134 /* initialize chains */
135 for (i = 0; i < BLKID_NCHAINS; i++) {
136 pr->chains[i].driver = chains_drvs[i];
137 pr->chains[i].flags = chains_drvs[i]->dflt_flags;
138 pr->chains[i].enabled = chains_drvs[i]->dflt_enabled;
139 }
140 return pr;
141 }
142
143 /**
144 * blkid_new_probe_from_filename:
145 * @filename: device or regular file
146 *
147 * This function is same as call open(filename), blkid_new_probe() and
148 * blkid_probe_set_device(pr, fd, 0, 0).
149 *
150 * The @filename is closed by blkid_free_probe() or by the
151 * blkid_probe_set_device() call.
152 *
153 * Returns: a pointer to the newly allocated probe struct or NULL in case of
154 * error.
155 */
156 blkid_probe blkid_new_probe_from_filename(const char *filename)
157 {
158 int fd = -1;
159 blkid_probe pr = NULL;
160
161 if (!filename)
162 return NULL;
163
164 fd = open(filename, O_RDONLY);
165 if (fd < 0)
166 return NULL;
167
168 pr = blkid_new_probe();
169 if (!pr)
170 goto err;
171
172 if (blkid_probe_set_device(pr, fd, 0, 0))
173 goto err;
174
175 pr->flags |= BLKID_PRIVATE_FD;
176 return pr;
177 err:
178 if (fd >= 0)
179 close(fd);
180 blkid_free_probe(pr);
181 return NULL;
182 }
183
184 /**
185 * blkid_free_probe:
186 * @pr: probe
187 *
188 * Deallocates the probe struct, buffers and all allocated
189 * data that are associated with this probing control struct.
190 */
191 void blkid_free_probe(blkid_probe pr)
192 {
193 int i;
194
195 if (!pr)
196 return;
197
198 for (i = 0; i < BLKID_NCHAINS; i++) {
199 struct blkid_chain *ch = &pr->chains[i];
200
201 if (ch->driver->free_data)
202 ch->driver->free_data(pr, ch->data);
203 free(ch->fltr);
204 }
205 free(pr->buf);
206 free(pr->sbbuf);
207
208 if ((pr->flags & BLKID_PRIVATE_FD) && pr->fd >= 0)
209 close(pr->fd);
210 free(pr);
211 }
212
213 static void blkid_probe_reset_buffer(blkid_probe pr)
214 {
215 DBG(DEBUG_LOWPROBE, printf("reseting blkid probe buffer\n"));
216 if (pr->buf)
217 memset(pr->buf, 0, pr->buf_max);
218 pr->buf_off = 0;
219 pr->buf_len = 0;
220 if (pr->sbbuf)
221 memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ);
222 pr->sbbuf_len = 0;
223 }
224
225
226 /*
227 * Removes chain values from probing result.
228 */
229 void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn)
230 {
231 int nvals = pr->nvals;
232 int i, x;
233
234 for (x = 0, i = 0; i < pr->nvals; i++) {
235 struct blkid_prval *v = &pr->vals[i];
236
237 if (v->chain != chn && x == i) {
238 x++;
239 continue;
240 }
241 if (v->chain == chn) {
242 --nvals;
243 continue;
244 }
245 memcpy(&pr->vals[x++], v, sizeof(struct blkid_prval));
246 }
247 pr->nvals = nvals;
248 }
249
250 static void blkid_probe_chain_reset_position(struct blkid_chain *chn)
251 {
252 if (chn)
253 chn->idx = -1;
254 }
255
256 /*
257 * Copies chain values from probing result to @vals, the max size of @vals is
258 * @nvals and returns real number of values.
259 */
260 int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn,
261 struct blkid_prval *vals, int nvals)
262 {
263 int i, x;
264
265 for (x = 0, i = 0; i < pr->nvals && x < nvals; i++) {
266 struct blkid_prval *v = &pr->vals[i];
267
268 if (v->chain != chn)
269 continue;
270 memcpy(&vals[x++], v, sizeof(struct blkid_prval));
271 }
272 return x;
273 }
274
275 /*
276 * Appends values from @vals to the probing result
277 */
278 void blkid_probe_append_vals(blkid_probe pr, struct blkid_prval *vals, int nvals)
279 {
280 int i = 0;
281
282 while (i < nvals && pr->nvals < BLKID_NVALS) {
283 memcpy(&pr->vals[pr->nvals++], &vals[i++],
284 sizeof(struct blkid_prval));
285 }
286 }
287
288 static void blkid_probe_reset_vals(blkid_probe pr)
289 {
290 memset(pr->vals, 0, sizeof(pr->vals));
291 pr->nvals = 0;
292 }
293
294 struct blkid_chain *blkid_probe_get_chain(blkid_probe pr)
295 {
296 return pr->cur_chain;
297 }
298
299 void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn)
300 {
301 int rc;
302
303 if (!pr && !chn)
304 return NULL;
305
306 pr->cur_chain = chn;
307 chn->binary = TRUE;
308 blkid_probe_chain_reset_position(chn);
309
310 rc = chn->driver->probe(pr, chn);
311
312 chn->binary = FALSE;
313 pr->cur_chain = NULL;
314 blkid_probe_chain_reset_position(chn);
315
316 if (rc != 0)
317 return NULL;
318
319 DBG(DEBUG_LOWPROBE,
320 printf("returning %s binary data\n", chn->driver->name));
321 return chn->data;
322 }
323
324
325 /**
326 * blkid_reset_probe:
327 * @pr: probe
328 *
329 * Zeroize probing results and resets the current probing (this has impact to
330 * blkid_do_probe() only). This function does not touch probing filters and
331 * keeps assigned device.
332 */
333 void blkid_reset_probe(blkid_probe pr)
334 {
335 int i;
336
337 if (!pr)
338 return;
339
340 blkid_probe_reset_buffer(pr);
341 blkid_probe_reset_vals(pr);
342
343 pr->cur_chain = NULL;
344
345 for (i = 0; i < BLKID_NCHAINS; i++)
346 blkid_probe_chain_reset_position(&pr->chains[i]);
347 }
348
349 /***
350 static int blkid_probe_dump_filter(blkid_probe pr, int chain)
351 {
352 struct blkid_chain *chn;
353 int i;
354
355 if (!pr || chain < 0 || chain >= BLKID_NCHAINS)
356 return -1;
357
358 chn = &pr->chains[chain];
359
360 if (!chn->fltr)
361 return -1;
362
363 for (i = 0; i < chn->driver->nidinfos; i++) {
364 const struct blkid_idinfo *id = chn->driver->idinfos[i];
365
366 DBG(DEBUG_LOWPROBE, printf("%d: %s: %s\n",
367 i,
368 id->name,
369 blkid_bmp_get_item(chn->fltr, i)
370 ? "disabled" : "enabled <--"));
371 }
372 return 0;
373 }
374 ***/
375
376 /*
377 * Returns properly initialized chain filter
378 */
379 unsigned long *blkid_probe_get_filter(blkid_probe pr, int chain, int create)
380 {
381 struct blkid_chain *chn;
382
383 if (!pr || chain < 0 || chain >= BLKID_NCHAINS)
384 return NULL;
385
386 chn = &pr->chains[chain];
387
388 /* always when you touch the chain filter all indexes are reseted and
389 * probing starts from scratch
390 */
391 blkid_probe_chain_reset_position(chn);
392 pr->cur_chain = NULL;
393
394 if (!chn->driver->has_fltr || (!chn->fltr && !create))
395 return NULL;
396
397 if (!chn->fltr)
398 chn->fltr = calloc(1, blkid_bmp_nbytes(chn->driver->nidinfos));
399 else
400 memset(chn->fltr, 0, blkid_bmp_nbytes(chn->driver->nidinfos));
401
402 /* blkid_probe_dump_filter(pr, chain); */
403 return chn->fltr;
404 }
405
406 /*
407 * Generic private functions for filter setting
408 */
409 int __blkid_probe_invert_filter(blkid_probe pr, int chain)
410 {
411 int i;
412 struct blkid_chain *chn;
413 unsigned long *fltr;
414
415 fltr = blkid_probe_get_filter(pr, chain, FALSE);
416 if (!fltr)
417 return -1;
418
419 chn = &pr->chains[chain];
420
421 for (i = 0; i < blkid_bmp_nwords(chn->driver->nidinfos); i++)
422 fltr[i] = ~fltr[i];
423
424 DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n"));
425 /* blkid_probe_dump_filter(pr, chain); */
426 return 0;
427 }
428
429 int __blkid_probe_reset_filter(blkid_probe pr, int chain)
430 {
431 return blkid_probe_get_filter(pr, chain, FALSE) ? 0 : -1;
432 }
433
434 int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[])
435 {
436 unsigned long *fltr;
437 struct blkid_chain *chn;
438 int i;
439
440 fltr = blkid_probe_get_filter(pr, chain, TRUE);
441 if (!fltr)
442 return -1;
443
444 chn = &pr->chains[chain];
445
446 for (i = 0; i < chn->driver->nidinfos; i++) {
447 int has = 0;
448 const struct blkid_idinfo *id = chn->driver->idinfos[i];
449 char **n;
450
451 for (n = names; *n; n++) {
452 if (!strcmp(id->name, *n)) {
453 has = 1;
454 break;
455 }
456 }
457 if (flag & BLKID_FLTR_ONLYIN) {
458 if (!has)
459 blkid_bmp_set_item(fltr, i);
460 } else if (flag & BLKID_FLTR_NOTIN) {
461 if (has)
462 blkid_bmp_set_item(fltr, i);
463 }
464 }
465
466 DBG(DEBUG_LOWPROBE,
467 printf("%s: a new probing type-filter initialized\n",
468 chn->driver->name));
469 /* blkid_probe_dump_filter(pr, chain); */
470 return 0;
471 }
472
473 static int blkid_probe_has_buffer(blkid_probe pr,
474 blkid_loff_t off, blkid_loff_t len)
475 {
476 return pr && (off + len <= pr->sbbuf_len ||
477 (pr->buf_off < off && off + len < pr->buf_len));
478 }
479
480 /*
481 * Returns buffer from the begin (69kB) of the device.
482 */
483 static unsigned char *blkid_probe_get_sb_buffer(blkid_probe pr,
484 blkid_loff_t off, blkid_loff_t len)
485 {
486 if (off + len > BLKID_SB_BUFSIZ)
487 return NULL;
488 if (!pr->sbbuf) {
489 pr->sbbuf = malloc(BLKID_SB_BUFSIZ);
490 if (!pr->sbbuf)
491 return NULL;
492 }
493 if (off + len > pr->sbbuf_len) {
494 /*
495 * The sbbuf is not completely in memory.
496 *
497 * We don't read whole BLKID_SB_BUFSIZ by one read(), it's too
498 * aggresive to small devices (floppies). We read necessary
499 * data to complete the current request (off + len) only.
500 */
501 ssize_t ret_read;
502
503 blkid_loff_t have = pr->sbbuf_len,
504 want = off + len - have;
505
506 DBG(DEBUG_LOWPROBE,
507 printf("\tsb-buffer read() off=%jd len=%jd\n", have, want));
508
509 if (lseek(pr->fd, pr->off + have, SEEK_SET) < 0)
510 return NULL;
511
512 ret_read = read(pr->fd, pr->sbbuf + have, want);
513 if (ret_read < 0)
514 ret_read = 0;
515 pr->sbbuf_len = have + ret_read;
516 }
517 if (off + len > pr->sbbuf_len)
518 return NULL;
519 return pr->sbbuf + off;
520 }
521
522 /*
523 * Returns pointer to the buffer on arbitrary offset on the device
524 */
525 unsigned char *blkid_probe_get_extra_buffer(blkid_probe pr,
526 blkid_loff_t off, blkid_loff_t len)
527 {
528 unsigned char *newbuf = NULL;
529
530 if (off + len <= BLKID_SB_BUFSIZ &&
531 (!blkid_probe_is_tiny(pr) || blkid_probe_has_buffer(pr, off, len)))
532 /*
533 * Don't use extra buffer for superblock data if
534 * - data are already in SB buffer
535 * - or the device is large and we needn't extra
536 * optimalization for tiny devices
537 */
538 return blkid_probe_get_sb_buffer(pr, off, len);
539
540 if (len > pr->buf_max) {
541 newbuf = realloc(pr->buf, len);
542 if (!newbuf)
543 return NULL;
544 pr->buf = newbuf;
545 pr->buf_max = len;
546 pr->buf_off = 0;
547 pr->buf_len = 0;
548 }
549 if (newbuf || off < pr->buf_off ||
550 off + len > pr->buf_off + pr->buf_len) {
551 ssize_t ret_read;
552
553 if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0)
554 return NULL;
555
556 DBG(DEBUG_LOWPROBE,
557 printf("\textra-buffer read: off=%jd len=%jd\n", off, len));
558
559 ret_read = read(pr->fd, pr->buf, len);
560 if (ret_read != (ssize_t) len)
561 return NULL;
562 pr->buf_off = off;
563 pr->buf_len = len;
564 }
565 return off ? pr->buf + (off - pr->buf_off) : pr->buf;
566 }
567
568
569 /*
570 * @off: offset within probing area
571 * @len: size of requested buffer
572 *
573 * The probing area is between pr->off and pr->size. The @off = 0 is pr->off, the
574 * max @len is pr->size.
575 *
576 * Note that we have two offsets:
577 *
578 * 1/ general device offset (pr->off), that's useful for example when we
579 * probe a partition from whole disk image:
580 * blkid -O <partition_position> -S <size> disk.img
581 *
582 * 2/ buffer offset (the @off argument), that useful for offsets in
583 * superbloks, ...
584 *
585 * That means never use lseek(fd, 0, SEEK_SET), the zero position is always
586 * pr->off, so lseek(fd, pr->off, SEEK_SET).
587 *
588 */
589 unsigned char *blkid_probe_get_buffer(blkid_probe pr,
590 blkid_loff_t off, blkid_loff_t len)
591 {
592 if (off < 0 || len < 0) {
593 DBG(DEBUG_LOWPROBE,
594 printf("unexpected offset or length of buffer requested\n"));
595 return NULL;
596 }
597 if (off + len > pr->size)
598 return NULL;
599 if (off + len <= BLKID_SB_BUFSIZ)
600 return blkid_probe_get_sb_buffer(pr, off, len);
601 return blkid_probe_get_extra_buffer(pr, off, len);
602 }
603
604 /*
605 * Small devices need a special care.
606 */
607 int blkid_probe_is_tiny(blkid_probe pr)
608 {
609 return (pr && pr->size <= 1440 * 1024 && !S_ISCHR(pr->mode));
610 }
611
612 /**
613 * blkid_probe_set_device:
614 * @pr: probe
615 * @fd: device file descriptor
616 * @off: begin of probing area
617 * @size: size of probing area (zero means whole device/file)
618 *
619 * Assigns the device to probe control struct, resets internal buffers and
620 * resets the current probing.
621 *
622 * Returns: -1 in case of failure, or 0 on success.
623 */
624 int blkid_probe_set_device(blkid_probe pr, int fd,
625 blkid_loff_t off, blkid_loff_t size)
626 {
627 if (!pr)
628 return -1;
629
630 blkid_reset_probe(pr);
631
632 if ((pr->flags & BLKID_PRIVATE_FD) && pr->fd >= 0)
633 close(pr->fd);
634
635 pr->flags &= ~BLKID_PRIVATE_FD;
636 pr->fd = fd;
637 pr->off = off;
638 pr->size = 0;
639 pr->devno = 0;
640 pr->mode = 0;
641 pr->blkssz = 0;
642
643 if (size)
644 pr->size = size;
645 else {
646 struct stat sb;
647
648 if (fstat(fd, &sb))
649 goto err;
650
651 pr->mode = sb.st_mode;
652
653 if (S_ISBLK(sb.st_mode))
654 blkdev_get_size(fd, (unsigned long long *) &pr->size);
655 else if (S_ISCHR(sb.st_mode))
656 pr->size = 1; /* UBI devices are char... */
657 else if (S_ISREG(sb.st_mode))
658 pr->size = sb.st_size; /* regular file */
659
660 if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode))
661 pr->devno = sb.st_rdev;
662
663 if (pr->off > pr->size)
664 goto err;
665
666 /* The probing area cannot be larger than whole device, pr->off
667 * is offset within the device */
668 pr->size -= pr->off;
669 }
670
671 if (!pr->size)
672 goto err;
673 DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n",
674 pr->off, pr->size));
675 return 0;
676 err:
677 DBG(DEBUG_LOWPROBE,
678 printf("failed to prepare a device for low-probing\n"));
679 return -1;
680
681 }
682
683 int blkid_probe_get_dimension(blkid_probe pr,
684 blkid_loff_t *off, blkid_loff_t *size)
685 {
686 if (!pr)
687 return -1;
688
689 *off = pr->off;
690 *size = pr->size;
691 return 0;
692 }
693
694 int blkid_probe_set_dimension(blkid_probe pr,
695 blkid_loff_t off, blkid_loff_t size)
696 {
697 if (!pr)
698 return -1;
699
700 DBG(DEBUG_LOWPROBE, printf(
701 "changing probing area: size=%llu, off=%llu "
702 "-to-> size=%llu, off=%llu\n",
703 (unsigned long long) pr->size,
704 (unsigned long long) pr->off,
705 (unsigned long long) size,
706 (unsigned long long) off));
707
708 pr->off = off;
709 pr->size = size;
710
711 blkid_probe_reset_buffer(pr);
712
713 return 0;
714 }
715
716 /**
717 * blkid_do_probe:
718 * @pr: prober
719 *
720 * Calls probing functions in all enabled chains. The superblocks chain is
721 * enabled by default. The blkid_do_probe() stores result from only one
722 * probing function. It's necessary to call this routine in a loop to get
723 * results from all probing functions in all chains. The probing is reseted
724 * by blkid_reset_probe() or by filter functions.
725 *
726 * This is string-based NAME=value interface only.
727 *
728 * <example>
729 * <title>basic case - use the first result only</title>
730 * <programlisting>
731 *
732 * if (blkid_do_probe(pr) == 0) {
733 * int nvals = blkid_probe_numof_values(pr);
734 * for (n = 0; n < nvals; n++) {
735 * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0)
736 * printf("%s = %s\n", name, data);
737 * }
738 * }
739 * </programlisting>
740 * </example>
741 *
742 * <example>
743 * <title>advanced case - probe for all signatures</title>
744 * <programlisting>
745 *
746 * while (blkid_do_probe(pr) == 0) {
747 * int nvals = blkid_probe_numof_values(pr);
748 * ...
749 * }
750 * </programlisting>
751 * </example>
752 *
753 * See also blkid_reset_probe().
754 *
755 * Returns: 0 on success, 1 when probing is done and -1 in case of error.
756 */
757 int blkid_do_probe(blkid_probe pr)
758 {
759 int rc = 1;
760
761 if (!pr)
762 return -1;
763
764 do {
765 struct blkid_chain *chn = pr->cur_chain;
766
767 if (!chn)
768 chn = pr->cur_chain = &pr->chains[0];
769
770 /* we go to the next chain only when the previous probing
771 * result was nothing (rc == 1) and when the current chain is
772 * disabled or we are at end of the current chain (chain->idx +
773 * 1 == sizeof chain)
774 */
775 else if (rc == 1 && (chn->enabled == FALSE ||
776 chn->idx + 1 == chn->driver->nidinfos)) {
777
778 int idx = chn->driver->id + 1;
779
780 if (idx < BLKID_NCHAINS)
781 chn = pr->cur_chain = &pr->chains[idx];
782 else
783 return 1; /* all chains already probed */
784 }
785
786 chn->binary = FALSE; /* for sure... */
787
788 DBG(DEBUG_LOWPROBE, printf("chain probe %s %s (idx=%d)\n",
789 chn->driver->name,
790 chn->enabled? "ENABLED" : "DISABLED",
791 chn->idx));
792
793 if (!chn->enabled)
794 continue;
795
796 /* rc: -1 = error, 0 = success, 1 = no result */
797 rc = chn->driver->probe(pr, chn);
798
799 } while (rc == 1);
800
801 return rc;
802 }
803
804 /**
805 * blkid_do_safeprobe:
806 * @pr: prober
807 *
808 * This function gathers probing results from all enabled chains and checks
809 * for ambivalent results (e.g. more filesystems on the device).
810 *
811 * This is string-based NAME=value interface only.
812 *
813 * Note about suberblocks chain -- the function does not check for filesystems
814 * when a RAID signature is detected. The function also does not check for
815 * collision between RAIDs. The first detected RAID is returned.
816 *
817 * Returns: 0 on success, 1 if nothing is detected, -2 if ambivalen result is
818 * detected and -1 on case of error.
819 */
820 int blkid_do_safeprobe(blkid_probe pr)
821 {
822 int i, count = 0, rc = 0;
823
824 if (!pr)
825 return -1;
826
827 for (i = 0; i < BLKID_NCHAINS; i++) {
828 struct blkid_chain *chn;
829
830 chn = pr->cur_chain = &pr->chains[i];
831 chn->binary = FALSE; /* for sure... */
832
833 DBG(DEBUG_LOWPROBE, printf("chain safeprobe %s %s\n",
834 chn->driver->name,
835 chn->enabled? "ENABLED" : "DISABLED"));
836
837 if (!chn->enabled)
838 continue;
839
840 blkid_probe_chain_reset_position(chn);
841
842 rc = chn->driver->safeprobe(pr, chn);
843
844 blkid_probe_chain_reset_position(chn);
845
846 /* rc: -2 ambivalent, -1 = error, 0 = success, 1 = no result */
847 if (rc < 0)
848 goto done; /* error */
849 if (rc == 0)
850 count++; /* success */
851 }
852
853 done:
854 pr->cur_chain = NULL;
855 if (rc < 0)
856 return rc;
857 return count ? 0 : 1;
858 }
859
860 /**
861 * blkid_do_fullprobe:
862 * @pr: prober
863 *
864 * This function gathers probing results from all enabled chains. Same as
865 * blkid_so_safeprobe() but does not check for collision between probing
866 * result.
867 *
868 * This is string-based NAME=value interface only.
869 *
870 * Returns: 0 on success, 1 if nothing is detected or -1 on case of error.
871 */
872 int blkid_do_fullprobe(blkid_probe pr)
873 {
874 int i, count = 0, rc = 0;
875
876 if (!pr)
877 return -1;
878
879 for (i = 0; i < BLKID_NCHAINS; i++) {
880 int rc;
881 struct blkid_chain *chn;
882
883 chn = pr->cur_chain = &pr->chains[i];
884 chn->binary = FALSE; /* for sure... */
885
886 DBG(DEBUG_LOWPROBE, printf("chain fullprobe %s: %s\n",
887 chn->driver->name,
888 chn->enabled? "ENABLED" : "DISABLED"));
889
890 if (!chn->enabled)
891 continue;
892
893 blkid_probe_chain_reset_position(chn);
894
895 rc = chn->driver->probe(pr, chn);
896
897 blkid_probe_chain_reset_position(chn);
898
899 /* rc: -1 = error, 0 = success, 1 = no result */
900 if (rc < 0)
901 goto done; /* error */
902 if (rc == 0)
903 count++; /* success */
904 }
905
906 done:
907 pr->cur_chain = NULL;
908 if (rc < 0)
909 return rc;
910 return count ? 0 : 1;
911 }
912
913 /* same sa blkid_probe_get_buffer() but works with 512-sectors */
914 unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector)
915 {
916 return pr ? blkid_probe_get_buffer(pr,
917 ((blkid_loff_t) sector) << 9, 0x200) : NULL;
918 }
919
920 struct blkid_prval *blkid_probe_assign_value(
921 blkid_probe pr, const char *name)
922 {
923 struct blkid_prval *v;
924
925 if (!name)
926 return NULL;
927 if (pr->nvals >= BLKID_NVALS)
928 return NULL;
929
930 v = &pr->vals[pr->nvals];
931 v->name = name;
932 v->chain = pr->cur_chain;
933 pr->nvals++;
934
935 DBG(DEBUG_LOWPROBE,
936 printf("assigning %s [%s]\n", name, v->chain->driver->name));
937 return v;
938 }
939
940 int blkid_probe_reset_last_value(blkid_probe pr)
941 {
942 struct blkid_prval *v;
943
944 if (pr == NULL || pr->nvals == 0)
945 return -1;
946
947 v = &pr->vals[pr->nvals - 1];
948
949 DBG(DEBUG_LOWPROBE,
950 printf("un-assigning %s [%s]\n", v->name, v->chain->driver->name));
951
952 memset(v, 0, sizeof(struct blkid_prval));
953 pr->nvals--;
954
955 return 0;
956
957 }
958
959 int blkid_probe_set_value(blkid_probe pr, const char *name,
960 unsigned char *data, size_t len)
961 {
962 struct blkid_prval *v;
963
964 if (len > BLKID_PROBVAL_BUFSIZ)
965 len = BLKID_PROBVAL_BUFSIZ;
966
967 v = blkid_probe_assign_value(pr, name);
968 if (!v)
969 return -1;
970
971 memcpy(v->data, data, len);
972 v->len = len;
973 return 0;
974 }
975
976 int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
977 const char *fmt, va_list ap)
978 {
979 struct blkid_prval *v;
980 size_t len;
981
982 v = blkid_probe_assign_value(pr, name);
983 if (!v)
984 return -1;
985
986 len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap);
987
988 if (len <= 0) {
989 blkid_probe_reset_last_value(pr);
990 return -1;
991 }
992 v->len = len + 1;
993 return 0;
994 }
995
996 int blkid_probe_sprintf_value(blkid_probe pr, const char *name,
997 const char *fmt, ...)
998 {
999 int rc;
1000 va_list ap;
1001
1002 va_start(ap, fmt);
1003 rc = blkid_probe_vsprintf_value(pr, name, fmt, ap);
1004 va_end(ap);
1005
1006 return rc;
1007 }
1008
1009 /**
1010 * blkid_probe_get_devno:
1011 * @pr: probe
1012 *
1013 * Returns: block device number, or 0 for regilar files.
1014 */
1015 dev_t blkid_probe_get_devno(blkid_probe pr)
1016 {
1017 if (!pr->devno) {
1018 struct stat sb;
1019
1020 if (fstat(pr->fd, &sb) == 0 &&
1021 (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)))
1022 pr->devno = sb.st_rdev;
1023 }
1024 return pr->devno;
1025 }
1026
1027 /**
1028 * blkid_probe_get_size:
1029 * @pr: probe
1030 *
1031 * Returns: block device (or file) size in bytes or -1 in case of error.
1032 */
1033 blkid_loff_t blkid_probe_get_size(blkid_probe pr)
1034 {
1035 return pr ? pr->size : -1;
1036 }
1037
1038 /**
1039 * blkid_probe_get_sectorsize:
1040 * @pr: probe
1041 *
1042 * Returns: block device logical sector size (BLKSSZGET ioctl, default 512).
1043 */
1044 unsigned int blkid_probe_get_sectorsize(blkid_probe pr)
1045 {
1046 if (!pr)
1047 return DEFAULT_SECTOR_SIZE; /*... and good luck! */
1048 if (pr->blkssz)
1049 return pr->blkssz;
1050 if (!pr->mode) {
1051 struct stat st;
1052
1053 if (fstat(pr->fd, &st))
1054 goto fallback;
1055 pr->mode = st.st_mode;
1056 }
1057 if (S_ISBLK(pr->mode)) {
1058 if (blkdev_get_sector_size(pr->fd, (int *) &pr->blkssz))
1059 goto fallback;
1060
1061 return pr->blkssz;
1062 }
1063
1064 fallback:
1065 pr->blkssz = DEFAULT_SECTOR_SIZE;
1066 return pr->blkssz;
1067 }
1068
1069 /**
1070 * blkid_probe_numof_values:
1071 * @pr: probe
1072 *
1073 * Returns: number of values in probing result or -1 in case of error.
1074 */
1075 int blkid_probe_numof_values(blkid_probe pr)
1076 {
1077 if (!pr)
1078 return -1;
1079 return pr->nvals;
1080 }
1081
1082 /**
1083 * blkid_probe_get_value:
1084 * @pr: probe
1085 * @num: wanted value in range 0..N, where N is blkid_probe_numof_values() - 1
1086 * @name: pointer to return value name or NULL
1087 * @data: pointer to return value data or NULL
1088 * @len: pointer to return value length or NULL
1089 *
1090 * Note, the @len returns length of the @data, including the terminating
1091 * '\0' character.
1092 *
1093 * Returns: 0 on success, or -1 in case of error.
1094 */
1095 int blkid_probe_get_value(blkid_probe pr, int num, const char **name,
1096 const char **data, size_t *len)
1097 {
1098 struct blkid_prval *v = __blkid_probe_get_value(pr, num);
1099
1100 if (!v)
1101 return -1;
1102 if (name)
1103 *name = v->name;
1104 if (data)
1105 *data = (char *) v->data;
1106 if (len)
1107 *len = v->len;
1108
1109 DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
1110 return 0;
1111 }
1112
1113 /**
1114 * blkid_probe_lookup_value:
1115 * @pr: probe
1116 * @name: name of value
1117 * @data: pointer to return value data or NULL
1118 * @len: pointer to return value length or NULL
1119 *
1120 * Note, the @len returns length of the @data, including the terminating
1121 * '\0' character.
1122 *
1123 * Returns: 0 on success, or -1 in case of error.
1124 */
1125 int blkid_probe_lookup_value(blkid_probe pr, const char *name,
1126 const char **data, size_t *len)
1127 {
1128 struct blkid_prval *v = __blkid_probe_lookup_value(pr, name);
1129
1130 if (!v)
1131 return -1;
1132 if (data)
1133 *data = (char *) v->data;
1134 if (len)
1135 *len = v->len;
1136 return 0;
1137 }
1138
1139 /**
1140 * blkid_probe_has_value:
1141 * @pr: probe
1142 * @name: name of value
1143 *
1144 * Returns: 1 if value exist in probing result, otherwise 0.
1145 */
1146 int blkid_probe_has_value(blkid_probe pr, const char *name)
1147 {
1148 if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0)
1149 return 1;
1150 return 0;
1151 }
1152
1153 struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num)
1154 {
1155 if (pr == NULL || num < 0 || num >= pr->nvals)
1156 return NULL;
1157
1158 return &pr->vals[num];
1159 }
1160
1161 struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name)
1162 {
1163 int i;
1164
1165 if (pr == NULL || pr->nvals == 0 || name == NULL)
1166 return NULL;
1167
1168 for (i = 0; i < pr->nvals; i++) {
1169 struct blkid_prval *v = &pr->vals[i];
1170
1171 if (v->name && strcmp(name, v->name) == 0) {
1172 DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
1173 return v;
1174 }
1175 }
1176 return NULL;
1177 }
1178
1179
1180 /* converts DCE UUID (uuid[16]) to human readable string
1181 * - the @len should be always 37 */
1182 void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len)
1183 {
1184 #ifdef HAVE_LIBUUID
1185 uuid_unparse(uuid, str);
1186 #else
1187 snprintf(str, len,
1188 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1189 uuid[0], uuid[1], uuid[2], uuid[3],
1190 uuid[4], uuid[5],
1191 uuid[6], uuid[7],
1192 uuid[8], uuid[9],
1193 uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]);
1194 #endif
1195 }
1196
1197
1198 /* Removes whitespace from the right-hand side of a string (trailing
1199 * whitespace).
1200 *
1201 * Returns size of the new string (without \0).
1202 */
1203 size_t blkid_rtrim_whitespace(unsigned char *str)
1204 {
1205 size_t i = strlen((char *) str);
1206
1207 while (i--) {
1208 if (!isspace(str[i]))
1209 break;
1210 }
1211 str[++i] = '\0';
1212 return i;
1213 }
1214