]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libs/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>
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 void blkid_reset_probe(blkid_probe pr
)
167 DBG(DEBUG_LOWPROBE
, printf("reseting blkid_probe\n"));
169 memset(pr
->buf
, 0, pr
->buf_max
);
174 memset(pr
->sbbuf
, 0, BLKID_SB_BUFSIZ
);
176 blkid_probe_reset_vals(pr
);
181 * Note that we have two offsets:
183 * 1/ general device offset (pr->off), that's useful for example when we
184 * probe a partition from whole disk image:
185 * blkid-low --offset <partition_position> disk.img
187 * 2/ buffer offset (the 'off' argument), that useful for offsets in
190 * That means never use lseek(fd, 0, SEEK_SET), the zero position is always
191 * pr->off, so lseek(fd, pr->off, SEEK_SET).
194 unsigned char *blkid_probe_get_buffer(blkid_probe pr
,
195 blkid_loff_t off
, blkid_loff_t len
)
197 ssize_t ret_read
= 0;
199 if (off
+ len
<= BLKID_SB_BUFSIZ
) {
201 pr
->sbbuf
= malloc(BLKID_SB_BUFSIZ
);
205 if (!pr
->sbbuf_len
) {
206 if (lseek(pr
->fd
, pr
->off
, SEEK_SET
) < 0)
208 ret_read
= read(pr
->fd
, pr
->sbbuf
, BLKID_SB_BUFSIZ
);
211 pr
->sbbuf_len
= ret_read
;
213 if (off
+ len
> pr
->sbbuf_len
)
215 return pr
->sbbuf
+ off
;
217 unsigned char *newbuf
= NULL
;
219 if (len
> pr
->buf_max
) {
220 newbuf
= realloc(pr
->buf
, len
);
228 if (newbuf
|| off
< pr
->buf_off
||
229 off
+ len
> pr
->buf_off
+ pr
->buf_len
) {
231 if (blkid_llseek(pr
->fd
, pr
->off
+ off
, SEEK_SET
) < 0)
234 ret_read
= read(pr
->fd
, pr
->buf
, len
);
235 if (ret_read
!= (ssize_t
) len
)
240 return off
? pr
->buf
+ (off
- pr
->buf_off
) : pr
->buf
;
245 * Assignes the device to probe control struct, resets internal buffers and
246 * reads 512 bytes from device to the buffers.
248 * Returns -1 in case of failure, or 0 on success.
250 int blkid_probe_set_device(blkid_probe pr
, int fd
,
251 blkid_loff_t off
, blkid_loff_t size
)
256 blkid_reset_probe(pr
);
271 if (S_ISBLK(sb
.st_mode
))
272 blkdev_get_size(fd
, (unsigned long long *) &pr
->size
);
274 pr
->size
= sb
.st_size
;
279 /* read SB to test if the device is readable */
280 if (!blkid_probe_get_buffer(pr
, 0, 0x200)) {
282 printf("failed to prepare a device for low-probing\n"));
286 DBG(DEBUG_LOWPROBE
, printf("ready for low-probing, offset=%zd, size=%zd\n",
291 int blkid_probe_set_request(blkid_probe pr
, int flags
)
299 int blkid_probe_reset_filter(blkid_probe pr
)
304 memset(pr
->fltr
, 0, BLKID_FLTR_SIZE
* sizeof(unsigned long));
312 * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN names[]
314 * BLKID_FLTR_ONLYIN - probe filesystem which are IN names[]
316 int blkid_probe_filter_types(blkid_probe pr
, int flag
, char *names
[])
323 pr
->fltr
= calloc(BLKID_FLTR_SIZE
, sizeof(unsigned long));
325 blkid_probe_reset_filter(pr
);
330 for (i
= 0; i
< ARRAY_SIZE(idinfos
); i
++) {
332 const struct blkid_idinfo
*id
= idinfos
[i
];
335 for (n
= names
; *n
; n
++) {
336 if (!strcmp(id
->name
, *n
)) {
341 /* The default is enable all filesystems,
342 * set relevant bitmap bit means disable the filesystem.
344 if (flag
& BLKID_FLTR_ONLYIN
) {
346 blkid_bmp_set_item(pr
->fltr
, i
);
347 } else if (flag
& BLKID_FLTR_NOTIN
) {
349 blkid_bmp_set_item(pr
->fltr
, i
);
352 DBG(DEBUG_LOWPROBE
, printf("a new probing type-filter initialized\n"));
360 * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN "usage"
362 * BLKID_FLTR_ONLYIN - probe filesystem which are IN "usage"
364 * where the "usage" is a set of filesystem according the usage flag (crypto,
365 * raid, filesystem, ...)
367 int blkid_probe_filter_usage(blkid_probe pr
, int flag
, int usage
)
374 pr
->fltr
= calloc(BLKID_FLTR_SIZE
, sizeof(unsigned long));
376 blkid_probe_reset_filter(pr
);
381 for (i
= 0; i
< ARRAY_SIZE(idinfos
); i
++) {
382 const struct blkid_idinfo
*id
= idinfos
[i
];
384 if (id
->usage
& usage
) {
385 if (flag
& BLKID_FLTR_NOTIN
)
386 blkid_bmp_set_item(pr
->fltr
, i
);
387 } else if (flag
& BLKID_FLTR_ONLYIN
)
388 blkid_bmp_set_item(pr
->fltr
, i
);
390 DBG(DEBUG_LOWPROBE
, printf("a new probing usage-filter initialized\n"));
396 int blkid_probe_invert_filter(blkid_probe pr
)
400 if (!pr
|| !pr
->fltr
)
402 for (i
= 0; i
< BLKID_FLTR_SIZE
; i
++)
403 pr
->fltr
[i
] = ~pr
->fltr
[i
];
405 DBG(DEBUG_LOWPROBE
, printf("probing filter inverted\n"));
411 * The blkid_do_probe() calls the probe functions. This routine could be used
412 * in a loop when you need to probe for all possible filesystems/raids.
414 * 1/ basic case -- use the first result:
416 * if (blkid_do_probe(pr) == 0) {
417 * int nvals = blkid_probe_numof_values(pr);
418 * for (n = 0; n < nvals; n++) {
419 * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0)
420 * printf("%s = %s\n", name, data);
424 * 2/ advanced case -- probe for all signatures (don't forget that some
425 * filesystems can co-exist on one volume (e.g. CD-ROM).
427 * while (blkid_do_probe(pr) == 0) {
428 * int nvals = blkid_probe_numof_values(pr);
432 * The internal probing index (pointer to the last probing function) is
433 * always reseted when you touch probing filter or set a new device. It
434 * means you cannot use:
436 * blkid_probe_invert_filter()
437 * blkid_probe_filter_usage()
438 * blkid_probe_filter_types()
439 * blkid_probe_reset_filter()
440 * blkid_probe_set_device()
442 * in the loop (e.g while()) when you iterate on all signatures.
444 int blkid_do_probe(blkid_probe pr
)
451 blkid_probe_reset_vals(pr
);
456 if (i
< 0 && i
>= ARRAY_SIZE(idinfos
))
459 DBG(DEBUG_LOWPROBE
, printf("--> starting probing loop\n"));
461 for ( ; i
< ARRAY_SIZE(idinfos
); i
++) {
462 const struct blkid_idinfo
*id
;
463 const struct blkid_idmag
*mag
;
468 if (pr
->fltr
&& blkid_bmp_get_item(pr
->fltr
, i
))
472 mag
= id
->magics
? &id
->magics
[0] : NULL
;
474 /* try to detect by magic string */
475 while(mag
&& mag
->magic
) {
479 idx
= mag
->kboff
+ (mag
->sboff
>> 10);
480 buf
= blkid_probe_get_buffer(pr
, idx
<< 10, 1024);
482 if (buf
&& !memcmp(mag
->magic
,
483 buf
+ (mag
->sboff
& 0x3ff), mag
->len
)) {
484 DBG(DEBUG_LOWPROBE
, printf(
485 "%s: magic sboff=%u, kboff=%ld\n",
486 id
->name
, mag
->sboff
, mag
->kboff
));
493 if (hasmag
== 0 && id
->magics
&& id
->magics
[0].magic
)
494 /* magic string(s) defined, but not found */
497 /* final check by probing function */
499 DBG(DEBUG_LOWPROBE
, printf(
500 "%s: call probefunc()\n", id
->name
));
501 if (id
->probefunc(pr
, mag
) != 0)
505 /* all cheks passed */
506 if (pr
->probreq
& BLKID_PROBREQ_TYPE
)
507 blkid_probe_set_value(pr
, "TYPE",
508 (unsigned char *) id
->name
,
509 strlen(id
->name
) + 1);
510 if (pr
->probreq
& BLKID_PROBREQ_USAGE
)
511 blkid_probe_set_usage(pr
, id
->usage
);
514 printf("<-- leaving probing loop (type=%s)\n", id
->name
));
517 DBG(DEBUG_LOWPROBE
, printf("<-- leaving probing loop (failed)\n"));
522 * This is the same function as blkid_do_probe(), but returns only one result
523 * (cannot be used in while()) and checks for ambivalen results (more
524 * filesystems on the device) -- in such case returns -2.
526 int blkid_do_safeprobe(blkid_probe pr
)
528 struct blkid_struct_probe first
;
533 while ((rc
= blkid_do_probe(pr
)) == 0) {
535 /* store the fist result */
536 memcpy(first
.vals
, pr
->vals
, sizeof(first
.vals
));
537 first
.nvals
= pr
->nvals
;
540 if (!(idinfos
[pr
->idx
]->flags
& BLKID_IDINFO_TOLERANT
))
545 return rc
; /* error */
546 if (count
> 1 && intol
) {
548 printf("ERROR: ambivalent result detected (%d filesystems)!\n",
550 return -2; /* error, ambivalent result (more FS) */
553 return 1; /* nothing detected */
555 /* restore the first result */
556 memcpy(pr
->vals
, first
.vals
, sizeof(first
.vals
));
557 pr
->nvals
= first
.nvals
;
563 int blkid_probe_numof_values(blkid_probe pr
)
571 static struct blkid_prval
*blkid_probe_assign_value(
572 blkid_probe pr
, const char *name
)
574 struct blkid_prval
*v
;
578 if (pr
->nvals
>= BLKID_PROBVAL_NVALS
)
581 v
= &pr
->vals
[pr
->nvals
];
585 DBG(DEBUG_LOWPROBE
, printf("assigning %s\n", name
));
589 int blkid_probe_set_value(blkid_probe pr
, const char *name
,
590 unsigned char *data
, size_t len
)
592 struct blkid_prval
*v
;
594 if (len
> BLKID_PROBVAL_BUFSIZ
)
595 len
= BLKID_PROBVAL_BUFSIZ
;
597 v
= blkid_probe_assign_value(pr
, name
);
601 memcpy(v
->data
, data
, len
);
606 int blkid_probe_vsprintf_value(blkid_probe pr
, const char *name
,
607 const char *fmt
, va_list ap
)
609 struct blkid_prval
*v
;
612 v
= blkid_probe_assign_value(pr
, name
);
616 len
= vsnprintf((char *) v
->data
, sizeof(v
->data
), fmt
, ap
);
619 pr
->nvals
--; /* reset the latest assigned value */
626 int blkid_probe_set_version(blkid_probe pr
, const char *version
)
628 if (pr
->probreq
& BLKID_PROBREQ_VERSION
)
629 return blkid_probe_set_value(pr
, "VERSION",
630 (unsigned char *) version
, strlen(version
) + 1);
634 int blkid_probe_sprintf_version(blkid_probe pr
, const char *fmt
, ...)
638 if (pr
->probreq
& BLKID_PROBREQ_VERSION
) {
642 rc
= blkid_probe_vsprintf_value(pr
, "VERSION", fmt
, ap
);
648 static int blkid_probe_set_usage(blkid_probe pr
, int usage
)
652 if (usage
& BLKID_USAGE_FILESYSTEM
)
654 else if (usage
& BLKID_USAGE_RAID
)
656 else if (usage
& BLKID_USAGE_CRYPTO
)
658 else if (usage
& BLKID_USAGE_OTHER
)
663 return blkid_probe_set_value(pr
, "USAGE", (unsigned char *) u
, strlen(u
) + 1);
666 int blkid_probe_set_label(blkid_probe pr
, unsigned char *label
, size_t len
)
668 struct blkid_prval
*v
;
671 if (len
> BLKID_PROBVAL_BUFSIZ
)
672 len
= BLKID_PROBVAL_BUFSIZ
;
674 if ((pr
->probreq
& BLKID_PROBREQ_LABELRAW
) &&
675 blkid_probe_set_value(pr
, "LABEL_RAW", label
, len
) < 0)
677 if (!(pr
->probreq
& BLKID_PROBREQ_LABEL
))
679 v
= blkid_probe_assign_value(pr
, "LABEL");
683 memcpy(v
->data
, label
, len
);
686 /* remove trailing whitespace */
687 i
= strnlen((char *) v
->data
, len
);
689 if (!isspace(v
->data
[i
]))
697 static size_t encode_to_utf8(int enc
, unsigned char *dest
, size_t len
,
698 unsigned char *src
, size_t count
)
703 for (j
= i
= 0; i
+ 2 <= count
; i
+= 2) {
704 if (enc
== BLKID_ENC_UTF16LE
)
705 c
= (src
[i
+1] << 8) | src
[i
];
706 else /* BLKID_ENC_UTF16BE */
707 c
= (src
[i
] << 8) | src
[i
+1];
711 } else if (c
< 0x80) {
714 dest
[j
++] = (uint8_t) c
;
715 } else if (c
< 0x800) {
718 dest
[j
++] = (uint8_t) (0xc0 | (c
>> 6));
719 dest
[j
++] = (uint8_t) (0x80 | (c
& 0x3f));
723 dest
[j
++] = (uint8_t) (0xe0 | (c
>> 12));
724 dest
[j
++] = (uint8_t) (0x80 | ((c
>> 6) & 0x3f));
725 dest
[j
++] = (uint8_t) (0x80 | (c
& 0x3f));
732 int blkid_probe_set_utf8label(blkid_probe pr
, unsigned char *label
,
735 struct blkid_prval
*v
;
737 if ((pr
->probreq
& BLKID_PROBREQ_LABELRAW
) &&
738 blkid_probe_set_value(pr
, "LABEL_RAW", label
, len
) < 0)
740 if (!(pr
->probreq
& BLKID_PROBREQ_LABEL
))
742 v
= blkid_probe_assign_value(pr
, "LABEL");
746 v
->len
= encode_to_utf8(enc
, v
->data
, sizeof(v
->data
), label
, len
);
750 /* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */
751 static int uuid_is_empty(const unsigned char *buf
, size_t len
)
755 for (i
= 0; i
< len
; i
++)
761 int blkid_probe_sprintf_uuid(blkid_probe pr
, unsigned char *uuid
,
762 size_t len
, const char *fmt
, ...)
767 if (len
> BLKID_PROBVAL_BUFSIZ
)
768 len
= BLKID_PROBVAL_BUFSIZ
;
770 if (uuid_is_empty(uuid
, len
))
773 if ((pr
->probreq
& BLKID_PROBREQ_UUIDRAW
) &&
774 blkid_probe_set_value(pr
, "UUID_RAW", uuid
, len
) < 0)
776 if (!(pr
->probreq
& BLKID_PROBREQ_UUID
))
780 rc
= blkid_probe_vsprintf_value(pr
, "UUID", fmt
, ap
);
783 /* convert to lower case (..be paranoid) */
786 struct blkid_prval
*v
= &pr
->vals
[pr
->nvals
];
788 for (i
= 0; i
< v
->len
; i
++)
789 if (v
->data
[i
] >= 'A' && v
->data
[i
] <= 'F')
790 v
->data
[i
] = (v
->data
[i
] - 'A') + 'a';
795 /* function to set UUIDs that are in suberblocks stored as strings */
796 int blkid_probe_strncpy_uuid(blkid_probe pr
, unsigned char *str
, size_t len
)
798 struct blkid_prval
*v
;
800 if (str
== NULL
|| *str
== '\0')
803 len
= strlen((char *) str
);
804 if (len
> BLKID_PROBVAL_BUFSIZ
)
805 len
= BLKID_PROBVAL_BUFSIZ
;
807 if ((pr
->probreq
& BLKID_PROBREQ_UUIDRAW
) &&
808 blkid_probe_set_value(pr
, "UUID_RAW", str
, len
) < 0)
810 if (!(pr
->probreq
& BLKID_PROBREQ_UUID
))
813 v
= blkid_probe_assign_value(pr
, "UUID");
815 memcpy((char *) v
->data
, str
, len
);
816 *(v
->data
+ len
) = '\0';
823 /* default _set_uuid function to set DCE UUIDs */
824 int blkid_probe_set_uuid_as(blkid_probe pr
, unsigned char *uuid
, const char *name
)
826 struct blkid_prval
*v
;
828 if (uuid_is_empty(uuid
, 16))
832 if ((pr
->probreq
& BLKID_PROBREQ_UUIDRAW
) &&
833 blkid_probe_set_value(pr
, "UUID_RAW", uuid
, 16) < 0)
835 if (!(pr
->probreq
& BLKID_PROBREQ_UUID
))
838 v
= blkid_probe_assign_value(pr
, "UUID");
840 v
= blkid_probe_assign_value(pr
, name
);
844 uuid_unparse(uuid
, (char *) v
->data
);
848 v
->len
= snprintf(v
->data
, sizeof(v
->data
),
849 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
850 uuid
[0], uuid
[1], uuid
[2], uuid
[3],
854 uuid
[10], uuid
[11], uuid
[12], uuid
[13], uuid
[14],uuid
[15]);
860 int blkid_probe_set_uuid(blkid_probe pr
, unsigned char *uuid
)
862 return blkid_probe_set_uuid_as(pr
, uuid
, NULL
);
865 int blkid_probe_get_value(blkid_probe pr
, int num
, const char **name
,
866 const char **data
, size_t *len
)
868 struct blkid_prval
*v
;
870 if (pr
== NULL
|| num
< 0 || num
>= pr
->nvals
)
877 *data
= (char *) v
->data
;
881 DBG(DEBUG_LOWPROBE
, printf("returning %s value\n", v
->name
));
885 int blkid_probe_lookup_value(blkid_probe pr
, const char *name
,
886 const char **data
, size_t *len
)
890 if (pr
== NULL
|| pr
->nvals
== 0 || name
== NULL
)
893 for (i
= 0; i
< pr
->nvals
; i
++) {
894 struct blkid_prval
*v
= &pr
->vals
[i
];
896 if (v
->name
&& strcmp(name
, v
->name
) == 0) {
898 *data
= (char *) v
->data
;
901 DBG(DEBUG_LOWPROBE
, printf("returning %s value\n", v
->name
));
908 int blkid_probe_has_value(blkid_probe pr
, const char *name
)
910 if (blkid_probe_lookup_value(pr
, name
, NULL
, NULL
) == 0)