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>
28
#include <uuid/uuid.h>
34
#include "probers/probers.h"
36
static const struct blkid_idinfo *idinfos[] =
93
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
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)
101
#define blkid_bmp_set_item(bmp, item) \
102
((bmp)[ blkid_bmp_idx_byte(item) ] |= blkid_bmp_idx_bit(item))
104
#define blkid_bmp_unset_item(bmp, item) \
105
((bmp)[ bmp_idx_byte(item) ] &= ~bmp_idx_bit(item))
107
#define blkid_bmp_get_item(bmp, item) \
108
((bmp)[ blkid_bmp_idx_byte(item) ] & blkid_bmp_idx_bit(item))
110
#define blkid_bmp_size(max_items) \
111
(((max_items) + blkid_bmp_wordsize) / blkid_bmp_wordsize)
113
#define BLKID_FLTR_ITEMS ARRAY_SIZE(idinfos)
114
#define BLKID_FLTR_SIZE blkid_bmp_size(BLKID_FLTR_ITEMS)
117
static int blkid_probe_set_usage(blkid_probe pr, int usage);
119
int blkid_known_fstype(const char *fstype)
126
for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
127
const struct blkid_idinfo *id = idinfos[i];
128
if (strcmp(id->name, fstype) == 0)
135
* Returns a pointer to the newly allocated probe struct
137
blkid_probe blkid_new_probe(void)
140
return calloc(1, sizeof(struct blkid_struct_probe));
144
* Deallocates probe struct, buffers and all allocated
145
* data that are associated with this probing control struct.
147
void blkid_free_probe(blkid_probe pr)
157
static void blkid_probe_reset_vals(blkid_probe pr)
159
memset(pr->vals, 0, sizeof(pr->vals));
163
static void blkid_probe_reset_idx(blkid_probe pr)
168
void blkid_reset_probe(blkid_probe pr)
172
DBG(DEBUG_LOWPROBE, printf("reseting blkid_probe\n"));
174
memset(pr->buf, 0, pr->buf_max);
178
memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ);
180
blkid_probe_reset_vals(pr);
181
blkid_probe_reset_idx(pr);
185
* Note that we have two offsets:
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
191
* 2/ buffer offset (the 'off' argument), that useful for offsets in
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).
198
unsigned char *blkid_probe_get_buffer(blkid_probe pr,
199
blkid_loff_t off, blkid_loff_t len)
201
ssize_t ret_read = 0;
203
if (off < 0 || len < 0) {
205
printf("unexpected offset or length of buffer requested\n"));
208
if (off + len <= BLKID_SB_BUFSIZ) {
210
pr->sbbuf = malloc(BLKID_SB_BUFSIZ);
214
if (!pr->sbbuf_len) {
215
if (lseek(pr->fd, pr->off, SEEK_SET) < 0)
217
ret_read = read(pr->fd, pr->sbbuf, BLKID_SB_BUFSIZ);
220
pr->sbbuf_len = ret_read;
222
if (off + len > pr->sbbuf_len)
224
return pr->sbbuf + off;
226
unsigned char *newbuf = NULL;
228
if (len > pr->buf_max) {
229
newbuf = realloc(pr->buf, len);
237
if (newbuf || off < pr->buf_off ||
238
off + len > pr->buf_off + pr->buf_len) {
240
if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0)
243
ret_read = read(pr->fd, pr->buf, len);
244
if (ret_read != (ssize_t) len)
249
return off ? pr->buf + (off - pr->buf_off) : pr->buf;
254
* Assignes the device to probe control struct, resets internal buffers and
255
* reads 512 bytes from device to the buffers.
257
* Returns -1 in case of failure, or 0 on success.
259
int blkid_probe_set_device(blkid_probe pr, int fd,
260
blkid_loff_t off, blkid_loff_t size)
265
blkid_reset_probe(pr);
279
if (S_ISBLK(sb.st_mode))
280
blkdev_get_size(fd, (unsigned long long *) &pr->size);
282
pr->size = sb.st_size;
287
/* read SB to test if the device is readable */
288
if (!blkid_probe_get_buffer(pr, 0, 0x200)) {
290
printf("failed to prepare a device for low-probing\n"));
294
DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n",
299
int blkid_probe_set_request(blkid_probe pr, int flags)
307
int blkid_probe_reset_filter(blkid_probe pr)
312
memset(pr->fltr, 0, BLKID_FLTR_SIZE * sizeof(unsigned long));
313
blkid_probe_reset_idx(pr);
320
* BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN names[]
322
* BLKID_FLTR_ONLYIN - probe filesystem which are IN names[]
324
int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[])
331
pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long));
332
blkid_probe_reset_idx(pr);
334
blkid_probe_reset_filter(pr);
339
for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
341
const struct blkid_idinfo *id = idinfos[i];
344
for (n = names; *n; n++) {
345
if (!strcmp(id->name, *n)) {
350
/* The default is enable all filesystems,
351
* set relevant bitmap bit means disable the filesystem.
353
if (flag & BLKID_FLTR_ONLYIN) {
355
blkid_bmp_set_item(pr->fltr, i);
356
} else if (flag & BLKID_FLTR_NOTIN) {
358
blkid_bmp_set_item(pr->fltr, i);
361
DBG(DEBUG_LOWPROBE, printf("a new probing type-filter initialized\n"));
368
* BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN "usage"
370
* BLKID_FLTR_ONLYIN - probe filesystem which are IN "usage"
372
* where the "usage" is a set of filesystem according the usage flag (crypto,
373
* raid, filesystem, ...)
375
int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage)
382
pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long));
383
blkid_probe_reset_idx(pr);
385
blkid_probe_reset_filter(pr);
390
for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
391
const struct blkid_idinfo *id = idinfos[i];
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);
399
DBG(DEBUG_LOWPROBE, printf("a new probing usage-filter initialized\n"));
404
int blkid_probe_invert_filter(blkid_probe pr)
408
if (!pr || !pr->fltr)
410
for (i = 0; i < BLKID_FLTR_SIZE; i++)
411
pr->fltr[i] = ~pr->fltr[i];
413
blkid_probe_reset_idx(pr);
414
DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n"));
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.
422
* 1/ basic case -- use the first result:
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);
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).
435
* while (blkid_do_probe(pr) == 0) {
436
* int nvals = blkid_probe_numof_values(pr);
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:
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()
450
* in the loop (e.g while()) when you iterate on all signatures.
452
int blkid_do_probe(blkid_probe pr)
456
if (!pr || pr->idx < -1)
459
blkid_probe_reset_vals(pr);
462
printf("--> starting probing loop [idx=%d]\n",
467
for ( ; i < ARRAY_SIZE(idinfos); i++) {
468
const struct blkid_idinfo *id;
469
const struct blkid_idmag *mag;
474
if (pr->fltr && blkid_bmp_get_item(pr->fltr, i))
478
mag = id->magics ? &id->magics[0] : NULL;
480
/* try to detect by magic string */
481
while(mag && mag->magic) {
485
idx = mag->kboff + (mag->sboff >> 10);
486
buf = blkid_probe_get_buffer(pr, idx << 10, 1024);
488
if (buf && !memcmp(mag->magic,
489
buf + (mag->sboff & 0x3ff), mag->len)) {
490
DBG(DEBUG_LOWPROBE, printf(
491
"%s: magic sboff=%u, kboff=%ld\n",
492
id->name, mag->sboff, mag->kboff));
499
if (hasmag == 0 && id->magics && id->magics[0].magic)
500
/* magic string(s) defined, but not found */
503
/* final check by probing function */
505
DBG(DEBUG_LOWPROBE, printf(
506
"%s: call probefunc()\n", id->name));
507
if (id->probefunc(pr, mag) != 0)
511
/* all cheks passed */
512
if (pr->probreq & BLKID_PROBREQ_TYPE)
513
blkid_probe_set_value(pr, "TYPE",
514
(unsigned char *) id->name,
515
strlen(id->name) + 1);
516
if (pr->probreq & BLKID_PROBREQ_USAGE)
517
blkid_probe_set_usage(pr, id->usage);
520
printf("<-- leaving probing loop (type=%s) [idx=%d]\n",
525
printf("<-- leaving probing loop (failed) [idx=%d]\n",
531
* This is the same function as blkid_do_probe(), but returns only one result
532
* (cannot be used in while()) and checks for ambivalen results (more
533
* filesystems on the device) -- in such case returns -2.
535
* The function does not check for filesystems when a RAID signature is
536
* detected. The function also does not check for collision between RAIDs. The
537
* first detected RAID is returned.
539
int blkid_do_safeprobe(blkid_probe pr)
541
struct blkid_struct_probe first;
546
while ((rc = blkid_do_probe(pr)) == 0) {
548
/* store the fist result */
549
memcpy(first.vals, pr->vals, sizeof(first.vals));
550
first.nvals = pr->nvals;
555
if (idinfos[pr->idx]->usage & BLKID_USAGE_RAID)
557
if (!(idinfos[pr->idx]->flags & BLKID_IDINFO_TOLERANT))
561
return rc; /* error */
562
if (count > 1 && intol) {
564
printf("ERROR: ambivalent result detected (%d filesystems)!\n",
566
return -2; /* error, ambivalent result (more FS) */
569
return 1; /* nothing detected */
571
/* restore the first result */
572
memcpy(pr->vals, first.vals, sizeof(first.vals));
573
pr->nvals = first.nvals;
579
int blkid_probe_numof_values(blkid_probe pr)
587
static struct blkid_prval *blkid_probe_assign_value(
588
blkid_probe pr, const char *name)
590
struct blkid_prval *v;
594
if (pr->nvals >= BLKID_PROBVAL_NVALS)
597
v = &pr->vals[pr->nvals];
601
DBG(DEBUG_LOWPROBE, printf("assigning %s\n", name));
605
int blkid_probe_set_value(blkid_probe pr, const char *name,
606
unsigned char *data, size_t len)
608
struct blkid_prval *v;
610
if (len > BLKID_PROBVAL_BUFSIZ)
611
len = BLKID_PROBVAL_BUFSIZ;
613
v = blkid_probe_assign_value(pr, name);
617
memcpy(v->data, data, len);
622
int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
623
const char *fmt, va_list ap)
625
struct blkid_prval *v;
628
v = blkid_probe_assign_value(pr, name);
632
len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap);
635
pr->nvals--; /* reset the latest assigned value */
642
int blkid_probe_set_version(blkid_probe pr, const char *version)
644
if (pr->probreq & BLKID_PROBREQ_VERSION)
645
return blkid_probe_set_value(pr, "VERSION",
646
(unsigned char *) version, strlen(version) + 1);
650
int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...)
654
if (pr->probreq & BLKID_PROBREQ_VERSION) {
658
rc = blkid_probe_vsprintf_value(pr, "VERSION", fmt, ap);
664
static int blkid_probe_set_usage(blkid_probe pr, int usage)
668
if (usage & BLKID_USAGE_FILESYSTEM)
670
else if (usage & BLKID_USAGE_RAID)
672
else if (usage & BLKID_USAGE_CRYPTO)
674
else if (usage & BLKID_USAGE_OTHER)
679
return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1);
682
int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len)
684
struct blkid_prval *v;
687
if (len > BLKID_PROBVAL_BUFSIZ)
688
len = BLKID_PROBVAL_BUFSIZ;
690
if ((pr->probreq & BLKID_PROBREQ_LABELRAW) &&
691
blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
693
if (!(pr->probreq & BLKID_PROBREQ_LABEL))
695
v = blkid_probe_assign_value(pr, "LABEL");
699
memcpy(v->data, label, len);
702
/* remove trailing whitespace */
703
i = strnlen((char *) v->data, len);
705
if (!isspace(v->data[i]))
713
static size_t encode_to_utf8(int enc, unsigned char *dest, size_t len,
714
unsigned char *src, size_t count)
719
for (j = i = 0; i + 2 <= count; i += 2) {
720
if (enc == BLKID_ENC_UTF16LE)
721
c = (src[i+1] << 8) | src[i];
722
else /* BLKID_ENC_UTF16BE */
723
c = (src[i] << 8) | src[i+1];
727
} else if (c < 0x80) {
730
dest[j++] = (uint8_t) c;
731
} else if (c < 0x800) {
734
dest[j++] = (uint8_t) (0xc0 | (c >> 6));
735
dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
739
dest[j++] = (uint8_t) (0xe0 | (c >> 12));
740
dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
741
dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
748
int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
751
struct blkid_prval *v;
753
if ((pr->probreq & BLKID_PROBREQ_LABELRAW) &&
754
blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
756
if (!(pr->probreq & BLKID_PROBREQ_LABEL))
758
v = blkid_probe_assign_value(pr, "LABEL");
762
v->len = encode_to_utf8(enc, v->data, sizeof(v->data), label, len);
766
/* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */
767
static int uuid_is_empty(const unsigned char *buf, size_t len)
771
for (i = 0; i < len; i++)
777
int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
778
size_t len, const char *fmt, ...)
783
if (len > BLKID_PROBVAL_BUFSIZ)
784
len = BLKID_PROBVAL_BUFSIZ;
786
if (uuid_is_empty(uuid, len))
789
if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
790
blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0)
792
if (!(pr->probreq & BLKID_PROBREQ_UUID))
796
rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap);
799
/* convert to lower case (..be paranoid) */
802
struct blkid_prval *v = &pr->vals[pr->nvals];
804
for (i = 0; i < v->len; i++)
805
if (v->data[i] >= 'A' && v->data[i] <= 'F')
806
v->data[i] = (v->data[i] - 'A') + 'a';
811
/* function to set UUIDs that are in suberblocks stored as strings */
812
int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len)
814
struct blkid_prval *v;
816
if (str == NULL || *str == '\0')
819
len = strlen((char *) str);
820
if (len > BLKID_PROBVAL_BUFSIZ)
821
len = BLKID_PROBVAL_BUFSIZ;
823
if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
824
blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0)
826
if (!(pr->probreq & BLKID_PROBREQ_UUID))
829
v = blkid_probe_assign_value(pr, "UUID");
831
memcpy((char *) v->data, str, len);
832
*(v->data + len) = '\0';
839
/* default _set_uuid function to set DCE UUIDs */
840
int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name)
842
struct blkid_prval *v;
844
if (uuid_is_empty(uuid, 16))
848
if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
849
blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0)
851
if (!(pr->probreq & BLKID_PROBREQ_UUID))
854
v = blkid_probe_assign_value(pr, "UUID");
856
v = blkid_probe_assign_value(pr, name);
860
uuid_unparse(uuid, (char *) v->data);
864
v->len = snprintf(v->data, sizeof(v->data),
865
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
866
uuid[0], uuid[1], uuid[2], uuid[3],
870
uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]);
876
int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid)
878
return blkid_probe_set_uuid_as(pr, uuid, NULL);
881
int blkid_probe_get_value(blkid_probe pr, int num, const char **name,
882
const char **data, size_t *len)
884
struct blkid_prval *v;
886
if (pr == NULL || num < 0 || num >= pr->nvals)
893
*data = (char *) v->data;
897
DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
901
int blkid_probe_lookup_value(blkid_probe pr, const char *name,
902
const char **data, size_t *len)
906
if (pr == NULL || pr->nvals == 0 || name == NULL)
909
for (i = 0; i < pr->nvals; i++) {
910
struct blkid_prval *v = &pr->vals[i];
912
if (v->name && strcmp(name, v->name) == 0) {
914
*data = (char *) v->data;
917
DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
924
int blkid_probe_has_value(blkid_probe pr, const char *name)
926
if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0)