use libblkid to get filesystem type
we can now use libblkid to detect exfat
diff --git a/libblkid/ext.c b/libblkid/ext.c
new file mode 100644
index 0000000..eff96a0
--- /dev/null
+++ b/libblkid/ext.c
@@ -0,0 +1,540 @@
+/*
+ * 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 "linux_version.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
+
+/*
+ * Check to see if a filesystem is in /proc/filesystems.
+ * Returns 1 if found, 0 if not
+ */
+static int fs_proc_check(const char *fs_name)
+{
+	FILE	*f;
+	char	buf[80], *cp, *t;
+
+	f = fopen("/proc/filesystems", "r");
+	if (!f)
+		return 0;
+	while (!feof(f)) {
+		if (!fgets(buf, sizeof(buf), f))
+			break;
+		cp = buf;
+		if (!isspace(*cp)) {
+			while (*cp && !isspace(*cp))
+				cp++;
+		}
+		while (*cp && isspace(*cp))
+			cp++;
+		if ((t = strchr(cp, '\n')) != NULL)
+			*t = 0;
+		if ((t = strchr(cp, '\t')) != NULL)
+			*t = 0;
+		if ((t = strchr(cp, ' ')) != NULL)
+			*t = 0;
+		if (!strcmp(fs_name, cp)) {
+			fclose(f);
+			return 1;
+		}
+	}
+	fclose(f);
+	return (0);
+}
+
+/*
+ * Check to see if a filesystem is available as a module
+ * Returns 1 if found, 0 if not
+ */
+static int check_for_modules(const char *fs_name)
+{
+#ifdef __linux__
+	struct utsname	uts;
+	FILE		*f;
+	char		buf[1024], *cp;
+	int		namesz;
+
+	if (uname(&uts))
+		return 0;
+	snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release);
+
+	f = fopen(buf, "r");
+	if (!f)
+		return 0;
+
+	namesz = strlen(fs_name);
+
+	while (!feof(f)) {
+		if (!fgets(buf, sizeof(buf), f))
+			break;
+		if ((cp = strchr(buf, ':')) != NULL)
+			*cp = 0;
+		else
+			continue;
+		if ((cp = strrchr(buf, '/')) == NULL)
+			continue;
+		cp++;
+
+		if (!strncmp(cp, fs_name, namesz) &&
+		    (!strcmp(cp + namesz, ".ko") ||
+		     !strcmp(cp + namesz, ".ko.gz"))) {
+			fclose(f);
+			return 1;
+		}
+	}
+	fclose(f);
+#endif /* __linux__ */
+	return 0;
+}
+
+/*
+ * Starting in 2.6.29, ext4 can be used to support filesystems
+ * without a journal.
+ */
+#define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29)
+
+static int system_supports_ext2(void)
+{
+	static time_t	last_check = 0;
+	static int	ret = -1;
+	time_t		now = time(0);
+
+	if (ret != -1 || (now - last_check) < 5)
+		return ret;
+	last_check = now;
+	ret = (fs_proc_check("ext2") || check_for_modules("ext2"));
+	return ret;
+}
+
+static int system_supports_ext4(void)
+{
+	static time_t	last_check = 0;
+	static int	ret = -1;
+	time_t		now = time(0);
+
+	if (ret != -1 || (now - last_check) < 5)
+		return ret;
+	last_check = now;
+	ret = (fs_proc_check("ext4") || check_for_modules("ext4"));
+	return ret;
+}
+
+static int system_supports_ext4dev(void)
+{
+	static time_t	last_check = 0;
+	static int	ret = -1;
+	time_t		now = time(0);
+
+	if (ret != -1 || (now - last_check) < 5)
+		return ret;
+	last_check = now;
+	ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev"));
+	return ret;
+}
+
+static int system_supports_ext4_ext2(void)
+{
+#ifdef __linux__
+	return get_linux_version() >= EXT4_SUPPORTS_EXT2;
+#else
+	return 0;
+#endif
+}
+/*
+ * 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(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n",
+		   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 -BLKID_ERR_PARAM;
+	if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
+		return -BLKID_ERR_PARAM;
+
+	ext_get_info(pr, 2, es);
+	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 -BLKID_ERR_PARAM;
+
+	/* Distinguish between ext3 and ext2 */
+	if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
+		return -BLKID_ERR_PARAM;
+
+	/* Any features which ext2 doesn't understand */
+	if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
+	    (fi  & EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
+		return -BLKID_ERR_PARAM;
+
+	/*
+	 * If ext2 is not present, but ext4 or ext4dev are, then
+	 * disclaim we are ext2
+	 */
+	if (!system_supports_ext2() &&
+	    (system_supports_ext4() || system_supports_ext4dev()) &&
+	    system_supports_ext4_ext2())
+		return -BLKID_ERR_PARAM;
+
+	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 -BLKID_ERR_PARAM;
+
+	/* ext3 requires journal */
+	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+		return -BLKID_ERR_PARAM;
+
+	/* Any features which ext3 doesn't understand */
+	if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) ||
+	    (fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+		return -BLKID_ERR_PARAM;
+
+	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 -BLKID_ERR_PARAM;
+
+	/* Distinguish from jbd */
+	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+		return -BLKID_ERR_PARAM;
+
+	/*
+	 * If the filesystem does not have a journal and ext2 and ext4
+	 * is not present, then force this to be detected as an
+	 * ext4dev filesystem.
+	 */
+	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+	    !system_supports_ext2() && !system_supports_ext4() &&
+	    system_supports_ext4dev() &&
+	    system_supports_ext4_ext2())
+		goto force_ext4dev;
+
+	/*
+	 * If the filesystem is marked as OK for use by in-development
+	 * filesystem code, but ext4dev is not supported, and ext4 is,
+	 * then don't call ourselves ext4dev, since we should be
+	 * detected as ext4 in that case.
+	 *
+	 * If the filesystem is marked as in use by production
+	 * filesystem, then it can only be used by ext4 and NOT by
+	 * ext4dev, so always disclaim we are ext4dev in that case.
+	 */
+	if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
+		if (!system_supports_ext4dev() && system_supports_ext4())
+			return -BLKID_ERR_PARAM;
+	} else
+		return -BLKID_ERR_PARAM;
+
+force_ext4dev:
+	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 -1;
+
+	/* Distinguish from jbd */
+	if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+		return -BLKID_ERR_PARAM;
+
+	/*
+	 * If the filesystem does not have a journal and ext2 is not
+	 * present, then force this to be detected as an ext2
+	 * filesystem.
+	 */
+	if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+	    !system_supports_ext2() && system_supports_ext4() &&
+	    system_supports_ext4_ext2())
+		goto force_ext4;
+
+	/* Ext4 has at least one feature which ext3 doesn't understand */
+	if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
+	    !(fi  & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+		return -BLKID_ERR_PARAM;
+
+force_ext4:
+	/*
+	 * 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) {
+		if (system_supports_ext4dev() || !system_supports_ext4())
+			return -BLKID_ERR_PARAM;
+	}
+
+	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
+};
+