Update blkid to 2.25.0
Break libblkid into 4 libraries: libblkid, libuuid, libutil-linux and libfdisk.

This should help in later patch updates.

Change-Id: I680d9a7feb031e5c29a603e9c58aff4b65826262
diff --git a/libblkid/src/.gitignore b/libblkid/src/.gitignore
new file mode 100644
index 0000000..af34f58
--- /dev/null
+++ b/libblkid/src/.gitignore
@@ -0,0 +1 @@
+blkid.h
diff --git a/libblkid/src/bitops.h b/libblkid/src/bitops.h
new file mode 100644
index 0000000..7439ece
--- /dev/null
+++ b/libblkid/src/bitops.h
@@ -0,0 +1,126 @@
+/*
+ * No copyright is claimed.  This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#ifndef BITOPS_H
+#define BITOPS_H
+
+#include <stdint.h>
+#include <sys/param.h>
+
+#if defined(HAVE_BYTESWAP_H)
+# include <byteswap.h>
+#endif
+
+#define HAVE_SYS_ENDIAN_H
+#if defined(HAVE_ENDIAN_H)
+#  include <endian.h>
+#elif defined(HAVE_SYS_ENDIAN_H)	/* BSDs have them here */
+#  include <sys/endian.h>
+#endif
+
+#if defined(__OpenBSD__)
+# include <sys/types.h>
+# define be16toh(x) betoh16(x)
+# define be32toh(x) betoh32(x)
+# define be64toh(x) betoh64(x)
+#endif
+
+/*
+ * Fallbacks
+ */
+#ifndef bswap_16
+# define bswap_16(x)   ((((x) & 0x00FF) << 8) | \
+			(((x) & 0xFF00) >> 8))
+#endif
+
+#ifndef bswap_32
+# define bswap_32(x)   ((((x) & 0x000000FF) << 24) | \
+			(((x) & 0x0000FF00) << 8)  | \
+			(((x) & 0x00FF0000) >> 8)  | \
+			(((x) & 0xFF000000) >> 24))
+#endif
+
+#ifndef bswap_64
+# define bswap_64(x) ((((x) & 0x00000000000000FFULL) << 56) | \
+                      (((x) & 0x000000000000FF00ULL) << 40) | \
+                      (((x) & 0x0000000000FF0000ULL) << 24) | \
+                      (((x) & 0x00000000FF000000ULL) << 8)  | \
+                      (((x) & 0x000000FF00000000ULL) >> 8)  | \
+                      (((x) & 0x0000FF0000000000ULL) >> 24) | \
+                      (((x) & 0x00FF000000000000ULL) >> 40) | \
+                      (((x) & 0xFF00000000000000ULL) >> 56))
+#endif
+
+//#ifndef htobe16
+//# if !defined(WORDS_BIGENDIAN)
+//#  define htobe16(x) bswap_16 (x)
+#  define htole16(x) (x)
+#  define be16toh(x) bswap_16 (x)
+#  define le16toh(x) (x)
+//#  define htobe32(x) bswap_32 (x)
+#  define htole32(x) (x)
+#  define be32toh(x) bswap_32 (x)
+#  define le32toh(x) (x)
+//#  define htobe64(x) bswap_64 (x)
+#  define htole64(x) (x)
+#  define be64toh(x) bswap_64 (x)
+#  define le64toh(x) (x)
+/*
+# else
+#  define htobe16(x) (x)
+#  define htole16(x) bswap_16 (x)
+#  define be16toh(x) (x)
+#  define le16toh(x) bswap_16 (x)
+#  define htobe32(x) (x)
+#  define htole32(x) bswap_32 (x)
+#  define be32toh(x) (x)
+#  define le32toh(x) bswap_32 (x)
+#  define htobe64(x) (x)
+#  define htole64(x) bswap_64 (x)
+#  define be64toh(x) (x)
+#  define le64toh(x) bswap_64 (x)
+# endif
+#endif
+*/
+/*
+ * Byte swab macros (based on linux/byteorder/swab.h)
+ */
+#define swab16(x) bswap_16(x)
+#define swab32(x) bswap_32(x)
+#define swab64(x) bswap_64(x)
+
+#define cpu_to_le16(x) ((uint16_t) htole16(x))
+#define cpu_to_le32(x) ((uint32_t) htole32(x))
+#define cpu_to_le64(x) ((uint64_t) htole64(x))
+
+#define cpu_to_be16(x) ((uint16_t) htobe16(x))
+#define cpu_to_be32(x) ((uint32_t) htobe32(x))
+#define cpu_to_be64(x) ((uint64_t) htobe64(x))
+
+#define le16_to_cpu(x) ((uint16_t) le16toh(x))
+#define le32_to_cpu(x) ((uint32_t) le32toh(x))
+#define le64_to_cpu(x) ((uint64_t) le64toh(x))
+
+#define be16_to_cpu(x) ((uint16_t) be16toh(x))
+#define be32_to_cpu(x) ((uint32_t) be32toh(x))
+#define be64_to_cpu(x) ((uint64_t) be64toh(x))
+
+/*
+ * Bit map related macros. Usually provided by libc.
+ */
+#ifndef NBBY
+# define NBBY            CHAR_BIT
+#endif
+
+#ifndef setbit
+# define setbit(a,i)	((a)[(i)/NBBY] |= 1<<((i)%NBBY))
+# define clrbit(a,i)	((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
+# define isset(a,i)	((a)[(i)/NBBY] & (1<<((i)%NBBY)))
+# define isclr(a,i)	(((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
+#endif
+
+#endif /* BITOPS_H */
+
diff --git a/libblkid/src/blkdev.h b/libblkid/src/blkdev.h
new file mode 100644
index 0000000..ade0887
--- /dev/null
+++ b/libblkid/src/blkdev.h
@@ -0,0 +1,146 @@
+/*
+ * No copyright is claimed.  This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#ifndef BLKDEV_H
+#define BLKDEV_H
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_IOCCOM_H
+# include <sys/ioccom.h> /* for _IO macro on e.g. Solaris */
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_MKDEV_H
+# include <sys/mkdev.h>		/* major and minor on Solaris */
+#endif
+
+#define DEFAULT_SECTOR_SIZE       512
+
+#ifdef __linux__
+/* very basic ioclts, should be available everywhere */
+# ifndef BLKROSET
+#  define BLKROSET   _IO(0x12,93)	/* set device read-only (0 = read-write) */
+#  define BLKROGET   _IO(0x12,94)	/* get read-only status (0 = read_write) */
+#  define BLKRRPART  _IO(0x12,95)	/* re-read partition table */
+#  define BLKGETSIZE _IO(0x12,96)	/* return device size /512 (long *arg) */
+#  define BLKFLSBUF  _IO(0x12,97)	/* flush buffer cache */
+#  define BLKRASET   _IO(0x12,98)	/* set read ahead for block device */
+#  define BLKRAGET   _IO(0x12,99)	/* get current read ahead setting */
+#  define BLKFRASET  _IO(0x12,100)	/* set filesystem (mm/filemap.c) read-ahead */
+#  define BLKFRAGET  _IO(0x12,101)	/* get filesystem (mm/filemap.c) read-ahead */
+#  define BLKSECTSET _IO(0x12,102)	/* set max sectors per request (ll_rw_blk.c) */
+#  define BLKSECTGET _IO(0x12,103)	/* get max sectors per request (ll_rw_blk.c) */
+#  define BLKSSZGET  _IO(0x12,104)	/* get block device sector size */
+
+/* ioctls introduced in 2.2.16, removed in 2.5.58 */
+#  define BLKELVGET  _IOR(0x12,106,size_t) /* elevator get */
+#  define BLKELVSET  _IOW(0x12,107,size_t) /* elevator set */
+
+#  define BLKBSZGET  _IOR(0x12,112,size_t)
+#  define BLKBSZSET  _IOW(0x12,113,size_t)
+# endif /* !BLKROSET */
+
+# ifndef BLKGETSIZE64
+#  define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
+# endif
+
+/* block device topology ioctls, introduced in 2.6.32 (commit ac481c20) */
+# ifndef BLKIOMIN
+#  define BLKIOMIN   _IO(0x12,120)
+#  define BLKIOOPT   _IO(0x12,121)
+#  define BLKALIGNOFF _IO(0x12,122)
+#  define BLKPBSZGET _IO(0x12,123)
+# endif
+
+/* discard zeroes support, introduced in 2.6.33 (commit 98262f27) */
+# ifndef BLKDISCARDZEROES
+#  define BLKDISCARDZEROES _IO(0x12,124)
+# endif
+
+/* filesystem freeze, introduced in 2.6.29 (commit fcccf502) */
+# ifndef FIFREEZE
+#  define FIFREEZE   _IOWR('X', 119, int)    /* Freeze */
+#  define FITHAW     _IOWR('X', 120, int)    /* Thaw */
+# endif
+
+/* uniform CD-ROM information */
+# ifndef CDROM_GET_CAPABILITY
+#  define CDROM_GET_CAPABILITY 0x5331
+# endif
+
+#endif /* __linux */
+
+
+#ifdef APPLE_DARWIN
+# define BLKGETSIZE DKIOCGETBLOCKCOUNT32
+#endif
+
+#ifndef HDIO_GETGEO
+# ifdef __linux__
+#  define HDIO_GETGEO 0x0301
+# endif
+
+struct hd_geometry {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned short cylinders;	/* truncated */
+	unsigned long start;
+};
+#endif /* HDIO_GETGEO */
+
+
+/* are we working with block device? */
+int is_blkdev(int fd);
+
+/* Determine size in bytes */
+off_t blkdev_find_size (int fd);
+
+/* get size in bytes */
+int blkdev_get_size(int fd, unsigned long long *bytes);
+
+/* get 512-byte sector count */
+int blkdev_get_sectors(int fd, unsigned long long *sectors);
+
+/* get hardware sector size */
+int blkdev_get_sector_size(int fd, int *sector_size);
+
+/* specifies whether or not the device is misaligned */
+int blkdev_is_misaligned(int fd);
+
+/* get physical block device size */
+int blkdev_get_physector_size(int fd, int *sector_size);
+
+/* is the device cdrom capable? */
+int blkdev_is_cdrom(int fd);
+
+/* get device's geometry - legacy */
+int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s);
+
+/* SCSI device types.  Copied almost as-is from kernel header.
+ * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=include/scsi/scsi.h */
+#define SCSI_TYPE_DISK			0x00
+#define SCSI_TYPE_TAPE			0x01
+#define SCSI_TYPE_PRINTER		0x02
+#define SCSI_TYPE_PROCESSOR		0x03	/* HP scanners use this */
+#define SCSI_TYPE_WORM			0x04	/* Treated as ROM by our system */
+#define SCSI_TYPE_ROM			0x05
+#define SCSI_TYPE_SCANNER		0x06
+#define SCSI_TYPE_MOD			0x07	/* Magneto-optical disk - treated as SCSI_TYPE_DISK */
+#define SCSI_TYPE_MEDIUM_CHANGER	0x08
+#define SCSI_TYPE_COMM			0x09	/* Communications device */
+#define SCSI_TYPE_RAID			0x0c
+#define SCSI_TYPE_ENCLOSURE		0x0d	/* Enclosure Services Device */
+#define SCSI_TYPE_RBC			0x0e
+#define SCSI_TYPE_OSD			0x11
+#define SCSI_TYPE_NO_LUN		0x7f
+
+/* convert scsi type code to name */
+const char *blkdev_scsi_type_to_name(int type);
+
+
+#endif /* BLKDEV_H */
diff --git a/libblkid/src/blkid.h.in b/libblkid/src/blkid.h.in
new file mode 100644
index 0000000..4f5fe2a
--- /dev/null
+++ b/libblkid/src/blkid.h.in
@@ -0,0 +1,414 @@
+/*
+ * blkid.h - Interface for libblkid, a library to identify block devices
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _BLKID_BLKID_H
+#define _BLKID_BLKID_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLKID_VERSION   "@LIBBLKID_VERSION@"
+#define BLKID_DATE      "@LIBBLKID_DATE@"
+
+/**
+ * blkid_dev:
+ *
+ * The device object keeps information about one device
+ */
+typedef struct blkid_struct_dev *blkid_dev;
+
+/**
+ * blkid_cache:
+ *
+ * information about all system devices
+ */
+typedef struct blkid_struct_cache *blkid_cache;
+
+/**
+ * blkid_probe:
+ *
+ * low-level probing setting
+ */
+typedef struct blkid_struct_probe *blkid_probe;
+
+/**
+ * blkid_topology:
+ *
+ * device topology information
+ */
+typedef struct blkid_struct_topology *blkid_topology;
+
+/**
+ * blkid_partlist
+ *
+ * list of all detected partitions and partitions tables
+ */
+typedef struct blkid_struct_partlist *blkid_partlist;
+
+/**
+ * blkid_partition:
+ *
+ * information about a partition
+ */
+typedef struct blkid_struct_partition *blkid_partition;
+
+/**
+ * blkid_parttable:
+ *
+ * information about a partition table
+ */
+typedef struct blkid_struct_parttable *blkid_parttable;
+
+/**
+ * blkid_loff_t:
+ *
+ * 64-bit signed number for offsets and sizes
+ */
+typedef int64_t blkid_loff_t;
+
+/**
+ * blkid_tag_iterate:
+ *
+ * tags iterator for high-level (blkid_cache) API
+ */
+typedef struct blkid_struct_tag_iterate *blkid_tag_iterate;
+
+/**
+ * blkid_dev_iterate:
+ *
+ * devices iterator for high-level (blkid_cache) API
+ */
+typedef struct blkid_struct_dev_iterate *blkid_dev_iterate;
+
+/*
+ * Flags for blkid_get_dev
+ *
+ * BLKID_DEV_CREATE	Create an empty device structure if not found
+ *			in the cache.
+ * BLKID_DEV_VERIFY	Make sure the device structure corresponds
+ *			with reality.
+ * BLKID_DEV_FIND	Just look up a device entry, and return NULL
+ *			if it is not found.
+ * BLKID_DEV_NORMAL	Get a valid device structure, either from the
+ *			cache or by probing the device.
+ */
+#define BLKID_DEV_FIND		0x0000
+#define BLKID_DEV_CREATE	0x0001
+#define BLKID_DEV_VERIFY	0x0002
+#define BLKID_DEV_NORMAL	(BLKID_DEV_CREATE | BLKID_DEV_VERIFY)
+
+
+#ifndef __GNUC_PREREQ
+# if defined __GNUC__ && defined __GNUC_MINOR__
+#  define __GNUC_PREREQ(maj, min)  ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+# else
+#  define __GNUC_PREREQ(maj, min) 0
+# endif
+#endif
+
+#ifndef __ul_attribute__
+# if __GNUC_PREREQ (3, 4)
+#  define __ul_attribute__(_a_) __attribute__(_a_)
+# else
+#  define __ul_attribute__(_a_)
+# endif
+#endif
+
+/* cache.c */
+extern void blkid_init_debug(int mask);
+extern void blkid_put_cache(blkid_cache cache);
+extern int blkid_get_cache(blkid_cache *cache, const char *filename);
+extern void blkid_gc_cache(blkid_cache cache);
+
+/* dev.c */
+extern const char *blkid_dev_devname(blkid_dev dev)
+			__ul_attribute__((warn_unused_result));
+
+extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache);
+extern int blkid_dev_set_search(blkid_dev_iterate iter,
+				char *search_type, char *search_value);
+extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev);
+extern void blkid_dev_iterate_end(blkid_dev_iterate iterate);
+
+/* devno.c */
+extern char *blkid_devno_to_devname(dev_t devno)
+			__ul_attribute__((warn_unused_result));
+extern int blkid_devno_to_wholedisk(dev_t dev, char *diskname,
+                        size_t len, dev_t *diskdevno)
+			__ul_attribute__((warn_unused_result));
+
+/* devname.c */
+extern int blkid_probe_all(blkid_cache cache);
+extern int blkid_probe_all_new(blkid_cache cache);
+extern int blkid_probe_all_removable(blkid_cache cache);
+
+extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags);
+
+/* getsize.c */
+extern blkid_loff_t blkid_get_dev_size(int fd);
+
+/* verify.c */
+extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev);
+
+/* read.c */
+
+/* resolve.c */
+extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname,
+				       const char *devname)
+			__ul_attribute__((warn_unused_result));
+extern char *blkid_get_devname(blkid_cache cache, const char *token,
+			       const char *value)
+			__ul_attribute__((warn_unused_result));
+
+/* tag.c */
+extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev);
+extern int blkid_tag_next(blkid_tag_iterate iterate,
+			      const char **type, const char **value);
+extern void blkid_tag_iterate_end(blkid_tag_iterate iterate);
+extern int blkid_dev_has_tag(blkid_dev dev, const char *type, const char *value);
+
+extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
+					 const char *type,
+					 const char *value);
+
+extern int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val);
+
+/* version.c */
+extern int blkid_parse_version_string(const char *ver_string)
+			__ul_attribute__((nonnull));
+extern int blkid_get_library_version(const char **ver_string,
+				     const char **date_string);
+
+/* encode.c */
+extern int blkid_encode_string(const char *str, char *str_enc, size_t len);
+extern int blkid_safe_string(const char *str, char *str_safe, size_t len);
+
+/* evaluate.c */
+extern int blkid_send_uevent(const char *devname, const char *action);
+extern char *blkid_evaluate_tag(const char *token, const char *value,
+				blkid_cache *cache)
+			__ul_attribute__((warn_unused_result));
+extern char *blkid_evaluate_spec(const char *spec, blkid_cache *cache)
+			__ul_attribute__((warn_unused_result));
+
+/* probe.c */
+extern blkid_probe blkid_new_probe(void)
+			__ul_attribute__((warn_unused_result));
+extern blkid_probe blkid_new_probe_from_filename(const char *filename)
+			__ul_attribute__((warn_unused_result));
+extern void blkid_free_probe(blkid_probe pr);
+
+extern void blkid_reset_probe(blkid_probe pr);
+
+extern int blkid_probe_set_device(blkid_probe pr, int fd,
+	                blkid_loff_t off, blkid_loff_t size);
+
+extern dev_t blkid_probe_get_devno(blkid_probe pr)
+			__ul_attribute__((nonnull));
+
+extern dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr)
+			__ul_attribute__((nonnull));
+
+extern int blkid_probe_is_wholedisk(blkid_probe pr)
+			__ul_attribute__((nonnull));
+
+extern blkid_loff_t blkid_probe_get_size(blkid_probe pr);
+extern blkid_loff_t blkid_probe_get_offset(blkid_probe pr);
+extern unsigned int blkid_probe_get_sectorsize(blkid_probe pr);
+extern blkid_loff_t blkid_probe_get_sectors(blkid_probe pr);
+
+extern int blkid_probe_get_fd(blkid_probe pr);
+
+/*
+ * superblocks probing
+ */
+extern int blkid_known_fstype(const char *fstype);
+
+extern int blkid_superblocks_get_name(size_t idx, const char **name, int *usage);
+
+extern int blkid_probe_enable_superblocks(blkid_probe pr, int enable);
+
+#define BLKID_SUBLKS_LABEL	(1 << 1) /* read LABEL from superblock */
+#define BLKID_SUBLKS_LABELRAW	(1 << 2) /* read and define LABEL_RAW result value*/
+#define BLKID_SUBLKS_UUID	(1 << 3) /* read UUID from superblock */
+#define BLKID_SUBLKS_UUIDRAW	(1 << 4) /* read and define UUID_RAW result value */
+#define BLKID_SUBLKS_TYPE	(1 << 5) /* define TYPE result value */
+#define BLKID_SUBLKS_SECTYPE	(1 << 6) /* define compatible fs type (second type) */
+#define BLKID_SUBLKS_USAGE	(1 << 7) /* define USAGE result value */
+#define BLKID_SUBLKS_VERSION	(1 << 8) /* read FS type from superblock */
+#define BLKID_SUBLKS_MAGIC	(1 << 9) /* define SBMAGIC and SBMAGIC_OFFSET */
+#define BLKID_SUBLKS_BADCSUM	(1 << 10) /* allow a bad checksum */
+
+#define BLKID_SUBLKS_DEFAULT	(BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | \
+				 BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE)
+
+extern int blkid_probe_set_superblocks_flags(blkid_probe pr, int flags);
+extern int blkid_probe_reset_superblocks_filter(blkid_probe pr);
+extern int blkid_probe_invert_superblocks_filter(blkid_probe pr);
+
+/**
+ * BLKID_FLTR_NOTIN
+ */
+#define BLKID_FLTR_NOTIN		1
+/**
+ * BLKID_FLTR_ONLYIN
+ */
+#define BLKID_FLTR_ONLYIN		2
+extern int blkid_probe_filter_superblocks_type(blkid_probe pr, int flag, char *names[]);
+
+#define BLKID_USAGE_FILESYSTEM		(1 << 1)
+#define BLKID_USAGE_RAID		(1 << 2)
+#define BLKID_USAGE_CRYPTO		(1 << 3)
+#define BLKID_USAGE_OTHER		(1 << 4)
+extern int blkid_probe_filter_superblocks_usage(blkid_probe pr, int flag, int usage);
+
+/*
+ * topology probing
+ */
+extern int blkid_probe_enable_topology(blkid_probe pr, int enable);
+
+/* binary interface */
+extern blkid_topology blkid_probe_get_topology(blkid_probe pr);
+
+extern unsigned long blkid_topology_get_alignment_offset(blkid_topology tp)
+			__ul_attribute__((nonnull));
+extern unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp)
+			__ul_attribute__((nonnull));
+extern unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp)
+			__ul_attribute__((nonnull));
+extern unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp)
+			__ul_attribute__((nonnull));
+extern unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp)
+			__ul_attribute__((nonnull));
+
+/*
+ * partitions probing
+ */
+extern int blkid_known_pttype(const char *pttype);
+
+extern int blkid_probe_enable_partitions(blkid_probe pr, int enable);
+
+extern int blkid_probe_reset_partitions_filter(blkid_probe pr);
+extern int blkid_probe_invert_partitions_filter(blkid_probe pr);
+extern int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[]);
+
+/* partitions probing flags */
+#define BLKID_PARTS_FORCE_GPT		(1 << 1)
+#define BLKID_PARTS_ENTRY_DETAILS	(1 << 2)
+#define BLKID_PARTS_MAGIC		(1 << 3)
+extern int blkid_probe_set_partitions_flags(blkid_probe pr, int flags);
+
+/* binary interface */
+extern blkid_partlist blkid_probe_get_partitions(blkid_probe pr);
+
+extern int blkid_partlist_numof_partitions(blkid_partlist ls);
+extern blkid_parttable blkid_partlist_get_table(blkid_partlist ls);
+extern blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n);
+extern blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n);
+extern blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno);
+extern blkid_parttable blkid_partition_get_table(blkid_partition par);
+
+extern const char *blkid_partition_get_name(blkid_partition par);
+extern const char *blkid_partition_get_uuid(blkid_partition par);
+extern int blkid_partition_get_partno(blkid_partition par);
+extern blkid_loff_t blkid_partition_get_start(blkid_partition par);
+extern blkid_loff_t blkid_partition_get_size(blkid_partition par);
+
+extern int blkid_partition_get_type(blkid_partition par)
+			__ul_attribute__((nonnull));
+
+extern const char *blkid_partition_get_type_string(blkid_partition par);
+
+extern unsigned long long blkid_partition_get_flags(blkid_partition par)
+			__ul_attribute__((nonnull));
+
+extern int blkid_partition_is_logical(blkid_partition par)
+			__ul_attribute__((nonnull));
+extern int blkid_partition_is_extended(blkid_partition par)
+			__ul_attribute__((nonnull));
+extern int blkid_partition_is_primary(blkid_partition par)
+			__ul_attribute__((nonnull));
+
+extern const char *blkid_parttable_get_type(blkid_parttable tab);
+extern const char *blkid_parttable_get_id(blkid_parttable tab);
+
+extern blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab);
+extern blkid_partition blkid_parttable_get_parent(blkid_parttable tab);
+
+/*
+ * NAME=value low-level interface
+ */
+extern int blkid_do_probe(blkid_probe pr);
+extern int blkid_do_safeprobe(blkid_probe pr);
+extern int blkid_do_fullprobe(blkid_probe pr);
+
+extern int blkid_probe_numof_values(blkid_probe pr);
+extern int blkid_probe_get_value(blkid_probe pr, int num, const char **name,
+                        const char **data, size_t *len);
+extern int blkid_probe_lookup_value(blkid_probe pr, const char *name,
+                        const char **data, size_t *len);
+extern int blkid_probe_has_value(blkid_probe pr, const char *name)
+			__ul_attribute__((nonnull));
+
+extern int blkid_do_wipe(blkid_probe pr, int dryrun);
+extern int blkid_probe_step_back(blkid_probe pr);
+
+/*
+ * Deprecated functions/macros
+ */
+#ifndef BLKID_DISABLE_DEPRECATED
+
+#define BLKID_PROBREQ_LABEL     BLKID_SUBLKS_LABEL
+#define BLKID_PROBREQ_LABELRAW  BLKID_SUBLKS_LABELRAW
+#define BLKID_PROBREQ_UUID      BLKID_SUBLKS_UUID
+#define BLKID_PROBREQ_UUIDRAW   BLKID_SUBLKS_UUIDRAW
+#define BLKID_PROBREQ_TYPE      BLKID_SUBLKS_TYPE
+#define BLKID_PROBREQ_SECTYPE   BLKID_SUBLKS_SECTYPE
+#define BLKID_PROBREQ_USAGE     BLKID_SUBLKS_USAGE
+#define BLKID_PROBREQ_VERSION   BLKID_SUBLKS_VERSION
+
+extern int blkid_probe_set_request(blkid_probe pr, int flags)
+			__ul_attribute__((deprecated));
+
+extern int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage)
+			__ul_attribute__((deprecated));
+
+extern int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[])
+			__ul_attribute__((deprecated));
+
+extern int blkid_probe_invert_filter(blkid_probe pr)
+			__ul_attribute__((deprecated));
+
+extern int blkid_probe_reset_filter(blkid_probe pr)
+			__ul_attribute__((deprecated));
+
+#endif /* BLKID_DISABLE_DEPRECATED */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BLKID_BLKID_H */
diff --git a/libblkid/src/blkidP.h b/libblkid/src/blkidP.h
new file mode 100644
index 0000000..fbf4e71
--- /dev/null
+++ b/libblkid/src/blkidP.h
@@ -0,0 +1,545 @@
+/*
+ * blkidP.h - Internal interfaces for libblkid
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#ifndef _BLKID_BLKIDP_H
+#define _BLKID_BLKIDP_H
+
+/* Always confirm that /dev/disk-by symlinks match with LABEL/UUID on device */
+/* #define CONFIG_BLKID_VERIFY_UDEV 1 */
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include "c.h"
+#include "bitops.h"	/* $(top_srcdir)/include/ */
+#include "blkdev.h"
+
+#include "debug.h"
+#include "blkid.h"
+#include "list.h"
+
+/*
+ * This describes the attributes of a specific device.
+ * We can traverse all of the tags by bid_tags (linking to the tag bit_names).
+ * The bid_label and bid_uuid fields are shortcuts to the LABEL and UUID tag
+ * values, if they exist.
+ */
+struct blkid_struct_dev
+{
+	struct list_head	bid_devs;	/* All devices in the cache */
+	struct list_head	bid_tags;	/* All tags for this device */
+	blkid_cache		bid_cache;	/* Dev belongs to this cache */
+	char			*bid_name;	/* Device inode pathname */
+	char			*bid_type;	/* Preferred device TYPE */
+	int			bid_pri;	/* Device priority */
+	dev_t			bid_devno;	/* Device major/minor number */
+	time_t			bid_time;	/* Last update time of device */
+	suseconds_t		bid_utime;	/* Last update time (microseconds) */
+	unsigned int		bid_flags;	/* Device status bitflags */
+	char			*bid_label;	/* Shortcut to device LABEL */
+	char			*bid_uuid;	/* Shortcut to binary UUID */
+};
+
+#define BLKID_BID_FL_VERIFIED	0x0001	/* Device data validated from disk */
+#define BLKID_BID_FL_INVALID	0x0004	/* Device is invalid */
+#define BLKID_BID_FL_REMOVABLE	0x0008	/* Device added by blkid_probe_all_removable() */
+
+/*
+ * Each tag defines a NAME=value pair for a particular device.  The tags
+ * are linked via bit_names for a single device, so that traversing the
+ * names list will get you a list of all tags associated with a device.
+ * They are also linked via bit_values for all devices, so one can easily
+ * search all tags with a given NAME for a specific value.
+ */
+struct blkid_struct_tag
+{
+	struct list_head	bit_tags;	/* All tags for this device */
+	struct list_head	bit_names;	/* All tags with given NAME */
+	char			*bit_name;	/* NAME of tag (shared) */
+	char			*bit_val;	/* value of tag */
+	blkid_dev		bit_dev;	/* pointer to device */
+};
+typedef struct blkid_struct_tag *blkid_tag;
+
+/*
+ * Chain IDs
+ */
+enum {
+	BLKID_CHAIN_SUBLKS,	/* FS/RAID superblocks (enabled by default) */
+	BLKID_CHAIN_TOPLGY,	/* Block device topology */
+	BLKID_CHAIN_PARTS,	/* Partition tables */
+
+	BLKID_NCHAINS		/* number of chains */
+};
+
+struct blkid_chain {
+	const struct blkid_chaindrv *driver;	/* chain driver */
+
+	int		enabled;	/* boolean */
+	int		flags;		/* BLKID_<chain>_* */
+	int		binary;		/* boolean */
+	int		idx;		/* index of the current prober (or -1) */
+	unsigned long	*fltr;		/* filter or NULL */
+	void		*data;		/* private chain data or NULL */
+};
+
+/*
+ * Chain driver
+ */
+struct blkid_chaindrv {
+	const size_t	id;		/* BLKID_CHAIN_* */
+	const char	*name;		/* name of chain (for debug purpose) */
+	const int	dflt_flags;	/* default chain flags */
+	const int	dflt_enabled;	/* default enabled boolean */
+	int		has_fltr;	/* boolean */
+
+	const struct blkid_idinfo **idinfos; /* description of probing functions */
+	const size_t	nidinfos;	/* number of idinfos */
+
+	/* driver operations */
+	int		(*probe)(blkid_probe, struct blkid_chain *);
+	int		(*safeprobe)(blkid_probe, struct blkid_chain *);
+	void		(*free_data)(blkid_probe, void *);
+};
+
+/*
+ * Low-level probe result
+ */
+#define BLKID_PROBVAL_BUFSIZ	128
+
+#define BLKID_NVALS_SUBLKS	18
+#define BLKID_NVALS_TOPLGY	5
+#define BLKID_NVALS_PARTS	13
+
+/* Max number of all values in probing result */
+#define BLKID_NVALS             (BLKID_NVALS_SUBLKS + \
+				 BLKID_NVALS_TOPLGY + \
+				 BLKID_NVALS_PARTS)
+
+struct blkid_prval
+{
+	const char	*name;			/* value name */
+	unsigned char	data[BLKID_PROBVAL_BUFSIZ]; /* value data */
+	size_t		len;			/* length of value data */
+
+	struct blkid_chain	*chain;		/* owner */
+};
+
+/*
+ * Filesystem / Raid magic strings
+ */
+struct blkid_idmag
+{
+	const char	*magic;		/* magic string */
+	unsigned int	len;		/* length of magic */
+
+	long		kboff;		/* kilobyte offset of superblock */
+	unsigned int	sboff;		/* byte offset within superblock */
+};
+
+/*
+ * Filesystem / Raid description
+ */
+struct blkid_idinfo
+{
+	const char	*name;		/* fs, raid or partition table name */
+	int		usage;		/* BLKID_USAGE_* flag */
+	int		flags;		/* BLKID_IDINFO_* flags */
+	int		minsz;		/* minimal device size */
+
+					/* probe function */
+	int		(*probefunc)(blkid_probe pr, const struct blkid_idmag *mag);
+
+	struct blkid_idmag	magics[];	/* NULL or array with magic strings */
+};
+
+#define BLKID_NONE_MAGIC	{{ NULL }}
+
+/*
+ * tolerant FS - can share the same device with more filesystems (e.g. typical
+ * on CD-ROMs). We need this flag to detect ambivalent results (e.g. valid fat
+ * and valid linux swap on the same device).
+ */
+#define BLKID_IDINFO_TOLERANT	(1 << 1)
+
+struct blkid_bufinfo {
+	unsigned char		*data;
+	blkid_loff_t		off;
+	blkid_loff_t		len;
+	struct list_head	bufs;	/* list of buffers */
+};
+
+/*
+ * Low-level probing control struct
+ */
+struct blkid_struct_probe
+{
+	int			fd;		/* device file descriptor */
+	blkid_loff_t		off;		/* begin of data on the device */
+	blkid_loff_t		size;		/* end of data on the device */
+
+	dev_t			devno;		/* device number (st.st_rdev) */
+	dev_t			disk_devno;	/* devno of the whole-disk or 0 */
+	unsigned int		blkssz;		/* sector size (BLKSSZGET ioctl) */
+	mode_t			mode;		/* struct stat.sb_mode */
+
+	int			flags;		/* private libray flags */
+	int			prob_flags;	/* always zeroized by blkid_do_*() */
+
+	blkid_loff_t		wipe_off;	/* begin of the wiped area */
+	blkid_loff_t		wipe_size;	/* size of the wiped area */
+	struct blkid_chain	*wipe_chain;	/* superblock, partition, ... */
+
+	struct list_head	buffers;	/* list of buffers */
+
+	struct blkid_chain	chains[BLKID_NCHAINS];	/* array of chains */
+	struct blkid_chain	*cur_chain;		/* current chain */
+
+	struct blkid_prval	vals[BLKID_NVALS];	/* results */
+	int			nvals;		/* number of assigned vals */
+
+	struct blkid_struct_probe *parent;	/* for clones */
+	struct blkid_struct_probe *disk_probe;	/* whole-disk probing */
+};
+
+/* private flags library flags */
+#define BLKID_FL_PRIVATE_FD	(1 << 1)	/* see blkid_new_probe_from_filename() */
+#define BLKID_FL_TINY_DEV	(1 << 2)	/* <= 1.47MiB (floppy or so) */
+#define BLKID_FL_CDROM_DEV	(1 << 3)	/* is a CD/DVD drive */
+#define BLKID_FL_NOSCAN_DEV	(1 << 4)	/* do not scan this device */
+
+/* private per-probing flags */
+#define BLKID_PROBE_FL_IGNORE_PT (1 << 1)	/* ignore partition table */
+
+extern blkid_probe blkid_clone_probe(blkid_probe parent);
+extern blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr);
+
+/*
+ * Evaluation methods (for blkid_eval_* API)
+ */
+enum {
+	BLKID_EVAL_UDEV = 0,
+	BLKID_EVAL_SCAN,
+
+	__BLKID_EVAL_LAST
+};
+
+/*
+ * Library config options
+ */
+struct blkid_config {
+	int eval[__BLKID_EVAL_LAST];	/* array with EVALUATION=<udev,cache> options */
+	int nevals;			/* number of elems in eval array */
+	int uevent;			/* SEND_UEVENT=<yes|not> option */
+	char *cachefile;		/* CACHE_FILE=<path> option */
+};
+
+extern struct blkid_config *blkid_read_config(const char *filename)
+			__ul_attribute__((warn_unused_result));
+extern void blkid_free_config(struct blkid_config *conf);
+
+/*
+ * Minimum number of seconds between device probes, even when reading
+ * from the cache.  This is to avoid re-probing all devices which were
+ * just probed by another program that does not share the cache.
+ */
+#define BLKID_PROBE_MIN		2
+
+/*
+ * Time in seconds an entry remains verified in the in-memory cache
+ * before being reverified (in case of long-running processes that
+ * keep a cache in memory and continue to use it for a long time).
+ */
+#define BLKID_PROBE_INTERVAL	200
+
+/* This describes an entire blkid cache file and probed devices.
+ * We can traverse all of the found devices via bic_list.
+ * We can traverse all of the tag types by bic_tags, which hold empty tags
+ * for each tag type.  Those tags can be used as list_heads for iterating
+ * through all devices with a specific tag type (e.g. LABEL).
+ */
+struct blkid_struct_cache
+{
+	struct list_head	bic_devs;	/* List head of all devices */
+	struct list_head	bic_tags;	/* List head of all tag types */
+	time_t			bic_time;	/* Last probe time */
+	time_t			bic_ftime;	/* Mod time of the cachefile */
+	unsigned int		bic_flags;	/* Status flags of the cache */
+	char			*bic_filename;	/* filename of cache */
+	blkid_probe		probe;		/* low-level probing stuff */
+};
+
+#define BLKID_BIC_FL_PROBED	0x0002	/* We probed /proc/partition devices */
+#define BLKID_BIC_FL_CHANGED	0x0004	/* Cache has changed from disk */
+
+/* config file */
+#define BLKID_CONFIG_FILE	"/etc/blkid.conf"
+
+/* cache file on systemds with /run */
+#define BLKID_RUNTIME_TOPDIR	"/run"
+#define BLKID_RUNTIME_DIR	BLKID_RUNTIME_TOPDIR "/blkid"
+#define BLKID_CACHE_FILE	BLKID_RUNTIME_DIR "/blkid.tab"
+
+/* old systems */
+#define BLKID_CACHE_FILE_OLD	"/etc/blkid.tab"
+
+#define BLKID_PROBE_OK	 0
+#define BLKID_PROBE_NONE 1
+
+#define BLKID_ERR_IO	 5
+#define BLKID_ERR_PROC	 9
+#define BLKID_ERR_MEM	12
+#define BLKID_ERR_CACHE	14
+#define BLKID_ERR_DEV	19
+#define BLKID_ERR_PARAM	22
+#define BLKID_ERR_BIG	27
+
+/*
+ * Priority settings for different types of devices
+ */
+#define BLKID_PRI_UBI	50
+#define BLKID_PRI_DM	40
+#define BLKID_PRI_EVMS	30
+#define BLKID_PRI_LVM	20
+#define BLKID_PRI_MD	10
+
+#define BLKID_DEBUG_HELP	(1 << 0)
+#define BLKID_DEBUG_INIT	(1 << 1)
+#define BLKID_DEBUG_CACHE	(1 << 2)
+#define BLKID_DEBUG_CONFIG	(1 << 3)
+#define BLKID_DEBUG_DEV		(1 << 4)
+#define BLKID_DEBUG_DEVNAME	(1 << 5)
+#define BLKID_DEBUG_DEVNO	(1 << 6)
+#define BLKID_DEBUG_EVALUATE	(1 << 7)
+#define BLKID_DEBUG_LOWPROBE	(1 << 8)
+#define BLKID_DEBUG_PROBE	(1 << 9)
+#define BLKID_DEBUG_READ	(1 << 10)
+#define BLKID_DEBUG_SAVE	(1 << 11)
+#define BLKID_DEBUG_TAG		(1 << 12)
+#define BLKID_DEBUG_ALL		0xFFFF		/* (1 << 16) aka FFFF is expected by API */
+
+UL_DEBUG_DECLARE_MASK(libblkid);
+#define DBG(m, x)	__UL_DBG(libblkid, BLKID_DEBUG_, m, x)
+#define ON_DBG(m, x)    __UL_DBG_CALL(libblkid, BLKID_DEBUG_, m, x)
+
+extern void blkid_debug_dump_dev(blkid_dev dev);
+extern void blkid_debug_dump_tag(blkid_tag tag);
+
+
+/* devno.c */
+struct dir_list {
+	char	*name;
+	struct dir_list *next;
+};
+extern void blkid__scan_dir(char *, dev_t, struct dir_list **, char **)
+			__attribute__((nonnull(1,4)));
+extern int blkid_driver_has_major(const char *drvname, int major)
+			__attribute__((warn_unused_result));
+
+/* lseek.c */
+extern blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence);
+
+/* read.c */
+extern void blkid_read_cache(blkid_cache cache)
+			__attribute__((nonnull));
+
+/* save.c */
+extern int blkid_flush_cache(blkid_cache cache)
+			__attribute__((nonnull));
+
+/* cache */
+extern char *blkid_safe_getenv(const char *arg)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern char *blkid_get_cache_filename(struct blkid_config *conf)
+			__attribute__((warn_unused_result));
+/*
+ * Functions to create and find a specific tag type: tag.c
+ */
+extern void blkid_free_tag(blkid_tag tag);
+extern blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern int blkid_set_tag(blkid_dev dev, const char *name,
+			 const char *value, const int vlength)
+			__attribute__((nonnull(1,2)));
+
+/*
+ * Functions to create and find a specific tag type: dev.c
+ */
+extern blkid_dev blkid_new_dev(void)
+			__attribute__((warn_unused_result));
+extern void blkid_free_dev(blkid_dev dev);
+
+/* probe.c */
+extern int blkid_probe_is_tiny(blkid_probe pr)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+extern int blkid_probe_is_cdrom(blkid_probe pr)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern unsigned char *blkid_probe_get_buffer(blkid_probe pr,
+                                blkid_loff_t off, blkid_loff_t len)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern int blkid_probe_get_dimension(blkid_probe pr,
+	                blkid_loff_t *off, blkid_loff_t *size)
+			__attribute__((nonnull));
+
+extern int blkid_probe_set_dimension(blkid_probe pr,
+	                blkid_loff_t off, blkid_loff_t size)
+			__attribute__((nonnull));
+
+extern int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id,
+			blkid_loff_t *offset, const struct blkid_idmag **res)
+			__attribute__((nonnull(1)));
+
+/* returns superblok according to 'struct blkid_idmag' */
+#define blkid_probe_get_sb(_pr, _mag, type) \
+			((type *) blkid_probe_get_buffer((_pr),\
+					(_mag)->kboff << 10, sizeof(type)))
+
+extern blkid_partlist blkid_probe_get_partlist(blkid_probe pr)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern int blkid_probe_is_covered_by_pt(blkid_probe pr,
+					blkid_loff_t offset, blkid_loff_t size)
+			__attribute__((warn_unused_result));
+
+extern void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn)
+			__attribute__((nonnull));
+extern int blkid_probe_chain_copy_vals(blkid_probe pr,
+				       struct blkid_chain *chn,
+			               struct blkid_prval *vals,
+				       int nvals)
+			__attribute__((nonnull));
+
+extern struct blkid_prval *blkid_probe_assign_value(blkid_probe pr,
+					const char *name)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern int blkid_probe_reset_last_value(blkid_probe pr)
+			__attribute__((nonnull));
+extern void blkid_probe_append_vals(blkid_probe pr,
+				    struct blkid_prval *vals,
+				    int nvals)
+			__attribute__((nonnull));
+
+extern struct blkid_chain *blkid_probe_get_chain(blkid_probe pr)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern unsigned long *blkid_probe_get_filter(blkid_probe pr, int chain, int create)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern int __blkid_probe_invert_filter(blkid_probe pr, int chain)
+			__attribute__((nonnull));
+extern int __blkid_probe_reset_filter(blkid_probe pr, int chain)
+			__attribute__((nonnull));
+extern int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[])
+			__attribute__((nonnull));
+
+extern void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+
+extern int blkid_probe_set_value(blkid_probe pr, const char *name,
+				unsigned char *data, size_t len)
+			__attribute__((nonnull));
+
+extern int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
+				const char *fmt, va_list ap)
+			__attribute__((nonnull));
+
+extern int blkid_probe_sprintf_value(blkid_probe pr, const char *name,
+				const char *fmt, ...)
+			__attribute__((nonnull))
+			__attribute__ ((__format__ (__printf__, 3, 4)));
+
+extern int blkid_probe_set_magic(blkid_probe pr, blkid_loff_t offset,
+				size_t len, unsigned char *magic)
+			__attribute__((nonnull));
+
+extern int blkid_probe_verify_csum(blkid_probe pr, uint64_t csum, uint64_t expected)
+			__attribute__((nonnull));
+
+extern void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len)
+			__attribute__((nonnull));
+extern int blkid_uuid_is_empty(const unsigned char *buf, size_t len);
+
+extern size_t blkid_rtrim_whitespace(unsigned char *str)
+			__attribute__((nonnull));
+extern size_t blkid_ltrim_whitespace(unsigned char *str)
+			__attribute__((nonnull));
+
+extern void blkid_probe_set_wiper(blkid_probe pr, blkid_loff_t off,
+				  blkid_loff_t size)
+			__attribute__((nonnull));
+extern int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn,
+		                blkid_loff_t off, blkid_loff_t size)
+			__attribute__((nonnull))
+			__attribute__((warn_unused_result));
+extern void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size)
+			__attribute__((nonnull));
+
+/* 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)[ blkid_bmp_idx_byte(item) ] &= ~blkid_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_nwords(max_items) \
+		(((max_items) + blkid_bmp_wordsize) / blkid_bmp_wordsize)
+
+#define blkid_bmp_nbytes(max_items) \
+		(blkid_bmp_nwords(max_items) * sizeof(unsigned long))
+
+/* encode.c */
+extern size_t blkid_encode_to_utf8(int enc, unsigned char *dest, size_t len,
+				const unsigned char *src, size_t count)
+			__attribute__((nonnull));
+
+#define BLKID_ENC_UTF16BE	0
+#define BLKID_ENC_UTF16LE	1
+
+#endif /* _BLKID_BLKIDP_H */
diff --git a/libblkid/src/c.h b/libblkid/src/c.h
new file mode 100644
index 0000000..6fcbc6d
--- /dev/null
+++ b/libblkid/src/c.h
@@ -0,0 +1,295 @@
+/*
+ * Fundamental C definitions.
+ */
+
+#ifndef UTIL_LINUX_C_H
+#define UTIL_LINUX_C_H
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "blkid.h"
+#ifdef HAVE_ERR_H
+# include <err.h>
+#endif
+
+#ifndef HAVE_USLEEP
+# include <time.h>
+#endif
+
+/*
+ * Compiler specific stuff
+ */
+#ifndef __GNUC_PREREQ
+# if defined __GNUC__ && defined __GNUC_MINOR__
+#  define __GNUC_PREREQ(maj, min) \
+	((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+# else
+#  define __GNUC_PREREQ(maj, min) 0
+# endif
+#endif
+
+#ifdef __GNUC__
+
+/* &a[0] degrades to a pointer: a different type from an array */
+# define __must_be_array(a) \
+	UL_BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(__typeof__(a), __typeof__(&a[0])))
+
+# define ignore_result(x) ({ \
+	__typeof__(x) __dummy __attribute__((__unused__)) = (x); (void) __dummy; \
+})
+
+#else /* !__GNUC__ */
+# define __must_be_array(a)	0
+# define __attribute__(_arg_)
+# define ignore_result(x) ((void) (x))
+#endif /* !__GNUC__ */
+
+/*
+ * Function attributes
+ */
+#ifndef __ul_alloc_size
+# if __GNUC_PREREQ (4, 3)
+#  define __ul_alloc_size(s) __attribute__((alloc_size(s)))
+# else
+#  define __ul_alloc_size(s)
+# endif
+#endif
+
+#ifndef __ul_calloc_size
+# if __GNUC_PREREQ (4, 3)
+#  define __ul_calloc_size(n, s) __attribute__((alloc_size(n, s)))
+# else
+#  define __ul_calloc_size(n, s)
+# endif
+#endif
+
+/* Force a compilation error if condition is true, but also produce a
+ * result (of value 0 and type size_t), so the expression can be used
+ * e.g. in a structure initializer (or where-ever else comma expressions
+ * aren't permitted).
+ */
+#define UL_BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
+#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
+#endif
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef min
+# define min(x, y) ({				\
+	__typeof__(x) _min1 = (x);		\
+	__typeof__(y) _min2 = (y);		\
+	(void) (&_min1 == &_min2);		\
+	_min1 < _min2 ? _min1 : _min2; })
+#endif
+
+#ifndef max
+# define max(x, y) ({				\
+	__typeof__(x) _max1 = (x);		\
+	__typeof__(y) _max2 = (y);		\
+	(void) (&_max1 == &_max2);		\
+	_max1 > _max2 ? _max1 : _max2; })
+#endif
+
+#ifndef cmp_numbers
+# define cmp_numbers(x, y) __extension__ ({     \
+        __typeof__(x) _a = (x);                 \
+        __typeof__(y) _b = (y);                 \
+        (void) (&_a == &_b);                    \
+        _a == _b ? 0 : _a > _b ? 1 : -1; })
+#endif
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({                       \
+	const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+#ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME
+# ifdef HAVE___PROGNAME
+extern char *__progname;
+#  define program_invocation_short_name __progname
+# else
+#  ifdef HAVE_GETEXECNAME
+#   define program_invocation_short_name \
+		prog_inv_sh_nm_from_file(getexecname(), 0)
+#  else
+#   define program_invocation_short_name \
+		prog_inv_sh_nm_from_file(__FILE__, 1)
+#  endif
+static char prog_inv_sh_nm_buf[256];
+static inline char *
+prog_inv_sh_nm_from_file(char *f, char stripext)
+{
+	char *t;
+
+	if ((t = strrchr(f, '/')) != NULL)
+		t++;
+	else
+		t = f;
+
+	strncpy(prog_inv_sh_nm_buf, t, sizeof(prog_inv_sh_nm_buf) - 1);
+	prog_inv_sh_nm_buf[sizeof(prog_inv_sh_nm_buf) - 1] = '\0';
+
+	if (stripext && (t = strrchr(prog_inv_sh_nm_buf, '.')) != NULL)
+		*t = '\0';
+
+	return prog_inv_sh_nm_buf;
+}
+# endif
+#endif
+
+
+#ifndef HAVE_ERR_H
+static inline void
+errmsg(char doexit, int excode, char adderr, const char *fmt, ...)
+{
+	fprintf(stderr, "%s: ", program_invocation_short_name);
+	if (fmt != NULL) {
+		va_list argp;
+		va_start(argp, fmt);
+		vfprintf(stderr, fmt, argp);
+		va_end(argp);
+		if (adderr)
+			fprintf(stderr, ": ");
+	}
+	if (adderr)
+		fprintf(stderr, "%m");
+	fprintf(stderr, "\n");
+	if (doexit)
+		exit(excode);
+}
+
+#ifndef HAVE_ERR
+# define err(E, FMT...) errmsg(1, E, 1, FMT)
+#endif
+
+#ifndef HAVE_ERRX
+# define errx(E, FMT...) errmsg(1, E, 0, FMT)
+#endif
+
+#ifndef HAVE_WARN
+# define warn(FMT...) errmsg(0, 0, 1, FMT)
+#endif
+
+#ifndef HAVE_WARNX
+# define warnx(FMT...) errmsg(0, 0, 0, FMT)
+#endif
+#endif /* !HAVE_ERR_H */
+
+
+static inline __attribute__((const)) int is_power_of_2(unsigned long num)
+{
+	return (num != 0 && ((num & (num - 1)) == 0));
+}
+
+#ifndef HAVE_LOFF_T
+typedef int64_t loff_t;
+#endif
+
+#if !defined(HAVE_DIRFD) && (!defined(HAVE_DECL_DIRFD) || HAVE_DECL_DIRFD == 0) && defined(HAVE_DIR_DD_FD)
+#include <sys/types.h>
+#include <dirent.h>
+static inline int dirfd(DIR *d)
+{
+	return d->dd_fd;
+}
+#endif
+
+/*
+ * Fallback defines for old versions of glibc
+ */
+#include <fcntl.h>
+
+#ifdef O_CLOEXEC
+#define UL_CLOEXECSTR   "e"
+#else
+#define UL_CLOEXECSTR   ""
+#endif
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+#ifndef AI_ADDRCONFIG
+#define AI_ADDRCONFIG 0x0020
+#endif
+
+#ifndef IUTF8
+#define IUTF8 0040000
+#endif
+
+/*
+ * MAXHOSTNAMELEN replacement
+ */
+static inline size_t get_hostname_max(void)
+{
+	long len = sysconf(255);
+
+	if (0 < len)
+		return len;
+
+#ifdef MAXHOSTNAMELEN
+	return MAXHOSTNAMELEN;
+#elif HOST_NAME_MAX
+	return HOST_NAME_MAX;
+#endif
+	return 64;
+}
+
+/*
+ * Constant strings for usage() functions. For more info see
+ * Documentation/howto-usage-function.txt and sys-utils/arch.c
+ */
+#define USAGE_HEADER     _("\nUsage:\n")
+#define USAGE_OPTIONS    _("\nOptions:\n")
+#define USAGE_SEPARATOR  _("\n")
+#define USAGE_HELP       _(" -h, --help     display this help and exit\n")
+#define USAGE_VERSION    _(" -V, --version  output version information and exit\n")
+#define USAGE_MAN_TAIL(_man)   _("\nFor more details see %s.\n"), _man
+
+#define UTIL_LINUX_VERSION _("%s from %s\n"), program_invocation_short_name, PACKAGE_STRING
+
+/*
+ * scanf modifiers for "strings allocation"
+ */
+#ifdef HAVE_SCANF_MS_MODIFIER
+#define UL_SCNsA	"%ms"
+#elif defined(HAVE_SCANF_AS_MODIFIER)
+#define UL_SCNsA	"%as"
+#endif
+
+/*
+ * seek stuff
+ */
+#ifndef SEEK_DATA
+# define SEEK_DATA	3
+#endif
+#ifndef SEEK_HOLE
+# define SEEK_HOLE	4
+#endif
+
+#endif /* UTIL_LINUX_C_H */
diff --git a/libblkid/src/cache.c b/libblkid/src/cache.c
new file mode 100644
index 0000000..b576df8
--- /dev/null
+++ b/libblkid/src/cache.c
@@ -0,0 +1,226 @@
+/*
+ * cache.c - allocation/initialization/free routines for cache
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "blkidP.h"
+#include "env.h"
+
+/**
+ * SECTION:cache
+ * @title: Cache
+ * @short_description: basic routines to work with libblkid cache
+ *
+ * Block device information is normally kept in a cache file blkid.tab and is
+ * verified to still be valid before being returned to the user (if the user has
+ * read permission on the raw block device, otherwise not).  The cache file also
+ * allows unprivileged users (normally anyone other than root, or those not in the
+ * "disk" group) to locate devices by label/id.  The standard location of the
+ * cache file can be overridden by the environment variable BLKID_FILE.
+ *
+ * In situations where one is getting information about a single known device, it
+ * does not impact performance whether the cache is used or not (unless you are
+ * not able to read the block device directly).  If you are dealing with multiple
+ * devices, use of the cache is highly recommended (even if empty) as devices will
+ * be scanned at most one time and the on-disk cache will be updated if possible.
+ * There is rarely a reason not to use the cache.
+ *
+ * In some cases (modular kernels), block devices are not even visible until after
+ * they are accessed the first time, so it is critical that there is some way to
+ * locate these devices without enumerating only visible devices, so the use of
+ * the cache file is required in this situation.
+ */
+static const char *get_default_cache_filename(void)
+{
+	struct stat st;
+
+	if (stat(BLKID_RUNTIME_TOPDIR, &st) == 0 && S_ISDIR(st.st_mode))
+		return BLKID_CACHE_FILE;	/* cache in /run */
+
+	return BLKID_CACHE_FILE_OLD;	/* cache in /etc */
+}
+
+/* returns allocated path to cache */
+char *blkid_get_cache_filename(struct blkid_config *conf)
+{
+	char *filename;
+
+	filename = safe_getenv("BLKID_FILE");
+	if (filename)
+		filename = strdup(filename);
+	else if (conf)
+		filename = conf->cachefile ? strdup(conf->cachefile) : NULL;
+	else {
+		struct blkid_config *c = blkid_read_config(NULL);
+		if (!c)
+			filename = strdup(get_default_cache_filename());
+		else {
+			filename = c->cachefile;  /* already allocated */
+			c->cachefile = NULL;
+			blkid_free_config(c);
+		}
+	}
+	return filename;
+}
+
+/**
+ * blkid_get_cache:
+ * @cache: pointer to return cache handler
+ * @filename: path to the cache file or NULL for the default path
+ *
+ * Allocates and initialize librray cache handler.
+ *
+ * Returns: 0 on success or number less than zero in case of error.
+ */
+int blkid_get_cache(blkid_cache *ret_cache, const char *filename)
+{
+	blkid_cache cache;
+
+	if (!ret_cache)
+		return -BLKID_ERR_PARAM;
+
+	blkid_init_debug(0);
+
+	DBG(CACHE, ul_debug("creating blkid cache (using %s)",
+				filename ? filename : "default cache"));
+
+	if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache))))
+		return -BLKID_ERR_MEM;
+
+	INIT_LIST_HEAD(&cache->bic_devs);
+	INIT_LIST_HEAD(&cache->bic_tags);
+
+	if (filename && !*filename)
+		filename = NULL;
+	if (filename)
+		cache->bic_filename = strdup(filename);
+	else
+		cache->bic_filename = blkid_get_cache_filename(NULL);
+
+	blkid_read_cache(cache);
+	*ret_cache = cache;
+	return 0;
+}
+
+/**
+ * blkid_put_cache:
+ * @cache: cache handler
+ *
+ * Saves changes to cache file.
+ */
+void blkid_put_cache(blkid_cache cache)
+{
+	if (!cache)
+		return;
+
+	(void) blkid_flush_cache(cache);
+
+	DBG(CACHE, ul_debug("freeing cache struct"));
+
+	/* DBG(CACHE, ul_debug_dump_cache(cache)); */
+
+	while (!list_empty(&cache->bic_devs)) {
+		blkid_dev dev = list_entry(cache->bic_devs.next,
+					   struct blkid_struct_dev,
+					    bid_devs);
+		blkid_free_dev(dev);
+	}
+
+	while (!list_empty(&cache->bic_tags)) {
+		blkid_tag tag = list_entry(cache->bic_tags.next,
+					   struct blkid_struct_tag,
+					   bit_tags);
+
+		while (!list_empty(&tag->bit_names)) {
+			blkid_tag bad = list_entry(tag->bit_names.next,
+						   struct blkid_struct_tag,
+						   bit_names);
+
+			DBG(CACHE, ul_debug("warning: unfreed tag %s=%s",
+						bad->bit_name, bad->bit_val));
+			blkid_free_tag(bad);
+		}
+		blkid_free_tag(tag);
+	}
+
+	blkid_free_probe(cache->probe);
+
+	free(cache->bic_filename);
+	free(cache);
+}
+
+/**
+ * blkid_gc_cache:
+ * @cache: cache handler
+ *
+ * Removes garbage (non-existing devices) from the cache.
+ */
+void blkid_gc_cache(blkid_cache cache)
+{
+	struct list_head *p, *pnext;
+	struct stat st;
+
+	if (!cache)
+		return;
+
+	list_for_each_safe(p, pnext, &cache->bic_devs) {
+		blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
+		if (stat(dev->bid_name, &st) < 0) {
+			DBG(CACHE, ul_debug("freeing %s", dev->bid_name));
+			blkid_free_dev(dev);
+			cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+		} else {
+			DBG(CACHE, ul_debug("Device %s exists", dev->bid_name));
+		}
+	}
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char** argv)
+{
+	blkid_cache cache = NULL;
+	int ret;
+
+	blkid_init_debug(BLKID_DEBUG_ALL);
+
+	if ((argc > 2)) {
+		fprintf(stderr, "Usage: %s [filename] \n", argv[0]);
+		exit(1);
+	}
+
+	if ((ret = blkid_get_cache(&cache, argv[1])) < 0) {
+		fprintf(stderr, "error %d parsing cache file %s\n", ret,
+			argv[1] ? argv[1] : blkid_get_cache_filename(NULL));
+		exit(1);
+	}
+	if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
+		fprintf(stderr, "%s: error creating cache (%d)\n",
+			argv[0], ret);
+		exit(1);
+	}
+	if ((ret = blkid_probe_all(cache)) < 0)
+		fprintf(stderr, "error probing devices\n");
+
+	blkid_put_cache(cache);
+
+	return ret;
+}
+#endif
diff --git a/libblkid/src/canonicalize.h b/libblkid/src/canonicalize.h
new file mode 100644
index 0000000..7a18aca
--- /dev/null
+++ b/libblkid/src/canonicalize.h
@@ -0,0 +1,21 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library Public License for more details.
+ */
+#ifndef CANONICALIZE_H
+#define CANONICALIZE_H
+
+#include "c.h"	/* for PATH_MAX */
+
+extern char *canonicalize_path(const char *path);
+extern char *canonicalize_path_restricted(const char *path);
+extern char *canonicalize_dm_name(const char *ptname);
+
+#endif /* CANONICALIZE_H */
diff --git a/libblkid/src/closestream.h b/libblkid/src/closestream.h
new file mode 100644
index 0000000..7842456
--- /dev/null
+++ b/libblkid/src/closestream.h
@@ -0,0 +1,71 @@
+#ifndef UTIL_LINUX_CLOSESTREAM_H
+#define UTIL_LINUX_CLOSESTREAM_H
+
+#include <stdio.h>
+#ifdef HAVE_STDIO_EXT_H
+#include <stdio_ext.h>
+#endif
+#include <unistd.h>
+
+#include "c.h"
+#include "nls.h"
+
+#ifndef HAVE___FPENDING
+static inline int
+__fpending(FILE *stream __attribute__((__unused__)))
+{
+	return 0;
+}
+#endif
+
+static inline int
+close_stream(FILE * stream)
+{
+	const int some_pending = (__fpending(stream) != 0);
+	const int prev_fail = (ferror(stream) != 0);
+	const int fclose_fail = (fclose(stream) != 0);
+
+	if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) {
+		if (!fclose_fail && !(errno == EPIPE))
+			errno = 0;
+		return EOF;
+	}
+	return 0;
+}
+
+/* Meant to be used atexit(close_stdout); */
+static inline void
+close_stdout(void)
+{
+	if (close_stream(stdout) != 0 && !(errno == EPIPE)) {
+		if (errno)
+			warn(_("write error"));
+		else
+			warnx(_("write error"));
+		_exit(EXIT_FAILURE);
+	}
+
+	if (close_stream(stderr) != 0)
+		_exit(EXIT_FAILURE);
+}
+
+#ifndef HAVE_FSYNC
+static inline int
+fsync(int fd __attribute__((__unused__)))
+{
+	return 0;
+}
+#endif
+
+static inline int
+close_fd(int fd)
+{
+	const int fsync_fail = (fsync(fd) != 0);
+	const int close_fail = (close(fd) != 0);
+
+	if (fsync_fail || close_fail)
+		return EOF;
+	return 0;
+}
+
+#endif /* UTIL_LINUX_CLOSESTREAM_H */
diff --git a/libblkid/src/colors.h b/libblkid/src/colors.h
new file mode 100644
index 0000000..97efc48
--- /dev/null
+++ b/libblkid/src/colors.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_COLORS_H
+#define UTIL_LINUX_COLORS_H
+
+#include <stdio.h>
+#include <unistd.h>
+
+#define UL_COLOR_RESET		"\033[0m"
+#define UL_COLOR_BOLD		"\033[1m"
+#define UL_COLOR_HALFBRIGHT	"\033[2m"
+#define UL_COLOR_UNDERSCORE	"\033[4m"
+#define UL_COLOR_BLINK		"\033[5m"
+#define UL_COLOR_REVERSE	"\033[7m"
+
+/* Standard colors */
+#define UL_COLOR_BLACK		"\033[30m"
+#define UL_COLOR_RED		"\033[31m"
+#define UL_COLOR_GREEN		"\033[32m"
+#define UL_COLOR_BROWN		"\033[33m"	/* well, brown */
+#define UL_COLOR_BLUE		"\033[34m"
+#define UL_COLOR_MAGENTA	"\033[35m"
+#define UL_COLOR_CYAN		"\033[36m"
+#define UL_COLOR_GRAY		"\033[37m"
+
+/* Bold variants */
+#define UL_COLOR_DARK_GRAY	"\033[1;30m"
+#define UL_COLOR_BOLD_RED	"\033[1;31m"
+#define UL_COLOR_BOLD_GREEN	"\033[1;32m"
+#define UL_COLOR_BOLD_YELLOW	"\033[1;33m"
+#define UL_COLOR_BOLD_BLUE	"\033[1;34m"
+#define UL_COLOR_BOLD_MAGENTA	"\033[1;35m"
+#define UL_COLOR_BOLD_CYAN	"\033[1;36m"
+
+#define UL_COLOR_WHITE		"\033[1;37m"
+
+/* --color[=WHEN] */
+enum colortmode {
+	UL_COLORMODE_AUTO = 0,
+	UL_COLORMODE_NEVER,
+	UL_COLORMODE_ALWAYS,
+	UL_COLORMODE_UNDEF,
+
+	__UL_NCOLORMODES	/* last */
+};
+
+extern int colormode_from_string(const char *str);
+extern int colormode_or_err(const char *str, const char *errmsg);
+
+/* Initialize the global variable UL_COLOR_TERM_OK */
+extern int colors_init(int mode, const char *util_name);
+
+/* Returns 1 or 0 */
+extern int colors_wanted(void);
+
+/* temporary enable/disable colors */
+extern void colors_off(void);
+extern void colors_on(void);
+
+
+/* Set the color */
+extern void color_fenable(const char *seq, FILE *f);
+
+extern void color_scheme_fenable(const char *name, const char *dflt, FILE *f);
+extern const char *color_scheme_get_sequence(const char *name, const char *dflt);
+
+static inline void color_enable(const char *seq)
+{
+	color_fenable(seq, stdout);
+}
+
+static inline void color_scheme_enable(const char *name, const char *dflt)
+{
+	color_scheme_fenable(name, dflt, stdout);
+}
+
+/* Reset colors to default */
+extern void color_fdisable(FILE *f);
+
+static inline void color_disable(void)
+{
+	color_fdisable(stdout);
+}
+
+/* converts "red" to UL_COLOR_RED, etc. */
+extern const char *color_sequence_from_colorname(const char *str);
+
+
+#endif /* UTIL_LINUX_COLORS_H */
diff --git a/libblkid/src/config.c b/libblkid/src/config.c
new file mode 100644
index 0000000..3c7f312
--- /dev/null
+++ b/libblkid/src/config.c
@@ -0,0 +1,198 @@
+/*
+ * config.c - blkid.conf routines
+ *
+ * Copyright (C) 2009 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_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "blkidP.h"
+#include "env.h"
+
+static int parse_evaluate(struct blkid_config *conf, char *s)
+{
+	while(s && *s) {
+		char *sep;
+
+		if (conf->nevals >= __BLKID_EVAL_LAST)
+			goto err;
+		sep = strchr(s, ',');
+		if (sep)
+			*sep = '\0';
+		if (strcmp(s, "udev") == 0)
+			conf->eval[conf->nevals] = BLKID_EVAL_UDEV;
+		else if (strcmp(s, "scan") == 0)
+			conf->eval[conf->nevals] = BLKID_EVAL_SCAN;
+		else
+			goto err;
+		conf->nevals++;
+		if (sep)
+			s = sep + 1;
+		else
+			break;
+	}
+	return 0;
+err:
+	DBG(CONFIG, ul_debug(
+		"config file: unknown evaluation method '%s'.", s));
+	return -1;
+}
+
+static int parse_next(FILE *fd, struct blkid_config *conf)
+{
+	char buf[BUFSIZ];
+	char *s;
+
+	/* read the next non-blank non-comment line */
+	do {
+		if (fgets (buf, sizeof(buf), fd) == NULL)
+			return feof(fd) ? 0 : -1;
+		s = strchr (buf, '\n');
+		if (!s) {
+			/* Missing final newline?  Otherwise extremely */
+			/* long line - assume file was corrupted */
+			if (feof(fd))
+				s = strchr (buf, '\0');
+			else {
+				DBG(CONFIG, ul_debug(
+					"config file: missing newline at line '%s'.",
+					buf));
+				return -1;
+			}
+		}
+		*s = '\0';
+		if (--s >= buf && *s == '\r')
+			*s = '\0';
+
+		s = buf;
+		while (*s == ' ' || *s == '\t')		/* skip space */
+			s++;
+
+	} while (*s == '\0' || *s == '#');
+
+	if (!strncmp(s, "SEND_UEVENT=", 12)) {
+		s += 13;
+		if (*s && !strcasecmp(s, "yes"))
+			conf->uevent = TRUE;
+		else if (*s)
+			conf->uevent = FALSE;
+	} else if (!strncmp(s, "CACHE_FILE=", 11)) {
+		s += 11;
+		if (*s)
+			conf->cachefile = strdup(s);
+	} else if (!strncmp(s, "EVALUATE=", 9)) {
+		s += 9;
+		if (*s && parse_evaluate(conf, s) == -1)
+			return -1;
+	} else {
+		DBG(CONFIG, ul_debug(
+			"config file: unknown option '%s'.", s));
+		return -1;
+	}
+	return 0;
+}
+
+/* return real config data or built-in default */
+struct blkid_config *blkid_read_config(const char *filename)
+{
+	struct blkid_config *conf;
+	FILE *f;
+
+	if (!filename)
+		filename = safe_getenv("BLKID_CONF");
+	if (!filename)
+		filename = BLKID_CONFIG_FILE;
+
+	conf = (struct blkid_config *) calloc(1, sizeof(*conf));
+	if (!conf)
+		return NULL;
+	conf->uevent = -1;
+
+	DBG(CONFIG, ul_debug("reading config file: %s.", filename));
+
+	f = fopen(filename, "r" UL_CLOEXECSTR);
+	if (!f) {
+		DBG(CONFIG, ul_debug("%s: does not exist, using built-in default", filename));
+		goto dflt;
+	}
+	while (!feof(f)) {
+		if (parse_next(f, conf)) {
+			DBG(CONFIG, ul_debug("%s: parse error", filename));
+			goto err;
+		}
+	}
+dflt:
+	if (!conf->nevals) {
+		conf->eval[0] = BLKID_EVAL_UDEV;
+		conf->eval[1] = BLKID_EVAL_SCAN;
+		conf->nevals = 2;
+	}
+	if (!conf->cachefile)
+		conf->cachefile = strdup(BLKID_CACHE_FILE);
+	if (conf->uevent == -1)
+		conf->uevent = TRUE;
+	if (f)
+		fclose(f);
+	return conf;
+err:
+	free(conf);
+	fclose(f);
+	return NULL;
+}
+
+void blkid_free_config(struct blkid_config *conf)
+{
+	if (!conf)
+		return;
+	free(conf->cachefile);
+	free(conf);
+}
+
+#ifdef TEST_PROGRAM
+/*
+ * usage: tst_config [<filename>]
+ */
+int main(int argc, char *argv[])
+{
+	int i;
+	struct blkid_config *conf;
+	char *filename = NULL;
+
+	blkid_init_debug(BLKID_DEBUG_ALL);
+
+	if (argc == 2)
+		filename = argv[1];
+
+	conf = blkid_read_config(filename);
+	if (!conf)
+		return EXIT_FAILURE;
+
+	printf("EVALUATE:    ");
+	for (i = 0; i < conf->nevals; i++)
+		printf("%s ", conf->eval[i] == BLKID_EVAL_UDEV ? "udev" : "scan");
+	printf("\n");
+
+	printf("SEND UEVENT: %s\n", conf->uevent ? "TRUE" : "FALSE");
+	printf("CACHE_FILE:  %s\n", conf->cachefile);
+
+	blkid_free_config(conf);
+	return EXIT_SUCCESS;
+}
+#endif
diff --git a/libblkid/src/crc32.h b/libblkid/src/crc32.h
new file mode 100644
index 0000000..2616910
--- /dev/null
+++ b/libblkid/src/crc32.h
@@ -0,0 +1,10 @@
+#ifndef UL_NG_CRC32_H
+#define UL_NG_CRC32_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+extern uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len);
+
+#endif
+
diff --git a/libblkid/src/debug.h b/libblkid/src/debug.h
new file mode 100644
index 0000000..0229ab3
--- /dev/null
+++ b/libblkid/src/debug.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_DEBUG_H
+#define UTIL_LINUX_DEBUG_H
+
+
+/*
+ * util-linux debug macros
+ *
+ * The debug stuff is based on <name>_debug_mask that controls what outputs is
+ * expected. The mask is usually initialized by <NAME>_DEBUG= env.variable
+ *
+ * After successful initialization the flag <PREFIX>_DEBUG_INIT is always set
+ * to the mask (this flag is required). The <PREFIX> is usually library API
+ * prefix (e.g. MNT_) or program name (e.g. CFDISK_)
+ *
+ * In the code is possible to use
+ *
+ *	DBG(FOO, ul_debug("this is output for foo"));
+ *
+ * where for the FOO has to be defined <PREFIX>_DEBUG_FOO.
+ *
+ * It's possible to initialize the mask by comma delimited strings with
+ * subsystem names (e.g. "LIBMOUNT_DEBUG=options,tab"). In this case is
+ * necessary to define mask names array. This functionality is optional.
+ *
+ * It's stringly recommended to use UL_* macros to define/declare/use
+ * the debug stuff.
+ *
+ * See disk-utils/cfdisk.c: cfdisk_init_debug()  for programs debug
+ *  or libmount/src/init.c: mnt_init_debug()     for library debug
+ *
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+struct ul_debug_maskname {
+	const char *name;
+	int mask;
+	const char *help;
+};
+#define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0, NULL }}
+#define UL_DEBUG_DEFINE_MASKNAMES(m) static const struct ul_debug_maskname m ## _masknames[]
+#define UL_DEBUG_MASKNAMES(m)	m ## _masknames
+
+#define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask
+#define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m)
+
+/* p - flag prefix, m - flag postfix */
+#define UL_DEBUG_DEFINE_FLAG(p, m) p ## m
+
+/* l - library name, p - flag prefix, m - flag postfix, x - function */
+#define __UL_DBG(l, p, m, x) \
+	do { \
+		if ((p ## m) & l ## _debug_mask) { \
+			fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \
+			x; \
+		} \
+	} while (0)
+
+#define __UL_DBG_CALL(l, p, m, x) \
+	do { \
+		if ((p ## m) & l ## _debug_mask) { \
+			x; \
+		} \
+	} while (0)
+
+#define __UL_DBG_FLUSH(l, p) \
+	do { \
+		if (l ## _debug_mask && \
+		    l ## _debug_mask != p ## INIT) { \
+			fflush(stderr); \
+		} \
+	} while (0)
+
+
+#define __UL_INIT_DEBUG(lib, pref, mask, env) \
+	do { \
+		if (lib ## _debug_mask & pref ## INIT) \
+		; \
+		else if (!mask) { \
+			char *str = getenv(# env); \
+			if (str) \
+				lib ## _debug_mask = ul_debug_parse_envmask(lib ## _masknames, str); \
+		} else \
+			lib ## _debug_mask = mask; \
+		lib ## _debug_mask |= pref ## INIT; \
+	} while (0)
+
+
+static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
+ul_debug(const char *mesg, ...)
+{
+	va_list ap;
+	va_start(ap, mesg);
+	vfprintf(stderr, mesg, ap);
+	va_end(ap);
+	fputc('\n', stderr);
+}
+
+static inline void __attribute__ ((__format__ (__printf__, 2, 3)))
+ul_debugobj(void *handler, const char *mesg, ...)
+{
+	va_list ap;
+
+	if (handler)
+		fprintf(stderr, "[%p]: ", handler);
+	va_start(ap, mesg);
+	vfprintf(stderr, mesg, ap);
+	va_end(ap);
+	fputc('\n', stderr);
+}
+
+static inline int ul_debug_parse_envmask(
+			const struct ul_debug_maskname flagnames[],
+			const char *mask)
+{
+	int res;
+	char *ptr;
+
+	/* let's check for a numeric mask first */
+	res = strtoul(mask, &ptr, 0);
+
+	/* perhaps it's a comma-separated string? */
+	if (ptr && *ptr && flagnames && flagnames[0].name) {
+		char *msbuf, *ms, *name;
+		res = 0;
+
+		ms = msbuf = strdup(mask);
+		if (!ms)
+			return res;
+
+		while ((name = strtok_r(ms, ",", &ptr))) {
+			const struct ul_debug_maskname *d;
+			ms = ptr;
+
+			for (d = flagnames; d && d->name; d++) {
+				if (strcmp(name, d->name) == 0) {
+					res |= d->mask;
+					break;
+				}
+			}
+			/* nothing else we can do by OR-ing the mask */
+			if (res == 0xffff)
+				break;
+		}
+		free(msbuf);
+	} else if (ptr && strcmp(ptr, "all") == 0)
+		res = 0xffff;
+
+	return res;
+}
+
+static inline void ul_debug_print_masks(
+			const char *env,
+			const struct ul_debug_maskname flagnames[])
+{
+	const struct ul_debug_maskname *d;
+
+	if (!flagnames)
+		return;
+
+	fprintf(stderr, "Available \"%s=<name>[,...]|<mask>\" debug masks:\n",
+			env);
+	for (d = flagnames; d && d->name; d++) {
+		if (!d->help)
+			continue;
+		fprintf(stderr, "   %-8s [0x%04x] : %s\n",
+				d->name, d->mask, d->help);
+	}
+}
+
+#endif /* UTIL_LINUX_DEBUG_H */
diff --git a/libblkid/src/dev.c b/libblkid/src/dev.c
new file mode 100644
index 0000000..9491331
--- /dev/null
+++ b/libblkid/src/dev.c
@@ -0,0 +1,274 @@
+/*
+ * dev.c - allocation/initialization/free routines for dev
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "blkidP.h"
+
+/*
+ * NOTE: reference manual is not structured as code. The following section is a generic
+ * section for all high-level cache search+iterate routines.
+ */
+
+/**
+ * SECTION:search
+ * @title: Search and iterate
+ * @short_description: search devices and iterate over devices in the cache.
+ *
+ * Note that high-level probing API provides information about superblocks
+ * (filesystems/raids) only.  For partitions and topology is necessary to use
+ * the low-level API.
+ */
+
+blkid_dev blkid_new_dev(void)
+{
+	blkid_dev dev;
+
+	if (!(dev = (blkid_dev) calloc(1, sizeof(struct blkid_struct_dev))))
+		return NULL;
+
+	INIT_LIST_HEAD(&dev->bid_devs);
+	INIT_LIST_HEAD(&dev->bid_tags);
+
+	return dev;
+}
+
+void blkid_free_dev(blkid_dev dev)
+{
+	if (!dev)
+		return;
+
+	DBG(DEV,
+	    ul_debug("  freeing dev %s (%s)", dev->bid_name, dev->bid_type ?
+		   dev->bid_type : "(null)"));
+	DBG(DEV, blkid_debug_dump_dev(dev));
+
+	list_del(&dev->bid_devs);
+	while (!list_empty(&dev->bid_tags)) {
+		blkid_tag tag = list_entry(dev->bid_tags.next,
+					   struct blkid_struct_tag,
+					   bit_tags);
+		blkid_free_tag(tag);
+	}
+	free(dev->bid_name);
+	free(dev);
+}
+
+/*
+ * Given a blkid device, return its name
+ */
+const char *blkid_dev_devname(blkid_dev dev)
+{
+	return dev ? dev->bid_name : NULL;
+}
+
+void blkid_debug_dump_dev(blkid_dev dev)
+{
+	struct list_head *p;
+
+	if (!dev) {
+		printf("  dev: NULL\n");
+		return;
+	}
+
+	fprintf(stderr, "  dev: name = %s\n", dev->bid_name);
+	fprintf(stderr, "  dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno);
+	fprintf(stderr, "  dev: TIME=\"%ld.%ld\"\n", (long)dev->bid_time, (long)dev->bid_utime);
+	fprintf(stderr, "  dev: PRI=\"%d\"\n", dev->bid_pri);
+	fprintf(stderr, "  dev: flags = 0x%08X\n", dev->bid_flags);
+
+	list_for_each(p, &dev->bid_tags) {
+		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
+		if (tag)
+			fprintf(stderr, "    tag: %s=\"%s\"\n", tag->bit_name,
+			       tag->bit_val);
+		else
+			fprintf(stderr, "    tag: NULL\n");
+	}
+}
+
+/*
+ * dev iteration routines for the public libblkid interface.
+ *
+ * These routines do not expose the list.h implementation, which are a
+ * contamination of the namespace, and which force us to reveal far, far
+ * too much of our internal implemenation.  I'm not convinced I want
+ * to keep list.h in the long term, anyway.  It's fine for kernel
+ * programming, but performance is not the #1 priority for this
+ * library, and I really don't like the tradeoff of type-safety for
+ * performance for this application.  [tytso:20030125.2007EST]
+ */
+
+/*
+ * This series of functions iterate over all devices in a blkid cache
+ */
+#define DEV_ITERATE_MAGIC	0x01a5284c
+
+struct blkid_struct_dev_iterate {
+	int			magic;
+	blkid_cache		cache;
+	char			*search_type;
+	char			*search_value;
+	struct list_head	*p;
+};
+
+blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
+{
+	blkid_dev_iterate iter;
+
+	if (!cache) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	iter = malloc(sizeof(struct blkid_struct_dev_iterate));
+	if (iter) {
+		iter->magic = DEV_ITERATE_MAGIC;
+		iter->cache = cache;
+		iter->p	= cache->bic_devs.next;
+		iter->search_type = 0;
+		iter->search_value = 0;
+	}
+	return iter;
+}
+
+int blkid_dev_set_search(blkid_dev_iterate iter,
+				 char *search_type, char *search_value)
+{
+	char *new_type, *new_value;
+
+	if (!iter || iter->magic != DEV_ITERATE_MAGIC || !search_type ||
+	    !search_value)
+		return -1;
+	new_type = malloc(strlen(search_type)+1);
+	new_value = malloc(strlen(search_value)+1);
+	if (!new_type || !new_value) {
+		free(new_type);
+		free(new_value);
+		return -1;
+	}
+	strcpy(new_type, search_type);
+	strcpy(new_value, search_value);
+	free(iter->search_type);
+	free(iter->search_value);
+	iter->search_type = new_type;
+	iter->search_value = new_value;
+	return 0;
+}
+
+/*
+ * Return 0 on success, -1 on error
+ */
+int blkid_dev_next(blkid_dev_iterate iter,
+			  blkid_dev *ret_dev)
+{
+	blkid_dev		dev;
+
+	if  (!ret_dev || !iter || iter->magic != DEV_ITERATE_MAGIC)
+		return -1;
+	*ret_dev = 0;
+	while (iter->p != &iter->cache->bic_devs) {
+		dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs);
+		iter->p = iter->p->next;
+		if (iter->search_type &&
+		    !blkid_dev_has_tag(dev, iter->search_type,
+				       iter->search_value))
+			continue;
+		*ret_dev = dev;
+		return 0;
+	}
+	return -1;
+}
+
+void blkid_dev_iterate_end(blkid_dev_iterate iter)
+{
+	if (!iter || iter->magic != DEV_ITERATE_MAGIC)
+		return;
+	iter->magic = 0;
+	free(iter->search_type);
+	free(iter->search_value);
+	free(iter);
+}
+
+#ifdef TEST_PROGRAM
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+
+void __attribute__((__noreturn__)) usage(char *prog)
+{
+	fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog);
+	fprintf(stderr, "\tList all devices and exit\n");
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	blkid_dev_iterate	iter;
+	blkid_cache 		cache = NULL;
+	blkid_dev		dev;
+	int			c, ret;
+	char			*tmp;
+	char			*file = NULL;
+	char			*search_type = NULL;
+	char			*search_value = NULL;
+
+	while ((c = getopt (argc, argv, "m:f:")) != EOF)
+		switch (c) {
+		case 'f':
+			file = optarg;
+			break;
+		case 'm':
+		{
+			int mask = strtoul (optarg, &tmp, 0);
+			if (*tmp) {
+				fprintf(stderr, "Invalid debug mask: %s\n",
+					optarg);
+				exit(1);
+			}
+			blkid_init_debug(mask);
+			break;
+		}
+		case '?':
+			usage(argv[0]);
+		}
+	if (argc >= optind+2) {
+		search_type = argv[optind];
+		search_value = argv[optind+1];
+		optind += 2;
+	}
+	if (argc != optind)
+		usage(argv[0]);
+
+	if ((ret = blkid_get_cache(&cache, file)) != 0) {
+		fprintf(stderr, "%s: error creating cache (%d)\n",
+			argv[0], ret);
+		exit(1);
+	}
+
+	iter = blkid_dev_iterate_begin(cache);
+	if (search_type)
+		blkid_dev_set_search(iter, search_type, search_value);
+	while (blkid_dev_next(iter, &dev) == 0) {
+		printf("Device: %s\n", blkid_dev_devname(dev));
+	}
+	blkid_dev_iterate_end(iter);
+
+
+	blkid_put_cache(cache);
+	return (0);
+}
+#endif
diff --git a/libblkid/src/devname.c b/libblkid/src/devname.c
new file mode 100644
index 0000000..fdbb5c9
--- /dev/null
+++ b/libblkid/src/devname.c
@@ -0,0 +1,675 @@
+/*
+ * devname.c - get a dev by its device inode name
+ *
+ * Copyright (C) Andries Brouwer
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o
+ * Copyright (C) 2001 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <dirent.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <time.h>
+
+#include "blkidP.h"
+
+#include "canonicalize.h"		/* $(top_srcdir)/include */
+#include "pathnames.h"
+#include "sysfs.h"
+#include "at.h"
+
+/*
+ * Find a dev struct in the cache by device name, if available.
+ *
+ * If there is no entry with the specified device name, and the create
+ * flag is set, then create an empty device entry.
+ */
+blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags)
+{
+	blkid_dev dev = NULL, tmp;
+	struct list_head *p, *pnext;
+
+	if (!cache || !devname)
+		return NULL;
+
+	list_for_each(p, &cache->bic_devs) {
+		tmp = list_entry(p, struct blkid_struct_dev, bid_devs);
+		if (strcmp(tmp->bid_name, devname))
+			continue;
+
+		DBG(DEVNAME, ul_debug("found devname %s in cache", tmp->bid_name));
+		dev = tmp;
+		break;
+	}
+
+	if (!dev && (flags & BLKID_DEV_CREATE)) {
+		if (access(devname, F_OK) < 0)
+			return NULL;
+		dev = blkid_new_dev();
+		if (!dev)
+			return NULL;
+		dev->bid_time = INT_MIN;
+		dev->bid_name = strdup(devname);
+		dev->bid_cache = cache;
+		list_add_tail(&dev->bid_devs, &cache->bic_devs);
+		cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+	}
+
+	if (flags & BLKID_DEV_VERIFY) {
+		dev = blkid_verify(cache, dev);
+		if (!dev || !(dev->bid_flags & BLKID_BID_FL_VERIFIED))
+			return dev;
+		/*
+		 * If the device is verified, then search the blkid
+		 * cache for any entries that match on the type, uuid,
+		 * and label, and verify them; if a cache entry can
+		 * not be verified, then it's stale and so we remove
+		 * it.
+		 */
+		list_for_each_safe(p, pnext, &cache->bic_devs) {
+			blkid_dev dev2 = list_entry(p, struct blkid_struct_dev, bid_devs);
+			if (dev2->bid_flags & BLKID_BID_FL_VERIFIED)
+				continue;
+			if (!dev->bid_type || !dev2->bid_type ||
+			    strcmp(dev->bid_type, dev2->bid_type))
+				continue;
+			if (dev->bid_label && dev2->bid_label &&
+			    strcmp(dev->bid_label, dev2->bid_label))
+				continue;
+			if (dev->bid_uuid && dev2->bid_uuid &&
+			    strcmp(dev->bid_uuid, dev2->bid_uuid))
+				continue;
+			if ((dev->bid_label && !dev2->bid_label) ||
+			    (!dev->bid_label && dev2->bid_label) ||
+			    (dev->bid_uuid && !dev2->bid_uuid) ||
+			    (!dev->bid_uuid && dev2->bid_uuid))
+				continue;
+			dev2 = blkid_verify(cache, dev2);
+			if (dev2 && !(dev2->bid_flags & BLKID_BID_FL_VERIFIED))
+				blkid_free_dev(dev2);
+		}
+	}
+	return dev;
+}
+
+/* Directories where we will try to search for device names */
+static const char *dirlist[] = { "/dev", "/devfs", "/devices", NULL };
+
+static int is_dm_leaf(const char *devname)
+{
+	struct dirent	*de, *d_de;
+	DIR		*dir, *d_dir;
+	char		path[256];
+	int		ret = 1;
+
+	if ((dir = opendir("/sys/block")) == NULL)
+		return 0;
+	while ((de = readdir(dir)) != NULL) {
+		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ||
+		    !strcmp(de->d_name, devname) ||
+		    strncmp(de->d_name, "dm-", 3) ||
+		    strlen(de->d_name) > sizeof(path)-32)
+			continue;
+		sprintf(path, "/sys/block/%s/slaves", de->d_name);
+		if ((d_dir = opendir(path)) == NULL)
+			continue;
+		while ((d_de = readdir(d_dir)) != NULL) {
+			if (!strcmp(d_de->d_name, devname)) {
+				ret = 0;
+				break;
+			}
+		}
+		closedir(d_dir);
+		if (!ret)
+			break;
+	}
+	closedir(dir);
+	return ret;
+}
+
+/*
+ * Probe a single block device to add to the device cache.
+ */
+static void probe_one(blkid_cache cache, const char *ptname,
+		      dev_t devno, int pri, int only_if_new, int removable)
+{
+	blkid_dev dev = NULL;
+	struct list_head *p, *pnext;
+	const char **dir;
+	char *devname = NULL;
+
+	/* See if we already have this device number in the cache. */
+	list_for_each_safe(p, pnext, &cache->bic_devs) {
+		blkid_dev tmp = list_entry(p, struct blkid_struct_dev,
+					   bid_devs);
+		if (tmp->bid_devno == devno) {
+			if (only_if_new && !access(tmp->bid_name, F_OK))
+				return;
+			dev = blkid_verify(cache, tmp);
+			if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))
+				break;
+			dev = 0;
+		}
+	}
+	if (dev && dev->bid_devno == devno)
+		goto set_pri;
+
+	/* Try to translate private device-mapper dm-<N> names
+	 * to standard /dev/mapper/<name>.
+	 */
+	if (!strncmp(ptname, "dm-", 3) && isdigit(ptname[3])) {
+		devname = canonicalize_dm_name(ptname);
+		if (!devname)
+			blkid__scan_dir("/dev/mapper", devno, 0, &devname);
+		if (devname)
+			goto get_dev;
+	}
+
+	/*
+	 * Take a quick look at /dev/ptname for the device number.  We check
+	 * all of the likely device directories.  If we don't find it, or if
+	 * the stat information doesn't check out, use blkid_devno_to_devname()
+	 * to find it via an exhaustive search for the device major/minor.
+	 */
+	for (dir = dirlist; *dir; dir++) {
+		struct stat st;
+		char device[256];
+
+		snprintf(device, sizeof(device), "%s/%s", *dir, ptname);
+		if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) &&
+		    dev->bid_devno == devno)
+			goto set_pri;
+
+		if (stat(device, &st) == 0 &&
+		    (S_ISBLK(st.st_mode) ||
+		     (S_ISCHR(st.st_mode) && !strncmp(ptname, "ubi", 3))) &&
+		    st.st_rdev == devno) {
+			devname = strdup(device);
+			goto get_dev;
+		}
+	}
+	/* Do a short-cut scan of /dev/mapper first */
+	if (!devname)
+		blkid__scan_dir("/dev/mapper", devno, 0, &devname);
+	if (!devname) {
+		devname = blkid_devno_to_devname(devno);
+		if (!devname)
+			return;
+	}
+
+get_dev:
+	dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL);
+	free(devname);
+
+set_pri:
+	if (dev) {
+		if (pri)
+			dev->bid_pri = pri;
+		else if (!strncmp(dev->bid_name, "/dev/mapper/", 11)) {
+			dev->bid_pri = BLKID_PRI_DM;
+			if (is_dm_leaf(ptname))
+				dev->bid_pri += 5;
+		} else if (!strncmp(ptname, "md", 2))
+			dev->bid_pri = BLKID_PRI_MD;
+		if (removable)
+			dev->bid_flags |= BLKID_BID_FL_REMOVABLE;
+	}
+	return;
+}
+
+#define PROC_PARTITIONS "/proc/partitions"
+#define VG_DIR		"/proc/lvm/VGs"
+
+/*
+ * This function initializes the UUID cache with devices from the LVM
+ * proc hierarchy.  We currently depend on the names of the LVM
+ * hierarchy giving us the device structure in /dev.  (XXX is this a
+ * safe thing to do?)
+ */
+#ifdef VG_DIR
+static dev_t lvm_get_devno(const char *lvm_device)
+{
+	FILE *lvf;
+	char buf[1024];
+	int ma, mi;
+	dev_t ret = 0;
+
+	DBG(DEVNAME, ul_debug("opening %s", lvm_device));
+	if ((lvf = fopen(lvm_device, "r" UL_CLOEXECSTR)) == NULL) {
+		DBG(DEVNAME, ul_debug("%s: (%d) %m", lvm_device, errno));
+		return 0;
+	}
+
+	while (fgets(buf, sizeof(buf), lvf)) {
+		if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) {
+			ret = makedev(ma, mi);
+			break;
+		}
+	}
+	fclose(lvf);
+
+	return ret;
+}
+
+static void lvm_probe_all(blkid_cache cache, int only_if_new)
+{
+	DIR		*vg_list;
+	struct dirent	*vg_iter;
+	int		vg_len = strlen(VG_DIR);
+	dev_t		dev;
+
+	if ((vg_list = opendir(VG_DIR)) == NULL)
+		return;
+
+	DBG(DEVNAME, ul_debug("probing LVM devices under %s", VG_DIR));
+
+	while ((vg_iter = readdir(vg_list)) != NULL) {
+		DIR		*lv_list;
+		char		*vdirname;
+		char		*vg_name;
+		struct dirent	*lv_iter;
+
+		vg_name = vg_iter->d_name;
+		if (!strcmp(vg_name, ".") || !strcmp(vg_name, ".."))
+			continue;
+		vdirname = malloc(vg_len + strlen(vg_name) + 8);
+		if (!vdirname)
+			goto exit;
+		sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name);
+
+		lv_list = opendir(vdirname);
+		free(vdirname);
+		if (lv_list == NULL)
+			continue;
+
+		while ((lv_iter = readdir(lv_list)) != NULL) {
+			char		*lv_name, *lvm_device;
+
+			lv_name = lv_iter->d_name;
+			if (!strcmp(lv_name, ".") || !strcmp(lv_name, ".."))
+				continue;
+
+			lvm_device = malloc(vg_len + strlen(vg_name) +
+					    strlen(lv_name) + 8);
+			if (!lvm_device) {
+				closedir(lv_list);
+				goto exit;
+			}
+			sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name,
+				lv_name);
+			dev = lvm_get_devno(lvm_device);
+			sprintf(lvm_device, "%s/%s", vg_name, lv_name);
+			DBG(DEVNAME, ul_debug("LVM dev %s: devno 0x%04X",
+						  lvm_device,
+						  (unsigned int) dev));
+			probe_one(cache, lvm_device, dev, BLKID_PRI_LVM,
+				  only_if_new, 0);
+			free(lvm_device);
+		}
+		closedir(lv_list);
+	}
+exit:
+	closedir(vg_list);
+}
+#endif
+
+#define PROC_EVMS_VOLUMES "/proc/evms/volumes"
+
+static int
+evms_probe_all(blkid_cache cache, int only_if_new)
+{
+	char line[100];
+	int ma, mi, sz, num = 0;
+	FILE *procpt;
+	char device[110];
+
+	procpt = fopen(PROC_EVMS_VOLUMES, "r" UL_CLOEXECSTR);
+	if (!procpt)
+		return 0;
+	while (fgets(line, sizeof(line), procpt)) {
+		if (sscanf (line, " %d %d %d %*s %*s %[^\n ]",
+			    &ma, &mi, &sz, device) != 4)
+			continue;
+
+		DBG(DEVNAME, ul_debug("Checking partition %s (%d, %d)",
+					  device, ma, mi));
+
+		probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS,
+			  only_if_new, 0);
+		num++;
+	}
+	fclose(procpt);
+	return num;
+}
+
+static void
+ubi_probe_all(blkid_cache cache, int only_if_new)
+{
+	const char **dirname;
+
+	for (dirname = dirlist; *dirname; dirname++) {
+		DIR		*dir;
+		struct dirent	*iter;
+
+		DBG(DEVNAME, ul_debug("probing UBI volumes under %s",
+					  *dirname));
+
+		dir = opendir(*dirname);
+		if (dir == NULL)
+			continue ;
+
+		while ((iter = readdir(dir)) != NULL) {
+			char		*name;
+			struct stat	st;
+			dev_t		dev;
+
+			name = iter->d_name;
+#ifdef _DIRENT_HAVE_D_TYPE
+			if (iter->d_type != DT_UNKNOWN &&
+			    iter->d_type != DT_CHR && iter->d_type != DT_LNK)
+				continue;
+#endif
+			if (!strcmp(name, ".") || !strcmp(name, "..") ||
+			    !strstr(name, "ubi"))
+				continue;
+			if (!strcmp(name, "ubi_ctrl"))
+				continue;
+			if (fstat_at(dirfd(dir), *dirname, name, &st, 0))
+				continue;
+
+			dev = st.st_rdev;
+
+			if (!S_ISCHR(st.st_mode) || !minor(dev))
+				continue;
+			DBG(DEVNAME, ul_debug("UBI vol %s/%s: devno 0x%04X",
+				  *dirname, name, (int) dev));
+			probe_one(cache, name, dev, BLKID_PRI_UBI, only_if_new, 0);
+		}
+		closedir(dir);
+	}
+}
+
+/*
+ * Read the device data for all available block devices in the system.
+ */
+static int probe_all(blkid_cache cache, int only_if_new)
+{
+	FILE *proc;
+	char line[1024];
+	char ptname0[128 + 1], ptname1[128 + 1], *ptname = 0;
+	char *ptnames[2];
+	dev_t devs[2];
+	int ma, mi;
+	unsigned long long sz;
+	int lens[2] = { 0, 0 };
+	int which = 0, last = 0;
+	struct list_head *p, *pnext;
+
+	ptnames[0] = ptname0;
+	ptnames[1] = ptname1;
+
+	if (!cache)
+		return -BLKID_ERR_PARAM;
+
+	if (cache->bic_flags & BLKID_BIC_FL_PROBED &&
+	    time(0) - cache->bic_time < BLKID_PROBE_INTERVAL)
+		return 0;
+
+	blkid_read_cache(cache);
+	evms_probe_all(cache, only_if_new);
+#ifdef VG_DIR
+	lvm_probe_all(cache, only_if_new);
+#endif
+	ubi_probe_all(cache, only_if_new);
+
+	proc = fopen(PROC_PARTITIONS, "r" UL_CLOEXECSTR);
+	if (!proc)
+		return -BLKID_ERR_PROC;
+
+	while (fgets(line, sizeof(line), proc)) {
+		last = which;
+		which ^= 1;
+		ptname = ptnames[which];
+
+		if (sscanf(line, " %d %d %llu %128[^\n ]",
+			   &ma, &mi, &sz, ptname) != 4)
+			continue;
+		devs[which] = makedev(ma, mi);
+
+		DBG(DEVNAME, ul_debug("read partition name %s", ptname));
+
+		/* Skip whole disk devs unless they have no partitions.
+		 * If base name of device has changed, also
+		 * check previous dev to see if it didn't have a partn.
+		 * heuristic: partition name ends in a digit, & partition
+		 * names contain whole device name as substring.
+		 *
+		 * Skip extended partitions.
+		 * heuristic: size is 1
+		 *
+		 * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs
+		 */
+
+		lens[which] = strlen(ptname);
+
+		/* ends in a digit, clearly a partition, so check */
+		if (isdigit(ptname[lens[which] - 1])) {
+			DBG(DEVNAME, ul_debug("partition dev %s, devno 0x%04X",
+				   ptname, (unsigned int) devs[which]));
+
+			if (sz > 1)
+				probe_one(cache, ptname, devs[which], 0,
+					  only_if_new, 0);
+			lens[which] = 0;	/* mark as checked */
+		}
+
+		/*
+		 * If last was a whole disk and we just found a partition
+		 * on it, remove the whole-disk dev from the cache if
+		 * it exists.
+		 */
+		if (lens[last] && !strncmp(ptnames[last], ptname, lens[last])) {
+			list_for_each_safe(p, pnext, &cache->bic_devs) {
+				blkid_dev tmp;
+
+				/* find blkid dev for the whole-disk devno */
+				tmp = list_entry(p, struct blkid_struct_dev,
+						 bid_devs);
+				if (tmp->bid_devno == devs[last]) {
+					DBG(DEVNAME, ul_debug("freeing %s",
+						       tmp->bid_name));
+					blkid_free_dev(tmp);
+					cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+					break;
+				}
+			}
+			lens[last] = 0;
+		}
+		/*
+		 * If last was not checked because it looked like a whole-disk
+		 * dev, and the device's base name has changed,
+		 * check last as well.
+		 */
+		if (lens[last] && strncmp(ptnames[last], ptname, lens[last])) {
+			DBG(DEVNAME, ul_debug("whole dev %s, devno 0x%04X",
+				   ptnames[last], (unsigned int) devs[last]));
+			probe_one(cache, ptnames[last], devs[last], 0,
+				  only_if_new, 0);
+			lens[last] = 0;
+		}
+	}
+
+	/* Handle the last device if it wasn't partitioned */
+	if (lens[which])
+		probe_one(cache, ptname, devs[which], 0, only_if_new, 0);
+
+	fclose(proc);
+	blkid_flush_cache(cache);
+	return 0;
+}
+
+/* Don't use it by default -- it's pretty slow (because cdroms, floppy, ...)
+ */
+static int probe_all_removable(blkid_cache cache)
+{
+	DIR *dir;
+	struct dirent *d;
+
+	if (!cache)
+		return -BLKID_ERR_PARAM;
+
+	dir = opendir(_PATH_SYS_BLOCK);
+	if (!dir)
+		return -BLKID_ERR_PROC;
+
+	while((d = readdir(dir))) {
+		struct sysfs_cxt sysfs = UL_SYSFSCXT_EMPTY;
+		int removable = 0;
+		dev_t devno;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+		if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK)
+			continue;
+#endif
+		if (d->d_name[0] == '.' &&
+		    ((d->d_name[1] == 0) ||
+		     ((d->d_name[1] == '.') && (d->d_name[2] == 0))))
+			continue;
+
+		devno = sysfs_devname_to_devno(d->d_name, NULL);
+		if (!devno)
+			continue;
+
+		if (sysfs_init(&sysfs, devno, NULL) == 0) {
+			if (sysfs_read_int(&sysfs, "removable", &removable) != 0)
+				removable = 0;
+			sysfs_deinit(&sysfs);
+		}
+
+		if (removable)
+			probe_one(cache, d->d_name, devno, 0, 0, 1);
+	}
+
+	closedir(dir);
+	return 0;
+}
+
+
+/**
+ * blkid_probe_all:
+ * @cache: cache handler
+ *
+ * Probes all block devices.
+ *
+ * Returns: 0 on success, or number less than zero in case of error.
+ */
+int blkid_probe_all(blkid_cache cache)
+{
+	int ret;
+
+	DBG(PROBE, ul_debug("Begin blkid_probe_all()"));
+	ret = probe_all(cache, 0);
+	if (ret == 0) {
+		cache->bic_time = time(0);
+		cache->bic_flags |= BLKID_BIC_FL_PROBED;
+	}
+	DBG(PROBE, ul_debug("End blkid_probe_all() [rc=%d]", ret));
+	return ret;
+}
+
+/**
+ * blkid_probe_all_new:
+ * @cache: cache handler
+ *
+ * Probes all new block devices.
+ *
+ * Returns: 0 on success, or number less than zero in case of error.
+ */
+int blkid_probe_all_new(blkid_cache cache)
+{
+	int ret;
+
+	DBG(PROBE, ul_debug("Begin blkid_probe_all_new()"));
+	ret = probe_all(cache, 1);
+	DBG(PROBE, ul_debug("End blkid_probe_all_new() [rc=%d]", ret));
+	return ret;
+}
+
+/**
+ * blkid_probe_all_removable:
+ * @cache: cache handler
+ *
+ * The libblkid probing is based on devices from /proc/partitions by default.
+ * This file usually does not contain removable devices (e.g. CDROMs) and this kind
+ * of devices are invisible for libblkid.
+ *
+ * This function adds removable block devices to @cache (probing is based on
+ * information from the /sys directory). Don't forget that removable devices
+ * (floppies, CDROMs, ...) could be pretty slow. It's very bad idea to call
+ * this function by default.
+ *
+ * Note that devices which were detected by this function won't be written to
+ * blkid.tab cache file.
+ *
+ * Returns: 0 on success, or number less than zero in case of error.
+ */
+int blkid_probe_all_removable(blkid_cache cache)
+{
+	int ret;
+
+	DBG(PROBE, ul_debug("Begin blkid_probe_all_removable()"));
+	ret = probe_all_removable(cache);
+	DBG(PROBE, ul_debug("End blkid_probe_all_removable() [rc=%d]", ret));
+	return ret;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+	blkid_cache cache = NULL;
+	int ret;
+
+	blkid_init_debug(BLKID_DEBUG_ALL);
+	if (argc != 1) {
+		fprintf(stderr, "Usage: %s\n"
+			"Probe all devices and exit\n", argv[0]);
+		exit(1);
+	}
+	if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
+		fprintf(stderr, "%s: error creating cache (%d)\n",
+			argv[0], ret);
+		exit(1);
+	}
+	if (blkid_probe_all(cache) < 0)
+		printf("%s: error probing devices\n", argv[0]);
+
+	if (blkid_probe_all_removable(cache) < 0)
+		printf("%s: error probing removable devices\n", argv[0]);
+
+	blkid_put_cache(cache);
+	return (0);
+}
+#endif
diff --git a/libblkid/src/devno.c b/libblkid/src/devno.c
new file mode 100644
index 0000000..f4a36e4
--- /dev/null
+++ b/libblkid/src/devno.c
@@ -0,0 +1,375 @@
+/*
+ * devno.c - find a particular device by its device number (major/minor)
+ *
+ * Copyright (C) 2000, 2001, 2003 Theodore Ts'o
+ * Copyright (C) 2001 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <dirent.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include "blkidP.h"
+#include "pathnames.h"
+#include "at.h"
+#include "sysfs.h"
+
+static char *blkid_strconcat(const char *a, const char *b, const char *c)
+{
+	char *res, *p;
+	size_t len, al, bl, cl;
+
+	al = a ? strlen(a) : 0;
+	bl = b ? strlen(b) : 0;
+	cl = c ? strlen(c) : 0;
+
+	len = al + bl + cl;
+	if (!len)
+		return NULL;
+	p = res = malloc(len + 1);
+	if (!res)
+		return NULL;
+	if (al) {
+		memcpy(p, a, al);
+		p += al;
+	}
+	if (bl) {
+		memcpy(p, b, bl);
+		p += bl;
+	}
+	if (cl) {
+		memcpy(p, c, cl);
+		p += cl;
+	}
+	*p = '\0';
+	return res;
+}
+
+/*
+ * This function adds an entry to the directory list
+ */
+static void add_to_dirlist(const char *dir, const char *subdir,
+				struct dir_list **list)
+{
+	struct dir_list *dp;
+
+	dp = malloc(sizeof(struct dir_list));
+	if (!dp)
+		return;
+	dp->name = subdir ? blkid_strconcat(dir, "/", subdir) :
+		   dir ? strdup(dir) : NULL;
+
+	if (!dp->name) {
+		free(dp);
+		return;
+	}
+	dp->next = *list;
+	*list = dp;
+}
+
+/*
+ * This function frees a directory list
+ */
+static void free_dirlist(struct dir_list **list)
+{
+	struct dir_list *dp, *next;
+
+	for (dp = *list; dp; dp = next) {
+		next = dp->next;
+		free(dp->name);
+		free(dp);
+	}
+	*list = NULL;
+}
+
+void blkid__scan_dir(char *dirname, dev_t devno, struct dir_list **list,
+		     char **devname)
+{
+	DIR	*dir;
+	struct dirent *dp;
+	struct stat st;
+
+	if ((dir = opendir(dirname)) == NULL)
+		return;
+
+	while ((dp = readdir(dir)) != NULL) {
+#ifdef _DIRENT_HAVE_D_TYPE
+		if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_BLK &&
+		    dp->d_type != DT_LNK && dp->d_type != DT_DIR)
+			continue;
+#endif
+		if (dp->d_name[0] == '.' &&
+		    ((dp->d_name[1] == 0) ||
+		     ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
+			continue;
+
+		if (fstat_at(dirfd(dir), dirname, dp->d_name, &st, 0))
+			continue;
+
+		if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
+			*devname = blkid_strconcat(dirname, "/", dp->d_name);
+			DBG(DEVNO, ul_debug("found 0x%llx at %s", (long long)devno,
+				   *devname));
+			break;
+		}
+
+		if (!list || !S_ISDIR(st.st_mode))
+			continue;
+
+		/* add subdirectory (but not symlink) to the list */
+#ifdef _DIRENT_HAVE_D_TYPE
+		if (dp->d_type == DT_LNK)
+			continue;
+		if (dp->d_type == DT_UNKNOWN)
+#endif
+		{
+			if (fstat_at(dirfd(dir), dirname, dp->d_name, &st, 1) ||
+			    !S_ISDIR(st.st_mode))
+				continue;	/* symlink or lstat() failed */
+		}
+
+		if (*dp->d_name == '.' || (
+#ifdef _DIRENT_HAVE_D_TYPE
+		    dp->d_type == DT_DIR &&
+#endif
+		    strcmp(dp->d_name, "shm") == 0))
+			/* ignore /dev/.{udev,mount,mdadm} and /dev/shm */
+			continue;
+
+		add_to_dirlist(dirname, dp->d_name, list);
+	}
+	closedir(dir);
+	return;
+}
+
+/* Directories where we will try to search for device numbers */
+static const char *devdirs[] = { "/devices", "/devfs", "/dev", NULL };
+
+/**
+ * SECTION: misc
+ * @title: Miscellaneous utils
+ * @short_description: mix of various utils for low-level and high-level API
+ */
+
+
+
+static char *scandev_devno_to_devpath(dev_t devno)
+{
+	struct dir_list *list = NULL, *new_list = NULL;
+	char *devname = NULL;
+	const char **dir;
+
+	/*
+	 * Add the starting directories to search in reverse order of
+	 * importance, since we are using a stack...
+	 */
+	for (dir = devdirs; *dir; dir++)
+		add_to_dirlist(*dir, NULL, &list);
+
+	while (list) {
+		struct dir_list *current = list;
+
+		list = list->next;
+		DBG(DEVNO, ul_debug("directory %s", current->name));
+		blkid__scan_dir(current->name, devno, &new_list, &devname);
+		free(current->name);
+		free(current);
+		if (devname)
+			break;
+		/*
+		 * If we're done checking at this level, descend to
+		 * the next level of subdirectories. (breadth-first)
+		 */
+		if (list == NULL) {
+			list = new_list;
+			new_list = NULL;
+		}
+	}
+	free_dirlist(&list);
+	free_dirlist(&new_list);
+
+	return devname;
+}
+
+/**
+ * blkid_devno_to_devname:
+ * @devno: device number
+ *
+ * This function finds the pathname to a block device with a given
+ * device number.
+ *
+ * Returns: a pointer to allocated memory to the pathname on success,
+ * and NULL on failure.
+ */
+char *blkid_devno_to_devname(dev_t devno)
+{
+	char *path = NULL;
+	char buf[PATH_MAX];
+
+	path = sysfs_devno_to_devpath(devno, buf, sizeof(buf));
+	if (path)
+		path = strdup(path);
+	if (!path)
+		path = scandev_devno_to_devpath(devno);
+
+	if (!path) {
+		DBG(DEVNO, ul_debug("blkid: couldn't find devno 0x%04lx",
+			   (unsigned long) devno));
+	} else {
+		DBG(DEVNO, ul_debug("found devno 0x%04llx as %s", (long long)devno, path));
+	}
+
+	return path;
+}
+
+
+/**
+ * blkid_devno_to_wholedisk:
+ * @dev: device number
+ * @diskname: buffer to return diskname (or NULL)
+ * @len: diskname buffer size (or 0)
+ * @diskdevno: pointer to returns devno of entire disk (or NULL)
+ *
+ * This function uses sysfs to convert the @devno device number to the *name*
+ * of the whole disk. The function DOES NOT return full device name. The @dev
+ * argument could be partition or whole disk -- both is converted.
+ *
+ * For example: sda1, 0x0801 --> sda, 0x0800
+ *
+ * For conversion to the full disk *path* use blkid_devno_to_devname(), for
+ * example:
+ *
+ * <informalexample>
+ *  <programlisting>
+ *
+ *	dev_t dev = 0x0801, disk;		// sda1 = 8:1
+ *	char *diskpath, diskname[32];
+ *
+ *	blkid_devno_to_wholedisk(dev, diskname, sizeof(diskname), &disk);
+ *	diskpath = blkid_devno_to_devname(disk);
+ *
+ *	// print "0x0801: sda, /dev/sda, 8:0
+ *	printf("0x%x: %s, %s, %d:%d\n",
+ *		dev, diskname, diskpath, major(disk), minor(disk));
+ *
+ *	free(diskpath);
+ *
+ *  </programlisting>
+ * </informalexample>
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int blkid_devno_to_wholedisk(dev_t dev, char *diskname,
+			size_t len, dev_t *diskdevno)
+{
+	return sysfs_devno_to_wholedisk( dev, diskname, len, diskdevno);
+}
+
+/*
+ * Returns 1 if the @major number is associated with @drvname.
+ */
+int blkid_driver_has_major(const char *drvname, int major)
+{
+	FILE *f;
+	char buf[128];
+	int match = 0;
+
+	f = fopen(_PATH_PROC_DEVICES, "r" UL_CLOEXECSTR);
+	if (!f)
+		return 0;
+
+	while (fgets(buf, sizeof(buf), f)) {	/* skip to block dev section */
+		if (strncmp("Block devices:\n", buf, sizeof(buf)) == 0)
+			break;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		int maj;
+		char name[64 + 1];
+
+		if (sscanf(buf, "%d %64[^\n ]", &maj, name) != 2)
+			continue;
+
+		if (maj == major && strcmp(name, drvname) == 0) {
+			match = 1;
+			break;
+		}
+	}
+
+	fclose(f);
+
+	DBG(DEVNO, ul_debug("major %d %s associated with '%s' driver",
+			major, match ? "is" : "is NOT", drvname));
+	return match;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char** argv)
+{
+	char	*devname, *tmp;
+	char	diskname[PATH_MAX];
+	int	major, minor;
+	dev_t	devno, disk_devno;
+	const char *errmsg = "Couldn't parse %s: %s\n";
+
+	blkid_init_debug(BLKID_DEBUG_ALL);
+	if ((argc != 2) && (argc != 3)) {
+		fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n"
+			"Resolve a device number to a device name\n",
+			argv[0], argv[0]);
+		exit(1);
+	}
+	if (argc == 2) {
+		devno = strtoul(argv[1], &tmp, 0);
+		if (*tmp) {
+			fprintf(stderr, errmsg, "device number", argv[1]);
+			exit(1);
+		}
+	} else {
+		major = strtoul(argv[1], &tmp, 0);
+		if (*tmp) {
+			fprintf(stderr, errmsg, "major number", argv[1]);
+			exit(1);
+		}
+		minor = strtoul(argv[2], &tmp, 0);
+		if (*tmp) {
+			fprintf(stderr, errmsg, "minor number", argv[2]);
+			exit(1);
+		}
+		devno = makedev(major, minor);
+	}
+	printf("Looking for device 0x%04llx\n", (long long)devno);
+	devname = blkid_devno_to_devname(devno);
+	free(devname);
+
+	printf("Looking for whole-device for 0x%04llx\n", (long long)devno);
+	if (blkid_devno_to_wholedisk(devno, diskname,
+				sizeof(diskname), &disk_devno) == 0)
+		printf("found devno 0x%04llx as /dev/%s\n", (long long) disk_devno, diskname);
+
+	return 0;
+}
+#endif
diff --git a/libblkid/src/encode.c b/libblkid/src/encode.c
new file mode 100644
index 0000000..ff57be4
--- /dev/null
+++ b/libblkid/src/encode.c
@@ -0,0 +1,340 @@
+
+/*
+ * encode.c - string conversion routines (mostly for compatibility with
+ *            udev/volume_id)
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "blkidP.h"
+
+#define UDEV_ALLOWED_CHARS_INPUT               "/ $%?,"
+
+/**
+ * SECTION: encode
+ * @title: Encoding utils
+ * @short_description: encode strings to safe udev-compatible formats
+ *
+ */
+
+/* count of characters used to encode one unicode char */
+static int utf8_encoded_expected_len(const char *str)
+{
+	unsigned char c = (unsigned char)str[0];
+
+	if (c < 0x80)
+		return 1;
+	if ((c & 0xe0) == 0xc0)
+		return 2;
+	if ((c & 0xf0) == 0xe0)
+		return 3;
+	if ((c & 0xf8) == 0xf0)
+		return 4;
+	if ((c & 0xfc) == 0xf8)
+		return 5;
+	if ((c & 0xfe) == 0xfc)
+		return 6;
+	return 0;
+}
+
+/* decode one unicode char */
+static int utf8_encoded_to_unichar(const char *str)
+{
+	int unichar;
+	int len;
+	int i;
+
+	len = utf8_encoded_expected_len(str);
+	switch (len) {
+	case 1:
+		return (int)str[0];
+	case 2:
+		unichar = str[0] & 0x1f;
+		break;
+	case 3:
+		unichar = (int)str[0] & 0x0f;
+		break;
+	case 4:
+		unichar = (int)str[0] & 0x07;
+		break;
+	case 5:
+		unichar = (int)str[0] & 0x03;
+		break;
+	case 6:
+		unichar = (int)str[0] & 0x01;
+		break;
+	default:
+		return -1;
+	}
+
+	for (i = 1; i < len; i++) {
+		if (((int)str[i] & 0xc0) != 0x80)
+			return -1;
+		unichar <<= 6;
+		unichar |= (int)str[i] & 0x3f;
+	}
+
+	return unichar;
+}
+
+/* expected size used to encode one unicode char */
+static int utf8_unichar_to_encoded_len(int unichar)
+{
+	if (unichar < 0x80)
+		return 1;
+	if (unichar < 0x800)
+		return 2;
+	if (unichar < 0x10000)
+		return 3;
+	if (unichar < 0x200000)
+		return 4;
+	if (unichar < 0x4000000)
+		return 5;
+	return 6;
+}
+
+/* check if unicode char has a valid numeric range */
+static int utf8_unichar_valid_range(int unichar)
+{
+	if (unichar > 0x10ffff)
+		return 0;
+	if ((unichar & 0xfffff800) == 0xd800)
+		return 0;
+	if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
+		return 0;
+	if ((unichar & 0xffff) == 0xffff)
+		return 0;
+	return 1;
+}
+
+/* validate one encoded unicode char and return its length */
+static int utf8_encoded_valid_unichar(const char *str)
+{
+	int len;
+	int unichar;
+	int i;
+
+	len = utf8_encoded_expected_len(str);
+	if (len == 0)
+		return -1;
+
+	/* ascii is valid */
+	if (len == 1)
+		return 1;
+
+	/* check if expected encoded chars are available */
+	for (i = 0; i < len; i++)
+		if ((str[i] & 0x80) != 0x80)
+			return -1;
+
+	unichar = utf8_encoded_to_unichar(str);
+
+	/* check if encoded length matches encoded value */
+	if (utf8_unichar_to_encoded_len(unichar) != len)
+		return -1;
+
+	/* check if value has valid range */
+	if (!utf8_unichar_valid_range(unichar))
+		return -1;
+
+	return len;
+}
+
+static int replace_whitespace(const char *str, char *to, size_t len)
+{
+	size_t i, j;
+
+	/* strip trailing whitespace */
+	len = strnlen(str, len);
+	while (len && isspace(str[len-1]))
+		len--;
+
+	/* strip leading whitespace */
+	i = 0;
+	while (isspace(str[i]) && (i < len))
+		i++;
+
+	j = 0;
+	while (i < len) {
+		/* substitute multiple whitespace with a single '_' */
+		if (isspace(str[i])) {
+			while (isspace(str[i]))
+				i++;
+			to[j++] = '_';
+		}
+		to[j++] = str[i++];
+	}
+	to[j] = '\0';
+	return 0;
+}
+
+static int is_whitelisted(char c, const char *white)
+{
+	if ((c >= '0' && c <= '9') ||
+	    (c >= 'A' && c <= 'Z') ||
+	    (c >= 'a' && c <= 'z') ||
+	    strchr("#+-.:=@_", c) != NULL ||
+	    (white != NULL && strchr(white, c) != NULL))
+		return 1;
+	return 0;
+}
+
+/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
+static int replace_chars(char *str, const char *white)
+{
+	size_t i = 0;
+	int replaced = 0;
+
+	while (str[i] != '\0') {
+		int len;
+
+		if (is_whitelisted(str[i], white)) {
+			i++;
+			continue;
+		}
+
+		/* accept hex encoding */
+		if (str[i] == '\\' && str[i+1] == 'x') {
+			i += 2;
+			continue;
+		}
+
+		/* accept valid utf8 */
+		len = utf8_encoded_valid_unichar(&str[i]);
+		if (len > 1) {
+			i += len;
+			continue;
+		}
+
+		/* if space is allowed, replace whitespace with ordinary space */
+		if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) {
+			str[i] = ' ';
+			i++;
+			replaced++;
+			continue;
+		}
+
+		/* everything else is replaced with '_' */
+		str[i] = '_';
+		i++;
+		replaced++;
+	}
+	return replaced;
+}
+
+size_t blkid_encode_to_utf8(int enc, unsigned char *dest, size_t len,
+			const 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;
+}
+
+/**
+ * blkid_encode_string:
+ * @str: input string to be encoded
+ * @str_enc: output string to store the encoded input string
+ * @len: maximum size of the output string, which may be
+ *       four times as long as the input string
+ *
+ * Encode all potentially unsafe characters of a string to the
+ * corresponding hex value prefixed by '\x'.
+ *
+ * Returns: 0 if the entire string was copied, non-zero otherwise.
+ **/
+int blkid_encode_string(const char *str, char *str_enc, size_t len)
+{
+	size_t i, j;
+
+	if (!str || !str_enc || !len)
+		return -1;
+
+	for (i = 0, j = 0; str[i] != '\0'; i++) {
+		int seqlen;
+
+		seqlen = utf8_encoded_valid_unichar(&str[i]);
+		if (seqlen > 1) {
+			if (len-j < (size_t)seqlen)
+				goto err;
+			memcpy(&str_enc[j], &str[i], seqlen);
+			j += seqlen;
+			i += (seqlen-1);
+		} else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) {
+			if (len-j < 4)
+				goto err;
+			sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
+			j += 4;
+		} else {
+			if (len-j < 1)
+				goto err;
+			str_enc[j] = str[i];
+			j++;
+		}
+		if (j+3 >= len)
+			goto err;
+	}
+	if (len-j < 1)
+		goto err;
+	str_enc[j] = '\0';
+	return 0;
+err:
+	return -1;
+}
+
+/**
+ * blkid_safe_string:
+ * @str: input string
+ * @str_safe: output string
+ * @len: size of output string
+ *
+ * Allows plain ascii, hex-escaping and valid utf8. Replaces all whitespaces
+ * with '_'.
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int blkid_safe_string(const char *str, char *str_safe, size_t len)
+{
+	if (!str || !str_safe || !len)
+		return -1;
+	replace_whitespace(str, str_safe, len);
+	replace_chars(str_safe, UDEV_ALLOWED_CHARS_INPUT);
+	return 0;
+}
diff --git a/libblkid/src/env.h b/libblkid/src/env.h
new file mode 100644
index 0000000..a53d310
--- /dev/null
+++ b/libblkid/src/env.h
@@ -0,0 +1,16 @@
+#ifndef UTIL_LINUX_ENV_H
+#define UTIL_LINUX_ENV_H
+
+#include "c.h"
+
+extern void sanitize_env(void);
+extern char *safe_getenv(const char *arg);
+
+static inline void xsetenv(char const *name, char const *val, int overwrite)
+{
+	if (setenv(name, val, overwrite) != 0)
+		err(EXIT_FAILURE, "failed to set the %s environment variable", name);
+}
+
+#endif /* UTIL_LINUX_ENV_H */
+
diff --git a/libblkid/src/evaluate.c b/libblkid/src/evaluate.c
new file mode 100644
index 0000000..ffbe097
--- /dev/null
+++ b/libblkid/src/evaluate.c
@@ -0,0 +1,324 @@
+/*
+ * evaluate.c - very high-level API to evaluate LABELs or UUIDs
+ *
+ * Copyright (C) 2009 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_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "pathnames.h"
+#include "canonicalize.h"
+#include "closestream.h"
+
+#include "blkidP.h"
+
+/**
+ * SECTION:evaluate
+ * @title: Tags and Spec evaluation
+ * @short_description: top-level API for LABEL and UUID evaluation.
+ *
+ * This API provides very simple and portable way how evaluate LABEL and UUID
+ * tags.  The blkid_evaluate_tag() and blkid_evaluate_spec() work on 2.4 and
+ * 2.6 systems and on systems with or without udev. Currently, the libblkid
+ * library supports "udev" and "scan" methods. The "udev" method uses udev
+ * /dev/disk/by-* symlinks and the "scan" method scans all block devices from
+ * the /proc/partitions file. The evaluation could be controlled by the
+ * /etc/blkid.conf config file. The default is to try "udev" and then "scan"
+ * method.
+ *
+ * The blkid_evaluate_tag() also automatically informs udevd when an obsolete
+ * /dev/disk/by-* symlink is detected.
+ *
+ * If you are not sure how translate LABEL or UUID to the device name use this
+ * API.
+ */
+
+#ifdef CONFIG_BLKID_VERIFY_UDEV
+/* returns zero when the device has NAME=value (LABEL/UUID) */
+static int verify_tag(const char *devname, const char *name, const char *value)
+{
+	blkid_probe pr;
+	int fd = -1, rc = -1;
+	size_t len;
+	const char *data;
+	int errsv = 0;
+
+	pr = blkid_new_probe();
+	if (!pr)
+		return -1;
+
+	blkid_probe_enable_superblocks(pr, TRUE);
+	blkid_probe_set_superblocks_flags(pr,
+			BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID);
+
+	blkid_probe_enable_partitions(pr, TRUE);
+	blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
+
+	fd = open(devname, O_RDONLY|O_CLOEXEC);
+	if (fd < 0) {
+		errsv = errno;
+		goto done;
+	}
+	if (blkid_probe_set_device(pr, fd, 0, 0))
+		goto done;
+	rc = blkid_do_safeprobe(pr);
+	if (rc)
+		goto done;
+	rc = blkid_probe_lookup_value(pr, name, &data, &len);
+	if (!rc)
+		rc = memcmp(value, data, len);
+done:
+	DBG(EVALUATE, ul_debug("%s: %s verification %s",
+			devname, name, rc == 0 ? "PASS" : "FAILED"));
+	if (fd >= 0)
+		close(fd);
+	blkid_free_probe(pr);
+
+	/* for non-root users we use unverified udev links */
+	return errsv == EACCES ? 0 : rc;
+}
+#endif /* CONFIG_BLKID_VERIFY_UDEV*/
+
+/**
+ * blkid_send_uevent:
+ * @devname: absolute path to the device
+ * @action: event string
+ *
+ * Returns: -1 in case of failure, or 0 on success.
+ */
+int blkid_send_uevent(const char *devname, const char *action)
+{
+	char uevent[PATH_MAX];
+	struct stat st;
+	FILE *f;
+	int rc = -1;
+
+	DBG(EVALUATE, ul_debug("%s: uevent '%s' requested", devname, action));
+
+	if (!devname || !action)
+		return -1;
+	if (stat(devname, &st) || !S_ISBLK(st.st_mode))
+		return -1;
+
+	snprintf(uevent, sizeof(uevent), "/sys/dev/block/%d:%d/uevent",
+			major(st.st_rdev), minor(st.st_rdev));
+
+	f = fopen(uevent, "w" UL_CLOEXECSTR);
+	if (f) {
+		rc = 0;
+		if (fputs(action, f) >= 0)
+			rc = 0;
+		if (close_stream(f) != 0)
+			DBG(EVALUATE, ul_debug("write failed: %s", uevent));
+	}
+	DBG(EVALUATE, ul_debug("%s: send uevent %s",
+			uevent, rc == 0 ? "SUCCES" : "FAILED"));
+	return rc;
+}
+
+static char *evaluate_by_udev(const char *token, const char *value, int uevent)
+{
+	char dev[PATH_MAX];
+	char *path = NULL;
+	size_t len;
+	struct stat st;
+
+	DBG(EVALUATE, ul_debug("evaluating by udev %s=%s", token, value));
+
+	if (!strcmp(token, "UUID"))
+		strcpy(dev, _PATH_DEV_BYUUID "/");
+	else if (!strcmp(token, "LABEL"))
+		strcpy(dev, _PATH_DEV_BYLABEL "/");
+	else if (!strcmp(token, "PARTLABEL"))
+		strcpy(dev, _PATH_DEV_BYPARTLABEL "/");
+	else if (!strcmp(token, "PARTUUID"))
+		strcpy(dev, _PATH_DEV_BYPARTUUID "/");
+	else {
+		DBG(EVALUATE, ul_debug("unsupported token %s", token));
+		return NULL;	/* unsupported tag */
+	}
+
+	len = strlen(dev);
+	if (blkid_encode_string(value, &dev[len], sizeof(dev) - len) != 0)
+		return NULL;
+
+	DBG(EVALUATE, ul_debug("expected udev link: %s", dev));
+
+	if (stat(dev, &st))
+		goto failed;	/* link or device does not exist */
+
+	if (!S_ISBLK(st.st_mode))
+		return NULL;
+
+	path = canonicalize_path(dev);
+	if (!path)
+		return NULL;
+
+#ifdef CONFIG_BLKID_VERIFY_UDEV
+	if (verify_tag(path, token, value))
+		goto failed;
+#endif
+	return path;
+
+failed:
+	DBG(EVALUATE, ul_debug("failed to evaluate by udev"));
+
+	if (uevent && path)
+		blkid_send_uevent(path, "change");
+	free(path);
+	return NULL;
+}
+
+static char *evaluate_by_scan(const char *token, const char *value,
+		blkid_cache *cache, struct blkid_config *conf)
+{
+	blkid_cache c = cache ? *cache : NULL;
+	char *res;
+
+	DBG(EVALUATE, ul_debug("evaluating by blkid scan %s=%s", token, value));
+
+	if (!c) {
+		char *cachefile = blkid_get_cache_filename(conf);
+		blkid_get_cache(&c, cachefile);
+		free(cachefile);
+	}
+	if (!c)
+		return NULL;
+
+	res = blkid_get_devname(c, token, value);
+
+	if (cache)
+		*cache = c;
+	else
+		blkid_put_cache(c);
+
+	return res;
+}
+
+/**
+ * blkid_evaluate_tag:
+ * @token: token name (e.g "LABEL" or "UUID") or unparsed tag (e.g. "LABEL=foo")
+ * @value: token data (e.g. "foo")
+ * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
+ *
+ * Returns: allocated string with a device name.
+ */
+char *blkid_evaluate_tag(const char *token, const char *value, blkid_cache *cache)
+{
+	struct blkid_config *conf = NULL;
+	char *t = NULL, *v = NULL;
+	char *ret = NULL;
+	int i;
+
+	if (!token)
+		return NULL;
+
+	if (!cache || !*cache)
+		blkid_init_debug(0);
+
+	DBG(EVALUATE, ul_debug("evaluating  %s%s%s", token, value ? "=" : "",
+		   value ? value : ""));
+
+	if (!value) {
+		if (!strchr(token, '=')) {
+			ret = strdup(token);
+			goto out;
+		}
+		blkid_parse_tag_string(token, &t, &v);
+		if (!t || !v)
+			goto out;
+		token = t;
+		value = v;
+	}
+
+	conf = blkid_read_config(NULL);
+	if (!conf)
+		goto out;
+
+	for (i = 0; i < conf->nevals; i++) {
+		if (conf->eval[i] == BLKID_EVAL_UDEV)
+			ret = evaluate_by_udev(token, value, conf->uevent);
+		else if (conf->eval[i] == BLKID_EVAL_SCAN)
+			ret = evaluate_by_scan(token, value, cache, conf);
+		if (ret)
+			break;
+	}
+
+	DBG(EVALUATE, ul_debug("%s=%s evaluated as %s", token, value, ret));
+out:
+	blkid_free_config(conf);
+	free(t);
+	free(v);
+	return ret;
+}
+
+/**
+ * blkid_evaluate_spec:
+ * @spec: unparsed tag (e.g. "LABEL=foo") or path (e.g. /dev/dm-0)
+ * @cache: pointer to cache (or NULL when you don't want to re-use the cache)
+ *
+ * All returned paths are canonicalized, device-mapper paths are converted
+ * to the /dev/mapper/name format.
+ *
+ * Returns: allocated string with a device name.
+ */
+char *blkid_evaluate_spec(const char *spec, blkid_cache *cache)
+{
+	char *t = NULL, *v = NULL, *res;
+
+	if (!spec)
+		return NULL;
+
+	if (strchr(spec, '=') &&
+	    blkid_parse_tag_string(spec, &t, &v) != 0)	/* parse error */
+		return NULL;
+
+	if (v)
+		res = blkid_evaluate_tag(t, v, cache);
+	else
+		res = canonicalize_path(spec);
+
+	free(t);
+	free(v);
+	return res;
+}
+
+
+#ifdef TEST_PROGRAM
+int main(int argc, char *argv[])
+{
+	blkid_cache cache = NULL;
+	char *res;
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s <tag> | <spec>\n", argv[0]);
+		return EXIT_FAILURE;
+	}
+
+	blkid_init_debug(0);
+
+	res = blkid_evaluate_spec(argv[1], &cache);
+	if (res)
+		printf("%s\n", res);
+	if (cache)
+		blkid_put_cache(cache);
+
+	return res ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+#endif
diff --git a/libblkid/src/exec_shell.h b/libblkid/src/exec_shell.h
new file mode 100644
index 0000000..a2aa757
--- /dev/null
+++ b/libblkid/src/exec_shell.h
@@ -0,0 +1 @@
+extern void __attribute__((__noreturn__)) exec_shell(void);
diff --git a/libblkid/src/fileutils.h b/libblkid/src/fileutils.h
new file mode 100644
index 0000000..3353f69
--- /dev/null
+++ b/libblkid/src/fileutils.h
@@ -0,0 +1,33 @@
+#ifndef UTIL_LINUX_FILEUTILS
+#define UTIL_LINUX_FILEUTILS
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "c.h"
+
+extern int xmkstemp(char **tmpname, char *dir);
+
+static inline FILE *xfmkstemp(char **tmpname, char *dir)
+{
+	int fd;
+	FILE *ret;
+
+	fd = xmkstemp(tmpname, dir);
+	if (fd == -1)
+		return NULL;
+
+	if (!(ret = fdopen(fd, "w+" UL_CLOEXECSTR))) {
+		close(fd);
+		return NULL;
+	}
+	return ret;
+}
+
+extern int get_fd_tabsize(void);
+
+extern int mkdir_p(const char *path, mode_t mode);
+extern char *stripoff_last_component(char *path);
+
+#endif /* UTIL_LINUX_FILEUTILS */
diff --git a/libblkid/src/getsize.c b/libblkid/src/getsize.c
new file mode 100644
index 0000000..abe6ebc
--- /dev/null
+++ b/libblkid/src/getsize.c
@@ -0,0 +1,34 @@
+/*
+ * getsize.c --- get the size of a partition.
+ *
+ * Copyright (C) 1995, 1995 Theodore Ts'o.
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "blkidP.h"
+
+/**
+ * blkid_get_dev_size:
+ * @fd: file descriptor
+ *
+ * Returns: size (in bytes) of the block device or size of the regular file or 0.
+ */
+blkid_loff_t blkid_get_dev_size(int fd)
+{
+	unsigned long long bytes;
+
+	if (blkdev_get_size(fd, &bytes))
+		return 0;
+
+	return bytes;
+}
+
diff --git a/libblkid/src/init.c b/libblkid/src/init.c
new file mode 100644
index 0000000..eead6c7
--- /dev/null
+++ b/libblkid/src/init.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008-2013 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: init
+ * @title: Library initialization
+ * @short_description: initialize debuging
+ */
+
+#include <stdarg.h>
+
+#include "blkidP.h"
+
+UL_DEBUG_DEFINE_MASK(libblkid);
+UL_DEBUG_DEFINE_MASKNAMES(libblkid) =
+{
+	{ "all", BLKID_DEBUG_ALL,	"info about all subsystems" },
+	{ "cache", BLKID_DEBUG_CACHE,	"blkid tags cache" },
+	{ "config", BLKID_DEBUG_CONFIG, "config file utils" },
+	{ "dev", BLKID_DEBUG_DEV,       "device utils" },
+	{ "devname", BLKID_DEBUG_DEVNAME, "/proc/partitions evaluation" },
+	{ "devno", BLKID_DEBUG_DEVNO,	"convertions to device name" },
+	{ "evaluate", BLKID_DEBUG_EVALUATE, "tags resolving" },
+	{ "help", BLKID_DEBUG_HELP,	"this help" },
+	{ "lowprobe", BLKID_DEBUG_LOWPROBE, "superblock/raids/partitions probing" },
+	{ "probe", BLKID_DEBUG_PROBE,	"devices verification" },
+	{ "read", BLKID_DEBUG_READ,	"cache parsing" },
+	{ "save", BLKID_DEBUG_SAVE,	"cache writing" },
+	{ "tag", BLKID_DEBUG_TAG,	"tags utils" },
+	{ NULL, 0, NULL }
+};
+
+/**
+ * blkid_init_debug:
+ * @mask: debug mask (0xffff to enable full debuging)
+ *
+ * If the @mask is not specified then this function reads
+ * LIBBLKID_DEBUG environment variable to get the mask.
+ *
+ * Already initialized debugging stuff cannot be changed. It does not
+ * have effect to call this function twice.
+ */
+void blkid_init_debug(int mask)
+{
+	if (libblkid_debug_mask)
+		return;
+
+	__UL_INIT_DEBUG(libblkid, BLKID_DEBUG_, mask, LIBBLKID_DEBUG);
+
+	if (libblkid_debug_mask != BLKID_DEBUG_INIT
+	    && libblkid_debug_mask != (BLKID_DEBUG_HELP|BLKID_DEBUG_INIT)) {
+		const char *ver = NULL;
+		const char *date = NULL;
+
+		blkid_get_library_version(&ver, &date);
+		DBG(INIT, ul_debug("library debug mask: 0x%04x", libblkid_debug_mask));
+		DBG(INIT, ul_debug("library version: %s [%s]", ver, date));
+
+	}
+	ON_DBG(HELP, ul_debug_print_masks("LIBBLKID_DEBUG",
+				UL_DEBUG_MASKNAMES(libblkid)));
+}
diff --git a/libblkid/src/ismounted.h b/libblkid/src/ismounted.h
new file mode 100644
index 0000000..57918cb
--- /dev/null
+++ b/libblkid/src/ismounted.h
@@ -0,0 +1,14 @@
+#ifndef IS_MOUNTED_H
+#define IS_MOUNTED_H
+
+#define MF_MOUNTED	1
+#define MF_ISROOT	2
+#define MF_READONLY	4
+#define MF_SWAP		8
+#define MF_BUSY		16
+
+extern int is_mounted(const char *file);
+extern int check_mount_point(const char *device, int *mount_flags,
+				 char *mtpt, int mtlen);
+
+#endif /* IS_MOUNTED_H */
diff --git a/libblkid/src/libblkid.sym b/libblkid/src/libblkid.sym
new file mode 100644
index 0000000..6b3cf08
--- /dev/null
+++ b/libblkid/src/libblkid.sym
@@ -0,0 +1,166 @@
+/*
+ * The symbol versioning ensures that a new application requiring symbol 'foo'
+ * can't run with old library.so not providing 'foo' - the global SONAME
+ * version info can't enforce this since we never change the SONAME.
+ *
+ * The original libblkid from e2fsprogs (<=1.41.4) does not to use
+ * symbol versioning -- all the original symbols are in BLKID_1.0 now.
+ *
+ * Copyright (C) 2009-2014 Karel Zak <kzak@redhat.com> 
+ */
+BLKID_1.0 {
+global:
+	blkid_dev_devname;
+	blkid_dev_has_tag;
+	blkid_dev_iterate_begin;
+	blkid_dev_iterate_end;
+	blkid_dev_next;
+	blkid_devno_to_devname;
+	blkid_dev_set_search;
+	blkid_find_dev_with_tag;
+	blkid_gc_cache;
+	blkid_get_cache;
+	blkid_get_dev;
+	blkid_get_devname;
+	blkid_get_dev_size;
+	blkid_get_library_version;
+	blkid_get_tag_value;
+	blkid_known_fstype;
+	blkid_parse_tag_string;
+	blkid_parse_version_string;
+	blkid_probe_all;
+	blkid_probe_all_new;
+	blkid_put_cache;
+	blkid_tag_iterate_begin;
+	blkid_tag_iterate_end;
+	blkid_tag_next;
+	blkid_verify;
+local:
+	*;
+};
+
+
+/*
+ * symbols since util-linux 2.15
+ */
+BLKID_2.15 {
+global:
+	blkid_do_probe;
+	blkid_do_safeprobe;
+	blkid_encode_string;
+	blkid_evaluate_tag;
+	blkid_free_probe;
+	blkid_new_probe;
+	blkid_probe_filter_types;
+	blkid_probe_filter_usage;
+	blkid_probe_get_value;
+	blkid_probe_has_value;
+	blkid_probe_invert_filter;
+	blkid_probe_lookup_value;
+	blkid_probe_numof_values;
+	blkid_probe_reset_filter;
+	blkid_probe_set_device;
+	blkid_probe_set_request;
+	blkid_reset_probe;
+	blkid_safe_string;
+	blkid_send_uevent;
+} BLKID_1.0;
+
+/*
+ * symbols since util-linux 2.17
+ */
+BLKID_2.17 {
+global:
+	blkid_devno_to_wholedisk;
+	blkid_do_fullprobe;
+	blkid_known_pttype;
+	blkid_new_probe_from_filename;
+	blkid_partition_get_name;
+	blkid_partition_get_partno;
+	blkid_partition_get_size;
+	blkid_partition_get_start;
+	blkid_partition_get_table;
+	blkid_partition_get_type;
+	blkid_partition_get_type_string;
+	blkid_partition_get_uuid;
+	blkid_partition_is_extended;
+	blkid_partition_is_logical;
+	blkid_partition_is_primary;
+	blkid_partlist_get_partition;
+	blkid_partlist_numof_partitions;
+	blkid_parttable_get_offset;
+	blkid_parttable_get_parent;
+	blkid_parttable_get_type;
+	blkid_probe_enable_partitions;
+	blkid_probe_enable_superblocks;
+	blkid_probe_enable_topology;
+	blkid_probe_filter_partitions_type;
+	blkid_probe_filter_superblocks_type;
+	blkid_probe_filter_superblocks_usage;
+	blkid_probe_get_devno;
+	blkid_probe_get_partitions;
+	blkid_probe_get_sectorsize;
+	blkid_probe_get_sectors;
+	blkid_probe_get_size;
+	blkid_probe_get_topology;
+	blkid_probe_invert_partitions_filter;
+	blkid_probe_invert_superblocks_filter;
+	blkid_probe_reset_partitions_filter;
+	blkid_probe_reset_superblocks_filter;
+	blkid_probe_set_partitions_flags;
+	blkid_probe_set_superblocks_flags;
+	blkid_topology_get_alignment_offset;
+	blkid_topology_get_logical_sector_size;
+	blkid_topology_get_minimum_io_size;
+	blkid_topology_get_optimal_io_size;
+	blkid_topology_get_physical_sector_size;
+} BLKID_2.15;
+
+/*
+ * symbols since util-linux 2.18
+ */
+BLKID_2.18 {
+global:
+	blkid_partition_get_flags;
+	blkid_partlist_devno_to_partition;
+	blkid_partlist_get_table;
+	blkid_probe_all_removable;
+	blkid_probe_get_fd;
+	blkid_probe_get_offset;
+	blkid_probe_get_wholedisk_devno;
+	blkid_probe_is_wholedisk;
+} BLKID_2.17;
+
+/*
+ * symbols since util-linux 2.20
+ */
+BLKID_2.20 {
+global:
+	blkid_evaluate_spec;
+	blkid_superblocks_get_name;
+} BLKID_2.18;
+
+/*
+ * symbols since util-linux 2.21
+ */
+BLKID_2.21 {
+global:
+	blkid_do_wipe;
+} BLKID_2.20;
+
+/*
+ * symbols since util-linux 2.23
+ */
+BLKID_2.23 {
+global:
+	blkid_probe_step_back;
+	blkid_parttable_get_id;
+	blkid_init_debug;
+} BLKID_2.21;
+
+/*
+ * symbols since util-linux 2.25
+ */
+BLKID_2.25 {
+	blkid_partlist_get_partition_by_partno;
+} BLKID_2.23;
diff --git a/libblkid/src/linux_version.h b/libblkid/src/linux_version.h
new file mode 100644
index 0000000..a6a1e99
--- /dev/null
+++ b/libblkid/src/linux_version.h
@@ -0,0 +1,14 @@
+#ifndef LINUX_VERSION_H
+#define LINUX_VERSION_H
+
+#ifdef HAVE_LINUX_VERSION_H
+# include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
+int get_linux_version(void);
+
+#endif /* LINUX_VERSION_H */
diff --git a/libblkid/src/list.h b/libblkid/src/list.h
new file mode 100644
index 0000000..7b60672
--- /dev/null
+++ b/libblkid/src/list.h
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 1999-2008 by Theodore Ts'o
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * (based on list.h from e2fsprogs)
+ * Merge sort based on kernel's implementation.
+ */
+
+#ifndef UTIL_LINUX_LIST_H
+#define UTIL_LINUX_LIST_H
+
+/* TODO: use AC_C_INLINE */
+#ifdef __GNUC__
+#define _INLINE_ static __inline__
+#else                         /* For Watcom C */
+#define _INLINE_ static inline
+#endif
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+_INLINE_ void __list_add(struct list_head * add,
+	struct list_head * prev,
+	struct list_head * next)
+{
+	next->prev = add;
+	add->next = next;
+	add->prev = prev;
+	prev->next = add;
+}
+
+/**
+ * list_add - add a new entry
+ * @add:	new entry to be added
+ * @head:	list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+_INLINE_ void list_add(struct list_head *add, struct list_head *head)
+{
+	__list_add(add, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @add:	new entry to be added
+ * @head:	list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+_INLINE_ void list_add_tail(struct list_head *add, struct list_head *head)
+{
+	__list_add(add, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+_INLINE_ void __list_del(struct list_head * prev,
+				  struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry:	the element to delete from the list.
+ *
+ * list_empty() on @entry does not return true after this, @entry is
+ * in an undefined state.
+ */
+_INLINE_ void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry:	the element to delete from the list.
+ */
+_INLINE_ void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head:	the list to test.
+ */
+_INLINE_ int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+/**
+ * list_entry_is_last - tests whether is entry last in the list
+ * @entry:	the entry to test.
+ * @head:	the list to test.
+ */
+_INLINE_ int list_entry_is_last(struct list_head *entry, struct list_head *head)
+{
+	return head->prev == entry;
+}
+
+/**
+ * list_splice - join two lists
+ * @list:	the new list to add.
+ * @head:	the place to add it in the first list.
+ */
+_INLINE_ void list_splice(struct list_head *list, struct list_head *head)
+{
+	struct list_head *first = list->next;
+
+	if (first != list) {
+		struct list_head *last = list->prev;
+		struct list_head *at = head->next;
+
+		first->prev = head;
+		head->next = first;
+
+		last->next = at;
+		at->prev = last;
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) ({              \
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);   \
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+#define list_first_entry(head, type, member) \
+	((head) && (head)->next != (head) ? list_entry((head)->next, type, member) : NULL)
+
+#define list_last_entry(head, type, member) \
+	((head) && (head)->prev != (head) ? list_entry((head)->prev, type, member) : NULL)
+
+/**
+ * list_for_each - iterate over elements in a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_backwardly - iterate over elements in a list in reverse
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each_backwardly(pos, head) \
+	for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over elements in a list, but don't dereference
+ *                      pos after the body is done (in case it is freed)
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @pnext:	the &struct list_head to use as a pointer to the next item.
+ * @head:	the head for your list (not included in iteration).
+ */
+#define list_for_each_safe(pos, pnext, head) \
+	for (pos = (head)->next, pnext = pos->next; pos != (head); \
+	     pos = pnext, pnext = pos->next)
+
+#define MAX_LIST_LENGTH_BITS 20
+
+/*
+ * Returns a list organized in an intermediate format suited
+ * to chaining of merge() calls: null-terminated, no reserved or
+ * sentinel head node, "prev" links not maintained.
+ */
+_INLINE_ struct list_head *merge(int (*cmp)(struct list_head *a,
+					  struct list_head *b),
+			       struct list_head *a, struct list_head *b)
+{
+	struct list_head head, *tail = &head;
+
+	while (a && b) {
+		/* if equal, take 'a' -- important for sort stability */
+		if ((*cmp)(a, b) <= 0) {
+			tail->next = a;
+			a = a->next;
+		} else {
+			tail->next = b;
+			b = b->next;
+		}
+		tail = tail->next;
+	}
+	tail->next = a ? a : b;
+	return head.next;
+}
+
+/*
+ * Combine final list merge with restoration of standard doubly-linked
+ * list structure.  This approach duplicates code from merge(), but
+ * runs faster than the tidier alternatives of either a separate final
+ * prev-link restoration pass, or maintaining the prev links
+ * throughout.
+ */
+_INLINE_ void merge_and_restore_back_links(int (*cmp)(struct list_head *a,
+						    struct list_head *b),
+					 struct list_head *head,
+					 struct list_head *a, struct list_head *b)
+{
+	struct list_head *tail = head;
+
+	while (a && b) {
+		/* if equal, take 'a' -- important for sort stability */
+		if ((*cmp)(a, b) <= 0) {
+			tail->next = a;
+			a->prev = tail;
+			a = a->next;
+		} else {
+			tail->next = b;
+			b->prev = tail;
+			b = b->next;
+		}
+		tail = tail->next;
+	}
+	tail->next = a ? a : b;
+
+	do {
+		/*
+		 * In worst cases this loop may run many iterations.
+		 * Continue callbacks to the client even though no
+		 * element comparison is needed, so the client's cmp()
+		 * routine can invoke cond_resched() periodically.
+		 */
+		(*cmp)(tail->next, tail->next);
+
+		tail->next->prev = tail;
+		tail = tail->next;
+	} while (tail->next);
+
+	tail->next = head;
+	head->prev = tail;
+}
+
+
+/**
+ * list_sort - sort a list
+ * @head: the list to sort
+ * @cmp: the elements comparison function
+ *
+ * This function implements "merge sort", which has O(nlog(n))
+ * complexity.
+ *
+ * The comparison function @cmp must return a negative value if @a
+ * should sort before @b, and a positive value if @a should sort after
+ * @b. If @a and @b are equivalent, and their original relative
+ * ordering is to be preserved, @cmp must return 0.
+ */
+_INLINE_ void list_sort(struct list_head *head,
+			int (*cmp)(struct list_head *a,
+				   struct list_head *b))
+{
+	struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
+							   -- last slot is a sentinel */
+	size_t lev;  /* index into part[] */
+	size_t max_lev = 0;
+	struct list_head *list;
+
+	if (list_empty(head))
+		return;
+
+	memset(part, 0, sizeof(part));
+
+	head->prev->next = NULL;
+	list = head->next;
+
+	while (list) {
+		struct list_head *cur = list;
+		list = list->next;
+		cur->next = NULL;
+
+		for (lev = 0; part[lev]; lev++) {
+			cur = merge(cmp, part[lev], cur);
+			part[lev] = NULL;
+		}
+		if (lev > max_lev) {
+			/* list passed to list_sort() too long for efficiency */
+			if (lev >= ARRAY_SIZE(part) - 1)
+				lev--;
+			max_lev = lev;
+		}
+		part[lev] = cur;
+	}
+
+	for (lev = 0; lev < max_lev; lev++)
+		if (part[lev])
+			list = merge(cmp, part[lev], list);
+
+	merge_and_restore_back_links(cmp, head, part[max_lev], list);
+}
+
+#undef _INLINE_
+
+#endif /* UTIL_LINUX_LIST_H */
diff --git a/libblkid/src/llseek.c b/libblkid/src/llseek.c
new file mode 100644
index 0000000..6733478
--- /dev/null
+++ b/libblkid/src/llseek.c
@@ -0,0 +1,142 @@
+/*
+ * llseek.c -- stub calling the llseek system call
+ *
+ * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef __MSDOS__
+#include <io.h>
+#endif
+
+#include "blkidP.h"
+
+#ifdef __linux__
+
+#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
+
+#define my_llseek lseek64
+
+#elif defined(HAVE_LLSEEK)
+#include <syscall.h>
+
+#ifndef HAVE_LLSEEK_PROTOTYPE
+extern long long llseek(int fd, long long offset, int origin);
+#endif
+
+#define my_llseek llseek
+
+#else	/* ! HAVE_LLSEEK */
+
+#if SIZEOF_LONG == SIZEOF_LONG_LONG
+
+#define llseek lseek
+
+#else /* SIZEOF_LONG != SIZEOF_LONG_LONG */
+
+#include <linux/unistd.h>
+
+#ifndef __NR__llseek
+#define __NR__llseek            140
+#endif
+
+#ifndef __i386__
+static int _llseek(unsigned int, unsigned long, unsigned long,
+		   blkid_loff_t *, unsigned int);
+
+static _syscall5(int, _llseek, unsigned int, fd, unsigned long, offset_high,
+		 unsigned long, offset_low, blkid_loff_t *, result,
+		 unsigned int, origin)
+#endif
+/*
+static blkid_loff_t my_llseek(int fd, blkid_loff_t offset, int origin)
+{
+	blkid_loff_t result;
+	int retval;
+
+#ifndef __i386__
+	retval = _llseek(fd, ((unsigned long long) offset) >> 32,
+			 ((unsigned long long)offset) & 0xffffffff,
+			 &result, origin);
+#else
+	retval = syscall(__NR__llseek, fd, ((unsigned long long) offset) >> 32,
+			 ((unsigned long long)offset) & 0xffffffff,
+			 &result, origin);
+#endif
+	return (retval == -1 ? (blkid_loff_t) retval : result);
+}
+*/
+#endif	/* __alpha__ || __ia64__ */
+
+#endif /* HAVE_LLSEEK */
+
+blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence)
+{
+	blkid_loff_t result;
+	static int do_compat = 0;
+
+	if ((sizeof(off_t) >= sizeof(blkid_loff_t)) ||
+	    (offset < ((blkid_loff_t) 1 << ((sizeof(off_t)*8) -1))))
+		return lseek(fd, (off_t) offset, whence);
+
+	if (do_compat) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+
+	result = lseek64(fd, offset, whence);
+	if (result == -1 && errno == ENOSYS) {
+		/*
+		 * Just in case this code runs on top of an old kernel
+		 * which does not support the llseek system call
+		 */
+		do_compat++;
+		errno = EOVERFLOW;
+	}
+	return result;
+}
+
+#else /* !linux */
+
+#ifndef EOVERFLOW
+#ifdef EXT2_ET_INVALID_ARGUMENT
+#define EOVERFLOW EXT2_ET_INVALID_ARGUMENT
+#else
+#define EOVERFLOW 112
+#endif
+#endif
+
+blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int origin)
+{
+#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
+	return lseek64 (fd, offset, origin);
+#else
+	if ((sizeof(off_t) < sizeof(blkid_loff_t)) &&
+	    (offset >= ((blkid_loff_t) 1 << ((sizeof(off_t)*8) - 1)))) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	return lseek(fd, (off_t) offset, origin);
+#endif
+}
+
+#endif	/* linux */
+
+
diff --git a/libblkid/src/loopdev.h b/libblkid/src/loopdev.h
new file mode 100644
index 0000000..573a569
--- /dev/null
+++ b/libblkid/src/loopdev.h
@@ -0,0 +1,193 @@
+#ifndef UTIL_LINUX_LOOPDEV_H
+#define UTIL_LINUX_LOOPDEV_H
+
+#include "sysfs.h"
+
+/*
+ * loop_info.lo_encrypt_type
+ */
+#define LO_CRYPT_NONE	0
+#define LO_CRYPT_XOR	1
+#define LO_CRYPT_DES	2
+#define LO_CRYPT_CRYPTOAPI 18
+
+#define LOOP_SET_FD		0x4C00
+#define LOOP_CLR_FD		0x4C01
+/*
+ * Obsolete (kernel < 2.6)
+ *
+ * #define LOOP_SET_STATUS	0x4C02
+ * #define LOOP_GET_STATUS	0x4C03
+ */
+#define LOOP_SET_STATUS64	0x4C04
+#define LOOP_GET_STATUS64	0x4C05
+/* #define LOOP_CHANGE_FD	0x4C06 */
+#define LOOP_SET_CAPACITY	0x4C07
+
+/* /dev/loop-control interface */
+#ifndef LOOP_CTL_ADD
+# define LOOP_CTL_ADD		0x4C80
+# define LOOP_CTL_REMOVE	0x4C81
+# define LOOP_CTL_GET_FREE	0x4C82
+#endif
+
+/*
+ * loop_info.lo_flags
+ */
+enum {
+	LO_FLAGS_READ_ONLY  = 1,
+	LO_FLAGS_USE_AOPS   = 2,
+	LO_FLAGS_AUTOCLEAR  = 4,	/* kernel >= 2.6.25 */
+	LO_FLAGS_PARTSCAN   = 8,	/* kernel >= 3.2 */
+};
+
+#define LO_NAME_SIZE	64
+#define LO_KEY_SIZE	32
+
+/*
+ * Linux LOOP_{SET,GET}_STATUS64 ioctl struct
+ */
+struct loop_info64 {
+	uint64_t	lo_device;
+	uint64_t	lo_inode;
+	uint64_t	lo_rdevice;
+	uint64_t	lo_offset;
+	uint64_t	lo_sizelimit; /* bytes, 0 == max available */
+	uint32_t	lo_number;
+	uint32_t	lo_encrypt_type;
+	uint32_t	lo_encrypt_key_size;
+	uint32_t	lo_flags;
+	uint8_t		lo_file_name[LO_NAME_SIZE];
+	uint8_t		lo_crypt_name[LO_NAME_SIZE];
+	uint8_t		lo_encrypt_key[LO_KEY_SIZE];
+	uint64_t	lo_init[2];
+};
+
+#define LOOPDEV_MAJOR		7	/* loop major number */
+#define LOOPDEV_DEFAULT_NNODES	8	/* default number of loop devices */
+
+struct loopdev_iter {
+	FILE		*proc;		/* /proc/partitions */
+	DIR		*sysblock;	/* /sys/block */
+	int		ncur;		/* current position */
+	int		*minors;	/* ary of minor numbers (when scan whole /dev) */
+	int		nminors;	/* number of items in *minors */
+	int		ct_perm;	/* count permission problems */
+	int		ct_succ;	/* count number of detected devices */
+
+	unsigned int	done:1;		/* scanning done */
+	unsigned int	default_check:1;/* check first LOOPDEV_NLOOPS */
+	int		flags;		/* LOOPITER_FL_* flags */
+};
+
+enum {
+	LOOPITER_FL_FREE	= (1 << 0),
+	LOOPITER_FL_USED	= (1 << 1)
+};
+
+/*
+ * handler for work with loop devices
+ */
+struct loopdev_cxt {
+	char		device[128];	/* device path (e.g. /dev/loop<N>) */
+	char		*filename;	/* backing file for loopcxt_set_... */
+	int		fd;		/* open(/dev/looo<N>) */
+	int		mode;		/* fd mode O_{RDONLY,RDWR} */
+
+	int		flags;		/* LOOPDEV_FL_* flags */
+	unsigned int	has_info:1;	/* .info contains data */
+	unsigned int	extra_check:1;	/* unusual stuff for iterator */
+	unsigned int	info_failed:1;	/* LOOP_GET_STATUS ioctl failed */
+	unsigned int    control_ok:1;	/* /dev/loop-control success */
+
+	struct sysfs_cxt	sysfs;	/* pointer to /sys/dev/block/<maj:min>/ */
+	struct loop_info64	info;	/* for GET/SET ioctl */
+	struct loopdev_iter	iter;	/* scans /sys or /dev for used/free devices */
+};
+
+#define UL_LOOPDEVCXT_EMPTY { .fd = -1, .sysfs = UL_SYSFSCXT_EMPTY }
+
+/*
+ * loopdev_cxt.flags
+ */
+enum {
+	LOOPDEV_FL_RDONLY	= (1 << 0),	/* open(/dev/loop) mode; default */
+	LOOPDEV_FL_RDWR		= (1 << 1),	/* necessary for loop setup only */
+	LOOPDEV_FL_OFFSET	= (1 << 4),
+	LOOPDEV_FL_NOSYSFS	= (1 << 5),
+	LOOPDEV_FL_NOIOCTL	= (1 << 6),
+	LOOPDEV_FL_DEVSUBDIR	= (1 << 7),
+	LOOPDEV_FL_CONTROL	= (1 << 8),	/* system with /dev/loop-control */
+	LOOPDEV_FL_SIZELIMIT	= (1 << 9)
+};
+
+/*
+ * High-level
+ */
+extern int loopmod_supports_partscan(void);
+
+extern int is_loopdev(const char *device);
+extern int loopdev_is_autoclear(const char *device);
+
+extern char *loopdev_get_backing_file(const char *device);
+extern int loopdev_is_used(const char *device, const char *filename,
+			   uint64_t offset, int flags);
+extern char *loopdev_find_by_backing_file(const char *filename,
+					  uint64_t offset, int flags);
+extern int loopcxt_find_unused(struct loopdev_cxt *lc);
+extern int loopdev_delete(const char *device);
+extern int loopdev_count_by_backing_file(const char *filename, char **loopdev);
+
+/*
+ * Low-level
+ */
+extern int loopcxt_init(struct loopdev_cxt *lc, int flags)
+				__attribute__ ((warn_unused_result));
+extern void loopcxt_deinit(struct loopdev_cxt *lc);
+
+extern int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
+				__attribute__ ((warn_unused_result));
+extern int loopcxt_has_device(struct loopdev_cxt *lc);
+extern int loopcxt_add_device(struct loopdev_cxt *lc);
+extern char *loopcxt_strdup_device(struct loopdev_cxt *lc);
+extern const char *loopcxt_get_device(struct loopdev_cxt *lc);
+extern struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc);
+extern struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc);
+
+extern int loopcxt_get_fd(struct loopdev_cxt *lc);
+extern int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode);
+
+extern int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags);
+extern int loopcxt_deinit_iterator(struct loopdev_cxt *lc);
+extern int loopcxt_next(struct loopdev_cxt *lc);
+
+extern int loopcxt_setup_device(struct loopdev_cxt *lc);
+extern int loopcxt_delete_device(struct loopdev_cxt *lc);
+extern int loopcxt_set_capacity(struct loopdev_cxt *lc);
+
+int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset);
+int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit);
+int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags);
+int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename);
+
+extern char *loopcxt_get_backing_file(struct loopdev_cxt *lc);
+extern int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno);
+extern int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino);
+extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset);
+extern int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size);
+extern int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type);
+extern const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc);
+extern int loopcxt_is_autoclear(struct loopdev_cxt *lc);
+extern int loopcxt_is_readonly(struct loopdev_cxt *lc);
+extern int loopcxt_is_partscan(struct loopdev_cxt *lc);
+extern int loopcxt_find_by_backing_file(struct loopdev_cxt *lc,
+				const char *filename,
+                                uint64_t offset, int flags);
+
+extern int loopcxt_is_used(struct loopdev_cxt *lc,
+                    struct stat *st,
+                    const char *backing_file,
+                    uint64_t offset,
+                    int flags);
+
+#endif /* UTIL_LINUX_LOOPDEV_H */
diff --git a/libblkid/src/mangle.h b/libblkid/src/mangle.h
new file mode 100644
index 0000000..ec492b5
--- /dev/null
+++ b/libblkid/src/mangle.h
@@ -0,0 +1,26 @@
+#ifndef UTIL_LINUX_MANGLE_H
+#define UTIL_LINUX_MANGLE_H
+
+/*
+ * Functions for \oct encoding used in mtab/fstab/swaps/etc.
+ */
+
+extern char *mangle(const char *s);
+
+extern void unmangle_to_buffer(const char *s, char *buf, size_t len);
+void unhexmangle_to_buffer(const char *s, char *buf, size_t len);
+
+extern char *unmangle(const char *s, char **end);
+
+static inline void unmangle_string(char *s)
+{
+	unmangle_to_buffer(s, s, strlen(s) + 1);
+}
+
+static inline void unhexmangle_string(char *s)
+{
+	unhexmangle_to_buffer(s, s, strlen(s) + 1);
+}
+
+#endif /* UTIL_LINUX_MANGLE_H */
+
diff --git a/libblkid/src/match.h b/libblkid/src/match.h
new file mode 100644
index 0000000..94440c2
--- /dev/null
+++ b/libblkid/src/match.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_MATCH_H
+#define UTIL_LINUX_MATCH_H
+
+extern int match_fstype(const char *type, const char *pattern);
+
+#endif /* UTIL_LINUX_MATCH_H */
diff --git a/libblkid/src/mbsalign.h b/libblkid/src/mbsalign.h
new file mode 100644
index 0000000..5eaf606
--- /dev/null
+++ b/libblkid/src/mbsalign.h
@@ -0,0 +1,56 @@
+/* Align/Truncate a string in a given screen width
+   Copyright (C) 2009-2010 Free Software Foundation, Inc.
+   Copyright (C) 2010-2013 Karel Zak <kzak@redhat.com>
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 2.1 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+#ifndef UTIL_LINUX_MBSALIGN_H
+# define UTIL_LINUX_MBSALIGN_H
+# include <stddef.h>
+
+typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t;
+
+enum {
+  /* Use unibyte mode for invalid multibyte strings or
+     or when heap memory is exhausted.  */
+  MBA_UNIBYTE_FALLBACK = 0x0001,
+
+#if 0 /* Other possible options.  */
+  /* Skip invalid multibyte chars rather than failing  */
+  MBA_IGNORE_INVALID   = 0x0002,
+
+  /* Align multibyte strings using "figure space" (\u2007)  */
+  MBA_USE_FIGURE_SPACE = 0x0004,
+
+  /* Don't add any padding  */
+  MBA_TRUNCATE_ONLY    = 0x0008,
+
+  /* Don't truncate  */
+  MBA_PAD_ONLY         = 0x0010,
+#endif
+};
+
+extern size_t mbs_truncate(char *str, size_t *width);
+
+extern size_t mbsalign (const char *src, char *dest,
+			size_t dest_size,  size_t *width,
+			mbs_align_t align, int flags);
+
+extern size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz);
+extern size_t mbs_safe_width(const char *s);
+
+extern char *mbs_safe_encode(const char *s, size_t *width);
+extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf);
+extern size_t mbs_safe_encode_size(size_t bytes);
+
+#endif /* UTIL_LINUX_MBSALIGN_H */
diff --git a/libblkid/src/md5.h b/libblkid/src/md5.h
new file mode 100644
index 0000000..d997e37
--- /dev/null
+++ b/libblkid/src/md5.h
@@ -0,0 +1,29 @@
+#ifndef MD5_H
+#define MD5_H
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+#endif
+
+#define MD5LENGTH 16
+
+struct MD5Context {
+	uint32_t buf[4];
+	uint32_t bits[2];
+	unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+	       unsigned len);
+void MD5Final(unsigned char digest[MD5LENGTH], struct MD5Context *context);
+void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* !MD5_H */
diff --git a/libblkid/src/nls.h b/libblkid/src/nls.h
new file mode 100644
index 0000000..3eabfe6
--- /dev/null
+++ b/libblkid/src/nls.h
@@ -0,0 +1,115 @@
+#ifndef UTIL_LINUX_NLS_H
+#define UTIL_LINUX_NLS_H
+
+int main(int argc, char *argv[]);
+
+#ifndef LOCALEDIR
+#define LOCALEDIR "/usr/share/locale"
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#else
+# undef setlocale
+# define setlocale(Category, Locale) /* empty */
+struct lconv
+{
+	char *decimal_point;
+};
+# undef localeconv
+# define localeconv() NULL
+#endif
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+# ifdef gettext_noop
+#  define N_(String) gettext_noop (String)
+# else
+#  define N_(String) (String)
+# endif
+# define P_(Singular, Plural, n) ngettext (Singular, Plural, n)
+#else
+# undef bindtextdomain
+# define bindtextdomain(Domain, Directory) /* empty */
+# undef textdomain
+# define textdomain(Domain) /* empty */
+# define _(Text) (Text)
+# define N_(Text) (Text)
+# define P_(Singular, Plural, n) ((n) == 1 ? (Singular) : (Plural))
+#endif
+
+#ifdef HAVE_LANGINFO_H
+# include <langinfo.h>
+#else
+
+typedef int nl_item;
+extern char *langinfo_fallback(nl_item item);
+
+# define nl_langinfo	langinfo_fallback
+
+enum {
+	CODESET = 1,
+	RADIXCHAR,
+	THOUSEP,
+	D_T_FMT,
+	D_FMT,
+	T_FMT,
+	T_FMT_AMPM,
+	AM_STR,
+	PM_STR,
+
+	DAY_1,
+	DAY_2,
+	DAY_3,
+	DAY_4,
+	DAY_5,
+	DAY_6,
+	DAY_7,
+
+	ABDAY_1,
+	ABDAY_2,
+	ABDAY_3,
+	ABDAY_4,
+	ABDAY_5,
+	ABDAY_6,
+	ABDAY_7,
+
+	MON_1,
+	MON_2,
+	MON_3,
+	MON_4,
+	MON_5,
+	MON_6,
+	MON_7,
+	MON_8,
+	MON_9,
+	MON_10,
+	MON_11,
+	MON_12,
+
+	ABMON_1,
+	ABMON_2,
+	ABMON_3,
+	ABMON_4,
+	ABMON_5,
+	ABMON_6,
+	ABMON_7,
+	ABMON_8,
+	ABMON_9,
+	ABMON_10,
+	ABMON_11,
+	ABMON_12,
+
+	ERA_D_FMT,
+	ERA_D_T_FMT,
+	ERA_T_FMT,
+	ALT_DIGITS,
+	CRNCYSTR,
+	YESEXPR,
+	NOEXPR
+};
+
+#endif /* !HAVE_LANGINFO_H */
+
+#endif /* UTIL_LINUX_NLS_H */
diff --git a/libblkid/src/partitions/aix.c b/libblkid/src/partitions/aix.c
new file mode 100644
index 0000000..4efdfa3
--- /dev/null
+++ b/libblkid/src/partitions/aix.c
@@ -0,0 +1,57 @@
+/*
+ * aix partitions
+ *
+ * Copyright (C) 2009 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 <stdint.h>
+
+#include "partitions.h"
+#include "aix.h"
+
+static int probe_aix_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	blkid_partlist ls;
+	blkid_parttable tab;
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return BLKID_PROBE_OK;
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		return BLKID_PROBE_NONE;
+
+	tab = blkid_partlist_new_parttable(ls, "aix", 0);
+	if (!tab)
+		return -ENOMEM;
+
+	return BLKID_PROBE_OK;
+}
+
+/*
+ * We know nothing about AIX on-disk structures. Everything what we know is the
+ * magic number at begin of the disk.
+ *
+ * Note, Linux kernel is tring to be smart and AIX signature is ignored when
+ * there is a valid DOS partitions table. We don't support such behavior. All
+ * fdisk-like programs has to properly wipe the fist sector. Everything other
+ * is a bug.
+ */
+const struct blkid_idinfo aix_pt_idinfo =
+{
+	.name		= "aix",
+	.probefunc	= probe_aix_pt,
+	.magics		=
+	{
+		{ .magic = BLKID_AIX_MAGIC_STRING, .len = BLKID_AIX_MAGIC_STRLEN },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/partitions/aix.h b/libblkid/src/partitions/aix.h
new file mode 100644
index 0000000..f767c5a
--- /dev/null
+++ b/libblkid/src/partitions/aix.h
@@ -0,0 +1,7 @@
+#ifndef BLKID_PARTITIONS_AIX_H
+#define BLKID_PARTITIONS_AIX_H
+
+#define BLKID_AIX_MAGIC_STRING	"\xC9\xC2\xD4\xC1"
+#define BLKID_AIX_MAGIC_STRLEN	(sizeof(BLKID_AIX_MAGIC_STRING) - 1)
+
+#endif
diff --git a/libblkid/src/partitions/bsd.c b/libblkid/src/partitions/bsd.c
new file mode 100644
index 0000000..d83f2cf
--- /dev/null
+++ b/libblkid/src/partitions/bsd.c
@@ -0,0 +1,179 @@
+/*
+ * BSD/OSF partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Inspired by fdisk, partx, Linux kernel, libparted and openbsd header files.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+#include "pt-bsd.h"
+
+/* Returns 'blkid_idmag' in 512-sectors */
+#define BLKID_MAG_SECTOR(_mag)  (((_mag)->kboff / 2)  + ((_mag)->sboff >> 9))
+
+/* Returns 'blkid_idmag' in bytes */
+#define BLKID_MAG_OFFSET(_mag)  ((_mag)->kboff << 10) + ((_mag)->sboff)
+
+/* Returns 'blkid_idmag' offset in bytes within the last sector */
+#define BLKID_MAG_LASTOFFSET(_mag) \
+		 (BLKID_MAG_OFFSET(_mag) - (BLKID_MAG_SECTOR(_mag) << 9))
+
+static int probe_bsd_pt(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct bsd_disklabel *l;
+	struct bsd_partition *p;
+	const char *name = "bsd" ;
+	blkid_parttable tab = NULL;
+	blkid_partition parent;
+	blkid_partlist ls;
+	int i, nparts = BSD_MAXPARTITIONS;
+	unsigned char *data;
+	int rc = BLKID_PROBE_NONE;
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return rc;
+
+	data = blkid_probe_get_sector(pr, BLKID_MAG_SECTOR(mag));
+	if (!data) {
+		if (errno)
+			rc = -errno;
+		goto nothing;
+	}
+
+	l = (struct bsd_disklabel *) data + BLKID_MAG_LASTOFFSET(mag);
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	/* try to determine the real type of BSD system according to
+	 * (parental) primary partition */
+	parent = blkid_partlist_get_parent(ls);
+	if (parent) {
+		switch(blkid_partition_get_type(parent)) {
+		case MBR_FREEBSD_PARTITION:
+			name = "freebsd";
+			break;
+		case MBR_NETBSD_PARTITION:
+			name = "netbsd";
+			break;
+		case MBR_OPENBSD_PARTITION:
+			name = "openbsd";
+			break;
+		default:
+			DBG(LOWPROBE, ul_debug(
+				"WARNING: BSD label detected on unknown (0x%x) "
+				"primary partition",
+				blkid_partition_get_type(parent)));
+			break;
+		}
+	}
+
+	tab = blkid_partlist_new_parttable(ls, name, BLKID_MAG_OFFSET(mag));
+	if (!tab) {
+		rc = -ENOMEM;
+		goto nothing;
+	}
+
+	if (le16_to_cpu(l->d_npartitions) < BSD_MAXPARTITIONS)
+		nparts = le16_to_cpu(l->d_npartitions);
+
+	else if (le16_to_cpu(l->d_npartitions) > BSD_MAXPARTITIONS)
+		DBG(LOWPROBE, ul_debug(
+			"WARNING: ignore %d more BSD partitions",
+			le16_to_cpu(l->d_npartitions) - BSD_MAXPARTITIONS));
+
+	for (i = 0, p = l->d_partitions; i < nparts; i++, p++) {
+		blkid_partition par;
+		uint32_t start, size;
+
+		/* TODO: in fdisk-mode returns all non-zero (p_size) partitions */
+		if (p->p_fstype == BSD_FS_UNUSED)
+			continue;
+
+		start = le32_to_cpu(p->p_offset);
+		size = le32_to_cpu(p->p_size);
+
+		if (parent && blkid_partition_get_start(parent) == start
+			   && blkid_partition_get_size(parent) == size) {
+			DBG(LOWPROBE, ul_debug(
+				"WARNING: BSD partition (%d) same like parent, "
+				"ignore", i));
+			continue;
+		}
+		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
+			DBG(LOWPROBE, ul_debug(
+				"WARNING: BSD partition (%d) overflow "
+				"detected, ignore", i));
+			continue;
+		}
+
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par) {
+			rc = -ENOMEM;
+			goto nothing;
+		}
+
+		blkid_partition_set_type(par, p->p_fstype);
+	}
+
+	return BLKID_PROBE_OK;
+
+nothing:
+	return rc;
+}
+
+
+/*
+ * All BSD variants use the same magic string (little-endian),
+ * and the same disklabel.
+ *
+ * The difference between {Free,Open,...}BSD is in the (parental)
+ * primary partition type.
+ *
+ * See also: http://en.wikipedia.org/wiki/BSD_disklabel
+ *
+ * The location of BSD disk label is architecture specific and in defined by
+ * LABELSECTOR and LABELOFFSET macros in the disklabel.h file. The location
+ * also depends on BSD variant, FreeBSD uses only one location, NetBSD and
+ * OpenBSD are more creative...
+ *
+ * The basic overview:
+ *
+ * arch                    | LABELSECTOR | LABELOFFSET
+ * ------------------------+-------------+------------
+ * amd64 arm hppa hppa64   |             |
+ * i386, macppc, mvmeppc   |      1      |      0
+ * sgi, aviion, sh, socppc |             |
+ * ------------------------+-------------+------------
+ * alpha luna88k mac68k    |      0      |     64
+ * sparc(OpenBSD) vax      |             |
+ * ------------------------+-------------+------------
+ * sparc64 sparc(NetBSD)   |      0      |    128
+ * ------------------------+-------------+------------
+ *
+ * ...and more (see http://fxr.watson.org/fxr/ident?v=NETBSD;i=LABELSECTOR)
+ *
+ */
+const struct blkid_idinfo bsd_pt_idinfo =
+{
+	.name		= "bsd",
+	.probefunc	= probe_bsd_pt,
+	.magics		=
+	{
+		{ .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 512 },
+		{ .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 64 },
+		{ .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 128 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/partitions/dos.c b/libblkid/src/partitions/dos.c
new file mode 100644
index 0000000..2539908
--- /dev/null
+++ b/libblkid/src/partitions/dos.c
@@ -0,0 +1,307 @@
+/*
+ * MS-DOS partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Inspired by fdisk, partx, Linux kernel and libparted.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+#include "aix.h"
+
+/* see superblocks/vfat.c */
+extern int blkid_probe_is_vfat(blkid_probe pr);
+
+static const struct dos_subtypes {
+	unsigned char type;
+	const struct blkid_idinfo *id;
+} dos_nested[] = {
+	{ MBR_FREEBSD_PARTITION, &bsd_pt_idinfo },
+	{ MBR_NETBSD_PARTITION, &bsd_pt_idinfo },
+	{ MBR_OPENBSD_PARTITION, &bsd_pt_idinfo },
+	{ MBR_UNIXWARE_PARTITION, &unixware_pt_idinfo },
+	{ MBR_SOLARIS_X86_PARTITION, &solaris_x86_pt_idinfo },
+	{ MBR_MINIX_PARTITION, &minix_pt_idinfo }
+};
+
+static inline int is_extended(struct dos_partition *p)
+{
+	return (p->sys_ind == MBR_DOS_EXTENDED_PARTITION ||
+		p->sys_ind == MBR_W95_EXTENDED_PARTITION ||
+		p->sys_ind == MBR_LINUX_EXTENDED_PARTITION);
+}
+
+static int parse_dos_extended(blkid_probe pr, blkid_parttable tab,
+		uint32_t ex_start, uint32_t ex_size, int ssf)
+{
+	blkid_partlist ls = blkid_probe_get_partlist(pr);
+	uint32_t cur_start = ex_start, cur_size = ex_size;
+	unsigned char *data;
+	int ct_nodata = 0;	/* count ext.partitions without data partitions */
+	int i;
+
+	while (1) {
+		struct dos_partition *p, *p0;
+		uint32_t start, size;
+
+		if (++ct_nodata > 100)
+			return BLKID_PROBE_OK;
+		data = blkid_probe_get_sector(pr, cur_start);
+		if (!data) {
+			if (errno)
+				return -errno;
+			goto leave;	/* malformed partition? */
+		}
+
+		if (!mbr_is_valid_magic(data))
+			goto leave;
+
+		p0 = mbr_get_partition(data, 0);
+
+		/* Usually, the first entry is the real data partition,
+		 * the 2nd entry is the next extended partition, or empty,
+		 * and the 3rd and 4th entries are unused.
+		 * However, DRDOS sometimes has the extended partition as
+		 * the first entry (when the data partition is empty),
+		 * and OS/2 seems to use all four entries.
+		 * -- Linux kernel fs/partitions/dos.c
+		 *
+		 * See also http://en.wikipedia.org/wiki/Extended_boot_record
+		 */
+
+		/* Parse data partition */
+		for (p = p0, i = 0; i < 4; i++, p++) {
+			uint32_t abs_start;
+			blkid_partition par;
+
+			/* the start is relative to the parental ext.partition */
+			start = dos_partition_get_start(p) * ssf;
+			size = dos_partition_get_size(p) * ssf;
+			abs_start = cur_start + start;	/* absolute start */
+
+			if (!size || is_extended(p))
+				continue;
+			if (i >= 2) {
+				/* extra checks to detect real data on
+				 * 3rd and 4th entries */
+				if (start + size > cur_size)
+					continue;
+				if (abs_start < ex_start)
+					continue;
+				if (abs_start + size > ex_start + ex_size)
+					continue;
+			}
+
+			par = blkid_partlist_add_partition(ls, tab, abs_start, size);
+			if (!par)
+				return -ENOMEM;
+
+			blkid_partition_set_type(par, p->sys_ind);
+			blkid_partition_set_flags(par, p->boot_ind);
+			blkid_partition_gen_uuid(par);
+			ct_nodata = 0;
+		}
+		/* The first nested ext.partition should be a link to the next
+		 * logical partition. Everything other (recursive ext.partitions)
+		 * is junk.
+		 */
+		for (p = p0, i = 0; i < 4; i++, p++) {
+			start = dos_partition_get_start(p) * ssf;
+			size = dos_partition_get_size(p) * ssf;
+
+			if (size && is_extended(p))
+				break;
+		}
+		if (i == 4)
+			goto leave;
+
+		cur_start = ex_start + start;
+		cur_size = size;
+	}
+leave:
+	return BLKID_PROBE_OK;
+}
+
+static int probe_dos_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	int i;
+	int ssf;
+	blkid_parttable tab = NULL;
+	blkid_partlist ls;
+	struct dos_partition *p0, *p;
+	unsigned char *data;
+	uint32_t start, size, id;
+	char idstr[37];
+
+
+	data = blkid_probe_get_sector(pr, 0);
+	if (!data) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	/* ignore disks with AIX magic number -- for more details see aix.c */
+	if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0)
+		goto nothing;
+
+	/*
+	 * Now that the 55aa signature is present, this is probably
+	 * either the boot sector of a FAT filesystem or a DOS-type
+	 * partition table.
+	 */
+	if (blkid_probe_is_vfat(pr) == 1) {
+		DBG(LOWPROBE, ul_debug("probably FAT -- ignore"));
+		goto nothing;
+	}
+
+	p0 = mbr_get_partition(data, 0);
+
+	/*
+	 * Reject PT where boot indicator is not 0 or 0x80.
+	 */
+	for (p = p0, i = 0; i < 4; i++, p++)
+		if (p->boot_ind != 0 && p->boot_ind != 0x80) {
+			DBG(LOWPROBE, ul_debug("missing boot indicator -- ignore"));
+			goto nothing;
+		}
+
+	/*
+	 * GPT uses valid MBR
+	 */
+	for (p = p0, i = 0; i < 4; i++, p++) {
+		if (p->sys_ind == MBR_GPT_PARTITION) {
+			DBG(LOWPROBE, ul_debug("probably GPT -- ignore"));
+			goto nothing;
+		}
+	}
+
+	blkid_probe_use_wiper(pr, MBR_PT_OFFSET, 512 - MBR_PT_OFFSET);
+
+	id = mbr_get_id(data);
+	if (id)
+		snprintf(idstr, sizeof(idstr), "%08x", id);
+
+	/*
+	 * Well, all checks pass, it's MS-DOS partiton table
+	 */
+	if (blkid_partitions_need_typeonly(pr)) {
+		/* Non-binary interface -- caller does not ask for details
+		 * about partitions, just set generic varibles only. */
+		if (id)
+			blkid_partitions_strcpy_ptuuid(pr, idstr);
+		return 0;
+	}
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	/* sector size factor (the start and size are in the real sectors, but
+	 * we need to convert all sizes to 512 logical sectors
+	 */
+	ssf = blkid_probe_get_sectorsize(pr) / 512;
+
+	/* allocate a new partition table */
+	tab = blkid_partlist_new_parttable(ls, "dos", MBR_PT_OFFSET);
+	if (!tab)
+		return -ENOMEM;
+
+	if (id)
+		blkid_parttable_set_id(tab, (unsigned char *) idstr);
+
+	/* Parse primary partitions */
+	for (p = p0, i = 0; i < 4; i++, p++) {
+		blkid_partition par;
+
+		start = dos_partition_get_start(p) * ssf;
+		size = dos_partition_get_size(p) * ssf;
+
+		if (!size) {
+			/* Linux kernel ignores empty partitions, but partno for
+			 * the empty primary partitions is not reused */
+			blkid_partlist_increment_partno(ls);
+			continue;
+		}
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par)
+			return -ENOMEM;
+
+		blkid_partition_set_type(par, p->sys_ind);
+		blkid_partition_set_flags(par, p->boot_ind);
+		blkid_partition_gen_uuid(par);
+	}
+
+	/* Linux uses partition numbers greater than 4
+	 * for all logical partition and all nested partition tables (bsd, ..)
+	 */
+	blkid_partlist_set_partno(ls, 5);
+
+	/* Parse logical partitions */
+	for (p = p0, i = 0; i < 4; i++, p++) {
+		start = dos_partition_get_start(p) * ssf;
+		size = dos_partition_get_size(p) * ssf;
+
+		if (!size)
+			continue;
+		if (is_extended(p) &&
+		    parse_dos_extended(pr, tab, start, size, ssf) == -1)
+			goto nothing;
+	}
+
+	/* Parse subtypes (nested partitions) on large disks */
+	if (!blkid_probe_is_tiny(pr)) {
+		for (p = p0, i = 0; i < 4; i++, p++) {
+			size_t n;
+			int rc;
+
+			if (!dos_partition_get_size(p) || is_extended(p))
+				continue;
+
+			for (n = 0; n < ARRAY_SIZE(dos_nested); n++) {
+				if (dos_nested[n].type != p->sys_ind)
+					continue;
+
+				rc = blkid_partitions_do_subprobe(pr,
+						blkid_partlist_get_partition(ls, i),
+						dos_nested[n].id);
+				if (rc < 0)
+					return rc;
+				break;
+			}
+		}
+	}
+	return BLKID_PROBE_OK;
+
+nothing:
+	return BLKID_PROBE_NONE;
+}
+
+
+const struct blkid_idinfo dos_pt_idinfo =
+{
+	.name		= "dos",
+	.probefunc	= probe_dos_pt,
+	.magics		=
+	{
+		/* DOS master boot sector:
+		 *
+		 *     0 | Code Area
+		 *   440 | Optional Disk signature
+		 *   446 | Partition table
+		 *   510 | 0x55
+		 *   511 | 0xAA
+		 */
+		{ .magic = "\x55\xAA", .len = 2, .sboff = 510 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/partitions/gpt.c b/libblkid/src/partitions/gpt.c
new file mode 100644
index 0000000..665577f
--- /dev/null
+++ b/libblkid/src/partitions/gpt.c
@@ -0,0 +1,470 @@
+/*
+ * EFI GPT partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * This code is not copy & past from any other implementation.
+ *
+ * For more information about GPT start your study at:
+ * http://en.wikipedia.org/wiki/GUID_Partition_Table
+ * http://technet.microsoft.com/en-us/library/cc739412(WS.10).aspx
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <limits.h>
+
+#include "partitions.h"
+#include "crc32.h"
+
+#define GPT_PRIMARY_LBA	1
+
+/* Signature - “EFI PART” */
+#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
+#define GPT_HEADER_SIGNATURE_STR "EFI PART"
+
+/* basic types */
+typedef uint16_t efi_char16_t;
+
+/* UUID */
+typedef struct {
+	uint32_t time_low;
+	uint16_t time_mid;
+	uint16_t time_hi_and_version;
+	uint8_t clock_seq_hi;
+	uint8_t clock_seq_low;
+	uint8_t node[6];
+} efi_guid_t;
+
+
+#define GPT_UNUSED_ENTRY_GUID \
+	    ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
+	                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
+struct gpt_header {
+	uint64_t	signature;		/* "EFI PART" */
+	uint32_t	revision;
+	uint32_t	header_size;		/* usually 92 bytes */
+	uint32_t	header_crc32;		/* checksum of header with this
+						 * field zeroed during calculation */
+	uint32_t	reserved1;
+
+	uint64_t	my_lba;			/* location of this header copy */
+	uint64_t	alternate_lba;		/* location of the other header copy */
+	uint64_t	first_usable_lba;	/* lirst usable LBA for partitions */
+	uint64_t	last_usable_lba;	/* last usable LBA for partitions */
+
+	efi_guid_t	disk_guid;		/* disk UUID */
+
+	uint64_t	partition_entries_lba;	/* always 2 in primary header copy */
+	uint32_t	num_partition_entries;
+	uint32_t	sizeof_partition_entry;
+	uint32_t	partition_entry_array_crc32;
+
+	/*
+	 * The rest of the block is reserved by UEFI and must be zero. EFI
+	 * standard handles this by:
+	 *
+	 * uint8_t		reserved2[ BLKSSZGET - 92 ];
+	 *
+	 * This definition is useless in practice. It is necessary to read
+	 * whole block from the device rather than sizeof(struct gpt_header)
+	 * only.
+	 */
+} __attribute__ ((packed));
+
+/*** not used
+struct gpt_entry_attributes {
+	uint64_t	required_to_function:1;
+	uint64_t	reserved:47;
+        uint64_t	type_guid_specific:16;
+} __attribute__ ((packed));
+***/
+
+struct gpt_entry {
+	efi_guid_t	partition_type_guid;	/* type UUID */
+	efi_guid_t	unique_partition_guid;	/* partition UUID */
+	uint64_t	starting_lba;
+	uint64_t	ending_lba;
+
+	/*struct gpt_entry_attributes	attributes;*/
+
+	uint64_t	attributes;
+
+	efi_char16_t	partition_name[72 / sizeof(efi_char16_t)]; /* UTF-16LE string*/
+} __attribute__ ((packed));
+
+
+/*
+ * EFI uses crc32 with ~0 seed and xor's with ~0 at the end.
+ */
+static inline uint32_t count_crc32(const unsigned char *buf, size_t len)
+{
+	return (crc32(~0L, buf, len) ^ ~0L);
+}
+
+static inline unsigned char *get_lba_buffer(blkid_probe pr,
+					uint64_t lba, size_t bytes)
+{
+	return blkid_probe_get_buffer(pr,
+			blkid_probe_get_sectorsize(pr) * lba, bytes);
+}
+
+static inline int guidcmp(efi_guid_t left, efi_guid_t right)
+{
+	return memcmp(&left, &right, sizeof (efi_guid_t));
+}
+
+/*
+ * UUID is traditionally 16 byte big-endian array, except Intel EFI
+ * specification where the UUID is a structure of little-endian fields.
+ */
+static void swap_efi_guid(efi_guid_t *uid)
+{
+	uid->time_low = swab32(uid->time_low);
+	uid->time_mid = swab16(uid->time_mid);
+	uid->time_hi_and_version = swab16(uid->time_hi_and_version);
+}
+
+static int last_lba(blkid_probe pr, uint64_t *lba)
+{
+	blkid_loff_t sz = blkid_probe_get_size(pr);
+	unsigned int ssz = blkid_probe_get_sectorsize(pr);
+
+	if (sz < ssz)
+		return -1;
+
+	*lba = (sz / ssz) - 1ULL;
+	return 0;
+}
+
+/*
+ * Protective (legacy) MBR.
+ *
+ * This MBR contains standard DOS partition table with a single partition, type
+ * of 0xEE.  The partition usually encompassing the entire GPT drive - or 2TiB
+ * for large disks.
+ *
+ * Note that Apple uses GPT/MBR hybrid disks, where the DOS partition table is
+ * synchronized with GPT. This synchronization has many restriction of course
+ * (due DOS PT limitations).
+ *
+ * Note that the PMBR detection is optional (enabled by default) and could be
+ * disabled by BLKID_PARTS_FOPCE_GPT flag (see also blkid_paertitions_set_flags()).
+ */
+static int is_pmbr_valid(blkid_probe pr, int *has)
+{
+	int flags = blkid_partitions_get_flags(pr);
+	unsigned char *data;
+	struct dos_partition *p;
+	int i;
+
+	if (has)
+		*has = 0;
+	if (flags & BLKID_PARTS_FORCE_GPT)
+		goto ok;			/* skip PMBR check */
+
+	data = blkid_probe_get_sector(pr, 0);
+	if (!data) {
+		if (errno)
+			return -errno;
+		goto failed;
+	}
+
+	if (!mbr_is_valid_magic(data))
+		goto failed;
+
+	for (i = 0, p = mbr_get_partition(data, 0); i < 4; i++, p++) {
+		if (p->sys_ind == MBR_GPT_PARTITION)
+			goto ok;
+	}
+failed:
+	return 0;
+ok:
+	if (has)
+		*has = 1;
+	return 1;
+}
+
+/*
+ * Reads GPT header to @hdr and returns a pointer to @hdr or NULL in case of
+ * error. The function also returns GPT entries in @ents.
+ *
+ * Note, this function does not allocate any memory. The GPT header has fixed
+ * size so we use stack, and @ents returns memory from libblkid buffer (so the
+ * next blkid_probe_get_buffer() will overwrite this buffer).
+ *
+ * This function checks validity of header and entries array. A corrupted
+ * header is not returned.
+ */
+static struct gpt_header *get_gpt_header(
+				blkid_probe pr, struct gpt_header *hdr,
+				struct gpt_entry **ents, uint64_t lba,
+				uint64_t lastlba)
+{
+	struct gpt_header *h;
+	uint32_t crc, orgcrc;
+	uint64_t lu, fu;
+	size_t esz;
+	uint32_t hsz, ssz;
+
+	ssz = blkid_probe_get_sectorsize(pr);
+
+	/* whole sector is allocated for GPT header */
+	h = (struct gpt_header *) get_lba_buffer(pr, lba, ssz);
+	if (!h)
+		return NULL;
+
+	if (le64_to_cpu(h->signature) != GPT_HEADER_SIGNATURE)
+		return NULL;
+
+	hsz = le32_to_cpu(h->header_size);
+
+	/* EFI: The HeaderSize must be greater than 92 and must be less
+	 *      than or equal to the logical block size.
+	 */
+	if (hsz > ssz || hsz < sizeof(*h))
+		return NULL;
+
+	/* Header has to be verified when header_crc32 is zero */
+	orgcrc = h->header_crc32;
+	h->header_crc32 = 0;
+	crc = count_crc32((unsigned char *) h, hsz);
+	h->header_crc32 = orgcrc;
+
+	if (crc != le32_to_cpu(orgcrc)) {
+		DBG(LOWPROBE, ul_debug("GPT header corrupted"));
+		return NULL;
+	}
+
+	/* Valid header has to be at MyLBA */
+	if (le64_to_cpu(h->my_lba) != lba) {
+		DBG(LOWPROBE, ul_debug(
+			"GPT->MyLBA mismatch with real position"));
+		return NULL;
+	}
+
+	fu = le64_to_cpu(h->first_usable_lba);
+	lu = le64_to_cpu(h->last_usable_lba);
+
+	/* Check if First and Last usable LBA makes sense */
+	if (lu < fu || fu > lastlba || lu > lastlba) {
+		DBG(LOWPROBE, ul_debug(
+			"GPT->{First,Last}UsableLBA out of range"));
+		return NULL;
+	}
+
+	/* The header has to be outside usable range */
+	if (fu < lba && lba < lu) {
+		DBG(LOWPROBE, ul_debug("GPT header is inside usable area"));
+		return NULL;
+	}
+
+	if (le32_to_cpu(h->num_partition_entries) == 0 ||
+	    le32_to_cpu(h->sizeof_partition_entry) == 0 ||
+	    ULONG_MAX / le32_to_cpu(h->num_partition_entries) < le32_to_cpu(h->sizeof_partition_entry)) {
+		DBG(LOWPROBE, ul_debug("GPT entries undefined"));
+		return NULL;
+	}
+
+	/* Size of blocks with GPT entries */
+	esz = le32_to_cpu(h->num_partition_entries) *
+			le32_to_cpu(h->sizeof_partition_entry);
+
+	/* The header seems valid, save it
+	 * (we don't care about zeros in hdr->reserved2 area) */
+	memcpy(hdr, h, sizeof(*h));
+	h = hdr;
+
+	/* Read GPT entries */
+	*ents = (struct gpt_entry *) get_lba_buffer(pr,
+				le64_to_cpu(h->partition_entries_lba), esz);
+	if (!*ents) {
+		DBG(LOWPROBE, ul_debug("GPT entries unreadable"));
+		return NULL;
+	}
+
+	/* Validate entries */
+	crc = count_crc32((unsigned char *) *ents, esz);
+	if (crc != le32_to_cpu(h->partition_entry_array_crc32)) {
+		DBG(LOWPROBE, ul_debug("GPT entries corrupted"));
+		return NULL;
+	}
+
+	return h;
+}
+
+static int probe_gpt_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	uint64_t lastlba = 0, lba;
+	struct gpt_header hdr, *h;
+	struct gpt_entry *e;
+	blkid_parttable tab = NULL;
+	blkid_partlist ls;
+	uint64_t fu, lu;
+	uint32_t ssf, i;
+	efi_guid_t guid;
+	int ret;
+
+	if (last_lba(pr, &lastlba))
+		goto nothing;
+
+	ret = is_pmbr_valid(pr, NULL);
+	if (ret < 0)
+		return ret;
+	else if (ret == 0)
+		goto nothing;
+
+	errno = 0;
+	h = get_gpt_header(pr, &hdr, &e, (lba = GPT_PRIMARY_LBA), lastlba);
+	if (!h && !errno)
+		h = get_gpt_header(pr, &hdr, &e, (lba = lastlba), lastlba);
+
+	if (!h) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	blkid_probe_use_wiper(pr, lba * blkid_probe_get_size(pr), 8);
+
+	if (blkid_probe_set_magic(pr, blkid_probe_get_sectorsize(pr) * lba,
+			      sizeof(GPT_HEADER_SIGNATURE_STR) - 1,
+			      (unsigned char *) GPT_HEADER_SIGNATURE_STR))
+		goto err;
+
+	guid = h->disk_guid;
+	swap_efi_guid(&guid);
+
+	if (blkid_partitions_need_typeonly(pr)) {
+		/* Non-binary interface -- caller does not ask for details
+		 * about partitions, just set generic varibles only. */
+		blkid_partitions_set_ptuuid(pr, (unsigned char *) &guid);
+		return BLKID_PROBE_OK;
+	}
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	tab = blkid_partlist_new_parttable(ls, "gpt",
+				blkid_probe_get_sectorsize(pr) * lba);
+	if (!tab)
+		goto err;
+
+	blkid_parttable_set_uuid(tab, (const unsigned char *) &guid);
+
+	ssf = blkid_probe_get_sectorsize(pr) / 512;
+
+	fu = le64_to_cpu(h->first_usable_lba);
+	lu = le64_to_cpu(h->last_usable_lba);
+
+	for (i = 0; i < le32_to_cpu(h->num_partition_entries); i++, e++) {
+
+		blkid_partition par;
+		uint64_t start = le64_to_cpu(e->starting_lba);
+		uint64_t size = le64_to_cpu(e->ending_lba) -
+					le64_to_cpu(e->starting_lba) + 1ULL;
+
+		/* 00000000-0000-0000-0000-000000000000 entry */
+		if (!guidcmp(e->partition_type_guid, GPT_UNUSED_ENTRY_GUID)) {
+			blkid_partlist_increment_partno(ls);
+			continue;
+		}
+		/* the partition has to inside usable range */
+		if (start < fu || start + size - 1 > lu) {
+			DBG(LOWPROBE, ul_debug(
+				"GPT entry[%d] overflows usable area - ignore",
+				i));
+			blkid_partlist_increment_partno(ls);
+			continue;
+		}
+
+		par = blkid_partlist_add_partition(ls, tab,
+					start * ssf, size * ssf);
+		if (!par)
+			goto err;
+
+		blkid_partition_set_utf8name(par,
+			(unsigned char *) e->partition_name,
+			sizeof(e->partition_name), BLKID_ENC_UTF16LE);
+
+		guid = e->unique_partition_guid;
+		swap_efi_guid(&guid);
+		blkid_partition_set_uuid(par, (const unsigned char *) &guid);
+
+		guid = e->partition_type_guid;
+		swap_efi_guid(&guid);
+		blkid_partition_set_type_uuid(par, (const unsigned char *) &guid);
+
+		blkid_partition_set_flags(par, le64_to_cpu(e->attributes));
+	}
+
+	return BLKID_PROBE_OK;
+
+nothing:
+	return BLKID_PROBE_NONE;
+
+err:
+	return -ENOMEM;
+}
+
+
+const struct blkid_idinfo gpt_pt_idinfo =
+{
+	.name		= "gpt",
+	.probefunc	= probe_gpt_pt,
+	.minsz		= 1024 * 1440 + 1,	/* ignore floppies */
+
+	/*
+	 * It would be possible to check for DOS signature (0xAA55), but
+	 * unfortunately almost all EFI GPT implemenations allow to optionaly
+	 * skip the legacy MBR. We follows this behavior and MBR is optional.
+	 * See is_valid_pmbr().
+	 *
+	 * It means we have to always call probe_gpt_pt().
+	 */
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
+
+/* probe for *alone* protective MBR */
+static int probe_pmbr_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	int has = 0;
+	struct gpt_entry *e;
+	uint64_t lastlba = 0;
+	struct gpt_header hdr;
+
+	if (last_lba(pr, &lastlba))
+		goto nothing;
+
+	is_pmbr_valid(pr, &has);
+	if (!has)
+		goto nothing;
+
+	if (!get_gpt_header(pr, &hdr, &e, GPT_PRIMARY_LBA, lastlba) &&
+	    !get_gpt_header(pr, &hdr, &e, lastlba, lastlba))
+		return 0;
+nothing:
+	return 1;
+}
+
+const struct blkid_idinfo pmbr_pt_idinfo =
+{
+	.name		= "PMBR",
+	.probefunc	= probe_pmbr_pt,
+	.magics		=
+	{
+		{ .magic = "\x55\xAA", .len = 2, .sboff = 510 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/partitions/mac.c b/libblkid/src/partitions/mac.c
new file mode 100644
index 0000000..4282605
--- /dev/null
+++ b/libblkid/src/partitions/mac.c
@@ -0,0 +1,192 @@
+/*
+ * mac partitions parsing code
+ *
+ * Copyright (C) 2009 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 <stdint.h>
+
+#include "partitions.h"
+
+#define MAC_PARTITION_MAGIC		0x504d
+#define MAC_PARTITION_MAGIC_OLD		0x5453
+
+/*
+ * Mac partition entry
+ * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-126.html
+ */
+struct mac_partition {
+	uint16_t	signature;	/* expected to be MAC_PARTITION_MAGIC */
+	uint16_t	reserved;	/* reserved */
+	uint32_t	map_count;	/* # blocks in partition map */
+	uint32_t	start_block;	/* absolute starting block # of partition */
+	uint32_t	block_count;	/* number of blocks in partition */
+	char		name[32];	/* partition name */
+	char		type[32];	/* string type description */
+	uint32_t	data_start;	/* rel block # of first data block */
+	uint32_t	data_count;	/* number of data blocks */
+	uint32_t	status;		/* partition status bits */
+	uint32_t	boot_start;	/* first logical block of boot code */
+	uint32_t	boot_size;	/* size of boot code, in bytes */
+	uint32_t	boot_load;	/* boot code load address */
+	uint32_t	boot_load2;	/* reserved */
+	uint32_t	boot_entry;	/* boot code entry point */
+	uint32_t	boot_entry2;	/* reserved */
+	uint32_t	boot_cksum;	/* boot code checksum */
+	char		processor[16];	/* identifies ISA of boot */
+
+	/* there is more stuff after this that we don't need */
+} __attribute__((packed));
+
+/*
+ * Driver descriptor structure, in block 0
+ * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-121.html
+ */
+struct mac_driver_desc {
+	uint16_t	signature;	/* expected to be MAC_DRIVER_MAGIC */
+	uint16_t	block_size;	/* block size of the device */
+	uint32_t	block_count;	/* number of blocks on the device */
+
+	/* there is more stuff after this that we don't need */
+} __attribute__((packed));
+
+static inline unsigned char *get_mac_block(
+					blkid_probe pr,
+					uint16_t block_size,
+					uint32_t num)
+{
+	return blkid_probe_get_buffer(pr,
+			(blkid_loff_t) num * block_size, block_size);
+}
+
+static inline int has_part_signature(struct mac_partition *p)
+{
+	return	be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC ||
+		be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC_OLD;
+}
+
+static int probe_mac_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct mac_driver_desc *md;
+	struct mac_partition *p;
+	blkid_parttable tab = NULL;
+	blkid_partlist ls;
+	uint16_t block_size;
+	uint16_t ssf;	/* sector size fragment */
+	uint32_t nblks, i;
+
+
+	/* The driver descriptor record is always located at physical block 0,
+	 * the first block on the disk.
+	 */
+	md = (struct mac_driver_desc *) blkid_probe_get_sector(pr, 0);
+	if (!md) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	block_size = be16_to_cpu(md->block_size);
+
+	/* The partition map always begins at physical block 1,
+	 * the second block on the disk.
+	 */
+	p = (struct mac_partition *) get_mac_block(pr, block_size, 1);
+	if (!p) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	/* check the first partition signature */
+	if (!has_part_signature(p))
+		goto nothing;
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return 0;
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	tab = blkid_partlist_new_parttable(ls, "mac", 0);
+	if (!tab)
+		goto err;
+
+	ssf = block_size / 512;
+	nblks = be32_to_cpu(p->map_count);
+
+	for (i = 1; i <= nblks; ++i) {
+		blkid_partition par;
+		uint32_t start;
+		uint32_t size;
+
+		p = (struct mac_partition *) get_mac_block(pr, block_size, i);
+		if (!p) {
+			if (errno)
+				return -errno;
+			goto nothing;
+		}
+		if (!has_part_signature(p))
+			goto nothing;
+
+		if (be32_to_cpu(p->map_count) != nblks) {
+			DBG(LOWPROBE, ul_debug(
+				"mac: inconsisten map_count in partition map, "
+				"entry[0]: %d, entry[%d]: %d",
+				nblks, i - 1,
+				be32_to_cpu(p->map_count)));
+		}
+
+		/*
+		 * note that libparted ignores some mac partitions according to
+		 * the partition name (e.g. "Apple_Free" or "Apple_Void"). We
+		 * follows Linux kernel and all partitions are visible
+		 */
+
+		start = be32_to_cpu(p->start_block) * ssf;
+		size = be32_to_cpu(p->block_count) * ssf;
+
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par)
+			goto err;
+
+		blkid_partition_set_name(par, (unsigned char *) p->name,
+						sizeof(p->name));
+
+		blkid_partition_set_type_string(par, (unsigned char *) p->type,
+						sizeof(p->type));
+	}
+
+	return BLKID_PROBE_OK;
+
+nothing:
+	return BLKID_PROBE_NONE;
+err:
+	return -ENOMEM;
+}
+
+/*
+ * Mac disk always begin with "Driver Descriptor Record"
+ * (struct mac_driver_desc) and magic 0x4552.
+ */
+const struct blkid_idinfo mac_pt_idinfo =
+{
+	.name		= "mac",
+	.probefunc	= probe_mac_pt,
+	.magics		=
+	{
+		/* big-endian magic string */
+		{ .magic = "\x45\x52", .len = 2 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/partitions/minix.c b/libblkid/src/partitions/minix.c
new file mode 100644
index 0000000..43c9d9a
--- /dev/null
+++ b/libblkid/src/partitions/minix.c
@@ -0,0 +1,102 @@
+/*
+ * Minix partition parsing code
+ *
+ * Copyright (C) 2009 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 <stdint.h>
+
+#include "partitions.h"
+#include "minix.h"
+
+static int probe_minix_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct dos_partition *p;
+	blkid_parttable tab = NULL;
+	blkid_partition parent;
+	blkid_partlist ls;
+	unsigned char *data;
+	int i;
+
+	data = blkid_probe_get_sector(pr, 0);
+	if (!data) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	/* Parent is required, because Minix uses the same PT as DOS and
+	 * difference is only in primary partition (parent) type.
+	 */
+	parent = blkid_partlist_get_parent(ls);
+	if (!parent)
+		goto nothing;
+
+	if (blkid_partition_get_type(parent) != MBR_MINIX_PARTITION)
+		goto nothing;
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return BLKID_PROBE_OK;
+
+	tab = blkid_partlist_new_parttable(ls, "minix", MBR_PT_OFFSET);
+	if (!tab)
+		goto err;
+
+	for (i = 0, p = mbr_get_partition(data, 0);
+			i < MINIX_MAXPARTITIONS; i++, p++) {
+
+		uint32_t start, size;
+		blkid_partition par;
+
+		if (p->sys_ind != MBR_MINIX_PARTITION)
+			continue;
+
+		start = dos_partition_get_start(p);
+		size = dos_partition_get_size(p);
+
+		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
+			DBG(LOWPROBE, ul_debug(
+				"WARNING: minix partition (%d) overflow "
+				"detected, ignore", i));
+			continue;
+		}
+
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par)
+			goto err;
+
+		blkid_partition_set_type(par, p->sys_ind);
+		blkid_partition_set_flags(par, p->boot_ind);
+	}
+
+	return BLKID_PROBE_OK;
+
+nothing:
+	return BLKID_PROBE_NONE;
+err:
+	return -ENOMEM;
+}
+
+/* same as DOS */
+const struct blkid_idinfo minix_pt_idinfo =
+{
+	.name		= "minix",
+	.probefunc	= probe_minix_pt,
+	.magics		=
+	{
+		{ .magic = "\x55\xAA", .len = 2, .sboff = 510 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c
new file mode 100644
index 0000000..4853f97
--- /dev/null
+++ b/libblkid/src/partitions/partitions.c
@@ -0,0 +1,1512 @@
+/*
+ * partitions - partition tables parsing
+ *
+ * Copyright (C) 2008-2009 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>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdarg.h>
+
+#include "partitions.h"
+#include "sysfs.h"
+
+/**
+ * SECTION: partitions
+ * @title: Partitions probing
+ * @short_description: partitions tables detection and parsing
+ *
+ * This chain supports binary and NAME=value interfaces, but complete PT
+ * description is provided by binary interface only. The libblkid prober is
+ * compatible with kernel partition tables parser. The parser does not return
+ * empty (size=0) partitions or special hidden partitions.
+ *
+ * NAME=value interface, supported tags:
+ *
+ * @PTTYPE: partition table type (dos, gpt, etc.).
+ *
+ * @PTUUID: partition table id (uuid for gpt, hex for dos).
+
+ * @PART_ENTRY_SCHEME: partition table type
+ *
+ * @PART_ENTRY_NAME: partition name (gpt and mac only)
+ *
+ * @PART_ENTRY_UUID: partition UUID (gpt, or pseudo IDs for MBR)
+ *
+ * @PART_ENTRY_TYPE: partition type, 0xNN (e.g 0x82) or type UUID (gpt only) or type string (mac)
+ *
+ * @PART_ENTRY_FLAGS: partition flags (e.g. boot_ind) or  attributes (e.g. gpt attributes)
+ *
+ * @PART_ENTRY_NUMBER: partition number
+ *
+ * @PART_ENTRY_OFFSET: the begin of the partition
+ *
+ * @PART_ENTRY_SIZE: size of the partition
+ *
+ * @PART_ENTRY_DISK: whole-disk maj:min
+ *
+ * Example:
+ *
+ * <informalexample>
+ *  <programlisting>
+ * blkid_probe pr;
+ * const char *ptname;
+ *
+ * pr = blkid_new_probe_from_filename(devname);
+ * if (!pr)
+ *	err("%s: faild to open device", devname);
+ *
+ * blkid_probe_enable_partitions(pr, TRUE);
+ * blkid_do_fullprobe(pr);
+ *
+ * blkid_probe_lookup_value(pr, "PTTYPE", &ptname, NULL);
+ * printf("%s partition type detected\n", pttype);
+ *
+ * blkid_free_probe(pr);
+ *
+ * // don't forget to check return codes in your code!
+ *  </programlisting>
+ * </informalexample>
+ *
+ * Binary interface:
+ *
+ * <informalexample>
+ *  <programlisting>
+ * blkid_probe pr;
+ * blkid_partlist ls;
+ * int nparts, i;
+ *
+ * pr = blkid_new_probe_from_filename(devname);
+ * if (!pr)
+ *	err("%s: faild to open device", devname);
+ *
+ * ls = blkid_probe_get_partitions(pr);
+ * nparts = blkid_partlist_numof_partitions(ls);
+ *
+ * for (i = 0; i < nparts; i++) {
+ *      blkid_partition par = blkid_partlist_get_partition(ls, i);
+ *      printf("#%d: %llu %llu  0x%x",
+ *               blkid_partition_get_partno(par),
+ *               blkid_partition_get_start(par),
+ *               blkid_partition_get_size(par),
+ *               blkid_partition_get_type(par));
+ * }
+ *
+ * blkid_free_probe(pr);
+ *
+ * // don't forget to check return codes in your code!
+ *  </programlisting>
+ * </informalexample>
+ */
+
+/*
+ * Chain driver function
+ */
+static int partitions_probe(blkid_probe pr, struct blkid_chain *chn);
+static void partitions_free_data(blkid_probe pr, void *data);
+
+/*
+ * Partitions chain probing functions
+ */
+static const struct blkid_idinfo *idinfos[] =
+{
+	&aix_pt_idinfo,
+	&sgi_pt_idinfo,
+	&sun_pt_idinfo,
+	&dos_pt_idinfo,
+	&gpt_pt_idinfo,
+	&pmbr_pt_idinfo,	/* always after GPT */
+	&mac_pt_idinfo,
+	&ultrix_pt_idinfo,
+	&bsd_pt_idinfo,
+	&unixware_pt_idinfo,
+	&solaris_x86_pt_idinfo,
+	&minix_pt_idinfo
+};
+
+/*
+ * Driver definition
+ */
+const struct blkid_chaindrv partitions_drv = {
+	.id           = BLKID_CHAIN_PARTS,
+	.name         = "partitions",
+	.dflt_enabled = FALSE,
+	.idinfos      = idinfos,
+	.nidinfos     = ARRAY_SIZE(idinfos),
+	.has_fltr     = TRUE,
+	.probe        = partitions_probe,
+	.safeprobe    = partitions_probe,
+	.free_data    = partitions_free_data
+};
+
+
+/*
+ * For compatibility with the rest of libblkid API (with the old high-level
+ * API) we use completely opaque typedefs for all structs. Don't forget that
+ * the final blkid_* types are pointers! See blkid.h.
+ *
+ * [Just for the record, I hate typedef for pointers --kzak]
+ */
+
+/* exported as opaque type "blkid_parttable" */
+struct blkid_struct_parttable {
+	const char	*type;		/* partition table type */
+	blkid_loff_t	offset;		/* begin of the partition table (in bytes) */
+	int		nparts;		/* number of partitions */
+	blkid_partition	parent;		/* parent of nested partition table */
+	char		id[37];		/* PT identifier (e.g. UUID for GPT) */
+
+	struct list_head t_tabs;	/* all tables */
+};
+
+/* exported as opaque type "blkid_partition" */
+struct blkid_struct_partition {
+	blkid_loff_t	start;		/* begin of the partition (512-bytes sectors) */
+	blkid_loff_t	size;		/* size of the partitions (512-bytes sectors) */
+
+	int		type;		/* partition type */
+	char		typestr[37];	/* partition type string (GPT and Mac) */
+
+	unsigned long long flags;	/* partition flags / attributes */
+
+	int		partno;		/* partition number */
+	char		uuid[37];	/* UUID (when supported by PT), e.g GPT */
+	unsigned char	name[128];	/* Partition in UTF8 name (when supporte by PT), e.g. Mac */
+
+	blkid_parttable	tab;		/* partition table */
+};
+
+/* exported as opaque type "blkid_partlist" */
+struct blkid_struct_partlist {
+	int		next_partno;	/* next partition number */
+	blkid_partition next_parent;	/* next parent if parsing nested PT */
+
+	int		nparts;		/* number of partitions */
+	int		nparts_max;	/* max.number of partitions */
+	blkid_partition	parts;		/* array of partitions */
+
+	struct list_head l_tabs;	/* list of partition tables */
+};
+
+static int blkid_partitions_probe_partition(blkid_probe pr);
+
+/**
+ * blkid_probe_enable_partitions:
+ * @pr: probe
+ * @enable: TRUE/FALSE
+ *
+ * Enables/disables the partitions probing for non-binary interface.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_enable_partitions(blkid_probe pr, int enable)
+{
+	if (!pr)
+		return -1;
+	pr->chains[BLKID_CHAIN_PARTS].enabled = enable;
+	return 0;
+}
+
+/**
+ * blkid_probe_set_partitions_flags:
+ * @pr: prober
+ * @flags: BLKID_PARTS_* flags
+ *
+ * Sets probing flags to the partitions prober. This function is optional.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_set_partitions_flags(blkid_probe pr, int flags)
+{
+	if (!pr)
+		return -1;
+	pr->chains[BLKID_CHAIN_PARTS].flags = flags;
+	return 0;
+}
+
+/**
+ * blkid_probe_reset_partitions_filter:
+ * @pr: prober
+ *
+ * Resets partitions probing filter
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_reset_partitions_filter(blkid_probe pr)
+{
+	return __blkid_probe_reset_filter(pr, BLKID_CHAIN_PARTS);
+}
+
+/**
+ * blkid_probe_invert_partitions_filter:
+ * @pr: prober
+ *
+ * Inverts partitions probing filter
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_invert_partitions_filter(blkid_probe pr)
+{
+	return __blkid_probe_invert_filter(pr, BLKID_CHAIN_PARTS);
+}
+
+/**
+ * blkid_probe_filter_partitions_type:
+ * @pr: prober
+ * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
+ * @names: NULL terminated array of probing function names (e.g. "vfat").
+ *
+ *  %BLKID_FLTR_NOTIN  - probe for all items which are NOT IN @names
+ *
+ *  %BLKID_FLTR_ONLYIN - probe for items which are IN @names
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[])
+{
+	return __blkid_probe_filter_types(pr, BLKID_CHAIN_PARTS, flag, names);
+}
+
+/**
+ * blkid_probe_get_partitions:
+ * @pr: probe
+ *
+ * This is a binary interface for partitions. See also blkid_partlist_*
+ * functions.
+ *
+ * This function is independent on blkid_do_[safe,full]probe() and
+ * blkid_probe_enable_partitions() calls.
+ *
+ * WARNING: the returned object will be overwritten by the next
+ *          blkid_probe_get_partitions() call for the same @pr. If you want to
+ *          use more blkid_partlist objects in the same time you have to create
+ *          more blkid_probe handlers (see blkid_new_probe()).
+ *
+ * Returns: list of partitions, or NULL in case of error.
+ */
+blkid_partlist blkid_probe_get_partitions(blkid_probe pr)
+{
+	return (blkid_partlist) blkid_probe_get_binary_data(pr,
+			&pr->chains[BLKID_CHAIN_PARTS]);
+}
+
+/* for internal usage only */
+blkid_partlist blkid_probe_get_partlist(blkid_probe pr)
+{
+	return (blkid_partlist) pr->chains[BLKID_CHAIN_PARTS].data;
+}
+
+static void blkid_probe_set_partlist(blkid_probe pr, blkid_partlist ls)
+{
+	pr->chains[BLKID_CHAIN_PARTS].data = ls;
+}
+
+static void ref_parttable(blkid_parttable tab)
+{
+	tab->nparts++;
+}
+
+static void unref_parttable(blkid_parttable tab)
+{
+	tab->nparts--;
+
+	if (tab->nparts <= 0) {
+		list_del(&tab->t_tabs);
+		free(tab);
+	}
+}
+
+/* free all allocated parttables */
+static void free_parttables(blkid_partlist ls)
+{
+	if (!ls || !ls->l_tabs.next)
+		return;
+
+	/* remove unassigned partition tables */
+	while (!list_empty(&ls->l_tabs)) {
+		blkid_parttable tab = list_entry(ls->l_tabs.next,
+					struct blkid_struct_parttable, t_tabs);
+		unref_parttable(tab);
+	}
+}
+
+static void reset_partlist(blkid_partlist ls)
+{
+	if (!ls)
+		return;
+
+	free_parttables(ls);
+
+	if (ls->next_partno) {
+		/* already initialized - reset */
+		int tmp_nparts = ls->nparts_max;
+		blkid_partition tmp_parts = ls->parts;
+
+		memset(ls, 0, sizeof(struct blkid_struct_partlist));
+
+		ls->nparts_max = tmp_nparts;
+		ls->parts = tmp_parts;
+	}
+
+	ls->nparts = 0;
+	ls->next_partno = 1;
+	INIT_LIST_HEAD(&ls->l_tabs);
+
+	DBG(LOWPROBE, ul_debug("partlist reset"));
+}
+
+static blkid_partlist partitions_init_data(struct blkid_chain *chn)
+{
+	blkid_partlist ls;
+
+	if (chn->data)
+		ls = (blkid_partlist) chn->data;
+	else {
+		/* allocate the new list of partitions */
+		ls = calloc(1, sizeof(struct blkid_struct_partlist));
+		if (!ls)
+			return NULL;
+		chn->data = (void *) ls;
+	}
+
+	reset_partlist(ls);
+
+	DBG(LOWPROBE, ul_debug("parts: initialized partitions list (%p, size=%d)",
+		ls, ls->nparts_max));
+	return ls;
+}
+
+static void partitions_free_data(blkid_probe pr __attribute__((__unused__)),
+				 void *data)
+{
+	blkid_partlist ls = (blkid_partlist) data;
+
+	if (!ls)
+		return;
+
+	free_parttables(ls);
+
+	/* deallocate partitions and partlist */
+	free(ls->parts);
+	free(ls);
+}
+
+blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls,
+				const char *type, blkid_loff_t offset)
+{
+	blkid_parttable tab;
+
+	tab = calloc(1, sizeof(struct blkid_struct_parttable));
+	if (!tab)
+		return NULL;
+	tab->type = type;
+	tab->offset = offset;
+	tab->parent = ls->next_parent;
+
+	INIT_LIST_HEAD(&tab->t_tabs);
+	list_add_tail(&tab->t_tabs, &ls->l_tabs);
+
+	DBG(LOWPROBE, ul_debug("parts: create a new partition table "
+		       "(%p, type=%s, offset=%"PRId64")", tab, type, offset));
+	return tab;
+}
+
+static blkid_partition new_partition(blkid_partlist ls, blkid_parttable tab)
+{
+	blkid_partition par;
+
+	if (ls->nparts + 1 > ls->nparts_max) {
+		/* Linux kernel has DISK_MAX_PARTS=256, but it's too much for
+		 * generic Linux machine -- let start with 32 partititions.
+		 */
+		void *tmp = realloc(ls->parts, (ls->nparts_max + 32) *
+					sizeof(struct blkid_struct_partition));
+		if (!tmp)
+			return NULL;
+		ls->parts = tmp;
+		ls->nparts_max += 32;
+	}
+
+	par = &ls->parts[ls->nparts++];
+	memset(par, 0, sizeof(struct blkid_struct_partition));
+
+	ref_parttable(tab);
+	par->tab = tab;
+	par->partno = blkid_partlist_increment_partno(ls);
+
+	return par;
+}
+
+blkid_partition blkid_partlist_add_partition(blkid_partlist ls,
+					blkid_parttable tab,
+					blkid_loff_t start, blkid_loff_t size)
+{
+	blkid_partition par = new_partition(ls, tab);
+
+	if (!par)
+		return NULL;
+
+	par->start = start;
+	par->size = size;
+
+	DBG(LOWPROBE, ul_debug("parts: add partition (%p start=%"
+		PRId64 ", size=%" PRId64 ", table=%p)",
+		par, par->start, par->size, tab));
+	return par;
+}
+
+/* allows to modify used partitions numbers (for example for logical partitions) */
+int blkid_partlist_set_partno(blkid_partlist ls, int partno)
+{
+	if (!ls)
+		return -1;
+	ls->next_partno = partno;
+	return 0;
+}
+
+int blkid_partlist_increment_partno(blkid_partlist ls)
+{
+	return ls ? ls->next_partno++ : -1;
+}
+
+/* allows to set "parent" for the next nested partition */
+int blkid_partlist_set_parent(blkid_partlist ls, blkid_partition par)
+{
+	if (!ls)
+		return -1;
+	ls->next_parent = par;
+	return 0;
+}
+
+blkid_partition blkid_partlist_get_parent(blkid_partlist ls)
+{
+	if (!ls)
+		return NULL;
+	return ls->next_parent;
+}
+
+int blkid_partitions_need_typeonly(blkid_probe pr)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+	return chn && chn->data && chn->binary ? FALSE : TRUE;
+}
+
+/* get private chain flags */
+int blkid_partitions_get_flags(blkid_probe pr)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+	return chn ? chn->flags : 0;
+}
+
+/* check if @start and @size are within @par partition */
+int blkid_is_nested_dimension(blkid_partition par,
+			blkid_loff_t start, blkid_loff_t size)
+{
+	blkid_loff_t pstart;
+	blkid_loff_t psize;
+
+	if (!par)
+		return 0;
+
+	pstart = blkid_partition_get_start(par);
+	psize = blkid_partition_get_size(par);
+
+	if (start < pstart || start + size > pstart + psize)
+		return 0;
+
+	return 1;
+}
+
+static int idinfo_probe(blkid_probe pr, const struct blkid_idinfo *id,
+			struct blkid_chain *chn)
+{
+	const struct blkid_idmag *mag = NULL;
+	blkid_loff_t off;
+	int rc = BLKID_PROBE_NONE;		/* default is nothing */
+
+	if (pr->size <= 0 || (id->minsz && id->minsz > pr->size))
+		goto nothing;	/* the device is too small */
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		goto nothing;
+
+	rc = blkid_probe_get_idmag(pr, id, &off, &mag);
+	if (rc != BLKID_PROBE_OK)
+		goto nothing;
+
+	/* final check by probing function */
+	if (id->probefunc) {
+		DBG(LOWPROBE, ul_debug(
+			"%s: ---> call probefunc()", id->name));
+		rc = id->probefunc(pr, mag);
+		if (rc < 0) {
+			/* reset after error */
+			reset_partlist(blkid_probe_get_partlist(pr));
+			if (chn && !chn->binary)
+				blkid_probe_chain_reset_vals(pr, chn);
+			DBG(LOWPROBE, ul_debug("%s probefunc failed, rc %d",
+						  id->name, rc));
+		}
+		if (rc == BLKID_PROBE_OK && mag && chn && !chn->binary)
+			rc = blkid_probe_set_magic(pr, off, mag->len,
+					(unsigned char *) mag->magic);
+
+		DBG(LOWPROBE, ul_debug("%s: <--- (rc = %d)", id->name, rc));
+	}
+
+	return rc;
+
+nothing:
+	return BLKID_PROBE_NONE;
+}
+
+/*
+ * The blkid_do_probe() backend.
+ */
+static int partitions_probe(blkid_probe pr, struct blkid_chain *chn)
+{
+	int rc = BLKID_PROBE_NONE;
+	size_t i;
+
+	if (!pr || chn->idx < -1)
+		return -EINVAL;
+
+	blkid_probe_chain_reset_vals(pr, chn);
+
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return BLKID_PROBE_NONE;
+
+	if (chn->binary)
+		partitions_init_data(chn);
+
+	if (!pr->wipe_size && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_PT))
+		goto details_only;
+
+	DBG(LOWPROBE, ul_debug("--> starting probing loop [PARTS idx=%d]",
+		chn->idx));
+
+	i = chn->idx < 0 ? 0 : chn->idx + 1U;
+
+	for ( ; i < ARRAY_SIZE(idinfos); i++) {
+		const char *name;
+
+		chn->idx = i;
+
+		/* apply filter */
+		if (chn->fltr && blkid_bmp_get_item(chn->fltr, i))
+			continue;
+
+		/* apply checks from idinfo */
+		rc = idinfo_probe(pr, idinfos[i], chn);
+		if (rc < 0)
+			break;
+		if (rc != BLKID_PROBE_OK)
+			continue;
+
+		name = idinfos[i]->name;
+
+		if (!chn->binary)
+			/*
+			 * Non-binary interface, set generic variables. Note
+			 * that the another variables could be set in prober
+			 * functions.
+			 */
+			blkid_probe_set_value(pr, "PTTYPE",
+						(unsigned char *) name,
+						strlen(name) + 1);
+
+		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [PARTS idx=%d]",
+			name, chn->idx));
+		rc = BLKID_PROBE_OK;
+		break;
+	}
+
+	if (rc != BLKID_PROBE_OK) {
+		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed=%d) [PARTS idx=%d]",
+			rc, chn->idx));
+	}
+
+details_only:
+	/*
+	 * Gather PART_ENTRY_* values if the current device is a partition.
+	 */
+	if ((rc == BLKID_PROBE_OK || rc == BLKID_PROBE_NONE) && !chn->binary &&
+	    (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) {
+
+		int xrc = blkid_partitions_probe_partition(pr);
+
+		/* partition entry probing is optional, and "not-found" from
+		 * this sub-probing must not to overwrite previous success. */
+		if (xrc < 0)
+			rc = xrc;			/* always propagate errors */
+		else if (rc == BLKID_PROBE_NONE)
+			rc = xrc;
+	}
+
+	DBG(LOWPROBE, ul_debug("partitions probe done [rc=%d]",	rc));
+	return rc;
+}
+
+/* Probe for nested partition table within the parental partition */
+int blkid_partitions_do_subprobe(blkid_probe pr, blkid_partition parent,
+		const struct blkid_idinfo *id)
+{
+	blkid_probe prc;
+	int rc;
+	blkid_partlist ls;
+	blkid_loff_t sz, off;
+
+	DBG(LOWPROBE, ul_debug(
+		"parts: ----> %s subprobe requested (parent=%p)",
+		id->name, parent));
+
+	if (!pr || !parent || !parent->size)
+		return -EINVAL;
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return BLKID_PROBE_NONE;
+
+	/* range defined by parent */
+	sz = ((blkid_loff_t) parent->size) << 9;
+	off = ((blkid_loff_t) parent->start) << 9;
+
+	if (off < pr->off || pr->off + pr->size < off + sz) {
+		DBG(LOWPROBE, ul_debug(
+			"ERROR: parts: <---- '%s' subprobe: overflow detected.",
+			id->name));
+		return -ENOSPC;
+	}
+
+	/* create private prober */
+	prc = blkid_clone_probe(pr);
+	if (!prc)
+		return -ENOMEM;
+
+	blkid_probe_set_dimension(prc, off, sz);
+
+	/* clone is always with reset chain, fix it */
+	prc->cur_chain = blkid_probe_get_chain(pr);
+
+	/*
+	 * Set 'parent' to the current list of the partitions and use the list
+	 * in cloned prober (so the cloned prober will extend the current list
+	 * of partitions rather than create a new).
+	 */
+	ls = blkid_probe_get_partlist(pr);
+	blkid_partlist_set_parent(ls, parent);
+
+	blkid_probe_set_partlist(prc, ls);
+
+	rc = idinfo_probe(prc, id, blkid_probe_get_chain(pr));
+
+	blkid_probe_set_partlist(prc, NULL);
+	blkid_partlist_set_parent(ls, NULL);
+
+	blkid_free_probe(prc);	/* free cloned prober */
+
+	DBG(LOWPROBE, ul_debug(
+		"parts: <---- %s subprobe done (parent=%p, rc=%d)",
+		id->name, parent, rc));
+
+	return rc;
+}
+
+static int blkid_partitions_probe_partition(blkid_probe pr)
+{
+	blkid_probe disk_pr = NULL;
+	blkid_partlist ls;
+	blkid_partition par;
+	dev_t devno;
+
+	DBG(LOWPROBE, ul_debug("parts: start probing for partition entry"));
+
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		goto nothing;
+
+	devno = blkid_probe_get_devno(pr);
+	if (!devno)
+		goto nothing;
+
+	disk_pr = blkid_probe_get_wholedisk_probe(pr);
+	if (!disk_pr)
+		goto nothing;
+
+	/* parse PT */
+	ls = blkid_probe_get_partitions(disk_pr);
+	if (!ls)
+		goto nothing;
+
+	par = blkid_partlist_devno_to_partition(ls, devno);
+	if (!par)
+		goto nothing;
+	else {
+		const char *v;
+		blkid_parttable tab = blkid_partition_get_table(par);
+		dev_t disk = blkid_probe_get_devno(disk_pr);
+
+		if (tab) {
+			v = blkid_parttable_get_type(tab);
+			if (v)
+				blkid_probe_set_value(pr, "PART_ENTRY_SCHEME",
+					(unsigned char *) v, strlen(v) + 1);
+		}
+
+		v = blkid_partition_get_name(par);
+		if (v)
+			blkid_probe_set_value(pr, "PART_ENTRY_NAME",
+				(unsigned char *) v, strlen(v) + 1);
+
+		v = blkid_partition_get_uuid(par);
+		if (v)
+			blkid_probe_set_value(pr, "PART_ENTRY_UUID",
+				(unsigned char *) v, strlen(v) + 1);
+
+		/* type */
+		v = blkid_partition_get_type_string(par);
+		if (v)
+			blkid_probe_set_value(pr, "PART_ENTRY_TYPE",
+				(unsigned char *) v, strlen(v) + 1);
+		else
+			blkid_probe_sprintf_value(pr, "PART_ENTRY_TYPE",
+				"0x%x", blkid_partition_get_type(par));
+
+		if (blkid_partition_get_flags(par))
+			blkid_probe_sprintf_value(pr, "PART_ENTRY_FLAGS",
+				"0x%llx", blkid_partition_get_flags(par));
+
+		blkid_probe_sprintf_value(pr, "PART_ENTRY_NUMBER",
+				"%d", blkid_partition_get_partno(par));
+
+		blkid_probe_sprintf_value(pr, "PART_ENTRY_OFFSET", "%jd",
+				blkid_partition_get_start(par));
+		blkid_probe_sprintf_value(pr, "PART_ENTRY_SIZE", "%jd",
+				blkid_partition_get_size(par));
+
+		blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u",
+				major(disk), minor(disk));
+	}
+
+	DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [success]"));
+	return BLKID_PROBE_OK;
+
+nothing:
+	DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [nothing]"));
+	return BLKID_PROBE_NONE;
+
+
+}
+
+/*
+ * Returns 1 if the device is whole-disk and the area specified by @offset and
+ * @size is covered by any partition.
+ */
+int blkid_probe_is_covered_by_pt(blkid_probe pr,
+				 blkid_loff_t offset, blkid_loff_t size)
+{
+	blkid_probe prc = NULL;
+	blkid_partlist ls = NULL;
+	blkid_loff_t start, end;
+	int nparts, i, rc = 0;
+
+	DBG(LOWPROBE, ul_debug(
+		"=> checking if off=%jd size=%jd covered by PT",
+		offset, size));
+
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		goto done;
+
+	prc = blkid_clone_probe(pr);
+	if (!prc)
+		goto done;
+
+	ls = blkid_probe_get_partitions(prc);
+	if (!ls)
+		goto done;
+
+	nparts = blkid_partlist_numof_partitions(ls);
+	if (!nparts)
+		goto done;
+
+	end = (offset + size) >> 9;
+	start = offset >> 9;
+
+	/* check if the partition table fits into the device */
+	for (i = 0; i < nparts; i++) {
+		blkid_partition par = &ls->parts[i];
+
+		if (par->start + par->size > (pr->size >> 9)) {
+			DBG(LOWPROBE, ul_debug("partition #%d overflows "
+				"device (off=%" PRId64 " size=%" PRId64 ")",
+				par->partno, par->start, par->size));
+			goto done;
+		}
+	}
+
+	/* check if the requested area is covered by PT */
+	for (i = 0; i < nparts; i++) {
+		blkid_partition par = &ls->parts[i];
+
+		if (start >= par->start && end <= par->start + par->size) {
+			rc = 1;
+			break;
+		}
+	}
+done:
+	blkid_free_probe(prc);
+
+	DBG(LOWPROBE, ul_debug("<= %s covered by PT", rc ? "IS" : "NOT"));
+	return rc;
+}
+
+/**
+ * blkid_known_pttype:
+ * @pttype: partiton name
+ *
+ * Returns: 1 for known or 0 for unknown partition type.
+ */
+int blkid_known_pttype(const char *pttype)
+{
+	size_t i;
+
+	if (!pttype)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
+		const struct blkid_idinfo *id = idinfos[i];
+		if (strcmp(id->name, pttype) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * blkid_partlist_numof_partitions:
+ * @ls: partitions list
+ *
+ * Returns: number of partitions in the list or -1 in case of error.
+ */
+int blkid_partlist_numof_partitions(blkid_partlist ls)
+{
+	return ls ? ls->nparts : -1;
+}
+
+/**
+ * blkid_partlist_get_table:
+ * @ls: partitions list
+ *
+ * Returns: top-level partition table or NULL of there is not a partition table
+ * on the device.
+ */
+blkid_parttable blkid_partlist_get_table(blkid_partlist ls)
+{
+	if (!ls || list_empty(&ls->l_tabs))
+		return NULL;
+
+	return list_entry(ls->l_tabs.next,
+			struct blkid_struct_parttable, t_tabs);
+}
+
+
+/**
+ * blkid_partlist_get_partition:
+ * @ls: partitions list
+ * @n: partition number in range 0..N, where 'N' is blkid_partlist_numof_partitions().
+ *
+ * It's possible that the list of partitions is *empty*, but there is a valid
+ * partition table on the disk. This happen when on-disk details about
+ * partitions are unknown or the partition table is empty.
+ *
+ * See also blkid_partlist_get_table().
+ *
+ * Returns: partition object or NULL in case or error.
+ */
+blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n)
+{
+	if (!ls || n < 0 || n >= ls->nparts)
+		return NULL;
+
+	return &ls->parts[n];
+}
+
+/**
+ * blkid_partlist_get_partition_by_partno
+ * @ls: partitions list
+ * @n: the partition number (e.g. 'N' from sda'N')
+ *
+ * This does not assume any order of the input blkid_partlist.  And correctly
+ * handles "out of order" partition tables.  partition N is located after
+ * partition N+1 on the disk.
+ *
+ * Returns: partition object or NULL in case or error.
+ */
+blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n)
+{
+	int i, nparts;
+	blkid_partition par;
+
+	if (!ls)
+		return NULL;
+
+	nparts = blkid_partlist_numof_partitions(ls);
+	for (i = 0; i < nparts; i++) {
+		par = blkid_partlist_get_partition(ls, i);
+		if (n == blkid_partition_get_partno(par))
+			return par;
+	}
+	return NULL;
+}
+
+
+/**
+ * blkid_partlist_devno_to_partition:
+ * @ls: partitions list
+ * @devno: requested partition
+ *
+ * This function tries to get start and size for @devno from sysfs and
+ * returns a partition from @ls which matches with the values from sysfs.
+ *
+ * This function is necessary when you want to make a relation between an entry
+ * in the partition table (@ls) and block devices in your system.
+ *
+ * Returns: partition object or NULL in case or error.
+ */
+blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno)
+{
+	struct sysfs_cxt sysfs;
+	uint64_t start, size;
+	int i, rc, partno = 0;
+
+	if (!ls)
+		return NULL;
+
+	DBG(LOWPROBE, ul_debug("triyng to convert devno 0x%llx to partition",
+			(long long) devno));
+
+	if (sysfs_init(&sysfs, devno, NULL)) {
+		DBG(LOWPROBE, ul_debug("failed t init sysfs context"));
+		return NULL;
+	}
+	rc = sysfs_read_u64(&sysfs, "size", &size);
+	if (!rc) {
+		rc = sysfs_read_u64(&sysfs, "start", &start);
+		if (rc) {
+			/* try to get partition number from DM uuid.
+			 */
+			char *uuid = sysfs_strdup(&sysfs, "dm/uuid");
+			char *tmp = uuid;
+			char *prefix = uuid ? strsep(&tmp, "-") : NULL;
+
+			if (prefix && strncasecmp(prefix, "part", 4) == 0) {
+				char *end = NULL;
+
+				partno = strtol(prefix + 4, &end, 10);
+				if (prefix == end || (end && *end))
+					partno = 0;
+				else
+					rc = 0;		/* success */
+			}
+			free(uuid);
+		}
+	}
+
+	sysfs_deinit(&sysfs);
+
+	if (rc)
+		return NULL;
+
+	if (partno) {
+		DBG(LOWPROBE, ul_debug("mapped by DM, using partno %d", partno));
+
+		/*
+		 * Partition mapped by kpartx does not provide "start" offset
+		 * in /sys, but if we know partno and size of the partition
+		 * that we can probably make the releation bettween the device
+		 * and an entry in partition table.
+		 */
+		 for (i = 0; i < ls->nparts; i++) {
+			 blkid_partition par = &ls->parts[i];
+
+			 if (partno != blkid_partition_get_partno(par))
+				 continue;
+
+			 if ((blkid_loff_t) size == blkid_partition_get_size(par) ||
+			     (blkid_partition_is_extended(par) && size <= 1024))
+				 return par;
+
+		 }
+		 return NULL;
+	}
+
+	DBG(LOWPROBE, ul_debug("searching by offset/size"));
+
+	for (i = 0; i < ls->nparts; i++) {
+		blkid_partition par = &ls->parts[i];
+
+		if (blkid_partition_get_start(par) == (blkid_loff_t) start &&
+		    blkid_partition_get_size(par) == (blkid_loff_t) size)
+			return par;
+
+		/* exception for extended dos partitions */
+		if (blkid_partition_get_start(par) == (blkid_loff_t) start &&
+		    blkid_partition_is_extended(par) && size <= 1024)
+			return par;
+
+	}
+
+	DBG(LOWPROBE, ul_debug("not found partition for device"));
+	return NULL;
+}
+
+
+int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id)
+{
+	if (!tab)
+		return -1;
+
+	blkid_unparse_uuid(id, tab->id, sizeof(tab->id));
+	return 0;
+}
+
+int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id)
+{
+	if (!tab)
+		return -1;
+
+	strncpy(tab->id, (const char *) id, sizeof(tab->id));
+	return 0;
+}
+
+/* set PTUUID variable for non-binary API */
+int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+	struct blkid_prval *v;
+
+	if (chn->binary || blkid_uuid_is_empty(uuid, 16))
+		return 0;
+
+	v = blkid_probe_assign_value(pr, "PTUUID");
+
+	blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data));
+	v->len = 37;
+
+	return 0;
+}
+
+/* set PTUUID variable for non-binary API for tables where
+ * the ID is just a string */
+int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+	struct blkid_prval *v;
+	size_t len;
+
+	if (chn->binary || !str || !*str)
+		return 0;
+
+	len = strlen((char *) str);
+	if (len > BLKID_PROBVAL_BUFSIZ)
+		len = BLKID_PROBVAL_BUFSIZ;
+
+	v = blkid_probe_assign_value(pr, "PTUUID");
+	if (v) {
+		if (len == BLKID_PROBVAL_BUFSIZ)
+			len--;		/* make a space for \0 */
+
+		memcpy((char *) v->data, str, len);
+		v->data[len] = '\0';
+		v->len = len + 1;
+		return 0;
+	}
+	return -1;
+}
+
+/**
+ * blkid_parttable_get_id:
+ * @tab: partition table
+ *
+ * The ID is GPT disk UUID or DOS disk ID (in hex format).
+ *
+ * Returns: partition table ID (for example GPT disk UUID) or NULL
+ */
+const char *blkid_parttable_get_id(blkid_parttable tab)
+{
+	return tab && *tab->id ? tab->id : NULL;
+}
+
+
+int blkid_partition_set_type(blkid_partition par, int type)
+{
+	if (!par)
+		return -1;
+	par->type = type;
+	return 0;
+}
+
+/**
+ * blkid_parttable_get_type:
+ * @tab: partition table
+ *
+ * Returns: partition table type (type name, e.g. "dos", "gpt", ...)
+ */
+const char *blkid_parttable_get_type(blkid_parttable tab)
+{
+	return tab ? tab->type : NULL;
+}
+
+/**
+ * blkid_parttable_get_parent:
+ * @tab: partition table
+ *
+ * Returns: parent for nexted partitition tables or NULL.
+ */
+blkid_partition blkid_parttable_get_parent(blkid_parttable tab)
+{
+	return tab ? tab->parent : NULL;
+}
+
+/**
+ * blkid_parttable_get_offset:
+ * @tab: partition table
+ *
+ * Note the position is relative to begin of the device as defined by
+ * blkid_probe_set_device() for primary partition table, and relative
+ * to parental partition for nested patition tables.
+ *
+ * <informalexample>
+ *   <programlisting>
+ * off_t offset;
+ * blkid_partition parent = blkid_parttable_get_parent(tab);
+ *
+ * offset = blkid_parttable_get_offset(tab);
+ *
+ * if (parent)
+ *      / * 'tab' is nested partition table * /
+ *	offset += blkid_partition_get_start(parent);
+ *   </programlisting>
+ * </informalexample>
+
+ * Returns: position (in bytes) of the partition table or -1 in case of error.
+ *
+ */
+blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab)
+{
+	return tab ? tab->offset : -1;
+}
+
+/**
+ * blkid_partition_get_table:
+ * @par: partition
+ *
+ * The "parttable" describes partition table. The table is usually the same for
+ * all partitions -- except nested partition tables.
+ *
+ * For example bsd, solaris, etc. use a nested partition table within
+ * standard primary dos partition:
+ *
+ * <informalexample>
+ *   <programlisting>
+ *
+ *  -- dos partition table
+ *  0: sda1     dos primary partition
+ *  1: sda2     dos primary partition
+ *     -- bsd partition table (with in sda2)
+ *  2:    sda5  bds partition
+ *  3:    sda6  bds partition
+ *
+ *   </programlisting>
+ * </informalexample>
+ *
+ * The library does not to use a separate partition table object for dos logical
+ * partitions (partitions within extended partition). It's possible to
+ * differentiate between logical, extended and primary partitions by
+ *
+ *	blkid_partition_is_{extended,primary,logical}().
+ *
+ * Returns: partition table object or NULL in case of error.
+ */
+blkid_parttable blkid_partition_get_table(blkid_partition par)
+{
+	return par ? par->tab : NULL;
+}
+
+static int partition_get_logical_type(blkid_partition par)
+{
+	blkid_parttable tab;
+
+	if (!par)
+		return -1;
+
+	tab = blkid_partition_get_table(par);
+	if (!tab || !tab->type)
+		return -1;
+
+	if (tab->parent)
+		return 'L';  /* report nested partitions as logical */
+
+	if (!strcmp(tab->type, "dos")) {
+		if (par->partno > 4)
+			return 'L';	/* logical */
+
+	        if(par->type == MBR_DOS_EXTENDED_PARTITION ||
+                   par->type == MBR_W95_EXTENDED_PARTITION ||
+		   par->type == MBR_LINUX_EXTENDED_PARTITION)
+			return 'E';
+	}
+	return 'P';
+}
+
+/**
+ * blkid_partition_is_primary:
+ * @par: partition
+ *
+ * Note, this function returns FALSE for DOS extended partitions and
+ * all partitions in nested partition tables.
+ *
+ * Returns: 1 if the partitions is primary partition or 0 if not.
+ */
+int blkid_partition_is_primary(blkid_partition par)
+{
+	return partition_get_logical_type(par) == 'P' ? TRUE : FALSE;
+}
+
+/**
+ * blkid_partition_is_extended:
+ * @par: partition
+ *
+ * Returns: 1 if the partitions is extended (dos, windows or linux)
+ * partition or 0 if not.
+ */
+int blkid_partition_is_extended(blkid_partition par)
+{
+	return partition_get_logical_type(par) == 'E' ? TRUE : FALSE;
+}
+
+/**
+ * blkid_partition_is_logical:
+ * @par: partition
+ *
+ * Note that this function returns TRUE for all partitions in all
+ * nested partition tables (e.g. BSD labels).
+ *
+ * Returns: 1 if the partitions is logical partition or 0 if not.
+ */
+int blkid_partition_is_logical(blkid_partition par)
+{
+	return partition_get_logical_type(par) == 'L' ? TRUE : FALSE;
+}
+
+static void set_string(unsigned char *item, size_t max,
+				const unsigned char *data, size_t len)
+{
+	if (len >= max)
+		len = max - 1;
+
+	memcpy(item, data, len);
+	item[len] = '\0';
+
+	blkid_rtrim_whitespace(item);
+}
+
+int blkid_partition_set_name(blkid_partition par,
+		const unsigned char *name, size_t len)
+{
+	if (!par)
+		return -1;
+
+	set_string(par->name, sizeof(par->name), name, len);
+	return 0;
+}
+
+int blkid_partition_set_utf8name(blkid_partition par, const unsigned char *name,
+		size_t len, int enc)
+{
+	if (!par)
+		return -1;
+
+	blkid_encode_to_utf8(enc, par->name, sizeof(par->name), name, len);
+	blkid_rtrim_whitespace(par->name);
+	return 0;
+}
+
+int blkid_partition_set_uuid(blkid_partition par, const unsigned char *uuid)
+{
+	if (!par)
+		return -1;
+
+	blkid_unparse_uuid(uuid, par->uuid, sizeof(par->uuid));
+	return 0;
+}
+
+int blkid_partition_gen_uuid(blkid_partition par)
+{
+	if (!par || !par->tab || !*par->tab->id)
+		return -1;
+
+	snprintf(par->uuid, sizeof(par->uuid), "%s-%02x",
+			par->tab->id, par->partno);
+	return 0;
+}
+
+/**
+ * blkid_partition_get_name:
+ * @par: partition
+ *
+ * Returns: partition name string if supported by PT (e.g. Mac) or NULL.
+ */
+const char *blkid_partition_get_name(blkid_partition par)
+{
+	return par && *par->name ? (char *) par->name : NULL;
+}
+
+/**
+ * blkid_partition_get_uuid:
+ * @par: partition
+ *
+ * Returns: partition UUID string if supported by PT (e.g. GPT) or NULL.
+ */
+const char *blkid_partition_get_uuid(blkid_partition par)
+{
+	return par && *par->uuid ? par->uuid : NULL;
+}
+
+/**
+ * blkid_partition_get_partno:
+ * @par: partition
+ *
+ * Returns: proposed partitin number (e.g. 'N' from sda'N') or -1 in case of
+ * error. Note that the number is generate by library independenly on your OS.
+ */
+int blkid_partition_get_partno(blkid_partition par)
+{
+	return par ? par->partno : -1;
+}
+
+/**
+ * blkid_partition_get_start:
+ * @par: partition
+ *
+ * Be careful if you _not_ probe whole disk:
+ *
+ * 1) the offset is usully relative to begin of the disk -- but if you probe a
+ *    fragment of the disk only -- then the offset could be still relative to
+ *    the begin of the disk rather that relative to the fragment.
+ *
+ * 2) the offset for nested partitions could be releative to parent (e.g. Solaris)
+ *    _or_ relative to the begin of the whole disk (e.g. bsd).
+ *
+ * You don't have to care about such details if you proble whole disk. In such
+ * a case libblkid always returns the offset relative to the begin of the disk.
+ *
+ * Returns: start of the partition (in 512-sectors).
+ */
+blkid_loff_t blkid_partition_get_start(blkid_partition par)
+{
+	return par ? par->start : -1;
+}
+
+/**
+ * blkid_partition_get_size:
+ * @par: partition
+ *
+ * WARNING: be very careful when you work with MS-DOS extended partitions. The
+ *          library always returns full size of the partition. If you want add
+ *          the partition to the Linux system (BLKPG_ADD_PARTITION ioctl) you
+ *          need to reduce the size of the partition to 1 or 2 blocks. The
+ *          rest of the partition has to be unaccessible for mkfs or mkswap
+ *          programs, we need a small space for boot loaders only.
+ *
+ *          For some unknown reason this (safe) practice is not to used for
+ *          nested BSD, Solaris, ..., partition tables in Linux kernel.
+ *
+ * Returns: size of the partition (in 512-sectors).
+ */
+blkid_loff_t blkid_partition_get_size(blkid_partition par)
+{
+	return par ? par->size : -1;
+}
+
+/**
+ * blkid_partition_get_type:
+ * @par: partition
+ *
+ * Returns: partition type.
+ */
+int blkid_partition_get_type(blkid_partition par)
+{
+	return par->type;
+}
+
+/* Sets partition 'type' for PT where the type is defined by string rather
+ * than by number
+ */
+int blkid_partition_set_type_string(blkid_partition par,
+		const unsigned char *type, size_t len)
+{
+	if (!par)
+		return -1;
+
+	set_string((unsigned char *) par->typestr,
+			sizeof(par->typestr), type, len);
+	return 0;
+}
+
+/* Sets partition 'type' for PT where the type is defined by UUIDrather
+ * than by number
+ */
+int blkid_partition_set_type_uuid(blkid_partition par, const unsigned char *uuid)
+{
+	if (!par)
+		return -1;
+
+	blkid_unparse_uuid(uuid, par->typestr, sizeof(par->typestr));
+	return 0;
+}
+
+/**
+ * blkid_partition_get_type_string:
+ * @par: partition
+ *
+ * The type string is supported by a small subset of partition tables (e.g Mac
+ * and EFI GPT).  Note that GPT uses type UUID and this function returns this
+ * UUID as string.
+ *
+ * Returns: partition type string or NULL.
+ */
+const char *blkid_partition_get_type_string(blkid_partition par)
+{
+	return par && *par->typestr ? par->typestr : NULL;
+}
+
+
+int blkid_partition_set_flags(blkid_partition par, unsigned long long flags)
+{
+	if (!par)
+		return -1;
+	par->flags = flags;
+	return 0;
+}
+
+/**
+ * blkid_partition_get_flags
+ * @par: partition
+ *
+ * Returns: partition flags (or attributes for gpt).
+ */
+unsigned long long blkid_partition_get_flags(blkid_partition par)
+{
+	return par->flags;
+}
+
diff --git a/libblkid/src/partitions/partitions.h b/libblkid/src/partitions/partitions.h
new file mode 100644
index 0000000..3651bbb
--- /dev/null
+++ b/libblkid/src/partitions/partitions.h
@@ -0,0 +1,71 @@
+#ifndef BLKID_PARTITIONS_H
+#define BLKID_PARTITIONS_H
+
+#include "blkidP.h"
+#include "pt-mbr.h"
+
+extern int blkid_partitions_get_flags(blkid_probe pr);
+
+extern blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls,
+				const char *type, blkid_loff_t offset);
+
+extern int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id);
+extern int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id);
+
+extern blkid_partition blkid_partlist_add_partition(blkid_partlist ls,
+				blkid_parttable tab,
+				blkid_loff_t start, blkid_loff_t size);
+
+extern int blkid_partlist_set_partno(blkid_partlist ls, int partno);
+extern int blkid_partlist_increment_partno(blkid_partlist ls);
+
+extern blkid_partition blkid_partlist_get_parent(blkid_partlist ls);
+
+extern int blkid_partitions_do_subprobe(blkid_probe pr,
+			blkid_partition parent, const struct blkid_idinfo *id);
+
+extern int blkid_partitions_need_typeonly(blkid_probe pr);
+extern int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid);
+extern int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str);
+
+
+extern int blkid_is_nested_dimension(blkid_partition par,
+                        blkid_loff_t start, blkid_loff_t size);
+
+extern int blkid_partition_set_name(blkid_partition par,
+		const unsigned char *name, size_t len);
+
+extern int blkid_partition_set_utf8name(blkid_partition par,
+		const unsigned char *name, size_t len, int enc);
+
+extern int blkid_partition_set_uuid(blkid_partition par,
+		const unsigned char *uuid);
+extern int blkid_partition_gen_uuid(blkid_partition par);
+
+extern int blkid_partition_set_type(blkid_partition par, int type);
+
+extern int blkid_partition_set_type_string(blkid_partition par,
+                const unsigned char *type, size_t len);
+
+extern int blkid_partition_set_type_uuid(blkid_partition par,
+		const unsigned char *uuid);
+
+extern int blkid_partition_set_flags(blkid_partition par, unsigned long long flags);
+
+/*
+ * partition probers
+ */
+extern const struct blkid_idinfo aix_pt_idinfo;
+extern const struct blkid_idinfo bsd_pt_idinfo;
+extern const struct blkid_idinfo unixware_pt_idinfo;
+extern const struct blkid_idinfo solaris_x86_pt_idinfo;
+extern const struct blkid_idinfo sun_pt_idinfo;
+extern const struct blkid_idinfo sgi_pt_idinfo;
+extern const struct blkid_idinfo mac_pt_idinfo;
+extern const struct blkid_idinfo dos_pt_idinfo;
+extern const struct blkid_idinfo minix_pt_idinfo;
+extern const struct blkid_idinfo gpt_pt_idinfo;
+extern const struct blkid_idinfo pmbr_pt_idinfo;
+extern const struct blkid_idinfo ultrix_pt_idinfo;
+
+#endif /* BLKID_PARTITIONS_H */
diff --git a/libblkid/src/partitions/sgi.c b/libblkid/src/partitions/sgi.c
new file mode 100644
index 0000000..99c0bf1
--- /dev/null
+++ b/libblkid/src/partitions/sgi.c
@@ -0,0 +1,87 @@
+/*
+ * sgi partition parsing code
+ *
+ * Copyright (C) 2009 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 <stdint.h>
+
+#include "partitions.h"
+#include "pt-sgi.h"
+
+static int probe_sgi_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct sgi_disklabel *l;
+	struct sgi_partition *p;
+	blkid_parttable tab = NULL;
+	blkid_partlist ls;
+	int i;
+
+	l = (struct sgi_disklabel *) blkid_probe_get_sector(pr, 0);
+	if (!l) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	if (sgi_pt_checksum(l)) {
+		DBG(LOWPROBE, ul_debug(
+			"detected corrupted sgi disk label -- ignore"));
+		goto nothing;
+	}
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return BLKID_PROBE_OK;
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	tab = blkid_partlist_new_parttable(ls, "sgi", 0);
+	if (!tab)
+		goto err;
+
+	for(i = 0, p = &l->partitions[0]; i < SGI_MAXPARTITIONS; i++, p++) {
+		uint32_t size = be32_to_cpu(p->num_blocks);
+		uint32_t start = be32_to_cpu(p->first_block);
+		uint32_t type = be32_to_cpu(p->type);
+		blkid_partition par;
+
+		if (!size) {
+			blkid_partlist_increment_partno(ls);
+			continue;
+		}
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par)
+			goto err;
+
+		blkid_partition_set_type(par, type);
+	}
+
+	return BLKID_PROBE_OK;
+
+nothing:
+	return BLKID_PROBE_NONE;
+err:
+	return -ENOMEM;
+}
+
+const struct blkid_idinfo sgi_pt_idinfo =
+{
+	.name		= "sgi",
+	.probefunc	= probe_sgi_pt,
+	.magics		=
+	{
+		{ .magic = "\x0B\xE5\xA9\x41", .len = 4	},
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/partitions/solaris_x86.c b/libblkid/src/partitions/solaris_x86.c
new file mode 100644
index 0000000..4ac9be5
--- /dev/null
+++ b/libblkid/src/partitions/solaris_x86.c
@@ -0,0 +1,154 @@
+/*
+ * Solaris x86 partition parsing code
+ *
+ * Copyright (C) 2009 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 <stdint.h>
+
+#include "partitions.h"
+
+/*
+ * Solaris-x86 is always within primary dos partition (nested PT table).  The
+ * solaris-x86 vtoc allows to split the entire partition to "slices". The
+ * offset (start) of the slice is always relatively to the primary dos
+ * partition.
+ *
+ * Note that Solaris-SPARC uses entire disk with a different partitionning
+ * scheme.
+ */
+
+/* some other implementation than Linux kernel assume 8 partitions only */
+#define SOLARIS_MAXPARTITIONS	16
+
+/* disklabel (vtoc) location  */
+#define SOLARIS_SECTOR		1			/* in 512-sectors */
+#define SOLARIS_OFFSET		(SOLARIS_SECTOR << 9)	/* in bytes */
+#define SOLARIS_MAGICOFFSET	(SOLARIS_OFFSET + 12)	/* v_sanity offset in bytes */
+
+/* slice tags */
+#define SOLARIS_TAG_WHOLEDISK	5
+
+struct solaris_slice {
+	uint16_t s_tag;      /* ID tag of partition */
+	uint16_t s_flag;     /* permission flags */
+	uint32_t s_start;    /* start sector no of partition */
+	uint32_t s_size;     /* # of blocks in partition */
+} __attribute__((packed));
+
+struct solaris_vtoc {
+	unsigned int v_bootinfo[3];     /* info needed by mboot (unsupported) */
+
+	uint32_t     v_sanity;          /* to verify vtoc sanity */
+	uint32_t     v_version;         /* layout version */
+	char         v_volume[8];       /* volume name */
+	uint16_t     v_sectorsz;        /* sector size in bytes */
+	uint16_t     v_nparts;          /* number of partitions */
+	unsigned int v_reserved[10];    /* free space */
+
+	struct solaris_slice v_slice[SOLARIS_MAXPARTITIONS]; /* slices */
+
+	unsigned int timestamp[SOLARIS_MAXPARTITIONS]; /* timestamp (unsupported) */
+	char         v_asciilabel[128];	/* for compatibility */
+} __attribute__((packed));
+
+static int probe_solaris_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct solaris_vtoc *l;	/* disk label */
+	struct solaris_slice *p;	/* partitsion */
+	blkid_parttable tab = NULL;
+	blkid_partition parent;
+	blkid_partlist ls;
+	int i;
+	uint16_t nparts;
+
+	l = (struct solaris_vtoc *) blkid_probe_get_sector(pr, SOLARIS_SECTOR);
+	if (!l) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	if (le32_to_cpu(l->v_version) != 1) {
+		DBG(LOWPROBE, ul_debug(
+			"WARNING: unsupported solaris x86 version %d, ignore",
+			le32_to_cpu(l->v_version)));
+		goto nothing;
+	}
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return BLKID_PROBE_OK;
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	parent = blkid_partlist_get_parent(ls);
+
+	tab = blkid_partlist_new_parttable(ls, "solaris", SOLARIS_OFFSET);
+	if (!tab)
+		goto err;
+
+	nparts = le16_to_cpu(l->v_nparts);
+	if (nparts > SOLARIS_MAXPARTITIONS)
+		nparts = SOLARIS_MAXPARTITIONS;
+
+	for (i = 1, p = &l->v_slice[0];	i < nparts; i++, p++) {
+
+		uint32_t start = le32_to_cpu(p->s_start);
+		uint32_t size = le32_to_cpu(p->s_size);
+		blkid_partition par;
+
+		if (size == 0 || le16_to_cpu(p->s_tag) == SOLARIS_TAG_WHOLEDISK)
+			continue;
+
+		if (parent)
+			/* Solaris slices are relative to the parent (primary
+			 * DOS partition) */
+			start += blkid_partition_get_start(parent);
+
+		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
+			DBG(LOWPROBE, ul_debug(
+				"WARNING: solaris partition (%d) overflow "
+				"detected, ignore", i));
+			continue;
+		}
+
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par)
+			goto err;
+
+		blkid_partition_set_type(par, le16_to_cpu(p->s_tag));
+		blkid_partition_set_flags(par, le16_to_cpu(p->s_flag));
+	}
+
+	return BLKID_PROBE_OK;
+
+nothing:
+	return BLKID_PROBE_NONE;
+err:
+	return -ENOMEM;
+}
+
+const struct blkid_idinfo solaris_x86_pt_idinfo =
+{
+	.name		= "solaris",
+	.probefunc	= probe_solaris_pt,
+	.magics		=
+	{
+		{
+		  .magic = "\xEE\xDE\x0D\x60",	/* little-endian magic string */
+		  .len = 4,			/* v_sanity size in bytes */
+		  .sboff = SOLARIS_MAGICOFFSET	/* offset of v_sanity */
+		},
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/partitions/sun.c b/libblkid/src/partitions/sun.c
new file mode 100644
index 0000000..22ee450
--- /dev/null
+++ b/libblkid/src/partitions/sun.c
@@ -0,0 +1,125 @@
+/*
+ * sun (solaris-sparc) partition parsing code
+ *
+ * Copyright (C) 2009 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 <stdint.h>
+#include <stddef.h>
+
+#include "pt-sun.h"
+#include "partitions.h"
+
+static int probe_sun_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct sun_disklabel *l;
+	struct sun_partition *p;
+	blkid_parttable tab = NULL;
+	blkid_partlist ls;
+	uint16_t nparts;
+	blkid_loff_t spc;
+	int i, use_vtoc;
+
+	l = (struct sun_disklabel *) blkid_probe_get_sector(pr, 0);
+	if (!l) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	if (sun_pt_checksum(l)) {
+		DBG(LOWPROBE, ul_debug(
+			"detected corrupted sun disk label -- ignore"));
+		goto nothing;
+	}
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return BLKID_PROBE_OK;
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	tab = blkid_partlist_new_parttable(ls, "sun", 0);
+	if (!tab)
+		goto err;
+
+	/* sectors per cylinder (partition offset is in cylinders...) */
+	spc = be16_to_cpu(l->nhead) * be16_to_cpu(l->nsect);
+
+	DBG(LOWPROBE, ul_debug("Sun VTOC sanity=%u version=%u nparts=%u",
+			be32_to_cpu(l->vtoc.sanity),
+			be32_to_cpu(l->vtoc.version),
+			be16_to_cpu(l->vtoc.nparts)));
+
+	/* Check to see if we can use the VTOC table */
+	use_vtoc = ((be32_to_cpu(l->vtoc.sanity) == SUN_VTOC_SANITY) &&
+		    (be32_to_cpu(l->vtoc.version) == SUN_VTOC_VERSION) &&
+		    (be16_to_cpu(l->vtoc.nparts) <= SUN_MAXPARTITIONS));
+
+	/* Use 8 partition entries if not specified in validated VTOC */
+	nparts = use_vtoc ? be16_to_cpu(l->vtoc.nparts) : SUN_MAXPARTITIONS;
+
+	/*
+	 * So that old Linux-Sun partitions continue to work,
+	 * alow the VTOC to be used under the additional condition ...
+	 */
+	use_vtoc = use_vtoc || !(l->vtoc.sanity || l->vtoc.version || l->vtoc.nparts);
+
+	for (i = 0, p = l->partitions; i < nparts; i++, p++) {
+
+		blkid_loff_t start, size;
+		uint16_t type = 0, flags = 0;
+		blkid_partition par;
+
+		start = be32_to_cpu(p->start_cylinder) * spc;
+		size = be32_to_cpu(p->num_sectors);
+		if (use_vtoc) {
+			type = be16_to_cpu(l->vtoc.infos[i].id);
+			flags = be16_to_cpu(l->vtoc.infos[i].flags);
+		}
+
+		if (type == SUN_TAG_WHOLEDISK || !size) {
+			blkid_partlist_increment_partno(ls);
+			continue;
+		}
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par)
+			goto err;
+
+		if (type)
+			blkid_partition_set_type(par, type);
+		if (flags)
+			blkid_partition_set_flags(par, flags);
+	}
+	return BLKID_PROBE_OK;
+
+nothing:
+	return BLKID_PROBE_NONE;
+err:
+	return -ENOMEM;
+}
+
+
+const struct blkid_idinfo sun_pt_idinfo =
+{
+	.name		= "sun",
+	.probefunc	= probe_sun_pt,
+	.magics		=
+	{
+		{
+		  .magic = "\xDA\xBE",		/* big-endian magic string */
+		  .len = 2,
+		  .sboff = offsetof(struct sun_disklabel, magic)
+		},
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/partitions/ultrix.c b/libblkid/src/partitions/ultrix.c
new file mode 100644
index 0000000..9c060be
--- /dev/null
+++ b/libblkid/src/partitions/ultrix.c
@@ -0,0 +1,99 @@
+/*
+ * uktrix partition parsing code
+ *
+ * Copyright (C) 2010 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 <stdint.h>
+
+#include "partitions.h"
+
+#define ULTRIX_MAXPARTITIONS	8
+
+#define ULTRIX_MAGIC		0x032957
+#define ULTRIX_MAGIC_STR	"\x02\x29\x57"
+
+/* sector with partition table */
+#define ULTRIX_SECTOR		((16384 - sizeof(struct ultrix_disklabel)) >> 9)
+/* position of partition table within ULTRIX_SECTOR */
+#define ULTRIX_OFFSET		(512 - sizeof(struct ultrix_disklabel))
+
+struct ultrix_disklabel {
+	int32_t	pt_magic;	/* magic no. indicating part. info exits */
+	int32_t	pt_valid;	/* set by driver if pt is current */
+	struct  pt_info {
+		int32_t		pi_nblocks; /* no. of sectors */
+		uint32_t	pi_blkoff;  /* block offset for start */
+	} pt_part[ULTRIX_MAXPARTITIONS];
+} __attribute__((packed));
+
+
+static int probe_ultrix_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	unsigned char *data;
+	struct ultrix_disklabel *l;
+	blkid_parttable tab = NULL;
+	blkid_partlist ls;
+	int i;
+
+	data = blkid_probe_get_sector(pr, ULTRIX_SECTOR);
+	if (!data) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	l = (struct ultrix_disklabel *) (data + ULTRIX_OFFSET);
+
+	if (l->pt_magic != ULTRIX_MAGIC || l->pt_valid != 1)
+		goto nothing;
+
+	if (blkid_probe_set_magic(pr, (ULTRIX_SECTOR << 9) + ULTRIX_OFFSET,
+			sizeof(ULTRIX_MAGIC_STR) - 1,
+			(unsigned char *) ULTRIX_MAGIC_STR))
+		goto err;
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return BLKID_PROBE_OK;
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	tab = blkid_partlist_new_parttable(ls, "ultrix", 0);
+	if (!tab)
+		goto err;
+
+	for (i = 0; i < ULTRIX_MAXPARTITIONS; i++) {
+		if (!l->pt_part[i].pi_nblocks)
+			 blkid_partlist_increment_partno(ls);
+		else {
+			if (!blkid_partlist_add_partition(ls, tab,
+						l->pt_part[i].pi_blkoff,
+						l->pt_part[i].pi_nblocks))
+				goto err;
+		}
+	}
+
+	return BLKID_PROBE_OK;
+nothing:
+	return BLKID_PROBE_NONE;
+err:
+	return -ENOMEM;
+}
+
+const struct blkid_idinfo ultrix_pt_idinfo =
+{
+	.name		= "ultrix",
+	.probefunc	= probe_ultrix_pt,
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/partitions/unixware.c b/libblkid/src/partitions/unixware.c
new file mode 100644
index 0000000..6742bcf
--- /dev/null
+++ b/libblkid/src/partitions/unixware.c
@@ -0,0 +1,197 @@
+/*
+ * unixware partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ *
+ * The intersting information about unixware PT:
+ *   - Linux kernel / partx
+ *   - vtoc(7) SCO UNIX command man page
+ *   - evms source code (http://evms.sourceforge.net/)
+ *   - vxtools source code (http://martin.hinner.info/fs/vxfs/)
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+
+/* disklabel location */
+#define UNIXWARE_SECTOR		29
+#define UNIXWARE_OFFSET		(UNIXWARE_SECTOR << 9)	/* offset in bytes */
+#define UNIXWARE_KBOFFSET	(UNIXWARE_OFFSET >> 10)	/* offset in 1024-blocks */
+
+/* disklabel->d_magic offset within the last 1024 block */
+#define UNIXWARE_MAGICOFFSET	(UNIXWARE_OFFSET - UNIXWARE_KBOFFSET + 4)
+
+#define UNIXWARE_VTOCMAGIC	0x600DDEEEUL
+#define UNIXWARE_MAXPARTITIONS	16
+
+/* unixware_partition->s_label flags */
+#define UNIXWARE_TAG_UNUSED       0x0000  /* unused partition */
+#define UNIXWARE_TAG_BOOT         0x0001  /* boot fs */
+#define UNIXWARE_TAG_ROOT         0x0002  /* root fs */
+#define UNIXWARE_TAG_SWAP         0x0003  /* swap fs */
+#define UNIXWARE_TAG_USER         0x0004  /* user fs */
+#define UNIXWARE_TAG_ENTIRE_DISK  0x0005  /* whole disk */
+#define UNIXWARE_TAG_ALT_S        0x0006  /* alternate sector space */
+#define UNIXWARE_TAG_OTHER        0x0007  /* non unix */
+#define UNIXWARE_TAG_ALT_T        0x0008  /* alternate track space */
+#define UNIXWARE_TAG_STAND        0x0009  /* stand partition */
+#define UNIXWARE_TAG_VAR          0x000a  /* var partition */
+#define UNIXWARE_TAG_HOME         0x000b  /* home partition */
+#define UNIXWARE_TAG_DUMP         0x000c  /* dump partition */
+#define UNIXWARE_TAG_ALT_ST       0x000d  /* alternate sector track */
+#define UNIXWARE_TAG_VM_PUBLIC    0x000e  /* volume mgt public partition */
+#define UNIXWARE_TAG_VM_PRIVATE   0x000f  /* volume mgt private partition */
+
+
+/* unixware_partition->s_flags flags */
+#define UNIXWARE_FLAG_VALID	0x0200
+
+struct unixware_partition {
+	uint16_t	s_label;	/* partition label (tag) */
+	uint16_t	s_flags;	/* permission flags */
+	uint32_t	start_sect;	/* starting sector */
+	uint32_t	nr_sects;	/* number of sectors */
+} __attribute__((packed));
+
+struct unixware_disklabel {
+	uint32_t	d_type;		/* drive type */
+	uint32_t	d_magic;	/* the magic number */
+	uint32_t	d_version;	/* version number */
+	char		d_serial[12];	/* serial number of the device */
+	uint32_t	d_ncylinders;	/* # of data cylinders per device */
+	uint32_t	d_ntracks;	/* # of tracks per cylinder */
+	uint32_t	d_nsectors;	/* # of data sectors per track */
+	uint32_t	d_secsize;	/* # of bytes per sector */
+	uint32_t	d_part_start;	/* # of first sector of this partition */
+	uint32_t	d_unknown1[12];	/* ? */
+	uint32_t	d_alt_tbl;	/* byte offset of alternate table */
+	uint32_t	d_alt_len;	/* byte length of alternate table */
+	uint32_t	d_phys_cyl;	/* # of physical cylinders per device */
+	uint32_t	d_phys_trk;	/* # of physical tracks per cylinder */
+	uint32_t	d_phys_sec;	/* # of physical sectors per track */
+	uint32_t	d_phys_bytes;	/* # of physical bytes per sector */
+	uint32_t	d_unknown2;	/* ? */
+	uint32_t	d_unknown3;	/* ? */
+	uint32_t	d_pad[8];	/* pad */
+
+	struct unixware_vtoc {
+		uint32_t	v_magic;	/* the magic number */
+		uint32_t	v_version;	/* version number */
+		char		v_name[8];	/* volume name */
+		uint16_t	v_nslices;	/* # of partitions */
+		uint16_t	v_unknown1;	/* ? */
+		uint32_t	v_reserved[10];	/* reserved */
+
+		struct unixware_partition
+			v_slice[UNIXWARE_MAXPARTITIONS]; /* partition */
+	} __attribute__((packed)) vtoc;
+};
+
+static int probe_unixware_pt(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct unixware_disklabel *l;
+	struct unixware_partition *p;
+	blkid_parttable tab = NULL;
+	blkid_partition parent;
+	blkid_partlist ls;
+	int i;
+
+	l = (struct unixware_disklabel *)
+			blkid_probe_get_sector(pr, UNIXWARE_SECTOR);
+	if (!l) {
+		if (errno)
+			return -errno;
+		goto nothing;
+	}
+
+	if (le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_VTOCMAGIC)
+		goto nothing;
+
+	if (blkid_partitions_need_typeonly(pr))
+		/* caller does not ask for details about partitions */
+		return BLKID_PROBE_OK;
+
+	ls = blkid_probe_get_partlist(pr);
+	if (!ls)
+		goto nothing;
+
+	parent = blkid_partlist_get_parent(ls);
+
+	tab = blkid_partlist_new_parttable(ls, "unixware", UNIXWARE_OFFSET);
+	if (!tab)
+		goto err;
+
+	/* Skip the first partition that describe whole disk
+	 */
+	for (i = 1, p = &l->vtoc.v_slice[1];
+			i < UNIXWARE_MAXPARTITIONS; i++, p++) {
+
+		uint32_t start, size;
+		uint16_t tag, flg;
+		blkid_partition par;
+
+		tag = le16_to_cpu(p->s_label);
+		flg = le16_to_cpu(p->s_flags);
+
+		if (tag == UNIXWARE_TAG_UNUSED ||
+		    tag == UNIXWARE_TAG_ENTIRE_DISK ||
+		    flg != UNIXWARE_FLAG_VALID)
+			continue;
+
+		start = le32_to_cpu(p->start_sect);
+		size = le32_to_cpu(p->nr_sects);
+
+		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
+			DBG(LOWPROBE, ul_debug(
+				"WARNING: unixware partition (%d) overflow "
+				"detected, ignore", i));
+			continue;
+		}
+
+		par = blkid_partlist_add_partition(ls, tab, start, size);
+		if (!par)
+			goto err;
+
+		blkid_partition_set_type(par, tag);
+		blkid_partition_set_flags(par, flg);
+	}
+
+	return BLKID_PROBE_OK;
+
+nothing:
+	return BLKID_PROBE_NONE;
+err:
+	return -ENOMEM;
+}
+
+
+/*
+ * The unixware partition table is within primary DOS partition.  The PT is
+ * located on 29 sector, PT magic string is d_magic member of 'struct
+ * unixware_disklabel'.
+ */
+const struct blkid_idinfo unixware_pt_idinfo =
+{
+	.name		= "unixware",
+	.probefunc	= probe_unixware_pt,
+	.minsz		= 1024 * 1440 + 1,		/* ignore floppies */
+	.magics		=
+	{
+		{
+		  .magic = "\x0D\x60\xE5\xCA",	/* little-endian magic string */
+		  .len = 4,			/* d_magic size in bytes */
+		  .kboff = UNIXWARE_KBOFFSET,
+		  .sboff = UNIXWARE_MAGICOFFSET
+		},
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/pathnames.h b/libblkid/src/pathnames.h
new file mode 100644
index 0000000..0d21b98
--- /dev/null
+++ b/libblkid/src/pathnames.h
@@ -0,0 +1,196 @@
+/*
+ * Vaguely based on
+ *	@(#)pathnames.h	5.3 (Berkeley) 5/9/89
+ * This code is in the public domain.
+ */
+#ifndef PATHNAMES_H
+#define PATHNAMES_H
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifndef __STDC__
+# error "we need an ANSI compiler"
+#endif
+
+/* used by kernel in /proc (e.g. /proc/swaps) for deleted files */
+#define PATH_DELETED_SUFFIX	"\\040(deleted)"
+#define PATH_DELETED_SUFFIX_SZ	(sizeof(PATH_DELETED_SUFFIX) - 1)
+
+/* DEFPATHs from <paths.h> don't include /usr/local */
+#undef _PATH_DEFPATH
+#define	_PATH_DEFPATH	        "/usr/local/bin:/bin:/usr/bin"
+
+#undef _PATH_DEFPATH_ROOT
+#define	_PATH_DEFPATH_ROOT	"/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
+
+#define _PATH_SECURETTY		"/etc/securetty"
+#define _PATH_WTMPLOCK		"/etc/wtmplock"
+
+#define	_PATH_HUSHLOGIN		".hushlogin"
+#define	_PATH_HUSHLOGINS	"/etc/hushlogins"
+
+#define _PATH_NOLOGIN_TXT	"/etc/nologin.txt"
+
+#ifndef _PATH_MAILDIR
+#define	_PATH_MAILDIR		"/var/spool/mail"
+#endif
+#define	_PATH_MOTDFILE		"/etc/motd"
+#define	_PATH_NOLOGIN		"/etc/nologin"
+#define	_PATH_VAR_NOLOGIN	"/var/run/nologin"
+
+#define _PATH_LOGIN		"/bin/login"
+#define _PATH_INITTAB		"/etc/inittab"
+#define _PATH_RC		"/etc/rc"
+#define _PATH_REBOOT		"/sbin/reboot"
+#define _PATH_SHUTDOWN		"/sbin/shutdown"
+#define _PATH_SINGLE		"/etc/singleboot"
+#define _PATH_SHUTDOWN_CONF	"/etc/shutdown.conf"
+
+#define _PATH_SECURE		"/etc/securesingle"
+#define _PATH_USERTTY           "/etc/usertty"
+
+#define _PATH_TERMCOLORS_DIRNAME "terminal-colors.d"
+#define _PATH_TERMCOLORS_DIR	"/etc/" _PATH_TERMCOLORS_DIRNAME
+
+/* used in login-utils/shutdown.c */
+
+/* used in login-utils/setpwnam.h and login-utils/islocal.c */
+#define _PATH_PASSWD		"/etc/passwd"
+
+/* used in login-utils/newgrp and login-utils/setpwnam.h*/
+#define _PATH_GSHADOW		"/etc/gshadow"
+
+/* used in login-utils/setpwnam.h */
+#define _PATH_GROUP		"/etc/group"
+#define _PATH_SHADOW_PASSWD	"/etc/shadow"
+#define _PATH_SHELLS		"/etc/shells"
+
+/* used in term-utils/agetty.c */
+#define _PATH_ISSUE		"/etc/issue"
+#define _PATH_OS_RELEASE	"/etc/os-release"
+#define _PATH_NUMLOCK_ON	_PATH_LOCALSTATEDIR "/numlock-on"
+
+#define _PATH_LOGINDEFS		"/etc/login.defs"
+
+/* used in misc-utils/look.c */
+#define _PATH_WORDS             "/usr/share/dict/words"
+#define _PATH_WORDS_ALT         "/usr/share/dict/web2"
+
+/* mount paths */
+#define _PATH_UMOUNT		"/bin/umount"
+
+#define _PATH_FILESYSTEMS	"/etc/filesystems"
+#define _PATH_PROC_SWAPS	"/proc/swaps"
+#define _PATH_PROC_FILESYSTEMS	"/proc/filesystems"
+#define _PATH_PROC_MOUNTS	"/proc/mounts"
+#define _PATH_PROC_PARTITIONS	"/proc/partitions"
+#define _PATH_PROC_DEVICES	"/proc/devices"
+#define _PATH_PROC_MOUNTINFO	"/proc/self/mountinfo"
+#define _PATH_PROC_LOCKS        "/proc/locks"
+#define _PATH_PROC_CDROMINFO	"/proc/sys/dev/cdrom/info"
+
+#define _PATH_PROC_UIDMAP	"/proc/self/uid_map"
+#define _PATH_PROC_GIDMAP	"/proc/self/gid_map"
+
+#define _PATH_PROC_ATTR_CURRENT	"/proc/self/attr/current"
+#define _PATH_PROC_ATTR_EXEC	"/proc/self/attr/exec"
+#define _PATH_PROC_CAPLASTCAP	"/proc/sys/kernel/cap_last_cap"
+
+
+#define _PATH_SYS_BLOCK		"/sys/block"
+#define _PATH_SYS_DEVBLOCK	"/sys/dev/block"
+#define _PATH_SYS_CLASS		"/sys/class"
+#define _PATH_SYS_SCSI		"/sys/bus/scsi"
+
+#define _PATH_SYS_SELINUX	"/sys/fs/selinux"
+#define _PATH_SYS_APPARMOR	"/sys/kernel/security/apparmor"
+
+#ifndef _PATH_MOUNTED
+# ifdef MOUNTED					/* deprecated */
+#  define _PATH_MOUNTED		MOUNTED
+# else
+#  define _PATH_MOUNTED		"/etc/mtab"
+# endif
+#endif
+
+#ifndef _PATH_MNTTAB
+# ifdef MNTTAB					/* deprecated */
+#  define _PATH_MNTTAB		MNTTAB
+# else
+#  define _PATH_MNTTAB		"/etc/fstab"
+# endif
+#endif
+
+#define _PATH_MNTTAB_DIR	_PATH_MNTTAB ".d"
+
+#define _PATH_MOUNTED_LOCK	_PATH_MOUNTED "~"
+#define _PATH_MOUNTED_TMP	_PATH_MOUNTED ".tmp"
+
+#ifndef _PATH_DEV
+  /*
+   * The tailing '/' in _PATH_DEV is there for compatibility with libc.
+   */
+# define _PATH_DEV		"/dev/"
+#endif
+
+#define _PATH_DEV_MEM		"/dev/mem"
+
+#define _PATH_DEV_LOOP		"/dev/loop"
+#define _PATH_DEV_LOOPCTL	"/dev/loop-control"
+#define _PATH_DEV_TTY		"/dev/tty"
+
+
+/* udev paths */
+#define _PATH_DEV_BYLABEL	"/dev/disk/by-label"
+#define _PATH_DEV_BYUUID	"/dev/disk/by-uuid"
+#define _PATH_DEV_BYID		"/dev/disk/by-id"
+#define _PATH_DEV_BYPATH	"/dev/disk/by-path"
+#define _PATH_DEV_BYPARTLABEL	"/dev/disk/by-partlabel"
+#define _PATH_DEV_BYPARTUUID	"/dev/disk/by-partuuid"
+
+/* hwclock paths */
+#ifdef CONFIG_ADJTIME_PATH
+# define _PATH_ADJTIME		CONFIG_ADJTIME_PATH
+#else
+# define _PATH_ADJTIME		"/etc/adjtime"
+#endif
+
+#define _PATH_LASTDATE		"/var/lib/lastdate"
+#ifdef __ia64__
+# define _PATH_RTC_DEV		"/dev/efirtc"
+#else
+# define _PATH_RTC_DEV		"/dev/rtc"
+#endif
+
+#ifndef _PATH_BTMP
+#define _PATH_BTMP		"/var/log/btmp"
+#endif
+
+/* raw paths*/
+#define _PATH_RAWDEVDIR		"/dev/raw/"
+#define _PATH_RAWDEVCTL		_PATH_RAWDEVDIR "rawctl"
+/* deprecated */
+#define _PATH_RAWDEVCTL_OLD	"/dev/rawctl"
+
+/* wdctl path */
+#define _PATH_WATCHDOG_DEV	"/dev/watchdog"
+
+/* ipc paths */
+#define _PATH_PROC_SYSV_MSG	"/proc/sysvipc/msg"
+#define _PATH_PROC_SYSV_SEM	"/proc/sysvipc/sem"
+#define _PATH_PROC_SYSV_SHM	"/proc/sysvipc/shm"
+#define _PATH_PROC_IPC_MSGMAX	"/proc/sys/kernel/msgmax"
+#define _PATH_PROC_IPC_MSGMNB	"/proc/sys/kernel/msgmnb"
+#define _PATH_PROC_IPC_MSGMNI	"/proc/sys/kernel/msgmni"
+#define _PATH_PROC_IPC_SEM	"/proc/sys/kernel/sem"
+#define _PATH_PROC_IPC_SHMALL	"/proc/sys/kernel/shmall"
+#define _PATH_PROC_IPC_SHMMAX	"/proc/sys/kernel/shmmax"
+#define _PATH_PROC_IPC_SHMMNI	"/proc/sys/kernel/shmmni"
+
+/* kernel command line */
+#define _PATH_PROC_CMDLINE	"/proc/cmdline"
+
+#endif /* PATHNAMES_H */
+
diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c
new file mode 100644
index 0000000..76ac099
--- /dev/null
+++ b/libblkid/src/probe.c
@@ -0,0 +1,1834 @@
+/*
+ * Low-level libblkid probing API
+ *
+ * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: lowprobe
+ * @title: Low-level probing
+ * @short_description: low-level prober initialization
+ *
+ * The low-level probing routines always and directly read information from
+ * the selected (see blkid_probe_set_device()) device.
+ *
+ * The probing routines are grouped together into separate chains. Currently,
+ * the library provides superblocks, partitions and topology chains.
+ *
+ * The probing routines is possible to filter (enable/disable) by type (e.g.
+ * fstype "vfat" or partype "gpt") or by usage flags (e.g. BLKID_USAGE_RAID).
+ * These filters are per-chain. Note that always when you touch the chain
+ * filter the current probing position is reset and probing starts from
+ * scratch.  It means that the chain filter should not be modified during
+ * probing, for example in loop where you call blkid_do_probe().
+ *
+ * For more details see the chain specific documentation.
+ *
+ * The low-level API provides two ways how access to probing results.
+ *
+ *   1. The NAME=value (tag) interface. This interface is older and returns all data
+ *      as strings. This interface is generic for all chains.
+ *
+ *   2. The binary interfaces. These interfaces return data in the native formats.
+ *      The interface is always specific to the probing chain.
+ *
+ *  Note that the previous probing result (binary or NAME=value) is always
+ *  zeroized when a chain probing function is called. For example:
+ *
+ * <informalexample>
+ *   <programlisting>
+ *     blkid_probe_enable_partitions(pr, TRUE);
+ *     blkid_probe_enable_superblocks(pr, FALSE);
+ *
+ *     blkid_do_safeprobe(pr);
+ *   </programlisting>
+ * </informalexample>
+ *
+ * overwrites the previous probing result for the partitions chain, the superblocks
+ * result is not modified.
+ */
+
+/**
+ * SECTION: lowprobe-tags
+ * @title: Low-level tags
+ * @short_description: generic NAME=value interface.
+ *
+ * The probing routines inside the chain are mutually exclusive by default --
+ * only few probing routines are marked as "tolerant". The "tolerant" probing
+ * routines are used for filesystem which can share the same device with any
+ * other filesystem. The blkid_do_safeprobe() checks for the "tolerant" flag.
+ *
+ * The SUPERBLOCKS chain is enabled by default. The all others chains is
+ * necessary to enable by blkid_probe_enable_'CHAINNAME'(). See chains specific
+ * documentation.
+ *
+ * The blkid_do_probe() function returns a result from only one probing
+ * routine, and the next call from the next probing routine. It means you need
+ * to call the function in loop, for example:
+ *
+ * <informalexample>
+ *   <programlisting>
+ *	while((blkid_do_probe(pr) == 0)
+ *		... use result ...
+ *   </programlisting>
+ * </informalexample>
+ *
+ * The blkid_do_safeprobe() is the same as blkid_do_probe(), but returns only
+ * first probing result for every enabled chain. This function checks for
+ * ambivalent results (e.g. more "intolerant" filesystems superblocks on the
+ * device).
+ *
+ * The probing result is set of NAME=value pairs (the NAME is always unique).
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#ifdef HAVE_LINUX_CDROM_H
+#include <linux/cdrom.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#ifdef HAVE_LIBUUID
+# include <uuid.h>
+#endif
+
+#include "blkidP.h"
+#include <blkid.h>
+#include "all-io.h"
+#include "sysfs.h"
+#include "strutils.h"
+
+/* chains */
+extern const struct blkid_chaindrv superblocks_drv;
+extern const struct blkid_chaindrv topology_drv;
+extern const struct blkid_chaindrv partitions_drv;
+
+/*
+ * All supported chains
+ */
+static const struct blkid_chaindrv *chains_drvs[] = {
+	[BLKID_CHAIN_SUBLKS] = &superblocks_drv,
+	[BLKID_CHAIN_TOPLGY] = &topology_drv,
+	[BLKID_CHAIN_PARTS] = &partitions_drv
+};
+
+static void blkid_probe_reset_vals(blkid_probe pr);
+static void blkid_probe_reset_buffer(blkid_probe pr);
+
+/**
+ * blkid_new_probe:
+ *
+ * Returns: a pointer to the newly allocated probe struct or NULL in case of error.
+ */
+blkid_probe blkid_new_probe(void)
+{
+	int i;
+	blkid_probe pr;
+
+	blkid_init_debug(0);
+	pr = calloc(1, sizeof(struct blkid_struct_probe));
+	if (!pr)
+		return NULL;
+
+	DBG(LOWPROBE, ul_debug("allocate a new probe %p", pr));
+
+	/* initialize chains */
+	for (i = 0; i < BLKID_NCHAINS; i++) {
+		pr->chains[i].driver = chains_drvs[i];
+		pr->chains[i].flags = chains_drvs[i]->dflt_flags;
+		pr->chains[i].enabled = chains_drvs[i]->dflt_enabled;
+	}
+	INIT_LIST_HEAD(&pr->buffers);
+	return pr;
+}
+
+/*
+ * Clone @parent, the new clone shares all, but except:
+ *
+ *	- probing result
+ *	- bufferes if another device (or offset) is set to the prober
+ */
+blkid_probe blkid_clone_probe(blkid_probe parent)
+{
+	blkid_probe pr;
+
+	if (!parent)
+		return NULL;
+
+	DBG(LOWPROBE, ul_debug("allocate a probe clone"));
+
+	pr = blkid_new_probe();
+	if (!pr)
+		return NULL;
+
+	pr->fd = parent->fd;
+	pr->off = parent->off;
+	pr->size = parent->size;
+	pr->devno = parent->devno;
+	pr->disk_devno = parent->disk_devno;
+	pr->blkssz = parent->blkssz;
+	pr->flags = parent->flags;
+	pr->parent = parent;
+
+	pr->flags &= ~BLKID_FL_PRIVATE_FD;
+
+	return pr;
+}
+
+
+
+/**
+ * blkid_new_probe_from_filename:
+ * @filename: device or regular file
+ *
+ * This function is same as call open(filename), blkid_new_probe() and
+ * blkid_probe_set_device(pr, fd, 0, 0).
+ *
+ * The @filename is closed by blkid_free_probe() or by the
+ * blkid_probe_set_device() call.
+ *
+ * Returns: a pointer to the newly allocated probe struct or NULL in case of
+ * error.
+ */
+blkid_probe blkid_new_probe_from_filename(const char *filename)
+{
+	int fd = -1;
+	blkid_probe pr = NULL;
+
+	if (!filename)
+		return NULL;
+
+	fd = open(filename, O_RDONLY|O_CLOEXEC);
+	if (fd < 0)
+		return NULL;
+
+	pr = blkid_new_probe();
+	if (!pr)
+		goto err;
+
+	if (blkid_probe_set_device(pr, fd, 0, 0))
+		goto err;
+
+	pr->flags |= BLKID_FL_PRIVATE_FD;
+	return pr;
+err:
+	if (fd >= 0)
+		close(fd);
+	blkid_free_probe(pr);
+	return NULL;
+}
+
+/**
+ * blkid_free_probe:
+ * @pr: probe
+ *
+ * Deallocates the probe struct, buffers and all allocated
+ * data that are associated with this probing control struct.
+ */
+void blkid_free_probe(blkid_probe pr)
+{
+	int i;
+
+	if (!pr)
+		return;
+
+	for (i = 0; i < BLKID_NCHAINS; i++) {
+		struct blkid_chain *ch = &pr->chains[i];
+
+		if (ch->driver->free_data)
+			ch->driver->free_data(pr, ch->data);
+		free(ch->fltr);
+	}
+
+	if ((pr->flags & BLKID_FL_PRIVATE_FD) && pr->fd >= 0)
+		close(pr->fd);
+	blkid_probe_reset_buffer(pr);
+	blkid_free_probe(pr->disk_probe);
+
+	DBG(LOWPROBE, ul_debug("free probe %p", pr));
+	free(pr);
+}
+
+
+/*
+ * Removes chain values from probing result.
+ */
+void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn)
+{
+	int nvals = pr->nvals;
+	int i, x;
+
+	for (x = 0, i = 0; i < pr->nvals; i++) {
+		struct blkid_prval *v = &pr->vals[i];
+
+		if (v->chain != chn && x == i) {
+			x++;
+			continue;
+		}
+		if (v->chain == chn) {
+			--nvals;
+			continue;
+		}
+		memcpy(&pr->vals[x++], v, sizeof(struct blkid_prval));
+	}
+	pr->nvals = nvals;
+}
+
+static void blkid_probe_chain_reset_position(struct blkid_chain *chn)
+{
+	if (chn)
+		chn->idx = -1;
+}
+
+/*
+ * Copies chain values from probing result to @vals, the max size of @vals is
+ * @nvals and returns real number of values.
+ */
+int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn,
+		struct blkid_prval *vals, int nvals)
+{
+	int i, x;
+
+	for (x = 0, i = 0; i < pr->nvals && x < nvals; i++) {
+		struct blkid_prval *v = &pr->vals[i];
+
+		if (v->chain != chn)
+			continue;
+		memcpy(&vals[x++], v, sizeof(struct blkid_prval));
+	}
+	return x;
+}
+
+/*
+ * Appends values from @vals to the probing result
+ */
+void blkid_probe_append_vals(blkid_probe pr, struct blkid_prval *vals, int nvals)
+{
+	int i = 0;
+
+	while (i < nvals && pr->nvals < BLKID_NVALS) {
+		memcpy(&pr->vals[pr->nvals++], &vals[i++],
+				sizeof(struct blkid_prval));
+	}
+}
+
+static void blkid_probe_reset_vals(blkid_probe pr)
+{
+	memset(pr->vals, 0, sizeof(pr->vals));
+	pr->nvals = 0;
+}
+
+struct blkid_chain *blkid_probe_get_chain(blkid_probe pr)
+{
+	return pr->cur_chain;
+}
+
+static const char *blkid_probe_get_probername(blkid_probe pr)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+	if (chn && chn->idx >= 0 && chn->idx < chn->driver->nidinfos)
+		return chn->driver->idinfos[chn->idx]->name;
+
+	return NULL;
+}
+
+void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn)
+{
+	int rc, org_prob_flags;
+	struct blkid_chain *org_chn;
+
+	if (!pr || !chn)
+		return NULL;
+
+	/* save the current setting -- the binary API has to be completely
+	 * independent on the current probing status
+	 */
+	org_chn = pr->cur_chain;
+	org_prob_flags = pr->prob_flags;
+
+	pr->cur_chain = chn;
+	pr->prob_flags = 0;
+	chn->binary = TRUE;
+	blkid_probe_chain_reset_position(chn);
+
+	rc = chn->driver->probe(pr, chn);
+
+	chn->binary = FALSE;
+	blkid_probe_chain_reset_position(chn);
+
+	/* restore the original setting
+	 */
+	pr->cur_chain = org_chn;
+	pr->prob_flags = org_prob_flags;
+
+	if (rc != 0)
+		return NULL;
+
+	DBG(LOWPROBE, ul_debug("returning %s binary data", chn->driver->name));
+	return chn->data;
+}
+
+
+/**
+ * blkid_reset_probe:
+ * @pr: probe
+ *
+ * Zeroize probing results and resets the current probing (this has impact to
+ * blkid_do_probe() only). This function does not touch probing filters and
+ * keeps assigned device.
+ */
+void blkid_reset_probe(blkid_probe pr)
+{
+	int i;
+
+	if (!pr)
+		return;
+
+	blkid_probe_reset_vals(pr);
+	blkid_probe_set_wiper(pr, 0, 0);
+
+	pr->cur_chain = NULL;
+
+	for (i = 0; i < BLKID_NCHAINS; i++)
+		blkid_probe_chain_reset_position(&pr->chains[i]);
+}
+
+/***
+static int blkid_probe_dump_filter(blkid_probe pr, int chain)
+{
+	struct blkid_chain *chn;
+	int i;
+
+	if (!pr || chain < 0 || chain >= BLKID_NCHAINS)
+		return -1;
+
+	chn = &pr->chains[chain];
+
+	if (!chn->fltr)
+		return -1;
+
+	for (i = 0; i < chn->driver->nidinfos; i++) {
+		const struct blkid_idinfo *id = chn->driver->idinfos[i];
+
+		DBG(LOWPROBE, ul_debug("%d: %s: %s",
+			i,
+			id->name,
+			blkid_bmp_get_item(chn->fltr, i)
+				? "disabled" : "enabled <--"));
+	}
+	return 0;
+}
+***/
+
+/*
+ * Returns properly initialized chain filter
+ */
+unsigned long *blkid_probe_get_filter(blkid_probe pr, int chain, int create)
+{
+	struct blkid_chain *chn;
+
+	if (!pr || chain < 0 || chain >= BLKID_NCHAINS)
+		return NULL;
+
+	chn = &pr->chains[chain];
+
+	/* always when you touch the chain filter all indexes are reset and
+	 * probing starts from scratch
+	 */
+	blkid_probe_chain_reset_position(chn);
+	pr->cur_chain = NULL;
+
+	if (!chn->driver->has_fltr || (!chn->fltr && !create))
+		return NULL;
+
+	if (!chn->fltr)
+		chn->fltr = calloc(1, blkid_bmp_nbytes(chn->driver->nidinfos));
+	else
+		memset(chn->fltr, 0, blkid_bmp_nbytes(chn->driver->nidinfos));
+
+	/* blkid_probe_dump_filter(pr, chain); */
+	return chn->fltr;
+}
+
+/*
+ * Generic private functions for filter setting
+ */
+int __blkid_probe_invert_filter(blkid_probe pr, int chain)
+{
+	size_t i;
+	struct blkid_chain *chn;
+
+	if (!pr)
+		return -1;
+
+	chn = &pr->chains[chain];
+
+	if (!chn->driver->has_fltr || !chn->fltr)
+		return -1;
+
+	for (i = 0; i < blkid_bmp_nwords(chn->driver->nidinfos); i++)
+		chn->fltr[i] = ~chn->fltr[i];
+
+	DBG(LOWPROBE, ul_debug("probing filter inverted"));
+	/* blkid_probe_dump_filter(pr, chain); */
+	return 0;
+}
+
+int __blkid_probe_reset_filter(blkid_probe pr, int chain)
+{
+	return blkid_probe_get_filter(pr, chain, FALSE) ? 0 : -1;
+}
+
+int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[])
+{
+	unsigned long *fltr;
+	struct blkid_chain *chn;
+	size_t i;
+
+	fltr = blkid_probe_get_filter(pr, chain, TRUE);
+	if (!fltr)
+		return -1;
+
+	chn = &pr->chains[chain];
+
+	for (i = 0; i < chn->driver->nidinfos; i++) {
+		int has = 0;
+		const struct blkid_idinfo *id = chn->driver->idinfos[i];
+		char **n;
+
+		for (n = names; *n; n++) {
+			if (!strcmp(id->name, *n)) {
+				has = 1;
+				break;
+			}
+		}
+		if (flag & BLKID_FLTR_ONLYIN) {
+		       if (!has)
+				blkid_bmp_set_item(fltr, i);
+		} else if (flag & BLKID_FLTR_NOTIN) {
+			if (has)
+				blkid_bmp_set_item(fltr, i);
+		}
+	}
+
+	DBG(LOWPROBE, ul_debug("%s: a new probing type-filter initialized",
+		chn->driver->name));
+	/* blkid_probe_dump_filter(pr, chain); */
+	return 0;
+}
+
+unsigned char *blkid_probe_get_buffer(blkid_probe pr,
+				blkid_loff_t off, blkid_loff_t len)
+{
+	struct list_head *p;
+	struct blkid_bufinfo *bf = NULL;
+
+	if (pr->size <= 0) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (pr->parent &&
+	    pr->parent->devno == pr->devno &&
+	    pr->parent->off <= pr->off &&
+	    pr->parent->off + pr->parent->size >= pr->off + pr->size) {
+		/*
+		 * This is a cloned prober and points to the same area as
+		 * parent. Let's use parent's buffers.
+		 *
+		 * Note that pr->off (and pr->parent->off) is always from the
+		 * beginig of the device.
+		 */
+		return blkid_probe_get_buffer(pr->parent,
+				pr->off + off - pr->parent->off, len);
+	}
+
+	list_for_each(p, &pr->buffers) {
+		struct blkid_bufinfo *x =
+				list_entry(p, struct blkid_bufinfo, bufs);
+
+		if (x->off <= off && off + len <= x->off + x->len) {
+			DBG(LOWPROBE, ul_debug("\treuse buffer: off=%jd len=%jd pr=%p",
+							x->off, x->len, pr));
+			bf = x;
+			break;
+		}
+	}
+	if (!bf) {
+		ssize_t ret;
+
+		if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) {
+			errno = 0;
+			return NULL;
+		}
+
+		/* someone trying to overflow some buffers? */
+		if (len > ULONG_MAX - sizeof(struct blkid_bufinfo)) {
+			errno = ENOMEM;
+			return NULL;
+		}
+
+		/* allocate info and space for data by why call */
+		bf = calloc(1, sizeof(struct blkid_bufinfo) + len);
+		if (!bf) {
+			errno = ENOMEM;
+			return NULL;
+		}
+
+		bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo);
+		bf->len = len;
+		bf->off = off;
+		INIT_LIST_HEAD(&bf->bufs);
+
+		DBG(LOWPROBE, ul_debug("\tbuffer read: off=%jd len=%jd pr=%p",
+				off, len, pr));
+
+		ret = read(pr->fd, bf->data, len);
+		if (ret != (ssize_t) len) {
+			DBG(LOWPROBE, ul_debug("\tbuffer read: return %zd error %m", ret));
+			free(bf);
+			if (ret >= 0)
+				errno = 0;
+			return NULL;
+		}
+		list_add_tail(&bf->bufs, &pr->buffers);
+	}
+
+	errno = 0;
+	return off ? bf->data + (off - bf->off) : bf->data;
+}
+
+
+static void blkid_probe_reset_buffer(blkid_probe pr)
+{
+	uint64_t read_ct = 0, len_ct = 0;
+
+	if (!pr || list_empty(&pr->buffers))
+		return;
+
+	DBG(LOWPROBE, ul_debug("reseting probing buffers pr=%p", pr));
+
+	while (!list_empty(&pr->buffers)) {
+		struct blkid_bufinfo *bf = list_entry(pr->buffers.next,
+						struct blkid_bufinfo, bufs);
+		read_ct++;
+		len_ct += bf->len;
+		list_del(&bf->bufs);
+		free(bf);
+	}
+
+	DBG(LOWPROBE, ul_debug("buffers summary: %"PRIu64" bytes "
+			"by %"PRIu64" read() call(s)",
+			len_ct, read_ct));
+
+	INIT_LIST_HEAD(&pr->buffers);
+}
+
+/*
+ * Small devices need a special care.
+ */
+int blkid_probe_is_tiny(blkid_probe pr)
+{
+	return pr && (pr->flags & BLKID_FL_TINY_DEV);
+}
+
+/*
+ * CDROMs may fail when probed for RAID (last sector problem)
+ */
+int blkid_probe_is_cdrom(blkid_probe pr)
+{
+	return pr && (pr->flags & BLKID_FL_CDROM_DEV);
+}
+
+/**
+ * blkid_probe_set_device:
+ * @pr: probe
+ * @fd: device file descriptor
+ * @off: begin of probing area
+ * @size: size of probing area (zero means whole device/file)
+ *
+ * Assigns the device to probe control struct, resets internal buffers and
+ * resets the current probing.
+ *
+ * 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)
+{
+	struct stat sb;
+
+	if (!pr)
+		return -1;
+
+	blkid_reset_probe(pr);
+	blkid_probe_reset_buffer(pr);
+
+	if ((pr->flags & BLKID_FL_PRIVATE_FD) && pr->fd >= 0)
+		close(pr->fd);
+
+	pr->flags &= ~BLKID_FL_PRIVATE_FD;
+	pr->flags &= ~BLKID_FL_TINY_DEV;
+	pr->flags &= ~BLKID_FL_CDROM_DEV;
+	pr->prob_flags = 0;
+	pr->fd = fd;
+	pr->off = off;
+	pr->size = 0;
+	pr->devno = 0;
+	pr->disk_devno = 0;
+	pr->mode = 0;
+	pr->blkssz = 0;
+	pr->wipe_off = 0;
+	pr->wipe_size = 0;
+	pr->wipe_chain = NULL;
+
+#if defined(POSIX_FADV_RANDOM) && defined(HAVE_POSIX_FADVISE)
+	/* Disable read-ahead */
+	posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM);
+#endif
+	if (fstat(fd, &sb))
+		goto err;
+
+	if (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode) && !S_ISREG(sb.st_mode))
+		goto err;
+
+
+	pr->mode = sb.st_mode;
+	if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode))
+		pr->devno = sb.st_rdev;
+
+	if (size)
+		pr->size = size;
+	else {
+		if (S_ISBLK(sb.st_mode)) {
+			if (blkdev_get_size(fd, (unsigned long long *) &pr->size)) {
+				DBG(LOWPROBE, ul_debug("failed to get device size"));
+				goto err;
+			}
+		} else if (S_ISCHR(sb.st_mode))
+			pr->size = 1;		/* UBI devices are char... */
+		else if (S_ISREG(sb.st_mode))
+			pr->size = sb.st_size;	/* regular file */
+
+		if (pr->off > pr->size)
+			goto err;
+
+		/* The probing area cannot be larger than whole device, pr->off
+		 * is offset within the device */
+		pr->size -= pr->off;
+	}
+
+	if (pr->size <= 1440 * 1024 && !S_ISCHR(sb.st_mode))
+		pr->flags |= BLKID_FL_TINY_DEV;
+
+	if (S_ISBLK(sb.st_mode) && sysfs_devno_is_lvm_private(sb.st_rdev)) {
+		DBG(LOWPROBE, ul_debug("ignore private LVM device"));
+		pr->flags |= BLKID_FL_NOSCAN_DEV;
+	}
+
+#ifdef CDROM_GET_CAPABILITY
+	else if (S_ISBLK(sb.st_mode) &&
+	    !blkid_probe_is_tiny(pr) &&
+	    blkid_probe_is_wholedisk(pr) &&
+	    ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0)
+		pr->flags |= BLKID_FL_CDROM_DEV;
+#endif
+
+	DBG(LOWPROBE, ul_debug("ready for low-probing, offset=%jd, size=%jd",
+				pr->off, pr->size));
+	DBG(LOWPROBE, ul_debug("whole-disk: %s, regfile: %s",
+		blkid_probe_is_wholedisk(pr) ?"YES" : "NO",
+		S_ISREG(pr->mode) ? "YES" : "NO"));
+
+	return 0;
+err:
+	DBG(LOWPROBE, ul_debug("failed to prepare a device for low-probing"));
+	return -1;
+
+}
+
+int blkid_probe_get_dimension(blkid_probe pr,
+		blkid_loff_t *off, blkid_loff_t *size)
+{
+	if (!pr)
+		return -1;
+
+	*off = pr->off;
+	*size = pr->size;
+	return 0;
+}
+
+int blkid_probe_set_dimension(blkid_probe pr,
+		blkid_loff_t off, blkid_loff_t size)
+{
+	if (!pr)
+		return -1;
+
+	DBG(LOWPROBE, ul_debug(
+		"changing probing area pr=%p: size=%llu, off=%llu "
+		"-to-> size=%llu, off=%llu",
+		pr,
+		(unsigned long long) pr->size,
+		(unsigned long long) pr->off,
+		(unsigned long long) size,
+		(unsigned long long) off));
+
+	pr->off = off;
+	pr->size = size;
+	pr->flags &= ~BLKID_FL_TINY_DEV;
+
+	if (pr->size <= 1440 * 1024 && !S_ISCHR(pr->mode))
+		pr->flags |= BLKID_FL_TINY_DEV;
+
+	blkid_probe_reset_buffer(pr);
+
+	return 0;
+}
+
+/*
+ * Check for matching magic value.
+ * Returns BLKID_PROBE_OK if found, BLKID_PROBE_NONE if not found
+ * or no magic present, or negative value on error.
+ */
+int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id,
+			blkid_loff_t *offset, const struct blkid_idmag **res)
+{
+	const struct blkid_idmag *mag = NULL;
+	blkid_loff_t off = 0;
+
+	if (id)
+		mag = &id->magics[0];
+	if (res)
+		*res = NULL;
+
+	/* try to detect by magic string */
+	while(mag && mag->magic) {
+		unsigned char *buf;
+
+		off = (mag->kboff + (mag->sboff >> 10)) << 10;
+		buf = blkid_probe_get_buffer(pr, off, 1024);
+
+		if (!buf && errno)
+			return -errno;
+		if (buf && !memcmp(mag->magic,
+				buf + (mag->sboff & 0x3ff), mag->len)) {
+			DBG(LOWPROBE, ul_debug("\tmagic sboff=%u, kboff=%ld",
+				mag->sboff, mag->kboff));
+			if (offset)
+				*offset = off + (mag->sboff & 0x3ff);
+			if (res)
+				*res = mag;
+			return BLKID_PROBE_OK;
+		}
+		mag++;
+	}
+
+	if (id && id->magics[0].magic)
+		/* magic string(s) defined, but not found */
+		return BLKID_PROBE_NONE;
+
+	return BLKID_PROBE_OK;
+}
+
+static inline void blkid_probe_start(blkid_probe pr)
+{
+	if (pr) {
+		DBG(LOWPROBE, ul_debug("%p: start probe", pr));
+		pr->cur_chain = NULL;
+		pr->prob_flags = 0;
+		blkid_probe_set_wiper(pr, 0, 0);
+	}
+}
+
+static inline void blkid_probe_end(blkid_probe pr)
+{
+	if (pr) {
+		DBG(LOWPROBE, ul_debug("%p: end probe", pr));
+		pr->cur_chain = NULL;
+		pr->prob_flags = 0;
+		blkid_probe_set_wiper(pr, 0, 0);
+	}
+}
+
+/**
+ * blkid_do_probe:
+ * @pr: prober
+ *
+ * Calls probing functions in all enabled chains. The superblocks chain is
+ * enabled by default. The blkid_do_probe() stores result from only one
+ * probing function. It's necessary to call this routine in a loop to get
+ * results from all probing functions in all chains. The probing is reset
+ * by blkid_reset_probe() or by filter functions.
+ *
+ * This is string-based NAME=value interface only.
+ *
+ * <example>
+ *   <title>basic case - use the first result only</title>
+ *   <programlisting>
+ *
+ *	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);
+ *		}
+ *	}
+ *  </programlisting>
+ * </example>
+ *
+ * <example>
+ *   <title>advanced case - probe for all signatures</title>
+ *   <programlisting>
+ *
+ *	while (blkid_do_probe(pr) == 0) {
+ *		int nvals = blkid_probe_numof_values(pr);
+ *		...
+ *	}
+ *  </programlisting>
+ * </example>
+ *
+ * See also blkid_reset_probe().
+ *
+ * Returns: 0 on success, 1 when probing is done and -1 in case of error.
+ */
+int blkid_do_probe(blkid_probe pr)
+{
+	int rc = 1;
+
+	if (!pr)
+		return -1;
+
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return 1;
+
+	do {
+		struct blkid_chain *chn = pr->cur_chain;
+
+		if (!chn) {
+			blkid_probe_start(pr);
+			chn = pr->cur_chain = &pr->chains[0];
+		}
+		/* we go to the next chain only when the previous probing
+		 * result was nothing (rc == 1) and when the current chain is
+		 * disabled or we are at end of the current chain (chain->idx +
+		 * 1 == sizeof chain) or the current chain bailed out right at
+		 * the start (chain->idx == -1)
+		 */
+		else if (rc == 1 && (chn->enabled == FALSE ||
+				     chn->idx + 1 == (int) chn->driver->nidinfos ||
+				     chn->idx == -1)) {
+
+			size_t idx = chn->driver->id + 1;
+
+			if (idx < BLKID_NCHAINS)
+				chn = pr->cur_chain = &pr->chains[idx];
+			else {
+				blkid_probe_end(pr);
+				return 1;	/* all chains already probed */
+			}
+		}
+
+		chn->binary = FALSE;		/* for sure... */
+
+		DBG(LOWPROBE, ul_debug("chain probe %s %s (idx=%d)",
+				chn->driver->name,
+				chn->enabled? "ENABLED" : "DISABLED",
+				chn->idx));
+
+		if (!chn->enabled)
+			continue;
+
+		/* rc: -1 = error, 0 = success, 1 = no result */
+		rc = chn->driver->probe(pr, chn);
+
+	} while (rc == 1);
+
+	return rc;
+}
+
+/**
+ * blkid_do_wipe:
+ * @pr: prober
+ * @dryrun: if TRUE then don't touch the device.
+ *
+ * This function erases the current signature detected by @pr. The @pr has to
+ * be open in O_RDWR mode, BLKID_SUBLKS_MAGIC or/and BLKID_PARTS_MAGIC flags
+ * has to be enabled (if you want to errase also superblock with broken check
+ * sums then use BLKID_SUBLKS_BADCSUM too).
+ *
+ * After successful signature removing the @pr prober will be moved one step
+ * back and the next blkid_do_probe() call will again call previously called
+ * probing function.
+ *
+ *  <example>
+ *  <title>wipe all filesystems or raids from the device</title>
+ *   <programlisting>
+ *      fd = open(devname, O_RDWR|O_CLOEXEC);
+ *      blkid_probe_set_device(pr, fd, 0, 0);
+ *
+ *      blkid_probe_enable_superblocks(pr, 1);
+ *      blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC);
+ *
+ *	while (blkid_do_probe(pr) == 0)
+ *		blkid_do_wipe(pr, FALSE);
+ *  </programlisting>
+ * </example>
+ *
+ * See also blkid_probe_step_back() if you cannot use this build-in wipe
+ * function, but you want to use libblkid probing as a source for wiping.
+ *
+ * Returns: 0 on success, and -1 in case of error.
+ */
+int blkid_do_wipe(blkid_probe pr, int dryrun)
+{
+	const char *off = NULL;
+	size_t len = 0;
+	loff_t offset, l;
+	char buf[BUFSIZ];
+	int fd, rc = 0;
+	struct blkid_chain *chn;
+
+	if (!pr)
+		return -1;
+
+	chn = pr->cur_chain;
+	if (!chn)
+		return -1;
+
+	switch (chn->driver->id) {
+	case BLKID_CHAIN_SUBLKS:
+		rc = blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL);
+		if (!rc)
+			rc = blkid_probe_lookup_value(pr, "SBMAGIC", NULL, &len);
+		break;
+	case BLKID_CHAIN_PARTS:
+		rc = blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &off, NULL);
+		if (!rc)
+			rc = blkid_probe_lookup_value(pr, "PTMAGIC", NULL, &len);
+		break;
+	default:
+		return 0;
+	}
+
+	if (rc || len == 0 || off == NULL)
+		return 0;
+
+	offset = strtoll(off, NULL, 10);
+	fd = blkid_probe_get_fd(pr);
+	if (fd < 0)
+		return -1;
+
+	if (len > sizeof(buf))
+		len = sizeof(buf);
+
+	DBG(LOWPROBE, ul_debug(
+	    "do_wipe [offset=0x%jx, len=%zd, chain=%s, idx=%d, dryrun=%s]\n",
+	    offset, len, chn->driver->name, chn->idx, dryrun ? "yes" : "not"));
+
+	l = lseek(fd, offset, SEEK_SET);
+	if (l == (off_t) -1)
+		return -1;
+
+	memset(buf, 0, len);
+
+	if (!dryrun && len) {
+		if (write_all(fd, buf, len))
+			return -1;
+		fsync(fd);
+		return blkid_probe_step_back(pr);
+	}
+
+	return 0;
+}
+
+/**
+ * blkid_probe_step_back:
+ * @pr: prober
+ *
+ * This function move pointer to the probing chain one step back -- it means
+ * that the previously used probing function will be called again in the next
+ * blkid_do_probe() call.
+ *
+ * This is necessary for example if you erase or modify on-disk superblock
+ * according to the current libblkid probing result.
+ *
+ * <example>
+ *  <title>wipe all superblock, but use libblkid only for probing</title>
+ *  <programlisting>
+ *      pr = blkid_new_probe_from_filename(devname);
+ *
+ *      blkid_probe_enable_superblocks(pr, 1);
+ *      blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC);
+ *
+ *      blkid_probe_enable_partitions(pr, 1);
+ *      blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC);
+ *
+ *	while (blkid_do_probe(pr) == 0) {
+ *		const char *ostr = NULL;
+ *		size_t len = 0;
+ *
+ *		// superblocks
+ *		if (blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &ostr, NULL) == 0)
+ *			blkid_probe_lookup_value(pr, "SBMAGIC", NULL, &len);
+ *
+ *		// partition tables
+ *		if (len == 0 && blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &ostr, NULL) == 0)
+ *			blkid_probe_lookup_value(pr, "PTMAGIC", NULL, &len);
+ *
+ *		if (!len || !str)
+ *			continue;
+ *
+ *		// convert ostr to the real offset by off = strtoll(ostr, NULL, 10);
+ *              // use your stuff to errase @len bytes at the @off
+ *              ....
+ *
+ *		// retry the last probing to check for backup superblocks ..etc.
+ *              blkid_probe_step_back(pr);
+ *	}
+ *  </programlisting>
+ * </example>
+ *
+ * Returns: 0 on success, and -1 in case of error.
+ */
+int blkid_probe_step_back(blkid_probe pr)
+{
+	struct blkid_chain *chn;
+
+	if (!pr)
+		return -1;
+
+	chn = pr->cur_chain;
+	if (!chn)
+		return -1;
+
+	blkid_probe_reset_buffer(pr);
+
+	if (chn->idx >= 0) {
+		chn->idx--;
+		DBG(LOWPROBE, ul_debug("step back: moving %s chain index to %d",
+			chn->driver->name,
+			chn->idx));
+	}
+
+	if (chn->idx == -1) {
+		/* blkid_do_probe() goes to the next chain if the index
+		 * of the current chain is -1, so we have to set the
+		 * chain pointer to the previous chain.
+		 */
+		size_t idx = chn->driver->id > 0 ? chn->driver->id - 1 : 0;
+
+		DBG(LOWPROBE, ul_debug("step back: moving to previous chain"));
+
+		if (idx > 0)
+			pr->cur_chain = &pr->chains[idx];
+		else if (idx == 0)
+			pr->cur_chain = NULL;
+	}
+
+	return 0;
+}
+
+/**
+ * blkid_do_safeprobe:
+ * @pr: prober
+ *
+ * This function gathers probing results from all enabled chains and checks
+ * for ambivalent results (e.g. more filesystems on the device).
+ *
+ * This is string-based NAME=value interface only.
+ *
+ * Note about suberblocks chain -- the function does not check for filesystems
+ * when a RAID signature is detected.  The function also does not check for
+ * collision between RAIDs. The first detected RAID is returned. The function
+ * checks for collision between partition table and RAID signature -- it's
+ * recommended to enable partitions chain together with superblocks chain.
+ *
+ * Returns: 0 on success, 1 if nothing is detected, -2 if ambivalen result is
+ * detected and -1 on case of error.
+ */
+int blkid_do_safeprobe(blkid_probe pr)
+{
+	int i, count = 0, rc = 0;
+
+	if (!pr)
+		return -1;
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return 1;
+
+	blkid_probe_start(pr);
+
+	for (i = 0; i < BLKID_NCHAINS; i++) {
+		struct blkid_chain *chn;
+
+		chn = pr->cur_chain = &pr->chains[i];
+		chn->binary = FALSE;		/* for sure... */
+
+		DBG(LOWPROBE, ul_debug("chain safeprobe %s %s",
+				chn->driver->name,
+				chn->enabled? "ENABLED" : "DISABLED"));
+
+		if (!chn->enabled)
+			continue;
+
+		blkid_probe_chain_reset_position(chn);
+
+		rc = chn->driver->safeprobe(pr, chn);
+
+		blkid_probe_chain_reset_position(chn);
+
+		/* rc: -2 ambivalent, -1 = error, 0 = success, 1 = no result */
+		if (rc < 0)
+			goto done;	/* error */
+		if (rc == 0)
+			count++;	/* success */
+	}
+
+done:
+	blkid_probe_end(pr);
+	if (rc < 0)
+		return rc;
+	return count ? 0 : 1;
+}
+
+/**
+ * blkid_do_fullprobe:
+ * @pr: prober
+ *
+ * This function gathers probing results from all enabled chains. Same as
+ * blkid_do_safeprobe() but does not check for collision between probing
+ * result.
+ *
+ * This is string-based NAME=value interface only.
+ *
+ * Returns: 0 on success, 1 if nothing is detected or -1 on case of error.
+ */
+int blkid_do_fullprobe(blkid_probe pr)
+{
+	int i, count = 0, rc = 0;
+
+	if (!pr)
+		return -1;
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return 1;
+
+	blkid_probe_start(pr);
+
+	for (i = 0; i < BLKID_NCHAINS; i++) {
+		struct blkid_chain *chn;
+
+		chn = pr->cur_chain = &pr->chains[i];
+		chn->binary = FALSE;		/* for sure... */
+
+		DBG(LOWPROBE, ul_debug("chain fullprobe %s: %s",
+				chn->driver->name,
+				chn->enabled? "ENABLED" : "DISABLED"));
+
+		if (!chn->enabled)
+			continue;
+
+		blkid_probe_chain_reset_position(chn);
+
+		rc = chn->driver->probe(pr, chn);
+
+		blkid_probe_chain_reset_position(chn);
+
+		/* rc: -1 = error, 0 = success, 1 = no result */
+		if (rc < 0)
+			goto done;	/* error */
+		if (rc == 0)
+			count++;	/* success */
+	}
+
+done:
+	blkid_probe_end(pr);
+	if (rc < 0)
+		return rc;
+	return count ? 0 : 1;
+}
+
+/* same sa blkid_probe_get_buffer() but works with 512-sectors */
+unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector)
+{
+	return pr ? blkid_probe_get_buffer(pr,
+			((blkid_loff_t) sector) << 9, 0x200) : NULL;
+}
+
+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_NVALS)
+		return NULL;
+
+	v = &pr->vals[pr->nvals];
+	v->name = name;
+	v->chain = pr->cur_chain;
+	pr->nvals++;
+
+	DBG(LOWPROBE, ul_debug("assigning %s [%s]", name, v->chain->driver->name));
+	return v;
+}
+
+int blkid_probe_reset_last_value(blkid_probe pr)
+{
+	struct blkid_prval *v;
+
+	if (pr == NULL || pr->nvals == 0)
+		return -1;
+
+	v = &pr->vals[pr->nvals - 1];
+
+	DBG(LOWPROBE, ul_debug("un-assigning %s [%s]", v->name, v->chain->driver->name));
+
+	memset(v, 0, sizeof(struct blkid_prval));
+	pr->nvals--;
+
+	return 0;
+
+}
+
+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;
+	ssize_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 || (size_t) len >= sizeof(v->data)) {
+		blkid_probe_reset_last_value(pr);
+		return -1;
+	}
+	v->len = len + 1;
+	return 0;
+}
+
+int blkid_probe_sprintf_value(blkid_probe pr, const char *name,
+		const char *fmt, ...)
+{
+	int rc;
+	va_list ap;
+
+	va_start(ap, fmt);
+	rc = blkid_probe_vsprintf_value(pr, name, fmt, ap);
+	va_end(ap);
+
+	return rc;
+}
+
+int blkid_probe_set_magic(blkid_probe pr, blkid_loff_t offset,
+			size_t len, unsigned char *magic)
+{
+	int rc = 0;
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+	if (!chn || !magic || !len || chn->binary)
+		return 0;
+
+	switch (chn->driver->id) {
+	case BLKID_CHAIN_SUBLKS:
+		if (!(chn->flags & BLKID_SUBLKS_MAGIC))
+			return 0;
+		rc = blkid_probe_set_value(pr, "SBMAGIC", magic, len);
+		if (!rc)
+			rc = blkid_probe_sprintf_value(pr,
+					"SBMAGIC_OFFSET", "%llu", (unsigned long long)offset);
+		break;
+	case BLKID_CHAIN_PARTS:
+		if (!(chn->flags & BLKID_PARTS_MAGIC))
+			return 0;
+		rc = blkid_probe_set_value(pr, "PTMAGIC", magic, len);
+		if (!rc)
+			rc = blkid_probe_sprintf_value(pr,
+					"PTMAGIC_OFFSET", "%llu", (unsigned long long)offset);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+int blkid_probe_verify_csum(blkid_probe pr, uint64_t csum, uint64_t expected)
+{
+	if (csum != expected) {
+		struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+		DBG(LOWPROBE, ul_debug(
+				"incorrect checksum for type %s,"
+				" got %jX, expected %jX",
+				blkid_probe_get_probername(pr),
+				csum, expected));
+		/*
+		 * Accept bad checksum if BLKID_SUBLKS_BADCSUM flags is set
+		 */
+		if (chn->driver->id == BLKID_CHAIN_SUBLKS
+		    && (chn->flags & BLKID_SUBLKS_BADCSUM)) {
+			blkid_probe_set_value(pr, "SBBADCSUM", (unsigned char *) "1", 2);
+			goto accept;
+		}
+		return 0;	/* bad checksum */
+	}
+
+accept:
+	return 1;
+}
+
+/**
+ * blkid_probe_get_devno:
+ * @pr: probe
+ *
+ * Returns: block device number, or 0 for regular files.
+ */
+dev_t blkid_probe_get_devno(blkid_probe pr)
+{
+	return pr->devno;
+}
+
+/**
+ * blkid_probe_get_wholedisk_devno:
+ * @pr: probe
+ *
+ * Returns: device number of the wholedisk, or 0 for regular files.
+ */
+dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr)
+{
+	if (!pr->disk_devno) {
+		dev_t devno, disk_devno = 0;
+
+		devno = blkid_probe_get_devno(pr);
+		if (!devno)
+			return 0;
+
+		 if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk_devno) == 0)
+			pr->disk_devno = disk_devno;
+	}
+	return pr->disk_devno;
+}
+
+/**
+ * blkid_probe_is_wholedisk:
+ * @pr: probe
+ *
+ * Returns: 1 if the device is whole-disk or 0.
+ */
+int blkid_probe_is_wholedisk(blkid_probe pr)
+{
+	dev_t devno, disk_devno;
+
+	devno = blkid_probe_get_devno(pr);
+	if (!devno)
+		return 0;
+
+	disk_devno = blkid_probe_get_wholedisk_devno(pr);
+	if (!disk_devno)
+		return 0;
+
+	return devno == disk_devno;
+}
+
+blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr)
+{
+	dev_t disk;
+
+	if (blkid_probe_is_wholedisk(pr))
+		return NULL;			/* this is not partition */
+
+	if (pr->parent)
+		/* this is cloned blkid_probe, use parent's stuff */
+		return blkid_probe_get_wholedisk_probe(pr->parent);
+
+	disk = blkid_probe_get_wholedisk_devno(pr);
+
+	if (pr->disk_probe && pr->disk_probe->devno != disk) {
+		/* we have disk prober, but for another disk... close it */
+		blkid_free_probe(pr->disk_probe);
+		pr->disk_probe = NULL;
+	}
+
+	if (!pr->disk_probe) {
+		/* Open a new disk prober */
+		char *disk_path = blkid_devno_to_devname(disk);
+
+		if (!disk_path)
+			return NULL;
+
+		DBG(LOWPROBE, ul_debug("allocate a wholedisk probe"));
+
+		pr->disk_probe = blkid_new_probe_from_filename(disk_path);
+
+		free(disk_path);
+
+		if (!pr->disk_probe)
+			return NULL;	/* ENOMEM? */
+	}
+
+	return pr->disk_probe;
+}
+
+/**
+ * blkid_probe_get_size:
+ * @pr: probe
+ *
+ * This function returns size of probing area as defined by blkid_probe_set_device().
+ * If the size of the probing area is unrestricted then this function returns
+ * the real size of device. See also blkid_get_dev_size().
+ *
+ * Returns: size in bytes or -1 in case of error.
+ */
+blkid_loff_t blkid_probe_get_size(blkid_probe pr)
+{
+	return pr ? pr->size : -1;
+}
+
+/**
+ * blkid_probe_get_offset:
+ * @pr: probe
+ *
+ * This function returns offset of probing area as defined by blkid_probe_set_device().
+ *
+ * Returns: offset in bytes or -1 in case of error.
+ */
+blkid_loff_t blkid_probe_get_offset(blkid_probe pr)
+{
+	return pr ? pr->off : -1;
+}
+
+/**
+ * blkid_probe_get_fd:
+ * @pr: probe
+ *
+ * Returns: file descriptor for assigned device/file or -1 in case of error.
+ */
+int blkid_probe_get_fd(blkid_probe pr)
+{
+	return pr ? pr->fd : -1;
+}
+
+/**
+ * blkid_probe_get_sectorsize:
+ * @pr: probe or NULL (for NULL returns 512)
+ *
+ * Returns: block device logical sector size (BLKSSZGET ioctl, default 512).
+ */
+unsigned int blkid_probe_get_sectorsize(blkid_probe pr)
+{
+	if (!pr)
+		return DEFAULT_SECTOR_SIZE;  /*... and good luck! */
+
+	if (pr->blkssz)
+		return pr->blkssz;
+
+	if (S_ISBLK(pr->mode) &&
+	    blkdev_get_sector_size(pr->fd, (int *) &pr->blkssz) == 0)
+		return pr->blkssz;
+
+	pr->blkssz = DEFAULT_SECTOR_SIZE;
+	return pr->blkssz;
+}
+
+/**
+ * blkid_probe_get_sectors:
+ * @pr: probe
+ *
+ * Returns: 512-byte sector count or -1 in case of error.
+ */
+blkid_loff_t blkid_probe_get_sectors(blkid_probe pr)
+{
+	return pr ? pr->size >> 9 : -1;
+}
+
+/**
+ * blkid_probe_numof_values:
+ * @pr: probe
+ *
+ * Returns: number of values in probing result or -1 in case of error.
+ */
+int blkid_probe_numof_values(blkid_probe pr)
+{
+	if (!pr)
+		return -1;
+	return pr->nvals;
+}
+
+/**
+ * blkid_probe_get_value:
+ * @pr: probe
+ * @num: wanted value in range 0..N, where N is blkid_probe_numof_values() - 1
+ * @name: pointer to return value name or NULL
+ * @data: pointer to return value data or NULL
+ * @len: pointer to return value length or NULL
+ *
+ * Note, the @len returns length of the @data, including the terminating
+ * '\0' character.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_get_value(blkid_probe pr, int num, const char **name,
+			const char **data, size_t *len)
+{
+	struct blkid_prval *v = __blkid_probe_get_value(pr, num);
+
+	if (!v)
+		return -1;
+	if (name)
+		*name = v->name;
+	if (data)
+		*data = (char *) v->data;
+	if (len)
+		*len = v->len;
+
+	DBG(LOWPROBE, ul_debug("returning %s value", v->name));
+	return 0;
+}
+
+/**
+ * blkid_probe_lookup_value:
+ * @pr: probe
+ * @name: name of value
+ * @data: pointer to return value data or NULL
+ * @len: pointer to return value length or NULL
+ *
+ * Note, the @len returns length of the @data, including the terminating
+ * '\0' character.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_lookup_value(blkid_probe pr, const char *name,
+			const char **data, size_t *len)
+{
+	struct blkid_prval *v = __blkid_probe_lookup_value(pr, name);
+
+	if (!v)
+		return -1;
+	if (data)
+		*data = (char *) v->data;
+	if (len)
+		*len = v->len;
+	return 0;
+}
+
+/**
+ * blkid_probe_has_value:
+ * @pr: probe
+ * @name: name of value
+ *
+ * Returns: 1 if value exist in probing result, otherwise 0.
+ */
+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;
+}
+
+struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num)
+{
+	if (!pr || num < 0 || num >= pr->nvals)
+		return NULL;
+
+	return &pr->vals[num];
+}
+
+struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name)
+{
+	int i;
+
+	if (!pr || !pr->nvals || !name)
+		return NULL;
+
+	for (i = 0; i < pr->nvals; i++) {
+		struct blkid_prval *v = &pr->vals[i];
+
+		if (v->name && strcmp(name, v->name) == 0) {
+			DBG(LOWPROBE, ul_debug("returning %s value", v->name));
+			return v;
+		}
+	}
+	return NULL;
+}
+
+
+/* converts DCE UUID (uuid[16]) to human readable string
+ * - the @len should be always 37 */
+#ifdef HAVE_LIBUUID
+void blkid_unparse_uuid(const unsigned char *uuid, char *str,
+			size_t len __attribute__((__unused__)))
+{
+	uuid_unparse(uuid, str);
+}
+#else
+void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len)
+{
+	snprintf(str, len,
+		"%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]);
+}
+#endif
+
+/* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */
+int blkid_uuid_is_empty(const unsigned char *buf, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++)
+		if (buf[i])
+			return 0;
+	return 1;
+}
+
+/* Removes whitespace from the right-hand side of a string (trailing
+ * whitespace).
+ *
+ * Returns size of the new string (without \0).
+ */
+size_t blkid_rtrim_whitespace(unsigned char *str)
+{
+	return rtrim_whitespace(str);
+}
+
+/* Removes whitespace from the left-hand side of a string.
+ *
+ * Returns size of the new string (without \0).
+ */
+size_t blkid_ltrim_whitespace(unsigned char *str)
+{
+	return ltrim_whitespace(str);
+}
+
+/*
+ * Some mkfs-like utils wipe some parts (usually begin) of the device.
+ * For example LVM (pvcreate) or mkswap(8). This information could be used
+ * for later resolution to conflicts between superblocks.
+ *
+ * For example we found valid LVM superblock, LVM wipes 8KiB at the begin of
+ * the device. If we found another signature (for example MBR) within the
+ * wiped area then the signature has been added later and LVM superblock
+ * should be ignore.
+ *
+ * Note that this heuristic is not 100% reliable, for example "pvcreate --zero
+ * n" allows to keep the begin of the device unmodified. It's probably better
+ * to use this heuristic for conflicts between superblocks and partition tables
+ * than for conflicts between filesystem superblocks -- existence of unwanted
+ * partition table is very unusual, because PT is pretty visible (parsed and
+ * interpreted by kernel).
+ *
+ * Note that we usually expect only one signature on the device, it means that
+ * we have to remember only one wiped area from previously successfully
+ * detected signature.
+ *
+ * blkid_probe_set_wiper() -- defines wiped area (e.g. LVM)
+ * blkid_probe_use_wiper() -- try to use area (e.g. MBR)
+ *
+ * Note that there is not relation between _wiper and blkid_to_wipe().
+ *
+ */
+void blkid_probe_set_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size)
+{
+	struct blkid_chain *chn;
+
+	if (!pr)
+		return;
+
+	if (!size) {
+		DBG(LOWPROBE, ul_debug("zeroize wiper"));
+		pr->wipe_size = pr->wipe_off = 0;
+		pr->wipe_chain = NULL;
+		return;
+	}
+
+	chn = pr->cur_chain;
+
+	if (!chn || !chn->driver ||
+	    chn->idx < 0 || (size_t) chn->idx >= chn->driver->nidinfos)
+		return;
+
+	pr->wipe_size = size;
+	pr->wipe_off = off;
+	pr->wipe_chain = chn;
+
+	DBG(LOWPROBE,
+		ul_debug("wiper set to %s::%s off=%jd size=%jd",
+			chn->driver->name,
+			chn->driver->idinfos[chn->idx]->name,
+			pr->wipe_off, pr->wipe_size));
+	return;
+}
+
+/*
+ * Returns 1 if the <@off,@size> area was wiped
+ */
+int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn,
+		     blkid_loff_t off, blkid_loff_t size)
+{
+	if (!pr || !size)
+		return 0;
+
+	if (pr->wipe_off <= off && off + size <= pr->wipe_off + pr->wipe_size) {
+		if (chn)
+			*chn = pr->wipe_chain;
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ *  Try to use any area -- if the area has been previously wiped then the
+ *  previous probing result should be ignored (reseted).
+ */
+void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size)
+{
+	struct blkid_chain *chn = NULL;
+
+	if (blkid_probe_is_wiped(pr, &chn, off, size) && chn) {
+		DBG(LOWPROBE, ul_debug("previously wiped area modified "
+				       " -- ignore previous results"));
+		blkid_probe_set_wiper(pr, 0, 0);
+		blkid_probe_chain_reset_vals(pr, chn);
+	}
+}
diff --git a/libblkid/src/pt-bsd.h b/libblkid/src/pt-bsd.h
new file mode 100644
index 0000000..9bf47a5
--- /dev/null
+++ b/libblkid/src/pt-bsd.h
@@ -0,0 +1,156 @@
+#ifndef UTIL_LINUX_PT_BSD_H
+#define UTIL_LINUX_PT_BSD_H
+
+#define BSD_MAXPARTITIONS	16
+#define BSD_FS_UNUSED		0
+
+#ifndef BSD_DISKMAGIC
+# define BSD_DISKMAGIC     ((uint32_t) 0x82564557)
+#endif
+
+#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
+
+#if defined (__alpha__) || defined (__powerpc__) || \
+    defined (__ia64__) || defined (__hppa__)
+# define BSD_LABELSECTOR   0
+# define BSD_LABELOFFSET   64
+#else
+# define BSD_LABELSECTOR   1
+# define BSD_LABELOFFSET   0
+#endif
+
+#define	BSD_BBSIZE        8192		/* size of boot area, with label */
+#define	BSD_SBSIZE        8192		/* max size of fs superblock */
+
+struct bsd_disklabel {
+	uint32_t	d_magic;		/* the magic number */
+	int16_t		d_type;			/* drive type */
+	int16_t		d_subtype;		/* controller/d_type specific */
+	char		d_typename[16];		/* type name, e.g. "eagle" */
+	char		d_packname[16];		/* pack identifier */
+
+			/* disk geometry: */
+	uint32_t	d_secsize;		/* # of bytes per sector */
+	uint32_t	d_nsectors;		/* # of data sectors per track */
+	uint32_t	d_ntracks;		/* # of tracks per cylinder */
+	uint32_t	d_ncylinders;		/* # of data cylinders per unit */
+	uint32_t	d_secpercyl;		/* # of data sectors per cylinder */
+	uint32_t	d_secperunit;		/* # of data sectors per unit */
+
+	/*
+	 * Spares (bad sector replacements) below
+	 * are not counted in d_nsectors or d_secpercyl.
+	 * Spare sectors are assumed to be physical sectors
+	 * which occupy space at the end of each track and/or cylinder.
+	 */
+	uint16_t	d_sparespertrack;	/* # of spare sectors per track */
+	uint16_t	d_sparespercyl;		/* # of spare sectors per cylinder */
+
+	/*
+	 * Alternate cylinders include maintenance, replacement,
+	 * configuration description areas, etc.
+	 */
+	uint32_t	d_acylinders;		/* # of alt. cylinders per unit */
+
+			/* hardware characteristics: */
+	/*
+	 * d_interleave, d_trackskew and d_cylskew describe perturbations
+	 * in the media format used to compensate for a slow controller.
+	 * Interleave is physical sector interleave, set up by the formatter
+	 * or controller when formatting.  When interleaving is in use,
+	 * logically adjacent sectors are not physically contiguous,
+	 * but instead are separated by some number of sectors.
+	 * It is specified as the ratio of physical sectors traversed
+	 * per logical sector.  Thus an interleave of 1:1 implies contiguous
+	 * layout, while 2:1 implies that logical sector 0 is separated
+	 * by one sector from logical sector 1.
+	 * d_trackskew is the offset of sector 0 on track N
+	 * relative to sector 0 on track N-1 on the same cylinder.
+	 * Finally, d_cylskew is the offset of sector 0 on cylinder N
+	 * relative to sector 0 on cylinder N-1.
+	 */
+	uint16_t	d_rpm;			/* rotational speed */
+	uint16_t	d_interleave;		/* hardware sector interleave */
+	uint16_t	d_trackskew;		/* sector 0 skew, per track */
+	uint16_t	d_cylskew;		/* sector 0 skew, per cylinder */
+	uint32_t	d_headswitch;		/* head switch time, usec */
+	uint32_t	d_trkseek;		/* track-to-track seek, usec */
+	uint32_t	d_flags;		/* generic flags */
+	uint32_t	d_drivedata[5];		/* drive-type specific information */
+	uint32_t	d_spare[5];		/* reserved for future use */
+	uint32_t	d_magic2;		/* the magic number (again) */
+	uint16_t	d_checksum;		/* xor of data incl. partitions */
+
+			/* filesystem and partition information: */
+	uint16_t	d_npartitions;	        /* number of partitions in following */
+	uint32_t	d_bbsize;	        /* size of boot area at sn0, bytes */
+	uint32_t	d_sbsize;	        /* max size of fs superblock, bytes */
+
+	struct bsd_partition	 {		/* the partition table */
+		uint32_t	p_size;	        /* number of sectors in partition */
+		uint32_t	p_offset;       /* starting sector */
+		uint32_t	p_fsize;        /* filesystem basic fragment size */
+		uint8_t		p_fstype;	/* filesystem type, see below */
+		uint8_t		p_frag;		/* filesystem fragments per block */
+		uint16_t	p_cpg;	        /* filesystem cylinders per group */
+	} __attribute__((packed)) d_partitions[BSD_MAXPARTITIONS];	/* actually may be more */
+} __attribute__((packed));
+
+
+/* d_type values: */
+#define	BSD_DTYPE_SMD		1		/* SMD, XSMD; VAX hp/up */
+#define	BSD_DTYPE_MSCP		2		/* MSCP */
+#define	BSD_DTYPE_DEC		3		/* other DEC (rk, rl) */
+#define	BSD_DTYPE_SCSI		4		/* SCSI */
+#define	BSD_DTYPE_ESDI		5		/* ESDI interface */
+#define	BSD_DTYPE_ST506		6		/* ST506 etc. */
+#define	BSD_DTYPE_HPIB		7		/* CS/80 on HP-IB */
+#define BSD_DTYPE_HPFL		8		/* HP Fiber-link */
+#define	BSD_DTYPE_FLOPPY	10		/* floppy */
+
+/* d_subtype values: */
+#define BSD_DSTYPE_INDOSPART	0x8		/* is inside dos partition */
+#define BSD_DSTYPE_DOSPART(s)	((s) & 3)	/* dos partition number */
+#define BSD_DSTYPE_GEOMETRY	0x10		/* drive params in label */
+
+/*
+ * Filesystem type and version.
+ * Used to interpret other filesystem-specific
+ * per-partition information.
+ */
+#define	BSD_FS_UNUSED	0		/* unused */
+#define	BSD_FS_SWAP    	1		/* swap */
+#define	BSD_FS_V6      	2		/* Sixth Edition */
+#define	BSD_FS_V7      	3		/* Seventh Edition */
+#define	BSD_FS_SYSV    	4		/* System V */
+#define	BSD_FS_V71K    	5		/* V7 with 1K blocks (4.1, 2.9) */
+#define	BSD_FS_V8      	6		/* Eighth Edition, 4K blocks */
+#define	BSD_FS_BSDFFS	7		/* 4.2BSD fast file system */
+#define	BSD_FS_BSDLFS	9		/* 4.4BSD log-structured file system */
+#define	BSD_FS_OTHER	10		/* in use, but unknown/unsupported */
+#define	BSD_FS_HPFS	11		/* OS/2 high-performance file system */
+#define	BSD_FS_ISO9660	12		/* ISO-9660 filesystem (cdrom) */
+#define BSD_FS_ISOFS	BSD_FS_ISO9660
+#define	BSD_FS_BOOT	13		/* partition contains bootstrap */
+#define BSD_FS_ADOS	14		/* AmigaDOS fast file system */
+#define BSD_FS_HFS	15		/* Macintosh HFS */
+#define BSD_FS_ADVFS	16		/* Digital Unix AdvFS */
+
+/* this is annoying, but it's also the way it is :-( */
+#ifdef __alpha__
+#define	BSD_FS_EXT2	8		/* ext2 file system */
+#else
+#define	BSD_FS_MSDOS	8		/* MS-DOS file system */
+#endif
+
+/*
+ * flags shared by various drives:
+ */
+#define	BSD_D_REMOVABLE	0x01		/* removable media */
+#define	BSD_D_ECC      	0x02		/* supports ECC */
+#define	BSD_D_BADSECT	0x04		/* supports bad sector forw. */
+#define	BSD_D_RAMDISK	0x08		/* disk emulator */
+#define	BSD_D_CHAIN    	0x10		/* can do back-back transfers */
+#define	BSD_D_DOSPART	0x20		/* within MSDOS partition */
+
+#endif /* UTIL_LINUX_PT_BSD_H */
diff --git a/libblkid/src/pt-mbr.h b/libblkid/src/pt-mbr.h
new file mode 100644
index 0000000..1279e3c
--- /dev/null
+++ b/libblkid/src/pt-mbr.h
@@ -0,0 +1,178 @@
+#ifndef UTIL_LINUX_PT_MBR_H
+#define UTIL_LINUX_PT_MBR_H
+
+struct dos_partition {
+	unsigned char boot_ind;		/* 0x80 - active */
+	unsigned char bh, bs, bc;	/* begin CHS */
+	unsigned char sys_ind;
+	unsigned char eh, es, ec;	/* end CHS */
+	unsigned char start_sect[4];
+	unsigned char nr_sects[4];
+} __attribute__((packed));
+
+#define MBR_PT_OFFSET		0x1be
+
+static inline struct dos_partition *mbr_get_partition(unsigned char *mbr, int i)
+{
+	return (struct dos_partition *)
+		(mbr + MBR_PT_OFFSET + (i * sizeof(struct dos_partition)));
+}
+
+/* assemble badly aligned little endian integer */
+static inline unsigned int __dos_assemble_4le(const unsigned char *p)
+{
+	return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+
+static inline void __dos_store_4le(unsigned char *p, unsigned int val)
+{
+	p[0] = (val & 0xff);
+	p[1] = ((val >> 8) & 0xff);
+	p[2] = ((val >> 16) & 0xff);
+	p[3] = ((val >> 24) & 0xff);
+}
+
+static inline unsigned int dos_partition_get_start(struct dos_partition *p)
+{
+	return __dos_assemble_4le(&(p->start_sect[0]));
+}
+
+static inline void dos_partition_set_start(struct dos_partition *p, unsigned int n)
+{
+	__dos_store_4le(p->start_sect, n);
+}
+
+static inline unsigned int dos_partition_get_size(struct dos_partition *p)
+{
+	return __dos_assemble_4le(&(p->nr_sects[0]));
+}
+
+static inline void dos_partition_set_size(struct dos_partition *p, unsigned int n)
+{
+	__dos_store_4le(p->nr_sects, n);
+}
+
+static inline int mbr_is_valid_magic(const unsigned char *mbr)
+{
+	return mbr[510] == 0x55 && mbr[511] == 0xaa ? 1 : 0;
+}
+
+static inline void mbr_set_magic(unsigned char *b)
+{
+	b[510] = 0x55;
+	b[511] = 0xaa;
+}
+
+static inline unsigned int mbr_get_id(const unsigned char *mbr)
+{
+	return __dos_assemble_4le(&mbr[440]);
+}
+
+static inline void mbr_set_id(unsigned char *b, unsigned int id)
+{
+	__dos_store_4le(&b[440], id);
+}
+
+enum {
+	MBR_EMPTY_PARTITION		= 0x00,
+	MBR_FAT12_PARTITION		= 0x01,
+	MBR_XENIX_ROOT_PARTITION	= 0x02,
+	MBR_XENIX_USR_PARTITION		= 0x03,
+	MBR_FAT16_LESS32M_PARTITION	= 0x04,
+	MBR_DOS_EXTENDED_PARTITION	= 0x05,
+	MBR_FAT16_PARTITION		= 0x06, /* DOS 16-bit >=32M */
+	MBR_HPFS_NTFS_PARTITION		= 0x07, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
+	MBR_AIX_PARTITION		= 0x08, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
+	MBR_AIX_BOOTABLE_PARTITION	= 0x09, /* AIX data or Coherent */
+	MBR_OS2_BOOTMNGR_PARTITION	= 0x0a, /* OS/2 Boot Manager */
+	MBR_W95_FAT32_PARTITION		= 0x0b,
+	MBR_W95_FAT32_LBA_PARTITION	= 0x0c, /* LBA really is `Extended Int 13h' */
+	MBR_W95_FAT16_LBA_PARTITION	= 0x0e,
+	MBR_W95_EXTENDED_PARTITION	= 0x0f,
+	MBR_OPUS_PARTITION		= 0x10,
+	MBR_HIDDEN_FAT12_PARTITION	= 0x11,
+	MBR_COMPAQ_DIAGNOSTICS_PARTITION = 0x12,
+	MBR_HIDDEN_FAT16_L32M_PARTITION	= 0x14,
+	MBR_HIDDEN_FAT16_PARTITION	= 0x16,
+	MBR_HIDDEN_HPFS_NTFS_PARTITION	= 0x17,
+	MBR_AST_SMARTSLEEP_PARTITION	= 0x18,
+	MBR_HIDDEN_W95_FAT32_PARTITION	= 0x1b,
+	MBR_HIDDEN_W95_FAT32LBA_PARTITION = 0x1c,
+	MBR_HIDDEN_W95_FAT16LBA_PARTITION = 0x1e,
+	MBR_NEC_DOS_PARTITION		= 0x24,
+	MBR_PLAN9_PARTITION		= 0x39,
+	MBR_PARTITIONMAGIC_PARTITION	= 0x3c,
+	MBR_VENIX80286_PARTITION	= 0x40,
+	MBR_PPC_PREP_BOOT_PARTITION	= 0x41,
+	MBR_SFS_PARTITION		= 0x42,
+	MBR_QNX_4X_PARTITION		= 0x4d,
+	MBR_QNX_4X_2ND_PARTITION	= 0x4e,
+	MBR_QNX_4X_3RD_PARTITION	= 0x4f,
+	MBR_DM_PARTITION		= 0x50,
+	MBR_DM6_AUX1_PARTITION		= 0x51, /* (or Novell) */
+	MBR_CPM_PARTITION		= 0x52, /* CP/M or Microport SysV/AT */
+	MBR_DM6_AUX3_PARTITION		= 0x53,
+	MBR_DM6_PARTITION		= 0x54,
+	MBR_EZ_DRIVE_PARTITION		= 0x55,
+	MBR_GOLDEN_BOW_PARTITION	= 0x56,
+	MBR_PRIAM_EDISK_PARTITION	= 0x5c,
+	MBR_SPEEDSTOR_PARTITION		= 0x61,
+	MBR_GNU_HURD_PARTITION		= 0x63, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
+	MBR_UNIXWARE_PARTITION		= MBR_GNU_HURD_PARTITION,
+	MBR_NETWARE_286_PARTITION	= 0x64,
+	MBR_NETWARE_386_PARTITION	= 0x65,
+	MBR_DISKSECURE_MULTIBOOT_PARTITION = 0x70,
+	MBR_PC_IX_PARTITION		= 0x75,
+	MBR_OLD_MINIX_PARTITION		= 0x80, /* Minix 1.4a and earlier */
+	MBR_MINIX_PARTITION		= 0x81, /* Minix 1.4b and later */
+	MBR_LINUX_SWAP_PARTITION	= 0x82,
+	MBR_SOLARIS_X86_PARTITION	= MBR_LINUX_SWAP_PARTITION,
+	MBR_LINUX_DATA_PARTITION	= 0x83,
+	MBR_OS2_HIDDEN_DRIVE_PARTITION	= 0x84,
+	MBR_LINUX_EXTENDED_PARTITION	= 0x85,
+	MBR_NTFS_VOL_SET1_PARTITION	= 0x86,
+	MBR_NTFS_VOL_SET2_PARTITION	= 0x87,
+	MBR_LINUX_PLAINTEXT_PARTITION	= 0x88,
+	MBR_LINUX_LVM_PARTITION		= 0x8e,
+	MBR_AMOEBA_PARTITION		= 0x93,
+	MBR_AMOEBA_BBT_PARTITION	= 0x94, /* (bad block table) */
+	MBR_BSD_OS_PARTITION		= 0x9f, /* BSDI */
+	MBR_THINKPAD_HIBERNATION_PARTITION = 0xa0,
+	MBR_FREEBSD_PARTITION		= 0xa5, /* various BSD flavours */
+	MBR_OPENBSD_PARTITION		= 0xa6,
+	MBR_NEXTSTEP_PARTITION		= 0xa7,
+	MBR_DARWIN_UFS_PARTITION	= 0xa8,
+	MBR_NETBSD_PARTITION		= 0xa9,
+	MBR_DARWIN_BOOT_PARTITION	= 0xab,
+	MBR_HFS_HFS_PARTITION		= 0xaf,
+	MBR_BSDI_FS_PARTITION		= 0xb7,
+	MBR_BSDI_SWAP_PARTITION		= 0xb8,
+	MBR_BOOTWIZARD_HIDDEN_PARTITION	= 0xbb,
+	MBR_SOLARIS_BOOT_PARTITION	= 0xbe,
+	MBR_SOLARIS_PARTITION		= 0xbf,
+	MBR_DRDOS_FAT12_PARTITION	= 0xc1,
+	MBR_DRDOS_FAT16_L32M_PARTITION	= 0xc4,
+	MBR_DRDOS_FAT16_PARTITION	= 0xc6,
+	MBR_SYRINX_PARTITION		= 0xc7,
+	MBR_NONFS_DATA_PARTITION	= 0xda,
+	MBR_CPM_CTOS_PARTITION		= 0xdb, /* CP/M or Concurrent CP/M or Concurrent DOS or CTOS */
+	MBR_DELL_UTILITY_PARTITION	= 0xde, /* Dell PowerEdge Server utilities */
+	MBR_BOOTIT_PARTITION		= 0xdf, /* BootIt EMBRM */
+	MBR_DOS_ACCESS_PARTITION	= 0xe1, /* DOS access or SpeedStor 12-bit FAT extended partition */
+	MBR_DOS_RO_PARTITION		= 0xe3, /* DOS R/O or SpeedStor */
+	MBR_SPEEDSTOR_EXTENDED_PARTITION = 0xe4, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */
+	MBR_BEOS_FS_PARTITION		= 0xeb,
+	MBR_GPT_PARTITION		= 0xee, /* Intel EFI GUID Partition Table */
+	MBR_EFI_SYSTEM_PARTITION	= 0xef, /* Intel EFI System Partition */
+	MBR_LINUX_PARISC_BOOT_PARTITION	= 0xf0, /* Linux/PA-RISC boot loader */
+	MBR_SPEEDSTOR1_PARTITION	= 0xf1,
+	MBR_SPEEDSTOR2_PARTITION	= 0xf4, /* SpeedStor large partition */
+	MBR_DOS_SECONDARY_PARTITION	= 0xf2, /* DOS 3.3+ secondary */
+	MBR_VMWARE_VMFS_PARTITION	= 0xfb,
+	MBR_VMWARE_VMKCORE_PARTITION	= 0xfc, /* VMware kernel dump partition */
+	MBR_LINUX_RAID_PARTITION	= 0xfd, /* New (2.2.x) raid partition with autodetect using persistent superblock */
+	MBR_LANSTEP_PARTITION		= 0xfe, /* SpeedStor >1024 cyl. or LANstep */
+	MBR_XENIX_BBT_PARTITION		= 0xff, /* Xenix Bad Block Table */
+};
+
+#endif /* UTIL_LINUX_PT_MBR_H */
diff --git a/libblkid/src/read.c b/libblkid/src/read.c
new file mode 100644
index 0000000..81ab0df
--- /dev/null
+++ b/libblkid/src/read.c
@@ -0,0 +1,510 @@
+/*
+ * read.c - read the blkid cache from disk, to avoid scanning all devices
+ *
+ * Copyright (C) 2001, 2003 Theodore Y. Ts'o
+ * Copyright (C) 2001 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "blkidP.h"
+
+#ifdef HAVE_STDLIB_H
+# ifndef _XOPEN_SOURCE
+#  define _XOPEN_SOURCE 600	/* for inclusion of strtoull */
+# endif
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRTOULL
+#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */
+#else
+/* FIXME: need to support real strtoull here */
+#define STRTOULL strtoul
+#endif
+
+#ifdef TEST_PROGRAM
+#define blkid_debug_dump_dev(dev)	(debug_dump_dev(dev))
+static void debug_dump_dev(blkid_dev dev);
+#endif
+
+/*
+ * File format:
+ *
+ *	<device [<NAME="value"> ...]>device_name</device>
+ *
+ *	The following tags are required for each entry:
+ *	<ID="id">	unique (within this file) ID number of this device
+ *	<TIME="sec.usec"> (time_t and suseconds_t) time this entry was last
+ *	                 read from disk
+ *	<TYPE="type">	(detected) type of filesystem/data for this partition
+ *
+ *	The following tags may be present, depending on the device contents
+ *	<LABEL="label">	(user supplied) label (volume name, etc)
+ *	<UUID="uuid">	(generated) universally unique identifier (serial no)
+ */
+
+static char *skip_over_blank(char *cp)
+{
+	while (*cp && isspace(*cp))
+		cp++;
+	return cp;
+}
+
+static char *skip_over_word(char *cp)
+{
+	char ch;
+
+	while ((ch = *cp)) {
+		/* If we see a backslash, skip the next character */
+		if (ch == '\\') {
+			cp++;
+			if (*cp == '\0')
+				break;
+			cp++;
+			continue;
+		}
+		if (isspace(ch) || ch == '<' || ch == '>')
+			break;
+		cp++;
+	}
+	return cp;
+}
+
+static char *strip_line(char *line)
+{
+	char	*p;
+
+	line = skip_over_blank(line);
+
+	p = line + strlen(line) - 1;
+
+	while (*line) {
+		if (isspace(*p))
+			*p-- = '\0';
+		else
+			break;
+	}
+
+	return line;
+}
+
+#if 0
+static char *parse_word(char **buf)
+{
+	char *word, *next;
+
+	word = *buf;
+	if (*word == '\0')
+		return NULL;
+
+	word = skip_over_blank(word);
+	next = skip_over_word(word);
+	if (*next) {
+		char *end = next - 1;
+		if (*end == '"' || *end == '\'')
+			*end = '\0';
+		*next++ = '\0';
+	}
+	*buf = next;
+
+	if (*word == '"' || *word == '\'')
+		word++;
+	return word;
+}
+#endif
+
+/*
+ * Start parsing a new line from the cache.
+ *
+ * line starts with "<device" return 1 -> continue parsing line
+ * line starts with "<foo", empty, or # return 0 -> skip line
+ * line starts with other, return -BLKID_ERR_CACHE -> error
+ */
+static int parse_start(char **cp)
+{
+	char *p;
+
+	p = strip_line(*cp);
+
+	/* Skip comment or blank lines.  We can't just NUL the first '#' char,
+	 * in case it is inside quotes, or escaped.
+	 */
+	if (*p == '\0' || *p == '#')
+		return 0;
+
+	if (!strncmp(p, "<device", 7)) {
+		DBG(READ, ul_debug("found device header: %8s", p));
+		p += 7;
+
+		*cp = p;
+		return 1;
+	}
+
+	if (*p == '<')
+		return 0;
+
+	return -BLKID_ERR_CACHE;
+}
+
+/* Consume the remaining XML on the line (cosmetic only) */
+static int parse_end(char **cp)
+{
+	*cp = skip_over_blank(*cp);
+
+	if (!strncmp(*cp, "</device>", 9)) {
+		DBG(READ, ul_debug("found device trailer %9s", *cp));
+		*cp += 9;
+		return 0;
+	}
+
+	return -BLKID_ERR_CACHE;
+}
+
+/*
+ * Allocate a new device struct with device name filled in.  Will handle
+ * finding the device on lines of the form:
+ * <device foo=bar>devname</device>
+ * <device>devname<foo>bar</foo></device>
+ */
+static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp)
+{
+	char *start, *tmp, *end, *name;
+	int ret;
+
+	if ((ret = parse_start(cp)) <= 0)
+		return ret;
+
+	start = tmp = strchr(*cp, '>');
+	if (!start) {
+		DBG(READ, ul_debug("blkid: short line parsing dev: %s", *cp));
+		return -BLKID_ERR_CACHE;
+	}
+	start = skip_over_blank(start + 1);
+	end = skip_over_word(start);
+
+	DBG(READ, ul_debug("device should be %*s",
+			       (int)(end - start), start));
+
+	if (**cp == '>')
+		*cp = end;
+	else
+		(*cp)++;
+
+	*tmp = '\0';
+
+	if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) {
+		DBG(READ, ul_debug("blkid: missing </device> ending: %s", end));
+	} else if (tmp)
+		*tmp = '\0';
+
+	if (end - start <= 1) {
+		DBG(READ, ul_debug("blkid: empty device name: %s", *cp));
+		return -BLKID_ERR_CACHE;
+	}
+
+	name = strndup(start, end - start);
+	if (name == NULL)
+		return -BLKID_ERR_MEM;
+
+	DBG(READ, ul_debug("found dev %s", name));
+
+	if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE))) {
+		free(name);
+		return -BLKID_ERR_MEM;
+	}
+
+	free(name);
+	return 1;
+}
+
+/*
+ * Extract a tag of the form NAME="value" from the line.
+ */
+static int parse_token(char **name, char **value, char **cp)
+{
+	char *end;
+
+	if (!name || !value || !cp)
+		return -BLKID_ERR_PARAM;
+
+	if (!(*value = strchr(*cp, '=')))
+		return 0;
+
+	**value = '\0';
+	*name = strip_line(*cp);
+	*value = skip_over_blank(*value + 1);
+
+	if (**value == '"') {
+		char *p = end = *value + 1;
+
+		/* convert 'foo\"bar'  to 'foo"bar' */
+		while (*p) {
+			if (*p == '\\') {
+				p++;
+				*end = *p;
+			} else {
+				*end = *p;
+				if (*p == '"')
+					break;
+			}
+			p++;
+			end++;
+		}
+
+		if (*end != '"') {
+			DBG(READ, ul_debug("unbalanced quotes at: %s", *value));
+			*cp = *value;
+			return -BLKID_ERR_CACHE;
+		}
+		(*value)++;
+		*end = '\0';
+		end = ++p;
+	} else {
+		end = skip_over_word(*value);
+		if (*end) {
+			*end = '\0';
+			end++;
+		}
+	}
+	*cp = end;
+
+	return 1;
+}
+
+/*
+ * Extract a tag of the form <NAME>value</NAME> from the line.
+ */
+/*
+static int parse_xml(char **name, char **value, char **cp)
+{
+	char *end;
+
+	if (!name || !value || !cp)
+		return -BLKID_ERR_PARAM;
+
+	*name = strip_line(*cp);
+
+	if ((*name)[0] != '<' || (*name)[1] == '/')
+		return 0;
+
+	FIXME: finish this.
+}
+*/
+
+/*
+ * Extract a tag from the line.
+ *
+ * Return 1 if a valid tag was found.
+ * Return 0 if no tag found.
+ * Return -ve error code.
+ */
+static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp)
+{
+	char *name = NULL;
+	char *value = NULL;
+	int ret;
+
+	if (!cache || !dev)
+		return -BLKID_ERR_PARAM;
+
+	if ((ret = parse_token(&name, &value, cp)) <= 0 /* &&
+	    (ret = parse_xml(&name, &value, cp)) <= 0 */)
+		return ret;
+
+	/* Some tags are stored directly in the device struct */
+	if (!strcmp(name, "DEVNO"))
+		dev->bid_devno = STRTOULL(value, 0, 0);
+	else if (!strcmp(name, "PRI"))
+		dev->bid_pri = strtol(value, 0, 0);
+	else if (!strcmp(name, "TIME")) {
+		char *end = NULL;
+		dev->bid_time = STRTOULL(value, &end, 0);
+		if (end && *end == '.')
+			dev->bid_utime = STRTOULL(end + 1, 0, 0);
+	} else
+		ret = blkid_set_tag(dev, name, value, strlen(value));
+
+	DBG(READ, ul_debug("    tag: %s=\"%s\"", name, value));
+
+	return ret < 0 ? ret : 1;
+}
+
+/*
+ * Parse a single line of data, and return a newly allocated dev struct.
+ * Add the new device to the cache struct, if one was read.
+ *
+ * Lines are of the form <device [TAG="value" ...]>/dev/foo</device>
+ *
+ * Returns -ve value on error.
+ * Returns 0 otherwise.
+ * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL
+ * (e.g. comment lines, unknown XML content, etc).
+ */
+static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp)
+{
+	blkid_dev dev;
+	int ret;
+
+	if (!cache || !dev_p)
+		return -BLKID_ERR_PARAM;
+
+	*dev_p = NULL;
+
+	DBG(READ, ul_debug("line: %s", cp));
+
+	if ((ret = parse_dev(cache, dev_p, &cp)) <= 0)
+		return ret;
+
+	dev = *dev_p;
+
+	while ((ret = parse_tag(cache, dev, &cp)) > 0) {
+		;
+	}
+
+	if (dev->bid_type == NULL) {
+		DBG(READ, ul_debug("blkid: device %s has no TYPE",dev->bid_name));
+		blkid_free_dev(dev);
+		goto done;
+	}
+
+	DBG(READ, blkid_debug_dump_dev(dev));
+
+done:
+	return ret;
+}
+
+/*
+ * Parse the specified filename, and return the data in the supplied or
+ * a newly allocated cache struct.  If the file doesn't exist, return a
+ * new empty cache struct.
+ */
+void blkid_read_cache(blkid_cache cache)
+{
+	FILE *file;
+	char buf[4096];
+	int fd, lineno = 0;
+	struct stat st;
+
+	if (!cache)
+		return;
+
+	/*
+	 * If the file doesn't exist, then we just return an empty
+	 * struct so that the cache can be populated.
+	 */
+	if ((fd = open(cache->bic_filename, O_RDONLY|O_CLOEXEC)) < 0)
+		return;
+	if (fstat(fd, &st) < 0)
+		goto errout;
+	if ((st.st_mtime == cache->bic_ftime) ||
+	    (cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
+		DBG(CACHE, ul_debug("skipping re-read of %s",
+					cache->bic_filename));
+		goto errout;
+	}
+
+	DBG(CACHE, ul_debug("reading cache file %s",
+				cache->bic_filename));
+
+	file = fdopen(fd, "r" UL_CLOEXECSTR);
+	if (!file)
+		goto errout;
+
+	while (fgets(buf, sizeof(buf), file)) {
+		blkid_dev dev;
+		unsigned int end;
+
+		lineno++;
+		if (buf[0] == 0)
+			continue;
+		end = strlen(buf) - 1;
+		/* Continue reading next line if it ends with a backslash */
+		while (end < (sizeof(buf) - 2) && buf[end] == '\\' &&
+		       fgets(buf + end, sizeof(buf) - end, file)) {
+			end = strlen(buf) - 1;
+			lineno++;
+		}
+
+		if (blkid_parse_line(cache, &dev, buf) < 0) {
+			DBG(READ, ul_debug("blkid: bad format on line %d", lineno));
+			continue;
+		}
+	}
+	fclose(file);
+
+	/*
+	 * Initially we do not need to write out the cache file.
+	 */
+	cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
+	cache->bic_ftime = st.st_mtime;
+
+	return;
+errout:
+	close(fd);
+	return;
+}
+
+#ifdef TEST_PROGRAM
+static void debug_dump_dev(blkid_dev dev)
+{
+	struct list_head *p;
+
+	if (!dev) {
+		printf("  dev: NULL\n");
+		return;
+	}
+
+	printf("  dev: name = %s\n", dev->bid_name);
+	printf("  dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno);
+	printf("  dev: TIME=\"%ld.%ld\"\n", (long)dev->bid_time, (long)dev->bid_utime);
+	printf("  dev: PRI=\"%d\"\n", dev->bid_pri);
+	printf("  dev: flags = 0x%08X\n", dev->bid_flags);
+
+	list_for_each(p, &dev->bid_tags) {
+		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
+		if (tag)
+			printf("    tag: %s=\"%s\"\n", tag->bit_name,
+			       tag->bit_val);
+		else
+			printf("    tag: NULL\n");
+	}
+	printf("\n");
+}
+
+int main(int argc, char**argv)
+{
+	blkid_cache cache = NULL;
+	int ret;
+
+	blkid_init_debug(BLKID_DEBUG_ALL);
+	if (argc > 2) {
+		fprintf(stderr, "Usage: %s [filename]\n"
+			"Test parsing of the cache (filename)\n", argv[0]);
+		exit(1);
+	}
+	if ((ret = blkid_get_cache(&cache, argv[1])) < 0)
+		fprintf(stderr, "error %d reading cache file %s\n", ret,
+			argv[1] ? argv[1] : blkid_get_cache_filename(NULL));
+
+	blkid_put_cache(cache);
+
+	return ret;
+}
+#endif
diff --git a/libblkid/src/resolve.c b/libblkid/src/resolve.c
new file mode 100644
index 0000000..59f0fea
--- /dev/null
+++ b/libblkid/src/resolve.c
@@ -0,0 +1,130 @@
+/*
+ * resolve.c - resolve names and tags into specific devices
+ *
+ * Copyright (C) 2001, 2003 Theodore Ts'o.
+ * Copyright (C) 2001 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "blkidP.h"
+
+/*
+ * Find a tagname (e.g. LABEL or UUID) on a specific device.
+ */
+char *blkid_get_tag_value(blkid_cache cache, const char *tagname,
+			  const char *devname)
+{
+	blkid_tag found;
+	blkid_dev dev;
+	blkid_cache c = cache;
+	char *ret = NULL;
+
+	DBG(TAG, ul_debug("looking for %s on %s", tagname, devname));
+
+	if (!devname)
+		return NULL;
+	if (!cache && blkid_get_cache(&c, NULL) < 0)
+		return NULL;
+
+	if ((dev = blkid_get_dev(c, devname, BLKID_DEV_NORMAL)) &&
+	    (found = blkid_find_tag_dev(dev, tagname)))
+		ret = found->bit_val ? strdup(found->bit_val) : NULL;
+
+	if (!cache)
+		blkid_put_cache(c);
+
+	return ret;
+}
+
+/*
+ * Locate a device name from a token (NAME=value string), or (name, value)
+ * pair.  In the case of a token, value is ignored.  If the "token" is not
+ * of the form "NAME=value" and there is no value given, then it is assumed
+ * to be the actual devname and a copy is returned.
+ */
+char *blkid_get_devname(blkid_cache cache, const char *token,
+			const char *value)
+{
+	blkid_dev dev;
+	blkid_cache c = cache;
+	char *t = 0, *v = 0;
+	char *ret = NULL;
+
+	if (!token)
+		return NULL;
+	if (!cache && blkid_get_cache(&c, NULL) < 0)
+		return NULL;
+
+	DBG(TAG, ul_debug("looking for %s%s%s %s", token, value ? "=" : "",
+		   value ? value : "", cache ? "in cache" : "from disk"));
+
+	if (!value) {
+		if (!strchr(token, '=')) {
+			ret = strdup(token);
+			goto out;
+		}
+		blkid_parse_tag_string(token, &t, &v);
+		if (!t || !v)
+			goto out;
+		token = t;
+		value = v;
+	}
+
+	dev = blkid_find_dev_with_tag(c, token, value);
+	if (!dev)
+		goto out;
+
+	ret = dev->bid_name ? strdup(dev->bid_name) : NULL;
+out:
+	free(t);
+	free(v);
+	if (!cache)
+		blkid_put_cache(c);
+	return ret;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+	char *value;
+	blkid_cache cache;
+
+	blkid_init_debug(BLKID_DEBUG_ALL);
+	if (argc != 2 && argc != 3) {
+		fprintf(stderr, "Usage:\t%s tagname=value\n"
+			"\t%s tagname devname\n"
+			"Find which device holds a given token or\n"
+			"Find what the value of a tag is in a device\n",
+			argv[0], argv[0]);
+		exit(1);
+	}
+	if (blkid_get_cache(&cache, "/dev/null") < 0) {
+		fprintf(stderr, "Couldn't get blkid cache\n");
+		exit(1);
+	}
+
+	if (argv[2]) {
+		value = blkid_get_tag_value(cache, argv[1], argv[2]);
+		printf("%s has tag %s=%s\n", argv[2], argv[1],
+		       value ? value : "<missing>");
+	} else {
+		value = blkid_get_devname(cache, argv[1], NULL);
+		printf("%s has tag %s\n", value ? value : "<none>", argv[1]);
+	}
+	blkid_put_cache(cache);
+	return value ? 0 : 1;
+}
+#endif
diff --git a/libblkid/src/save.c b/libblkid/src/save.c
new file mode 100644
index 0000000..c2a9753
--- /dev/null
+++ b/libblkid/src/save.c
@@ -0,0 +1,244 @@
+/*
+ * save.c - write the cache struct to disk
+ *
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "closestream.h"
+
+#include "blkidP.h"
+
+
+static void save_quoted(const char *data, FILE *file)
+{
+	const char *p;
+
+	fputc('"', file);
+	for (p = data; p && *p; p++) {
+		if ((unsigned char) *p == 0x22 ||		/* " */
+		    (unsigned char) *p == 0x5c)			/* \ */
+			fputc('\\', file);
+
+		fputc(*p, file);
+	}
+	fputc('"', file);
+}
+static int save_dev(blkid_dev dev, FILE *file)
+{
+	struct list_head *p;
+
+	if (!dev || dev->bid_name[0] != '/')
+		return 0;
+
+	DBG(SAVE, ul_debug("device %s, type %s", dev->bid_name, dev->bid_type ?
+		   dev->bid_type : "(null)"));
+
+	fprintf(file, "<device DEVNO=\"0x%04lx\" TIME=\"%ld.%ld\"",
+			(unsigned long) dev->bid_devno,
+			(long) dev->bid_time,
+			(long) dev->bid_utime);
+
+	if (dev->bid_pri)
+		fprintf(file, " PRI=\"%d\"", dev->bid_pri);
+
+	list_for_each(p, &dev->bid_tags) {
+		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
+
+		fputc(' ', file);			/* space between tags */
+		fputs(tag->bit_name, file);		/* tag NAME */
+		fputc('=', file);			/* separator between NAME and VALUE */
+		save_quoted(tag->bit_val, file);	/* tag "VALUE" */
+	}
+	fprintf(file, ">%s</device>\n", dev->bid_name);
+
+	return 0;
+}
+
+/*
+ * Write out the cache struct to the cache file on disk.
+ */
+int blkid_flush_cache(blkid_cache cache)
+{
+	struct list_head *p;
+	char *tmp = NULL;
+	char *opened = NULL;
+	char *filename;
+	FILE *file = NULL;
+	int fd, ret = 0;
+	struct stat st;
+
+	if (!cache)
+		return -BLKID_ERR_PARAM;
+
+	if (list_empty(&cache->bic_devs) ||
+	    !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
+		DBG(SAVE, ul_debug("skipping cache file write"));
+		return 0;
+	}
+
+	filename = cache->bic_filename ? cache->bic_filename :
+					 blkid_get_cache_filename(NULL);
+	if (!filename)
+		return -BLKID_ERR_PARAM;
+
+	if (strncmp(filename,
+	    BLKID_RUNTIME_DIR "/", sizeof(BLKID_RUNTIME_DIR)) == 0) {
+
+		/* default destination, create the directory if necessary */
+		if (stat(BLKID_RUNTIME_DIR, &st)
+		    && errno == ENOENT
+		    && mkdir(BLKID_RUNTIME_DIR, S_IWUSR|
+						S_IRUSR|S_IRGRP|S_IROTH|
+						S_IXUSR|S_IXGRP|S_IXOTH) != 0
+		    && errno != EEXIST) {
+			DBG(SAVE, ul_debug("can't create %s directory for cache file",
+					BLKID_RUNTIME_DIR));
+			return 0;
+		}
+	}
+
+	/* If we can't write to the cache file, then don't even try */
+	if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) ||
+	    (ret == 0 && access(filename, W_OK) < 0)) {
+		DBG(SAVE, ul_debug("can't write to cache file %s", filename));
+		return 0;
+	}
+
+	/*
+	 * Try and create a temporary file in the same directory so
+	 * that in case of error we don't overwrite the cache file.
+	 * If the cache file doesn't yet exist, it isn't a regular
+	 * file (e.g. /dev/null or a socket), or we couldn't create
+	 * a temporary file then we open it directly.
+	 */
+	if (ret == 0 && S_ISREG(st.st_mode)) {
+		tmp = malloc(strlen(filename) + 8);
+		if (tmp) {
+			sprintf(tmp, "%s-XXXXXX", filename);
+			fd = mkstemp(tmp);
+			if (fd >= 0) {
+				if (fchmod(fd, 0644) != 0)
+					DBG(SAVE, ul_debug("%s: fchmod failed", filename));
+				else if ((file = fdopen(fd, "w" UL_CLOEXECSTR)))
+					opened = tmp;
+				if (!file)
+					close(fd);
+			}
+		}
+	}
+
+	if (!file) {
+		file = fopen(filename, "w" UL_CLOEXECSTR);
+		opened = filename;
+	}
+
+	DBG(SAVE, ul_debug("writing cache file %s (really %s)",
+		   filename, opened));
+
+	if (!file) {
+		ret = errno;
+		goto errout;
+	}
+
+	list_for_each(p, &cache->bic_devs) {
+		blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
+		if (!dev->bid_type || (dev->bid_flags & BLKID_BID_FL_REMOVABLE))
+			continue;
+		if ((ret = save_dev(dev, file)) < 0)
+			break;
+	}
+
+	if (ret >= 0) {
+		cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
+		ret = 1;
+	}
+
+	if (close_stream(file) != 0)
+		DBG(SAVE, ul_debug("write failed: %s", filename));
+
+	if (opened != filename) {
+		if (ret < 0) {
+			unlink(opened);
+			DBG(SAVE, ul_debug("unlinked temp cache %s", opened));
+		} else {
+			char *backup;
+
+			backup = malloc(strlen(filename) + 5);
+			if (backup) {
+				sprintf(backup, "%s.old", filename);
+				unlink(backup);
+				if (link(filename, backup)) {
+					DBG(SAVE, ul_debug("can't link %s to %s",
+							filename, backup));
+				}
+				free(backup);
+			}
+			if (rename(opened, filename)) {
+				ret = errno;
+				DBG(SAVE, ul_debug("can't rename %s to %s",
+						opened, filename));
+			} else {
+				DBG(SAVE, ul_debug("moved temp cache %s", opened));
+			}
+		}
+	}
+
+errout:
+	free(tmp);
+	if (filename != cache->bic_filename)
+		free(filename);
+	return ret;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+	blkid_cache cache = NULL;
+	int ret;
+
+	blkid_init_debug(BLKID_DEBUG_ALL);
+	if (argc > 2) {
+		fprintf(stderr, "Usage: %s [filename]\n"
+			"Test loading/saving a cache (filename)\n", argv[0]);
+		exit(1);
+	}
+
+	if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
+		fprintf(stderr, "%s: error creating cache (%d)\n",
+			argv[0], ret);
+		exit(1);
+	}
+	if ((ret = blkid_probe_all(cache)) < 0) {
+		fprintf(stderr, "error (%d) probing devices\n", ret);
+		exit(1);
+	}
+	cache->bic_filename = strdup(argv[1]);
+
+	if ((ret = blkid_flush_cache(cache)) < 0) {
+		fprintf(stderr, "error (%d) saving cache\n", ret);
+		exit(1);
+	}
+
+	blkid_put_cache(cache);
+
+	return ret;
+}
+#endif
diff --git a/libblkid/src/strutils.h b/libblkid/src/strutils.h
new file mode 100644
index 0000000..4d8463a
--- /dev/null
+++ b/libblkid/src/strutils.h
@@ -0,0 +1,204 @@
+#ifndef UTIL_LINUX_STRUTILS
+#define UTIL_LINUX_STRUTILS
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+/* default strtoxx_or_err() exit code */
+#ifndef STRTOXX_EXIT_CODE
+# define STRTOXX_EXIT_CODE EXIT_FAILURE
+#endif
+
+
+extern int parse_size(const char *str, uintmax_t *res, int *power);
+extern int strtosize(const char *str, uintmax_t *res);
+extern uintmax_t strtosize_or_err(const char *str, const char *errmesg);
+
+extern int16_t strtos16_or_err(const char *str, const char *errmesg);
+extern uint16_t strtou16_or_err(const char *str, const char *errmesg);
+
+extern int32_t strtos32_or_err(const char *str, const char *errmesg);
+extern uint32_t strtou32_or_err(const char *str, const char *errmesg);
+
+extern int64_t strtos64_or_err(const char *str, const char *errmesg);
+extern uint64_t strtou64_or_err(const char *str, const char *errmesg);
+
+extern double strtod_or_err(const char *str, const char *errmesg);
+
+extern long strtol_or_err(const char *str, const char *errmesg);
+extern unsigned long strtoul_or_err(const char *str, const char *errmesg);
+
+extern void strtotimeval_or_err(const char *str, struct timeval *tv,
+		const char *errmesg);
+
+extern int isdigit_string(const char *str);
+
+#ifndef HAVE_MEMPCPY
+extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n);
+#endif
+#ifndef HAVE_STRNLEN
+extern size_t strnlen(const char *s, size_t maxlen);
+#endif
+#ifndef HAVE_STRNDUP
+extern char *strndup(const char *s, size_t n);
+#endif
+#ifndef HAVE_STRNCHR
+extern char *strnchr(const char *s, size_t maxlen, int c);
+#endif
+
+/* caller guarantees n > 0 */
+static inline void xstrncpy(char *dest, const char *src, size_t n)
+{
+	strncpy(dest, src, n-1);
+	dest[n-1] = 0;
+}
+
+static inline char *strdup_to_offset(void *stru, size_t offset, const char *str)
+{
+	char *n = NULL;
+	char **o = (char **) ((char *) stru + offset);
+
+	if (str) {
+		n = strdup(str);
+		if (!n)
+			return NULL;
+	}
+
+	free(*o);
+	*o = n;
+	return n;
+}
+
+#define strdup_to_struct_member(_s, _m, _str) \
+		strdup_to_offset((void *) _s, offsetof(__typeof__(*(_s)), _m), _str)
+
+extern void strmode(mode_t mode, char *str);
+
+/* Options for size_to_human_string() */
+enum
+{
+        SIZE_SUFFIX_1LETTER = 0,
+        SIZE_SUFFIX_3LETTER = 1,
+        SIZE_SUFFIX_SPACE   = 2
+};
+
+extern char *size_to_human_string(int options, uint64_t bytes);
+
+extern int string_to_idarray(const char *list, int ary[], size_t arysz,
+			   int (name2id)(const char *, size_t));
+extern int string_add_to_idarray(const char *list, int ary[],
+				 size_t arysz, int *ary_pos,
+				 int (name2id)(const char *, size_t));
+
+extern int string_to_bitarray(const char *list, char *ary,
+			    int (*name2bit)(const char *, size_t));
+
+extern int string_to_bitmask(const char *list,
+			     unsigned long *mask,
+			     long (*name2flag)(const char *, size_t));
+extern int parse_range(const char *str, int *lower, int *upper, int def);
+
+extern int streq_except_trailing_slash(const char *s1, const char *s2);
+
+/*
+ * Match string beginning.
+ */
+static inline const char *startswith(const char *s, const char *prefix)
+{
+	size_t sz = prefix ? strlen(prefix) : 0;
+
+        if (s && sz && strncmp(s, prefix, sz) == 0)
+                return s + sz;
+	return NULL;
+}
+
+/*
+ * Case insensitive match string beginning.
+ */
+static inline const char *startswith_no_case(const char *s, const char *prefix)
+{
+	size_t sz = prefix ? strlen(prefix) : 0;
+
+        if (s && sz && strncasecmp(s, prefix, sz) == 0)
+                return s + sz;
+	return NULL;
+}
+
+/*
+ * Match string ending.
+ */
+static inline const char *endswith(const char *s, const char *postfix)
+{
+	size_t sl = s ? strlen(s) : 0;
+	size_t pl = postfix ? strlen(postfix) : 0;
+
+	if (pl == 0)
+		return (char *)s + sl;
+	if (sl < pl)
+		return NULL;
+	if (memcmp(s + sl - pl, postfix, pl) != 0)
+		return NULL;
+	return (char *)s + sl - pl;
+}
+
+/*
+ * Skip leading white space.
+ */
+static inline const char *skip_space(const char *p)
+{
+	while (isspace(*p))
+		++p;
+	return p;
+}
+
+static inline const char *skip_blank(const char *p)
+{
+	while (isblank(*p))
+		++p;
+	return p;
+}
+
+
+/* Removes whitespace from the right-hand side of a string (trailing
+ * whitespace).
+ *
+ * Returns size of the new string (without \0).
+ */
+static inline size_t rtrim_whitespace(unsigned char *str)
+{
+	size_t i = strlen((char *) str);
+
+	while (i) {
+		i--;
+		if (!isspace(str[i])) {
+			i++;
+			break;
+		}
+	}
+	str[i] = '\0';
+	return i;
+}
+
+/* Removes whitespace from the left-hand side of a string.
+ *
+ * Returns size of the new string (without \0).
+ */
+static inline size_t ltrim_whitespace(unsigned char *str)
+{
+	size_t len;
+	unsigned char *p;
+
+	for (p = str; p && isspace(*p); p++);
+
+	len = strlen((char *) p);
+
+	if (len && p > str)
+		memmove(str, p, len + 1);
+
+	return len;
+}
+
+#endif
diff --git a/libblkid/src/superblocks/adaptec_raid.c b/libblkid/src/superblocks/adaptec_raid.c
new file mode 100644
index 0000000..65fd5b8
--- /dev/null
+++ b/libblkid/src/superblocks/adaptec_raid.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct adaptec_metadata {
+
+	uint32_t	b0idcode;
+	uint8_t		lunsave[8];
+	uint16_t	sdtype;
+	uint16_t	ssavecyl;
+	uint8_t		ssavehed;
+	uint8_t		ssavesec;
+	uint8_t		sb0flags;
+	uint8_t		jbodEnable;
+	uint8_t		lundsave;
+	uint8_t		svpdirty;
+	uint16_t	biosInfo;
+	uint16_t	svwbskip;
+	uint16_t	svwbcln;
+	uint16_t	svwbmax;
+	uint16_t	res3;
+	uint16_t	svwbmin;
+	uint16_t	res4;
+	uint16_t	svrcacth;
+	uint16_t	svwcacth;
+	uint16_t	svwbdly;
+	uint8_t		svsdtime;
+	uint8_t		res5;
+	uint16_t	firmval;
+	uint16_t	firmbln;
+	uint32_t	firmblk;
+	uint32_t	fstrsvrb;
+	uint16_t	svBlockStorageTid;
+	uint16_t	svtid;
+	uint8_t		svseccfl;
+	uint8_t		res6;
+	uint8_t		svhbanum;
+	uint8_t		resver;
+	uint32_t	drivemagic;
+	uint8_t		reserved[20];
+	uint8_t		testnum;
+	uint8_t		testflags;
+	uint16_t	maxErrorCount;
+	uint32_t	count;
+	uint32_t	startTime;
+	uint32_t	interval;
+	uint8_t		tstxt0;
+	uint8_t		tstxt1;
+	uint8_t		serNum[32];
+	uint8_t		res8[102];
+	uint32_t	fwTestMagic;
+	uint32_t	fwTestSeqNum;
+	uint8_t		fwTestRes[8];
+	uint32_t	smagic;
+	uint32_t	raidtbl;
+	uint16_t	raidline;
+	uint8_t		res9[0xF6];
+} __attribute__((packed));
+
+#define AD_SIGNATURE	0x4450544D	/* "DPTM" */
+#define AD_MAGIC	0x37FC4D1E
+
+static int probe_adraid(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	uint64_t off;
+	struct adaptec_metadata *ad;
+
+	if (pr->size < 0x10000)
+		return BLKID_PROBE_NONE;
+
+	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+		return BLKID_PROBE_NONE;
+
+	off = ((pr->size / 0x200)-1) * 0x200;
+	ad = (struct adaptec_metadata *)
+			blkid_probe_get_buffer(pr,
+					off,
+					sizeof(struct adaptec_metadata));
+	if (!ad)
+		return errno ? -errno : BLKID_PROBE_NONE;;
+
+	if (ad->smagic != be32_to_cpu(AD_SIGNATURE))
+		return BLKID_PROBE_NONE;
+	if (ad->b0idcode != be32_to_cpu(AD_MAGIC))
+		return BLKID_PROBE_NONE;
+	if (blkid_probe_sprintf_version(pr, "%u", ad->resver) != 0)
+		return BLKID_PROBE_NONE;
+	if (blkid_probe_set_magic(pr, off, sizeof(ad->b0idcode),
+				(unsigned char *) &ad->b0idcode))
+		return BLKID_PROBE_NONE;
+
+	return BLKID_PROBE_OK;
+}
+
+const struct blkid_idinfo adraid_idinfo = {
+	.name		= "adaptec_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_adraid,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/bcache.c b/libblkid/src/superblocks/bcache.c
new file mode 100644
index 0000000..b3e397b
--- /dev/null
+++ b/libblkid/src/superblocks/bcache.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 Rolf Fokkens <rolf@fokkens.nl>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Based on code fragments from bcache-tools by Kent Overstreet:
+ * http://evilpiepirate.org/git/bcache-tools.git
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "superblocks.h"
+#include "crc64.h"
+
+#define SB_LABEL_SIZE      32
+#define SB_JOURNAL_BUCKETS 256U
+
+#define node(i, j)         ((i)->d + (j))
+#define end(i)             node(i, (i)->keys)
+
+static const char bcache_magic[] = {
+	0xc6, 0x85, 0x73, 0xf6, 0x4e, 0x1a, 0x45, 0xca,
+	0x82, 0x65, 0xf5, 0x7f, 0x48, 0xba, 0x6d, 0x81
+};
+
+struct bcache_super_block {
+	uint64_t		csum;
+	uint64_t		offset;	/* sector where this sb was written */
+	uint64_t		version;
+
+	uint8_t			magic[16];
+
+	uint8_t			uuid[16];
+	union {
+		uint8_t		set_uuid[16];
+		uint64_t	set_magic;
+	};
+	uint8_t			label[SB_LABEL_SIZE];
+
+	uint64_t		flags;
+	uint64_t		seq;
+	uint64_t		pad[8];
+
+	union {
+	struct {
+		/* Cache devices */
+		uint64_t	nbuckets;	/* device size */
+
+		uint16_t	block_size;	/* sectors */
+		uint16_t	bucket_size;	/* sectors */
+
+		uint16_t	nr_in_set;
+		uint16_t	nr_this_dev;
+	};
+	struct {
+		/* Backing devices */
+		uint64_t	data_offset;
+
+		/*
+		 * block_size from the cache device section is still used by
+		 * backing devices, so don't add anything here until we fix
+		 * things to not need it for backing devices anymore
+		 */
+	};
+	};
+
+	uint32_t		last_mount;	/* time_t */
+
+	uint16_t		first_bucket;
+	union {
+		uint16_t	njournal_buckets;
+		uint16_t	keys;
+	};
+	uint64_t		d[SB_JOURNAL_BUCKETS];	/* journal buckets */
+};
+
+/* magic string */
+#define BCACHE_SB_MAGIC     bcache_magic
+/* magic string len */
+#define BCACHE_SB_MAGIC_LEN sizeof (bcache_magic)
+/* super block offset */
+#define BCACHE_SB_OFF       0x1000
+/* supper block offset in kB */
+#define BCACHE_SB_KBOFF     (BCACHE_SB_OFF >> 10)
+/* magic string offset within super block */
+#define BCACHE_SB_MAGIC_OFF offsetof (struct bcache_super_block, magic)
+
+static uint64_t bcache_crc64(struct bcache_super_block *bcs)
+{
+	unsigned char *data = (unsigned char *) bcs;
+	size_t sz;
+
+	data += 8;		/* skip csum field */
+	sz = (unsigned char *) end(bcs) - data;
+
+	return crc64(0xFFFFFFFFFFFFFFFFULL, data, sz) ^ 0xFFFFFFFFFFFFFFFFULL;
+}
+
+static int probe_bcache (blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct bcache_super_block *bcs;
+
+	bcs = blkid_probe_get_sb(pr, mag, struct bcache_super_block);
+	if (!bcs)
+		return errno ? -errno : BLKID_PROBE_NONE;
+
+	if (le64_to_cpu(bcs->offset) != BCACHE_SB_OFF / 512)
+		return BLKID_PROBE_NONE;
+	if (!blkid_probe_verify_csum(pr, bcache_crc64(bcs), le64_to_cpu(bcs->csum)))
+		return BLKID_PROBE_NONE;
+
+	if (blkid_probe_set_uuid(pr, bcs->uuid) < 0)
+		return BLKID_PROBE_NONE;
+
+	return BLKID_PROBE_OK;
+};
+
+const struct blkid_idinfo bcache_idinfo =
+{
+	.name		= "bcache",
+	.usage		= BLKID_USAGE_OTHER,
+	.probefunc	= probe_bcache,
+	.minsz		= 8192,
+	.magics		=
+	{
+		{ .magic = BCACHE_SB_MAGIC
+		, .len   = BCACHE_SB_MAGIC_LEN
+		, .kboff = BCACHE_SB_KBOFF
+		, .sboff = BCACHE_SB_MAGIC_OFF
+		} ,
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/befs.c b/libblkid/src/superblocks/befs.c
new file mode 100644
index 0000000..e4453bc
--- /dev/null
+++ b/libblkid/src/superblocks/befs.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2010 Jeroen Oortwijn <oortwijn@gmail.com>
+ *
+ * Partly based on the Haiku BFS driver by
+ *     Axel Dörfler <axeld@pinc-software.de>
+ *
+ * Also inspired by the Linux BeFS driver by
+ *     Will Dyson <will_dyson@pobox.com>, et al.
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "superblocks.h"
+
+#define B_OS_NAME_LENGTH	0x20
+#define SUPER_BLOCK_MAGIC1	0x42465331	/* BFS1 */
+#define SUPER_BLOCK_MAGIC2	0xdd121031
+#define SUPER_BLOCK_MAGIC3	0x15b6830e
+#define SUPER_BLOCK_FS_ENDIAN	0x42494745	/* BIGE */
+#define INODE_MAGIC1		0x3bbe0ad9
+#define BPLUSTREE_MAGIC		0x69f6c2e8
+#define BPLUSTREE_NULL		-1LL
+#define NUM_DIRECT_BLOCKS	12
+#define B_UINT64_TYPE		0x554c4c47	/* ULLG */
+#define KEY_NAME		"be:volume_id"
+#define KEY_SIZE		8
+
+#define FS16_TO_CPU(value, fs_is_le) (fs_is_le ? le16_to_cpu(value) \
+							: be16_to_cpu(value))
+#define FS32_TO_CPU(value, fs_is_le) (fs_is_le ? le32_to_cpu(value) \
+							: be32_to_cpu(value))
+#define FS64_TO_CPU(value, fs_is_le) (fs_is_le ? le64_to_cpu(value) \
+							: be64_to_cpu(value))
+
+typedef struct block_run {
+	int32_t		allocation_group;
+	uint16_t	start;
+	uint16_t	len;
+} __attribute__((packed)) block_run, inode_addr;
+
+struct befs_super_block {
+	char		name[B_OS_NAME_LENGTH];
+	int32_t		magic1;
+	int32_t		fs_byte_order;
+	uint32_t	block_size;
+	uint32_t	block_shift;
+	int64_t		num_blocks;
+	int64_t		used_blocks;
+	int32_t		inode_size;
+	int32_t		magic2;
+	int32_t		blocks_per_ag;
+	int32_t		ag_shift;
+	int32_t		num_ags;
+	int32_t		flags;
+	block_run	log_blocks;
+	int64_t		log_start;
+	int64_t		log_end;
+	int32_t		magic3;
+	inode_addr	root_dir;
+	inode_addr	indices;
+	int32_t		pad[8];
+} __attribute__((packed));
+
+typedef struct data_stream {
+	block_run	direct[NUM_DIRECT_BLOCKS];
+	int64_t		max_direct_range;
+	block_run	indirect;
+	int64_t		max_indirect_range;
+	block_run	double_indirect;
+	int64_t		max_double_indirect_range;
+	int64_t		size;
+} __attribute__((packed)) data_stream;
+
+struct befs_inode {
+	int32_t		magic1;
+	inode_addr	inode_num;
+	int32_t		uid;
+	int32_t		gid;
+	int32_t		mode;
+	int32_t		flags;
+	int64_t		create_time;
+	int64_t		last_modified_time;
+	inode_addr	parent;
+	inode_addr	attributes;
+	uint32_t	type;
+	int32_t		inode_size;
+	uint32_t	etc;
+	data_stream	data;
+	int32_t		pad[4];
+	int32_t		small_data[0];
+} __attribute__((packed));
+
+struct small_data {
+	uint32_t	type;
+	uint16_t	name_size;
+	uint16_t	data_size;
+	char		name[0];
+} __attribute__((packed));
+
+struct bplustree_header {
+	uint32_t	magic;
+	uint32_t	node_size;
+	uint32_t	max_number_of_levels;
+	uint32_t	data_type;
+	int64_t		root_node_pointer;
+	int64_t		free_node_pointer;
+	int64_t		maximum_size;
+} __attribute__((packed));
+
+struct bplustree_node {
+	int64_t		left_link;
+	int64_t		right_link;
+	int64_t		overflow_link;
+	uint16_t	all_key_count;
+	uint16_t	all_key_length;
+	char		name[0];
+} __attribute__((packed));
+
+static unsigned char *get_block_run(blkid_probe pr, const struct befs_super_block *bs,
+					const struct block_run *br, int fs_le)
+{
+	return blkid_probe_get_buffer(pr,
+			((blkid_loff_t) FS32_TO_CPU(br->allocation_group, fs_le)
+					<< FS32_TO_CPU(bs->ag_shift, fs_le)
+					<< FS32_TO_CPU(bs->block_shift, fs_le))
+				+ ((blkid_loff_t) FS16_TO_CPU(br->start, fs_le)
+					<< FS32_TO_CPU(bs->block_shift, fs_le)),
+			(blkid_loff_t) FS16_TO_CPU(br->len, fs_le)
+					<< FS32_TO_CPU(bs->block_shift, fs_le));
+}
+
+static unsigned char *get_custom_block_run(blkid_probe pr,
+				const struct befs_super_block *bs,
+				const struct block_run *br,
+				int64_t offset, uint32_t length, int fs_le)
+{
+	if (offset + length > (int64_t) FS16_TO_CPU(br->len, fs_le)
+					<< FS32_TO_CPU(bs->block_shift, fs_le))
+		return NULL;
+
+	return blkid_probe_get_buffer(pr,
+			((blkid_loff_t) FS32_TO_CPU(br->allocation_group, fs_le)
+					<< FS32_TO_CPU(bs->ag_shift, fs_le)
+					<< FS32_TO_CPU(bs->block_shift, fs_le))
+				+ ((blkid_loff_t) FS16_TO_CPU(br->start, fs_le)
+					<< FS32_TO_CPU(bs->block_shift, fs_le))
+				+ offset,
+			length);
+}
+
+static unsigned char *get_tree_node(blkid_probe pr, const struct befs_super_block *bs,
+				const struct data_stream *ds,
+				int64_t start, uint32_t length, int fs_le)
+{
+	if (start < (int64_t) FS64_TO_CPU(ds->max_direct_range, fs_le)) {
+		int64_t br_len;
+		size_t i;
+
+		for (i = 0; i < NUM_DIRECT_BLOCKS; i++) {
+			br_len = (int64_t) FS16_TO_CPU(ds->direct[i].len, fs_le)
+					<< FS32_TO_CPU(bs->block_shift, fs_le);
+			if (start < br_len)
+				return get_custom_block_run(pr, bs,
+							&ds->direct[i],
+							start, length, fs_le);
+			else
+				start -= br_len;
+		}
+	} else if (start < (int64_t) FS64_TO_CPU(ds->max_indirect_range, fs_le)) {
+		struct block_run *br;
+		int64_t max_br, br_len, i;
+
+		start -= FS64_TO_CPU(ds->max_direct_range, fs_le);
+		max_br = ((int64_t) FS16_TO_CPU(ds->indirect.len, fs_le)
+					<< FS32_TO_CPU(bs->block_shift, fs_le))
+				/ sizeof(struct block_run);
+
+		br = (struct block_run *) get_block_run(pr, bs, &ds->indirect,
+									fs_le);
+		if (!br)
+			return NULL;
+
+		for (i = 0; i < max_br; i++) {
+			br_len = (int64_t) FS16_TO_CPU(br[i].len, fs_le)
+					<< FS32_TO_CPU(bs->block_shift, fs_le);
+			if (start < br_len)
+				return get_custom_block_run(pr, bs, &br[i],
+							start, length, fs_le);
+			else
+				start -= br_len;
+		}
+	} else if (start < (int64_t) FS64_TO_CPU(ds->max_double_indirect_range, fs_le)) {
+		struct block_run *br;
+		int64_t di_br_size, br_per_di_br, di_index, i_index;
+
+		start -= (int64_t) FS64_TO_CPU(ds->max_indirect_range, fs_le);
+
+		di_br_size = (int64_t) FS16_TO_CPU(ds->double_indirect.len,
+				fs_le) << FS32_TO_CPU(bs->block_shift, fs_le);
+		if (di_br_size == 0)
+			return NULL;
+
+		br_per_di_br = di_br_size / sizeof(struct block_run);
+		if (br_per_di_br == 0)
+			return NULL;
+
+		di_index = start / (br_per_di_br * di_br_size);
+		i_index = (start % (br_per_di_br * di_br_size)) / di_br_size;
+		start = (start % (br_per_di_br * di_br_size)) % di_br_size;
+
+		br = (struct block_run *) get_block_run(pr, bs,
+						&ds->double_indirect, fs_le);
+		if (!br)
+			return NULL;
+
+		br = (struct block_run *) get_block_run(pr, bs, &br[di_index],
+									fs_le);
+		if (!br)
+			return NULL;
+
+		return get_custom_block_run(pr, bs, &br[i_index], start, length,
+									fs_le);
+	}
+	return NULL;
+}
+
+static int32_t compare_keys(const char keys1[], uint16_t keylengths1[], int32_t index,
+			const char *key2, uint16_t keylength2, int fs_le)
+{
+	const char *key1;
+	uint16_t keylength1;
+	int32_t result;
+
+	key1 = &keys1[index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1],
+									fs_le)];
+	keylength1 = FS16_TO_CPU(keylengths1[index], fs_le)
+			- (index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1],
+									fs_le));
+
+	result = strncmp(key1, key2, min(keylength1, keylength2));
+
+	if (result == 0)
+		return keylength1 - keylength2;
+
+	return result;
+}
+
+static int64_t get_key_value(blkid_probe pr, const struct befs_super_block *bs,
+			const struct befs_inode *bi, const char *key, int fs_le)
+{
+	struct bplustree_header *bh;
+	struct bplustree_node *bn;
+	uint16_t *keylengths;
+	int64_t *values;
+	int64_t node_pointer;
+	int32_t first, last, mid, cmp;
+
+	errno = 0;
+	bh = (struct bplustree_header *) get_tree_node(pr, bs, &bi->data, 0,
+					sizeof(struct bplustree_header), fs_le);
+	if (!bh)
+		return errno ? -errno : -ENOENT;
+
+	if ((int32_t) FS32_TO_CPU(bh->magic, fs_le) != BPLUSTREE_MAGIC)
+		return -ENOENT;
+
+	node_pointer = FS64_TO_CPU(bh->root_node_pointer, fs_le);
+
+	do {
+		errno = 0;
+		bn = (struct bplustree_node *) get_tree_node(pr, bs, &bi->data,
+			node_pointer, FS32_TO_CPU(bh->node_size, fs_le), fs_le);
+		if (!bn)
+			return errno ? -errno : -ENOENT;
+
+		keylengths = (uint16_t *) ((uint8_t *) bn
+				+ ((sizeof(struct bplustree_node)
+					+ FS16_TO_CPU(bn->all_key_length, fs_le)
+					+ sizeof(int64_t) - 1)
+						& ~(sizeof(int64_t) - 1)));
+		values = (int64_t *) ((uint8_t *) keylengths
+					+ FS16_TO_CPU(bn->all_key_count, fs_le)
+						* sizeof(uint16_t));
+		first = 0;
+		mid = 0;
+		last = FS16_TO_CPU(bn->all_key_count, fs_le) - 1;
+
+		cmp = compare_keys(bn->name, keylengths, last, key, strlen(key),
+									fs_le);
+		if (cmp == 0) {
+			if ((int64_t) FS64_TO_CPU(bn->overflow_link, fs_le)
+							== BPLUSTREE_NULL)
+				return FS64_TO_CPU(values[last], fs_le);
+			else
+				node_pointer = FS64_TO_CPU(values[last], fs_le);
+		} else if (cmp < 0)
+			node_pointer = FS64_TO_CPU(bn->overflow_link, fs_le);
+		else {
+			while (first <= last) {
+				mid = (first + last) / 2;
+
+				cmp = compare_keys(bn->name, keylengths, mid,
+						key, strlen(key), fs_le);
+				if (cmp == 0) {
+					if ((int64_t) FS64_TO_CPU(bn->overflow_link,
+						fs_le) == BPLUSTREE_NULL)
+						return FS64_TO_CPU(values[mid],
+									fs_le);
+					else
+						break;
+				} else if (cmp < 0)
+					first = mid + 1;
+				else
+					last = mid - 1;
+			}
+			if (cmp < 0)
+				node_pointer = FS64_TO_CPU(values[mid + 1],
+									fs_le);
+			else
+				node_pointer = FS64_TO_CPU(values[mid], fs_le);
+		}
+	} while ((int64_t) FS64_TO_CPU(bn->overflow_link, fs_le)
+						!= BPLUSTREE_NULL);
+	return 0;
+}
+
+static int get_uuid(blkid_probe pr, const struct befs_super_block *bs,
+					uint64_t * const uuid, int fs_le)
+{
+	struct befs_inode *bi;
+	struct small_data *sd;
+
+	bi = (struct befs_inode *) get_block_run(pr, bs, &bs->root_dir, fs_le);
+	if (!bi)
+		return errno ? -errno : BLKID_PROBE_NONE;
+
+	if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
+		return BLKID_PROBE_NONE;
+
+	sd = (struct small_data *) bi->small_data;
+
+	do {
+		if (FS32_TO_CPU(sd->type, fs_le) == B_UINT64_TYPE
+			&& FS16_TO_CPU(sd->name_size, fs_le) == strlen(KEY_NAME)
+			&& FS16_TO_CPU(sd->data_size, fs_le) == KEY_SIZE
+			&& strcmp(sd->name, KEY_NAME) == 0) {
+
+			memcpy(uuid,
+			       sd->name + FS16_TO_CPU(sd->name_size, fs_le) + 3,
+			       sizeof(uint64_t));
+
+			break;
+		} else if (FS32_TO_CPU(sd->type, fs_le) == 0
+				&& FS16_TO_CPU(sd->name_size, fs_le) == 0
+				&& FS16_TO_CPU(sd->data_size, fs_le) == 0)
+			break;
+
+		sd = (struct small_data *) ((uint8_t *) sd
+				+ sizeof(struct small_data)
+				+ FS16_TO_CPU(sd->name_size, fs_le) + 3
+				+ FS16_TO_CPU(sd->data_size, fs_le) + 1);
+
+	} while ((intptr_t) sd < (intptr_t) bi
+				+ (int32_t) FS32_TO_CPU(bi->inode_size, fs_le)
+				- (int32_t) sizeof(struct small_data));
+	if (*uuid == 0
+		&& (FS32_TO_CPU(bi->attributes.allocation_group, fs_le) != 0
+			|| FS16_TO_CPU(bi->attributes.start, fs_le) != 0
+			|| FS16_TO_CPU(bi->attributes.len, fs_le) != 0)) {
+		int64_t value;
+
+		bi = (struct befs_inode *) get_block_run(pr, bs,
+							&bi->attributes, fs_le);
+		if (!bi)
+			return errno ? -errno : BLKID_PROBE_NONE;
+
+		if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
+			return BLKID_PROBE_NONE;
+
+		value = get_key_value(pr, bs, bi, KEY_NAME, fs_le);
+		if (value < 0)
+			return value == -ENOENT ? BLKID_PROBE_NONE : value;
+
+		else if (value > 0) {
+			bi = (struct befs_inode *) blkid_probe_get_buffer(pr,
+				value << FS32_TO_CPU(bs->block_shift, fs_le),
+				FS32_TO_CPU(bs->block_size, fs_le));
+			if (!bi)
+				return errno ? -errno : BLKID_PROBE_NONE;
+
+			if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1)
+				return 1;
+
+			if (FS32_TO_CPU(bi->type, fs_le) == B_UINT64_TYPE
+				&& FS64_TO_CPU(bi->data.size, fs_le) == KEY_SIZE
+				&& FS16_TO_CPU(bi->data.direct[0].len, fs_le)
+									== 1) {
+				uint64_t *attr_data;
+
+				attr_data = (uint64_t *) get_block_run(pr, bs,
+						&bi->data.direct[0], fs_le);
+				if (!attr_data)
+					return errno ? -errno : BLKID_PROBE_NONE;
+
+				*uuid = *attr_data;
+			}
+		}
+	}
+	return 0;
+}
+
+static int probe_befs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct befs_super_block *bs;
+	const char *version = NULL;
+	uint64_t volume_id = 0;
+	int fs_le, ret;
+
+	bs = (struct befs_super_block *) blkid_probe_get_buffer(pr,
+					mag->sboff - B_OS_NAME_LENGTH,
+					sizeof(struct befs_super_block));
+	if (!bs)
+		return errno ? -errno : BLKID_PROBE_NONE;
+
+	if (le32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1
+		&& le32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2
+		&& le32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3
+		&& le32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) {
+		fs_le = 1;
+		version = "little-endian";
+	} else if (be32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1
+		&& be32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2
+		&& be32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3
+		&& be32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) {
+		fs_le = 0;
+		version = "big-endian";
+	} else
+		return BLKID_PROBE_NONE;
+
+	ret = get_uuid(pr, bs, &volume_id, fs_le);
+
+	if (ret != 0)
+		return ret;
+
+	/*
+	 * all checks pass, set LABEL, VERSION and UUID
+	 */
+	if (strlen(bs->name))
+		blkid_probe_set_label(pr, (unsigned char *) bs->name,
+							sizeof(bs->name));
+	if (version)
+		blkid_probe_set_version(pr, version);
+
+	if (volume_id)
+		blkid_probe_sprintf_uuid(pr, (unsigned char *) &volume_id,
+					sizeof(volume_id), "%016" PRIx64,
+					FS64_TO_CPU(volume_id, fs_le));
+	return BLKID_PROBE_OK;
+}
+
+const struct blkid_idinfo befs_idinfo =
+{
+	.name		= "befs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_befs,
+	.minsz		= 1024 * 1440,
+	.magics		= {
+		{ .magic = "BFS1", .len = 4, .sboff = B_OS_NAME_LENGTH },
+		{ .magic = "1SFB", .len = 4, .sboff = B_OS_NAME_LENGTH },
+		{ .magic = "BFS1", .len = 4, .sboff = 0x200 +
+							B_OS_NAME_LENGTH },
+		{ .magic = "1SFB", .len = 4, .sboff = 0x200 +
+							B_OS_NAME_LENGTH },
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/bfs.c b/libblkid/src/superblocks/bfs.c
new file mode 100644
index 0000000..8a34c58
--- /dev/null
+++ b/libblkid/src/superblocks/bfs.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include "superblocks.h"
+
+/*
+ * BFS actually has two different labels in the superblock, each
+ * of them only 6 bytes long.  Until we find out what their use
+ * we just ignore them.
+ */
+const struct blkid_idinfo bfs_idinfo =
+{
+	.name		= "bfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.magics		= {
+		{ .magic = "\xce\xfa\xad\x1b", .len = 4 },
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/btrfs.c b/libblkid/src/superblocks/btrfs.c
new file mode 100644
index 0000000..7ce3dff
--- /dev/null
+++ b/libblkid/src/superblocks/btrfs.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct btrfs_super_block {
+	uint8_t csum[32];
+	uint8_t fsid[16];
+	uint64_t bytenr;
+	uint64_t flags;
+	uint8_t magic[8];
+	uint64_t generation;
+	uint64_t root;
+	uint64_t chunk_root;
+	uint64_t log_root;
+	uint64_t log_root_transid;
+	uint64_t total_bytes;
+	uint64_t bytes_used;
+	uint64_t root_dir_objectid;
+	uint64_t num_devices;
+	uint32_t sectorsize;
+	uint32_t nodesize;
+	uint32_t leafsize;
+	uint32_t stripesize;
+	uint32_t sys_chunk_array_size;
+	uint64_t chunk_root_generation;
+	uint64_t compat_flags;
+	uint64_t compat_ro_flags;
+	uint64_t incompat_flags;
+	uint16_t csum_type;
+	uint8_t root_level;
+	uint8_t chunk_root_level;
+	uint8_t log_root_level;
+	struct btrfs_dev_item {
+		uint64_t devid;
+		uint64_t total_bytes;
+		uint64_t bytes_used;
+		uint32_t io_align;
+		uint32_t io_width;
+		uint32_t sector_size;
+		uint64_t type;
+		uint64_t generation;
+		uint64_t start_offset;
+		uint32_t dev_group;
+		uint8_t seek_speed;
+		uint8_t bandwidth;
+		uint8_t uuid[16];
+		uint8_t fsid[16];
+	} __attribute__ ((__packed__)) dev_item;
+	uint8_t label[256];
+} __attribute__ ((__packed__));
+
+static int probe_btrfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct btrfs_super_block *bfs;
+
+	bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block);
+	if (!bfs)
+		return errno ? -errno : 1;
+
+	if (*bfs->label)
+		blkid_probe_set_label(pr,
+				(unsigned char *) bfs->label,
+				sizeof(bfs->label));
+
+	blkid_probe_set_uuid(pr, bfs->fsid);
+	blkid_probe_set_uuid_as(pr, bfs->dev_item.uuid, "UUID_SUB");
+
+	return 0;
+}
+
+const struct blkid_idinfo btrfs_idinfo =
+{
+	.name		= "btrfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_btrfs,
+	.minsz		= 1024 * 1024,
+	.magics		=
+	{
+	  { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 },
+	  { NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/cramfs.c b/libblkid/src/superblocks/cramfs.c
new file mode 100644
index 0000000..6d01b0b
--- /dev/null
+++ b/libblkid/src/superblocks/cramfs.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct cramfs_super
+{
+	uint8_t		magic[4];
+	uint32_t	size;
+	uint32_t	flags;
+	uint32_t	future;
+	uint8_t		signature[16];
+	struct cramfs_info
+	{
+		uint32_t	crc;
+		uint32_t	edition;
+		uint32_t	blocks;
+		uint32_t	files;
+	} __attribute__((packed)) info;
+	uint8_t		name[16];
+} __attribute__((packed));
+
+static int probe_cramfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct cramfs_super *cs;
+
+	cs = blkid_probe_get_sb(pr, mag, struct cramfs_super);
+	if (!cs)
+		return errno ? -errno : 1;
+
+	blkid_probe_set_label(pr, cs->name, sizeof(cs->name));
+	return 0;
+}
+
+const struct blkid_idinfo cramfs_idinfo =
+{
+	.name		= "cramfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_cramfs,
+	.magics		=
+	{
+		{ "\x45\x3d\xcd\x28", 4, 0, 0 },
+		{ "\x28\xcd\x3d\x45", 4, 0, 0 },
+		{ NULL }
+	}
+};
+
+
diff --git a/libblkid/src/superblocks/ddf_raid.c b/libblkid/src/superblocks/ddf_raid.c
new file mode 100644
index 0000000..fc2c39d
--- /dev/null
+++ b/libblkid/src/superblocks/ddf_raid.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+/* http://www.snia.org/standards/home */
+#define DDF_GUID_LENGTH			24
+#define DDF_REV_LENGTH			8
+#define DDF_MAGIC			0xDE11DE11
+
+
+struct ddf_header {
+	uint32_t	signature;
+	uint32_t	crc;
+	uint8_t		guid[DDF_GUID_LENGTH];
+	char		ddf_rev[8];	/* 01.02.00 */
+	uint32_t	seq;		/* starts at '1' */
+	uint32_t	timestamp;
+	uint8_t		openflag;
+	uint8_t		foreignflag;
+	uint8_t		enforcegroups;
+	uint8_t		pad0;		/* 0xff */
+	uint8_t		pad1[12];	/* 12 * 0xff */
+	/* 64 bytes so far */
+	uint8_t		header_ext[32];	/* reserved: fill with 0xff */
+	uint64_t	primary_lba;
+	uint64_t	secondary_lba;
+	uint8_t		type;
+	uint8_t		pad2[3];	/* 0xff */
+	uint32_t	workspace_len;	/* sectors for vendor space -
+					 * at least 32768(sectors) */
+	uint64_t	workspace_lba;
+	uint16_t	max_pd_entries;	/* one of 15, 63, 255, 1023, 4095 */
+	uint16_t	max_vd_entries; /* 2^(4,6,8,10,12)-1 : i.e. as above */
+	uint16_t	max_partitions; /* i.e. max num of configuration
+					   record entries per disk */
+	uint16_t	config_record_len; /* 1 +ROUNDUP(max_primary_element_entries
+				           *12/512) */
+	uint16_t	max_primary_element_entries; /* 16, 64, 256, 1024, or 4096 */
+	uint8_t		pad3[54];	/* 0xff */
+	/* 192 bytes so far */
+	uint32_t	controller_section_offset;
+	uint32_t	controller_section_length;
+	uint32_t	phys_section_offset;
+	uint32_t	phys_section_length;
+	uint32_t	virt_section_offset;
+	uint32_t	virt_section_length;
+	uint32_t	config_section_offset;
+	uint32_t	config_section_length;
+	uint32_t	data_section_offset;
+	uint32_t	data_section_length;
+	uint32_t	bbm_section_offset;
+	uint32_t	bbm_section_length;
+	uint32_t	diag_space_offset;
+	uint32_t	diag_space_length;
+	uint32_t	vendor_offset;
+	uint32_t	vendor_length;
+	/* 256 bytes so far */
+	uint8_t		pad4[256];	/* 0xff */
+} __attribute__((packed));
+
+static int probe_ddf(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	int hdrs[] = { 1, 257 };
+	size_t i;
+	struct ddf_header *ddf = NULL;
+	char version[DDF_REV_LENGTH + 1];
+	uint64_t off, lba;
+
+	if (pr->size < 0x30000)
+		return 1;
+
+	for (i = 0; i < ARRAY_SIZE(hdrs); i++) {
+		off = ((pr->size / 0x200) - hdrs[i]) * 0x200;
+
+		ddf = (struct ddf_header *) blkid_probe_get_buffer(pr,
+					off,
+					sizeof(struct ddf_header));
+		if (!ddf)
+			return errno ? -errno : 1;
+		if (ddf->signature == cpu_to_be32(DDF_MAGIC) ||
+		    ddf->signature == cpu_to_le32(DDF_MAGIC))
+			break;
+		ddf = NULL;
+	}
+
+	if (!ddf)
+		return 1;
+
+	lba = ddf->signature == cpu_to_be32(DDF_MAGIC) ?
+			be64_to_cpu(ddf->primary_lba) :
+			le64_to_cpu(ddf->primary_lba);
+
+	if (lba > 0) {
+		/* check primary header */
+		unsigned char *buf;
+
+		buf = blkid_probe_get_buffer(pr,
+					lba << 9, sizeof(ddf->signature));
+		if (!buf)
+			return errno ? -errno : 1;
+
+		if (memcmp(buf, &ddf->signature, 4) != 0)
+			return 1;
+	}
+
+	blkid_probe_strncpy_uuid(pr, ddf->guid, sizeof(ddf->guid));
+
+	memcpy(version, ddf->ddf_rev, sizeof(ddf->ddf_rev));
+	*(version + sizeof(ddf->ddf_rev)) = '\0';
+
+	if (blkid_probe_set_version(pr, version) != 0)
+		return 1;
+	if (blkid_probe_set_magic(pr, off,
+			sizeof(ddf->signature),
+			(unsigned char *) &ddf->signature))
+		return 1;
+	return 0;
+}
+
+const struct blkid_idinfo ddfraid_idinfo = {
+	.name		= "ddf_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_ddf,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/drbd.c b/libblkid/src/superblocks/drbd.c
new file mode 100644
index 0000000..e88e9f3
--- /dev/null
+++ b/libblkid/src/superblocks/drbd.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2009 by Bastian Friedrich <bastian.friedrich@collax.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * defines, structs taken from drbd source; file names represent drbd source
+ * files.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <stddef.h>
+
+#include "superblocks.h"
+
+/*
+ * drbd/linux/drbd.h
+ */
+#define DRBD_MAGIC 0x83740267
+
+/*
+ * user/drbdmeta.c
+ * We only support v08 for now
+ */
+#define DRBD_MD_MAGIC_08         (DRBD_MAGIC+4)
+#define DRBD_MD_MAGIC_84_UNCLEAN (DRBD_MAGIC+5)
+
+/*
+ * drbd/linux/drbd.h
+ */
+enum drbd_uuid_index {
+	UI_CURRENT,
+	UI_BITMAP,
+	UI_HISTORY_START,
+	UI_HISTORY_END,
+	UI_SIZE,		/* nl-packet: number of dirty bits */
+	UI_FLAGS,		/* nl-packet: flags */
+	UI_EXTENDED_SIZE	/* Everything. */
+};
+
+/*
+ * user/drbdmeta.c
+ * Minor modifications wrt. types
+ */
+struct md_on_disk_08 {
+	uint64_t la_sect;         /* last agreed size. */
+	uint64_t uuid[UI_SIZE];   /* UUIDs */
+	uint64_t device_uuid;
+	uint64_t reserved_u64_1;
+	uint32_t flags;
+	uint32_t magic;
+	uint32_t md_size_sect;
+	int32_t  al_offset;       /* signed sector offset to this block */
+	uint32_t al_nr_extents;   /* important for restoring the AL */
+	int32_t  bm_offset;       /* signed sector offset to the bitmap, from here */
+	uint32_t bm_bytes_per_bit;
+	uint32_t reserved_u32[4];
+
+	char reserved[8 * 512 - (8*(UI_SIZE+3)+4*11)];
+};
+
+
+static int probe_drbd(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct md_on_disk_08 *md;
+	off_t off;
+
+	off = pr->size - sizeof(*md);
+
+	/* Small devices cannot be drbd (?) */
+	if (pr->size < 0x10000)
+		return 1;
+
+	md = (struct md_on_disk_08 *)
+			blkid_probe_get_buffer(pr,
+					off,
+					sizeof(struct md_on_disk_08));
+	if (!md)
+		return errno ? -errno : 1;
+
+	if (be32_to_cpu(md->magic) != DRBD_MD_MAGIC_08 &&
+			be32_to_cpu(md->magic) != DRBD_MD_MAGIC_84_UNCLEAN)
+		return 1;
+
+	/*
+	 * DRBD does not have "real" uuids; the following resembles DRBD's
+	 * notion of uuids (64 bit, see struct above)
+	 */
+	blkid_probe_sprintf_uuid(pr,
+		(unsigned char *) &md->device_uuid, sizeof(md->device_uuid),
+		"%" PRIx64, be64_to_cpu(md->device_uuid));
+
+	blkid_probe_set_version(pr, "v08");
+
+	if (blkid_probe_set_magic(pr,
+				off + offsetof(struct md_on_disk_08, magic),
+				sizeof(md->magic),
+				(unsigned char *) &md->magic))
+		return 1;
+
+	return 0;
+}
+
+const struct blkid_idinfo drbd_idinfo =
+{
+	.name		= "drbd",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_drbd,
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/superblocks/drbdproxy_datalog.c b/libblkid/src/superblocks/drbdproxy_datalog.c
new file mode 100644
index 0000000..af59722
--- /dev/null
+++ b/libblkid/src/superblocks/drbdproxy_datalog.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 by Philipp Marek <philipp.marek@linbit.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <stddef.h>
+
+#include "superblocks.h"
+
+
+struct log_header_t {
+	uint64_t magic;
+	uint64_t version;
+
+	unsigned char uuid[16];
+
+	uint64_t flags;
+} __attribute__((packed));
+
+
+static int probe_drbdproxy_datalog(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct log_header_t *lh;
+
+	lh = (struct log_header_t *) blkid_probe_get_buffer(pr, 0, sizeof(*lh));
+	if (!lh)
+		return errno ? -errno : 1;
+
+	blkid_probe_set_uuid(pr, lh->uuid);
+	blkid_probe_sprintf_version(pr, "v%jd", le64_to_cpu(lh->version));
+
+	return 0;
+}
+
+const struct blkid_idinfo drbdproxy_datalog_idinfo =
+{
+	.name		= "drbdproxy_datalog",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_drbdproxy_datalog,
+	.minsz		= 16*1024,
+	.magics		=
+	{
+		{ .magic = "DRBDdlh*", .len = 8, .sboff = 0, .kboff = 0 },
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/exfat.c b/libblkid/src/superblocks/exfat.c
new file mode 100644
index 0000000..b526560
--- /dev/null
+++ b/libblkid/src/superblocks/exfat.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2010 Andrew Nayenko <resver@gmail.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include "superblocks.h"
+
+struct exfat_super_block {
+	uint8_t jump[3];
+	uint8_t oem_name[8];
+	uint8_t	__unused1[53];
+	uint64_t block_start;
+	uint64_t block_count;
+	uint32_t fat_block_start;
+	uint32_t fat_block_count;
+	uint32_t cluster_block_start;
+	uint32_t cluster_count;
+	uint32_t rootdir_cluster;
+	uint8_t volume_serial[4];
+	struct {
+		uint8_t minor;
+		uint8_t major;
+	} version;
+	uint16_t volume_state;
+	uint8_t block_bits;
+	uint8_t bpc_bits;
+	uint8_t fat_count;
+	uint8_t drive_no;
+	uint8_t allocated_percent;
+} __attribute__((__packed__));
+
+struct exfat_entry_label {
+	uint8_t type;
+	uint8_t length;
+	uint8_t name[30];
+} __attribute__((__packed__));
+
+#define BLOCK_SIZE(sb) (1 << (sb)->block_bits)
+#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb)->bpc_bits)
+#define EXFAT_FIRST_DATA_CLUSTER 2
+#define EXFAT_LAST_DATA_CLUSTER 0xffffff6
+#define EXFAT_ENTRY_SIZE 32
+
+#define EXFAT_ENTRY_EOD		0x00
+#define EXFAT_ENTRY_LABEL	0x83
+
+static blkid_loff_t block_to_offset(const struct exfat_super_block *sb,
+		blkid_loff_t block)
+{
+	return (blkid_loff_t) block << sb->block_bits;
+}
+
+static blkid_loff_t cluster_to_block(const struct exfat_super_block *sb,
+		uint32_t cluster)
+{
+	return le32_to_cpu(sb->cluster_block_start) +
+			((blkid_loff_t) (cluster - EXFAT_FIRST_DATA_CLUSTER)
+					<< sb->bpc_bits);
+}
+
+static blkid_loff_t cluster_to_offset(const struct exfat_super_block *sb,
+		uint32_t cluster)
+{
+	return block_to_offset(sb, cluster_to_block(sb, cluster));
+}
+
+static uint32_t next_cluster(blkid_probe pr,
+		const struct exfat_super_block *sb, uint32_t cluster)
+{
+	uint32_t *next;
+	blkid_loff_t fat_offset;
+
+	fat_offset = block_to_offset(sb, le32_to_cpu(sb->fat_block_start))
+		+ (blkid_loff_t) cluster * sizeof(cluster);
+	next = (uint32_t *) blkid_probe_get_buffer(pr, fat_offset,
+			sizeof(uint32_t));
+	if (!next)
+		return 0;
+	return le32_to_cpu(*next);
+}
+
+static struct exfat_entry_label *find_label(blkid_probe pr,
+		const struct exfat_super_block *sb)
+{
+	uint32_t cluster = le32_to_cpu(sb->rootdir_cluster);
+	blkid_loff_t offset = cluster_to_offset(sb, cluster);
+	uint8_t *entry;
+
+	for (;;) {
+		entry = (uint8_t *) blkid_probe_get_buffer(pr, offset,
+				EXFAT_ENTRY_SIZE);
+		if (!entry)
+			return NULL;
+		if (entry[0] == EXFAT_ENTRY_EOD)
+			return NULL;
+		if (entry[0] == EXFAT_ENTRY_LABEL)
+			return (struct exfat_entry_label *) entry;
+		offset += EXFAT_ENTRY_SIZE;
+		if (offset % CLUSTER_SIZE(sb) == 0) {
+			cluster = next_cluster(pr, sb, cluster);
+			if (cluster < EXFAT_FIRST_DATA_CLUSTER)
+				return NULL;
+			if (cluster > EXFAT_LAST_DATA_CLUSTER)
+				return NULL;
+			offset = cluster_to_offset(sb, cluster);
+		}
+	}
+}
+
+static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct exfat_super_block *sb;
+	struct exfat_entry_label *label;
+
+	sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block);
+	if (!sb)
+		return errno ? -errno : BLKID_PROBE_NONE;
+
+	label = find_label(pr, sb);
+	if (label)
+		blkid_probe_set_utf8label(pr, label->name,
+				min(label->length * 2, 30), BLKID_ENC_UTF16LE);
+	else if (errno)
+		return -errno;
+
+	blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4,
+			"%02hhX%02hhX-%02hhX%02hhX",
+			sb->volume_serial[3], sb->volume_serial[2],
+			sb->volume_serial[1], sb->volume_serial[0]);
+
+	blkid_probe_sprintf_version(pr, "%u.%u",
+			sb->version.major, sb->version.minor);
+
+	return BLKID_PROBE_OK;
+}
+
+const struct blkid_idinfo exfat_idinfo =
+{
+	.name		= "exfat",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_exfat,
+	.magics		=
+	{
+		{ .magic = "EXFAT   ", .len = 8, .sboff = 3 },
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/ext.c b/libblkid/src/superblocks/ext.c
new file mode 100644
index 0000000..5b1d179
--- /dev/null
+++ b/libblkid/src/superblocks/ext.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 1999, 2001 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+#include <time.h>
+
+#include "superblocks.h"
+
+struct ext2_super_block {
+	uint32_t		s_inodes_count;
+	uint32_t		s_blocks_count;
+	uint32_t		s_r_blocks_count;
+	uint32_t		s_free_blocks_count;
+	uint32_t		s_free_inodes_count;
+	uint32_t		s_first_data_block;
+	uint32_t		s_log_block_size;
+	uint32_t		s_dummy3[7];
+	unsigned char		s_magic[2];
+	uint16_t		s_state;
+	uint16_t		s_errors;
+	uint16_t		s_minor_rev_level;
+	uint32_t		s_lastcheck;
+	uint32_t		s_checkinterval;
+	uint32_t		s_creator_os;
+	uint32_t		s_rev_level;
+	uint16_t		s_def_resuid;
+	uint16_t		s_def_resgid;
+	uint32_t		s_first_ino;
+	uint16_t		s_inode_size;
+	uint16_t		s_block_group_nr;
+	uint32_t		s_feature_compat;
+	uint32_t		s_feature_incompat;
+	uint32_t		s_feature_ro_compat;
+	unsigned char		s_uuid[16];
+	char			s_volume_name[16];
+	char			s_last_mounted[64];
+	uint32_t		s_algorithm_usage_bitmap;
+	uint8_t			s_prealloc_blocks;
+	uint8_t			s_prealloc_dir_blocks;
+	uint16_t		s_reserved_gdt_blocks;
+	uint8_t			s_journal_uuid[16];
+	uint32_t		s_journal_inum;
+	uint32_t		s_journal_dev;
+	uint32_t		s_last_orphan;
+	uint32_t		s_hash_seed[4];
+	uint8_t			s_def_hash_version;
+	uint8_t			s_jnl_backup_type;
+	uint16_t		s_reserved_word_pad;
+	uint32_t		s_default_mount_opts;
+	uint32_t		s_first_meta_bg;
+	uint32_t		s_mkfs_time;
+	uint32_t		s_jnl_blocks[17];
+	uint32_t		s_blocks_count_hi;
+	uint32_t		s_r_blocks_count_hi;
+	uint32_t		s_free_blocks_hi;
+	uint16_t		s_min_extra_isize;
+	uint16_t		s_want_extra_isize;
+	uint32_t		s_flags;
+	uint16_t		s_raid_stride;
+	uint16_t		s_mmp_interval;
+	uint64_t		s_mmp_block;
+	uint32_t		s_raid_stripe_width;
+	uint32_t		s_reserved[163];
+} __attribute__((packed));
+
+/* magic string */
+#define EXT_SB_MAGIC				"\123\357"
+/* supper block offset */
+#define EXT_SB_OFF				0x400
+/* supper block offset in kB */
+#define EXT_SB_KBOFF				(EXT_SB_OFF >> 10)
+/* magic string offset within super block */
+#define EXT_MAG_OFF				0x38
+
+
+
+/* for s_flags */
+#define EXT2_FLAGS_TEST_FILESYS		0x0004
+
+/* for s_feature_compat */
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004
+
+/* for s_feature_ro_compat */
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
+#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE	0x0008
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM		0x0010
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK	0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE	0x0040
+
+/* for s_feature_incompat */
+#define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG		0x0010
+#define EXT4_FEATURE_INCOMPAT_EXTENTS		0x0040 /* extents support */
+#define EXT4_FEATURE_INCOMPAT_64BIT		0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP		0x0100
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG		0x0200
+
+#define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+					 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+#define EXT2_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE| \
+					 EXT2_FEATURE_INCOMPAT_META_BG)
+#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED	~EXT2_FEATURE_INCOMPAT_SUPP
+#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED	~EXT2_FEATURE_RO_COMPAT_SUPP
+
+#define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+					 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+#define EXT3_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE| \
+					 EXT3_FEATURE_INCOMPAT_RECOVER| \
+					 EXT2_FEATURE_INCOMPAT_META_BG)
+#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED	~EXT3_FEATURE_INCOMPAT_SUPP
+#define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED	~EXT3_FEATURE_RO_COMPAT_SUPP
+
+/*
+ * Starting in 2.6.29, ext4 can be used to support filesystems
+ * without a journal.
+ */
+#define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29)
+
+/*
+ * reads superblock and returns:
+ *	fc = feature_compat
+ *	fi = feature_incompat
+ *	frc = feature_ro_compat
+ */
+static struct ext2_super_block *ext_get_super(
+		blkid_probe pr, uint32_t *fc, uint32_t *fi, uint32_t *frc)
+{
+	struct ext2_super_block *es;
+
+	es = (struct ext2_super_block *)
+			blkid_probe_get_buffer(pr, EXT_SB_OFF, 0x200);
+	if (!es)
+		return NULL;
+	if (fc)
+		*fc = le32_to_cpu(es->s_feature_compat);
+	if (fi)
+		*fi = le32_to_cpu(es->s_feature_incompat);
+	if (frc)
+		*frc = le32_to_cpu(es->s_feature_ro_compat);
+
+	return es;
+}
+
+static void ext_get_info(blkid_probe pr, int ver, struct ext2_super_block *es)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+	DBG(PROBE, ul_debug("ext2_sb.compat = %08X:%08X:%08X",
+		   le32_to_cpu(es->s_feature_compat),
+		   le32_to_cpu(es->s_feature_incompat),
+		   le32_to_cpu(es->s_feature_ro_compat)));
+
+	if (strlen(es->s_volume_name))
+		blkid_probe_set_label(pr, (unsigned char *) es->s_volume_name,
+					sizeof(es->s_volume_name));
+	blkid_probe_set_uuid(pr, es->s_uuid);
+
+	if (le32_to_cpu(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
+		blkid_probe_set_uuid_as(pr, es->s_journal_uuid, "EXT_JOURNAL");
+
+	if (ver != 2 && (chn->flags & BLKID_SUBLKS_SECTYPE) &&
+	    ((le32_to_cpu(es->s_feature_incompat) & EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0))
+		blkid_probe_set_value(pr, "SEC_TYPE",
+				(unsigned char *) "ext2",
+				sizeof("ext2"));
+
+	blkid_probe_sprintf_version(pr, "%u.%u",
+		le32_to_cpu(es->s_rev_level),
+		le16_to_cpu(es->s_minor_rev_level));
+}
+
+
+static int probe_jbd(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct ext2_super_block *es;
+	uint32_t fi;
+
+	es = ext_get_super(pr, NULL, &fi, NULL);
+	if (!es)
+		return errno ? -errno : 1;
+	if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
+		return 1;
+
+	ext_get_info(pr, 2, es);
+	blkid_probe_set_uuid_as(pr, es->s_uuid, "LOGUUID");
+
+	return 0;
+}
+
+static int probe_ext2(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct ext2_super_block *es;
+	uint32_t fc, frc, fi;
+
+	es = ext_get_super(pr, &fc, &fi, &frc);
+	if (!es)
+		return errno ? -errno : 1;
+
+	/* Distinguish between ext3 and ext2 */
+	if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
+		return 1;
+
+	/* Any features which ext2 doesn't understand */
+	if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
+	    (fi  & EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
+		return 1;
+
+	ext_get_info(pr, 2, es);
+	return 0;
+}
+
+static int probe_ext3(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct ext2_super_block *es;
+	uint32_t fc, frc, fi;
+
+	es = ext_get_super(pr, &fc, &fi, &frc);
+	if (!es)
+		return errno ? -errno : 1;
+
+	/* ext3 requires journal */
+	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+		return 1;
+
+	/* Any features which ext3 doesn't understand */
+	if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) ||
+	    (fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+		return 1;
+
+	ext_get_info(pr, 3, es);
+	return 0;
+}
+
+
+static int probe_ext4dev(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct ext2_super_block *es;
+	uint32_t fc, frc, fi;
+
+	es = ext_get_super(pr, &fc, &fi, &frc);
+	if (!es)
+		return errno ? -errno : 1;
+
+	/* Distinguish from jbd */
+	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+		return 1;
+
+	if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS))
+		return 1;
+
+	ext_get_info(pr, 4, es);
+	return 0;
+}
+
+static int probe_ext4(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct ext2_super_block *es;
+	uint32_t fc, frc, fi;
+
+	es = ext_get_super(pr, &fc, &fi, &frc);
+	if (!es)
+		return errno ? -errno : 1;
+
+	/* Distinguish from jbd */
+	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+		return 1;
+
+	/* Ext4 has at least one feature which ext3 doesn't understand */
+	if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
+	    !(fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+		return 1;
+
+	/*
+	 * If the filesystem is a OK for use by in-development
+	 * filesystem code, and ext4dev is supported or ext4 is not
+	 * supported, then don't call ourselves ext4, so we can redo
+	 * the detection and mark the filesystem as ext4dev.
+	 *
+	 * If the filesystem is marked as in use by production
+	 * filesystem, then it can only be used by ext4 and NOT by
+	 * ext4dev.
+	 */
+	if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)
+		return 1;
+
+	ext_get_info(pr, 4, es);
+	return 0;
+}
+
+#define BLKID_EXT_MAGICS \
+	{ \
+		{	 \
+			.magic = EXT_SB_MAGIC, \
+			.len = sizeof(EXT_SB_MAGIC) - 1, \
+			.kboff = EXT_SB_KBOFF, \
+			.sboff = EXT_MAG_OFF \
+		}, \
+		{ NULL } \
+	}
+
+const struct blkid_idinfo jbd_idinfo =
+{
+	.name		= "jbd",
+	.usage		= BLKID_USAGE_OTHER,
+	.probefunc	= probe_jbd,
+	.magics		= BLKID_EXT_MAGICS
+};
+
+const struct blkid_idinfo ext2_idinfo =
+{
+	.name		= "ext2",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_ext2,
+	.magics		= BLKID_EXT_MAGICS
+};
+
+const struct blkid_idinfo ext3_idinfo =
+{
+	.name		= "ext3",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_ext3,
+	.magics		= BLKID_EXT_MAGICS
+};
+
+const struct blkid_idinfo ext4_idinfo =
+{
+	.name		= "ext4",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_ext4,
+	.magics		= BLKID_EXT_MAGICS
+};
+
+const struct blkid_idinfo ext4dev_idinfo =
+{
+	.name		= "ext4dev",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_ext4dev,
+	.magics		= BLKID_EXT_MAGICS
+};
+
diff --git a/libblkid/src/superblocks/f2fs.c b/libblkid/src/superblocks/f2fs.c
new file mode 100644
index 0000000..2bf0f5e
--- /dev/null
+++ b/libblkid/src/superblocks/f2fs.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 Alejandro Martinez Ruiz <alex@nowcomputing.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "superblocks.h"
+
+#define F2FS_MAGIC		"\x10\x20\xF5\xF2"
+#define F2FS_MAGIC_OFF		0
+#define F2FS_UUID_SIZE		16
+#define F2FS_LABEL_SIZE		512
+#define F2FS_SB1_OFF		0x400
+#define F2FS_SB1_KBOFF		(F2FS_SB1_OFF >> 10)
+#define F2FS_SB2_OFF		0x1400
+#define F2FS_SB2_KBOFF		(F2FS_SB2_OFF >> 10)
+
+struct f2fs_super_block {					/* According to version 1.1 */
+/* 0x00 */	uint32_t	magic;				/* Magic Number */
+/* 0x04 */	uint16_t	major_ver;			/* Major Version */
+/* 0x06 */	uint16_t	minor_ver;			/* Minor Version */
+/* 0x08 */	uint32_t	log_sectorsize;			/* log2 sector size in bytes */
+/* 0x0C */	uint32_t	log_sectors_per_block;		/* log2 # of sectors per block */
+/* 0x10 */	uint32_t	log_blocksize;			/* log2 block size in bytes */
+/* 0x14 */	uint32_t	log_blocks_per_seg;		/* log2 # of blocks per segment */
+/* 0x18 */	uint32_t	segs_per_sec;			/* # of segments per section */
+/* 0x1C */	uint32_t	secs_per_zone;			/* # of sections per zone */
+/* 0x20 */	uint32_t	checksum_offset;		/* checksum offset inside super block */
+/* 0x24 */	uint64_t	block_count;			/* total # of user blocks */
+/* 0x2C */	uint32_t	section_count;			/* total # of sections */
+/* 0x30 */	uint32_t	segment_count;			/* total # of segments */
+/* 0x34 */	uint32_t	segment_count_ckpt;		/* # of segments for checkpoint */
+/* 0x38 */	uint32_t	segment_count_sit;		/* # of segments for SIT */
+/* 0x3C */	uint32_t	segment_count_nat;		/* # of segments for NAT */
+/* 0x40 */	uint32_t	segment_count_ssa;		/* # of segments for SSA */
+/* 0x44 */	uint32_t	segment_count_main;		/* # of segments for main area */
+/* 0x48 */	uint32_t	segment0_blkaddr;		/* start block address of segment 0 */
+/* 0x4C */	uint32_t	cp_blkaddr;			/* start block address of checkpoint */
+/* 0x50 */	uint32_t	sit_blkaddr;			/* start block address of SIT */
+/* 0x54 */	uint32_t	nat_blkaddr;			/* start block address of NAT */
+/* 0x58 */	uint32_t	ssa_blkaddr;			/* start block address of SSA */
+/* 0x5C */	uint32_t	main_blkaddr;			/* start block address of main area */
+/* 0x60 */	uint32_t	root_ino;			/* root inode number */
+/* 0x64 */	uint32_t	node_ino;			/* node inode number */
+/* 0x68 */	uint32_t	meta_ino;			/* meta inode number */
+/* 0x6C */	uint8_t		uuid[F2FS_UUID_SIZE];		/* 128-bit uuid for volume */
+/* 0x7C */	uint16_t	volume_name[F2FS_LABEL_SIZE];	/* volume name */
+#if 0
+/* 0x47C */	uint32_t	extension_count;		/* # of extensions below */
+/* 0x480 */	uint8_t		extension_list[64][8];		/* extension array */
+#endif
+} __attribute__((packed));
+
+static int probe_f2fs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct f2fs_super_block *sb;
+	uint16_t major, minor;
+
+	sb = blkid_probe_get_sb(pr, mag, struct f2fs_super_block);
+	if (!sb)
+		return errno ? -errno : 1;
+
+	major = le16_to_cpu(sb->major_ver);
+	minor = le16_to_cpu(sb->minor_ver);
+
+	/* For version 1.0 we cannot know the correct sb structure */
+	if (major == 1 && minor == 0)
+		return 0;
+
+	if (*((unsigned char *) sb->volume_name))
+		blkid_probe_set_utf8label(pr, (unsigned char *) sb->volume_name,
+						sizeof(sb->volume_name),
+						BLKID_ENC_UTF16LE);
+
+	blkid_probe_set_uuid(pr, sb->uuid);
+	blkid_probe_sprintf_version(pr, "%u.%u", major, minor);
+	return 0;
+}
+
+const struct blkid_idinfo f2fs_idinfo =
+{
+	.name           = "f2fs",
+	.usage          = BLKID_USAGE_FILESYSTEM,
+	.probefunc      = probe_f2fs,
+	.magics         =
+        {
+		{
+			.magic = F2FS_MAGIC,
+			.len = 4,
+			.kboff = F2FS_SB1_KBOFF,
+			.sboff = F2FS_MAGIC_OFF
+		},
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/gfs.c b/libblkid/src/superblocks/gfs.c
new file mode 100644
index 0000000..1b26558
--- /dev/null
+++ b/libblkid/src/superblocks/gfs.c
@@ -0,0 +1,131 @@
+/*
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+/* Common gfs/gfs2 constants: */
+#define GFS_LOCKNAME_LEN        64
+
+/* gfs1 constants: */
+#define GFS_FORMAT_FS           1309
+#define GFS_FORMAT_MULTI        1401
+/* gfs2 constants: */
+#define GFS2_FORMAT_FS          1801
+#define GFS2_FORMAT_MULTI       1900
+
+struct gfs2_meta_header {
+	uint32_t mh_magic;
+	uint32_t mh_type;
+	uint64_t __pad0;          /* Was generation number in gfs1 */
+	uint32_t mh_format;
+	uint32_t __pad1;          /* Was incarnation number in gfs1 */
+};
+
+struct gfs2_inum {
+	uint64_t no_formal_ino;
+	uint64_t no_addr;
+};
+
+struct gfs2_sb {
+	struct gfs2_meta_header sb_header;
+
+	uint32_t sb_fs_format;
+	uint32_t sb_multihost_format;
+	uint32_t  __pad0;  /* Was superblock flags in gfs1 */
+
+	uint32_t sb_bsize;
+	uint32_t sb_bsize_shift;
+	uint32_t __pad1;   /* Was journal segment size in gfs1 */
+
+	struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */
+	struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */
+	struct gfs2_inum sb_root_dir;
+
+	char sb_lockproto[GFS_LOCKNAME_LEN];
+	char sb_locktable[GFS_LOCKNAME_LEN];
+
+	struct gfs2_inum __pad3; /* Was quota inode in gfs1 */
+	struct gfs2_inum __pad4; /* Was licence inode in gfs1 */
+	uint8_t sb_uuid[16]; /* The UUID maybe 0 for backwards compat */
+} __attribute__((packed));
+
+static int probe_gfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct gfs2_sb *sbd;
+
+	sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb);
+	if (!sbd)
+		return errno ? -errno : 1;
+
+	if (be32_to_cpu(sbd->sb_fs_format) == GFS_FORMAT_FS &&
+	    be32_to_cpu(sbd->sb_multihost_format) == GFS_FORMAT_MULTI)
+	{
+		if (*sbd->sb_locktable)
+			blkid_probe_set_label(pr,
+				(unsigned char *) sbd->sb_locktable,
+				sizeof(sbd->sb_locktable));
+
+		blkid_probe_set_uuid(pr, sbd->sb_uuid);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct gfs2_sb *sbd;
+
+	sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb);
+	if (!sbd)
+		return errno ? -errno : 1;
+
+	if (be32_to_cpu(sbd->sb_fs_format) == GFS2_FORMAT_FS &&
+	    be32_to_cpu(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI)
+	{
+		if (*sbd->sb_locktable)
+			blkid_probe_set_label(pr,
+				(unsigned char *) sbd->sb_locktable,
+				sizeof(sbd->sb_locktable));
+		blkid_probe_set_uuid(pr, sbd->sb_uuid);
+		blkid_probe_set_version(pr, "1");
+		return 0;
+	}
+	return 1;
+}
+
+const struct blkid_idinfo gfs_idinfo =
+{
+	.name		= "gfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_gfs,
+	.minsz		= 32 * 1024 * 1024,	/* minimal size of GFS journal */
+	.magics		=
+	{
+		{ .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo gfs2_idinfo =
+{
+	.name		= "gfs2",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_gfs2,
+	.minsz		= 32 * 1024 * 1024,	/* minimal size of GFS journal */
+	.magics		=
+	{
+		{ .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/hfs.c b/libblkid/src/superblocks/hfs.c
new file mode 100644
index 0000000..fe57241
--- /dev/null
+++ b/libblkid/src/superblocks/hfs.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "superblocks.h"
+#include "md5.h"
+
+/* HFS / HFS+ */
+struct hfs_finder_info {
+        uint32_t        boot_folder;
+        uint32_t        start_app;
+        uint32_t        open_folder;
+        uint32_t        os9_folder;
+        uint32_t        reserved;
+        uint32_t        osx_folder;
+        uint8_t         id[8];
+} __attribute__((packed));
+
+struct hfs_mdb {
+        uint8_t         signature[2];
+        uint32_t        cr_date;
+        uint32_t        ls_Mod;
+        uint16_t        atrb;
+        uint16_t        nm_fls;
+        uint16_t        vbm_st;
+        uint16_t        alloc_ptr;
+        uint16_t        nm_al_blks;
+        uint32_t        al_blk_size;
+        uint32_t        clp_size;
+        uint16_t        al_bl_st;
+        uint32_t        nxt_cnid;
+        uint16_t        free_bks;
+        uint8_t         label_len;
+        uint8_t         label[27];
+        uint32_t        vol_bkup;
+        uint16_t        vol_seq_num;
+        uint32_t        wr_cnt;
+        uint32_t        xt_clump_size;
+        uint32_t        ct_clump_size;
+        uint16_t        num_root_dirs;
+        uint32_t        file_count;
+        uint32_t        dir_count;
+        struct hfs_finder_info finder_info;
+        uint8_t         embed_sig[2];
+        uint16_t        embed_startblock;
+        uint16_t        embed_blockcount;
+} __attribute__((packed));
+
+
+#define HFS_NODE_LEAF			0xff
+#define HFSPLUS_POR_CNID		1
+
+struct hfsplus_bnode_descriptor {
+	uint32_t		next;
+	uint32_t		prev;
+	uint8_t		type;
+	uint8_t		height;
+	uint16_t		num_recs;
+	uint16_t		reserved;
+} __attribute__((packed));
+
+struct hfsplus_bheader_record {
+	uint16_t		depth;
+	uint32_t		root;
+	uint32_t		leaf_count;
+	uint32_t		leaf_head;
+	uint32_t		leaf_tail;
+	uint16_t		node_size;
+} __attribute__((packed));
+
+struct hfsplus_catalog_key {
+	uint16_t	key_len;
+	uint32_t	parent_id;
+	uint16_t	unicode_len;
+	uint8_t		unicode[255 * 2];
+} __attribute__((packed));
+
+struct hfsplus_extent {
+	uint32_t		start_block;
+	uint32_t		block_count;
+} __attribute__((packed));
+
+#define HFSPLUS_EXTENT_COUNT		8
+struct hfsplus_fork {
+	uint64_t		total_size;
+	uint32_t		clump_size;
+	uint32_t		total_blocks;
+	struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+} __attribute__((packed));
+
+struct hfsplus_vol_header {
+	uint8_t		signature[2];
+	uint16_t		version;
+	uint32_t		attributes;
+	uint32_t		last_mount_vers;
+	uint32_t		reserved;
+	uint32_t		create_date;
+	uint32_t		modify_date;
+	uint32_t		backup_date;
+	uint32_t		checked_date;
+	uint32_t		file_count;
+	uint32_t		folder_count;
+	uint32_t		blocksize;
+	uint32_t		total_blocks;
+	uint32_t		free_blocks;
+	uint32_t		next_alloc;
+	uint32_t		rsrc_clump_sz;
+	uint32_t		data_clump_sz;
+	uint32_t		next_cnid;
+	uint32_t		write_count;
+	uint64_t		encodings_bmp;
+	struct hfs_finder_info finder_info;
+	struct hfsplus_fork alloc_file;
+	struct hfsplus_fork ext_file;
+	struct hfsplus_fork cat_file;
+	struct hfsplus_fork attr_file;
+	struct hfsplus_fork start_file;
+}  __attribute__((packed));
+
+#define HFSPLUS_SECTOR_SIZE        512
+
+static int hfs_set_uuid(blkid_probe pr, unsigned char const *hfs_info, size_t len)
+{
+	static unsigned char const hash_init[MD5LENGTH] = {
+		0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6,
+		0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
+	};
+	unsigned char uuid[MD5LENGTH];
+	struct MD5Context md5c;
+
+	if (memcmp(hfs_info, "\0\0\0\0\0\0\0\0", len) == 0)
+		return -1;
+	MD5Init(&md5c);
+	MD5Update(&md5c, hash_init, MD5LENGTH);
+	MD5Update(&md5c, hfs_info, len);
+	MD5Final(uuid, &md5c);
+	uuid[6] = 0x30 | (uuid[6] & 0x0f);
+	uuid[8] = 0x80 | (uuid[8] & 0x3f);
+	return blkid_probe_set_uuid(pr, uuid);
+}
+
+static int probe_hfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct hfs_mdb	*hfs;
+
+	hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
+	if (!hfs)
+		return errno ? -errno : 1;
+
+	if ((memcmp(hfs->embed_sig, "H+", 2) == 0) ||
+	    (memcmp(hfs->embed_sig, "HX", 2) == 0))
+		return 1;	/* Not hfs, but an embedded HFS+ */
+
+	hfs_set_uuid(pr, hfs->finder_info.id, sizeof(hfs->finder_info.id));
+
+	blkid_probe_set_label(pr, hfs->label, hfs->label_len);
+	return 0;
+}
+
+static int probe_hfsplus(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+	struct hfsplus_bnode_descriptor *descr;
+	struct hfsplus_bheader_record *bnode;
+	struct hfsplus_catalog_key *key;
+	struct hfsplus_vol_header *hfsplus;
+	struct hfs_mdb *sbd;
+	unsigned int alloc_block_size;
+	unsigned int alloc_first_block;
+	unsigned int embed_first_block;
+	unsigned int off = 0;
+	unsigned int blocksize;
+	unsigned int cat_block;
+	unsigned int ext_block_start;
+	unsigned int ext_block_count;
+	unsigned int record_count;
+	unsigned int leaf_node_head;
+	unsigned int leaf_node_count;
+	unsigned int leaf_node_size;
+	unsigned int leaf_block;
+	int ext;
+	uint64_t leaf_off;
+	unsigned char *buf;
+
+	sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
+	if (!sbd)
+		return errno ? -errno : 1;
+
+	/* Check for a HFS+ volume embedded in a HFS volume */
+	if (memcmp(sbd->signature, "BD", 2) == 0) {
+		if ((memcmp(sbd->embed_sig, "H+", 2) != 0) &&
+		    (memcmp(sbd->embed_sig, "HX", 2) != 0))
+			/* This must be an HFS volume, so fail */
+			return 1;
+
+		alloc_block_size = be32_to_cpu(sbd->al_blk_size);
+		alloc_first_block = be16_to_cpu(sbd->al_bl_st);
+		embed_first_block = be16_to_cpu(sbd->embed_startblock);
+		off = (alloc_first_block * 512) +
+			(embed_first_block * alloc_block_size);
+
+		buf = blkid_probe_get_buffer(pr,
+				off + (mag->kboff * 1024),
+				sizeof(struct hfsplus_vol_header));
+		hfsplus = (struct hfsplus_vol_header *) buf;
+
+	} else
+		hfsplus = blkid_probe_get_sb(pr, mag,
+				struct hfsplus_vol_header);
+
+	if (!hfsplus)
+		return errno ? -errno : 1;
+
+	if ((memcmp(hfsplus->signature, "H+", 2) != 0) &&
+	    (memcmp(hfsplus->signature, "HX", 2) != 0))
+		return 1;
+
+	hfs_set_uuid(pr, hfsplus->finder_info.id, sizeof(hfsplus->finder_info.id));
+
+	blocksize = be32_to_cpu(hfsplus->blocksize);
+	if (blocksize < HFSPLUS_SECTOR_SIZE)
+		return 1;
+
+	memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
+	cat_block = be32_to_cpu(extents[0].start_block);
+
+	buf = blkid_probe_get_buffer(pr,
+			off + ((blkid_loff_t) cat_block * blocksize), 0x2000);
+	if (!buf)
+		return errno ? -errno : 0;
+
+	bnode = (struct hfsplus_bheader_record *)
+		&buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+	leaf_node_head = be32_to_cpu(bnode->leaf_head);
+	leaf_node_size = be16_to_cpu(bnode->node_size);
+	leaf_node_count = be32_to_cpu(bnode->leaf_count);
+	if (leaf_node_count == 0)
+		return 0;
+
+	leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
+
+	/* get physical location */
+	for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
+		ext_block_start = be32_to_cpu(extents[ext].start_block);
+		ext_block_count = be32_to_cpu(extents[ext].block_count);
+		if (ext_block_count == 0)
+			return 0;
+
+		/* this is our extent */
+		if (leaf_block < ext_block_count)
+			break;
+
+		leaf_block -= ext_block_count;
+	}
+	if (ext == HFSPLUS_EXTENT_COUNT)
+		return 0;
+
+	leaf_off = (ext_block_start + leaf_block) * blocksize;
+
+	buf = blkid_probe_get_buffer(pr,
+				(blkid_loff_t) off + leaf_off,
+				leaf_node_size);
+	if (!buf)
+		return errno ? -errno : 0;
+
+	descr = (struct hfsplus_bnode_descriptor *) buf;
+	record_count = be16_to_cpu(descr->num_recs);
+	if (record_count == 0)
+		return 0;
+
+	if (descr->type != HFS_NODE_LEAF)
+		return 0;
+
+	key = (struct hfsplus_catalog_key *)
+		&buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+	if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
+		return 0;
+
+	blkid_probe_set_utf8label(pr, key->unicode,
+			be16_to_cpu(key->unicode_len) * 2,
+			BLKID_ENC_UTF16BE);
+	return 0;
+}
+
+const struct blkid_idinfo hfs_idinfo =
+{
+	.name		= "hfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_hfs,
+	.flags		= BLKID_IDINFO_TOLERANT,
+	.magics		=
+	{
+		{ .magic = "BD", .len = 2, .kboff = 1 },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo hfsplus_idinfo =
+{
+	.name		= "hfsplus",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_hfsplus,
+	.magics		=
+	{
+		{ .magic = "BD", .len = 2, .kboff = 1 },
+		{ .magic = "H+", .len = 2, .kboff = 1 },
+		{ .magic = "HX", .len = 2, .kboff = 1 },
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/highpoint_raid.c b/libblkid/src/superblocks/highpoint_raid.c
new file mode 100644
index 0000000..ad3b538
--- /dev/null
+++ b/libblkid/src/superblocks/highpoint_raid.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct hpt45x_metadata {
+	uint32_t	magic;
+};
+
+#define HPT45X_MAGIC_OK			0x5a7816f3
+#define HPT45X_MAGIC_BAD		0x5a7816fd
+
+static int probe_highpoint45x(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct hpt45x_metadata *hpt;
+	uint64_t off;
+	uint32_t magic;
+
+	if (pr->size < 0x10000)
+		return 1;
+	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+		return 1;
+
+	off = ((pr->size / 0x200) - 11) * 0x200;
+	hpt = (struct hpt45x_metadata *)
+			blkid_probe_get_buffer(pr,
+					off,
+					sizeof(struct hpt45x_metadata));
+	if (!hpt)
+		return errno ? -errno : 1;
+	magic = le32_to_cpu(hpt->magic);
+	if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD)
+		return 1;
+	if (blkid_probe_set_magic(pr, off, sizeof(hpt->magic),
+				(unsigned char *) &hpt->magic))
+		return 1;
+	return 0;
+}
+
+static int probe_highpoint37x(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+		return 1;
+	return 0;
+}
+
+
+const struct blkid_idinfo highpoint45x_idinfo = {
+	.name		= "hpt45x_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_highpoint45x,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+const struct blkid_idinfo highpoint37x_idinfo = {
+	.name		= "hpt37x_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_highpoint37x,
+	.magics		= {
+		/*
+		 * Superblok offset:                      4608 bytes  (9 sectors)
+		 * Magic string offset within superblock:   32 bytes
+		 *
+		 * kboff = (4608 + 32) / 1024
+		 * sboff = (4608 + 32) % kboff
+		 */
+		{ .magic = "\xf0\x16\x78\x5a", .len = 4, .kboff = 4, .sboff = 544 },
+		{ .magic = "\xfd\x16\x78\x5a", .len = 4, .kboff = 4, .sboff = 544 },
+		{ NULL }
+	}
+};
+
+
diff --git a/libblkid/src/superblocks/hpfs.c b/libblkid/src/superblocks/hpfs.c
new file mode 100644
index 0000000..0565d37
--- /dev/null
+++ b/libblkid/src/superblocks/hpfs.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct hpfs_boot_block
+{
+	uint8_t		jmp[3];
+	uint8_t		oem_id[8];
+	uint8_t		bytes_per_sector[2];
+	uint8_t		sectors_per_cluster;
+	uint8_t		n_reserved_sectors[2];
+	uint8_t		n_fats;
+	uint8_t		n_rootdir_entries[2];
+	uint8_t		n_sectors_s[2];
+	uint8_t		media_byte;
+	uint16_t	sectors_per_fat;
+	uint16_t	sectors_per_track;
+	uint16_t	heads_per_cyl;
+	uint32_t	n_hidden_sectors;
+	uint32_t	n_sectors_l;
+	uint8_t		drive_number;
+	uint8_t		mbz;
+	uint8_t		sig_28h;
+	uint8_t		vol_serno[4];
+	uint8_t		vol_label[11];
+	uint8_t		sig_hpfs[8];
+	uint8_t		pad[448];
+	uint8_t		magic[2];
+} __attribute__((packed));
+
+struct hpfs_super_block
+{
+	uint8_t		magic[4];
+	uint8_t		magic1[4];
+	uint8_t		version;
+} __attribute__((packed));
+
+struct hpfs_spare_super
+{
+	uint8_t		magic[4];
+	uint8_t		magic1[4];
+} __attribute__((packed));
+
+
+#define HPFS_SB_OFFSET			0x2000
+#define HPFS_SBSPARE_OFFSET		0x2200
+
+static int probe_hpfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct hpfs_super_block *hs;
+	struct hpfs_spare_super *hss;
+	struct hpfs_boot_block *hbb;
+	uint8_t version;
+
+	/* super block */
+	hs = blkid_probe_get_sb(pr, mag, struct hpfs_super_block);
+	if (!hs)
+		return errno ? -errno : 1;
+	version = hs->version;
+
+	/* spare super block */
+	hss = (struct hpfs_spare_super *)
+			blkid_probe_get_buffer(pr,
+				HPFS_SBSPARE_OFFSET,
+				sizeof(struct hpfs_spare_super));
+	if (!hss)
+		return errno ? -errno : 1;
+	if (memcmp(hss->magic, "\x49\x18\x91\xf9", 4) != 0)
+		return 1;
+
+	/* boot block (with UUID and LABEL) */
+	hbb = (struct hpfs_boot_block *)
+			blkid_probe_get_buffer(pr,
+				0,
+				sizeof(struct hpfs_boot_block));
+	if (!hbb)
+		return errno ? -errno : 1;
+	if (memcmp(hbb->magic, "\x55\xaa", 2) == 0 &&
+	    memcmp(hbb->sig_hpfs, "HPFS", 4) == 0 &&
+	    hbb->sig_28h == 0x28) {
+		blkid_probe_set_label(pr, hbb->vol_label, sizeof(hbb->vol_label));
+		blkid_probe_sprintf_uuid(pr,
+				hbb->vol_serno, sizeof(hbb->vol_serno),
+				"%02X%02X-%02X%02X",
+				hbb->vol_serno[3], hbb->vol_serno[2],
+				hbb->vol_serno[1], hbb->vol_serno[0]);
+	}
+	blkid_probe_sprintf_version(pr, "%u", version);
+
+	return 0;
+}
+
+const struct blkid_idinfo hpfs_idinfo =
+{
+	.name		= "hpfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_hpfs,
+	.magics		=
+	{
+		{
+		  .magic = "\x49\xe8\x95\xf9",
+		  .len = 4,
+		  .kboff = (HPFS_SB_OFFSET >> 10)
+		},
+		{ NULL }
+	}
+};
+
+
diff --git a/libblkid/src/superblocks/iso9660.c b/libblkid/src/superblocks/iso9660.c
new file mode 100644
index 0000000..d099467
--- /dev/null
+++ b/libblkid/src/superblocks/iso9660.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired also by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <ctype.h>
+
+#include "superblocks.h"
+
+struct iso9660_date {
+	unsigned char year[4];
+	unsigned char month[2];
+	unsigned char day[2];
+	unsigned char hour[2];
+	unsigned char minute[2];
+	unsigned char second[2];
+	unsigned char hundredth[2];
+	unsigned char offset;
+} __attribute__ ((packed));
+
+/* PVD - Primary volume descriptor */
+struct iso_volume_descriptor {
+	unsigned char	vd_type;
+	unsigned char	vd_id[5];
+	unsigned char	vd_version;
+	unsigned char	flags;
+	unsigned char	system_id[32];
+	unsigned char	volume_id[32];
+	unsigned char	unused[8];
+	unsigned char	space_size[8];
+	unsigned char	escape_sequences[8];
+	unsigned char  unused1[222];
+	unsigned char  publisher_id[128];
+	unsigned char  unused2[128];
+	unsigned char  application_id[128];
+	unsigned char  unused3[111];
+	struct iso9660_date created;
+	struct iso9660_date modified;
+} __attribute__((packed));
+
+/* Boot Record */
+struct boot_record {
+	unsigned char	vd_type;
+	unsigned char	vd_id[5];
+	unsigned char	vd_version;
+	unsigned char	boot_system_id[32];
+	unsigned char	boot_id[32];
+	unsigned char	unused[1];
+} __attribute__((packed));
+
+#define ISO_SUPERBLOCK_OFFSET		0x8000
+#define ISO_SECTOR_SIZE			0x800
+#define ISO_VD_OFFSET			(ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE)
+#define ISO_VD_BOOT_RECORD		0x0
+#define ISO_VD_SUPPLEMENTARY		0x2
+#define ISO_VD_END			0xff
+#define ISO_VD_MAX			16
+
+struct high_sierra_volume_descriptor {
+	unsigned char	foo[8];
+	unsigned char	type;
+	unsigned char	id[5];
+	unsigned char	version;
+	unsigned char	unused1;
+	unsigned char	system_id[32];
+	unsigned char   volume_id[32];
+} __attribute__((packed));
+
+/* returns 1 if the begin of @ascii is equal to @utf16 string.
+ */
+static int ascii_eq_utf16be(unsigned char *ascii,
+			unsigned char *utf16, size_t len)
+{
+	size_t a, u;
+
+	for (a = 0, u = 0; u < len; a++, u += 2) {
+		if (utf16[u] != 0x0 || ascii[a] != utf16[u + 1])
+			return 0;
+	}
+	return 1;
+}
+
+/* old High Sierra format */
+static int probe_iso9660_hsfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct high_sierra_volume_descriptor *iso;
+
+	iso = blkid_probe_get_sb(pr, mag, struct high_sierra_volume_descriptor);
+	if (!iso)
+		return errno ? -errno : 1;
+
+	blkid_probe_set_version(pr, "High Sierra");
+	blkid_probe_set_label(pr, iso->volume_id, sizeof(iso->volume_id));
+	return 0;
+}
+
+static int probe_iso9660_set_uuid (blkid_probe pr, const struct iso9660_date *date)
+{
+	unsigned char buffer[16];
+	unsigned int i, zeros = 0;
+
+	buffer[0] = date->year[0];
+	buffer[1] = date->year[1];
+	buffer[2] = date->year[2];
+	buffer[3] = date->year[3];
+	buffer[4] = date->month[0];
+	buffer[5] = date->month[1];
+	buffer[6] = date->day[0];
+	buffer[7] = date->day[1];
+	buffer[8] = date->hour[0];
+	buffer[9] = date->hour[1];
+	buffer[10] = date->minute[0];
+	buffer[11] = date->minute[1];
+	buffer[12] = date->second[0];
+	buffer[13] = date->second[1];
+	buffer[14] = date->hundredth[0];
+	buffer[15] = date->hundredth[1];
+
+	/* count the number of zeros ('0') in the date buffer */
+	for (i = 0, zeros = 0; i < sizeof(buffer); i++)
+		if (buffer[i] == '0')
+			zeros++;
+
+	/* due to the iso9660 standard if all date fields are '0' and offset is 0, the date is unset */
+	if (zeros == sizeof(buffer) && date->offset == 0)
+		return 0;
+
+	/* generate an UUID using this date and return success */
+	blkid_probe_sprintf_uuid (pr, buffer, sizeof(buffer),
+		"%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c",
+		buffer[0], buffer[1], buffer[2], buffer[3],
+		buffer[4], buffer[5],
+		buffer[6], buffer[7],
+		buffer[8], buffer[9],
+		buffer[10], buffer[11],
+		buffer[12], buffer[13],
+		buffer[14], buffer[15]);
+
+	return 1;
+}
+
+static int is_str_empty(const unsigned char *str, size_t len)
+{
+	size_t i;
+
+	if (!str || !*str)
+		return 1;
+
+	for (i = 0; i < len; i++)
+		if (!isspace(str[i]))
+			return 0;
+	return 1;
+}
+
+/* iso9660 [+ Microsoft Joliet Extension] */
+int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct iso_volume_descriptor *iso;
+	unsigned char label[32];
+	int i;
+	int off;
+
+	if (strcmp(mag->magic, "CDROM") == 0)
+		return probe_iso9660_hsfs(pr, mag);
+
+	iso = blkid_probe_get_sb(pr, mag, struct iso_volume_descriptor);
+	if (!iso)
+		return errno ? -errno : 1;
+
+	memcpy(label, iso->volume_id, sizeof(label));
+
+	if (!is_str_empty(iso->system_id, sizeof(iso->system_id)))
+		blkid_probe_set_id_label(pr, "SYSTEM_ID",
+				iso->system_id, sizeof(iso->system_id));
+
+	if (!is_str_empty(iso->publisher_id, sizeof(iso->publisher_id)))
+		blkid_probe_set_id_label(pr, "PUBLISHER_ID",
+				iso->publisher_id, sizeof(iso->publisher_id));
+
+	if (!is_str_empty(iso->application_id, sizeof(iso->application_id)))
+		blkid_probe_set_id_label(pr, "APPLICATION_ID",
+				iso->application_id, sizeof(iso->application_id));
+
+	/* create an UUID using the modified/created date */
+	if (! probe_iso9660_set_uuid(pr, &iso->modified))
+		probe_iso9660_set_uuid(pr, &iso->created);
+
+	/* Joliet Extension and Boot Record */
+	off = ISO_VD_OFFSET;
+	for (i = 0; i < ISO_VD_MAX; i++) {
+		struct boot_record *boot= (struct boot_record *)
+			blkid_probe_get_buffer(pr,
+					off,
+					max(sizeof(struct boot_record),
+					    sizeof(struct iso_volume_descriptor)));
+
+		if (boot == NULL || boot->vd_type == ISO_VD_END)
+			break;
+
+		if (boot->vd_type == ISO_VD_BOOT_RECORD) {
+			if (!is_str_empty(boot->boot_system_id,
+					  sizeof(boot->boot_system_id)))
+				blkid_probe_set_id_label(pr, "BOOT_SYSTEM_ID",
+							boot->boot_system_id,
+							sizeof(boot->boot_system_id));
+			off += ISO_SECTOR_SIZE;
+			continue;
+		}
+
+		/* Not a Boot record, lets see if its supplemntary volume descriptor */
+		iso = (struct iso_volume_descriptor *) boot;
+
+		if (iso->vd_type != ISO_VD_SUPPLEMENTARY) {
+			off += ISO_SECTOR_SIZE;
+			continue;
+		}
+
+		if (memcmp(iso->escape_sequences, "%/@", 3) == 0 ||
+		    memcmp(iso->escape_sequences, "%/C", 3) == 0 ||
+		    memcmp(iso->escape_sequences, "%/E", 3) == 0) {
+
+			blkid_probe_set_version(pr, "Joliet Extension");
+
+			/* Is the Joliet (UTF16BE) label equal to the label in
+			 * the PVD? If yes, use PVD label.  The Jolied version
+			 * of the label could be trimed (because UTF16..).
+			 */
+			if (ascii_eq_utf16be(label, iso->volume_id, 32))
+				break;
+
+			blkid_probe_set_utf8label(pr,
+					iso->volume_id,
+					sizeof(iso->volume_id),
+					BLKID_ENC_UTF16BE);
+			goto has_label;
+		}
+		off += ISO_SECTOR_SIZE;
+	}
+
+	/* Joliet not found, let use standard iso label */
+	blkid_probe_set_label(pr, label, sizeof(label));
+
+has_label:
+	return 0;
+}
+
+const struct blkid_idinfo iso9660_idinfo =
+{
+	.name		= "iso9660",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_iso9660,
+	.flags		= BLKID_IDINFO_TOLERANT,
+	.magics		=
+	{
+		{ .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 },
+		{ .magic = "CDROM", .len = 5, .kboff = 32, .sboff = 9 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/iso9660.h b/libblkid/src/superblocks/iso9660.h
new file mode 100644
index 0000000..a8d729d
--- /dev/null
+++ b/libblkid/src/superblocks/iso9660.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2013 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef _BLKID_ISO9660_H
+#define _BLKID_ISO9660_H
+
+#include "blkidP.h"
+
+extern int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag);
+
+#endif /* _BLKID_ISO9660_H */
diff --git a/libblkid/src/superblocks/isw_raid.c b/libblkid/src/superblocks/isw_raid.c
new file mode 100644
index 0000000..065c2b2
--- /dev/null
+++ b/libblkid/src/superblocks/isw_raid.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct isw_metadata {
+	uint8_t		sig[32];
+	uint32_t	check_sum;
+	uint32_t	mpb_size;
+	uint32_t	family_num;
+	uint32_t	generation_num;
+};
+
+#define ISW_SIGNATURE		"Intel Raid ISM Cfg Sig. "
+
+
+static int probe_iswraid(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	uint64_t off;
+	struct isw_metadata *isw;
+
+	if (pr->size < 0x10000)
+		return 1;
+	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+		return 1;
+
+	off = ((pr->size / 0x200) - 2) * 0x200;
+	isw = (struct isw_metadata *)
+			blkid_probe_get_buffer(pr,
+					off,
+					sizeof(struct isw_metadata));
+	if (!isw)
+		return errno ? -errno : 1;
+
+	if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0)
+		return 1;
+	if (blkid_probe_sprintf_version(pr, "%6s",
+			&isw->sig[sizeof(ISW_SIGNATURE)-1]) != 0)
+		return 1;
+	if (blkid_probe_set_magic(pr, off, sizeof(isw->sig),
+				(unsigned char *) isw->sig))
+		return 1;
+	return 0;
+}
+
+const struct blkid_idinfo iswraid_idinfo = {
+	.name		= "isw_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_iswraid,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/jfs.c b/libblkid/src/superblocks/jfs.c
new file mode 100644
index 0000000..ac684d8
--- /dev/null
+++ b/libblkid/src/superblocks/jfs.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct jfs_super_block {
+	unsigned char	js_magic[4];
+	uint32_t	js_version;
+	uint64_t	js_size;
+	uint32_t	js_bsize;	/* 4: aggregate block size in bytes */
+	uint16_t	js_l2bsize;	/* 2: log2 of s_bsize */
+	uint16_t	js_l2bfactor;	/* 2: log2(s_bsize/hardware block size) */
+	uint32_t	js_pbsize;	/* 4: hardware/LVM block size in bytes */
+	uint16_t	js_l2pbsize;	/* 2: log2 of s_pbsize */
+	uint16_t	js_pad;		/* 2: padding necessary for alignment */
+	uint32_t	js_dummy2[26];
+	unsigned char	js_uuid[16];
+	unsigned char	js_label[16];
+	unsigned char	js_loguuid[16];
+};
+
+static int probe_jfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct jfs_super_block *js;
+
+	js = blkid_probe_get_sb(pr, mag, struct jfs_super_block);
+	if (!js)
+		return errno ? -errno : 1;
+	if (le32_to_cpu(js->js_bsize) != (1U << le16_to_cpu(js->js_l2bsize)))
+		return 1;
+	if (le32_to_cpu(js->js_pbsize) != (1U << le16_to_cpu(js->js_l2pbsize)))
+		return 1;
+	if ((le16_to_cpu(js->js_l2bsize) - le16_to_cpu(js->js_l2pbsize)) !=
+	    le16_to_cpu(js->js_l2bfactor))
+		return 1;
+
+	if (strlen((char *) js->js_label))
+		blkid_probe_set_label(pr, js->js_label, sizeof(js->js_label));
+	blkid_probe_set_uuid(pr, js->js_uuid);
+	return 0;
+}
+
+
+const struct blkid_idinfo jfs_idinfo =
+{
+	.name		= "jfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_jfs,
+	.minsz		= 16 * 1024 * 1024,
+	.magics		=
+	{
+		{ .magic = "JFS1", .len = 4, .kboff = 32 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/jmicron_raid.c b/libblkid/src/superblocks/jmicron_raid.c
new file mode 100644
index 0000000..ca79867
--- /dev/null
+++ b/libblkid/src/superblocks/jmicron_raid.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct jm_metadata {
+	int8_t		signature[2];
+	uint8_t		minor_version;
+	uint8_t		major_version;
+	uint16_t	checksum;
+};
+
+#define JM_SIGNATURE		"JM"
+
+static int probe_jmraid(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	uint64_t off;
+	struct jm_metadata *jm;
+
+	if (pr->size < 0x10000)
+		return 1;
+	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+		return 1;
+
+	off = ((pr->size / 0x200) - 1) * 0x200;
+	jm = (struct jm_metadata *)
+		blkid_probe_get_buffer(pr,
+				off,
+				sizeof(struct jm_metadata));
+	if (!jm)
+		return errno ? -errno : 1;
+
+	if (memcmp(jm->signature, JM_SIGNATURE, sizeof(JM_SIGNATURE) - 1) != 0)
+		return 1;
+	if (blkid_probe_sprintf_version(pr, "%u.%u",
+				jm->major_version, jm->minor_version) != 0)
+		return 1;
+	if (blkid_probe_set_magic(pr, off, sizeof(jm->signature),
+				(unsigned char *) jm->signature))
+		return 1;
+	return 0;
+}
+
+const struct blkid_idinfo jmraid_idinfo = {
+	.name		= "jmicron_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_jmraid,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/linux_raid.c b/libblkid/src/superblocks/linux_raid.c
new file mode 100644
index 0000000..cf29141
--- /dev/null
+++ b/libblkid/src/superblocks/linux_raid.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct mdp0_super_block {
+	uint32_t	md_magic;
+	uint32_t	major_version;
+	uint32_t	minor_version;
+	uint32_t	patch_version;
+	uint32_t	gvalid_words;
+	uint32_t	set_uuid0;
+	uint32_t	ctime;
+	uint32_t	level;
+	uint32_t	size;
+	uint32_t	nr_disks;
+	uint32_t	raid_disks;
+	uint32_t	md_minor;
+	uint32_t	not_persistent;
+	uint32_t	set_uuid1;
+	uint32_t	set_uuid2;
+	uint32_t	set_uuid3;
+};
+
+/*
+ * Version-1, little-endian.
+ */
+struct mdp1_super_block {
+	/* constant array information - 128 bytes */
+	uint32_t	magic;		/* MD_SB_MAGIC: 0xa92b4efc - little endian */
+	uint32_t	major_version;	/* 1 */
+	uint32_t	feature_map;	/* 0 for now */
+	uint32_t	pad0;		/* always set to 0 when writing */
+
+	uint8_t		set_uuid[16];	/* user-space generated. */
+	unsigned char	set_name[32];	/* set and interpreted by user-space */
+
+	uint64_t	ctime;		/* lo 40 bits are seconds, top 24 are microseconds or 0*/
+	uint32_t	level;		/* -4 (multipath), -1 (linear), 0,1,4,5 */
+	uint32_t	layout;		/* only for raid5 currently */
+	uint64_t	size;		/* used size of component devices, in 512byte sectors */
+
+	uint32_t	chunksize;	/* in 512byte sectors */
+	uint32_t	raid_disks;
+	uint32_t	bitmap_offset;	/* sectors after start of superblock that bitmap starts
+					 * NOTE: signed, so bitmap can be before superblock
+					 * only meaningful of feature_map[0] is set.
+					 */
+
+	/* These are only valid with feature bit '4' */
+	uint32_t	new_level;	/* new level we are reshaping to		*/
+	uint64_t	reshape_position;	/* next address in array-space for reshape */
+	uint32_t	delta_disks;	/* change in number of raid_disks		*/
+	uint32_t	new_layout;	/* new layout					*/
+	uint32_t	new_chunk;	/* new chunk size (bytes)			*/
+	uint8_t		pad1[128-124];	/* set to 0 when written */
+
+	/* constant this-device information - 64 bytes */
+	uint64_t	data_offset;	/* sector start of data, often 0 */
+	uint64_t	data_size;	/* sectors in this device that can be used for data */
+	uint64_t	super_offset;	/* sector start of this superblock */
+	uint64_t	recovery_offset;/* sectors before this offset (from data_offset) have been recovered */
+	uint32_t	dev_number;	/* permanent identifier of this  device - not role in raid */
+	uint32_t	cnt_corrected_read; /* number of read errors that were corrected by re-writing */
+	uint8_t		device_uuid[16]; /* user-space setable, ignored by kernel */
+        uint8_t		devflags;        /* per-device flags.  Only one defined...*/
+	uint8_t		pad2[64-57];	/* set to 0 when writing */
+
+	/* array state information - 64 bytes */
+	uint64_t	utime;		/* 40 bits second, 24 btes microseconds */
+	uint64_t	events;		/* incremented when superblock updated */
+	uint64_t	resync_offset;	/* data before this offset (from data_offset) known to be in sync */
+	uint32_t	sb_csum;	/* checksum up to dev_roles[max_dev] */
+	uint32_t	max_dev;	/* size of dev_roles[] array to consider */
+	uint8_t		pad3[64-32];	/* set to 0 when writing */
+
+	/* device state information. Indexed by dev_number.
+	 * 2 bytes per device
+	 * Note there are no per-device state flags. State information is rolled
+	 * into the 'roles' value.  If a device is spare or faulty, then it doesn't
+	 * have a meaningful role.
+	 */
+	uint16_t	dev_roles[0];	/* role in array, or 0xffff for a spare, or 0xfffe for faulty */
+};
+
+
+#define MD_RESERVED_BYTES		0x10000
+#define MD_SB_MAGIC			0xa92b4efc
+
+static int probe_raid0(blkid_probe pr, blkid_loff_t off)
+{
+	struct mdp0_super_block *mdp0;
+	union {
+		uint32_t ints[4];
+		uint8_t bytes[16];
+	} uuid;
+	uint32_t ma, mi, pa;
+	uint64_t size;
+
+	if (pr->size < MD_RESERVED_BYTES)
+		return 1;
+	mdp0 = (struct mdp0_super_block *)
+			blkid_probe_get_buffer(pr,
+				off,
+				sizeof(struct mdp0_super_block));
+	if (!mdp0)
+		return errno ? -errno : 1;
+
+	memset(uuid.ints, 0, sizeof(uuid.ints));
+
+	if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
+		uuid.ints[0] = swab32(mdp0->set_uuid0);
+		if (le32_to_cpu(mdp0->minor_version) >= 90) {
+			uuid.ints[1] = swab32(mdp0->set_uuid1);
+			uuid.ints[2] = swab32(mdp0->set_uuid2);
+			uuid.ints[3] = swab32(mdp0->set_uuid3);
+		}
+		ma = le32_to_cpu(mdp0->major_version);
+		mi = le32_to_cpu(mdp0->minor_version);
+		pa = le32_to_cpu(mdp0->patch_version);
+		size = le32_to_cpu(mdp0->size);
+
+	} else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
+		uuid.ints[0] = mdp0->set_uuid0;
+		if (be32_to_cpu(mdp0->minor_version) >= 90) {
+			uuid.ints[1] = mdp0->set_uuid1;
+			uuid.ints[2] = mdp0->set_uuid2;
+			uuid.ints[3] = mdp0->set_uuid3;
+		}
+		ma = be32_to_cpu(mdp0->major_version);
+		mi = be32_to_cpu(mdp0->minor_version);
+		pa = be32_to_cpu(mdp0->patch_version);
+		size = be32_to_cpu(mdp0->size);
+	} else
+		return 1;
+
+	size <<= 10;	/* convert KiB to bytes */
+
+	if (pr->size < 0 || (uint64_t) pr->size < size + MD_RESERVED_BYTES)
+		/* device is too small */
+		return 1;
+
+	if (off < 0 || (uint64_t) off < size)
+		/* no space before superblock */
+		return 1;
+
+	/*
+	 * Check for collisions between RAID and partition table
+	 *
+	 * For example the superblock is at the end of the last partition, it's
+	 * the same position as at the end of the disk...
+	 */
+	if ((S_ISREG(pr->mode) || blkid_probe_is_wholedisk(pr)) &&
+	    blkid_probe_is_covered_by_pt(pr,
+			off - size,				/* min. start  */
+			size + MD_RESERVED_BYTES)) {		/* min. length */
+
+		/* ignore this superblock, it's within any partition and
+		 * we are working with whole-disk now */
+		return 1;
+	}
+
+	if (blkid_probe_sprintf_version(pr, "%u.%u.%u", ma, mi, pa) != 0)
+		return 1;
+	if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0)
+		return 1;
+	if (blkid_probe_set_magic(pr, off, sizeof(mdp0->md_magic),
+				(unsigned char *) &mdp0->md_magic))
+		return 1;
+	return 0;
+}
+
+static int probe_raid1(blkid_probe pr, off_t off)
+{
+	struct mdp1_super_block *mdp1;
+
+	mdp1 = (struct mdp1_super_block *)
+			blkid_probe_get_buffer(pr,
+				off,
+				sizeof(struct mdp1_super_block));
+	if (!mdp1)
+		return errno ? -errno : 1;
+	if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
+		return 1;
+	if (le32_to_cpu(mdp1->major_version) != 1U)
+		return 1;
+	if (le64_to_cpu(mdp1->super_offset) != (uint64_t) off >> 9)
+		return 1;
+	if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0)
+		return 1;
+	if (blkid_probe_set_uuid_as(pr,
+			(unsigned char *) mdp1->device_uuid, "UUID_SUB") != 0)
+		return 1;
+	if (blkid_probe_set_label(pr, mdp1->set_name,
+				sizeof(mdp1->set_name)) != 0)
+		return 1;
+	if (blkid_probe_set_magic(pr, off, sizeof(mdp1->magic),
+				(unsigned char *) &mdp1->magic))
+		return 1;
+	return 0;
+}
+
+int probe_raid(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	const char *ver = NULL;
+	int ret = BLKID_PROBE_NONE;
+
+	if (pr->size > MD_RESERVED_BYTES) {
+		/* version 0 at the end of the device */
+		uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1))
+			- MD_RESERVED_BYTES;
+		ret = probe_raid0(pr, sboff);
+		if (ret < 1)
+			return ret;	/* error */
+
+		/* version 1.0 at the end of the device */
+		sboff = (pr->size & ~(0x1000 - 1)) - 0x2000;
+		ret = probe_raid1(pr, sboff);
+		if (ret < 0)
+			return ret;	/* error */
+		if (ret == 0)
+			ver = "1.0";
+	}
+
+	if (!ver) {
+		/* version 1.1 at the start of the device */
+		ret = probe_raid1(pr, 0);
+		if (ret == 0)
+			ver = "1.1";
+
+		/* version 1.2 at 4k offset from the start */
+		else if (ret == BLKID_PROBE_NONE) {
+			ret = probe_raid1(pr, 0x1000);
+			if (ret == 0)
+				ver = "1.2";
+		}
+	}
+
+	if (ver) {
+		blkid_probe_set_version(pr, ver);
+		return BLKID_PROBE_OK;
+	}
+	return ret;
+}
+
+
+const struct blkid_idinfo linuxraid_idinfo = {
+	.name		= "linux_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_raid,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/lsi_raid.c b/libblkid/src/superblocks/lsi_raid.c
new file mode 100644
index 0000000..697b0fe
--- /dev/null
+++ b/libblkid/src/superblocks/lsi_raid.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct lsi_metadata {
+	uint8_t		sig[6];
+};
+
+
+#define LSI_SIGNATURE		"$XIDE$"
+
+static int probe_lsiraid(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	uint64_t off;
+	struct lsi_metadata *lsi;
+
+	if (pr->size < 0x10000)
+		return 1;
+	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+		return 1;
+
+	off = ((pr->size / 0x200) - 1) * 0x200;
+	lsi = (struct lsi_metadata *)
+		blkid_probe_get_buffer(pr,
+				off,
+				sizeof(struct lsi_metadata));
+	if (!lsi)
+		return errno ? -errno : 1;
+
+	if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0)
+		return 1;
+	if (blkid_probe_set_magic(pr, off, sizeof(lsi->sig),
+				(unsigned char *) lsi->sig))
+		return 1;
+	return 0;
+}
+
+const struct blkid_idinfo lsiraid_idinfo = {
+	.name		= "lsi_mega_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_lsiraid,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/luks.c b/libblkid/src/superblocks/luks.c
new file mode 100644
index 0000000..00696f2
--- /dev/null
+++ b/libblkid/src/superblocks/luks.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+#define LUKS_CIPHERNAME_L		32
+#define LUKS_CIPHERMODE_L		32
+#define LUKS_HASHSPEC_L			32
+#define LUKS_DIGESTSIZE			20
+#define LUKS_SALTSIZE			32
+#define LUKS_MAGIC_L			6
+#define UUID_STRING_L			40
+
+struct luks_phdr {
+	uint8_t		magic[LUKS_MAGIC_L];
+	uint16_t	version;
+	uint8_t		cipherName[LUKS_CIPHERNAME_L];
+	uint8_t		cipherMode[LUKS_CIPHERMODE_L];
+	uint8_t		hashSpec[LUKS_HASHSPEC_L];
+	uint32_t	payloadOffset;
+	uint32_t	keyBytes;
+	uint8_t		mkDigest[LUKS_DIGESTSIZE];
+	uint8_t		mkDigestSalt[LUKS_SALTSIZE];
+	uint32_t	mkDigestIterations;
+	uint8_t		uuid[UUID_STRING_L];
+} __attribute__((packed));
+
+static int probe_luks(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct luks_phdr *header;
+
+	header = blkid_probe_get_sb(pr, mag, struct luks_phdr);
+	if (header == NULL)
+		return errno ? -errno : 1;
+
+	blkid_probe_strncpy_uuid(pr, (unsigned char *) header->uuid,
+			sizeof(header->uuid));
+	blkid_probe_sprintf_version(pr, "%u", be16_to_cpu(header->version));
+	return 0;
+}
+
+const struct blkid_idinfo luks_idinfo =
+{
+	.name		= "crypto_LUKS",
+	.usage		= BLKID_USAGE_CRYPTO,
+	.probefunc	= probe_luks,
+	.magics		=
+	{
+		{ .magic = "LUKS\xba\xbe", .len = 6 },
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/lvm.c b/libblkid/src/superblocks/lvm.c
new file mode 100644
index 0000000..3c6df74
--- /dev/null
+++ b/libblkid/src/superblocks/lvm.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2012 Milan Broz <mbroz@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+#define LVM1_ID_LEN 128
+#define LVM2_ID_LEN 32
+
+struct lvm2_pv_label_header {
+	/* label_header */
+	uint8_t		id[8];		/* LABELONE */
+	uint64_t	sector_xl;	/* Sector number of this label */
+	uint32_t	crc_xl;		/* From next field to end of sector */
+	uint32_t	offset_xl;	/* Offset from start of struct to contents */
+	uint8_t		type[8];	/* LVM2 001 */
+	/* pv_header */
+	uint8_t		pv_uuid[LVM2_ID_LEN];
+} __attribute__ ((packed));
+
+struct lvm1_pv_label_header {
+	uint8_t id[2];			/* HM */
+	uint16_t version;		/* version 1 or 2 */
+	uint32_t _notused[10];		/* lvm1 internals */
+	uint8_t pv_uuid[LVM1_ID_LEN];
+} __attribute__ ((packed));
+
+#define LVM2_LABEL_SIZE 512
+static unsigned int lvm2_calc_crc(const void *buf, unsigned int size)
+{
+	static const unsigned int crctab[] = {
+		0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+		0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+		0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+		0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+	};
+	unsigned int i, crc = 0xf597a6cf;
+	const uint8_t *data = (const uint8_t *) buf;
+
+	for (i = 0; i < size; i++) {
+		crc ^= *data++;
+		crc = (crc >> 4) ^ crctab[crc & 0xf];
+		crc = (crc >> 4) ^ crctab[crc & 0xf];
+	}
+	return crc;
+}
+
+/* Length of real UUID is always LVM2_ID_LEN */
+static void format_lvm_uuid(char *dst_uuid, char *src_uuid)
+{
+	unsigned int i, b;
+
+	for (i = 0, b = 1; i < LVM2_ID_LEN; i++, b <<= 1) {
+		if (b & 0x4444440)
+			*dst_uuid++ = '-';
+		*dst_uuid++ = *src_uuid++;
+	}
+	*dst_uuid = '\0';
+}
+
+static int probe_lvm2(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	int sector = mag->kboff << 1;
+	struct lvm2_pv_label_header *label;
+	char uuid[LVM2_ID_LEN + 7];
+	unsigned char *buf;
+
+	buf = blkid_probe_get_buffer(pr,
+			mag->kboff << 10,
+			512 + sizeof(struct lvm2_pv_label_header));
+	if (!buf)
+		return errno ? -errno : 1;
+
+	/* buf is at 0k or 1k offset; find label inside */
+	if (memcmp(buf, "LABELONE", 8) == 0) {
+		label = (struct lvm2_pv_label_header *) buf;
+	} else if (memcmp(buf + 512, "LABELONE", 8) == 0) {
+		label = (struct lvm2_pv_label_header *)(buf + 512);
+		sector++;
+	} else {
+		return 1;
+	}
+
+	if (le64_to_cpu(label->sector_xl) != (unsigned) sector)
+		return 1;
+
+	if (!blkid_probe_verify_csum(
+		pr, lvm2_calc_crc(
+			&label->offset_xl, LVM2_LABEL_SIZE -
+			((char *) &label->offset_xl - (char *) label)),
+			le32_to_cpu(label->crc_xl)))
+		return 1;
+
+	format_lvm_uuid(uuid, (char *) label->pv_uuid);
+	blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
+			"%s", uuid);
+
+	/* the mag->magic is the same string as label->type,
+	 * but zero terminated */
+	blkid_probe_set_version(pr, mag->magic);
+
+	/* LVM (pvcreate) wipes begin of the device -- let's remember this
+	 * to resolve conflicts bettween LVM and partition tables, ...
+	 */
+	blkid_probe_set_wiper(pr, 0, 8 * 1024);
+
+	return 0;
+}
+
+static int probe_lvm1(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct lvm1_pv_label_header *label;
+	char uuid[LVM2_ID_LEN + 7];
+	unsigned int version;
+
+	label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header);
+	if (!label)
+		return errno ? -errno : 1;
+
+	version = le16_to_cpu(label->version);
+	if (version != 1 && version != 2)
+		return 1;
+
+	format_lvm_uuid(uuid, (char *) label->pv_uuid);
+	blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
+			"%s", uuid);
+
+	return 0;
+}
+
+struct verity_sb {
+	uint8_t  signature[8];	/* "verity\0\0" */
+	uint32_t version;	/* superblock version */
+	uint32_t hash_type;	/* 0 - Chrome OS, 1 - normal */
+	uint8_t  uuid[16];	/* UUID of hash device */
+	uint8_t  algorithm[32];/* hash algorithm name */
+	uint32_t data_block_size; /* data block in bytes */
+	uint32_t hash_block_size; /* hash block in bytes */
+	uint64_t data_blocks;	/* number of data blocks */
+	uint16_t salt_size;	/* salt size */
+	uint8_t  _pad1[6];
+	uint8_t  salt[256];	/* salt */
+	uint8_t  _pad2[168];
+} __attribute__((packed));
+
+static int probe_verity(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct verity_sb *sb;
+	unsigned int version;
+
+	sb = blkid_probe_get_sb(pr, mag, struct verity_sb);
+	if (sb == NULL)
+		return errno ? -errno : 1;
+
+	version = le32_to_cpu(sb->version);
+	if (version != 1)
+		return 1;
+
+	blkid_probe_set_uuid(pr, sb->uuid);
+	blkid_probe_sprintf_version(pr, "%u", version);
+	return 0;
+}
+
+/* NOTE: the original libblkid uses "lvm2pv" as a name */
+const struct blkid_idinfo lvm2_idinfo =
+{
+	.name		= "LVM2_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_lvm2,
+	.magics		=
+	{
+		{ .magic = "LVM2 001", .len = 8, .sboff = 0x218 },
+		{ .magic = "LVM2 001", .len = 8, .sboff = 0x018 },
+		{ .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x018 },
+		{ .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x218 },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo lvm1_idinfo =
+{
+	.name		= "LVM1_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_lvm1,
+	.magics		=
+	{
+		{ .magic = "HM", .len = 2 },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo snapcow_idinfo =
+{
+	.name		= "DM_snapshot_cow",
+	.usage		= BLKID_USAGE_OTHER,
+	.magics		=
+	{
+		{ .magic = "SnAp", .len = 4 },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo verity_hash_idinfo =
+{
+	.name		= "DM_verity_hash",
+	.usage		= BLKID_USAGE_CRYPTO,
+	.probefunc	= probe_verity,
+	.magics		=
+	{
+		{ .magic = "verity\0\0", .len = 8 },
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/minix.c b/libblkid/src/superblocks/minix.c
new file mode 100644
index 0000000..9ea49fe
--- /dev/null
+++ b/libblkid/src/superblocks/minix.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008-2013 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <string.h>
+#include "superblocks.h"
+#include "minix.h"
+
+#define minix_swab16(doit, num)	((uint16_t) (doit ? swab16(num) : num))
+#define minix_swab32(doit, num)	((uint32_t) (doit ? swab32(num) : num))
+
+static int get_minix_version(const unsigned char *data, int *other_endian)
+{
+	struct minix_super_block *sb = (struct minix_super_block *) data;
+	struct minix3_super_block *sb3 = (struct minix3_super_block *) data;
+	int version = 0;
+
+	*other_endian = 0;
+
+	switch (sb->s_magic) {
+	case MINIX_SUPER_MAGIC:
+	case MINIX_SUPER_MAGIC2:
+		version = 1;
+		break;
+	case MINIX2_SUPER_MAGIC:
+	case MINIX2_SUPER_MAGIC2:
+		version = 2;
+		break;
+	default:
+		if (sb3->s_magic == MINIX3_SUPER_MAGIC)
+			version = 3;
+		break;
+	}
+
+	if (!version) {
+		*other_endian = 1;
+
+		switch (swab16(sb->s_magic)) {
+		case MINIX_SUPER_MAGIC:
+		case MINIX_SUPER_MAGIC2:
+			version = 1;
+			break;
+		case MINIX2_SUPER_MAGIC:
+		case MINIX2_SUPER_MAGIC2:
+			version = 2;
+			break;
+		default:
+			if (sb3->s_magic == MINIX3_SUPER_MAGIC)
+				version = 3;
+			break;
+		}
+	}
+	if (!version)
+		return -1;
+
+	DBG(LOWPROBE, ul_debug("minix version %d detected [%s]", version,
+#if defined(WORDS_BIGENDIAN)
+	*other_endian ? "LE" : "BE"
+#else
+	*other_endian ? "BE" : "LE"
+#endif
+	));
+	return version;
+}
+
+static int probe_minix(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	unsigned char *ext;
+	const unsigned char *data;
+	int version = 0, swabme = 0;
+
+	data = blkid_probe_get_buffer(pr, 1024,
+			max(sizeof(struct minix_super_block),
+			    sizeof(struct minix3_super_block)));
+	if (!data)
+		return errno ? -errno : 1;
+	version = get_minix_version(data, &swabme);
+	if (version < 1)
+		return 1;
+
+	if (version <= 2) {
+		struct minix_super_block *sb = (struct minix_super_block *) data;
+		int zones, ninodes, imaps, zmaps, firstz;
+
+		if (sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0)
+			return 1;
+
+		zones = version == 2 ? minix_swab32(swabme, sb->s_zones) :
+				       minix_swab16(swabme, sb->s_nzones);
+		ninodes = minix_swab16(swabme, sb->s_ninodes);
+		imaps   = minix_swab16(swabme, sb->s_imap_blocks);
+		zmaps   = minix_swab16(swabme, sb->s_zmap_blocks);
+		firstz  = minix_swab16(swabme, sb->s_firstdatazone);
+
+		/* sanity checks to be sure that the FS is really minix */
+		if (imaps * MINIX_BLOCK_SIZE * 8 < ninodes + 1)
+			return 1;
+		if (zmaps * MINIX_BLOCK_SIZE * 8 < zones - firstz + 1)
+			return 1;
+
+	} else if (version == 3) {
+		struct minix3_super_block *sb = (struct minix3_super_block *) data;
+
+		if (sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0)
+			return 1;
+	}
+
+	/* unfortunately, some parts of ext3 is sometimes possible to
+	 * interpreted as minix superblock. So check for extN magic
+	 * string. (For extN magic string and offsets see ext.c.)
+	 */
+	ext = blkid_probe_get_buffer(pr, 0x400 + 0x38, 2);
+	if (!ext)
+		return errno ? -errno : 1;
+	else if (memcmp(ext, "\123\357", 2) == 0)
+		return 1;
+
+	blkid_probe_sprintf_version(pr, "%d", version);
+	return 0;
+}
+
+const struct blkid_idinfo minix_idinfo =
+{
+	.name		= "minix",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_minix,
+	.magics		=
+	{
+		/* version 1 - LE */
+		{ .magic = "\177\023", .len = 2, .kboff = 1, .sboff = 0x10 },
+		{ .magic = "\217\023", .len = 2, .kboff = 1, .sboff = 0x10 },
+
+		/* version 1 - BE */
+		{ .magic = "\023\177", .len = 2, .kboff = 1, .sboff = 0x10 },
+		{ .magic = "\023\217", .len = 2, .kboff = 1, .sboff = 0x10 },
+
+		/* version 2 - LE */
+		{ .magic = "\150\044", .len = 2, .kboff = 1, .sboff = 0x10 },
+		{ .magic = "\170\044", .len = 2, .kboff = 1, .sboff = 0x10 },
+
+		/* version 2 - BE */
+		{ .magic = "\044\150", .len = 2, .kboff = 1, .sboff = 0x10 },
+		{ .magic = "\044\170", .len = 2, .kboff = 1, .sboff = 0x10 },
+
+		/* version 3 - LE */
+		{ .magic = "\132\115", .len = 2, .kboff = 1, .sboff = 0x18 },
+
+		/* version 3 - BE */
+		{ .magic = "\115\132", .len = 2, .kboff = 1, .sboff = 0x18 },
+
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/netware.c b/libblkid/src/superblocks/netware.c
new file mode 100644
index 0000000..af81cf5
--- /dev/null
+++ b/libblkid/src/superblocks/netware.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct netware_super_block {
+	uint8_t		SBH_Signature[4];
+	uint16_t	SBH_VersionMajor;
+	uint16_t	SBH_VersionMinor;
+	uint16_t	SBH_VersionMediaMajor;
+	uint16_t	SBH_VersionMediaMinor;
+	uint32_t	SBH_ItemsMoved;
+	uint8_t		SBH_InternalID[16];
+	uint32_t	SBH_PackedSize;
+	uint32_t	SBH_Checksum;
+	uint32_t	supersyncid;
+	int64_t		superlocation[4];
+	uint32_t	physSizeUsed;
+	uint32_t	sizeUsed;
+	uint32_t	superTimeStamp;
+	uint32_t	reserved0[1];
+	int64_t		SBH_LoggedPoolDataBlk;
+	int64_t		SBH_PoolDataBlk;
+	uint8_t		SBH_OldInternalID[16];
+	uint32_t	SBH_PoolToLVStartUTC;
+	uint32_t	SBH_PoolToLVEndUTC;
+	uint16_t	SBH_VersionMediaMajorCreate;
+	uint16_t	SBH_VersionMediaMinorCreate;
+	uint32_t	SBH_BlocksMoved;
+	uint32_t	SBH_TempBTSpBlk;
+	uint32_t	SBH_TempFTSpBlk;
+	uint32_t	SBH_TempFTSpBlk1;
+	uint32_t	SBH_TempFTSpBlk2;
+	uint32_t	nssMagicNumber;
+	uint32_t	poolClassID;
+	uint32_t	poolID;
+	uint32_t	createTime;
+	int64_t		SBH_LoggedVolumeDataBlk;
+	int64_t		SBH_VolumeDataBlk;
+	int64_t		SBH_SystemBeastBlkNum;
+	uint64_t	totalblocks;
+	uint16_t	SBH_Name[64];
+	uint8_t		SBH_VolumeID[16];
+	uint8_t		SBH_PoolID[16];
+	uint8_t		SBH_PoolInternalID[16];
+	uint64_t	SBH_Lsn;
+	uint32_t	SBH_SS_Enabled;
+	uint32_t	SBH_SS_CreateTime;
+	uint8_t		SBH_SS_OriginalPoolID[16];
+	uint8_t		SBH_SS_OriginalVolumeID[16];
+	uint8_t		SBH_SS_Guid[16];
+	uint16_t	SBH_SS_OriginalName[64];
+	uint32_t	reserved2[64-(2+46)];
+} __attribute__((__packed__));
+
+static int probe_netware(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct netware_super_block *nw;
+
+	nw = blkid_probe_get_sb(pr, mag, struct netware_super_block);
+	if (!nw)
+		return errno ? -errno : 1;
+
+	blkid_probe_set_uuid(pr, nw->SBH_PoolID);
+
+	blkid_probe_sprintf_version(pr, "%u.%02u",
+		 le16_to_cpu(nw->SBH_VersionMediaMajor),
+		 le16_to_cpu(nw->SBH_VersionMediaMinor));
+
+	return 0;
+}
+
+const struct blkid_idinfo netware_idinfo =
+{
+	.name		= "nss",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_netware,
+	.magics		=
+	{
+		{ .magic = "SPB5", .len = 4, .kboff = 4 },
+		{ NULL }
+	}
+};
+
+
diff --git a/libblkid/src/superblocks/nilfs.c b/libblkid/src/superblocks/nilfs.c
new file mode 100644
index 0000000..3f03901
--- /dev/null
+++ b/libblkid/src/superblocks/nilfs.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2010 by Jiro SEKIBA <jir@unicus.jp>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License
+ */
+#include <stddef.h>
+#include <string.h>
+
+#include "superblocks.h"
+#include "crc32.h"
+
+struct nilfs_super_block {
+	uint32_t	s_rev_level;
+	uint16_t	s_minor_rev_level;
+	uint16_t	s_magic;
+
+	uint16_t	s_bytes;
+
+	uint16_t	s_flags;
+	uint32_t	s_crc_seed;
+	uint32_t	s_sum;
+
+	uint32_t	s_log_block_size;
+
+	uint64_t	s_nsegments;
+	uint64_t	s_dev_size;
+	uint64_t	s_first_data_block;
+	uint32_t	s_blocks_per_segment;
+	uint32_t	s_r_segments_percentage;
+
+	uint64_t	s_last_cno;
+	uint64_t	s_last_pseg;
+	uint64_t	s_last_seq;
+	uint64_t	s_free_blocks_count;
+
+	uint64_t	s_ctime;
+
+	uint64_t	s_mtime;
+	uint64_t	s_wtime;
+	uint16_t	s_mnt_count;
+	uint16_t	s_max_mnt_count;
+	uint16_t	s_state;
+	uint16_t	s_errors;
+	uint64_t	s_lastcheck;
+
+	uint32_t	s_checkinterval;
+	uint32_t	s_creator_os;
+	uint16_t	s_def_resuid;
+	uint16_t	s_def_resgid;
+	uint32_t	s_first_ino;
+
+	uint16_t	s_inode_size;
+	uint16_t	s_dat_entry_size;
+	uint16_t	s_checkpoint_size;
+	uint16_t	s_segment_usage_size;
+
+	uint8_t		s_uuid[16];
+	char		s_volume_name[80];
+
+	uint32_t	s_c_interval;
+	uint32_t	s_c_block_max;
+	uint32_t	s_reserved[192];
+};
+
+#define NILFS_SB_MAGIC		0x3434
+#define NILFS_SB_OFFSET		0x400
+
+static int nilfs_valid_sb(blkid_probe pr, struct nilfs_super_block *sb)
+{
+	static unsigned char sum[4];
+	const int sumoff = offsetof(struct nilfs_super_block, s_sum);
+	size_t bytes;
+	uint32_t crc;
+
+	if (!sb || le16_to_cpu(sb->s_magic) != NILFS_SB_MAGIC)
+		return 0;
+
+	bytes = le16_to_cpu(sb->s_bytes);
+	crc = crc32(le32_to_cpu(sb->s_crc_seed), (unsigned char *)sb, sumoff);
+	crc = crc32(crc, sum, 4);
+	crc = crc32(crc, (unsigned char *)sb + sumoff + 4, bytes - sumoff - 4);
+
+	return blkid_probe_verify_csum(pr, crc, le32_to_cpu(sb->s_sum));
+}
+
+static int probe_nilfs2(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct nilfs_super_block *sb, *sbp, *sbb;
+	int valid[2], swp = 0;
+
+	/* primary */
+	sbp = (struct nilfs_super_block *) blkid_probe_get_buffer(
+			pr, NILFS_SB_OFFSET, sizeof(struct nilfs_super_block));
+	if (!sbp)
+		return errno ? -errno : 1;
+	/* backup */
+	sbb = (struct nilfs_super_block *) blkid_probe_get_buffer(
+			pr, ((pr->size / 0x200) - 8) * 0x200, sizeof(struct nilfs_super_block));
+	if (!sbb)
+		return errno ? -errno : 1;
+
+	/*
+	 * Compare two super blocks and set 1 in swp if the secondary
+	 * super block is valid and newer.  Otherwise, set 0 in swp.
+	 */
+	valid[0] = nilfs_valid_sb(pr, sbp);
+	valid[1] = nilfs_valid_sb(pr, sbb);
+	if (!valid[0] && !valid[1])
+		return 1;
+
+	swp = valid[1] && (!valid[0] ||
+			   le64_to_cpu(sbp->s_last_cno) >
+			   le64_to_cpu(sbb->s_last_cno));
+	sb = swp ? sbb : sbp;
+
+	DBG(LOWPROBE, ul_debug("nilfs2: primary=%d, backup=%d, swap=%d",
+				valid[0], valid[1], swp));
+
+	if (strlen(sb->s_volume_name))
+		blkid_probe_set_label(pr, (unsigned char *) sb->s_volume_name,
+				      sizeof(sb->s_volume_name));
+
+	blkid_probe_set_uuid(pr, sb->s_uuid);
+	blkid_probe_sprintf_version(pr, "%u", le32_to_cpu(sb->s_rev_level));
+
+	return 0;
+}
+
+const struct blkid_idinfo nilfs2_idinfo =
+{
+	.name		= "nilfs2",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_nilfs2,
+	/* default min.size is 128MiB, but 1MiB for "mkfs.nilfs2 -b 1024 -B 16" */
+	.minsz		= (1024 * 1024),
+	.magics		= BLKID_NONE_MAGIC
+};
diff --git a/libblkid/src/superblocks/ntfs.c b/libblkid/src/superblocks/ntfs.c
new file mode 100644
index 0000000..8ff9ccd
--- /dev/null
+++ b/libblkid/src/superblocks/ntfs.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "superblocks.h"
+
+struct ntfs_bios_parameters {
+	uint16_t	sector_size;	/* Size of a sector in bytes. */
+	uint8_t		sectors_per_cluster;	/* Size of a cluster in sectors. */
+	uint16_t	reserved_sectors;	/* zero */
+	uint8_t		fats;			/* zero */
+	uint16_t	root_entries;		/* zero */
+	uint16_t	sectors;		/* zero */
+	uint8_t		media_type;		/* 0xf8 = hard disk */
+	uint16_t	sectors_per_fat;	/* zero */
+	uint16_t	sectors_per_track;	/* irrelevant */
+	uint16_t	heads;			/* irrelevant */
+	uint32_t	hidden_sectors;		/* zero */
+	uint32_t	large_sectors;		/* zero */
+} __attribute__ ((__packed__));
+
+struct ntfs_super_block {
+	uint8_t		jump[3];
+	uint8_t		oem_id[8];	/* magic string */
+
+	struct ntfs_bios_parameters	bpb;
+
+	uint16_t	unused[2];
+	uint64_t	number_of_sectors;
+	uint64_t	mft_cluster_location;
+	uint64_t	mft_mirror_cluster_location;
+	int8_t		clusters_per_mft_record;
+	uint8_t		reserved1[3];
+	int8_t		cluster_per_index_record;
+	uint8_t		reserved2[3];
+	uint64_t	volume_serial;
+	uint32_t	checksum;
+} __attribute__((packed));
+
+struct master_file_table_record {
+	uint32_t	magic;
+	uint16_t	usa_ofs;
+	uint16_t	usa_count;
+	uint64_t	lsn;
+	uint16_t	sequence_number;
+	uint16_t	link_count;
+	uint16_t	attrs_offset;
+	uint16_t	flags;
+	uint32_t	bytes_in_use;
+	uint32_t	bytes_allocated;
+} __attribute__((__packed__));
+
+struct file_attribute {
+	uint32_t	type;
+	uint32_t	len;
+	uint8_t		non_resident;
+	uint8_t		name_len;
+	uint16_t	name_offset;
+	uint16_t	flags;
+	uint16_t	instance;
+	uint32_t	value_len;
+	uint16_t	value_offset;
+} __attribute__((__packed__));
+
+#define MFT_RECORD_VOLUME	3
+#define NTFS_MAX_CLUSTER_SIZE	(64 * 1024)
+
+enum {
+	MFT_RECORD_ATTR_VOLUME_NAME		= 0x60,
+	MFT_RECORD_ATTR_END			= 0xffffffff
+};
+
+static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct ntfs_super_block *ns;
+	struct master_file_table_record *mft;
+
+	uint32_t sectors_per_cluster, mft_record_size, attr_off;
+	uint16_t sector_size;
+	uint64_t nr_clusters, off;
+	unsigned char *buf_mft;
+
+	ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block);
+	if (!ns)
+		return errno ? -errno : 1;
+
+	/*
+	 * Check bios parameters block
+	 */
+	sector_size = le16_to_cpu(ns->bpb.sector_size);
+	sectors_per_cluster = ns->bpb.sectors_per_cluster;
+
+	if (sector_size < 256 || sector_size > 4096)
+		return 1;
+
+	switch (sectors_per_cluster) {
+	case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
+		break;
+	default:
+		return 1;
+	}
+
+	if ((uint16_t) le16_to_cpu(ns->bpb.sector_size) *
+			ns->bpb.sectors_per_cluster > NTFS_MAX_CLUSTER_SIZE)
+		return 1;
+
+	/* Unused fields must be zero */
+	if (le16_to_cpu(ns->bpb.reserved_sectors)
+	    || le16_to_cpu(ns->bpb.root_entries)
+	    || le16_to_cpu(ns->bpb.sectors)
+	    || le16_to_cpu(ns->bpb.sectors_per_fat)
+	    || le32_to_cpu(ns->bpb.large_sectors)
+	    || ns->bpb.fats)
+		return 1;
+
+	if ((uint8_t) ns->clusters_per_mft_record < 0xe1
+	    || (uint8_t) ns->clusters_per_mft_record > 0xf7) {
+
+		switch (ns->clusters_per_mft_record) {
+		case 1: case 2: case 4: case 8: case 16: case 32: case 64:
+			break;
+		default:
+			return 1;
+		}
+	}
+
+	if (ns->clusters_per_mft_record > 0)
+		mft_record_size = ns->clusters_per_mft_record *
+				  sectors_per_cluster * sector_size;
+	else
+		mft_record_size = 1 << (0 - ns->clusters_per_mft_record);
+
+	nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster;
+
+	if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) ||
+	    (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters))
+		return 1;
+
+
+	off = le64_to_cpu(ns->mft_cluster_location) * sector_size *
+		sectors_per_cluster;
+
+	DBG(LOWPROBE, ul_debug("NTFS: sector_size=%d, mft_record_size=%d, "
+			"sectors_per_cluster=%d, nr_clusters=%ju "
+			"cluster_offset=%jd",
+			(int) sector_size, mft_record_size,
+			sectors_per_cluster, nr_clusters,
+			off));
+
+	buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
+	if (!buf_mft)
+		return errno ? -errno : 1;
+
+	if (memcmp(buf_mft, "FILE", 4))
+		return 1;
+
+	off += MFT_RECORD_VOLUME * mft_record_size;
+
+	buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
+	if (!buf_mft)
+		return errno ? -errno : 1;
+
+	if (memcmp(buf_mft, "FILE", 4))
+		return 1;
+
+	mft = (struct master_file_table_record *) buf_mft;
+	attr_off = le16_to_cpu(mft->attrs_offset);
+
+	while (attr_off < mft_record_size &&
+	       attr_off <= le32_to_cpu(mft->bytes_allocated)) {
+
+		uint32_t attr_len;
+		struct file_attribute *attr;
+
+		attr = (struct file_attribute *) (buf_mft + attr_off);
+		attr_len = le32_to_cpu(attr->len);
+		if (!attr_len)
+			break;
+
+		if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_END)
+			break;
+		if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_VOLUME_NAME) {
+			unsigned int val_off = le16_to_cpu(attr->value_offset);
+			unsigned int val_len = le32_to_cpu(attr->value_len);
+			unsigned char *val = ((uint8_t *) attr) + val_off;
+
+			blkid_probe_set_utf8label(pr, val, val_len, BLKID_ENC_UTF16LE);
+			break;
+		}
+
+		if (UINT_MAX - attr_len < attr_off)
+			break;
+		attr_off += attr_len;
+	}
+
+	blkid_probe_sprintf_uuid(pr,
+			(unsigned char *) &ns->volume_serial,
+			sizeof(ns->volume_serial),
+			"%016" PRIX64, le64_to_cpu(ns->volume_serial));
+	return 0;
+}
+
+
+const struct blkid_idinfo ntfs_idinfo =
+{
+	.name		= "ntfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_ntfs,
+	.magics		=
+	{
+		{ .magic = "NTFS    ", .len = 8, .sboff = 3 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/nvidia_raid.c b/libblkid/src/superblocks/nvidia_raid.c
new file mode 100644
index 0000000..5db8ec2
--- /dev/null
+++ b/libblkid/src/superblocks/nvidia_raid.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct nv_metadata {
+	uint8_t		vendor[8];
+	uint32_t	size;
+	uint32_t	chksum;
+	uint16_t	version;
+} __attribute__((packed));
+
+#define NVIDIA_SIGNATURE		"NVIDIA"
+
+static int probe_nvraid(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	uint64_t off;
+	struct nv_metadata *nv;
+
+	if (pr->size < 0x10000)
+		return 1;
+	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+		return 1;
+
+	off = ((pr->size / 0x200) - 2) * 0x200;
+	nv = (struct nv_metadata *)
+		blkid_probe_get_buffer(pr,
+				off,
+				sizeof(struct nv_metadata));
+	if (!nv)
+		return errno ? -errno : 1;
+
+	if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0)
+		return 1;
+	if (blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(nv->version)) != 0)
+		return 1;
+	if (blkid_probe_set_magic(pr, off, sizeof(nv->vendor),
+				(unsigned char *) nv->vendor))
+		return 1;
+	return 0;
+}
+
+const struct blkid_idinfo nvraid_idinfo = {
+	.name		= "nvidia_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_nvraid,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/ocfs.c b/libblkid/src/superblocks/ocfs.c
new file mode 100644
index 0000000..3fe199d
--- /dev/null
+++ b/libblkid/src/superblocks/ocfs.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 1999, 2001 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct ocfs_volume_header {
+	unsigned char	minor_version[4];
+	unsigned char	major_version[4];
+	unsigned char	signature[128];
+	char		mount[128];
+	unsigned char   mount_len[2];
+} __attribute__((packed));
+
+struct ocfs_volume_label {
+	unsigned char	disk_lock[48];
+	char		label[64];
+	unsigned char	label_len[2];
+	unsigned char   vol_id[16];
+	unsigned char   vol_id_len[2];
+} __attribute__((packed));
+
+#define ocfsmajor(o) ( (uint32_t) o.major_version[0] \
+                   + (((uint32_t) o.major_version[1]) << 8) \
+                   + (((uint32_t) o.major_version[2]) << 16) \
+                   + (((uint32_t) o.major_version[3]) << 24))
+
+#define ocfsminor(o) ( (uint32_t) o.minor_version[0] \
+                   + (((uint32_t) o.minor_version[1]) << 8) \
+                   + (((uint32_t) o.minor_version[2]) << 16) \
+                   + (((uint32_t) o.minor_version[3]) << 24))
+
+#define ocfslabellen(o)	((uint32_t)o.label_len[0] + (((uint32_t) o.label_len[1]) << 8))
+#define ocfsmountlen(o)	((uint32_t)o.mount_len[0] + (((uint32_t) o.mount_len[1]) << 8))
+
+struct ocfs2_super_block {
+	uint8_t		i_signature[8];
+	uint32_t	i_generation;
+	int16_t		i_suballoc_slot;
+	uint16_t	i_suballoc_bit;
+	uint32_t	i_reserved0;
+	uint32_t	i_clusters;
+	uint32_t	i_uid;
+	uint32_t	i_gid;
+	uint64_t	i_size;
+	uint16_t	i_mode;
+	uint16_t	i_links_count;
+	uint32_t	i_flags;
+	uint64_t	i_atime;
+	uint64_t	i_ctime;
+	uint64_t	i_mtime;
+	uint64_t	i_dtime;
+	uint64_t	i_blkno;
+	uint64_t	i_last_eb_blk;
+	uint32_t	i_fs_generation;
+	uint32_t	i_atime_nsec;
+	uint32_t	i_ctime_nsec;
+	uint32_t	i_mtime_nsec;
+	uint64_t	i_reserved1[9];
+	uint64_t	i_pad1;
+	uint16_t	s_major_rev_level;
+	uint16_t	s_minor_rev_level;
+	uint16_t	s_mnt_count;
+	int16_t		s_max_mnt_count;
+	uint16_t	s_state;
+	uint16_t	s_errors;
+	uint32_t	s_checkinterval;
+	uint64_t	s_lastcheck;
+	uint32_t	s_creator_os;
+	uint32_t	s_feature_compat;
+	uint32_t	s_feature_incompat;
+	uint32_t	s_feature_ro_compat;
+	uint64_t	s_root_blkno;
+	uint64_t	s_system_dir_blkno;
+	uint32_t	s_blocksize_bits;
+	uint32_t	s_clustersize_bits;
+	uint16_t	s_max_slots;
+	uint16_t	s_reserved1;
+	uint32_t	s_reserved2;
+	uint64_t	s_first_cluster_group;
+	uint8_t		s_label[64];
+	uint8_t		s_uuid[16];
+} __attribute__((packed));
+
+struct oracle_asm_disk_label {
+	char dummy[32];
+	char dl_tag[8];
+	char dl_id[24];
+} __attribute__((packed));
+
+static int probe_ocfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	unsigned char *buf;
+	struct ocfs_volume_header ovh;
+	struct ocfs_volume_label ovl;
+	uint32_t maj, min;
+
+	/* header */
+	buf = blkid_probe_get_buffer(pr, mag->kboff << 10,
+			sizeof(struct ocfs_volume_header));
+	if (!buf)
+		return errno ? -errno : 1;
+	memcpy(&ovh, buf, sizeof(ovh));
+
+	/* label */
+	buf = blkid_probe_get_buffer(pr, (mag->kboff << 10) + 512,
+			sizeof(struct ocfs_volume_label));
+	if (!buf)
+		return errno ? -errno : 1;
+	memcpy(&ovl, buf, sizeof(ovl));
+
+	maj = ocfsmajor(ovh);
+	min = ocfsminor(ovh);
+
+	if (maj == 1)
+		blkid_probe_set_value(pr, "SEC_TYPE",
+				(unsigned char *) "ocfs1", sizeof("ocfs1"));
+	else if (maj >= 9)
+		blkid_probe_set_value(pr, "SEC_TYPE",
+				(unsigned char *) "ntocfs", sizeof("ntocfs"));
+
+	blkid_probe_set_label(pr, (unsigned char *) ovl.label,
+				ocfslabellen(ovl));
+	blkid_probe_set_value(pr, "MOUNT", (unsigned char *) ovh.mount,
+				ocfsmountlen(ovh));
+	blkid_probe_set_uuid(pr, ovl.vol_id);
+	blkid_probe_sprintf_version(pr, "%u.%u", maj, min);
+	return 0;
+}
+
+static int probe_ocfs2(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct ocfs2_super_block *osb;
+
+	osb = blkid_probe_get_sb(pr, mag, struct ocfs2_super_block);
+	if (!osb)
+		return errno ? -errno : 1;
+
+	blkid_probe_set_label(pr, (unsigned char *) osb->s_label, sizeof(osb->s_label));
+	blkid_probe_set_uuid(pr, osb->s_uuid);
+
+	blkid_probe_sprintf_version(pr, "%u.%u",
+		le16_to_cpu(osb->s_major_rev_level),
+		le16_to_cpu(osb->s_minor_rev_level));
+
+	return 0;
+}
+
+static int probe_oracleasm(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct oracle_asm_disk_label *dl;
+
+	dl = blkid_probe_get_sb(pr, mag, struct oracle_asm_disk_label);
+	if (!dl)
+		return errno ? -errno : 1;
+
+	blkid_probe_set_label(pr, (unsigned char *) dl->dl_id, sizeof(dl->dl_id));
+	return 0;
+}
+
+
+const struct blkid_idinfo ocfs_idinfo =
+{
+	.name		= "ocfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_ocfs,
+	.minsz		= 14000 * 1024,
+	.magics		=
+	{
+		{ .magic = "OracleCFS", .len = 9, .kboff = 8 },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo ocfs2_idinfo =
+{
+	.name		= "ocfs2",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_ocfs2,
+	.minsz		= 14000 * 1024,
+	.magics		=
+	{
+		{ .magic = "OCFSV2", .len = 6, .kboff = 1 },
+		{ .magic = "OCFSV2", .len = 6, .kboff = 2 },
+		{ .magic = "OCFSV2", .len = 6, .kboff = 4 },
+		{ .magic = "OCFSV2", .len = 6, .kboff = 8 },
+		{ NULL }
+	}
+};
+
+/* Oracle ASM (Automatic Storage Management) */
+const struct blkid_idinfo oracleasm_idinfo =
+{
+	.name		= "oracleasm",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_oracleasm,
+	.magics		=
+	{
+		{ .magic = "ORCLDISK", .len = 8, .sboff = 32 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/promise_raid.c b/libblkid/src/superblocks/promise_raid.c
new file mode 100644
index 0000000..678460a
--- /dev/null
+++ b/libblkid/src/superblocks/promise_raid.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct promise_metadata {
+	uint8_t	sig[24];
+};
+
+#define PDC_CONFIG_OFF		0x1200
+#define PDC_SIGNATURE		"Promise Technology, Inc."
+
+static int probe_pdcraid(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	unsigned int i;
+	static unsigned int sectors[] = {
+	  63, 255, 256, 16, 399, 591, 675, 735, 911, 974, 991, 951, 3087, 0
+	};
+
+	if (pr->size < 0x40000)
+		return 1;
+	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+		return 1;
+
+	for (i = 0; sectors[i] != 0; i++) {
+		uint64_t off;
+		struct promise_metadata *pdc;
+
+		off = ((pr->size / 0x200) - sectors[i]) * 0x200;
+		pdc = (struct promise_metadata *)
+				blkid_probe_get_buffer(pr,
+					off,
+					sizeof(struct promise_metadata));
+		if (!pdc)
+			return errno ? -errno : 1;
+
+		if (memcmp(pdc->sig, PDC_SIGNATURE,
+				sizeof(PDC_SIGNATURE) - 1) == 0) {
+
+			if (blkid_probe_set_magic(pr, off, sizeof(pdc->sig),
+						(unsigned char *) pdc->sig))
+				return 1;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+const struct blkid_idinfo pdcraid_idinfo = {
+	.name		= "promise_fasttrack_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_pdcraid,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/refs.c b/libblkid/src/superblocks/refs.c
new file mode 100644
index 0000000..ea81f20
--- /dev/null
+++ b/libblkid/src/superblocks/refs.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "superblocks.h"
+
+
+const struct blkid_idinfo refs_idinfo =
+{
+	.name		= "ReFS",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.magics		=
+	{
+		{ .magic = "\000\000\000ReFS\000", .len = 8 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/reiserfs.c b/libblkid/src/superblocks/reiserfs.c
new file mode 100644
index 0000000..edbaaa9
--- /dev/null
+++ b/libblkid/src/superblocks/reiserfs.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 1999, 2001 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct reiserfs_super_block {
+	uint32_t	rs_blocks_count;
+	uint32_t	rs_free_blocks;
+	uint32_t	rs_root_block;
+	uint32_t	rs_journal_block;
+	uint32_t	rs_journal_dev;
+	uint32_t	rs_orig_journal_size;
+	uint32_t	rs_dummy2[5];
+	uint16_t	rs_blocksize;
+	uint16_t	rs_dummy3[3];
+	unsigned char	rs_magic[12];
+	uint32_t	rs_dummy4[5];
+	unsigned char	rs_uuid[16];
+	char		rs_label[16];
+} __attribute__((packed));
+
+struct reiser4_super_block {
+	unsigned char	rs4_magic[16];
+	uint16_t	rs4_dummy[2];
+	unsigned char	rs4_uuid[16];
+	unsigned char	rs4_label[16];
+	uint64_t	rs4_dummy2;
+} __attribute__((packed));
+
+static int probe_reiser(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct reiserfs_super_block *rs;
+	unsigned int blocksize;
+
+	rs = blkid_probe_get_sb(pr, mag, struct reiserfs_super_block);
+	if (!rs)
+		return errno ? -errno : 1;
+
+	blocksize = le16_to_cpu(rs->rs_blocksize);
+
+	/* The blocksize must be at least 512B */
+	if ((blocksize >> 9) == 0)
+		return 1;
+
+	/* If the superblock is inside the journal, we have the wrong one */
+	if (mag->kboff / (blocksize >> 9) > le32_to_cpu(rs->rs_journal_block) / 2)
+		return 1;
+
+	/* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
+	if (mag->magic[6] == '2' || mag->magic[6] == '3') {
+		if (*rs->rs_label)
+			blkid_probe_set_label(pr,
+					(unsigned char *) rs->rs_label,
+					sizeof(rs->rs_label));
+		blkid_probe_set_uuid(pr, rs->rs_uuid);
+	}
+
+	if (mag->magic[6] == '3')
+		blkid_probe_set_version(pr, "JR");
+	else if (mag->magic[6] == '2')
+		blkid_probe_set_version(pr, "3.6");
+	else
+		blkid_probe_set_version(pr, "3.5");
+
+	return 0;
+}
+
+static int probe_reiser4(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct reiser4_super_block *rs4;
+
+	rs4 = blkid_probe_get_sb(pr, mag, struct reiser4_super_block);
+	if (!rs4)
+		return errno ? -errno : 1;
+
+	if (*rs4->rs4_label)
+		blkid_probe_set_label(pr, rs4->rs4_label, sizeof(rs4->rs4_label));
+	blkid_probe_set_uuid(pr, rs4->rs4_uuid);
+	blkid_probe_set_version(pr, "4");
+
+	return 0;
+}
+
+
+const struct blkid_idinfo reiser_idinfo =
+{
+	.name		= "reiserfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_reiser,
+	.minsz		= 128 * 1024,
+	.magics		=
+	{
+		{ .magic = "ReIsErFs",  .len = 8, .kboff = 8,  .sboff = 0x34 },
+		{ .magic = "ReIsEr2Fs", .len = 9, .kboff = 64, .sboff = 0x34 },
+		{ .magic = "ReIsEr3Fs", .len = 9, .kboff = 64, .sboff = 0x34 },
+		{ .magic = "ReIsErFs",  .len = 8, .kboff = 64, .sboff = 0x34 },
+		{ .magic = "ReIsErFs",  .len = 8, .kboff =  8, .sboff = 20   },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo reiser4_idinfo =
+{
+	.name		= "reiser4",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_reiser4,
+	.minsz		= 128 * 1024,
+	.magics		=
+	{
+		{ .magic = "ReIsEr4", .len = 7, .kboff = 64 },
+		{ NULL }
+	}
+};
+
+
+
+
diff --git a/libblkid/src/superblocks/romfs.c b/libblkid/src/superblocks/romfs.c
new file mode 100644
index 0000000..8e63c10
--- /dev/null
+++ b/libblkid/src/superblocks/romfs.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 1999, 2001 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct romfs_super_block {
+	unsigned char	ros_magic[8];
+	uint32_t	ros_dummy1[2];
+	unsigned char	ros_volume[16];
+} __attribute__((packed));
+
+static int probe_romfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct romfs_super_block *ros;
+
+	ros = blkid_probe_get_sb(pr, mag, struct romfs_super_block);
+	if (!ros)
+		return errno ? -errno : 1;
+
+	if (strlen((char *) ros->ros_volume))
+		blkid_probe_set_label(pr, ros->ros_volume,
+				sizeof(ros->ros_volume));
+	return 0;
+}
+
+const struct blkid_idinfo romfs_idinfo =
+{
+	.name		= "romfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_romfs,
+	.magics		=
+	{
+		{ .magic = "-rom1fs-", .len = 8 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/silicon_raid.c b/libblkid/src/superblocks/silicon_raid.c
new file mode 100644
index 0000000..edbefbc
--- /dev/null
+++ b/libblkid/src/superblocks/silicon_raid.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "superblocks.h"
+
+struct silicon_metadata {
+	uint8_t		unknown0[0x2E];
+	uint8_t		ascii_version[0x36 - 0x2E];
+	int8_t		diskname[0x56 - 0x36];
+	int8_t		unknown1[0x60 - 0x56];
+	uint32_t	magic;
+	int8_t		unknown1a[0x6C - 0x64];
+	uint32_t	array_sectors_low;
+	uint32_t	array_sectors_high;
+	int8_t		unknown2[0x78 - 0x74];
+	uint32_t	thisdisk_sectors;
+	int8_t		unknown3[0x100 - 0x7C];
+	int8_t		unknown4[0x104 - 0x100];
+	uint16_t	product_id;
+	uint16_t	vendor_id;
+	uint16_t	minor_ver;
+	uint16_t	major_ver;
+	uint8_t		seconds;
+	uint8_t		minutes;
+	uint8_t		hour;
+	uint8_t		day;
+	uint8_t		month;
+	uint8_t		year;
+	uint16_t	raid0_stride;
+	int8_t		unknown6[0x116 - 0x114];
+	uint8_t		disk_number;
+	uint8_t		type;			/* SILICON_TYPE_* */
+	int8_t		drives_per_striped_set;
+	int8_t		striped_set_number;
+	int8_t		drives_per_mirrored_set;
+	int8_t		mirrored_set_number;
+	uint32_t	rebuild_ptr_low;
+	uint32_t	rebuild_ptr_high;
+	uint32_t	incarnation_no;
+	uint8_t		member_status;
+	uint8_t		mirrored_set_state;	/* SILICON_MIRROR_* */
+	uint8_t		reported_device_location;
+	uint8_t		idechannel;
+	uint8_t		auto_rebuild;
+	uint8_t		unknown8;
+	uint8_t		text_type[0x13E - 0x12E];
+	uint16_t	checksum1;
+	int8_t		assumed_zeros[0x1FE - 0x140];
+	uint16_t	checksum2;
+} __attribute__((packed));
+
+#define SILICON_MAGIC		0x2F000000
+
+static uint16_t silraid_checksum(struct silicon_metadata *sil)
+{
+	int sum = 0;
+	unsigned short count = offsetof(struct silicon_metadata, checksum1) / 2;
+	uint16_t *p = (uint16_t *) sil;
+
+	while (count--) {
+		uint16_t x = *p++;
+		sum += le16_to_cpu(x);
+	}
+
+	return (-sum & 0xFFFF);
+}
+
+static int probe_silraid(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	uint64_t off;
+	struct silicon_metadata *sil;
+
+	if (pr->size < 0x10000)
+		return 1;
+	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+		return 1;
+
+	off = ((pr->size / 0x200) - 1) * 0x200;
+
+	sil = (struct silicon_metadata *)
+			blkid_probe_get_buffer(pr, off,
+				sizeof(struct silicon_metadata));
+	if (!sil)
+		return errno ? -errno : 1;
+
+	if (le32_to_cpu(sil->magic) != SILICON_MAGIC)
+		return 1;
+	if (sil->disk_number >= 8)
+		return 1;
+	if (!blkid_probe_verify_csum(pr, silraid_checksum(sil), le16_to_cpu(sil->checksum1)))
+		return 1;
+
+	if (blkid_probe_sprintf_version(pr, "%u.%u",
+				le16_to_cpu(sil->major_ver),
+				le16_to_cpu(sil->minor_ver)) != 0)
+		return 1;
+
+	if (blkid_probe_set_magic(pr,
+			off + offsetof(struct silicon_metadata, magic),
+			sizeof(sil->magic),
+			(unsigned char *) &sil->magic))
+		return 1;
+	return 0;
+}
+
+const struct blkid_idinfo silraid_idinfo = {
+	.name		= "silicon_medley_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_silraid,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/squashfs.c b/libblkid/src/superblocks/squashfs.c
new file mode 100644
index 0000000..8ed2838
--- /dev/null
+++ b/libblkid/src/superblocks/squashfs.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "bitops.h"	/* swab16() */
+#include "superblocks.h"
+
+struct sqsh_super_block {
+	uint32_t	s_magic;
+	uint32_t	inodes;
+	uint32_t	bytes_used_2;
+	uint32_t	uid_start_2;
+	uint32_t	guid_start_2;
+	uint32_t	inode_table_start_2;
+	uint32_t	directory_table_start_2;
+	uint16_t	s_major;
+	uint16_t	s_minor;
+} __attribute__((packed));
+
+static int probe_squashfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct sqsh_super_block *sq;
+	uint16_t major;
+	uint16_t minor;
+
+	sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block);
+	if (!sq)
+		return errno ? -errno : 1;
+
+	major = le16_to_cpu(sq->s_major);
+	minor = le16_to_cpu(sq->s_minor);
+	if (major < 4)
+		return 1;
+
+	blkid_probe_sprintf_version(pr, "%u.%u", major, minor);
+
+	return 0;
+}
+
+static int probe_squashfs3(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct sqsh_super_block *sq;
+	uint16_t major;
+	uint16_t minor;
+
+	sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block);
+	if (!sq)
+		return errno ? -errno : 1;
+
+	if (strcmp(mag->magic, "sqsh") == 0) {
+		major = be16_to_cpu(sq->s_major);
+		minor = be16_to_cpu(sq->s_minor);
+	} else {
+		major = le16_to_cpu(sq->s_major);
+		minor = le16_to_cpu(sq->s_minor);
+	}
+
+	if (major > 3)
+		return 1;
+
+	blkid_probe_sprintf_version(pr, "%u.%u", major, minor);
+
+	return 0;
+}
+
+const struct blkid_idinfo squashfs_idinfo =
+{
+	.name		= "squashfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_squashfs,
+	.magics		=
+	{
+		{ .magic = "hsqs", .len = 4 },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo squashfs3_idinfo =
+{
+	.name		= "squashfs3",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_squashfs3,
+	.magics		=
+	{
+		{ .magic = "sqsh", .len = 4 }, /* big endian */
+		{ .magic = "hsqs", .len = 4 }, /* little endian */
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/superblocks.c b/libblkid/src/superblocks/superblocks.c
new file mode 100644
index 0000000..80bd6e5
--- /dev/null
+++ b/libblkid/src/superblocks/superblocks.c
@@ -0,0 +1,813 @@
+/*
+ * superblocks.c - reads information from filesystem and raid superblocks
+ *
+ * Copyright (C) 2008-2009 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>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#include "superblocks.h"
+
+/**
+ * SECTION:superblocks
+ * @title: Superblocks probing
+ * @short_description: filesystems and raids superblocks probing.
+ *
+ * The library API has been originally designed for superblocks probing only.
+ * This is reason why some *deprecated* superblock specific functions don't use
+ * '_superblocks_' namespace in the function name. Please, don't use these
+ * functions in new code.
+ *
+ * The 'superblocks' probers support NAME=value (tags) interface only. The
+ * superblocks probing is enabled by default (and controlled by
+ * blkid_probe_enable_superblocks()).
+ *
+ * Currently supported tags:
+ *
+ * @TYPE: filesystem type
+ *
+ * @SEC_TYPE: secondary filesystem type
+ *
+ * @LABEL: filesystem label
+ *
+ * @LABEL_RAW: raw label from FS superblock
+ *
+ * @UUID: filesystem UUID (lower case)
+ *
+ * @UUID_SUB: subvolume uuid (e.g. btrfs)
+ *
+ * @LOGUUID: external log UUID (e.g. xfs)
+ *
+ * @UUID_RAW: raw UUID from FS superblock
+ *
+ * @EXT_JOURNAL: external journal UUID
+ *
+ * @USAGE:  usage string: "raid", "filesystem", ...
+ *
+ * @VERSION: filesystem version
+ *
+ * @MOUNT: cluster mount name (?) -- ocfs only
+ *
+ * @SBMAGIC: super block magic string
+ *
+ * @SBMAGIC_OFFSET: offset of SBMAGIC
+ *
+ * @FSSIZE: size of filessystem [not-implemented yet]
+ *
+ * @SYSTEM_ID: ISO9660 system identifier
+ *
+ * @PUBLISHER_ID: ISO9660 publisher identifier
+ *
+ * @APPLICATION_ID: ISO9660 application identifier
+ *
+ * @BOOT_SYSTEM_ID: ISO9660 boot system identifier
+ */
+
+static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn);
+static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn);
+
+static int blkid_probe_set_usage(blkid_probe pr, int usage);
+
+
+/*
+ * Superblocks chains probing functions
+ */
+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,
+
+	&bcache_idinfo,
+	&drbd_idinfo,
+	&drbdproxy_datalog_idinfo,
+	&lvm2_idinfo,
+	&lvm1_idinfo,
+	&snapcow_idinfo,
+	&verity_hash_idinfo,
+	&luks_idinfo,
+	&vmfs_volume_idinfo,
+
+	/* Filesystems */
+	&vfat_idinfo,
+	&swsuspend_idinfo,
+	&swap_idinfo,
+	&xfs_idinfo,
+	&xfs_log_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,
+	&refs_idinfo,
+	&cramfs_idinfo,
+	&romfs_idinfo,
+	&minix_idinfo,
+	&gfs_idinfo,
+	&gfs2_idinfo,
+	&ocfs_idinfo,
+	&ocfs2_idinfo,
+	&oracleasm_idinfo,
+	&vxfs_idinfo,
+	&squashfs_idinfo,
+	&squashfs3_idinfo,
+	&netware_idinfo,
+	&btrfs_idinfo,
+	&ubifs_idinfo,
+	&bfs_idinfo,
+	&vmfs_fs_idinfo,
+	&befs_idinfo,
+	&nilfs2_idinfo,
+	&exfat_idinfo,
+	&f2fs_idinfo
+};
+
+/*
+ * Driver definition
+ */
+const struct blkid_chaindrv superblocks_drv = {
+	.id           = BLKID_CHAIN_SUBLKS,
+	.name         = "superblocks",
+	.dflt_enabled = TRUE,
+	.dflt_flags   = BLKID_SUBLKS_DEFAULT,
+	.idinfos      = idinfos,
+	.nidinfos     = ARRAY_SIZE(idinfos),
+	.has_fltr     = TRUE,
+	.probe        = superblocks_probe,
+	.safeprobe    = superblocks_safeprobe,
+};
+
+/**
+ * blkid_probe_enable_superblocks:
+ * @pr: probe
+ * @enable: TRUE/FALSE
+ *
+ * Enables/disables the superblocks probing for non-binary interface.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_enable_superblocks(blkid_probe pr, int enable)
+{
+	if (!pr)
+		return -1;
+	pr->chains[BLKID_CHAIN_SUBLKS].enabled = enable;
+	return 0;
+}
+
+/**
+ * blkid_probe_set_superblocks_flags:
+ * @pr: prober
+ * @flags: BLKID_SUBLKS_* flags
+ *
+ * Sets probing flags to the superblocks prober. This function is optional, the
+ * default are BLKID_SUBLKS_DEFAULTS flags.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_set_superblocks_flags(blkid_probe pr, int flags)
+{
+	if (!pr)
+		return -1;
+
+	pr->chains[BLKID_CHAIN_SUBLKS].flags = flags;
+	return 0;
+}
+
+/**
+ * blkid_probe_reset_superblocks_filter:
+ * @pr: prober
+ *
+ * Resets superblocks probing filter
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_reset_superblocks_filter(blkid_probe pr)
+{
+	return __blkid_probe_reset_filter(pr, BLKID_CHAIN_SUBLKS);
+}
+
+/**
+ * blkid_probe_invert_superblocks_filter:
+ * @pr: prober
+ *
+ * Inverts superblocks probing filter
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_invert_superblocks_filter(blkid_probe pr)
+{
+	return __blkid_probe_invert_filter(pr, BLKID_CHAIN_SUBLKS);
+}
+
+/**
+ * blkid_probe_filter_superblocks_type:
+ * @pr: prober
+ * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
+ * @names: NULL terminated array of probing function names (e.g. "vfat").
+ *
+ *  %BLKID_FLTR_NOTIN  - probe for all items which are NOT IN @names;
+ *
+ *  %BLKID_FLTR_ONLYIN - probe for items which are IN @names
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_filter_superblocks_type(blkid_probe pr, int flag, char *names[])
+{
+	return __blkid_probe_filter_types(pr, BLKID_CHAIN_SUBLKS, flag, names);
+}
+
+/**
+ * blkid_probe_filter_superblocks_usage:
+ * @pr: prober
+ * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
+ * @usage: BLKID_USAGE_* flags
+ *
+ *  %BLKID_FLTR_NOTIN  - probe for all items which are NOT IN @usage;
+ *
+ *  %BLKID_FLTR_ONLYIN - probe for items which are IN @usage
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_filter_superblocks_usage(blkid_probe pr, int flag, int usage)
+{
+	unsigned long *fltr;
+	struct blkid_chain *chn;
+	size_t i;
+
+	fltr = blkid_probe_get_filter(pr, BLKID_CHAIN_SUBLKS, TRUE);
+	if (!fltr)
+		return -1;
+
+	chn = &pr->chains[BLKID_CHAIN_SUBLKS];
+
+	for (i = 0; i < chn->driver->nidinfos; i++) {
+		const struct blkid_idinfo *id = chn->driver->idinfos[i];
+
+		if (id->usage & usage) {
+			if (flag & BLKID_FLTR_NOTIN)
+				blkid_bmp_set_item(chn->fltr, i);
+		} else if (flag & BLKID_FLTR_ONLYIN)
+			blkid_bmp_set_item(chn->fltr, i);
+	}
+	DBG(LOWPROBE, ul_debug("a new probing usage-filter initialized"));
+	return 0;
+}
+
+/**
+ * blkid_known_fstype:
+ * @fstype: filesystem name
+ *
+ * Returns: 1 for known filesytems, or 0 for unknown filesystem.
+ */
+int blkid_known_fstype(const char *fstype)
+{
+	size_t 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;
+}
+
+/**
+ * blkid_superblocks_get_name:
+ * @idx: number >= 0
+ * @name: returns name of supported filesystem/raid (optional)
+ * @usage: returns BLKID_USAGE_* flags, (optional)
+ *
+ * Returns: -1 if @idx is out of range, or 0 on success.
+ */
+int blkid_superblocks_get_name(size_t idx, const char **name, int *usage)
+{
+	if (idx < ARRAY_SIZE(idinfos)) {
+		if (name)
+			*name = idinfos[idx]->name;
+		if (usage)
+			*usage = idinfos[idx]->usage;
+		return 0;
+	}
+	return -1;
+}
+
+/*
+ * The blkid_do_probe() backend.
+ */
+static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn)
+{
+	size_t i;
+	int rc = BLKID_PROBE_NONE;
+
+	if (!pr || chn->idx < -1)
+		return -EINVAL;
+
+	blkid_probe_chain_reset_vals(pr, chn);
+
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return BLKID_PROBE_NONE;
+
+	if (pr->size <= 0 || (pr->size <= 1024 && !S_ISCHR(pr->mode)))
+		/* Ignore very very small block devices or regular files (e.g.
+		 * extended partitions). Note that size of the UBI char devices
+		 * is 1 byte */
+		return BLKID_PROBE_NONE;
+
+	DBG(LOWPROBE, ul_debug("--> starting probing loop [SUBLKS idx=%d]",
+		chn->idx));
+
+	i = chn->idx < 0 ? 0 : chn->idx + 1U;
+
+	for ( ; i < ARRAY_SIZE(idinfos); i++) {
+		const struct blkid_idinfo *id;
+		const struct blkid_idmag *mag = NULL;
+		blkid_loff_t off = 0;
+
+		chn->idx = i;
+		id = idinfos[i];
+
+		if (chn->fltr && blkid_bmp_get_item(chn->fltr, i)) {
+			DBG(LOWPROBE, ul_debug("filter out: %s", id->name));
+			rc = BLKID_PROBE_NONE;
+			continue;
+		}
+
+		if (id->minsz && id->minsz > pr->size) {
+			rc = BLKID_PROBE_NONE;
+			continue;	/* the device is too small */
+		}
+
+		/* don't probe for RAIDs, swap or journal on CD/DVDs */
+		if ((id->usage & (BLKID_USAGE_RAID | BLKID_USAGE_OTHER)) &&
+		    blkid_probe_is_cdrom(pr)) {
+			rc = BLKID_PROBE_NONE;
+			continue;
+		}
+
+		/* don't probe for RAIDs on floppies */
+		if ((id->usage & BLKID_USAGE_RAID) && blkid_probe_is_tiny(pr)) {
+			rc = BLKID_PROBE_NONE;
+			continue;
+		}
+
+		DBG(LOWPROBE, ul_debug("[%zd] %s:", i, id->name));
+
+		rc = blkid_probe_get_idmag(pr, id, &off, &mag);
+		if (rc < 0)
+			break;
+		if (rc != BLKID_PROBE_OK)
+			continue;
+
+		/* final check by probing function */
+		if (id->probefunc) {
+			DBG(LOWPROBE, ul_debug("\tcall probefunc()"));
+			rc = id->probefunc(pr, mag);
+			if (rc != BLKID_PROBE_OK) {
+				blkid_probe_chain_reset_vals(pr, chn);
+				if (rc < 0)
+					break;
+				continue;
+			}
+		}
+
+		/* all cheks passed */
+		if (chn->flags & BLKID_SUBLKS_TYPE)
+			rc = blkid_probe_set_value(pr, "TYPE",
+				(unsigned char *) id->name,
+				strlen(id->name) + 1);
+
+		if (!rc)
+			rc = blkid_probe_set_usage(pr, id->usage);
+
+		if (!rc && mag)
+			rc = blkid_probe_set_magic(pr, off, mag->len,
+					(unsigned char *) mag->magic);
+		if (rc) {
+			blkid_probe_chain_reset_vals(pr, chn);
+			DBG(LOWPROBE, ul_debug("failed to set result -- ignore"));
+			continue;
+		}
+
+		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [SUBLKS idx=%d]",
+			id->name, chn->idx));
+		return BLKID_PROBE_OK;
+	}
+
+	DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed=%d) [SUBLKS idx=%d]",
+			rc, chn->idx));
+	return rc;
+}
+
+/*
+ * 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.
+ *
+ * The function does not check for filesystems when a RAID or crypto signature
+ * is detected.  The function also does not check for collision between RAIDs
+ * and crypto devices. The first detected RAID or crypto device is returned.
+ *
+ * The function does not probe for ambivalent results on very small devices
+ * (e.g. floppies), on small devices the first detected filesystem is returned.
+ */
+static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
+{
+	struct blkid_prval vals[BLKID_NVALS_SUBLKS];
+	int nvals = BLKID_NVALS_SUBLKS;
+	int idx = -1;
+	int count = 0;
+	int intol = 0;
+	int rc;
+
+	if (pr->flags & BLKID_FL_NOSCAN_DEV)
+		return BLKID_PROBE_NONE;
+
+	while ((rc = superblocks_probe(pr, chn)) == 0) {
+
+		if (blkid_probe_is_tiny(pr) && !count)
+			return BLKID_PROBE_OK;	/* floppy or so -- returns the first result. */
+
+		count++;
+
+		if (chn->idx >= 0 &&
+		    idinfos[chn->idx]->usage & (BLKID_USAGE_RAID | BLKID_USAGE_CRYPTO))
+			break;
+
+		if (chn->idx >= 0 &&
+		    !(idinfos[chn->idx]->flags & BLKID_IDINFO_TOLERANT))
+			intol++;
+
+		if (count == 1) {
+			/* save the first result */
+			nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals);
+			idx = chn->idx;
+		}
+	}
+
+	if (rc < 0)
+		return rc;		/* error */
+
+	if (count > 1 && intol) {
+		DBG(LOWPROBE, ul_debug("ERROR: superblocks chain: "
+			       "ambivalent result detected (%d filesystems)!",
+			       count));
+		return -2;		/* error, ambivalent result (more FS) */
+	}
+	if (!count)
+		return BLKID_PROBE_NONE;
+
+	if (idx != -1) {
+		/* restore the first result */
+		blkid_probe_chain_reset_vals(pr, chn);
+		blkid_probe_append_vals(pr, vals, nvals);
+		chn->idx = idx;
+	}
+
+	/*
+	 * The RAID device could be partitioned. The problem are RAID1 devices
+	 * where the partition table is visible from underlaying devices. We
+	 * have to ignore such partition tables.
+	 */
+	if (chn->idx >= 0 && idinfos[chn->idx]->usage & BLKID_USAGE_RAID)
+		pr->prob_flags |= BLKID_PROBE_FL_IGNORE_PT;
+
+	return BLKID_PROBE_OK;
+}
+
+int blkid_probe_set_version(blkid_probe pr, const char *version)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+	if (chn->flags & BLKID_SUBLKS_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, ...)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+	int rc = 0;
+
+	if (chn->flags & BLKID_SUBLKS_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)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+	char *u = NULL;
+
+	if (!(chn->flags & BLKID_SUBLKS_USAGE))
+		return 0;
+
+	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_id_label(blkid_probe pr, const char *name,
+			     unsigned char *data, size_t len)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+	struct blkid_prval *v;
+
+	if (!(chn->flags & BLKID_SUBLKS_LABEL))
+		return 0;
+
+	v = blkid_probe_assign_value(pr, name);
+	if (!v)
+		return -1;
+
+	if (len >= BLKID_PROBVAL_BUFSIZ)
+		len = BLKID_PROBVAL_BUFSIZ - 1;			/* make a space for \0 */
+
+	memcpy(v->data, data, len);
+	v->data[len] = '\0';
+
+	/* remove white spaces */
+	v->len = blkid_rtrim_whitespace(v->data) + 1;
+	if (v->len > 1)
+		v->len = blkid_ltrim_whitespace(v->data) + 1;
+
+	if (v->len <= 1)
+		blkid_probe_reset_last_value(pr);		/* ignore empty */
+	return 0;
+}
+
+int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+	struct blkid_prval *v;
+	if (len > BLKID_PROBVAL_BUFSIZ)
+		len = BLKID_PROBVAL_BUFSIZ;
+
+	if ((chn->flags & BLKID_SUBLKS_LABELRAW) &&
+	    blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
+		return -1;
+	if (!(chn->flags & BLKID_SUBLKS_LABEL))
+		return 0;
+	v = blkid_probe_assign_value(pr, "LABEL");
+	if (!v)
+		return -1;
+
+	if (len == BLKID_PROBVAL_BUFSIZ)
+		len--;				/* make a space for \0 */
+
+	memcpy(v->data, label, len);
+	v->data[len] = '\0';
+
+	v->len = blkid_rtrim_whitespace(v->data) + 1;
+	if (v->len == 1)
+		blkid_probe_reset_last_value(pr);
+	return 0;
+}
+
+int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
+				size_t len, int enc)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+	struct blkid_prval *v;
+
+	if ((chn->flags & BLKID_SUBLKS_LABELRAW) &&
+	    blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
+		return -1;
+	if (!(chn->flags & BLKID_SUBLKS_LABEL))
+		return 0;
+	v = blkid_probe_assign_value(pr, "LABEL");
+	if (!v)
+		return -1;
+
+	blkid_encode_to_utf8(enc, v->data, sizeof(v->data), label, len);
+	v->len = blkid_rtrim_whitespace(v->data) + 1;
+	if (v->len == 1)
+		blkid_probe_reset_last_value(pr);
+	return 0;
+}
+
+int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
+				size_t len, const char *fmt, ...)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+	int rc = -1;
+	va_list ap;
+
+	if (len > BLKID_PROBVAL_BUFSIZ)
+		len = BLKID_PROBVAL_BUFSIZ;
+
+	if (blkid_uuid_is_empty(uuid, len))
+		return 0;
+
+	if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
+	    blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0)
+		return -1;
+	if (!(chn->flags & BLKID_SUBLKS_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) {
+		size_t i;
+		struct blkid_prval *v = __blkid_probe_get_value(pr,
+						blkid_probe_numof_values(pr));
+		if (v) {
+			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_chain *chn = blkid_probe_get_chain(pr);
+	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 ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
+	    blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0)
+		return -1;
+	if (!(chn->flags & BLKID_SUBLKS_UUID))
+		return 0;
+
+	v = blkid_probe_assign_value(pr, "UUID");
+	if (v) {
+		if (len == BLKID_PROBVAL_BUFSIZ)
+			len--;		/* make a space for \0 */
+
+		memcpy((char *) v->data, str, len);
+		v->data[len] = '\0';
+		v->len = len + 1;
+		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_chain *chn = blkid_probe_get_chain(pr);
+	struct blkid_prval *v;
+
+	if (blkid_uuid_is_empty(uuid, 16))
+		return 0;
+
+	if (!name) {
+		if ((chn->flags & BLKID_SUBLKS_UUIDRAW) &&
+		    blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0)
+			return -1;
+		if (!(chn->flags & BLKID_SUBLKS_UUID))
+			return 0;
+
+		v = blkid_probe_assign_value(pr, "UUID");
+	} else
+		v = blkid_probe_assign_value(pr, name);
+
+	blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data));
+	v->len = 37;
+
+	return 0;
+}
+
+int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid)
+{
+	return blkid_probe_set_uuid_as(pr, uuid, NULL);
+}
+
+/**
+ * blkid_probe_set_request:
+ * @pr: probe
+ * @flags: BLKID_PROBREQ_* (deprecated) or BLKID_SUBLKS_* flags
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ *
+ * Deprecated: Use blkid_probe_set_superblocks_flags().
+ */
+int blkid_probe_set_request(blkid_probe pr, int flags)
+{
+	return blkid_probe_set_superblocks_flags(pr, flags);
+}
+
+/**
+ * blkid_probe_reset_filter:
+ * @pr: prober
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ *
+ * Deprecated: Use blkid_probe_reset_superblocks_filter().
+ */
+int blkid_probe_reset_filter(blkid_probe pr)
+{
+	return __blkid_probe_reset_filter(pr, BLKID_CHAIN_SUBLKS);
+}
+
+/**
+ * blkid_probe_invert_filter:
+ * @pr: prober
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ *
+ * Deprecated: Use blkid_probe_invert_superblocks_filter().
+ */
+int blkid_probe_invert_filter(blkid_probe pr)
+{
+	return __blkid_probe_invert_filter(pr, BLKID_CHAIN_SUBLKS);
+}
+
+/**
+ * blkid_probe_filter_types
+ * @pr: prober
+ * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
+ * @names: NULL terminated array of probing function names (e.g. "vfat").
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ *
+ * Deprecated: Use blkid_probe_filter_superblocks_types().
+ */
+int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[])
+{
+	return __blkid_probe_filter_types(pr, BLKID_CHAIN_SUBLKS, flag, names);
+}
+
+/**
+ * blkid_probe_filter_usage
+ * @pr: prober
+ * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
+ * @usage: BLKID_USAGE_* flags
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ *
+ * Deprecated: Use blkid_probe_filter_superblocks_usage().
+ */
+int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage)
+{
+	return blkid_probe_filter_superblocks_usage(pr, flag, usage);
+}
+
+
diff --git a/libblkid/src/superblocks/superblocks.h b/libblkid/src/superblocks/superblocks.h
new file mode 100644
index 0000000..3bbfb9c
--- /dev/null
+++ b/libblkid/src/superblocks/superblocks.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef _BLKID_SUPERBLOCKS_H
+#define _BLKID_SUPERBLOCKS_H
+
+#include "blkidP.h"
+
+extern const struct blkid_idinfo cramfs_idinfo;
+extern const struct blkid_idinfo swap_idinfo;
+extern const struct blkid_idinfo swsuspend_idinfo;
+extern const struct blkid_idinfo adraid_idinfo;
+extern const struct blkid_idinfo ddfraid_idinfo;
+extern const struct blkid_idinfo iswraid_idinfo;
+extern const struct blkid_idinfo jmraid_idinfo;
+extern const struct blkid_idinfo lsiraid_idinfo;
+extern const struct blkid_idinfo nvraid_idinfo;
+extern const struct blkid_idinfo pdcraid_idinfo;
+extern const struct blkid_idinfo silraid_idinfo;
+extern const struct blkid_idinfo viaraid_idinfo;
+extern const struct blkid_idinfo linuxraid_idinfo;
+extern const struct blkid_idinfo ext4dev_idinfo;
+extern const struct blkid_idinfo ext4_idinfo;
+extern const struct blkid_idinfo ext3_idinfo;
+extern const struct blkid_idinfo ext2_idinfo;
+extern const struct blkid_idinfo jbd_idinfo;
+extern const struct blkid_idinfo jfs_idinfo;
+extern const struct blkid_idinfo xfs_idinfo;
+extern const struct blkid_idinfo xfs_log_idinfo;
+extern const struct blkid_idinfo gfs_idinfo;
+extern const struct blkid_idinfo gfs2_idinfo;
+extern const struct blkid_idinfo romfs_idinfo;
+extern const struct blkid_idinfo ocfs_idinfo;
+extern const struct blkid_idinfo ocfs2_idinfo;
+extern const struct blkid_idinfo oracleasm_idinfo;
+extern const struct blkid_idinfo reiser_idinfo;
+extern const struct blkid_idinfo reiser4_idinfo;
+extern const struct blkid_idinfo hfs_idinfo;
+extern const struct blkid_idinfo hfsplus_idinfo;
+extern const struct blkid_idinfo ntfs_idinfo;
+extern const struct blkid_idinfo refs_idinfo;
+extern const struct blkid_idinfo iso9660_idinfo;
+extern const struct blkid_idinfo udf_idinfo;
+extern const struct blkid_idinfo vxfs_idinfo;
+extern const struct blkid_idinfo minix_idinfo;
+extern const struct blkid_idinfo vfat_idinfo;
+extern const struct blkid_idinfo ufs_idinfo;
+extern const struct blkid_idinfo hpfs_idinfo;
+extern const struct blkid_idinfo lvm2_idinfo;
+extern const struct blkid_idinfo lvm1_idinfo;
+extern const struct blkid_idinfo snapcow_idinfo;
+extern const struct blkid_idinfo verity_hash_idinfo;
+extern const struct blkid_idinfo luks_idinfo;
+extern const struct blkid_idinfo highpoint37x_idinfo;
+extern const struct blkid_idinfo highpoint45x_idinfo;
+extern const struct blkid_idinfo squashfs_idinfo;
+extern const struct blkid_idinfo squashfs3_idinfo;
+extern const struct blkid_idinfo netware_idinfo;
+extern const struct blkid_idinfo sysv_idinfo;
+extern const struct blkid_idinfo xenix_idinfo;
+extern const struct blkid_idinfo btrfs_idinfo;
+extern const struct blkid_idinfo ubifs_idinfo;
+extern const struct blkid_idinfo zfs_idinfo;
+extern const struct blkid_idinfo bfs_idinfo;
+extern const struct blkid_idinfo vmfs_volume_idinfo;
+extern const struct blkid_idinfo vmfs_fs_idinfo;
+extern const struct blkid_idinfo drbd_idinfo;
+extern const struct blkid_idinfo drbdproxy_datalog_idinfo;
+extern const struct blkid_idinfo befs_idinfo;
+extern const struct blkid_idinfo nilfs2_idinfo;
+extern const struct blkid_idinfo exfat_idinfo;
+extern const struct blkid_idinfo f2fs_idinfo;
+extern const struct blkid_idinfo bcache_idinfo;
+
+/*
+ * superblock functions
+ */
+extern int blkid_probe_set_version(blkid_probe pr, const char *version);
+extern int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...)
+		__attribute__ ((__format__ (__printf__, 2, 3)));
+
+extern int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len);
+extern int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
+                size_t len, int enc);
+extern int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
+                size_t len, const char *fmt, ...)
+		__attribute__ ((__format__ (__printf__, 4, 5)));
+extern int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len);
+
+extern int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid);
+extern int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name);
+
+extern int blkid_probe_set_id_label(blkid_probe pr, const char *name,
+			     unsigned char *data, size_t len);
+
+#endif /* _BLKID_SUPERBLOCKS_H */
diff --git a/libblkid/src/superblocks/swap.c b/libblkid/src/superblocks/swap.c
new file mode 100644
index 0000000..3f21391
--- /dev/null
+++ b/libblkid/src/superblocks/swap.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+/* linux-2.6/include/linux/swap.h */
+struct swap_header_v1_2 {
+     /*	char		bootbits[1024];	*/ /* Space for disklabel etc. */
+	uint32_t	version;
+	uint32_t	lastpage;
+	uint32_t	nr_badpages;
+	unsigned char	uuid[16];
+	unsigned char	volume[16];
+	uint32_t	padding[117];
+	uint32_t	badpages[1];
+} __attribute__((packed));
+
+#define PAGESIZE_MIN	0xff6	/* 4086 (arm, i386, ...) */
+#define PAGESIZE_MAX	0xfff6	/* 65526 (ia64) */
+
+#define TOI_MAGIC_STRING	"\xed\xc3\x02\xe9\x98\x56\xe5\x0c"
+#define TOI_MAGIC_STRLEN	(sizeof(TOI_MAGIC_STRING) - 1)
+
+static int swap_set_info(blkid_probe pr, const char *version)
+{
+	struct swap_header_v1_2 *hdr;
+
+	/* Swap header always located at offset of 1024 bytes */
+	hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024,
+				sizeof(struct swap_header_v1_2));
+	if (!hdr)
+		return errno ? -errno : 1;
+
+	/* SWAPSPACE2 - check for wrong version or zeroed pagecount */
+	if (strcmp(version, "1") == 0) {
+		if (hdr->version != 1 && swab32(hdr->version) != 1) {
+			DBG(LOWPROBE, ul_debug("incorrect swap version"));
+			return 1;
+		}
+		if (hdr->lastpage == 0) {
+			DBG(LOWPROBE, ul_debug("not set last swap page"));
+			return 1;
+		}
+	}
+
+	/* arbitrary sanity check.. is there any garbage down there? */
+	if (hdr->padding[32] == 0 && hdr->padding[33] == 0) {
+		if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume,
+				sizeof(hdr->volume)) < 0)
+			return 1;
+		if (blkid_probe_set_uuid(pr, hdr->uuid) < 0)
+			return 1;
+	}
+
+	blkid_probe_set_version(pr, version);
+	return 0;
+}
+
+static int probe_swap(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	unsigned char *buf;
+
+	if (!mag)
+		return 1;
+
+	/* TuxOnIce keeps valid swap header at the end of the 1st page */
+	buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN);
+	if (!buf)
+		return errno ? -errno : 1;
+
+	if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0)
+		return 1;	/* Ignore swap signature, it's TuxOnIce */
+
+	if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) {
+		/* swap v0 doesn't support LABEL or UUID */
+		blkid_probe_set_version(pr, "0");
+		return 0;
+
+	} else if (!memcmp(mag->magic, "SWAPSPACE2", mag->len))
+		return swap_set_info(pr, "1");
+
+	return 1;
+}
+
+static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	if (!mag)
+		return 1;
+	if (!memcmp(mag->magic, "S1SUSPEND", mag->len))
+		return swap_set_info(pr, "s1suspend");
+	if (!memcmp(mag->magic, "S2SUSPEND", mag->len))
+		return swap_set_info(pr, "s2suspend");
+	if (!memcmp(mag->magic, "ULSUSPEND", mag->len))
+		return swap_set_info(pr, "ulsuspend");
+	if (!memcmp(mag->magic, TOI_MAGIC_STRING, mag->len))
+		return swap_set_info(pr, "tuxonice");
+	if (!memcmp(mag->magic, "LINHIB0001", mag->len))
+		return swap_set_info(pr, "linhib0001");
+
+	return 1;	/* no signature detected */
+}
+
+const struct blkid_idinfo swap_idinfo =
+{
+	.name		= "swap",
+	.usage		= BLKID_USAGE_OTHER,
+	.probefunc	= probe_swap,
+	.minsz		= 10 * 4096,	/* 10 pages */
+	.magics		=
+	{
+		{ "SWAP-SPACE", 10, 0,  0xff6 },
+		{ "SWAPSPACE2", 10, 0,  0xff6 },
+		{ "SWAP-SPACE", 10, 0, 0x1ff6 },
+		{ "SWAPSPACE2", 10, 0, 0x1ff6 },
+		{ "SWAP-SPACE", 10, 0, 0x3ff6 },
+		{ "SWAPSPACE2", 10, 0, 0x3ff6 },
+		{ "SWAP-SPACE", 10, 0, 0x7ff6 },
+		{ "SWAPSPACE2", 10, 0, 0x7ff6 },
+		{ "SWAP-SPACE", 10, 0, 0xfff6 },
+		{ "SWAPSPACE2", 10, 0, 0xfff6 },
+		{ NULL }
+	}
+};
+
+
+const struct blkid_idinfo swsuspend_idinfo =
+{
+	.name		= "swsuspend",
+	.usage		= BLKID_USAGE_OTHER,
+	.probefunc	= probe_swsuspend,
+	.minsz		= 10 * 4096,	/* 10 pages */
+	.magics		=
+	{
+		{ TOI_MAGIC_STRING, TOI_MAGIC_STRLEN, 0, 0 },
+		{ "S1SUSPEND", 9, 0, 0xff6 },
+		{ "S2SUSPEND", 9, 0, 0xff6 },
+		{ "ULSUSPEND", 9, 0, 0xff6 },
+		{ "LINHIB0001",10,0, 0xff6 },
+
+		{ "S1SUSPEND", 9, 0, 0x1ff6 },
+		{ "S2SUSPEND", 9, 0, 0x1ff6 },
+		{ "ULSUSPEND", 9, 0, 0x1ff6 },
+		{ "LINHIB0001",10,0, 0x1ff6 },
+
+		{ "S1SUSPEND", 9, 0, 0x3ff6 },
+		{ "S2SUSPEND", 9, 0, 0x3ff6 },
+		{ "ULSUSPEND", 9, 0, 0x3ff6 },
+		{ "LINHIB0001",10,0, 0x3ff6 },
+
+		{ "S1SUSPEND", 9, 0, 0x7ff6 },
+		{ "S2SUSPEND", 9, 0, 0x7ff6 },
+		{ "ULSUSPEND", 9, 0, 0x7ff6 },
+		{ "LINHIB0001",10,0, 0x7ff6 },
+
+		{ "S1SUSPEND", 9, 0, 0xfff6 },
+		{ "S2SUSPEND", 9, 0, 0xfff6 },
+		{ "ULSUSPEND", 9, 0, 0xfff6 },
+		{ "LINHIB0001",10,0, 0xfff6 },
+
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/sysv.c b/libblkid/src/superblocks/sysv.c
new file mode 100644
index 0000000..4b34591
--- /dev/null
+++ b/libblkid/src/superblocks/sysv.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * This is written from sratch according to Linux kernel fs/sysv/super.c file.
+ * It seems that sysv probing code in libvolume_id and also in the original
+ * blkid is useless.
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "superblocks.h"
+
+#define XENIX_NICINOD				100
+#define XENIX_NICFREE				100
+
+struct xenix_super_block {
+	uint16_t	s_isize;
+	uint32_t	s_fsize;
+	uint16_t	s_nfree;
+	uint32_t	s_free[XENIX_NICFREE];
+	uint16_t	s_ninode;
+	uint16_t	s_inode[XENIX_NICINOD];
+	uint8_t		s_flock;
+	uint8_t		s_ilock;
+	uint8_t		s_fmod;
+	uint8_t		s_ronly;
+	uint32_t	s_time;
+	uint32_t	s_tfree;
+	uint16_t	s_tinode;
+	uint16_t	s_dinfo[4];
+	uint8_t		s_fname[6];
+	uint8_t		s_fpack[6];
+	uint8_t		s_clean;
+	uint8_t		s_fill[371];
+	uint32_t	s_magic;
+	uint32_t	s_type;
+} __attribute__((packed));
+
+
+#define SYSV_NICINOD			100
+#define SYSV_NICFREE			50
+
+struct sysv_super_block
+{
+	uint16_t	s_isize;
+	uint16_t	s_pad0;
+	uint32_t	s_fsize;
+	uint16_t	s_nfree;
+	uint16_t	s_pad1;
+	uint32_t	s_free[SYSV_NICFREE];
+	uint16_t	s_ninode;
+	uint16_t	s_pad2;
+	uint16_t	s_inode[SYSV_NICINOD];
+	uint8_t		s_flock;
+	uint8_t		s_ilock;
+	uint8_t		s_fmod;
+	uint8_t		s_ronly;
+	uint32_t	s_time;
+	uint16_t	s_dinfo[4];
+	uint32_t	s_tfree;
+	uint16_t	s_tinode;
+	uint16_t	s_pad3;
+	uint8_t		s_fname[6];
+	uint8_t		s_fpack[6];
+	uint32_t	s_fill[12];
+	uint32_t	s_state;
+	uint32_t	s_magic;
+	uint32_t	s_type;
+};
+
+static int probe_xenix(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct xenix_super_block *sb;
+
+	sb = blkid_probe_get_sb(pr, mag, struct xenix_super_block);
+	if (!sb)
+		return errno ? -errno : 1;
+	blkid_probe_set_label(pr, sb->s_fname, sizeof(sb->s_fname));
+	return 0;
+}
+
+#define SYSV_BLOCK_SIZE	1024
+
+/* Note that we don't probe for Coherent FS, this FS does not have
+ * magic string. (It requires to probe fname/fpack field..)
+ */
+static int probe_sysv(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct sysv_super_block *sb;
+	int blocks[] = {0, 9, 15, 18};
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(blocks); i++) {
+		int off = blocks[i] * SYSV_BLOCK_SIZE + SYSV_BLOCK_SIZE/2;
+
+		sb = (struct sysv_super_block *)
+			blkid_probe_get_buffer(pr,
+					off,
+					sizeof(struct sysv_super_block));
+		if (!sb)
+			return errno ? -errno : 1;
+
+		if (sb->s_magic == cpu_to_le32(0xfd187e20) ||
+		    sb->s_magic == cpu_to_be32(0xfd187e20)) {
+
+			if (blkid_probe_set_label(pr, sb->s_fname,
+						sizeof(sb->s_fname)))
+				return 1;
+
+			if (blkid_probe_set_magic(pr,
+					off + offsetof(struct sysv_super_block,
+								s_magic),
+					sizeof(sb->s_magic),
+					(unsigned char *) &sb->s_magic))
+				return 1;
+
+			return 0;
+		}
+	}
+	return 1;
+}
+
+const struct blkid_idinfo xenix_idinfo =
+{
+	.name		= "xenix",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_xenix,
+	.magics		=
+	{
+		{ .magic = "\x2b\x55\x44", .len = 3, .kboff = 1, .sboff = 0x400 },
+		{ .magic = "\x44\x55\x2b", .len = 3, .kboff = 1, .sboff = 0x400 },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo sysv_idinfo =
+{
+	.name		= "sysv",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_sysv,
+
+	/* SYSV is BE and LE and superblock could be on four positions. It's
+	 * simpler to probe for the magic string by .probefunc().
+	 */
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/superblocks/ubifs.c b/libblkid/src/superblocks/ubifs.c
new file mode 100644
index 0000000..dc84260
--- /dev/null
+++ b/libblkid/src/superblocks/ubifs.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2009 Corentin Chary <corentincj@iksaif.net>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+/*
+ * struct ubifs_ch - common header node.
+ * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
+ * @crc: CRC-32 checksum of the node header
+ * @sqnum: sequence number
+ * @len: full node length
+ * @node_type: node type
+ * @group_type: node group type
+ * @padding: reserved for future, zeroes
+ *
+ * Every UBIFS node starts with this common part. If the node has a key, the
+ * key always goes next.
+ */
+struct ubifs_ch {
+	uint32_t magic;
+	uint32_t crc;
+	uint64_t sqnum;
+	uint32_t len;
+	uint8_t node_type;
+	uint8_t group_type;
+	uint8_t padding[2];
+} __attribute__ ((packed));
+
+/*
+ * struct ubifs_sb_node - superblock node.
+ * @ch: common header
+ * @padding: reserved for future, zeroes
+ * @key_hash: type of hash function used in keys
+ * @key_fmt: format of the key
+ * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc)
+ * @min_io_size: minimal input/output unit size
+ * @leb_size: logical eraseblock size in bytes
+ * @leb_cnt: count of LEBs used by file-system
+ * @max_leb_cnt: maximum count of LEBs used by file-system
+ * @max_bud_bytes: maximum amount of data stored in buds
+ * @log_lebs: log size in logical eraseblocks
+ * @lpt_lebs: number of LEBs used for lprops table
+ * @orph_lebs: number of LEBs used for recording orphans
+ * @jhead_cnt: count of journal heads
+ * @fanout: tree fanout (max. number of links per indexing node)
+ * @lsave_cnt: number of LEB numbers in LPT's save table
+ * @fmt_version: UBIFS on-flash format version
+ * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
+ * @padding1: reserved for future, zeroes
+ * @rp_uid: reserve pool UID
+ * @rp_gid: reserve pool GID
+ * @rp_size: size of the reserved pool in bytes
+ * @padding2: reserved for future, zeroes
+ * @time_gran: time granularity in nanoseconds
+ * @uuid: UUID generated when the file system image was created
+ * @ro_compat_version: UBIFS R/O compatibility version
+ */
+struct ubifs_sb_node {
+	struct ubifs_ch ch;
+	uint8_t padding[2];
+	uint8_t key_hash;
+	uint8_t key_fmt;
+	uint32_t flags;
+	uint32_t min_io_size;
+	uint32_t leb_size;
+	uint32_t leb_cnt;
+	uint32_t max_leb_cnt;
+	uint64_t max_bud_bytes;
+	uint32_t log_lebs;
+	uint32_t lpt_lebs;
+	uint32_t orph_lebs;
+	uint32_t jhead_cnt;
+	uint32_t fanout;
+	uint32_t lsave_cnt;
+	uint32_t fmt_version;
+	uint16_t default_compr;
+	uint8_t padding1[2];
+	uint32_t rp_uid;
+	uint32_t rp_gid;
+	uint64_t rp_size;
+	uint32_t time_gran;
+	uint8_t uuid[16];
+	uint32_t ro_compat_version;
+	uint8_t padding2[3968];
+} __attribute__ ((packed));
+
+static int probe_ubifs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct ubifs_sb_node *sb;
+
+	sb = blkid_probe_get_sb(pr, mag, struct ubifs_sb_node);
+	if (!sb)
+		return errno ? -errno : 1;
+
+	blkid_probe_set_uuid(pr, sb->uuid);
+	blkid_probe_sprintf_version(pr, "w%dr%d",
+			le32_to_cpu(sb->fmt_version),
+			le32_to_cpu(sb->ro_compat_version));
+	return 0;
+}
+
+const struct blkid_idinfo ubifs_idinfo =
+{
+	.name		= "ubifs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_ubifs,
+	.magics		=
+	{
+		{ .magic = "\x31\x18\x10\x06", .len = 4 },
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/udf.c b/libblkid/src/superblocks/udf.c
new file mode 100644
index 0000000..5cde3cc
--- /dev/null
+++ b/libblkid/src/superblocks/udf.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+#include "iso9660.h"
+
+struct volume_descriptor {
+	struct descriptor_tag {
+		uint16_t	id;
+		uint16_t	version;
+		uint8_t		checksum;
+		uint8_t		reserved;
+		uint16_t	serial;
+		uint16_t	crc;
+		uint16_t	crc_len;
+		uint32_t	location;
+	} __attribute__((packed)) tag;
+
+	union {
+		struct anchor_descriptor {
+			uint32_t	length;
+			uint32_t	location;
+		} __attribute__((packed)) anchor;
+
+		struct primary_descriptor {
+			uint32_t	seq_num;
+			uint32_t	desc_num;
+			struct dstring {
+				uint8_t	clen;
+				uint8_t	c[31];
+			} __attribute__((packed)) ident;
+		} __attribute__((packed)) primary;
+
+	} __attribute__((packed)) type;
+
+} __attribute__((packed));
+
+struct volume_structure_descriptor {
+	uint8_t		type;
+	uint8_t		id[5];
+	uint8_t		version;
+} __attribute__((packed));
+
+#define UDF_VSD_OFFSET			0x8000LL
+
+static int probe_udf(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct volume_descriptor *vd;
+	struct volume_structure_descriptor *vsd;
+	unsigned int bs;
+	unsigned int pbs[2];
+	unsigned int b;
+	unsigned int type;
+	unsigned int count;
+	unsigned int loc;
+	unsigned int i;
+
+	/* The block size of a UDF filesystem is that of the underlying
+	 * storage; we check later on for the special case of image files,
+	 * which may have the 2048-byte block size of optical media. */
+	pbs[0] = blkid_probe_get_sectorsize(pr);
+	pbs[1] = 0x800;
+
+	/* check for a Volume Structure Descriptor (VSD); each is
+	 * 2048 bytes long */
+	for (b = 0; b < 0x8000; b += 0x800) {
+		vsd = (struct volume_structure_descriptor *)
+			blkid_probe_get_buffer(pr,
+					UDF_VSD_OFFSET + b,
+					sizeof(*vsd));
+		if (!vsd)
+			return errno ? -errno : 1;
+		if (vsd->id[0] != '\0')
+			goto nsr;
+	}
+	return 1;
+
+nsr:
+	/* search the list of VSDs for a NSR descriptor */
+	for (b = 0; b < 64; b++) {
+		vsd = (struct volume_structure_descriptor *)
+			blkid_probe_get_buffer(pr,
+					UDF_VSD_OFFSET + ((blkid_loff_t) b * 0x800),
+					sizeof(*vsd));
+		if (!vsd)
+			return errno ? -errno : 1;
+		if (vsd->id[0] == '\0')
+			return 1;
+		if (memcmp(vsd->id, "NSR02", 5) == 0)
+			goto anchor;
+		if (memcmp(vsd->id, "NSR03", 5) == 0)
+			goto anchor;
+	}
+	return 1;
+
+anchor:
+	/* read Anchor Volume Descriptor (AVDP), checking block size */
+	for (i = 0; i < 2; i++) {
+		vd = (struct volume_descriptor *)
+			blkid_probe_get_buffer(pr, 256 * pbs[i], sizeof(*vd));
+		if (!vd)
+			return errno ? -errno : 1;
+
+		type = le16_to_cpu(vd->tag.id);
+		if (type == 2) /* TAG_ID_AVDP */
+			goto real_blksz;
+	}
+	return 0;
+
+real_blksz:
+	/* Use the actual block size from here on out */
+	bs = pbs[i];
+
+	/* get descriptor list address and block count */
+	count = le32_to_cpu(vd->type.anchor.length) / bs;
+	loc = le32_to_cpu(vd->type.anchor.location);
+
+	/* check if the list is usable */
+	for (b = 0; b < count; b++) {
+		vd = (struct volume_descriptor *)
+			blkid_probe_get_buffer(pr,
+					(blkid_loff_t) (loc + b) * bs,
+					sizeof(*vd));
+		if (!vd)
+			return errno ? -errno : 1;
+	}
+
+	/* Try extract all possible ISO9660 information -- if there is
+	 * usable LABEL in ISO header then use it, otherwise read UDF
+	 * specific LABEL */
+	if (probe_iso9660(pr, mag) == 0 &&
+	    __blkid_probe_lookup_value(pr, "LABEL") != NULL)
+		return 0;
+
+	/* Read UDF label */
+	for (b = 0; b < count; b++) {
+		vd = (struct volume_descriptor *)
+			blkid_probe_get_buffer(pr,
+					(blkid_loff_t) (loc + b) * bs,
+					sizeof(*vd));
+		if (!vd)
+			return errno ? -errno : 1;
+		type = le16_to_cpu(vd->tag.id);
+		if (type == 0)
+			break;
+		if (le32_to_cpu(vd->tag.location) != loc + b)
+			break;
+		if (type == 1) { /* TAG_ID_PVD */
+			uint8_t clen = vd->type.primary.ident.clen;
+
+			if (clen == 8)
+				blkid_probe_set_label(pr,
+						vd->type.primary.ident.c, 31);
+			else if (clen == 16)
+				blkid_probe_set_utf8label(pr,
+						vd->type.primary.ident.c,
+						31, BLKID_ENC_UTF16BE);
+
+			if (clen == 8 || clen == 16)
+				break;
+		}
+	}
+
+	return 0;
+}
+
+
+const struct blkid_idinfo udf_idinfo =
+{
+	.name		= "udf",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_udf,
+	.flags		= BLKID_IDINFO_TOLERANT,
+	.magics		=
+	{
+		{ .magic = "BEA01", .len = 5, .kboff = 32, .sboff = 1 },
+		{ .magic = "BOOT2", .len = 5, .kboff = 32, .sboff = 1 },
+		{ .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 },
+		{ .magic = "CDW02", .len = 5, .kboff = 32, .sboff = 1 },
+		{ .magic = "NSR02", .len = 5, .kboff = 32, .sboff = 1 },
+		{ .magic = "NSR03", .len = 5, .kboff = 32, .sboff = 1 },
+		{ .magic = "TEA01", .len = 5, .kboff = 32, .sboff = 1 },
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/ufs.c b/libblkid/src/superblocks/ufs.c
new file mode 100644
index 0000000..6ef2acd
--- /dev/null
+++ b/libblkid/src/superblocks/ufs.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "superblocks.h"
+
+struct ufs_super_block {
+	uint32_t	fs_link;
+	uint32_t	fs_rlink;
+	uint32_t	fs_sblkno;
+	uint32_t	fs_cblkno;
+	uint32_t	fs_iblkno;
+	uint32_t	fs_dblkno;
+	uint32_t	fs_cgoffset;
+	uint32_t	fs_cgmask;
+	uint32_t	fs_time;
+	uint32_t	fs_size;
+	uint32_t	fs_dsize;
+	uint32_t	fs_ncg;
+	uint32_t	fs_bsize;
+	uint32_t	fs_fsize;
+	uint32_t	fs_frag;
+	uint32_t	fs_minfree;
+	uint32_t	fs_rotdelay;
+	uint32_t	fs_rps;
+	uint32_t	fs_bmask;
+	uint32_t	fs_fmask;
+	uint32_t	fs_bshift;
+	uint32_t	fs_fshift;
+	uint32_t	fs_maxcontig;
+	uint32_t	fs_maxbpg;
+	uint32_t	fs_fragshift;
+	uint32_t	fs_fsbtodb;
+	uint32_t	fs_sbsize;
+	uint32_t	fs_csmask;
+	uint32_t	fs_csshift;
+	uint32_t	fs_nindir;
+	uint32_t	fs_inopb;
+	uint32_t	fs_nspf;
+	uint32_t	fs_optim;
+	uint32_t	fs_npsect_state;
+	uint32_t	fs_interleave;
+	uint32_t	fs_trackskew;
+	uint32_t	fs_id[2];
+	uint32_t	fs_csaddr;
+	uint32_t	fs_cssize;
+	uint32_t	fs_cgsize;
+	uint32_t	fs_ntrak;
+	uint32_t	fs_nsect;
+	uint32_t	fs_spc;
+	uint32_t	fs_ncyl;
+	uint32_t	fs_cpg;
+	uint32_t	fs_ipg;
+	uint32_t	fs_fpg;
+	struct ufs_csum {
+		uint32_t	cs_ndir;
+		uint32_t	cs_nbfree;
+		uint32_t	cs_nifree;
+		uint32_t	cs_nffree;
+	} fs_cstotal;
+	int8_t		fs_fmod;
+	int8_t		fs_clean;
+	int8_t		fs_ronly;
+	int8_t		fs_flags;
+	union {
+		struct {
+			int8_t	fs_fsmnt[512];
+			uint32_t	fs_cgrotor;
+			uint32_t	fs_csp[31];
+			uint32_t	fs_maxcluster;
+			uint32_t	fs_cpc;
+			uint16_t	fs_opostbl[16][8];
+		} fs_u1;
+		struct {
+			int8_t		fs_fsmnt[468];
+			uint8_t		fs_volname[32];
+			uint64_t	fs_swuid;
+			int32_t		fs_pad;
+			uint32_t	fs_cgrotor;
+			uint32_t	fs_ocsp[28];
+			uint32_t	fs_contigdirs;
+			uint32_t	fs_csp;
+			uint32_t	fs_maxcluster;
+			uint32_t	fs_active;
+			int32_t		fs_old_cpc;
+			int32_t		fs_maxbsize;
+			int64_t		fs_sparecon64[17];
+			int64_t		fs_sblockloc;
+			struct ufs2_csum_total {
+				uint64_t	cs_ndir;
+				uint64_t	cs_nbfree;
+				uint64_t	cs_nifree;
+				uint64_t	cs_nffree;
+				uint64_t	cs_numclusters;
+				uint64_t	cs_spare[3];
+			} fs_cstotal;
+			struct ufs_timeval {
+				int32_t		tv_sec;
+				int32_t		tv_usec;
+			} fs_time;
+			int64_t		fs_size;
+			int64_t		fs_dsize;
+			uint64_t	fs_csaddr;
+			int64_t		fs_pendingblocks;
+			int32_t		fs_pendinginodes;
+		} __attribute__((packed)) fs_u2;
+	}  fs_u11;
+	union {
+		struct {
+			int32_t		fs_sparecon[53];
+			int32_t		fs_reclaim;
+			int32_t		fs_sparecon2[1];
+			int32_t		fs_state;
+			uint32_t	fs_qbmask[2];
+			uint32_t	fs_qfmask[2];
+		} fs_sun;
+		struct {
+			int32_t		fs_sparecon[53];
+			int32_t		fs_reclaim;
+			int32_t		fs_sparecon2[1];
+			uint32_t	fs_npsect;
+			uint32_t	fs_qbmask[2];
+			uint32_t	fs_qfmask[2];
+		} fs_sunx86;
+		struct {
+			int32_t		fs_sparecon[50];
+			int32_t		fs_contigsumsize;
+			int32_t		fs_maxsymlinklen;
+			int32_t		fs_inodefmt;
+			uint32_t	fs_maxfilesize[2];
+			uint32_t	fs_qbmask[2];
+			uint32_t	fs_qfmask[2];
+			int32_t		fs_state;
+		} fs_44;
+	} fs_u2;
+	int32_t		fs_postblformat;
+	int32_t		fs_nrpos;
+	int32_t		fs_postbloff;
+	int32_t		fs_rotbloff;
+	uint32_t	fs_magic;
+	uint8_t		fs_space[1];
+} __attribute__((packed));
+
+#define UFS_MAGIC			0x00011954
+#define UFS2_MAGIC			0x19540119
+#define UFS_MAGIC_FEA			0x00195612
+#define UFS_MAGIC_LFN			0x00095014
+#define UFS_MAGIC_SEC			0x00612195
+#define UFS_MAGIC_4GB			0x05231994
+
+static int probe_ufs(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	int offsets[] = { 0, 8, 64, 256 };
+	uint32_t mags[] = {
+		UFS2_MAGIC, UFS_MAGIC, UFS_MAGIC_FEA, UFS_MAGIC_LFN,
+		UFS_MAGIC_SEC, UFS_MAGIC_4GB
+	};
+	size_t i;
+	uint32_t magic;
+	struct ufs_super_block *ufs;
+	int is_be;
+
+	for (i = 0; i < ARRAY_SIZE(offsets); i++) {
+		uint32_t magLE, magBE;
+		size_t y;
+
+		ufs = (struct ufs_super_block *)
+				blkid_probe_get_buffer(pr,
+					offsets[i] * 1024,
+					sizeof(struct ufs_super_block));
+		if (!ufs)
+			return errno ? -errno : 1;
+
+		magBE = be32_to_cpu(ufs->fs_magic);
+		magLE = le32_to_cpu(ufs->fs_magic);
+
+		for (y = 0; y < ARRAY_SIZE(mags); y++) {
+			if (magLE == mags[y] || magBE == mags[y]) {
+				magic = mags[y];
+				is_be = (magBE == mags[y]);
+				goto found;
+			}
+		}
+	}
+
+	return 1;
+
+found:
+	if (magic == UFS2_MAGIC) {
+		blkid_probe_set_version(pr, "2");
+		blkid_probe_set_label(pr, ufs->fs_u11.fs_u2.fs_volname,
+				sizeof(ufs->fs_u11.fs_u2.fs_volname));
+	} else
+		blkid_probe_set_version(pr, "1");
+	if (ufs->fs_id[0] || ufs->fs_id[1])
+	{
+		if (is_be)
+			blkid_probe_sprintf_uuid(pr,
+					 (unsigned char *) &ufs->fs_id,
+						 sizeof(ufs->fs_id),
+						 "%08x%08x",
+						 be32_to_cpu(ufs->fs_id[0]),
+						 be32_to_cpu(ufs->fs_id[1]));
+		else
+			blkid_probe_sprintf_uuid(pr,
+					 (unsigned char *) &ufs->fs_id,
+						 sizeof(ufs->fs_id),
+						 "%08x%08x",
+						 le32_to_cpu(ufs->fs_id[0]),
+						 le32_to_cpu(ufs->fs_id[1]));
+	}
+
+	if (blkid_probe_set_magic(pr,
+			(offsets[i] * 1024) +
+				offsetof(struct ufs_super_block, fs_magic),
+			sizeof(ufs->fs_magic),
+			(unsigned char *) &ufs->fs_magic))
+		return 1;
+
+	return 0;
+}
+
+/*
+ * According to libvolume_id the UFS superblock could be on four positions.
+ * The original libblkid has checked one position (.kboff=8) only.
+ *
+ * We know four UFS magic strings and UFS could be both little-endian and
+ * big-endian. ... so we have:
+ *
+ *	4 position * 4 string * 2 version = 32 magic strings
+ *
+ * It seems simpler to check for these string in probing function that hardcode
+ * all in the .magic array.
+ */
+const struct blkid_idinfo ufs_idinfo =
+{
+	.name		= "ufs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_ufs,
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/superblocks/vfat.c b/libblkid/src/superblocks/vfat.c
new file mode 100644
index 0000000..f38deac
--- /dev/null
+++ b/libblkid/src/superblocks/vfat.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+/* Yucky misaligned values */
+struct vfat_super_block {
+/* 00*/	unsigned char	vs_ignored[3];
+/* 03*/	unsigned char	vs_sysid[8];
+/* 0b*/	unsigned char	vs_sector_size[2];
+/* 0d*/	uint8_t		vs_cluster_size;
+/* 0e*/	uint16_t	vs_reserved;
+/* 10*/	uint8_t		vs_fats;
+/* 11*/	unsigned char	vs_dir_entries[2];
+/* 13*/	unsigned char	vs_sectors[2];
+/* 15*/	unsigned char	vs_media;
+/* 16*/	uint16_t	vs_fat_length;
+/* 18*/	uint16_t	vs_secs_track;
+/* 1a*/	uint16_t	vs_heads;
+/* 1c*/	uint32_t	vs_hidden;
+/* 20*/	uint32_t	vs_total_sect;
+/* 24*/	uint32_t	vs_fat32_length;
+/* 28*/	uint16_t	vs_flags;
+/* 2a*/	uint8_t		vs_version[2];
+/* 2c*/	uint32_t	vs_root_cluster;
+/* 30*/	uint16_t	vs_fsinfo_sector;
+/* 32*/	uint16_t	vs_backup_boot;
+/* 34*/	uint16_t	vs_reserved2[6];
+/* 40*/	unsigned char	vs_unknown[3];
+/* 43*/	unsigned char	vs_serno[4];
+/* 47*/	unsigned char	vs_label[11];
+/* 52*/	unsigned char   vs_magic[8];
+/* 5a*/	unsigned char	vs_dummy2[0x1fe - 0x5a];
+/*1fe*/	unsigned char	vs_pmagic[2];
+} __attribute__((packed));
+
+/* Yucky misaligned values */
+struct msdos_super_block {
+/* 00*/	unsigned char	ms_ignored[3];
+/* 03*/	unsigned char	ms_sysid[8];
+/* 0b*/	unsigned char	ms_sector_size[2];
+/* 0d*/	uint8_t		ms_cluster_size;
+/* 0e*/	uint16_t	ms_reserved;
+/* 10*/	uint8_t		ms_fats;
+/* 11*/	unsigned char	ms_dir_entries[2];
+/* 13*/	unsigned char	ms_sectors[2]; /* =0 iff V3 or later */
+/* 15*/	unsigned char	ms_media;
+/* 16*/	uint16_t	ms_fat_length; /* Sectors per FAT */
+/* 18*/	uint16_t	ms_secs_track;
+/* 1a*/	uint16_t	ms_heads;
+/* 1c*/	uint32_t	ms_hidden;
+/* V3 BPB */
+/* 20*/	uint32_t	ms_total_sect; /* iff ms_sectors == 0 */
+/* V4 BPB */
+/* 24*/	unsigned char	ms_unknown[3]; /* Phys drive no., resvd, V4 sig (0x29) */
+/* 27*/	unsigned char	ms_serno[4];
+/* 2b*/	unsigned char	ms_label[11];
+/* 36*/	unsigned char   ms_magic[8];
+/* 3e*/	unsigned char	ms_dummy2[0x1fe - 0x3e];
+/*1fe*/	unsigned char	ms_pmagic[2];
+} __attribute__((packed));
+
+struct vfat_dir_entry {
+	uint8_t		name[11];
+	uint8_t		attr;
+	uint16_t	time_creat;
+	uint16_t	date_creat;
+	uint16_t	time_acc;
+	uint16_t	date_acc;
+	uint16_t	cluster_high;
+	uint16_t	time_write;
+	uint16_t	date_write;
+	uint16_t	cluster_low;
+	uint32_t	size;
+} __attribute__((packed));
+
+struct fat32_fsinfo {
+	uint8_t signature1[4];
+	uint32_t reserved1[120];
+	uint8_t signature2[4];
+	uint32_t free_clusters;
+	uint32_t next_cluster;
+	uint32_t reserved2[4];
+} __attribute__((packed));
+
+/* maximum number of clusters */
+#define FAT12_MAX 0xFF4
+#define FAT16_MAX 0xFFF4
+#define FAT32_MAX 0x0FFFFFF6
+
+#define FAT_ATTR_VOLUME_ID		0x08
+#define FAT_ATTR_DIR			0x10
+#define FAT_ATTR_LONG_NAME		0x0f
+#define FAT_ATTR_MASK			0x3f
+#define FAT_ENTRY_FREE			0xe5
+
+static const char *no_name = "NO NAME    ";
+
+#define unaligned_le16(x) \
+		(((unsigned char *) x)[0] + (((unsigned char *) x)[1] << 8))
+
+/*
+ * Look for LABEL (name) in the FAT root directory.
+ */
+static unsigned char *search_fat_label(blkid_probe pr,
+				uint64_t offset, uint32_t entries)
+{
+	struct vfat_dir_entry *ent, *dir = NULL;
+	uint32_t i;
+
+	DBG(LOWPROBE, ul_debug("\tlook for label in root-dir "
+			"(entries: %d, offset: %jd)", entries, offset));
+
+	if (!blkid_probe_is_tiny(pr)) {
+		/* large disk, read whole root directory */
+		dir = (struct vfat_dir_entry *)
+			blkid_probe_get_buffer(pr,
+					offset,
+					(blkid_loff_t) entries *
+						sizeof(struct vfat_dir_entry));
+		if (!dir)
+			return NULL;
+	}
+
+	for (i = 0; i < entries; i++) {
+		/*
+		 * The root directory could be relatively large (4-16kB).
+		 * Fortunately, the LABEL is usually the first entry in the
+		 * directory. On tiny disks we call read() per entry.
+		 */
+		if (!dir)
+			ent = (struct vfat_dir_entry *)
+				blkid_probe_get_buffer(pr,
+					(blkid_loff_t) offset + (i *
+						sizeof(struct vfat_dir_entry)),
+					sizeof(struct vfat_dir_entry));
+		else
+			ent = &dir[i];
+
+		if (!ent || ent->name[0] == 0x00)
+			break;
+
+		if ((ent->name[0] == FAT_ENTRY_FREE) ||
+		    (ent->cluster_high != 0 || ent->cluster_low != 0) ||
+		    ((ent->attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME))
+			continue;
+
+		if ((ent->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) ==
+		    FAT_ATTR_VOLUME_ID) {
+			DBG(LOWPROBE, ul_debug("\tfound fs LABEL at entry %d", i));
+			return ent->name;
+		}
+	}
+	return NULL;
+}
+
+static int fat_valid_superblock(const struct blkid_idmag *mag,
+			struct msdos_super_block *ms,
+			struct vfat_super_block *vs,
+			uint32_t *cluster_count, uint32_t *fat_size)
+{
+	uint16_t sector_size, dir_entries, reserved;
+	uint32_t sect_count, __fat_size, dir_size, __cluster_count, fat_length;
+	uint32_t max_count;
+
+	/* extra check for FATs without magic strings */
+	if (mag->len <= 2) {
+		/* Old floppies have a valid MBR signature */
+		if (ms->ms_pmagic[0] != 0x55 || ms->ms_pmagic[1] != 0xAA)
+			return 0;
+
+		/*
+		 * OS/2 and apparently DFSee will place a FAT12/16-like
+		 * pseudo-superblock in the first 512 bytes of non-FAT
+		 * filesystems --- at least JFS and HPFS, and possibly others.
+		 * So we explicitly check for those filesystems at the
+		 * FAT12/16 filesystem magic field identifier, and if they are
+		 * present, we rule this out as a FAT filesystem, despite the
+		 * FAT-like pseudo-header.
+		 */
+		if ((memcmp(ms->ms_magic, "JFS     ", 8) == 0) ||
+		    (memcmp(ms->ms_magic, "HPFS    ", 8) == 0))
+			return 0;
+	}
+
+	/* fat counts(Linux kernel expects at least 1 FAT table) */
+	if (!ms->ms_fats)
+		return 0;
+	if (!ms->ms_reserved)
+		return 0;
+	if (!(0xf8 <= ms->ms_media || ms->ms_media == 0xf0))
+		return 0;
+	if (!is_power_of_2(ms->ms_cluster_size))
+		return 0;
+
+	sector_size = unaligned_le16(&ms->ms_sector_size);
+	if (!is_power_of_2(sector_size) ||
+	    sector_size < 512 || sector_size > 4096)
+		return 0;
+
+	dir_entries = unaligned_le16(&ms->ms_dir_entries);
+	reserved =  le16_to_cpu(ms->ms_reserved);
+	sect_count = unaligned_le16(&ms->ms_sectors);
+
+	if (sect_count == 0)
+		sect_count = le32_to_cpu(ms->ms_total_sect);
+
+	fat_length = le16_to_cpu(ms->ms_fat_length);
+	if (fat_length == 0)
+		fat_length = le32_to_cpu(vs->vs_fat32_length);
+
+	__fat_size = fat_length * ms->ms_fats;
+	dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
+					(sector_size-1)) / sector_size;
+
+	__cluster_count = (sect_count - (reserved + __fat_size + dir_size)) /
+							ms->ms_cluster_size;
+	if (!ms->ms_fat_length && vs->vs_fat32_length)
+		max_count = FAT32_MAX;
+	else
+		max_count = __cluster_count > FAT12_MAX ? FAT16_MAX : FAT12_MAX;
+
+	if (__cluster_count > max_count)
+		return 0;
+
+	if (fat_size)
+		*fat_size = __fat_size;
+	if (cluster_count)
+		*cluster_count = __cluster_count;
+
+	return 1;	/* valid */
+}
+
+/*
+ * This function is used by MBR partition table parser to avoid
+ * misinterpretation of FAT filesystem.
+ */
+int blkid_probe_is_vfat(blkid_probe pr)
+{
+	struct vfat_super_block *vs;
+	struct msdos_super_block *ms;
+	const struct blkid_idmag *mag = NULL;
+	int rc;
+
+	rc = blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag);
+	if (rc < 0)
+		return rc;	/* error */
+	if (rc != BLKID_PROBE_OK || !mag)
+		return 0;
+
+	ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block);
+	if (!ms)
+		return errno ? -errno : 0;
+	vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block);
+	if (!vs)
+		return errno ? -errno : 0;
+
+	return fat_valid_superblock(mag, ms, vs, NULL, NULL);
+}
+
+/* FAT label extraction from the root directory taken from Kay
+ * Sievers's volume_id library */
+static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct vfat_super_block *vs;
+	struct msdos_super_block *ms;
+	const unsigned char *vol_label = 0;
+	unsigned char *vol_serno = NULL, vol_label_buf[11];
+	uint16_t sector_size = 0, reserved;
+	uint32_t cluster_count, fat_size;
+	const char *version = NULL;
+
+	ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block);
+	if (!ms)
+		return errno ? -errno : 1;
+
+	vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block);
+	if (!vs)
+		return errno ? -errno : 1;
+
+	if (!fat_valid_superblock(mag, ms, vs, &cluster_count, &fat_size))
+		return 1;
+
+	sector_size = unaligned_le16(&ms->ms_sector_size);
+	reserved =  le16_to_cpu(ms->ms_reserved);
+
+	if (ms->ms_fat_length) {
+		/* the label may be an attribute in the root directory */
+		uint32_t root_start = (reserved + fat_size) * sector_size;
+		uint32_t root_dir_entries = unaligned_le16(&vs->vs_dir_entries);
+
+		vol_label = search_fat_label(pr, root_start, root_dir_entries);
+		if (vol_label) {
+			memcpy(vol_label_buf, vol_label, 11);
+			vol_label = vol_label_buf;
+		}
+
+		if (!vol_label || !memcmp(vol_label, no_name, 11))
+			vol_label = ms->ms_label;
+		vol_serno = ms->ms_serno;
+
+		blkid_probe_set_value(pr, "SEC_TYPE", (unsigned char *) "msdos",
+                              sizeof("msdos"));
+
+		if (cluster_count < FAT12_MAX)
+			version = "FAT12";
+		else if (cluster_count < FAT16_MAX)
+			version = "FAT16";
+
+	} else if (vs->vs_fat32_length) {
+		unsigned char *buf;
+		uint16_t fsinfo_sect;
+		int maxloop = 100;
+
+		/* Search the FAT32 root dir for the label attribute */
+		uint32_t buf_size = vs->vs_cluster_size * sector_size;
+		uint32_t start_data_sect = reserved + fat_size;
+		uint32_t entries = le32_to_cpu(vs->vs_fat32_length) *
+					sector_size / sizeof(uint32_t);
+		uint32_t next = le32_to_cpu(vs->vs_root_cluster);
+
+		while (next && next < entries && --maxloop) {
+			uint32_t next_sect_off;
+			uint64_t next_off, fat_entry_off;
+			int count;
+
+			next_sect_off = (next - 2) * vs->vs_cluster_size;
+			next_off = (uint64_t)(start_data_sect + next_sect_off) *
+				sector_size;
+
+			count = buf_size / sizeof(struct vfat_dir_entry);
+
+			vol_label = search_fat_label(pr, next_off, count);
+			if (vol_label) {
+				memcpy(vol_label_buf, vol_label, 11);
+				vol_label = vol_label_buf;
+				break;
+			}
+
+			/* get FAT entry */
+			fat_entry_off = ((uint64_t) reserved * sector_size) +
+				(next * sizeof(uint32_t));
+			buf = blkid_probe_get_buffer(pr, fat_entry_off, buf_size);
+			if (buf == NULL)
+				break;
+
+			/* set next cluster */
+			next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff;
+		}
+
+		version = "FAT32";
+
+		if (!vol_label || !memcmp(vol_label, no_name, 11))
+			vol_label = vs->vs_label;
+		vol_serno = vs->vs_serno;
+
+		/*
+		 * FAT32 should have a valid signature in the fsinfo block,
+		 * but also allow all bytes set to '\0', because some volumes
+		 * do not set the signature at all.
+		 */
+		fsinfo_sect = le16_to_cpu(vs->vs_fsinfo_sector);
+		if (fsinfo_sect) {
+			struct fat32_fsinfo *fsinfo;
+
+			buf = blkid_probe_get_buffer(pr,
+					(blkid_loff_t) fsinfo_sect * sector_size,
+					sizeof(struct fat32_fsinfo));
+			if (buf == NULL)
+				return errno ? -errno : 1;
+
+			fsinfo = (struct fat32_fsinfo *) buf;
+			if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0 &&
+			    memcmp(fsinfo->signature1, "\x52\x52\x64\x41", 4) != 0 &&
+			    memcmp(fsinfo->signature1, "\x00\x00\x00\x00", 4) != 0)
+				return 1;
+			if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0 &&
+			    memcmp(fsinfo->signature2, "\x00\x00\x00\x00", 4) != 0)
+				return 1;
+		}
+	}
+
+	if (vol_label && memcmp(vol_label, no_name, 11))
+		blkid_probe_set_label(pr, (unsigned char *) vol_label, 11);
+
+	/* We can't just print them as %04X, because they are unaligned */
+	if (vol_serno)
+		blkid_probe_sprintf_uuid(pr, vol_serno, 4, "%02X%02X-%02X%02X",
+			vol_serno[3], vol_serno[2], vol_serno[1], vol_serno[0]);
+	if (version)
+		blkid_probe_set_version(pr, version);
+
+	return 0;
+}
+
+
+const struct blkid_idinfo vfat_idinfo =
+{
+	.name		= "vfat",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_vfat,
+	.magics		=
+	{
+		{ .magic = "MSWIN",    .len = 5, .sboff = 0x52 },
+		{ .magic = "FAT32   ", .len = 8, .sboff = 0x52 },
+		{ .magic = "MSDOS",    .len = 5, .sboff = 0x36 },
+		{ .magic = "FAT16   ", .len = 8, .sboff = 0x36 },
+		{ .magic = "FAT12   ", .len = 8, .sboff = 0x36 },
+		{ .magic = "FAT     ", .len = 8, .sboff = 0x36 },
+		{ .magic = "\353",     .len = 1, },
+		{ .magic = "\351",     .len = 1, },
+		{ .magic = "\125\252", .len = 2, .sboff = 0x1fe },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/via_raid.c b/libblkid/src/superblocks/via_raid.c
new file mode 100644
index 0000000..ee3ab65
--- /dev/null
+++ b/libblkid/src/superblocks/via_raid.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * Inspired by libvolume_id by
+ *     Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct via_metadata {
+	uint16_t	signature;
+	uint8_t		version_number;
+	struct via_array {
+		uint16_t	disk_bit_mask;
+		uint8_t		disk_array_ex;
+		uint32_t	capacity_low;
+		uint32_t	capacity_high;
+		uint32_t	serial_checksum;
+	} __attribute__((packed)) array;
+	uint32_t	serial_checksum[8];
+	uint8_t		checksum;
+} __attribute__((packed));
+
+#define VIA_SIGNATURE		0xAA55
+
+/* 8 bit checksum on first 50 bytes of metadata. */
+static uint8_t via_checksum(struct via_metadata *v)
+{
+	uint8_t i = 50, cs = 0;
+
+	while (i--)
+		cs += ((uint8_t*) v)[i];
+
+	return cs;
+}
+
+static int probe_viaraid(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	uint64_t off;
+	struct via_metadata *v;
+
+	if (pr->size < 0x10000)
+		return 1;
+	if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+		return 1;
+
+	off = ((pr->size / 0x200)-1) * 0x200;
+
+	v = (struct via_metadata *)
+			blkid_probe_get_buffer(pr,
+				off,
+				sizeof(struct via_metadata));
+	if (!v)
+		return errno ? -errno : 1;
+
+	if (le16_to_cpu(v->signature) != VIA_SIGNATURE)
+		return 1;
+	if (v->version_number > 2)
+		return 1;
+	if (!blkid_probe_verify_csum(pr, via_checksum(v), v->checksum))
+		return 1;
+
+	if (blkid_probe_sprintf_version(pr, "%u", v->version_number) != 0)
+		return 1;
+	if (blkid_probe_set_magic(pr, off,
+				sizeof(v->signature),
+				(unsigned char *) &v->signature))
+		return 1;
+	return 0;
+}
+
+const struct blkid_idinfo viaraid_idinfo = {
+	.name		= "via_raid_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_viaraid,
+	.magics		= BLKID_NONE_MAGIC
+};
+
+
diff --git a/libblkid/src/superblocks/vmfs.c b/libblkid/src/superblocks/vmfs.c
new file mode 100644
index 0000000..fac87ab
--- /dev/null
+++ b/libblkid/src/superblocks/vmfs.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 Mike Hommey <mh@glandium.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include "superblocks.h"
+
+struct vmfs_fs_info {
+	uint32_t magic;
+	uint32_t volume_version;
+	uint8_t version;
+	uint8_t uuid[16];
+	uint32_t mode;
+	char label[128];
+} __attribute__ ((__packed__));
+
+struct vmfs_volume_info {
+	uint32_t magic;
+	uint32_t ver;
+	uint8_t irrelevant[122];
+	uint8_t uuid[16];
+} __attribute__ ((__packed__));
+
+static int probe_vmfs_fs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct vmfs_fs_info *header;
+
+	header = blkid_probe_get_sb(pr, mag, struct vmfs_fs_info);
+	if (header == NULL)
+		return errno ? -errno : 1;
+
+	blkid_probe_sprintf_uuid(pr, (unsigned char *) header->uuid, 16,
+		"%02x%02x%02x%02x-%02x%02x%02x%02x-"
+		"%02x%02x-%02x%02x%02x%02x%02x%02x",
+		header->uuid[3], header->uuid[2], header->uuid[1],
+		header->uuid[0], header->uuid[7], header->uuid[6],
+		header->uuid[5], header->uuid[4], header->uuid[9],
+		header->uuid[8], header->uuid[10], header->uuid[11],
+		header->uuid[12], header->uuid[13], header->uuid[14],
+		header->uuid[15]);
+
+	blkid_probe_set_label(pr, (unsigned char *) header->label,
+					sizeof(header->label));
+	blkid_probe_sprintf_version(pr, "%u", header->version);
+	return 0;
+}
+
+static int probe_vmfs_volume(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct vmfs_volume_info *header;
+	unsigned char *lvm_uuid;
+
+	header = blkid_probe_get_sb(pr, mag, struct vmfs_volume_info);
+	if (header == NULL)
+		return errno ? -errno : 1;
+
+	blkid_probe_sprintf_value(pr, "UUID_SUB",
+		"%02x%02x%02x%02x-%02x%02x%02x%02x-"
+		"%02x%02x-%02x%02x%02x%02x%02x%02x",
+		header->uuid[3], header->uuid[2], header->uuid[1],
+		header->uuid[0], header->uuid[7], header->uuid[6],
+		header->uuid[5], header->uuid[4], header->uuid[9],
+		header->uuid[8], header->uuid[10], header->uuid[11],
+		header->uuid[12], header->uuid[13], header->uuid[14],
+		header->uuid[15]);
+	blkid_probe_sprintf_version(pr, "%u", le32_to_cpu(header->ver));
+
+	lvm_uuid = blkid_probe_get_buffer(pr,
+				1024 * 1024 /* Start of the volume info */
+				+ 512 /* Offset to lvm info */
+				+ 20 /* Offset in lvm info */, 35);
+	if (lvm_uuid)
+		blkid_probe_strncpy_uuid(pr, lvm_uuid, 35);
+
+	return 0;
+}
+
+const struct blkid_idinfo vmfs_fs_idinfo =
+{
+	.name		= "VMFS",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_vmfs_fs,
+	.magics		=
+	{
+		{ .magic = "\x5e\xf1\xab\x2f", .len = 4, .kboff = 2048 },
+		{ NULL }
+	}
+};
+
+const struct blkid_idinfo vmfs_volume_idinfo =
+{
+	.name		= "VMFS_volume_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_vmfs_volume,
+	.magics		=
+	{
+		{ .magic = "\x0d\xd0\x01\xc0", .len = 4, .kboff = 1024 },
+		{ NULL }
+	}
+};
diff --git a/libblkid/src/superblocks/vxfs.c b/libblkid/src/superblocks/vxfs.c
new file mode 100644
index 0000000..19d284c
--- /dev/null
+++ b/libblkid/src/superblocks/vxfs.c
@@ -0,0 +1,41 @@
+/*
+ * 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 "superblocks.h"
+
+struct vxfs_super_block {
+	uint32_t		vs_magic;
+	int32_t			vs_version;
+};
+
+static int probe_vxfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct vxfs_super_block *vxs;
+
+	vxs = blkid_probe_get_sb(pr, mag, struct vxfs_super_block);
+	if (!vxs)
+		return errno ? -errno : 1;
+
+	blkid_probe_sprintf_version(pr, "%u", (unsigned int) vxs->vs_version);
+	return 0;
+}
+
+
+const struct blkid_idinfo vxfs_idinfo =
+{
+	.name		= "vxfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_vxfs,
+	.magics		=
+	{
+		{ .magic = "\365\374\001\245", .len = 4, .kboff = 1 },
+		{ NULL }
+	}
+};
+
diff --git a/libblkid/src/superblocks/xfs.c b/libblkid/src/superblocks/xfs.c
new file mode 100644
index 0000000..a6c04a2
--- /dev/null
+++ b/libblkid/src/superblocks/xfs.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2013 Eric Sandeen <sandeen@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+struct xfs_super_block {
+	uint32_t	sb_magicnum;	/* magic number == XFS_SB_MAGIC */
+	uint32_t	sb_blocksize;	/* logical block size, bytes */
+	uint64_t	sb_dblocks;	/* number of data blocks */
+	uint64_t	sb_rblocks;	/* number of realtime blocks */
+	uint64_t	sb_rextents;	/* number of realtime extents */
+	unsigned char	sb_uuid[16];	/* file system unique id */
+	uint64_t	sb_logstart;	/* starting block of log if internal */
+	uint64_t	sb_rootino;	/* root inode number */
+	uint64_t	sb_rbmino;	/* bitmap inode for realtime extents */
+	uint64_t	sb_rsumino;	/* summary inode for rt bitmap */
+	uint32_t	sb_rextsize;	/* realtime extent size, blocks */
+	uint32_t	sb_agblocks;	/* size of an allocation group */
+	uint32_t	sb_agcount;	/* number of allocation groups */
+	uint32_t	sb_rbmblocks;	/* number of rt bitmap blocks */
+	uint32_t	sb_logblocks;	/* number of log blocks */
+
+	uint16_t	sb_versionnum;	/* header version == XFS_SB_VERSION */
+	uint16_t	sb_sectsize;	/* volume sector size, bytes */
+	uint16_t	sb_inodesize;	/* inode size, bytes */
+	uint16_t	sb_inopblock;	/* inodes per block */
+	char		sb_fname[12];	/* file system name */
+	uint8_t		sb_blocklog;	/* log2 of sb_blocksize */
+	uint8_t		sb_sectlog;	/* log2 of sb_sectsize */
+	uint8_t		sb_inodelog;	/* log2 of sb_inodesize */
+	uint8_t		sb_inopblog;	/* log2 of sb_inopblock */
+	uint8_t		sb_agblklog;	/* log2 of sb_agblocks (rounded up) */
+	uint8_t		sb_rextslog;	/* log2 of sb_rextents */
+	uint8_t		sb_inprogress;	/* mkfs is in progress, don't mount */
+	uint8_t		sb_imax_pct;	/* max % of fs for inode space */
+					/* statistics */
+	uint64_t	sb_icount;	/* allocated inodes */
+	uint64_t	sb_ifree;	/* free inodes */
+	uint64_t	sb_fdblocks;	/* free data blocks */
+	uint64_t	sb_frextents;	/* free realtime extents */
+
+	/* this is not all... but enough for libblkid */
+
+} __attribute__((packed));
+
+#define XFS_MIN_BLOCKSIZE_LOG	9	/* i.e. 512 bytes */
+#define XFS_MAX_BLOCKSIZE_LOG	16	/* i.e. 65536 bytes */
+#define XFS_MIN_BLOCKSIZE	(1 << XFS_MIN_BLOCKSIZE_LOG)
+#define XFS_MAX_BLOCKSIZE	(1 << XFS_MAX_BLOCKSIZE_LOG)
+#define XFS_MIN_SECTORSIZE_LOG	9	/* i.e. 512 bytes */
+#define XFS_MAX_SECTORSIZE_LOG	15	/* i.e. 32768 bytes */
+#define XFS_MIN_SECTORSIZE	(1 << XFS_MIN_SECTORSIZE_LOG)
+#define XFS_MAX_SECTORSIZE	(1 << XFS_MAX_SECTORSIZE_LOG)
+
+#define	XFS_DINODE_MIN_LOG	8
+#define	XFS_DINODE_MAX_LOG	11
+#define	XFS_DINODE_MIN_SIZE	(1 << XFS_DINODE_MIN_LOG)
+#define	XFS_DINODE_MAX_SIZE	(1 << XFS_DINODE_MAX_LOG)
+
+#define	XFS_MAX_RTEXTSIZE	(1024 * 1024 * 1024)	/* 1GB */
+#define	XFS_DFL_RTEXTSIZE	(64 * 1024)	        /* 64kB */
+#define	XFS_MIN_RTEXTSIZE	(4 * 1024)		/* 4kB */
+
+#define XFS_MIN_AG_BLOCKS	64
+#define XFS_MAX_DBLOCKS(s) ((uint64_t)(s)->sb_agcount * (s)->sb_agblocks)
+#define XFS_MIN_DBLOCKS(s) ((uint64_t)((s)->sb_agcount - 1) *	\
+			 (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
+
+
+static void sb_from_disk(struct xfs_super_block *from,
+			 struct xfs_super_block *to)
+{
+
+	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
+	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
+	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
+	to->sb_rblocks = be64_to_cpu(from->sb_rblocks);
+	to->sb_rextents = be64_to_cpu(from->sb_rextents);
+	to->sb_logstart = be64_to_cpu(from->sb_logstart);
+	to->sb_rootino = be64_to_cpu(from->sb_rootino);
+	to->sb_rbmino = be64_to_cpu(from->sb_rbmino);
+	to->sb_rsumino = be64_to_cpu(from->sb_rsumino);
+	to->sb_rextsize = be32_to_cpu(from->sb_rextsize);
+	to->sb_agblocks = be32_to_cpu(from->sb_agblocks);
+	to->sb_agcount = be32_to_cpu(from->sb_agcount);
+	to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks);
+	to->sb_logblocks = be32_to_cpu(from->sb_logblocks);
+	to->sb_versionnum = be16_to_cpu(from->sb_versionnum);
+	to->sb_sectsize = be16_to_cpu(from->sb_sectsize);
+	to->sb_inodesize = be16_to_cpu(from->sb_inodesize);
+	to->sb_inopblock = be16_to_cpu(from->sb_inopblock);
+	to->sb_blocklog = from->sb_blocklog;
+	to->sb_sectlog = from->sb_sectlog;
+	to->sb_inodelog = from->sb_inodelog;
+	to->sb_inopblog = from->sb_inopblog;
+	to->sb_agblklog = from->sb_agblklog;
+	to->sb_rextslog = from->sb_rextslog;
+	to->sb_inprogress = from->sb_inprogress;
+	to->sb_imax_pct = from->sb_imax_pct;
+	to->sb_icount = be64_to_cpu(from->sb_icount);
+	to->sb_ifree = be64_to_cpu(from->sb_ifree);
+	to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks);
+	to->sb_frextents = be64_to_cpu(from->sb_frextents);
+}
+
+static int xfs_verify_sb(struct xfs_super_block *ondisk)
+{
+	struct xfs_super_block sb, *sbp = &sb;
+
+	/* beXX_to_cpu(), but don't convert UUID and fsname! */
+	sb_from_disk(ondisk, sbp);
+
+	/* sanity checks, we don't want to rely on magic string only */
+	if (sbp->sb_agcount <= 0					||
+	    sbp->sb_sectsize < XFS_MIN_SECTORSIZE			||
+	    sbp->sb_sectsize > XFS_MAX_SECTORSIZE			||
+	    sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG			||
+	    sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG			||
+	    sbp->sb_sectsize != (1 << sbp->sb_sectlog)			||
+	    sbp->sb_blocksize < XFS_MIN_BLOCKSIZE			||
+	    sbp->sb_blocksize > XFS_MAX_BLOCKSIZE			||
+	    sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG			||
+	    sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG			||
+	    sbp->sb_blocksize != (1 << sbp->sb_blocklog)		||
+	    sbp->sb_inodesize < XFS_DINODE_MIN_SIZE			||
+	    sbp->sb_inodesize > XFS_DINODE_MAX_SIZE			||
+	    sbp->sb_inodelog < XFS_DINODE_MIN_LOG			||
+	    sbp->sb_inodelog > XFS_DINODE_MAX_LOG			||
+	    sbp->sb_inodesize != (1 << sbp->sb_inodelog)		||
+	    (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)	||
+	    (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)	||
+	    (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)	||
+	    (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */)	||
+	    sbp->sb_dblocks == 0					||
+	    sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)			||
+	    sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))
+		return 0;
+
+	/* TODO: version 5 has also checksum CRC32, maybe we can check it too */
+
+	return 1;
+}
+
+static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	struct xfs_super_block *xs;
+
+	xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block);
+	if (!xs)
+		return errno ? -errno : 1;
+
+	if (!xfs_verify_sb(xs))
+		return 1;
+
+	if (strlen(xs->sb_fname))
+		blkid_probe_set_label(pr, (unsigned char *) xs->sb_fname,
+				sizeof(xs->sb_fname));
+	blkid_probe_set_uuid(pr, xs->sb_uuid);
+	return 0;
+}
+
+const struct blkid_idinfo xfs_idinfo =
+{
+	.name		= "xfs",
+	.usage		= BLKID_USAGE_FILESYSTEM,
+	.probefunc	= probe_xfs,
+	.magics		=
+	{
+		{ .magic = "XFSB", .len = 4 },
+		{ NULL }
+	}
+};
+
+struct xlog_rec_header {
+	uint32_t	h_magicno;
+	uint32_t	h_dummy1[1];
+	uint32_t	h_version;
+	uint32_t	h_len;
+	uint32_t	h_dummy2[71];
+	uint32_t	h_fmt;
+	unsigned char	h_uuid[16];
+} __attribute__((packed));
+
+#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe
+
+/*
+ * For very small filesystems, the minimum log size
+ * can be smaller, but that seems vanishingly unlikely
+ * when used with an external log (which is used for
+ * performance reasons; tiny conflicts with that goal).
+ */
+#define XFS_MIN_LOG_BYTES	(10 * 1024 * 1024)
+
+#define XLOG_FMT_LINUX_LE	1
+#define XLOG_FMT_LINUX_BE	2
+#define XLOG_FMT_IRIX_BE	3
+
+#define XLOG_VERSION_1		1
+#define XLOG_VERSION_2		2	/* Large IClogs, Log sunit */
+#define XLOG_VERSION_OKBITS	(XLOG_VERSION_1 | XLOG_VERSION_2)
+
+static int xlog_valid_rec_header(struct xlog_rec_header *rhead)
+{
+	uint32_t hlen;
+
+	if (rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))
+		return 0;
+
+	if (!rhead->h_version ||
+            (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS)))
+		return 0;
+
+	/* LR body must have data or it wouldn't have been written */
+	hlen = be32_to_cpu(rhead->h_len);
+	if (hlen <= 0 || hlen > INT_MAX)
+		return 0;
+
+	if (rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_LE) &&
+	    rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_BE) &&
+	    rhead->h_fmt != cpu_to_be32(XLOG_FMT_IRIX_BE))
+		return 0;
+
+	return 1;
+}
+
+/* xlog record header will be in some sector in the first 256k */
+static int probe_xfs_log(blkid_probe pr, const struct blkid_idmag *mag)
+{
+	int i;
+	struct xlog_rec_header *rhead;
+	unsigned char *buf;
+
+	buf = blkid_probe_get_buffer(pr, 0, 256*1024);
+	if (!buf)
+		return errno ? -errno : 1;
+
+	if (memcmp(buf, "XFSB", 4) == 0)
+		return 1;			/* this is regular XFS, ignore */
+
+	/* check the first 512 512-byte sectors */
+	for (i = 0; i < 512; i++) {
+		rhead = (struct xlog_rec_header *)&buf[i*512];
+
+		if (xlog_valid_rec_header(rhead)) {
+			blkid_probe_set_uuid_as(pr, rhead->h_uuid, "LOGUUID");
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+const struct blkid_idinfo xfs_log_idinfo =
+{
+	.name		= "xfs_external_log",
+	.usage		= BLKID_USAGE_OTHER,
+	.probefunc	= probe_xfs_log,
+	.magics		= BLKID_NONE_MAGIC,
+	.minsz		= XFS_MIN_LOG_BYTES,
+};
diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c
new file mode 100644
index 0000000..86da59d
--- /dev/null
+++ b/libblkid/src/superblocks/zfs.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2009-2010 by Andreas Dilger <adilger@sun.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <limits.h>
+
+#include "superblocks.h"
+
+#define VDEV_LABEL_UBERBLOCK	(128 * 1024ULL)
+#define VDEV_LABEL_NVPAIR	( 16 * 1024ULL)
+#define VDEV_LABEL_SIZE		(256 * 1024ULL)
+
+/* #include <sys/uberblock_impl.h> */
+#define UBERBLOCK_MAGIC         0x00bab10c              /* oo-ba-bloc!  */
+struct zfs_uberblock {
+	uint64_t	ub_magic;	/* UBERBLOCK_MAGIC		*/
+	uint64_t	ub_version;	/* SPA_VERSION			*/
+	uint64_t	ub_txg;		/* txg of last sync		*/
+	uint64_t	ub_guid_sum;	/* sum of all vdev guids	*/
+	uint64_t	ub_timestamp;	/* UTC time of last sync	*/
+	char		ub_rootbp;	/* MOS objset_phys_t		*/
+} __attribute__((packed));
+
+#define ZFS_TRIES	64
+#define ZFS_WANT	 4
+
+#define DATA_TYPE_UINT64 8
+#define DATA_TYPE_STRING 9
+
+struct nvpair {
+	uint32_t	nvp_size;
+	uint32_t	nvp_unkown;
+	uint32_t	nvp_namelen;
+	char		nvp_name[0]; /* aligned to 4 bytes */
+	/* aligned ptr array for string arrays */
+	/* aligned array of data for value */
+};
+
+struct nvstring {
+	uint32_t	nvs_type;
+	uint32_t	nvs_elem;
+	uint32_t	nvs_strlen;
+	unsigned char	nvs_string[0];
+};
+
+struct nvuint64 {
+	uint32_t	nvu_type;
+	uint32_t	nvu_elem;
+	uint64_t	nvu_value;
+};
+
+struct nvlist {
+	uint32_t	nvl_unknown[3];
+	struct nvpair	nvl_nvpair;
+};
+
+#define nvdebug(fmt, ...)	do { } while(0)
+/*#define nvdebug(fmt, a...)	fprintf(stderr, fmt, ##a)*/
+
+static void zfs_extract_guid_name(blkid_probe pr, loff_t offset)
+{
+	struct nvlist *nvl;
+	struct nvpair *nvp;
+	size_t left = 4096;
+	int found = 0;
+
+	offset = (offset & ~(VDEV_LABEL_SIZE - 1)) + VDEV_LABEL_NVPAIR;
+
+	/* Note that we currently assume that the desired fields are within
+	 * the first 4k (left) of the nvlist.  This is true for all pools
+	 * I've seen, and simplifies this code somewhat, because we don't
+	 * have to handle an nvpair crossing a buffer boundary. */
+	nvl = (struct nvlist *)blkid_probe_get_buffer(pr, offset, left);
+	if (nvl == NULL)
+		return;
+
+	nvdebug("zfs_extract: nvlist offset %llu\n", offset);
+
+	nvp = &nvl->nvl_nvpair;
+	while (left > sizeof(*nvp) && nvp->nvp_size != 0 && found < 3) {
+		int avail;   /* tracks that name/value data fits in nvp_size */
+		int namesize;
+
+		nvp->nvp_size = be32_to_cpu(nvp->nvp_size);
+		nvp->nvp_namelen = be32_to_cpu(nvp->nvp_namelen);
+		avail = nvp->nvp_size - nvp->nvp_namelen - sizeof(*nvp);
+
+		nvdebug("left %zd nvp_size %u\n", left, nvp->nvp_size);
+		if (left < nvp->nvp_size || avail < 0)
+			break;
+
+		namesize = (nvp->nvp_namelen + 3) & ~3;
+
+		nvdebug("nvlist: size %u, namelen %u, name %*s\n",
+			nvp->nvp_size, nvp->nvp_namelen, nvp->nvp_namelen,
+			nvp->nvp_name);
+		if (strncmp(nvp->nvp_name, "name", nvp->nvp_namelen) == 0) {
+			struct nvstring *nvs = (void *)(nvp->nvp_name+namesize);
+
+			nvs->nvs_type = be32_to_cpu(nvs->nvs_type);
+			nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen);
+			if (nvs->nvs_strlen > UINT_MAX - sizeof(*nvs))
+				break;
+			avail -= nvs->nvs_strlen + sizeof(*nvs);
+			nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type,
+				nvs->nvs_strlen, nvs->nvs_string);
+			if (nvs->nvs_type == DATA_TYPE_STRING && avail >= 0)
+				blkid_probe_set_label(pr, nvs->nvs_string,
+						      nvs->nvs_strlen);
+			found++;
+		} else if (strncmp(nvp->nvp_name, "guid",
+				   nvp->nvp_namelen) == 0) {
+			struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize);
+			uint64_t nvu_value;
+
+			memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value));
+			nvu->nvu_type = be32_to_cpu(nvu->nvu_type);
+			nvu_value = be64_to_cpu(nvu_value);
+			avail -= sizeof(*nvu);
+			nvdebug("nvuint64: type %u value %"PRIu64"\n",
+				nvu->nvu_type, nvu_value);
+			if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0)
+				blkid_probe_sprintf_value(pr, "UUID_SUB",
+							  "%"PRIu64, nvu_value);
+			found++;
+		} else if (strncmp(nvp->nvp_name, "pool_guid",
+				   nvp->nvp_namelen) == 0) {
+			struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize);
+			uint64_t nvu_value;
+
+			memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value));
+			nvu->nvu_type = be32_to_cpu(nvu->nvu_type);
+			nvu_value = be64_to_cpu(nvu_value);
+			avail -= sizeof(*nvu);
+			nvdebug("nvuint64: type %u value %"PRIu64"\n",
+				nvu->nvu_type, nvu_value);
+			if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0)
+				blkid_probe_sprintf_uuid(pr, (unsigned char *)
+							 &nvu_value,
+							 sizeof(nvu_value),
+							 "%"PRIu64, nvu_value);
+			found++;
+		}
+		if (left > nvp->nvp_size)
+			left -= nvp->nvp_size;
+		else
+			left = 0;
+		nvp = (struct nvpair *)((char *)nvp + nvp->nvp_size);
+	}
+}
+
+#define zdebug(fmt, ...)	do {} while(0)
+/*#define zdebug(fmt, a...)	fprintf(stderr, fmt, ##a)*/
+
+/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start
+ * of the disk, and 2 areas at the end of the disk.  Check only some of them...
+ * #4 (@ 132kB) is the first one written on a new filesystem. */
+static int probe_zfs(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	uint64_t swab_magic = swab64(UBERBLOCK_MAGIC);
+	struct zfs_uberblock *ub;
+	int swab_endian;
+	loff_t offset, ub_offset = 0;
+	int tried;
+	int found;
+
+	zdebug("probe_zfs\n");
+	/* Look for at least 4 uberblocks to ensure a positive match */
+	for (tried = found = 0, offset = VDEV_LABEL_UBERBLOCK;
+	     tried < ZFS_TRIES && found < ZFS_WANT;
+	     tried++, offset += 4096) {
+		/* also try the second uberblock copy */
+		if (tried == (ZFS_TRIES / 2))
+			offset = VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK;
+
+		ub = (struct zfs_uberblock *)
+			blkid_probe_get_buffer(pr, offset,
+					       sizeof(struct zfs_uberblock));
+		if (ub == NULL)
+			return errno ? -errno : 1;
+
+		if (ub->ub_magic == UBERBLOCK_MAGIC) {
+			ub_offset = offset;
+			found++;
+		}
+
+		if ((swab_endian = (ub->ub_magic == swab_magic))) {
+			ub_offset = offset;
+			found++;
+		}
+
+		zdebug("probe_zfs: found %s-endian uberblock at %llu\n",
+		       swab_endian ? "big" : "little", offset >> 10);
+	}
+
+	if (found < 4)
+		return 1;
+
+	/* If we found the 4th uberblock, then we will have exited from the
+	 * scanning loop immediately, and ub will be a valid uberblock. */
+	blkid_probe_sprintf_version(pr, "%" PRIu64, swab_endian ?
+				    swab64(ub->ub_version) : ub->ub_version);
+
+	zfs_extract_guid_name(pr, offset);
+
+	if (blkid_probe_set_magic(pr, ub_offset,
+				sizeof(ub->ub_magic),
+				(unsigned char *) &ub->ub_magic))
+		return 1;
+
+	return 0;
+}
+
+const struct blkid_idinfo zfs_idinfo =
+{
+	.name		= "zfs_member",
+	.usage		= BLKID_USAGE_RAID,
+	.probefunc	= probe_zfs,
+	.minsz		= 64 * 1024 * 1024,
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/sysfs.h b/libblkid/src/sysfs.h
new file mode 100644
index 0000000..1de624a
--- /dev/null
+++ b/libblkid/src/sysfs.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
+ */
+#ifndef UTIL_LINUX_SYSFS_H
+#define UTIL_LINUX_SYSFS_H
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <inttypes.h>
+#include <dirent.h>
+
+struct sysfs_cxt {
+	dev_t	devno;
+	int	dir_fd;		/* /sys/block/<name> */
+	char	*dir_path;
+	struct sysfs_cxt *parent;
+
+	unsigned int	scsi_host,
+			scsi_channel,
+			scsi_target,
+			scsi_lun;
+
+	unsigned int	has_hctl : 1;
+};
+
+#define UL_SYSFSCXT_EMPTY { 0, -1, NULL, NULL, 0, 0, 0, 0, 0 }
+
+extern char *sysfs_devno_attribute_path(dev_t devno, char *buf,
+                                 size_t bufsiz, const char *attr);
+extern int sysfs_devno_has_attribute(dev_t devno, const char *attr);
+extern char *sysfs_devno_path(dev_t devno, char *buf, size_t bufsiz);
+extern char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz);
+extern dev_t sysfs_devname_to_devno(const char *name, const char *parent);
+
+extern int sysfs_init(struct sysfs_cxt *cxt, dev_t devno, struct sysfs_cxt *parent)
+					__attribute__ ((warn_unused_result));
+extern void sysfs_deinit(struct sysfs_cxt *cxt);
+
+extern DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr);
+
+extern int sysfs_stat(struct sysfs_cxt *cxt, const char *attr, struct stat *st);
+extern ssize_t sysfs_readlink(struct sysfs_cxt *cxt, const char *attr,
+	                   char *buf, size_t bufsiz);
+extern int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr);
+
+extern int sysfs_scanf(struct sysfs_cxt *cxt,  const char *attr,
+		       const char *fmt, ...)
+		        __attribute__ ((format (scanf, 3, 4)));
+
+extern int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res);
+extern int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res);
+extern int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res);
+
+extern int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str);
+extern int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num);
+
+extern char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz);
+
+extern char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr);
+
+extern int sysfs_count_dirents(struct sysfs_cxt *cxt, const char *attr);
+extern int sysfs_count_partitions(struct sysfs_cxt *cxt, const char *devname);
+extern dev_t sysfs_partno_to_devno(struct sysfs_cxt *cxt, int partno);
+extern char *sysfs_get_slave(struct sysfs_cxt *cxt);
+
+extern char *sysfs_get_devchain(struct sysfs_cxt *cxt, char *buf, size_t bufsz);
+extern int sysfs_next_subsystem(struct sysfs_cxt *cxt, char *devchain, char **subsys);
+extern int sysfs_is_hotpluggable(struct sysfs_cxt *cxt);
+
+extern int sysfs_is_partition_dirent(DIR *dir, struct dirent *d,
+			const char *parent_name);
+
+extern int sysfs_devno_to_wholedisk(dev_t dev, char *diskname,
+            size_t len, dev_t *diskdevno);
+
+extern int sysfs_devno_is_lvm_private(dev_t devno);
+extern int sysfs_devno_is_wholedisk(dev_t devno);
+
+extern int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h,
+			       int *c, int *t, int *l);
+extern char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt,
+                const char *type, const char *attr);
+extern int sysfs_scsi_host_is(struct sysfs_cxt *cxt, const char *type);
+extern int sysfs_scsi_has_attribute(struct sysfs_cxt *cxt, const char *attr);
+extern int sysfs_scsi_path_contains(struct sysfs_cxt *cxt, const char *pattern);
+
+#endif /* UTIL_LINUX_SYSFS_H */
diff --git a/libblkid/src/tag.c b/libblkid/src/tag.c
new file mode 100644
index 0000000..6af8062
--- /dev/null
+++ b/libblkid/src/tag.c
@@ -0,0 +1,481 @@
+/*
+ * tag.c - allocation/initialization/free routines for tag structs
+ *
+ * Copyright (C) 2001 Andreas Dilger
+ * Copyright (C) 2003 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "blkidP.h"
+
+static blkid_tag blkid_new_tag(void)
+{
+	blkid_tag tag;
+
+	if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag))))
+		return NULL;
+
+	INIT_LIST_HEAD(&tag->bit_tags);
+	INIT_LIST_HEAD(&tag->bit_names);
+
+	return tag;
+}
+
+void blkid_debug_dump_tag(blkid_tag tag)
+{
+	if (!tag) {
+		fprintf(stderr, "    tag: NULL\n");
+		return;
+	}
+
+	fprintf(stderr, "    tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
+}
+
+void blkid_free_tag(blkid_tag tag)
+{
+	if (!tag)
+		return;
+
+	DBG(TAG, ul_debug("    freeing tag %s=%s", tag->bit_name,
+		   tag->bit_val ? tag->bit_val : "(NULL)"));
+	DBG(TAG, blkid_debug_dump_tag(tag));
+
+	list_del(&tag->bit_tags);	/* list of tags for this device */
+	list_del(&tag->bit_names);	/* list of tags with this type */
+
+	free(tag->bit_name);
+	free(tag->bit_val);
+
+	free(tag);
+}
+
+/*
+ * Find the desired tag on a device.  If value is NULL, then the
+ * first such tag is returned, otherwise return only exact tag if found.
+ */
+blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
+{
+	struct list_head *p;
+
+	if (!dev || !type)
+		return NULL;
+
+	list_for_each(p, &dev->bid_tags) {
+		blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
+					   bit_tags);
+
+		if (!strcmp(tmp->bit_name, type))
+			return tmp;
+	}
+	return NULL;
+}
+
+int blkid_dev_has_tag(blkid_dev dev, const char *type,
+			     const char *value)
+{
+	blkid_tag		tag;
+
+	tag = blkid_find_tag_dev(dev, type);
+	if (!value)
+		return (tag != NULL);
+	if (!tag || strcmp(tag->bit_val, value))
+		return 0;
+	return 1;
+}
+
+/*
+ * Find the desired tag type in the cache.
+ * We return the head tag for this tag type.
+ */
+static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
+{
+	blkid_tag head = NULL, tmp;
+	struct list_head *p;
+
+	if (!cache || !type)
+		return NULL;
+
+	list_for_each(p, &cache->bic_tags) {
+		tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
+		if (!strcmp(tmp->bit_name, type)) {
+			DBG(TAG, ul_debug("    found cache tag head %s", type));
+			head = tmp;
+			break;
+		}
+	}
+	return head;
+}
+
+/*
+ * Set a tag on an existing device.
+ *
+ * If value is NULL, then delete the tagsfrom the device.
+ */
+int blkid_set_tag(blkid_dev dev, const char *name,
+		  const char *value, const int vlength)
+{
+	blkid_tag	t = 0, head = 0;
+	char		*val = 0;
+	char		**dev_var = 0;
+
+	if (!dev || !name)
+		return -BLKID_ERR_PARAM;
+
+	if (value && !(val = strndup(value, vlength)))
+		return -BLKID_ERR_MEM;
+
+	/*
+	 * Certain common tags are linked directly to the device struct
+	 * We need to know what they are before we do anything else because
+	 * the function name parameter might get freed later on.
+	 */
+	if (!strcmp(name, "TYPE"))
+		dev_var = &dev->bid_type;
+	else if (!strcmp(name, "LABEL"))
+		dev_var = &dev->bid_label;
+	else if (!strcmp(name, "UUID"))
+		dev_var = &dev->bid_uuid;
+
+	t = blkid_find_tag_dev(dev, name);
+	if (!value) {
+		if (t)
+			blkid_free_tag(t);
+	} else if (t) {
+		if (!strcmp(t->bit_val, val)) {
+			/* Same thing, exit */
+			free(val);
+			return 0;
+		}
+		free(t->bit_val);
+		t->bit_val = val;
+	} else {
+		/* Existing tag not present, add to device */
+		if (!(t = blkid_new_tag()))
+			goto errout;
+		t->bit_name = name ? strdup(name) : NULL;
+		t->bit_val = val;
+		t->bit_dev = dev;
+
+		list_add_tail(&t->bit_tags, &dev->bid_tags);
+
+		if (dev->bid_cache) {
+			head = blkid_find_head_cache(dev->bid_cache,
+						     t->bit_name);
+			if (!head) {
+				head = blkid_new_tag();
+				if (!head)
+					goto errout;
+
+				DBG(TAG, ul_debug("    creating new cache tag head %s", name));
+				head->bit_name = name ? strdup(name) : NULL;
+				if (!head->bit_name)
+					goto errout;
+				list_add_tail(&head->bit_tags,
+					      &dev->bid_cache->bic_tags);
+			}
+			list_add_tail(&t->bit_names, &head->bit_names);
+		}
+	}
+
+	/* Link common tags directly to the device struct */
+	if (dev_var)
+		*dev_var = val;
+
+	if (dev->bid_cache)
+		dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+	return 0;
+
+errout:
+	if (t)
+		blkid_free_tag(t);
+	else
+		free(val);
+	if (head)
+		blkid_free_tag(head);
+	return -BLKID_ERR_MEM;
+}
+
+
+/*
+ * Parse a "NAME=value" string.  This is slightly different than
+ * parse_token, because that will end an unquoted value at a space, while
+ * this will assume that an unquoted value is the rest of the token (e.g.
+ * if we are passed an already quoted string from the command-line we don't
+ * have to both quote and escape quote so that the quotes make it to
+ * us).
+ *
+ * Returns 0 on success, and -1 on failure.
+ */
+int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
+{
+	char *name, *value, *cp;
+
+	DBG(TAG, ul_debug("trying to parse '%s' as a tag", token));
+
+	if (!token || !(cp = strchr(token, '=')))
+		return -1;
+
+	name = strdup(token);
+	if (!name)
+		return -1;
+	value = name + (cp - token);
+	*value++ = '\0';
+	if (*value == '"' || *value == '\'') {
+		char c = *value++;
+		if (!(cp = strrchr(value, c)))
+			goto errout; /* missing closing quote */
+		*cp = '\0';
+	}
+
+	if (ret_val) {
+		value = value && *value ? strdup(value) : NULL;
+		if (!value)
+			goto errout;
+		*ret_val = value;
+	}
+
+	if (ret_type)
+		*ret_type = name;
+	else
+		free(name);
+
+	return 0;
+
+errout:
+	DBG(TAG, ul_debug("parse error: '%s'", token));
+	free(name);
+	return -1;
+}
+
+/*
+ * Tag iteration routines for the public libblkid interface.
+ *
+ * These routines do not expose the list.h implementation, which are a
+ * contamination of the namespace, and which force us to reveal far, far
+ * too much of our internal implemenation.  I'm not convinced I want
+ * to keep list.h in the long term, anyway.  It's fine for kernel
+ * programming, but performance is not the #1 priority for this
+ * library, and I really don't like the tradeoff of type-safety for
+ * performance for this application.  [tytso:20030125.2007EST]
+ */
+
+/*
+ * This series of functions iterate over all tags in a device
+ */
+#define TAG_ITERATE_MAGIC	0x01a5284c
+
+struct blkid_struct_tag_iterate {
+	int			magic;
+	blkid_dev		dev;
+	struct list_head	*p;
+};
+
+blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
+{
+	blkid_tag_iterate	iter;
+
+	if (!dev) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	iter = malloc(sizeof(struct blkid_struct_tag_iterate));
+	if (iter) {
+		iter->magic = TAG_ITERATE_MAGIC;
+		iter->dev = dev;
+		iter->p	= dev->bid_tags.next;
+	}
+	return (iter);
+}
+
+/*
+ * Return 0 on success, -1 on error
+ */
+int blkid_tag_next(blkid_tag_iterate iter,
+			  const char **type, const char **value)
+{
+	blkid_tag tag;
+
+	if (!type || !value ||
+	    !iter || iter->magic != TAG_ITERATE_MAGIC ||
+	    iter->p == &iter->dev->bid_tags)
+		return -1;
+
+	*type = 0;
+	*value = 0;
+	tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
+	*type = tag->bit_name;
+	*value = tag->bit_val;
+	iter->p = iter->p->next;
+	return 0;
+}
+
+void blkid_tag_iterate_end(blkid_tag_iterate iter)
+{
+	if (!iter || iter->magic != TAG_ITERATE_MAGIC)
+		return;
+	iter->magic = 0;
+	free(iter);
+}
+
+/*
+ * This function returns a device which matches a particular
+ * type/value pair.  If there is more than one device that matches the
+ * search specification, it returns the one with the highest priority
+ * value.  This allows us to give preference to EVMS or LVM devices.
+ */
+blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
+					 const char *type,
+					 const char *value)
+{
+	blkid_tag	head;
+	blkid_dev	dev;
+	int		pri;
+	struct list_head *p;
+	int		probe_new = 0;
+
+	if (!cache || !type || !value)
+		return NULL;
+
+	blkid_read_cache(cache);
+
+	DBG(TAG, ul_debug("looking for %s=%s in cache", type, value));
+
+try_again:
+	pri = -1;
+	dev = 0;
+	head = blkid_find_head_cache(cache, type);
+
+	if (head) {
+		list_for_each(p, &head->bit_names) {
+			blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
+						   bit_names);
+
+			if (!strcmp(tmp->bit_val, value) &&
+			    (tmp->bit_dev->bid_pri > pri) &&
+			    !access(tmp->bit_dev->bid_name, F_OK)) {
+				dev = tmp->bit_dev;
+				pri = dev->bid_pri;
+			}
+		}
+	}
+	if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
+		dev = blkid_verify(cache, dev);
+		if (!dev || (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)))
+			goto try_again;
+	}
+
+	if (!dev && !probe_new) {
+		if (blkid_probe_all_new(cache) < 0)
+			return NULL;
+		probe_new++;
+		goto try_again;
+	}
+
+	if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
+		if (blkid_probe_all(cache) < 0)
+			return NULL;
+		goto try_again;
+	}
+	return dev;
+}
+
+#ifdef TEST_PROGRAM
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+
+void __attribute__((__noreturn__)) usage(char *prog)
+{
+	fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device "
+		"[type value]\n",
+		prog);
+	fprintf(stderr, "\tList all tags for a device and exit\n");
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	blkid_tag_iterate	iter;
+	blkid_cache 		cache = NULL;
+	blkid_dev		dev;
+	int			c, ret, found;
+	int			flags = BLKID_DEV_FIND;
+	char			*tmp;
+	char			*file = NULL;
+	char			*devname = NULL;
+	char			*search_type = NULL;
+	char			*search_value = NULL;
+	const char		*type, *value;
+
+	while ((c = getopt (argc, argv, "m:f:")) != EOF)
+		switch (c) {
+		case 'f':
+			file = optarg;
+			break;
+		case 'm':
+		{
+			int mask = strtoul (optarg, &tmp, 0);
+			if (*tmp) {
+				fprintf(stderr, "Invalid debug mask: %s\n",
+					optarg);
+				exit(1);
+			}
+			blkid_init_debug(mask);
+			break;
+		}
+		case '?':
+			usage(argv[0]);
+		}
+	if (argc > optind)
+		devname = argv[optind++];
+	if (argc > optind)
+		search_type = argv[optind++];
+	if (argc > optind)
+		search_value = argv[optind++];
+	if (!devname || (argc != optind))
+		usage(argv[0]);
+
+	if ((ret = blkid_get_cache(&cache, file)) != 0) {
+		fprintf(stderr, "%s: error creating cache (%d)\n",
+			argv[0], ret);
+		exit(1);
+	}
+
+	dev = blkid_get_dev(cache, devname, flags);
+	if (!dev) {
+		fprintf(stderr, "%s: Can not find device in blkid cache\n",
+			devname);
+		exit(1);
+	}
+	if (search_type) {
+		found = blkid_dev_has_tag(dev, search_type, search_value);
+		printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev),
+		       search_type, search_value ? search_value : "NULL",
+		       found ? "FOUND" : "NOT FOUND");
+		return(!found);
+	}
+	printf("Device %s...\n", blkid_dev_devname(dev));
+
+	iter = blkid_tag_iterate_begin(dev);
+	while (blkid_tag_next(iter, &type, &value) == 0) {
+		printf("\tTag %s has value %s\n", type, value);
+	}
+	blkid_tag_iterate_end(iter);
+
+	blkid_put_cache(cache);
+	return (0);
+}
+#endif
diff --git a/libblkid/src/topology/dm.c b/libblkid/src/topology/dm.c
new file mode 100644
index 0000000..e061632
--- /dev/null
+++ b/libblkid/src/topology/dm.c
@@ -0,0 +1,135 @@
+/*
+ * device-mapper (dm) topology
+ * -- this is fallback for old systems where the topology information is not
+ *    exported by sysfs
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "topology.h"
+
+static int is_dm_device(dev_t devno)
+{
+	return blkid_driver_has_major("device-mapper", major(devno));
+}
+
+static int probe_dm_tp(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	const char *paths[] = {
+		"/usr/local/sbin/dmsetup",
+		"/usr/sbin/dmsetup",
+		"/sbin/dmsetup"
+	};
+	int dmpipe[] = { -1, -1 }, stripes, stripesize;
+	char *cmd = NULL;
+	FILE *stream = NULL;
+	long long  offset, size;
+	size_t i;
+	dev_t devno = blkid_probe_get_devno(pr);
+
+	if (!devno)
+		goto nothing;		/* probably not a block device */
+	if (!is_dm_device(devno))
+		goto nothing;
+
+	for (i = 0; i < ARRAY_SIZE(paths); i++) {
+		struct stat sb;
+		if (stat(paths[i], &sb) == 0) {
+			cmd = (char *) paths[i];
+			break;
+		}
+	}
+
+	if (!cmd)
+		goto nothing;
+	if (pipe(dmpipe) < 0) {
+		DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno));
+		goto nothing;
+	}
+
+	switch (fork()) {
+	case 0:
+	{
+		char *dmargv[7], maj[16], min[16];
+
+		/* Plumbing */
+		close(dmpipe[0]);
+
+		if (dmpipe[1] != STDOUT_FILENO)
+			dup2(dmpipe[1], STDOUT_FILENO);
+
+		/* The libblkid library could linked with setuid programs */
+		if (setgid(getgid()) < 0)
+			 exit(1);
+		if (setuid(getuid()) < 0)
+			 exit(1);
+
+		snprintf(maj, sizeof(maj), "%d", major(devno));
+		snprintf(min, sizeof(min), "%d", minor(devno));
+
+		dmargv[0] = cmd;
+		dmargv[1] = "table";
+		dmargv[2] = "-j";
+		dmargv[3] = maj;
+		dmargv[4] = "-m";
+		dmargv[5] = min;
+		dmargv[6] = NULL;
+
+		execv(dmargv[0], dmargv);
+
+		DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno));
+		exit(1);
+	}
+	case -1:
+		DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno));
+		goto nothing;
+	default:
+		break;
+	}
+
+	stream = fdopen(dmpipe[0], "r" UL_CLOEXECSTR);
+	if (!stream)
+		goto nothing;
+
+	if (fscanf(stream, "%lld %lld striped %d %d ",
+			&offset, &size, &stripes, &stripesize) != 0)
+		goto nothing;
+
+	blkid_topology_set_minimum_io_size(pr, stripesize << 9);
+	blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 9);
+
+	fclose(stream);
+	close(dmpipe[1]);
+	return 0;
+
+nothing:
+	if (stream)
+		fclose(stream);
+	else if (dmpipe[0] != -1)
+		close(dmpipe[0]);
+	if (dmpipe[1] != -1)
+		close(dmpipe[1]);
+	return 1;
+}
+
+const struct blkid_idinfo dm_tp_idinfo =
+{
+	.name		= "dm",
+	.probefunc	= probe_dm_tp,
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/topology/evms.c b/libblkid/src/topology/evms.c
new file mode 100644
index 0000000..7a4fd55
--- /dev/null
+++ b/libblkid/src/topology/evms.c
@@ -0,0 +1,77 @@
+/*
+ * Evms topology
+ * -- this is fallback for old systems where the toplogy information is not
+ *    exported by sysfs
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "topology.h"
+
+#define EVMS_MAJOR		117
+
+#ifndef _IOT__IOTBASE_u_int32_t
+#define _IOT__IOTBASE_u_int32_t IOT_SIMPLE(uint32_t)
+#endif
+#define _IOT_evms_stripe_info _IOT (_IOTS(uint32_t), 2, 0, 0, 0, 0)
+#define EVMS_GET_STRIPE_INFO	_IOR(EVMS_MAJOR, 0xF0, struct evms_stripe_info)
+
+struct evms_stripe_info {
+	uint32_t	size;		/* stripe unit 512-byte blocks */
+	uint32_t	width;		/* the number of stripe members or RAID data disks */
+} evms_stripe_info;
+
+static int is_evms_device(dev_t devno)
+{
+	if (major(devno) == EVMS_MAJOR)
+		return 1;
+	return blkid_driver_has_major("evms", major(devno));
+}
+
+static int probe_evms_tp(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	struct evms_stripe_info evms;
+	dev_t devno = blkid_probe_get_devno(pr);
+
+	if (!devno)
+		goto nothing;		/* probably not a block device */
+
+	if (!is_evms_device(devno))
+		goto nothing;
+
+	memset(&evms, 0, sizeof(evms));
+
+	if (ioctl(pr->fd, EVMS_GET_STRIPE_INFO, &evms))
+		goto nothing;
+
+	blkid_topology_set_minimum_io_size(pr, evms.size << 9);
+	blkid_topology_set_optimal_io_size(pr, (evms.size * evms.width) << 9);
+
+	return 0;
+
+nothing:
+	return 1;
+}
+
+const struct blkid_idinfo evms_tp_idinfo =
+{
+	.name		= "evms",
+	.probefunc	= probe_evms_tp,
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/topology/ioctl.c b/libblkid/src/topology/ioctl.c
new file mode 100644
index 0000000..3aba09e
--- /dev/null
+++ b/libblkid/src/topology/ioctl.c
@@ -0,0 +1,74 @@
+/*
+ * ioctl based topology -- gathers topology information
+ *
+ * Copyright (C) 2009 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 <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "topology.h"
+
+/*
+ * ioctl topology values
+ */
+static struct topology_val {
+
+	long  ioc;
+
+	/* functions to set probing result */
+	int (*set_ulong)(blkid_probe, unsigned long);
+	int (*set_int)(blkid_probe, int);
+
+} topology_vals[] = {
+	{ BLKALIGNOFF, NULL, blkid_topology_set_alignment_offset },
+	{ BLKIOMIN, blkid_topology_set_minimum_io_size },
+	{ BLKIOOPT, blkid_topology_set_optimal_io_size },
+	{ BLKPBSZGET, blkid_topology_set_physical_sector_size }
+	/* we read BLKSSZGET in topology.c */
+};
+
+static int probe_ioctl_tp(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(topology_vals); i++) {
+		struct topology_val *val = &topology_vals[i];
+		int rc = 1;
+		unsigned int data;
+
+		if (ioctl(pr->fd, val->ioc, &data) == -1)
+			goto nothing;
+
+		if (val->set_int)
+			rc = val->set_int(pr, (int) data);
+		else
+			rc = val->set_ulong(pr, (unsigned long) data);
+		if (rc)
+			goto err;
+	}
+
+	return 0;
+nothing:
+	return 1;
+err:
+	return -1;
+}
+
+const struct blkid_idinfo ioctl_tp_idinfo =
+{
+	.name		= "ioctl",
+	.probefunc	= probe_ioctl_tp,
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/topology/lvm.c b/libblkid/src/topology/lvm.c
new file mode 100644
index 0000000..bd079d4
--- /dev/null
+++ b/libblkid/src/topology/lvm.c
@@ -0,0 +1,147 @@
+/*
+ * lvm topology
+ * -- this is fallback for old systems where the topology information is not
+ *    exported by sysfs
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "topology.h"
+
+#ifndef LVM_BLK_MAJOR
+# define LVM_BLK_MAJOR     58
+#endif
+
+static int is_lvm_device(dev_t devno)
+{
+	if (major(devno) == LVM_BLK_MAJOR)
+		return 1;
+	return blkid_driver_has_major("lvm", major(devno));
+}
+
+static int probe_lvm_tp(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	const char *paths[] = {
+		"/usr/local/sbin/lvdisplay",
+		"/usr/sbin/lvdisplay",
+		"/sbin/lvdisplay"
+	};
+	int lvpipe[] = { -1, -1 }, stripes = 0, stripesize = 0;
+	FILE *stream = NULL;
+	char *cmd = NULL, *devname = NULL, buf[1024];
+	size_t i;
+	dev_t devno = blkid_probe_get_devno(pr);
+
+	if (!devno)
+		goto nothing;		/* probably not a block device */
+	if (!is_lvm_device(devno))
+		goto nothing;
+
+	for (i = 0; i < ARRAY_SIZE(paths); i++) {
+		struct stat sb;
+		if (stat(paths[i], &sb) == 0) {
+			cmd = (char *) paths[i];
+			break;
+		}
+	}
+
+	if (!cmd)
+		goto nothing;
+
+	devname = blkid_devno_to_devname(devno);
+	if (!devname)
+		goto nothing;
+
+	if (pipe(lvpipe) < 0) {
+		DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno));
+		goto nothing;
+	}
+
+	switch (fork()) {
+	case 0:
+	{
+		char *lvargv[3];
+
+		/* Plumbing */
+		close(lvpipe[0]);
+
+		if (lvpipe[1] != STDOUT_FILENO)
+			dup2(lvpipe[1], STDOUT_FILENO);
+
+		/* The libblkid library could linked with setuid programs */
+		if (setgid(getgid()) < 0)
+			 exit(1);
+		if (setuid(getuid()) < 0)
+			 exit(1);
+
+		lvargv[0] = cmd;
+		lvargv[1] = devname;
+		lvargv[2] = NULL;
+
+		execv(lvargv[0], lvargv);
+
+		DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno));
+		exit(1);
+	}
+	case -1:
+		DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno));
+		goto nothing;
+	default:
+		break;
+	}
+
+	stream = fdopen(lvpipe[0], "r" UL_CLOEXECSTR);
+	if (!stream)
+		goto nothing;
+
+	while (fgets(buf, sizeof(buf), stream) != NULL) {
+		if (!strncmp(buf, "Stripes", 7))
+			sscanf(buf, "Stripes %d", &stripes);
+
+		if (!strncmp(buf, "Stripe size", 11))
+			sscanf(buf, "Stripe size (KByte) %d", &stripesize);
+	}
+
+	if (!stripes)
+		goto nothing;
+
+	blkid_topology_set_minimum_io_size(pr, stripesize << 10);
+	blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 10);
+
+	free(devname);
+	fclose(stream);
+	close(lvpipe[1]);
+	return 0;
+
+nothing:
+	free(devname);
+	if (stream)
+		fclose(stream);
+	else if (lvpipe[0] != -1)
+		close(lvpipe[0]);
+	if (lvpipe[1] != -1)
+		close(lvpipe[1]);
+	return 1;
+}
+
+const struct blkid_idinfo lvm_tp_idinfo =
+{
+	.name		= "lvm",
+	.probefunc	= probe_lvm_tp,
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/topology/md.c b/libblkid/src/topology/md.c
new file mode 100644
index 0000000..5eba947
--- /dev/null
+++ b/libblkid/src/topology/md.c
@@ -0,0 +1,154 @@
+/*
+ * Linux Software RAID (md) topology
+ * -- this is fallback for old systems where the topology information is not
+ *    exported by sysfs
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "topology.h"
+
+#ifndef MD_MAJOR
+#define MD_MAJOR	9
+#endif
+
+#ifndef _IOT__IOTBASE_uint32_t
+#define _IOT__IOTBASE_uint32_t IOT_SIMPLE(uint32_t)
+#endif
+#define _IOT_md_array_info _IOT (_IOTS(uint32_t), 18, 0, 0, 0, 0)
+#define GET_ARRAY_INFO          _IOR (MD_MAJOR, 0x11, struct md_array_info)
+
+struct md_array_info {
+	/*
+	 * Generic constant information
+	 */
+	uint32_t major_version;
+	uint32_t minor_version;
+	uint32_t patch_version;
+	uint32_t ctime;
+	uint32_t level;
+	uint32_t size;
+	uint32_t nr_disks;
+	uint32_t raid_disks;
+	uint32_t md_minor;
+	uint32_t not_persistent;
+
+	/*
+	 * Generic state information
+	 */
+	uint32_t utime;	  /*  0 Superblock update time		  */
+	uint32_t state;	  /*  1 State bits (clean, ...)		  */
+	uint32_t active_disks;  /*  2 Number of currently active disks  */
+	uint32_t working_disks; /*  3 Number of working disks		  */
+	uint32_t failed_disks;  /*  4 Number of failed disks		  */
+	uint32_t spare_disks;	  /*  5 Number of spare disks		  */
+
+	/*
+	 * Personality information
+	 */
+	uint32_t layout;	  /*  0 the array's physical layout	  */
+	uint32_t chunk_size;	  /*  1 chunk size in bytes		  */
+
+};
+
+static int is_md_device(dev_t devno)
+{
+	if (major(devno) == MD_MAJOR)
+		return 1;
+	return blkid_driver_has_major("md", major(devno));
+}
+
+static int probe_md_tp(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	int fd = -1;
+	dev_t disk = 0;
+	dev_t devno = blkid_probe_get_devno(pr);
+	struct md_array_info md;
+
+	if (!devno)
+		goto nothing;		/* probably not a block device */
+
+	if (!is_md_device(devno))
+		goto nothing;
+
+	if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk))
+		goto nothing;
+
+	if (disk == devno)
+		fd = pr->fd;
+	else {
+		char *diskpath = blkid_devno_to_devname(disk);
+
+		if (!diskpath)
+			goto nothing;
+
+		fd = open(diskpath, O_RDONLY|O_CLOEXEC);
+		free(diskpath);
+
+                if (fd == -1)
+			goto nothing;
+	}
+
+	memset(&md, 0, sizeof(md));
+
+	if (ioctl(fd, GET_ARRAY_INFO, &md))
+		goto nothing;
+
+	if (fd >= 0 && fd != pr->fd) {
+		close(fd);
+		fd = -1;
+	}
+
+	/*
+	 * Ignore levels we don't want aligned (e.g. linear)
+	 * and deduct disk(s) from stripe width on RAID4/5/6
+	 */
+	switch (md.level) {
+	case 6:
+		md.raid_disks--;
+		/* fallthrough */
+	case 5:
+	case 4:
+		md.raid_disks--;
+		/* fallthrough */
+	case 1:
+	case 0:
+	case 10:
+		break;
+	default:
+		goto nothing;
+	}
+
+	blkid_topology_set_minimum_io_size(pr, md.chunk_size);
+	blkid_topology_set_optimal_io_size(pr, md.chunk_size * md.raid_disks);
+
+	return 0;
+
+nothing:
+	if (fd >= 0 && fd != pr->fd)
+		close(fd);
+	return 1;
+}
+
+const struct blkid_idinfo md_tp_idinfo =
+{
+	.name		= "md",
+	.probefunc	= probe_md_tp,
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/topology/sysfs.c b/libblkid/src/topology/sysfs.c
new file mode 100644
index 0000000..a04b20a
--- /dev/null
+++ b/libblkid/src/topology/sysfs.c
@@ -0,0 +1,119 @@
+/*
+ * sysfs based topology -- gathers topology information from Linux sysfs
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * For more information see Linux kernel Documentation/ABI/testing/sysfs-block.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "sysfs.h"
+#include "topology.h"
+
+/*
+ * Sysfs topology values (since 2.6.31, May 2009).
+ */
+static struct topology_val {
+
+	/* /sys/dev/block/<maj>:<min>/<ATTR> */
+	const char *attr;
+
+	/* functions to set probing resut */
+	int (*set_ulong)(blkid_probe, unsigned long);
+	int (*set_int)(blkid_probe, int);
+
+} topology_vals[] = {
+	{ "alignment_offset", NULL, blkid_topology_set_alignment_offset },
+	{ "queue/minimum_io_size", blkid_topology_set_minimum_io_size },
+	{ "queue/optimal_io_size", blkid_topology_set_optimal_io_size },
+	{ "queue/physical_block_size", blkid_topology_set_physical_sector_size },
+};
+
+static int probe_sysfs_tp(blkid_probe pr,
+		const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+	dev_t dev, disk = 0;
+	int rc;
+	struct sysfs_cxt sysfs = UL_SYSFSCXT_EMPTY,
+			 parent = UL_SYSFSCXT_EMPTY;
+	size_t i, count = 0;
+
+	dev = blkid_probe_get_devno(pr);
+	if (!dev || sysfs_init(&sysfs, dev, NULL) != 0)
+		return 1;
+
+	rc = 1;		/* nothing (default) */
+
+	for (i = 0; i < ARRAY_SIZE(topology_vals); i++) {
+		struct topology_val *val = &topology_vals[i];
+		int ok = sysfs_has_attribute(&sysfs, val->attr);
+
+		rc = 1;	/* nothing */
+
+		if (!ok) {
+			if (!disk) {
+				/*
+				 * Read atrributes from "disk" if the current
+				 * device is a partition.
+				 */
+				disk = blkid_probe_get_wholedisk_devno(pr);
+				if (disk && disk != dev) {
+					if (sysfs_init(&parent, disk, NULL) != 0)
+						goto done;
+
+					sysfs.parent = &parent;
+					ok = sysfs_has_attribute(&sysfs,
+								 val->attr);
+				}
+			}
+			if (!ok)
+				continue;	/* attribute does not exist */
+		}
+
+		if (val->set_ulong) {
+			uint64_t data;
+
+			if (sysfs_read_u64(&sysfs, val->attr, &data) != 0)
+				continue;
+			rc = val->set_ulong(pr, (unsigned long) data);
+
+		} else if (val->set_int) {
+			int64_t data;
+
+			if (sysfs_read_s64(&sysfs, val->attr, &data) != 0)
+				continue;
+			rc = val->set_int(pr, (int) data);
+		}
+
+		if (rc < 0)
+			goto done;	/* error */
+		if (rc == 0)
+			count++;
+	}
+
+done:
+	sysfs_deinit(&sysfs);
+	sysfs_deinit(&parent);
+
+	if (count)
+		return 0;		/* success */
+	return rc;			/* error or nothing */
+}
+
+const struct blkid_idinfo sysfs_tp_idinfo =
+{
+	.name		= "sysfs",
+	.probefunc	= probe_sysfs_tp,
+	.magics		= BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/topology/topology.c b/libblkid/src/topology/topology.c
new file mode 100644
index 0000000..93fa380
--- /dev/null
+++ b/libblkid/src/topology/topology.c
@@ -0,0 +1,362 @@
+/*
+ * topology - gathers information about device topology
+ *
+ * Copyright 2009 Red Hat, Inc.  All rights reserved.
+ *
+ * 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 <stddef.h>
+
+#include "topology.h"
+
+/**
+ * SECTION:topology
+ * @title: Topology information
+ * @short_description: block device topology information.
+ *
+ * The topology chain provides details about Linux block devices, for more
+ * information see:
+ *
+ *      Linux kernel Documentation/ABI/testing/sysfs-block
+ *
+ * NAME=value (tags) interface is enabled by blkid_probe_enable_topology(),
+ * and provides:
+ *
+ * @LOGICAL_SECTOR_SIZE: this is the smallest unit the storage device can
+ *                       address. It is typically 512 bytes.
+ *
+ * @PHYSICAL_SECTOR_SIZE: this is the smallest unit a physical storage device
+ *                        can write atomically. It is usually the same as the
+ *                        logical sector size but may be bigger.
+ *
+ * @MINIMUM_IO_SIZE: minimum size which is the device's preferred unit of I/O.
+ *                   For RAID arrays it is often the stripe chunk size.
+ *
+ * @OPTIMAL_IO_SIZE: usually the stripe width for RAID or zero. For RAID arrays
+ *                   it is usually the stripe width or the internal track size.
+ *
+ * @ALIGNMENT_OFFSET: indicates how many bytes the beginning of the device is
+ *                    offset from the disk's natural alignment.
+ *
+ * The NAME=value tags are not defined when the corresponding topology value
+ * is zero. The MINIMUM_IO_SIZE should be always defined if kernel provides
+ * topology information.
+ *
+ * Binary interface:
+ *
+ * blkid_probe_get_topology()
+ *
+ * blkid_topology_get_'VALUENAME'()
+ */
+static int topology_probe(blkid_probe pr, struct blkid_chain *chn);
+static void topology_free(blkid_probe pr, void *data);
+static int topology_is_complete(blkid_probe pr);
+static int topology_set_logical_sector_size(blkid_probe pr);
+
+/*
+ * Binary interface
+ */
+struct blkid_struct_topology {
+	unsigned long	alignment_offset;
+	unsigned long	minimum_io_size;
+	unsigned long	optimal_io_size;
+	unsigned long	logical_sector_size;
+	unsigned long	physical_sector_size;
+};
+
+/*
+ * Topology chain probing functions
+ */
+static const struct blkid_idinfo *idinfos[] =
+{
+#ifdef __linux__
+	&ioctl_tp_idinfo,
+	&sysfs_tp_idinfo,
+	&md_tp_idinfo,
+	&dm_tp_idinfo,
+	&lvm_tp_idinfo,
+	&evms_tp_idinfo
+#endif
+};
+
+
+/*
+ * Driver definition
+ */
+const struct blkid_chaindrv topology_drv = {
+	.id           = BLKID_CHAIN_TOPLGY,
+	.name         = "topology",
+	.dflt_enabled = FALSE,
+	.idinfos      = idinfos,
+	.nidinfos     = ARRAY_SIZE(idinfos),
+	.probe        = topology_probe,
+	.safeprobe    = topology_probe,
+	.free_data    = topology_free
+};
+
+/**
+ * blkid_probe_enable_topology:
+ * @pr: probe
+ * @enable: TRUE/FALSE
+ *
+ * Enables/disables the topology probing for non-binary interface.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_enable_topology(blkid_probe pr, int enable)
+{
+	if (!pr)
+		return -1;
+	pr->chains[BLKID_CHAIN_TOPLGY].enabled = enable;
+	return 0;
+}
+
+/**
+ * blkid_probe_get_topology:
+ * @pr: probe
+ *
+ * This is a binary interface for topology values. See also blkid_topology_*
+ * functions.
+ *
+ * This function is independent on blkid_do_[safe,full]probe() and
+ * blkid_probe_enable_topology() calls.
+ *
+ * WARNING: the returned object will be overwritten by the next
+ *          blkid_probe_get_topology() call for the same @pr. If you want to
+ *          use more blkid_topopogy objects in the same time you have to create
+ *          more blkid_probe handlers (see blkid_new_probe()).
+ *
+ * Returns: blkid_topopogy, or NULL in case of error.
+ */
+blkid_topology blkid_probe_get_topology(blkid_probe pr)
+{
+	return (blkid_topology) blkid_probe_get_binary_data(pr,
+			&pr->chains[BLKID_CHAIN_TOPLGY]);
+}
+
+/*
+ * The blkid_do_probe() backend.
+ */
+static int topology_probe(blkid_probe pr, struct blkid_chain *chn)
+{
+	size_t i;
+
+	if (!pr || chn->idx < -1)
+		return -1;
+
+	if (!S_ISBLK(pr->mode))
+		return -EINVAL;	/* nothing, works with block devices only */
+
+	if (chn->binary) {
+		DBG(LOWPROBE, ul_debug("initialize topology binary data"));
+
+		if (chn->data)
+			/* reset binary data */
+			memset(chn->data, 0,
+					sizeof(struct blkid_struct_topology));
+		else {
+			chn->data = calloc(1,
+					sizeof(struct blkid_struct_topology));
+			if (!chn->data)
+				return -ENOMEM;
+		}
+	}
+
+	blkid_probe_chain_reset_vals(pr, chn);
+
+	DBG(LOWPROBE, ul_debug("--> starting probing loop [TOPOLOGY idx=%d]",
+		chn->idx));
+
+	i = chn->idx < 0 ? 0 : chn->idx + 1U;
+
+	for ( ; i < ARRAY_SIZE(idinfos); i++) {
+		const struct blkid_idinfo *id = idinfos[i];
+
+		chn->idx = i;
+
+		if (id->probefunc) {
+			DBG(LOWPROBE, ul_debug("%s: call probefunc()", id->name));
+			if (id->probefunc(pr, NULL) != 0)
+				continue;
+		}
+
+		if (!topology_is_complete(pr))
+			continue;
+
+		/* generic for all probing drivers */
+		topology_set_logical_sector_size(pr);
+
+		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [TOPOLOGY idx=%d]",
+			id->name, chn->idx));
+		return BLKID_PROBE_OK;
+	}
+
+	DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed) [TOPOLOGY idx=%d]",
+		chn->idx));
+	return BLKID_PROBE_NONE;
+}
+
+static void topology_free(blkid_probe pr __attribute__((__unused__)),
+			  void *data)
+{
+	free(data);
+}
+
+static int topology_set_value(blkid_probe pr, const char *name,
+				size_t structoff, unsigned long data)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+	if (!chn)
+		return -1;
+	if (!data)
+		return 0;	/* ignore zeros */
+
+	if (chn->binary) {
+		memcpy(chn->data + structoff, &data, sizeof(data));
+		return 0;
+	}
+	return blkid_probe_sprintf_value(pr, name, "%lu", data);
+}
+
+
+/* the topology info is complete when we have at least "minimum_io_size" which
+ * is provided by all blkid topology drivers */
+static int topology_is_complete(blkid_probe pr)
+{
+	struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+	if (!chn)
+		return FALSE;
+
+	if (chn->binary && chn->data) {
+		blkid_topology tp = (blkid_topology) chn->data;
+		if (tp->minimum_io_size)
+			return TRUE;
+	}
+
+	return __blkid_probe_lookup_value(pr, "MINIMUM_IO_SIZE") ? TRUE : FALSE;
+}
+
+int blkid_topology_set_alignment_offset(blkid_probe pr, int val)
+{
+	unsigned long xval;
+
+	/* Welcome to Hell. The kernel is able to return -1 as an
+	 * alignment_offset if no compatible sizes and alignments
+	 * exist for stacked devices.
+	 *
+	 * There is no way how libblkid caller can respond to the value -1, so
+	 * we will hide this corner case...
+	 *
+	 * (TODO: maybe we can export an extra boolean value 'misaligned' rather
+	 *  then complete hide this problem.)
+	 */
+	xval = val < 0 ? 0 : val;
+
+	return topology_set_value(pr,
+			"ALIGNMENT_OFFSET",
+			offsetof(struct blkid_struct_topology, alignment_offset),
+			xval);
+}
+
+int blkid_topology_set_minimum_io_size(blkid_probe pr, unsigned long val)
+{
+	return topology_set_value(pr,
+			"MINIMUM_IO_SIZE",
+			offsetof(struct blkid_struct_topology, minimum_io_size),
+			val);
+}
+
+int blkid_topology_set_optimal_io_size(blkid_probe pr, unsigned long val)
+{
+	return topology_set_value(pr,
+			"OPTIMAL_IO_SIZE",
+			offsetof(struct blkid_struct_topology, optimal_io_size),
+			val);
+}
+
+/* BLKSSZGET is provided on all systems since 2.3.3 -- so we don't have to
+ * waste time with sysfs.
+ */
+static int topology_set_logical_sector_size(blkid_probe pr)
+{
+	unsigned long val = blkid_probe_get_sectorsize(pr);
+
+	if (!val)
+		return -1;
+
+	return topology_set_value(pr,
+			"LOGICAL_SECTOR_SIZE",
+			offsetof(struct blkid_struct_topology, logical_sector_size),
+			val);
+}
+
+int blkid_topology_set_physical_sector_size(blkid_probe pr, unsigned long val)
+{
+	return topology_set_value(pr,
+			"PHYSICAL_SECTOR_SIZE",
+			offsetof(struct blkid_struct_topology, physical_sector_size),
+			val);
+}
+
+/**
+ * blkid_topology_get_alignment_offset:
+ * @tp: topology
+ *
+ * Returns: alignment offset in bytes or 0.
+ */
+unsigned long blkid_topology_get_alignment_offset(blkid_topology tp)
+{
+	return tp->alignment_offset;
+}
+
+/**
+ * blkid_topology_get_minimum_io_size:
+ * @tp: topology
+ *
+ * Returns: minimum io size in bytes or 0.
+ */
+unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp)
+{
+	return tp->minimum_io_size;
+}
+
+/**
+ * blkid_topology_get_optimal_io_size
+ * @tp: topology
+ *
+ * Returns: optimal io size in bytes or 0.
+ */
+unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp)
+{
+	return tp->optimal_io_size;
+}
+
+/**
+ * blkid_topology_get_logical_sector_size
+ * @tp: topology
+ *
+ * Returns: logical sector size (BLKSSZGET ioctl) in bytes or 0.
+ */
+unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp)
+{
+	return tp->logical_sector_size;
+}
+
+/**
+ * blkid_topology_get_physical_sector_size
+ * @tp: topology
+ *
+ * Returns: logical sector size (BLKSSZGET ioctl) in bytes or 0.
+ */
+unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp)
+{
+	return tp->physical_sector_size;
+}
+
diff --git a/libblkid/src/topology/topology.h b/libblkid/src/topology/topology.h
new file mode 100644
index 0000000..6d2f433
--- /dev/null
+++ b/libblkid/src/topology/topology.h
@@ -0,0 +1,24 @@
+#ifndef BLKID_TOPOLOGY_H
+#define BLKID_TOPOLOGY_H
+
+#include "blkidP.h"
+
+extern int blkid_topology_set_alignment_offset(blkid_probe pr, int val);
+extern int blkid_topology_set_minimum_io_size(blkid_probe pr, unsigned long val);
+extern int blkid_topology_set_optimal_io_size(blkid_probe pr, unsigned long val);
+extern int blkid_topology_set_physical_sector_size(blkid_probe pr, unsigned long val);
+
+/*
+ * topology probers
+ */
+#ifdef __linux__
+extern const struct blkid_idinfo ioctl_tp_idinfo;
+extern const struct blkid_idinfo md_tp_idinfo;
+extern const struct blkid_idinfo evms_tp_idinfo;
+extern const struct blkid_idinfo sysfs_tp_idinfo;
+extern const struct blkid_idinfo dm_tp_idinfo;
+extern const struct blkid_idinfo lvm_tp_idinfo;
+#endif
+
+#endif /* BLKID_TOPOLOGY_H */
+
diff --git a/libblkid/src/verify.c b/libblkid/src/verify.c
new file mode 100644
index 0000000..06f6d53
--- /dev/null
+++ b/libblkid/src/verify.c
@@ -0,0 +1,224 @@
+/*
+ * 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 <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "blkidP.h"
+#include "sysfs.h"
+
+static void blkid_probe_to_tags(blkid_probe pr, blkid_dev dev)
+{
+	const char *data;
+	const char *name;
+	int nvals, n;
+	size_t len;
+
+	nvals = blkid_probe_numof_values(pr);
+
+	for (n = 0; n < nvals; n++) {
+		if (blkid_probe_get_value(pr, n, &name, &data, &len) != 0)
+			continue;
+		if (strncmp(name, "PART_ENTRY_", 11) == 0) {
+			if (strcmp(name, "PART_ENTRY_UUID") == 0)
+				blkid_set_tag(dev, "PARTUUID", data, len);
+			else if (strcmp(name, "PART_ENTRY_NAME") == 0)
+				blkid_set_tag(dev, "PARTLABEL", data, len);
+
+		} else if (!strstr(name, "_ID")) {
+			/* superblock UUID, LABEL, ...
+			 * but not {SYSTEM,APPLICATION,..._ID} */
+			blkid_set_tag(dev, name, data, len);
+		}
+	}
+}
+
+/*
+ * Verify that the data in dev is consistent with what is on the actual
+ * block device (using the devname field only).  Normally this will be
+ * called when finding items in the cache, but for long running processes
+ * is also desirable to revalidate an item before use.
+ *
+ * If we are unable to revalidate the data, we return the old data and
+ * do not set the BLKID_BID_FL_VERIFIED flag on it.
+ */
+blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev)
+{
+	blkid_tag_iterate iter;
+	const char *type, *value;
+	struct stat st;
+	time_t diff, now;
+	int fd;
+
+	if (!dev || !cache)
+		return NULL;
+
+	now = time(0);
+	diff = now - dev->bid_time;
+
+	if (stat(dev->bid_name, &st) < 0) {
+		DBG(PROBE, ul_debug("blkid_verify: error %m (%d) while "
+			   "trying to stat %s", errno,
+			   dev->bid_name));
+	open_err:
+		if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) {
+			/* We don't have read permission, just return cache data. */
+			DBG(PROBE, ul_debug("returning unverified data for %s",
+						dev->bid_name));
+			return dev;
+		}
+		blkid_free_dev(dev);
+		return NULL;
+	}
+
+	if (now >= dev->bid_time &&
+#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+	    (st.st_mtime < dev->bid_time ||
+	        (st.st_mtime == dev->bid_time &&
+		 st.st_mtim.tv_nsec / 1000 <= dev->bid_utime)) &&
+#else
+	    st.st_mtime <= dev->bid_time &&
+#endif
+	    (diff < BLKID_PROBE_MIN ||
+		(dev->bid_flags & BLKID_BID_FL_VERIFIED &&
+		 diff < BLKID_PROBE_INTERVAL)))
+		return dev;
+
+#ifndef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+	DBG(PROBE, ul_debug("need to revalidate %s (cache time %lu, stat time %lu,\t"
+		   "time since last check %lu)",
+		   dev->bid_name, (unsigned long)dev->bid_time,
+		   (unsigned long)st.st_mtime, (unsigned long)diff));
+#else
+	DBG(PROBE, ul_debug("need to revalidate %s (cache time %lu.%lu, stat time %lu.%lu,\t"
+		   "time since last check %lu)",
+		   dev->bid_name,
+		   (unsigned long)dev->bid_time, (unsigned long)dev->bid_utime,
+		   (unsigned long)st.st_mtime, (unsigned long)st.st_mtim.tv_nsec / 1000,
+		   (unsigned long)diff));
+#endif
+
+	if (sysfs_devno_is_lvm_private(st.st_rdev)) {
+		blkid_free_dev(dev);
+		return NULL;
+	}
+	if (!cache->probe) {
+		cache->probe = blkid_new_probe();
+		if (!cache->probe) {
+			blkid_free_dev(dev);
+			return NULL;
+		}
+	}
+
+	fd = open(dev->bid_name, O_RDONLY|O_CLOEXEC);
+	if (fd < 0) {
+		DBG(PROBE, ul_debug("blkid_verify: error %m (%d) while "
+					"opening %s", errno,
+					dev->bid_name));
+		goto open_err;
+	}
+
+	if (blkid_probe_set_device(cache->probe, fd, 0, 0)) {
+		/* failed to read the device */
+		close(fd);
+		blkid_free_dev(dev);
+		return NULL;
+	}
+
+	/* remove old cache info */
+	iter = blkid_tag_iterate_begin(dev);
+	while (blkid_tag_next(iter, &type, &value) == 0)
+		blkid_set_tag(dev, type, NULL, 0);
+	blkid_tag_iterate_end(iter);
+
+	/* enable superblocks probing */
+	blkid_probe_enable_superblocks(cache->probe, TRUE);
+	blkid_probe_set_superblocks_flags(cache->probe,
+		BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
+		BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE);
+
+	/* enable partitions probing */
+	blkid_probe_enable_partitions(cache->probe, TRUE);
+	blkid_probe_set_partitions_flags(cache->probe, BLKID_PARTS_ENTRY_DETAILS);
+
+	/* probe */
+	if (blkid_do_safeprobe(cache->probe)) {
+		/* found nothing or error */
+		blkid_free_dev(dev);
+		dev = NULL;
+	}
+
+	if (dev) {
+#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+		struct timeval tv;
+		if (!gettimeofday(&tv, NULL)) {
+			dev->bid_time = tv.tv_sec;
+			dev->bid_utime = tv.tv_usec;
+		} else
+#endif
+			dev->bid_time = time(0);
+
+		dev->bid_devno = st.st_rdev;
+		dev->bid_flags |= BLKID_BID_FL_VERIFIED;
+		cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+
+		blkid_probe_to_tags(cache->probe, dev);
+
+		DBG(PROBE, ul_debug("%s: devno 0x%04llx, type %s",
+			   dev->bid_name, (long long)st.st_rdev, dev->bid_type));
+	}
+
+	blkid_reset_probe(cache->probe);
+	blkid_probe_reset_superblocks_filter(cache->probe);
+	close(fd);
+	return dev;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+	blkid_dev dev;
+	blkid_cache cache;
+	int ret;
+
+	if (argc != 2) {
+		fprintf(stderr, "Usage: %s device\n"
+			"Probe a single device to determine type\n", argv[0]);
+		exit(1);
+	}
+	if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
+		fprintf(stderr, "%s: error creating cache (%d)\n",
+			argv[0], ret);
+		exit(1);
+	}
+	dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL);
+	if (!dev) {
+		printf("%s: %s has an unsupported type\n", argv[0], argv[1]);
+		return (1);
+	}
+	printf("TYPE='%s'\n", dev->bid_type ? dev->bid_type : "(null)");
+	if (dev->bid_label)
+		printf("LABEL='%s'\n", dev->bid_label);
+	if (dev->bid_uuid)
+		printf("UUID='%s'\n", dev->bid_uuid);
+
+	blkid_free_dev(dev);
+	return (0);
+}
+#endif
diff --git a/libblkid/src/version.c b/libblkid/src/version.c
new file mode 100644
index 0000000..9d129f7
--- /dev/null
+++ b/libblkid/src/version.c
@@ -0,0 +1,62 @@
+/*
+ * version.c --- Return the version of the blkid library
+ *
+ * Copyright (C) 2004 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Lesser General
+ * Public License.
+ * %End-Header%
+ */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include <blkid.h>
+
+/* LIBBLKID_* defined in the global config.h */
+static const char *lib_version = LIBBLKID_VERSION;	/* release version */
+static const char *lib_date = LIBBLKID_DATE;
+
+/**
+ * blkid_parse_version_string:
+ * @ver_string:  version string (e.g. "2.16.0")
+ *
+ * Returns: release version code.
+ */
+int blkid_parse_version_string(const char *ver_string)
+{
+	const char *cp;
+	int version = 0;
+
+	for (cp = ver_string; *cp; cp++) {
+		if (*cp == '.')
+			continue;
+		if (!isdigit(*cp))
+			break;
+		version = (version * 10) + (*cp - '0');
+	}
+	return version;
+}
+
+/**
+ * blkid_get_library_version:
+ * @ver_string: returns relese version (!= SONAME version)
+ * @date_string: returns date
+ *
+ * Returns: release version code.
+ */
+int blkid_get_library_version(const char **ver_string,
+			       const char **date_string)
+{
+	if (ver_string)
+		*ver_string = lib_version;
+	if (date_string)
+		*date_string = lib_date;
+
+	return blkid_parse_version_string(lib_version);
+}
diff --git a/libblkid/src/widechar.h b/libblkid/src/widechar.h
new file mode 100644
index 0000000..b023b5f
--- /dev/null
+++ b/libblkid/src/widechar.h
@@ -0,0 +1,38 @@
+/* Declarations for wide characters */
+/* This file must be included last because the redefinition of wchar_t may
+   cause conflicts when system include files were included after it. */
+
+#ifdef HAVE_WIDECHAR
+
+# include <wchar.h>
+# include <wctype.h>
+
+#else /* !HAVE_WIDECHAR */
+
+# include <ctype.h>
+  /* Fallback for types */
+# define wchar_t char
+# define wint_t int
+# define WEOF EOF
+  /* Fallback for input operations */
+# define fgetwc fgetc
+# define getwc getc
+# define getwchar getchar
+# define fgetws fgets
+  /* Fallback for output operations */
+# define fputwc fputc
+# define putwc putc
+# define putwchar putchar
+# define fputws fputs
+  /* Fallback for character classification */
+# define iswgraph isgraph
+# define iswprint isprint
+# define iswspace isspace
+  /* Fallback for string functions */
+# define wcschr strchr
+# define wcsdup strdup
+# define wcslen strlen
+
+# define wcwidth(c) 1
+
+#endif /* HAVE_WIDECHAR */
diff --git a/libblkid/src/xalloc.h b/libblkid/src/xalloc.h
new file mode 100644
index 0000000..f012fb2
--- /dev/null
+++ b/libblkid/src/xalloc.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * General memory allocation wrappers for malloc, realloc, calloc and strdup
+ */
+
+#ifndef UTIL_LINUX_XALLOC_H
+#define UTIL_LINUX_XALLOC_H
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "c.h"
+
+#ifndef XALLOC_EXIT_CODE
+# define XALLOC_EXIT_CODE EXIT_FAILURE
+#endif
+
+static inline __ul_alloc_size(1)
+void *xmalloc(const size_t size)
+{
+        void *ret = malloc(size);
+
+        if (!ret && size)
+                err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size);
+        return ret;
+}
+
+static inline __ul_alloc_size(2)
+void *xrealloc(void *ptr, const size_t size)
+{
+        void *ret = realloc(ptr, size);
+
+        if (!ret && size)
+                err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size);
+        return ret;
+}
+
+static inline __ul_calloc_size(1, 2)
+void *xcalloc(const size_t nelems, const size_t size)
+{
+        void *ret = calloc(nelems, size);
+
+        if (!ret && size && nelems)
+                err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size);
+        return ret;
+}
+
+static inline char __attribute__((warn_unused_result)) *xstrdup(const char *str)
+{
+        char *ret;
+
+        if (!str)
+                return NULL;
+
+        ret = strdup(str);
+
+        if (!ret)
+                err(XALLOC_EXIT_CODE, "cannot duplicate string");
+        return ret;
+}
+
+static inline char * __attribute__((warn_unused_result)) xstrndup(const char *str, size_t size)
+{
+        char *ret;
+
+        if (!str)
+                return NULL;
+
+        ret = strndup(str, size);
+
+        if (!ret)
+                err(XALLOC_EXIT_CODE, "cannot duplicate string");
+        return ret;
+}
+
+
+static inline int __attribute__ ((__format__(printf, 2, 3)))
+    xasprintf(char **strp, const char *fmt, ...)
+{
+	int ret;
+	va_list args;
+	va_start(args, fmt);
+	ret = vasprintf(&(*strp), fmt, args);
+	va_end(args);
+	if (ret < 0)
+		err(XALLOC_EXIT_CODE, "cannot allocate string");
+	return ret;
+}
+
+static inline int xvasprintf(char **strp, const char *fmt, va_list ap)
+{
+	int ret = vasprintf(&(*strp), fmt, ap);
+	if (ret < 0)
+		err(XALLOC_EXIT_CODE, "cannot allocate string");
+	return ret;
+}
+
+
+static inline char * __attribute__((warn_unused_result)) xgethostname(void)
+{
+	char *name;
+	size_t sz = get_hostname_max() + 1;
+
+	name = xmalloc(sizeof(char) * sz);
+
+	if (gethostname(name, sz) != 0) {
+		free(name);
+		return NULL;
+	}
+	name[sz - 1] = '\0';
+	return name;
+}
+
+#endif