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>
39 #include "probers/probers.h"
41 static const struct blkid_idinfo *idinfos[] =
99 # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
102 /* filter bitmap macros */
103 #define blkid_bmp_wordsize (8 * sizeof(unsigned long))
104 #define blkid_bmp_idx_bit(item) (1UL << ((item) % blkid_bmp_wordsize))
105 #define blkid_bmp_idx_byte(item) ((item) / blkid_bmp_wordsize)
107 #define blkid_bmp_set_item(bmp, item) \
108 ((bmp)[ blkid_bmp_idx_byte(item) ] |= blkid_bmp_idx_bit(item))
110 #define blkid_bmp_unset_item(bmp, item) \
111 ((bmp)[ bmp_idx_byte(item) ] &= ~bmp_idx_bit(item))
113 #define blkid_bmp_get_item(bmp, item) \
114 ((bmp)[ blkid_bmp_idx_byte(item) ] & blkid_bmp_idx_bit(item))
116 #define blkid_bmp_size(max_items) \
117 (((max_items) + blkid_bmp_wordsize) / blkid_bmp_wordsize)
119 #define BLKID_FLTR_ITEMS ARRAY_SIZE(idinfos)
120 #define BLKID_FLTR_SIZE blkid_bmp_size(BLKID_FLTR_ITEMS)
123 static int blkid_probe_set_usage(blkid_probe pr, int usage);
125 int blkid_known_fstype(const char *fstype)
132 for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
133 const struct blkid_idinfo *id = idinfos[i];
134 if (strcmp(id->name, fstype) == 0)
141 * Returns a pointer to the newly allocated probe struct
143 blkid_probe blkid_new_probe(void)
146 return calloc(1, sizeof(struct blkid_struct_probe));
150 * Deallocates probe struct, buffers and all allocated
151 * data that are associated with this probing control struct.
153 void blkid_free_probe(blkid_probe pr)
163 static void blkid_probe_reset_vals(blkid_probe pr)
165 memset(pr->vals, 0, sizeof(pr->vals));
169 static void blkid_probe_reset_idx(blkid_probe pr)
174 void blkid_reset_probe(blkid_probe pr)
178 DBG(DEBUG_LOWPROBE, printf("reseting blkid_probe\n"));
180 memset(pr->buf, 0, pr->buf_max);
184 memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ);
186 blkid_probe_reset_vals(pr);
187 blkid_probe_reset_idx(pr);
191 * Note that we have two offsets:
193 * 1/ general device offset (pr->off), that's useful for example when we
194 * probe a partition from whole disk image:
195 * blkid-low --offset <partition_position> disk.img
197 * 2/ buffer offset (the 'off' argument), that useful for offsets in
200 * That means never use lseek(fd, 0, SEEK_SET), the zero position is always
201 * pr->off, so lseek(fd, pr->off, SEEK_SET).
204 unsigned char *blkid_probe_get_buffer(blkid_probe pr,
205 blkid_loff_t off, blkid_loff_t len)
207 ssize_t ret_read = 0;
209 if (off < 0 || len < 0) {
211 printf("unexpected offset or length of buffer requested\n"));
214 if (off + len <= BLKID_SB_BUFSIZ) {
216 pr->sbbuf = malloc(BLKID_SB_BUFSIZ);
220 if (!pr->sbbuf_len) {
221 if (lseek(pr->fd, pr->off, SEEK_SET) < 0)
223 ret_read = read(pr->fd, pr->sbbuf, BLKID_SB_BUFSIZ);
226 pr->sbbuf_len = ret_read;
228 if (off + len > pr->sbbuf_len)
230 return pr->sbbuf + off;
232 unsigned char *newbuf = NULL;
234 if (len > pr->buf_max) {
235 newbuf = realloc(pr->buf, len);
243 if (newbuf || off < pr->buf_off ||
244 off + len > pr->buf_off + pr->buf_len) {
246 if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0)
249 ret_read = read(pr->fd, pr->buf, len);
250 if (ret_read != (ssize_t) len)
255 return off ? pr->buf + (off - pr->buf_off) : pr->buf;
260 * Assignes the device to probe control struct, resets internal buffers and
261 * reads 512 bytes from device to the buffers.
263 * Returns -1 in case of failure, or 0 on success.
265 int blkid_probe_set_device(blkid_probe pr, int fd,
266 blkid_loff_t off, blkid_loff_t size)
271 blkid_reset_probe(pr);
285 if (S_ISBLK(sb.st_mode))
286 blkdev_get_size(fd, (unsigned long long *) &pr->size);
288 pr->size = sb.st_size;
293 /* read SB to test if the device is readable */
294 if (!blkid_probe_get_buffer(pr, 0, 0x200)) {
296 printf("failed to prepare a device for low-probing\n"));
300 DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n",
305 int blkid_probe_set_request(blkid_probe pr, int flags)
313 int blkid_probe_reset_filter(blkid_probe pr)
318 memset(pr->fltr, 0, BLKID_FLTR_SIZE * sizeof(unsigned long));
319 blkid_probe_reset_idx(pr);
326 * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN names[]
328 * BLKID_FLTR_ONLYIN - probe filesystem which are IN names[]
330 int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[])
337 pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long));
338 blkid_probe_reset_idx(pr);
340 blkid_probe_reset_filter(pr);
345 for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
347 const struct blkid_idinfo *id = idinfos[i];
350 for (n = names; *n; n++) {
351 if (!strcmp(id->name, *n)) {
356 /* The default is enable all filesystems,
357 * set relevant bitmap bit means disable the filesystem.
359 if (flag & BLKID_FLTR_ONLYIN) {
361 blkid_bmp_set_item(pr->fltr, i);
362 } else if (flag & BLKID_FLTR_NOTIN) {
364 blkid_bmp_set_item(pr->fltr, i);
367 DBG(DEBUG_LOWPROBE, printf("a new probing type-filter initialized\n"));
374 * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN "usage"
376 * BLKID_FLTR_ONLYIN - probe filesystem which are IN "usage"
378 * where the "usage" is a set of filesystem according the usage flag (crypto,
379 * raid, filesystem, ...)
381 int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage)
388 pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long));
389 blkid_probe_reset_idx(pr);
391 blkid_probe_reset_filter(pr);
396 for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
397 const struct blkid_idinfo *id = idinfos[i];
399 if (id->usage & usage) {
400 if (flag & BLKID_FLTR_NOTIN)
401 blkid_bmp_set_item(pr->fltr, i);
402 } else if (flag & BLKID_FLTR_ONLYIN)
403 blkid_bmp_set_item(pr->fltr, i);
405 DBG(DEBUG_LOWPROBE, printf("a new probing usage-filter initialized\n"));
410 int blkid_probe_invert_filter(blkid_probe pr)
414 if (!pr || !pr->fltr)
416 for (i = 0; i < BLKID_FLTR_SIZE; i++)
417 pr->fltr[i] = ~pr->fltr[i];
419 blkid_probe_reset_idx(pr);
420 DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n"));
425 * The blkid_do_probe() calls the probe functions. This routine could be used
426 * in a loop when you need to probe for all possible filesystems/raids.
428 * 1/ basic case -- use the first result:
430 * if (blkid_do_probe(pr) == 0) {
431 * int nvals = blkid_probe_numof_values(pr);
432 * for (n = 0; n < nvals; n++) {
433 * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0)
434 * printf("%s = %s\n", name, data);
438 * 2/ advanced case -- probe for all signatures (don't forget that some
439 * filesystems can co-exist on one volume (e.g. CD-ROM).
441 * while (blkid_do_probe(pr) == 0) {
442 * int nvals = blkid_probe_numof_values(pr);
446 * The internal probing index (pointer to the last probing function) is
447 * always reseted when you touch probing filter or set a new device. It
448 * means you cannot use:
450 * blkid_probe_invert_filter()
451 * blkid_probe_filter_usage()
452 * blkid_probe_filter_types()
453 * blkid_probe_reset_filter()
454 * blkid_probe_set_device()
456 * in the loop (e.g while()) when you iterate on all signatures.
458 int blkid_do_probe(blkid_probe pr)
462 if (!pr || pr->idx < -1)
465 blkid_probe_reset_vals(pr);
468 printf("--> starting probing loop [idx=%d]\n",
473 for ( ; i < ARRAY_SIZE(idinfos); i++) {
474 const struct blkid_idinfo *id;
475 const struct blkid_idmag *mag;
480 if (pr->fltr && blkid_bmp_get_item(pr->fltr, i))
484 mag = id->magics ? &id->magics[0] : NULL;
486 /* try to detect by magic string */
487 while(mag && mag->magic) {
491 idx = mag->kboff + (mag->sboff >> 10);
492 buf = blkid_probe_get_buffer(pr, idx << 10, 1024);
494 if (buf && !memcmp(mag->magic,
495 buf + (mag->sboff & 0x3ff), mag->len)) {
496 DBG(DEBUG_LOWPROBE, printf(
497 "%s: magic sboff=%u, kboff=%ld\n",
498 id->name, mag->sboff, mag->kboff));
505 if (hasmag == 0 && id->magics && id->magics[0].magic)
506 /* magic string(s) defined, but not found */
509 /* final check by probing function */
511 DBG(DEBUG_LOWPROBE, printf(
512 "%s: call probefunc()\n", id->name));
513 if (id->probefunc(pr, mag) != 0)
517 /* all cheks passed */
518 if (pr->probreq & BLKID_PROBREQ_TYPE)
519 blkid_probe_set_value(pr, "TYPE",
520 (unsigned char *) id->name,
521 strlen(id->name) + 1);
522 if (pr->probreq & BLKID_PROBREQ_USAGE)
523 blkid_probe_set_usage(pr, id->usage);
526 printf("<-- leaving probing loop (type=%s) [idx=%d]\n",
531 printf("<-- leaving probing loop (failed) [idx=%d]\n",
537 * This is the same function as blkid_do_probe(), but returns only one result
538 * (cannot be used in while()) and checks for ambivalen results (more
539 * filesystems on the device) -- in such case returns -2.
541 * The function does not check for filesystems when a RAID signature is
542 * detected. The function also does not check for collision between RAIDs. The
543 * first detected RAID is returned.
545 int blkid_do_safeprobe(blkid_probe pr)
547 struct blkid_struct_probe first;
552 while ((rc = blkid_do_probe(pr)) == 0) {
554 /* store the fist result */
555 memcpy(first.vals, pr->vals, sizeof(first.vals));
556 first.nvals = pr->nvals;
561 if (idinfos[pr->idx]->usage & BLKID_USAGE_RAID)
563 if (!(idinfos[pr->idx]->flags & BLKID_IDINFO_TOLERANT))
567 return rc; /* error */
568 if (count > 1 && intol) {
570 printf("ERROR: ambivalent result detected (%d filesystems)!\n",
572 return -2; /* error, ambivalent result (more FS) */
575 return 1; /* nothing detected */
577 /* restore the first result */
578 memcpy(pr->vals, first.vals, sizeof(first.vals));
579 pr->nvals = first.nvals;
585 int blkid_probe_numof_values(blkid_probe pr)
593 static struct blkid_prval *blkid_probe_assign_value(
594 blkid_probe pr, const char *name)
596 struct blkid_prval *v;
600 if (pr->nvals >= BLKID_PROBVAL_NVALS)
603 v = &pr->vals[pr->nvals];
607 DBG(DEBUG_LOWPROBE, printf("assigning %s\n", name));
611 int blkid_probe_set_value(blkid_probe pr, const char *name,
612 unsigned char *data, size_t len)
614 struct blkid_prval *v;
616 if (len > BLKID_PROBVAL_BUFSIZ)
617 len = BLKID_PROBVAL_BUFSIZ;
619 v = blkid_probe_assign_value(pr, name);
623 memcpy(v->data, data, len);
628 int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
629 const char *fmt, va_list ap)
631 struct blkid_prval *v;
634 v = blkid_probe_assign_value(pr, name);
638 len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap);
641 pr->nvals--; /* reset the latest assigned value */
648 int blkid_probe_set_version(blkid_probe pr, const char *version)
650 if (pr->probreq & BLKID_PROBREQ_VERSION)
651 return blkid_probe_set_value(pr, "VERSION",
652 (unsigned char *) version, strlen(version) + 1);
656 int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...)
660 if (pr->probreq & BLKID_PROBREQ_VERSION) {
664 rc = blkid_probe_vsprintf_value(pr, "VERSION", fmt, ap);
670 static int blkid_probe_set_usage(blkid_probe pr, int usage)
674 if (usage & BLKID_USAGE_FILESYSTEM)
676 else if (usage & BLKID_USAGE_RAID)
678 else if (usage & BLKID_USAGE_CRYPTO)
680 else if (usage & BLKID_USAGE_OTHER)
685 return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1);
689 /* Removes whitespace from the right-hand side of a string (trailing
692 * Returns size of the new string (without \0).
694 static size_t blkid_rtrim_whitespace(unsigned char *str)
696 size_t i = strlen((char *) str);
699 if (!isspace(str[i]))
706 int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len)
708 struct blkid_prval *v;
710 if (len > BLKID_PROBVAL_BUFSIZ)
711 len = BLKID_PROBVAL_BUFSIZ;
713 if ((pr->probreq & BLKID_PROBREQ_LABELRAW) &&
714 blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
716 if (!(pr->probreq & BLKID_PROBREQ_LABEL))
718 v = blkid_probe_assign_value(pr, "LABEL");
722 memcpy(v->data, label, len);
724 v->len = blkid_rtrim_whitespace(v->data) + 1;
728 static size_t encode_to_utf8(int enc, unsigned char *dest, size_t len,
729 unsigned char *src, size_t count)
734 for (j = i = 0; i + 2 <= count; i += 2) {
735 if (enc == BLKID_ENC_UTF16LE)
736 c = (src[i+1] << 8) | src[i];
737 else /* BLKID_ENC_UTF16BE */
738 c = (src[i] << 8) | src[i+1];
742 } else if (c < 0x80) {
745 dest[j++] = (uint8_t) c;
746 } else if (c < 0x800) {
749 dest[j++] = (uint8_t) (0xc0 | (c >> 6));
750 dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
754 dest[j++] = (uint8_t) (0xe0 | (c >> 12));
755 dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
756 dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
763 int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
766 struct blkid_prval *v;
768 if ((pr->probreq & BLKID_PROBREQ_LABELRAW) &&
769 blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
771 if (!(pr->probreq & BLKID_PROBREQ_LABEL))
773 v = blkid_probe_assign_value(pr, "LABEL");
777 encode_to_utf8(enc, v->data, sizeof(v->data), label, len);
778 v->len = blkid_rtrim_whitespace(v->data) + 1;
782 /* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */
783 static int uuid_is_empty(const unsigned char *buf, size_t len)
787 for (i = 0; i < len; i++)
793 int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
794 size_t len, const char *fmt, ...)
799 if (len > BLKID_PROBVAL_BUFSIZ)
800 len = BLKID_PROBVAL_BUFSIZ;
802 if (uuid_is_empty(uuid, len))
805 if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
806 blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0)
808 if (!(pr->probreq & BLKID_PROBREQ_UUID))
812 rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap);
815 /* convert to lower case (..be paranoid) */
818 struct blkid_prval *v = &pr->vals[pr->nvals];
820 for (i = 0; i < v->len; i++)
821 if (v->data[i] >= 'A' && v->data[i] <= 'F')
822 v->data[i] = (v->data[i] - 'A') + 'a';
827 /* function to set UUIDs that are in suberblocks stored as strings */
828 int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len)
830 struct blkid_prval *v;
832 if (str == NULL || *str == '\0')
835 len = strlen((char *) str);
836 if (len > BLKID_PROBVAL_BUFSIZ)
837 len = BLKID_PROBVAL_BUFSIZ;
839 if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
840 blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0)
842 if (!(pr->probreq & BLKID_PROBREQ_UUID))
845 v = blkid_probe_assign_value(pr, "UUID");
847 memcpy((char *) v->data, str, len);
848 *(v->data + len) = '\0';
855 /* default _set_uuid function to set DCE UUIDs */
856 int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name)
858 struct blkid_prval *v;
860 if (uuid_is_empty(uuid, 16))
864 if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
865 blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0)
867 if (!(pr->probreq & BLKID_PROBREQ_UUID))
870 v = blkid_probe_assign_value(pr, "UUID");
872 v = blkid_probe_assign_value(pr, name);
876 uuid_unparse(uuid, (char *) v->data);
880 v->len = snprintf(v->data, sizeof(v->data),
881 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
882 uuid[0], uuid[1], uuid[2], uuid[3],
886 uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]);
892 int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid)
894 return blkid_probe_set_uuid_as(pr, uuid, NULL);
897 int blkid_probe_get_value(blkid_probe pr, int num, const char **name,
898 const char **data, size_t *len)
900 struct blkid_prval *v;
902 if (pr == NULL || num < 0 || num >= pr->nvals)
909 *data = (char *) v->data;
913 DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
917 int blkid_probe_lookup_value(blkid_probe pr, const char *name,
918 const char **data, size_t *len)
922 if (pr == NULL || pr->nvals == 0 || name == NULL)
925 for (i = 0; i < pr->nvals; i++) {
926 struct blkid_prval *v = &pr->vals[i];
928 if (v->name && strcmp(name, v->name) == 0) {
930 *data = (char *) v->data;
933 DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
940 int blkid_probe_has_value(blkid_probe pr, const char *name)
942 if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0)