]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - shlibs/blkid/src/probe.c
2 * probe.c - reads tags (LABEL, UUID, FS type, ..) from a block device
4 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
16 #include <sys/types.h>
17 #ifdef HAVE_SYS_STAT_H
20 #ifdef HAVE_SYS_MKDEV_H
21 #include <sys/mkdev.h>
30 # ifdef HAVE_UUID_UUID_H
31 # include <uuid/uuid.h>
40 #include "superblocks/superblocks.h"
42 static const struct blkid_idinfo
*idinfos
[] =
100 # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
103 #define BLKID_FLTR_ITEMS ARRAY_SIZE(idinfos)
104 #define BLKID_FLTR_SIZE blkid_bmp_nwords(BLKID_FLTR_ITEMS)
106 static int blkid_probe_set_usage(blkid_probe pr
, int usage
);
108 int blkid_known_fstype(const char *fstype
)
115 for (i
= 0; i
< ARRAY_SIZE(idinfos
); i
++) {
116 const struct blkid_idinfo
*id
= idinfos
[i
];
117 if (strcmp(id
->name
, fstype
) == 0)
124 * Returns a pointer to the newly allocated probe struct
126 blkid_probe
blkid_new_probe(void)
129 return calloc(1, sizeof(struct blkid_struct_probe
));
133 * Deallocates probe struct, buffers and all allocated
134 * data that are associated with this probing control struct.
136 void blkid_free_probe(blkid_probe pr
)
146 static void blkid_probe_reset_vals(blkid_probe pr
)
148 memset(pr
->vals
, 0, sizeof(pr
->vals
));
152 static void blkid_probe_reset_idx(blkid_probe pr
)
157 void blkid_reset_probe(blkid_probe pr
)
161 DBG(DEBUG_LOWPROBE
, printf("reseting blkid_probe\n"));
163 memset(pr
->buf
, 0, pr
->buf_max
);
167 memset(pr
->sbbuf
, 0, BLKID_SB_BUFSIZ
);
169 blkid_probe_reset_vals(pr
);
170 blkid_probe_reset_idx(pr
);
174 * Note that we have two offsets:
176 * 1/ general device offset (pr->off), that's useful for example when we
177 * probe a partition from whole disk image:
178 * blkid-low --offset <partition_position> disk.img
180 * 2/ buffer offset (the 'off' argument), that useful for offsets in
183 * That means never use lseek(fd, 0, SEEK_SET), the zero position is always
184 * pr->off, so lseek(fd, pr->off, SEEK_SET).
187 unsigned char *blkid_probe_get_buffer(blkid_probe pr
,
188 blkid_loff_t off
, blkid_loff_t len
)
190 ssize_t ret_read
= 0;
192 if (off
< 0 || len
< 0) {
194 printf("unexpected offset or length of buffer requested\n"));
197 if (off
+ len
<= BLKID_SB_BUFSIZ
) {
199 pr
->sbbuf
= malloc(BLKID_SB_BUFSIZ
);
203 if (!pr
->sbbuf_len
) {
204 if (lseek(pr
->fd
, pr
->off
, SEEK_SET
) < 0)
206 ret_read
= read(pr
->fd
, pr
->sbbuf
, BLKID_SB_BUFSIZ
);
209 pr
->sbbuf_len
= ret_read
;
211 if (off
+ len
> pr
->sbbuf_len
)
213 return pr
->sbbuf
+ off
;
215 unsigned char *newbuf
= NULL
;
217 if (len
> pr
->buf_max
) {
218 newbuf
= realloc(pr
->buf
, len
);
226 if (newbuf
|| off
< pr
->buf_off
||
227 off
+ len
> pr
->buf_off
+ pr
->buf_len
) {
229 if (blkid_llseek(pr
->fd
, pr
->off
+ off
, SEEK_SET
) < 0)
232 ret_read
= read(pr
->fd
, pr
->buf
, len
);
233 if (ret_read
!= (ssize_t
) len
)
238 return off
? pr
->buf
+ (off
- pr
->buf_off
) : pr
->buf
;
243 * Assignes the device to probe control struct, resets internal buffers and
244 * reads 512 bytes from device to the buffers.
246 * Returns -1 in case of failure, or 0 on success.
248 int blkid_probe_set_device(blkid_probe pr
, int fd
,
249 blkid_loff_t off
, blkid_loff_t size
)
254 blkid_reset_probe(pr
);
268 if (S_ISBLK(sb
.st_mode
))
269 blkdev_get_size(fd
, (unsigned long long *) &pr
->size
);
271 pr
->size
= sb
.st_size
;
276 /* read SB to test if the device is readable */
277 if (!blkid_probe_get_buffer(pr
, 0, 0x200)) {
279 printf("failed to prepare a device for low-probing\n"));
283 DBG(DEBUG_LOWPROBE
, printf("ready for low-probing, offset=%zd, size=%zd\n",
288 int blkid_probe_set_request(blkid_probe pr
, int flags
)
296 int blkid_probe_reset_filter(blkid_probe pr
)
301 memset(pr
->fltr
, 0, BLKID_FLTR_SIZE
* sizeof(unsigned long));
302 blkid_probe_reset_idx(pr
);
309 * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN names[]
311 * BLKID_FLTR_ONLYIN - probe filesystem which are IN names[]
313 int blkid_probe_filter_types(blkid_probe pr
, int flag
, char *names
[])
320 pr
->fltr
= calloc(BLKID_FLTR_SIZE
, sizeof(unsigned long));
321 blkid_probe_reset_idx(pr
);
323 blkid_probe_reset_filter(pr
);
328 for (i
= 0; i
< ARRAY_SIZE(idinfos
); i
++) {
330 const struct blkid_idinfo
*id
= idinfos
[i
];
333 for (n
= names
; *n
; n
++) {
334 if (!strcmp(id
->name
, *n
)) {
339 /* The default is enable all filesystems,
340 * set relevant bitmap bit means disable the filesystem.
342 if (flag
& BLKID_FLTR_ONLYIN
) {
344 blkid_bmp_set_item(pr
->fltr
, i
);
345 } else if (flag
& BLKID_FLTR_NOTIN
) {
347 blkid_bmp_set_item(pr
->fltr
, i
);
350 DBG(DEBUG_LOWPROBE
, printf("a new probing type-filter initialized\n"));
357 * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN "usage"
359 * BLKID_FLTR_ONLYIN - probe filesystem which are IN "usage"
361 * where the "usage" is a set of filesystem according the usage flag (crypto,
362 * raid, filesystem, ...)
364 int blkid_probe_filter_usage(blkid_probe pr
, int flag
, int usage
)
371 pr
->fltr
= calloc(BLKID_FLTR_SIZE
, sizeof(unsigned long));
372 blkid_probe_reset_idx(pr
);
374 blkid_probe_reset_filter(pr
);
379 for (i
= 0; i
< ARRAY_SIZE(idinfos
); i
++) {
380 const struct blkid_idinfo
*id
= idinfos
[i
];
382 if (id
->usage
& usage
) {
383 if (flag
& BLKID_FLTR_NOTIN
)
384 blkid_bmp_set_item(pr
->fltr
, i
);
385 } else if (flag
& BLKID_FLTR_ONLYIN
)
386 blkid_bmp_set_item(pr
->fltr
, i
);
388 DBG(DEBUG_LOWPROBE
, printf("a new probing usage-filter initialized\n"));
393 int blkid_probe_invert_filter(blkid_probe pr
)
397 if (!pr
|| !pr
->fltr
)
399 for (i
= 0; i
< BLKID_FLTR_SIZE
; i
++)
400 pr
->fltr
[i
] = ~pr
->fltr
[i
];
402 blkid_probe_reset_idx(pr
);
403 DBG(DEBUG_LOWPROBE
, printf("probing filter inverted\n"));
408 * The blkid_do_probe() calls the probe functions. This routine could be used
409 * in a loop when you need to probe for all possible filesystems/raids.
411 * 1/ basic case -- use the first result:
413 * if (blkid_do_probe(pr) == 0) {
414 * int nvals = blkid_probe_numof_values(pr);
415 * for (n = 0; n < nvals; n++) {
416 * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0)
417 * printf("%s = %s\n", name, data);
421 * 2/ advanced case -- probe for all signatures (don't forget that some
422 * filesystems can co-exist on one volume (e.g. CD-ROM).
424 * while (blkid_do_probe(pr) == 0) {
425 * int nvals = blkid_probe_numof_values(pr);
429 * The internal probing index (pointer to the last probing function) is
430 * always reseted when you touch probing filter or set a new device. It
431 * means you cannot use:
433 * blkid_probe_invert_filter()
434 * blkid_probe_filter_usage()
435 * blkid_probe_filter_types()
436 * blkid_probe_reset_filter()
437 * blkid_probe_set_device()
439 * in the loop (e.g while()) when you iterate on all signatures.
441 int blkid_do_probe(blkid_probe pr
)
445 if (!pr
|| pr
->idx
< -1)
448 blkid_probe_reset_vals(pr
);
451 printf("--> starting probing loop [idx=%d]\n",
456 for ( ; i
< ARRAY_SIZE(idinfos
); i
++) {
457 const struct blkid_idinfo
*id
;
458 const struct blkid_idmag
*mag
;
463 if (pr
->fltr
&& blkid_bmp_get_item(pr
->fltr
, i
))
467 mag
= id
->magics
? &id
->magics
[0] : NULL
;
469 /* try to detect by magic string */
470 while(mag
&& mag
->magic
) {
474 idx
= mag
->kboff
+ (mag
->sboff
>> 10);
475 buf
= blkid_probe_get_buffer(pr
, idx
<< 10, 1024);
477 if (buf
&& !memcmp(mag
->magic
,
478 buf
+ (mag
->sboff
& 0x3ff), mag
->len
)) {
479 DBG(DEBUG_LOWPROBE
, printf(
480 "%s: magic sboff=%u, kboff=%ld\n",
481 id
->name
, mag
->sboff
, mag
->kboff
));
488 if (hasmag
== 0 && id
->magics
&& id
->magics
[0].magic
)
489 /* magic string(s) defined, but not found */
492 /* final check by probing function */
494 DBG(DEBUG_LOWPROBE
, printf(
495 "%s: call probefunc()\n", id
->name
));
496 if (id
->probefunc(pr
, mag
) != 0)
500 /* all cheks passed */
501 if (pr
->probreq
& BLKID_PROBREQ_TYPE
)
502 blkid_probe_set_value(pr
, "TYPE",
503 (unsigned char *) id
->name
,
504 strlen(id
->name
) + 1);
505 if (pr
->probreq
& BLKID_PROBREQ_USAGE
)
506 blkid_probe_set_usage(pr
, id
->usage
);
509 printf("<-- leaving probing loop (type=%s) [idx=%d]\n",
514 printf("<-- leaving probing loop (failed) [idx=%d]\n",
520 * This is the same function as blkid_do_probe(), but returns only one result
521 * (cannot be used in while()) and checks for ambivalen results (more
522 * filesystems on the device) -- in such case returns -2.
524 * The function does not check for filesystems when a RAID signature is
525 * detected. The function also does not check for collision between RAIDs. The
526 * first detected RAID is returned.
528 int blkid_do_safeprobe(blkid_probe pr
)
530 struct blkid_struct_probe first
;
535 while ((rc
= blkid_do_probe(pr
)) == 0) {
537 /* store the fist result */
538 memcpy(first
.vals
, pr
->vals
, sizeof(first
.vals
));
539 first
.nvals
= pr
->nvals
;
544 if (idinfos
[pr
->idx
]->usage
& BLKID_USAGE_RAID
)
546 if (!(idinfos
[pr
->idx
]->flags
& BLKID_IDINFO_TOLERANT
))
550 return rc
; /* error */
551 if (count
> 1 && intol
) {
553 printf("ERROR: ambivalent result detected (%d filesystems)!\n",
555 return -2; /* error, ambivalent result (more FS) */
558 return 1; /* nothing detected */
560 /* restore the first result */
561 memcpy(pr
->vals
, first
.vals
, sizeof(first
.vals
));
562 pr
->nvals
= first
.nvals
;
568 int blkid_probe_numof_values(blkid_probe pr
)
576 static struct blkid_prval
*blkid_probe_assign_value(
577 blkid_probe pr
, const char *name
)
579 struct blkid_prval
*v
;
583 if (pr
->nvals
>= BLKID_NVALS
)
586 v
= &pr
->vals
[pr
->nvals
];
590 DBG(DEBUG_LOWPROBE
, printf("assigning %s\n", name
));
594 int blkid_probe_set_value(blkid_probe pr
, const char *name
,
595 unsigned char *data
, size_t len
)
597 struct blkid_prval
*v
;
599 if (len
> BLKID_PROBVAL_BUFSIZ
)
600 len
= BLKID_PROBVAL_BUFSIZ
;
602 v
= blkid_probe_assign_value(pr
, name
);
606 memcpy(v
->data
, data
, len
);
611 int blkid_probe_vsprintf_value(blkid_probe pr
, const char *name
,
612 const char *fmt
, va_list ap
)
614 struct blkid_prval
*v
;
617 v
= blkid_probe_assign_value(pr
, name
);
621 len
= vsnprintf((char *) v
->data
, sizeof(v
->data
), fmt
, ap
);
624 pr
->nvals
--; /* reset the latest assigned value */
631 int blkid_probe_set_version(blkid_probe pr
, const char *version
)
633 if (pr
->probreq
& BLKID_PROBREQ_VERSION
)
634 return blkid_probe_set_value(pr
, "VERSION",
635 (unsigned char *) version
, strlen(version
) + 1);
639 int blkid_probe_sprintf_version(blkid_probe pr
, const char *fmt
, ...)
643 if (pr
->probreq
& BLKID_PROBREQ_VERSION
) {
647 rc
= blkid_probe_vsprintf_value(pr
, "VERSION", fmt
, ap
);
653 static int blkid_probe_set_usage(blkid_probe pr
, int usage
)
657 if (usage
& BLKID_USAGE_FILESYSTEM
)
659 else if (usage
& BLKID_USAGE_RAID
)
661 else if (usage
& BLKID_USAGE_CRYPTO
)
663 else if (usage
& BLKID_USAGE_OTHER
)
668 return blkid_probe_set_value(pr
, "USAGE", (unsigned char *) u
, strlen(u
) + 1);
671 int blkid_probe_set_label(blkid_probe pr
, unsigned char *label
, size_t len
)
673 struct blkid_prval
*v
;
676 if (len
> BLKID_PROBVAL_BUFSIZ
)
677 len
= BLKID_PROBVAL_BUFSIZ
;
679 if ((pr
->probreq
& BLKID_PROBREQ_LABELRAW
) &&
680 blkid_probe_set_value(pr
, "LABEL_RAW", label
, len
) < 0)
682 if (!(pr
->probreq
& BLKID_PROBREQ_LABEL
))
684 v
= blkid_probe_assign_value(pr
, "LABEL");
688 memcpy(v
->data
, label
, len
);
691 /* remove trailing whitespace */
692 i
= strnlen((char *) v
->data
, len
);
694 if (!isspace(v
->data
[i
]))
702 int blkid_probe_set_utf8label(blkid_probe pr
, unsigned char *label
,
705 struct blkid_prval
*v
;
707 if ((pr
->probreq
& BLKID_PROBREQ_LABELRAW
) &&
708 blkid_probe_set_value(pr
, "LABEL_RAW", label
, len
) < 0)
710 if (!(pr
->probreq
& BLKID_PROBREQ_LABEL
))
712 v
= blkid_probe_assign_value(pr
, "LABEL");
716 v
->len
= blkid_encode_to_utf8(enc
, v
->data
, sizeof(v
->data
), label
, len
);
720 /* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */
721 static int uuid_is_empty(const unsigned char *buf
, size_t len
)
725 for (i
= 0; i
< len
; i
++)
731 int blkid_probe_sprintf_uuid(blkid_probe pr
, unsigned char *uuid
,
732 size_t len
, const char *fmt
, ...)
737 if (len
> BLKID_PROBVAL_BUFSIZ
)
738 len
= BLKID_PROBVAL_BUFSIZ
;
740 if (uuid_is_empty(uuid
, len
))
743 if ((pr
->probreq
& BLKID_PROBREQ_UUIDRAW
) &&
744 blkid_probe_set_value(pr
, "UUID_RAW", uuid
, len
) < 0)
746 if (!(pr
->probreq
& BLKID_PROBREQ_UUID
))
750 rc
= blkid_probe_vsprintf_value(pr
, "UUID", fmt
, ap
);
753 /* convert to lower case (..be paranoid) */
756 struct blkid_prval
*v
= &pr
->vals
[pr
->nvals
];
758 for (i
= 0; i
< v
->len
; i
++)
759 if (v
->data
[i
] >= 'A' && v
->data
[i
] <= 'F')
760 v
->data
[i
] = (v
->data
[i
] - 'A') + 'a';
765 /* function to set UUIDs that are in suberblocks stored as strings */
766 int blkid_probe_strncpy_uuid(blkid_probe pr
, unsigned char *str
, size_t len
)
768 struct blkid_prval
*v
;
770 if (str
== NULL
|| *str
== '\0')
773 len
= strlen((char *) str
);
774 if (len
> BLKID_PROBVAL_BUFSIZ
)
775 len
= BLKID_PROBVAL_BUFSIZ
;
777 if ((pr
->probreq
& BLKID_PROBREQ_UUIDRAW
) &&
778 blkid_probe_set_value(pr
, "UUID_RAW", str
, len
) < 0)
780 if (!(pr
->probreq
& BLKID_PROBREQ_UUID
))
783 v
= blkid_probe_assign_value(pr
, "UUID");
785 memcpy((char *) v
->data
, str
, len
);
786 *(v
->data
+ len
) = '\0';
793 /* default _set_uuid function to set DCE UUIDs */
794 int blkid_probe_set_uuid_as(blkid_probe pr
, unsigned char *uuid
, const char *name
)
796 struct blkid_prval
*v
;
798 if (uuid_is_empty(uuid
, 16))
802 if ((pr
->probreq
& BLKID_PROBREQ_UUIDRAW
) &&
803 blkid_probe_set_value(pr
, "UUID_RAW", uuid
, 16) < 0)
805 if (!(pr
->probreq
& BLKID_PROBREQ_UUID
))
808 v
= blkid_probe_assign_value(pr
, "UUID");
810 v
= blkid_probe_assign_value(pr
, name
);
812 blkid_unparse_uuid(uuid
, (char *) v
->data
, sizeof(v
->data
));
818 int blkid_probe_set_uuid(blkid_probe pr
, unsigned char *uuid
)
820 return blkid_probe_set_uuid_as(pr
, uuid
, NULL
);
823 int blkid_probe_get_value(blkid_probe pr
, int num
, const char **name
,
824 const char **data
, size_t *len
)
826 struct blkid_prval
*v
;
828 if (pr
== NULL
|| num
< 0 || num
>= pr
->nvals
)
835 *data
= (char *) v
->data
;
839 DBG(DEBUG_LOWPROBE
, printf("returning %s value\n", v
->name
));
843 int blkid_probe_lookup_value(blkid_probe pr
, const char *name
,
844 const char **data
, size_t *len
)
848 if (pr
== NULL
|| pr
->nvals
== 0 || name
== NULL
)
851 for (i
= 0; i
< pr
->nvals
; i
++) {
852 struct blkid_prval
*v
= &pr
->vals
[i
];
854 if (v
->name
&& strcmp(name
, v
->name
) == 0) {
856 *data
= (char *) v
->data
;
859 DBG(DEBUG_LOWPROBE
, printf("returning %s value\n", v
->name
));
866 int blkid_probe_has_value(blkid_probe pr
, const char *name
)
868 if (blkid_probe_lookup_value(pr
, name
, NULL
, NULL
) == 0)
874 /* converts DCE UUID (uuid[16]) to human readable string
875 * - the @len should be always 37 */
876 void blkid_unparse_uuid(const unsigned char *uuid
, char *str
, size_t len
)
879 uuid_unparse(uuid
, str
);
882 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
883 uuid
[0], uuid
[1], uuid
[2], uuid
[3],
887 uuid
[10], uuid
[11], uuid
[12], uuid
[13], uuid
[14],uuid
[15]);