summaryrefslogtreecommitdiffstats
path: root/shlibs/blkid/src/probe.c
diff options
context:
space:
mode:
Diffstat (limited to 'shlibs/blkid/src/probe.c')
-rw-r--r--shlibs/blkid/src/probe.c919
1 files changed, 919 insertions, 0 deletions
diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c
new file mode 100644
index 000000000..0e4745aca
--- /dev/null
+++ b/shlibs/blkid/src/probe.c
@@ -0,0 +1,919 @@
+/*
+ * probe.c - reads tags (LABEL, UUID, FS type, ..) from a block device
+ *
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdint.h>
+#ifdef HAVE_LIBUUID
+#include <uuid/uuid.h>
+#endif
+#include <stdarg.h>
+
+#include "blkdev.h"
+#include "blkidP.h"
+#include "probers/probers.h"
+
+static const struct blkid_idinfo *idinfos[] =
+{
+ /* RAIDs */
+ &linuxraid_idinfo,
+ &ddfraid_idinfo,
+ &iswraid_idinfo,
+ &lsiraid_idinfo,
+ &viaraid_idinfo,
+ &silraid_idinfo,
+ &nvraid_idinfo,
+ &pdcraid_idinfo,
+ &highpoint45x_idinfo,
+ &highpoint37x_idinfo,
+ &adraid_idinfo,
+ &jmraid_idinfo,
+ &lvm2_idinfo,
+ &lvm1_idinfo,
+ &luks_idinfo,
+
+ /* Filesystems */
+ &vfat_idinfo,
+ &swsuspend_idinfo,
+ &swap_idinfo,
+ &xfs_idinfo,
+ &ext4dev_idinfo,
+ &ext4_idinfo,
+ &ext3_idinfo,
+ &ext2_idinfo,
+ &jbd_idinfo,
+ &reiser_idinfo,
+ &reiser4_idinfo,
+ &jfs_idinfo,
+ &udf_idinfo,
+ &iso9660_idinfo,
+ &zfs_idinfo,
+ &hfsplus_idinfo,
+ &hfs_idinfo,
+ &ufs_idinfo,
+ &hpfs_idinfo,
+ &sysv_idinfo,
+ &xenix_idinfo,
+ &ntfs_idinfo,
+ &cramfs_idinfo,
+ &romfs_idinfo,
+ &minix_idinfo,
+ &gfs_idinfo,
+ &gfs2_idinfo,
+ &ocfs_idinfo,
+ &ocfs2_idinfo,
+ &oracleasm_idinfo,
+ &vxfs_idinfo,
+ &squashfs_idinfo,
+ &netware_idinfo,
+ &btrfs_idinfo
+};
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+/* filter bitmap macros */
+#define blkid_bmp_wordsize (8 * sizeof(unsigned long))
+#define blkid_bmp_idx_bit(item) (1UL << ((item) % blkid_bmp_wordsize))
+#define blkid_bmp_idx_byte(item) ((item) / blkid_bmp_wordsize)
+
+#define blkid_bmp_set_item(bmp, item) \
+ ((bmp)[ blkid_bmp_idx_byte(item) ] |= blkid_bmp_idx_bit(item))
+
+#define blkid_bmp_unset_item(bmp, item) \
+ ((bmp)[ bmp_idx_byte(item) ] &= ~bmp_idx_bit(item))
+
+#define blkid_bmp_get_item(bmp, item) \
+ ((bmp)[ blkid_bmp_idx_byte(item) ] & blkid_bmp_idx_bit(item))
+
+#define blkid_bmp_size(max_items) \
+ (((max_items) + blkid_bmp_wordsize) / blkid_bmp_wordsize)
+
+#define BLKID_FLTR_ITEMS ARRAY_SIZE(idinfos)
+#define BLKID_FLTR_SIZE blkid_bmp_size(BLKID_FLTR_ITEMS)
+
+
+static int blkid_probe_set_usage(blkid_probe pr, int usage);
+
+int blkid_known_fstype(const char *fstype)
+{
+ int i;
+
+ if (!fstype)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
+ const struct blkid_idinfo *id = idinfos[i];
+ if (strcmp(id->name, fstype) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Returns a pointer to the newly allocated probe struct
+ */
+blkid_probe blkid_new_probe(void)
+{
+ blkid_init_debug(0);
+ return calloc(1, sizeof(struct blkid_struct_probe));
+}
+
+/*
+ * Deallocates probe struct, buffers and all allocated
+ * data that are associated with this probing control struct.
+ */
+void blkid_free_probe(blkid_probe pr)
+{
+ if (!pr)
+ return;
+ free(pr->fltr);
+ free(pr->buf);
+ free(pr->sbbuf);
+ free(pr);
+}
+
+static void blkid_probe_reset_vals(blkid_probe pr)
+{
+ memset(pr->vals, 0, sizeof(pr->vals));
+ pr->nvals = 0;
+}
+
+void blkid_reset_probe(blkid_probe pr)
+{
+ if (!pr)
+ return;
+ DBG(DEBUG_LOWPROBE, printf("reseting blkid_probe\n"));
+ if (pr->buf)
+ memset(pr->buf, 0, pr->buf_max);
+ pr->buf_off = 0;
+ pr->buf_len = 0;
+ pr->idx = 0;
+ if (pr->sbbuf)
+ memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ);
+ pr->sbbuf_len = 0;
+ blkid_probe_reset_vals(pr);
+}
+
+
+/*
+ * Note that we have two offsets:
+ *
+ * 1/ general device offset (pr->off), that's useful for example when we
+ * probe a partition from whole disk image:
+ * blkid-low --offset <partition_position> disk.img
+ *
+ * 2/ buffer offset (the 'off' argument), that useful for offsets in
+ * superbloks, ...
+ *
+ * That means never use lseek(fd, 0, SEEK_SET), the zero position is always
+ * pr->off, so lseek(fd, pr->off, SEEK_SET).
+ *
+ */
+unsigned char *blkid_probe_get_buffer(blkid_probe pr,
+ blkid_loff_t off, blkid_loff_t len)
+{
+ ssize_t ret_read = 0;
+
+ if (off < 0 || len < 0) {
+ DBG(DEBUG_LOWPROBE,
+ printf("unexpected offset or length of buffer requested\n"));
+ return NULL;
+ }
+ if (off + len <= BLKID_SB_BUFSIZ) {
+ if (!pr->sbbuf) {
+ pr->sbbuf = malloc(BLKID_SB_BUFSIZ);
+ if (!pr->sbbuf)
+ return NULL;
+ }
+ if (!pr->sbbuf_len) {
+ if (lseek(pr->fd, pr->off, SEEK_SET) < 0)
+ return NULL;
+ ret_read = read(pr->fd, pr->sbbuf, BLKID_SB_BUFSIZ);
+ if (ret_read < 0)
+ ret_read = 0;
+ pr->sbbuf_len = ret_read;
+ }
+ if (off + len > pr->sbbuf_len)
+ return NULL;
+ return pr->sbbuf + off;
+ } else {
+ unsigned char *newbuf = NULL;
+
+ if (len > pr->buf_max) {
+ newbuf = realloc(pr->buf, len);
+ if (!newbuf)
+ return NULL;
+ pr->buf = newbuf;
+ pr->buf_max = len;
+ pr->buf_off = 0;
+ pr->buf_len = 0;
+ }
+ if (newbuf || off < pr->buf_off ||
+ off + len > pr->buf_off + pr->buf_len) {
+
+ if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0)
+ return NULL;
+
+ ret_read = read(pr->fd, pr->buf, len);
+ if (ret_read != (ssize_t) len)
+ return NULL;
+ pr->buf_off = off;
+ pr->buf_len = len;
+ }
+ return off ? pr->buf + (off - pr->buf_off) : pr->buf;
+ }
+}
+
+/*
+ * Assignes the device to probe control struct, resets internal buffers and
+ * reads 512 bytes from device to the buffers.
+ *
+ * Returns -1 in case of failure, or 0 on success.
+ */
+int blkid_probe_set_device(blkid_probe pr, int fd,
+ blkid_loff_t off, blkid_loff_t size)
+{
+ if (!pr)
+ return -1;
+
+ blkid_reset_probe(pr);
+
+ pr->fd = fd;
+ pr->off = off;
+ pr->size = 0;
+ pr->idx = 0;
+
+ if (size)
+ pr->size = size;
+ else {
+ struct stat sb;
+
+ if (fstat(fd, &sb))
+ return -1;
+
+ if (S_ISBLK(sb.st_mode))
+ blkdev_get_size(fd, (unsigned long long *) &pr->size);
+ else
+ pr->size = sb.st_size;
+ }
+ if (!pr->size)
+ return -1;
+
+ /* read SB to test if the device is readable */
+ if (!blkid_probe_get_buffer(pr, 0, 0x200)) {
+ DBG(DEBUG_LOWPROBE,
+ printf("failed to prepare a device for low-probing\n"));
+ return -1;
+ }
+
+ DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n",
+ pr->off, pr->size));
+ return 0;
+}
+
+int blkid_probe_set_request(blkid_probe pr, int flags)
+{
+ if (!pr)
+ return -1;
+ pr->probreq = flags;
+ return 0;
+}
+
+int blkid_probe_reset_filter(blkid_probe pr)
+{
+ if (!pr)
+ return -1;
+ if (pr->fltr)
+ memset(pr->fltr, 0, BLKID_FLTR_SIZE * sizeof(unsigned long));
+ pr->idx = 0;
+ return 0;
+}
+
+/*
+ * flag:
+ *
+ * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN names[]
+ *
+ * BLKID_FLTR_ONLYIN - probe filesystem which are IN names[]
+ */
+int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[])
+{
+ int i;
+
+ if (!pr || !names)
+ return -1;
+ if (!pr->fltr)
+ pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long));
+ else
+ blkid_probe_reset_filter(pr);
+
+ if (!pr->fltr)
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
+ int has = 0;
+ const struct blkid_idinfo *id = idinfos[i];
+ char **n;
+
+ for (n = names; *n; n++) {
+ if (!strcmp(id->name, *n)) {
+ has = 1;
+ break;
+ }
+ }
+ /* The default is enable all filesystems,
+ * set relevant bitmap bit means disable the filesystem.
+ */
+ if (flag & BLKID_FLTR_ONLYIN) {
+ if (!has)
+ blkid_bmp_set_item(pr->fltr, i);
+ } else if (flag & BLKID_FLTR_NOTIN) {
+ if (has)
+ blkid_bmp_set_item(pr->fltr, i);
+ }
+ }
+ DBG(DEBUG_LOWPROBE, printf("a new probing type-filter initialized\n"));
+ pr->idx = 0;
+ return 0;
+}
+
+/*
+ * flag:
+ *
+ * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN "usage"
+ *
+ * BLKID_FLTR_ONLYIN - probe filesystem which are IN "usage"
+ *
+ * where the "usage" is a set of filesystem according the usage flag (crypto,
+ * raid, filesystem, ...)
+ */
+int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage)
+{
+ int i;
+
+ if (!pr || !usage)
+ return -1;
+ if (!pr->fltr)
+ pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long));
+ else
+ blkid_probe_reset_filter(pr);
+
+ if (!pr->fltr)
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
+ const struct blkid_idinfo *id = idinfos[i];
+
+ if (id->usage & usage) {
+ if (flag & BLKID_FLTR_NOTIN)
+ blkid_bmp_set_item(pr->fltr, i);
+ } else if (flag & BLKID_FLTR_ONLYIN)
+ blkid_bmp_set_item(pr->fltr, i);
+ }
+ DBG(DEBUG_LOWPROBE, printf("a new probing usage-filter initialized\n"));
+ pr->idx = 0;
+ return 0;
+}
+
+
+int blkid_probe_invert_filter(blkid_probe pr)
+{
+ int i;
+
+ if (!pr || !pr->fltr)
+ return -1;
+ for (i = 0; i < BLKID_FLTR_SIZE; i++)
+ pr->fltr[i] = ~pr->fltr[i];
+
+ DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n"));
+ pr->idx = 0;
+ return 0;
+}
+
+/*
+ * The blkid_do_probe() calls the probe functions. This routine could be used
+ * in a loop when you need to probe for all possible filesystems/raids.
+ *
+ * 1/ basic case -- use the first result:
+ *
+ * if (blkid_do_probe(pr) == 0) {
+ * int nvals = blkid_probe_numof_values(pr);
+ * for (n = 0; n < nvals; n++) {
+ * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0)
+ * printf("%s = %s\n", name, data);
+ * }
+ * }
+ *
+ * 2/ advanced case -- probe for all signatures (don't forget that some
+ * filesystems can co-exist on one volume (e.g. CD-ROM).
+ *
+ * while (blkid_do_probe(pr) == 0) {
+ * int nvals = blkid_probe_numof_values(pr);
+ * ...
+ * }
+ *
+ * The internal probing index (pointer to the last probing function) is
+ * always reseted when you touch probing filter or set a new device. It
+ * means you cannot use:
+ *
+ * blkid_probe_invert_filter()
+ * blkid_probe_filter_usage()
+ * blkid_probe_filter_types()
+ * blkid_probe_reset_filter()
+ * blkid_probe_set_device()
+ *
+ * in the loop (e.g while()) when you iterate on all signatures.
+ */
+int blkid_do_probe(blkid_probe pr)
+{
+ int i = 0;
+
+ if (!pr)
+ return -1;
+
+ blkid_probe_reset_vals(pr);
+
+ if (pr->idx)
+ i = pr->idx + 1;
+
+ if (i < 0 && i >= ARRAY_SIZE(idinfos))
+ return -1;
+
+ DBG(DEBUG_LOWPROBE, printf("--> starting probing loop\n"));
+
+ for ( ; i < ARRAY_SIZE(idinfos); i++) {
+ const struct blkid_idinfo *id;
+ const struct blkid_idmag *mag;
+ int hasmag = 0;
+
+ pr->idx = i;
+
+ if (pr->fltr && blkid_bmp_get_item(pr->fltr, i))
+ continue;
+
+ id = idinfos[i];
+ mag = id->magics ? &id->magics[0] : NULL;
+
+ /* try to detect by magic string */
+ while(mag && mag->magic) {
+ int idx;
+ unsigned char *buf;
+
+ idx = mag->kboff + (mag->sboff >> 10);
+ buf = blkid_probe_get_buffer(pr, idx << 10, 1024);
+
+ if (buf && !memcmp(mag->magic,
+ buf + (mag->sboff & 0x3ff), mag->len)) {
+ DBG(DEBUG_LOWPROBE, printf(
+ "%s: magic sboff=%u, kboff=%ld\n",
+ id->name, mag->sboff, mag->kboff));
+ hasmag = 1;
+ break;
+ }
+ mag++;
+ }
+
+ if (hasmag == 0 && id->magics && id->magics[0].magic)
+ /* magic string(s) defined, but not found */
+ continue;
+
+ /* final check by probing function */
+ if (id->probefunc) {
+ DBG(DEBUG_LOWPROBE, printf(
+ "%s: call probefunc()\n", id->name));
+ if (id->probefunc(pr, mag) != 0)
+ continue;
+ }
+
+ /* all cheks passed */
+ if (pr->probreq & BLKID_PROBREQ_TYPE)
+ blkid_probe_set_value(pr, "TYPE",
+ (unsigned char *) id->name,
+ strlen(id->name) + 1);
+ if (pr->probreq & BLKID_PROBREQ_USAGE)
+ blkid_probe_set_usage(pr, id->usage);
+
+ DBG(DEBUG_LOWPROBE,
+ printf("<-- leaving probing loop (type=%s)\n", id->name));
+ return 0;
+ }
+ DBG(DEBUG_LOWPROBE, printf("<-- leaving probing loop (failed)\n"));
+ return 1;
+}
+
+/*
+ * This is the same function as blkid_do_probe(), but returns only one result
+ * (cannot be used in while()) and checks for ambivalen results (more
+ * filesystems on the device) -- in such case returns -2.
+ */
+int blkid_do_safeprobe(blkid_probe pr)
+{
+ struct blkid_struct_probe first;
+ int count = 0;
+ int intol = 0;
+ int rc;
+
+ while ((rc = blkid_do_probe(pr)) == 0) {
+ if (!count) {
+ /* store the fist result */
+ memcpy(first.vals, pr->vals, sizeof(first.vals));
+ first.nvals = pr->nvals;
+ first.idx = pr->idx;
+ }
+ if (!(idinfos[pr->idx]->flags & BLKID_IDINFO_TOLERANT))
+ intol++;
+ count++;
+ }
+ if (rc < 0)
+ return rc; /* error */
+ if (count > 1 && intol) {
+ DBG(DEBUG_LOWPROBE,
+ printf("ERROR: ambivalent result detected (%d filesystems)!\n",
+ count));
+ return -2; /* error, ambivalent result (more FS) */
+ }
+ if (!count)
+ return 1; /* nothing detected */
+
+ /* restore the first result */
+ memcpy(pr->vals, first.vals, sizeof(first.vals));
+ pr->nvals = first.nvals;
+ pr->idx = first.idx;
+
+ return 0;
+}
+
+int blkid_probe_numof_values(blkid_probe pr)
+{
+ if (!pr)
+ return -1;
+ return pr->nvals;
+}
+
+
+static struct blkid_prval *blkid_probe_assign_value(
+ blkid_probe pr, const char *name)
+{
+ struct blkid_prval *v;
+
+ if (!name)
+ return NULL;
+ if (pr->nvals >= BLKID_PROBVAL_NVALS)
+ return NULL;
+
+ v = &pr->vals[pr->nvals];
+ v->name = name;
+ pr->nvals++;
+
+ DBG(DEBUG_LOWPROBE, printf("assigning %s\n", name));
+ return v;
+}
+
+int blkid_probe_set_value(blkid_probe pr, const char *name,
+ unsigned char *data, size_t len)
+{
+ struct blkid_prval *v;
+
+ if (len > BLKID_PROBVAL_BUFSIZ)
+ len = BLKID_PROBVAL_BUFSIZ;
+
+ v = blkid_probe_assign_value(pr, name);
+ if (!v)
+ return -1;
+
+ memcpy(v->data, data, len);
+ v->len = len;
+ return 0;
+}
+
+int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
+ const char *fmt, va_list ap)
+{
+ struct blkid_prval *v;
+ size_t len;
+
+ v = blkid_probe_assign_value(pr, name);
+ if (!v)
+ return -1;
+
+ len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap);
+
+ if (len <= 0) {
+ pr->nvals--; /* reset the latest assigned value */
+ return -1;
+ }
+ v->len = len + 1;
+ return 0;
+}
+
+int blkid_probe_set_version(blkid_probe pr, const char *version)
+{
+ if (pr->probreq & BLKID_PROBREQ_VERSION)
+ return blkid_probe_set_value(pr, "VERSION",
+ (unsigned char *) version, strlen(version) + 1);
+ return 0;
+}
+
+int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...)
+{
+ int rc = 0;
+
+ if (pr->probreq & BLKID_PROBREQ_VERSION) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = blkid_probe_vsprintf_value(pr, "VERSION", fmt, ap);
+ va_end(ap);
+ }
+ return rc;
+}
+
+static int blkid_probe_set_usage(blkid_probe pr, int usage)
+{
+ char *u = NULL;
+
+ if (usage & BLKID_USAGE_FILESYSTEM)
+ u = "filesystem";
+ else if (usage & BLKID_USAGE_RAID)
+ u = "raid";
+ else if (usage & BLKID_USAGE_CRYPTO)
+ u = "crypto";
+ else if (usage & BLKID_USAGE_OTHER)
+ u = "other";
+ else
+ u = "unknown";
+
+ return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1);
+}
+
+int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len)
+{
+ struct blkid_prval *v;
+ int i;
+
+ if (len > BLKID_PROBVAL_BUFSIZ)
+ len = BLKID_PROBVAL_BUFSIZ;
+
+ if ((pr->probreq & BLKID_PROBREQ_LABELRAW) &&
+ blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
+ return -1;
+ if (!(pr->probreq & BLKID_PROBREQ_LABEL))
+ return 0;
+ v = blkid_probe_assign_value(pr, "LABEL");
+ if (!v)
+ return -1;
+
+ memcpy(v->data, label, len);
+ v->data[len] = '\0';
+
+ /* remove trailing whitespace */
+ i = strnlen((char *) v->data, len);
+ while (i--) {
+ if (!isspace(v->data[i]))
+ break;
+ }
+ v->data[++i] = '\0';
+ v->len = i + 1;
+ return 0;
+}
+
+static size_t encode_to_utf8(int enc, unsigned char *dest, size_t len,
+ unsigned char *src, size_t count)
+{
+ size_t i, j;
+ uint16_t c;
+
+ for (j = i = 0; i + 2 <= count; i += 2) {
+ if (enc == BLKID_ENC_UTF16LE)
+ c = (src[i+1] << 8) | src[i];
+ else /* BLKID_ENC_UTF16BE */
+ c = (src[i] << 8) | src[i+1];
+ if (c == 0) {
+ dest[j] = '\0';
+ break;
+ } else if (c < 0x80) {
+ if (j+1 >= len)
+ break;
+ dest[j++] = (uint8_t) c;
+ } else if (c < 0x800) {
+ if (j+2 >= len)
+ break;
+ dest[j++] = (uint8_t) (0xc0 | (c >> 6));
+ dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
+ } else {
+ if (j+3 >= len)
+ break;
+ dest[j++] = (uint8_t) (0xe0 | (c >> 12));
+ dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
+ dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
+ }
+ }
+ dest[j] = '\0';
+ return j;
+}
+
+int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
+ size_t len, int enc)
+{
+ struct blkid_prval *v;
+
+ if ((pr->probreq & BLKID_PROBREQ_LABELRAW) &&
+ blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
+ return -1;
+ if (!(pr->probreq & BLKID_PROBREQ_LABEL))
+ return 0;
+ v = blkid_probe_assign_value(pr, "LABEL");
+ if (!v)
+ return -1;
+
+ v->len = encode_to_utf8(enc, v->data, sizeof(v->data), label, len);
+ return 0;
+}
+
+/* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */
+static int uuid_is_empty(const unsigned char *buf, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (buf[i])
+ return 0;
+ return 1;
+}
+
+int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
+ size_t len, const char *fmt, ...)
+{
+ int rc = -1;
+ va_list ap;
+
+ if (len > BLKID_PROBVAL_BUFSIZ)
+ len = BLKID_PROBVAL_BUFSIZ;
+
+ if (uuid_is_empty(uuid, len))
+ return 0;
+
+ if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
+ blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0)
+ return -1;
+ if (!(pr->probreq & BLKID_PROBREQ_UUID))
+ return 0;
+
+ va_start(ap, fmt);
+ rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap);
+ va_end(ap);
+
+ /* convert to lower case (..be paranoid) */
+ if (!rc) {
+ int i;
+ struct blkid_prval *v = &pr->vals[pr->nvals];
+
+ for (i = 0; i < v->len; i++)
+ if (v->data[i] >= 'A' && v->data[i] <= 'F')
+ v->data[i] = (v->data[i] - 'A') + 'a';
+ }
+ return rc;
+}
+
+/* function to set UUIDs that are in suberblocks stored as strings */
+int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len)
+{
+ struct blkid_prval *v;
+
+ if (str == NULL || *str == '\0')
+ return -1;
+ if (!len)
+ len = strlen((char *) str);
+ if (len > BLKID_PROBVAL_BUFSIZ)
+ len = BLKID_PROBVAL_BUFSIZ;
+
+ if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
+ blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0)
+ return -1;
+ if (!(pr->probreq & BLKID_PROBREQ_UUID))
+ return 0;
+
+ v = blkid_probe_assign_value(pr, "UUID");
+ if (v) {
+ memcpy((char *) v->data, str, len);
+ *(v->data + len) = '\0';
+ v->len = len;
+ return 0;
+ }
+ return -1;
+}
+
+/* default _set_uuid function to set DCE UUIDs */
+int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name)
+{
+ struct blkid_prval *v;
+
+ if (uuid_is_empty(uuid, 16))
+ return 0;
+
+ if (!name) {
+ if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
+ blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0)
+ return -1;
+ if (!(pr->probreq & BLKID_PROBREQ_UUID))
+ return 0;
+
+ v = blkid_probe_assign_value(pr, "UUID");
+ } else
+ v = blkid_probe_assign_value(pr, name);
+
+#ifdef HAVE_LIBUUID
+ {
+ uuid_unparse(uuid, (char *) v->data);
+ v->len = 37;
+ }
+#else
+ v->len = snprintf(v->data, sizeof(v->data),
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5],
+ uuid[6], uuid[7],
+ uuid[8], uuid[9],
+ uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]);
+ v->len++;
+#endif
+ return 0;
+}
+
+int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid)
+{
+ return blkid_probe_set_uuid_as(pr, uuid, NULL);
+}
+
+int blkid_probe_get_value(blkid_probe pr, int num, const char **name,
+ const char **data, size_t *len)
+{
+ struct blkid_prval *v;
+
+ if (pr == NULL || num < 0 || num >= pr->nvals)
+ return -1;
+
+ v = &pr->vals[num];
+ if (name)
+ *name = v->name;
+ if (data)
+ *data = (char *) v->data;
+ if (len)
+ *len = v->len;
+
+ DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
+ return 0;
+}
+
+int blkid_probe_lookup_value(blkid_probe pr, const char *name,
+ const char **data, size_t *len)
+{
+ int i;
+
+ if (pr == NULL || pr->nvals == 0 || name == NULL)
+ return -1;
+
+ for (i = 0; i < pr->nvals; i++) {
+ struct blkid_prval *v = &pr->vals[i];
+
+ if (v->name && strcmp(name, v->name) == 0) {
+ if (data)
+ *data = (char *) v->data;
+ if (len)
+ *len = v->len;
+ DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int blkid_probe_has_value(blkid_probe pr, const char *name)
+{
+ if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0)
+ return 1;
+ return 0;
+}
+