]> err.no Git - util-linux/commitdiff
blkid: merge libblkid code from e2fsprogs/lib/blkid
authorKarel Zak <kzak@redhat.com>
Wed, 27 Aug 2008 13:09:47 +0000 (15:09 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 11 Feb 2009 22:21:43 +0000 (23:21 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
24 files changed:
configure.ac
libs/blkid/Makefile.am
libs/blkid/blkid.pc.in
libs/blkid/libblkid.3.in [new file with mode: 0644]
libs/blkid/src/Makefile.am [new file with mode: 0644]
libs/blkid/src/blkid.h [new file with mode: 0644]
libs/blkid/src/blkid.sym [new file with mode: 0644]
libs/blkid/src/blkidP.h [new file with mode: 0644]
libs/blkid/src/blkid_types.h.in [new file with mode: 0644]
libs/blkid/src/cache.c [new file with mode: 0644]
libs/blkid/src/dev.c [new file with mode: 0644]
libs/blkid/src/devname.c [new file with mode: 0644]
libs/blkid/src/devno.c [new file with mode: 0644]
libs/blkid/src/getsize.c [new file with mode: 0644]
libs/blkid/src/list.h [new file with mode: 0644]
libs/blkid/src/llseek.c [new file with mode: 0644]
libs/blkid/src/probe.c [new file with mode: 0644]
libs/blkid/src/probe.h [new file with mode: 0644]
libs/blkid/src/read.c [new file with mode: 0644]
libs/blkid/src/resolve.c [new file with mode: 0644]
libs/blkid/src/save.c [new file with mode: 0644]
libs/blkid/src/tag.c [new file with mode: 0644]
libs/blkid/src/tst_types.c [new file with mode: 0644]
libs/blkid/src/version.c [new file with mode: 0644]

index aa145cfc45df553d5c387b267ce6c0e14a34a8b5..490e84f35f3aa2310bb21effa0f9541b1792d391 100644 (file)
@@ -10,6 +10,23 @@ AC_CONFIG_SRCDIR(mount/mount.c)
 
 AC_PREFIX_DEFAULT([/usr])
 
+dnl libblkid version definition
+dnl -----------------------------
+BLKID_VERSION_MAJOR=1
+BLKID_VERSION_MINOR=41
+BLKID_VERSION_RELEASE=0
+BLKID_DATE="10-Jul-2008"
+
+BLKID_VERSION=$BLKID_VERSION_MAJOR.$BLKID_VERSION_MINOR.$BLKID_VERSION_RELEASE
+
+AC_SUBST(BLKID_VERSION_MAJOR)
+AC_SUBST(BLKID_VERSION_MINOR)
+AC_SUBST(BLKID_VERSION_RELEASE)
+AC_SUBST(BLKID_VERSION)
+
+AC_DEFINE_UNQUOTED(BLKID_VERSION, "$BLKID_VERSION", [libblkid version string])
+AC_DEFINE_UNQUOTED(BLKID_DATE, "$BLKID_DATE", [libblkid date string])
+
 # Check whether exec_prefix=/usr:
 case $exec_prefix:$prefix in
 NONE:NONE | NONE:/usr | /usr:*)
@@ -32,6 +49,7 @@ AC_PROG_CC_STDC
 AC_GNU_SOURCE
 AC_CANONICAL_HOST
 AC_C_BIGENDIAN
+AC_PROG_RANLIB
 
 linux_os=no
 case ${host_os} in
@@ -53,16 +71,29 @@ AC_CHECK_HEADERS([linux/compiler.h linux/blkpg.h linux/major.h], [], [], [
 #endif
 ])
 AC_CHECK_HEADERS(
-       [scsi/scsi.h \
+       [err.h \
+       errno.h \
+       getopt.h \
        langinfo.h \
+       linux/fd.h \
+       linux/tiocl.h \
+       linux/version.h \
        locale.h \
-       sys/user.h \
+       pty.h \
        rpcsvc/nfs_prot.h \
+       scsi/scsi.h \
+       stdlib.h \
+       sys/disk.h \
+       sys/disklabel.h \
+       sys/ioctl.h \
        sys/io.h \
-       pty.h \
-       err.h \
-       linux/tiocl.h \
-       linux/version.h])
+       sys/mkdev.h \
+       sys/prctl.h \
+       sys/queue.h \
+       sys/stat.h \
+       sys/types.h \
+       sys/user.h \
+       unistd.h ])
 AC_CHECK_HEADERS([linux/raw.h],
                 [AM_CONDITIONAL([HAVE_RAW], [true])],
                 [AM_CONDITIONAL([HAVE_RAW], [false])])
@@ -76,7 +107,12 @@ AC_CHECK_FUNCS(
        personality \
        updwtmp \
        lchown \
+       llseek \
+       lseek64 \
+       strtoull \
        inotify_init \
+       prctl \
+       __secure_getenv \
        rpmatch])
 AC_FUNC_FSEEKO
 
@@ -608,22 +644,25 @@ fi
 
 # TODO remove devmapper from blkid
 #
-STATIC_BLKID_DEVMAPPER_LIBS=''
 AC_ARG_ENABLE([blkid-devmapper],
    AS_HELP_STRING([--enable-blkid-devmapper], [build with device-mapper support]),
    [], with_blkid-devmapper=no
 )
 if test x$with_devmapper = xno; then
+  AC_MSG_RESULT([Disabling device-mapper support])
   AM_CONDITIONAL(HAVE_DEVMAPPER, false)
   DEVMAPPER_LIBS_STATIC=''
   DEVMAPPER_REQ=''
   DEVMAPPER_PC_LIBS=''
+  DEVMAPPER_LIBS=''
 else
+  AC_MSG_RESULT([Enabling device-mapper support])
   UTIL_CHECK_LIB(devmapper, dm_tree_create)
   case $with_blkid-devmapper:$have_blkid-devmapper in
   yes:no) AC_MSG_ERROR([devmapper selected but libdevmapper not found]);;
   esac
   UTIL_PKG_STATIC([DEVMAPPER_LIBS_STATIC], [devmapper])
+  DEVMAPPER_LIBS="-ldevmapper"
   DEVMAPPER_REQ="devmapper"
   DEVMAPPER_PC_LIBS="-ldevmapper"
 
@@ -638,9 +677,10 @@ else
   esac
 fi
 
-AC_SUBST(DEVMAPPER_REQ)
-AC_SUBST(DEVMAPPER_PC_LIBS)
-AC_SUBST(DEVMAPPER_LIBS_STATIC)
+AC_SUBST([DEVMAPPER_LIBS])
+AC_SUBST([DEVMAPPER_REQ])
+AC_SUBST([DEVMAPPER_PC_LIBS])
+AC_SUBST([DEVMAPPER_LIBS_STATIC])
 
 
 AC_ARG_ENABLE([schedutils],
@@ -750,8 +790,11 @@ hwclock/Makefile
 include/Makefile
 lib/Makefile
 libs/Makefile
-libs/blkid/Makefile
 libs/blkid/blkid.pc
+libs/blkid/libblkid.3
+libs/blkid/Makefile
+libs/blkid/src/blkid_types.h
+libs/blkid/src/Makefile
 login-utils/Makefile
 misc-utils/Makefile
 mount/Makefile
index 28558d43a39119a4527e840934b1ae53bc556063..05ab8daa4e464206f89f2a875a95bf993c6e6c79 100644 (file)
@@ -1,7 +1,12 @@
 include $(top_srcdir)/config/include-Makefile.am
 
+SUBDIRS = src
+
 # pkg-config stuff
 pkgconfigdir = $(usrlibexecdir)/pkgconfig
 pkgconfig_DATA = blkid.pc
 
-EXTRA_DIST = README.blkid blkid.pc blkid.pc.in
+dist_man_MANS = libblkid.3
+
+EXTRA_DIST = README.blkid blkid.pc blkid.pc.in libblkid.3.in
+
index 5195539e114d428b795bcf38cafc316d036935a9..db03cc13a519cab9ab82986299b7fef724569c9d 100644 (file)
@@ -5,7 +5,7 @@ includedir=@includedir@
 
 Name: blkid
 Description: Block device id library
-Version: @VERSION@
+Version: @BLKID_VERSION@
 Requires: uuid @DEVMAPPER_REQ@
 Cflags: -I${includedir}
 Libs: -L${libdir} -lblkid
diff --git a/libs/blkid/libblkid.3.in b/libs/blkid/libblkid.3.in
new file mode 100644 (file)
index 0000000..bd24cb1
--- /dev/null
@@ -0,0 +1,80 @@
+.\" Copyright 2001 Andreas Dilger (adilger@turbolinux.com)
+.\"
+.\" This man page was created for libblkid.so.1.0 from e2fsprogs-1.24.
+.\"
+.\" This file may be copied under the terms of the GNU Public License.
+.\"
+.\" Created  Wed Sep 14 12:02:12 2001, Andreas Dilger
+.TH LIBBLKID 3 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+.SH NAME
+libblkid \- block device identification library
+.SH SYNOPSIS
+.B #include <blkid/blkid.h>
+.sp
+.B cc
+.I file.c
+.B \-lblkid
+.SH DESCRIPTION
+The
+.B libblkid
+library is used to identify block devices (disks) as to their content (e.g.
+filesystem type) as well as extracting additional information such as
+filesystem labels/volume names, unique identifiers/serial numbers, etc.
+A common use is to allow use of LABEL= and UUID= tags instead of hard-coding
+specific block device names into configuration files.
+.P
+Block device information is normally kept in a cache file
+.I /etc/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.
+.P
+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.
+.P
+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
+.B required
+in this situation.
+.SH AUTHOR
+.B libblkid
+was written by Andreas Dilger for the ext2 filesystem utilties, with input
+from Ted Ts'o.  The library was subsequently heavily modified by Ted Ts'o.
+.SH FILES
+.TP
+.I /etc/blkid.tab
+Caches data extracted from each recognized block device.
+.SH AVAILABILITY
+.B libblkid
+is part of the e2fsprogs package since version 1.33 and is available from
+http://e2fsprogs.sourceforge.net.
+.SH COPYING
+.B libblkid
+is available under the terms of the GNU Library General Public License (LGPL),
+version 2 (or at your discretion any later version).  A copy of the LGPL
+should be included with this library in the file COPYING.  If not, write to
+.RS
+Free Software Foundation, Inc.
+.br
+51 Franklin St
+.br
+Fifth Floor
+.br
+Boston, MA  02110-1301  USA
+.RE
+.PP
+or visit
+.UR http://www.gnu.org/licenses/licenses.html#LGPL
+http://www.gnu.org/licenses/licenses.html#LGPL
+.UE
+.SH "SEE ALSO"
+.BR blkid (8)
diff --git a/libs/blkid/src/Makefile.am b/libs/blkid/src/Makefile.am
new file mode 100644 (file)
index 0000000..d5396d4
--- /dev/null
@@ -0,0 +1,52 @@
+include $(top_srcdir)/config/include-Makefile.am
+
+AM_CPPFLAGS += -I$(top_builddir)/blkid/src
+
+# static library
+lib_LIBRARIES = libblkid.a
+libblkid_a_SOURCES = cache.c dev.c devname.c devno.c getsize.c llseek.c  \
+                    probe.c read.c resolve.c save.c tag.c version.c \
+                    blkid.h blkidP.h list.h
+libblkid_a_CFLAGS = -fPIC
+
+# shared library (note that we don't use LIBTOOL!)
+blkid_IMAGE = libblkid.so
+blkid_LDSCRIPT = $(srcdir)/blkid.sym
+blkid_LIB = $(blkid_IMAGE).$(BLKID_VERSION)
+blkid_SONAME = $(blkid_IMAGE).$(BLKID_VERSION_MAJOR)
+blkid_LINKS = $(blkid_IMAGE) $(blkid_SONAME)
+
+if HAVE_DEVMAPPER
+blkid_OTHERLDADD = $(DEVMAPPER_LIBS)
+endif
+
+EXTRA_DIST = blkid.sym
+
+all-local: $(blkid_LIB)
+
+$(blkid_LIB): $(lib_LIBRARIES) $(blkid_LDSCRIPT)
+       $(CC) --shared -o $(blkid_LIB) $(AM_LDFLAGS) \
+              -Wl,-soname,$(blkid_SONAME),--version-script,$(blkid_LDSCRIPT) \
+             $(blkid_a_OBJECTS) $(blkid_OTHERLDADD)
+       for I in $(blkid_LINKS); do \
+               ln -sf $(blkid_LIB) $$I; \
+       done
+
+clean-local:
+       rm -f $(blkid_LIB) $(blkid_LINKS)
+
+installdirs-local:
+       $(MKDIR_P) $(DESTDIR)$(libdir)
+
+install-exec-hook:
+       $(INSTALL_PROGRAM) $(blkid_LIB) $(DESTDIR)$(libdir)
+       for I in $(blkid_LINKS); do \
+               cd $(DESTDIR)$(libdir) && ln -sf $(blkid_LIB) $$I; \
+       done
+
+uninstall-hook:
+       rm -f $(DESTDIR)$(libdir)/$(blkid_LIB)
+       for I in $(blkid_LINKS); do \
+               cd $(DESTDIR)$(libdir) && rm -f $(blkid_LIB) $$I; \
+       done
+
diff --git a/libs/blkid/src/blkid.h b/libs/blkid/src/blkid.h
new file mode 100644 (file)
index 0000000..4582879
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * blkid.h - Interface for libblkid, a library to identify block devices
+ *
+ * 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_BLKID_H
+#define _BLKID_BLKID_H
+
+#include <sys/types.h>
+#include <blkid/blkid_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct blkid_struct_dev *blkid_dev;
+typedef struct blkid_struct_cache *blkid_cache;
+typedef __s64 blkid_loff_t;
+
+typedef struct blkid_struct_tag_iterate *blkid_tag_iterate;
+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)
+
+/* cache.c */
+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);
+
+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);
+
+/* devname.c */
+extern int blkid_probe_all(blkid_cache cache);
+extern int blkid_probe_all_new(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);
+
+/* probe.c */
+int blkid_known_fstype(const char *fstype);
+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);
+extern char *blkid_get_devname(blkid_cache cache, const char *token,
+                              const char *value);
+
+/* 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);
+extern int blkid_get_library_version(const char **ver_string,
+                                    const char **date_string);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BLKID_BLKID_H */
diff --git a/libs/blkid/src/blkid.sym b/libs/blkid/src/blkid.sym
new file mode 100644 (file)
index 0000000..3687ae0
--- /dev/null
@@ -0,0 +1,29 @@
+{ 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:
+       *;
+};
diff --git a/libs/blkid/src/blkidP.h b/libs/blkid/src/blkidP.h
new file mode 100644 (file)
index 0000000..7ac2b82
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#include <blkid/blkid.h>
+#include <list.h>
+
+#ifdef __GNUC__
+#define __BLKID_ATTR(x) __attribute__(x)
+#else
+#define __BLKID_ATTR(x)
+#endif
+
+
+/*
+ * 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 */
+       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 */
+
+/*
+ * 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;
+
+/*
+ * 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 */
+};
+
+#define BLKID_BIC_FL_PROBED    0x0002  /* We probed /proc/partition devices */
+#define BLKID_BIC_FL_CHANGED   0x0004  /* Cache has changed from disk */
+
+extern char *blkid_strdup(const char *s);
+extern char *blkid_strndup(const char *s, const int length);
+
+#define BLKID_CACHE_FILE "/etc/blkid.tab"
+extern const char *blkid_devdirs[];
+
+#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_DM   40
+#define BLKID_PRI_EVMS 30
+#define BLKID_PRI_LVM  20
+#define BLKID_PRI_MD   10
+
+#if defined(TEST_PROGRAM) && !defined(CONFIG_BLKID_DEBUG)
+#define CONFIG_BLKID_DEBUG
+#endif
+
+#define DEBUG_CACHE    0x0001
+#define DEBUG_DUMP     0x0002
+#define DEBUG_DEV      0x0004
+#define DEBUG_DEVNAME  0x0008
+#define DEBUG_DEVNO    0x0010
+#define DEBUG_PROBE    0x0020
+#define DEBUG_READ     0x0040
+#define DEBUG_RESOLVE  0x0080
+#define DEBUG_SAVE     0x0100
+#define DEBUG_TAG      0x0200
+#define DEBUG_INIT     0x8000
+#define DEBUG_ALL      0xFFFF
+
+#ifdef CONFIG_BLKID_DEBUG
+#include <stdio.h>
+extern int     blkid_debug_mask;
+#define DBG(m,x)       if ((m) & blkid_debug_mask) x;
+#else
+#define DBG(m,x)
+#endif
+
+#ifdef CONFIG_BLKID_DEBUG
+extern void blkid_debug_dump_dev(blkid_dev dev);
+extern void blkid_debug_dump_tag(blkid_tag tag);
+#endif
+
+/* 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);
+
+/* save.c */
+extern int blkid_flush_cache(blkid_cache cache);
+
+/*
+ * 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);
+extern int blkid_set_tag(blkid_dev dev, const char *name,
+                        const char *value, const int vlength);
+
+/*
+ * Functions to create and find a specific tag type: dev.c
+ */
+extern blkid_dev blkid_new_dev(void);
+extern void blkid_free_dev(blkid_dev dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BLKID_BLKIDP_H */
diff --git a/libs/blkid/src/blkid_types.h.in b/libs/blkid/src/blkid_types.h.in
new file mode 100644 (file)
index 0000000..4efffba
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * If linux/types.h is already been included, assume it has defined
+ * everything we need.  (cross fingers)  Other header files may have
+ * also defined the types that we need.
+ */
+#if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \
+       !defined(_EXT2_TYPES_H))
+#define _BLKID_TYPES_H
+
+@ASM_TYPES_HEADER@
+
+#ifdef __U8_TYPEDEF
+typedef __U8_TYPEDEF __u8;
+#else
+typedef unsigned char __u8;
+#endif
+
+#ifdef __S8_TYPEDEF
+typedef __S8_TYPEDEF __s8;
+#else
+typedef signed char __s8;
+#endif
+
+#ifdef __U16_TYPEDEF
+typedef __U16_TYPEDEF __u16;
+#else
+#if (@SIZEOF_INT@ == 2)
+typedef        unsigned int    __u16;
+#else
+#if (@SIZEOF_SHORT@ == 2)
+typedef        unsigned short  __u16;
+#else
+  ?==error: undefined 16 bit type
+#endif /* SIZEOF_SHORT == 2 */
+#endif /* SIZEOF_INT == 2 */
+#endif /* __U16_TYPEDEF */
+
+#ifdef __S16_TYPEDEF
+typedef __S16_TYPEDEF __s16;
+#else
+#if (@SIZEOF_INT@ == 2)
+typedef        int             __s16;
+#else
+#if (@SIZEOF_SHORT@ == 2)
+typedef        short           __s16;
+#else
+  ?==error: undefined 16 bit type
+#endif /* SIZEOF_SHORT == 2 */
+#endif /* SIZEOF_INT == 2 */
+#endif /* __S16_TYPEDEF */
+
+
+#ifdef __U32_TYPEDEF
+typedef __U32_TYPEDEF __u32;
+#else
+#if (@SIZEOF_INT@ == 4)
+typedef        unsigned int    __u32;
+#else
+#if (@SIZEOF_LONG@ == 4)
+typedef        unsigned long   __u32;
+#else
+#if (@SIZEOF_SHORT@ == 4)
+typedef        unsigned short  __u32;
+#else
+ ?== error: undefined 32 bit type
+#endif /* SIZEOF_SHORT == 4 */
+#endif /* SIZEOF_LONG == 4 */
+#endif /* SIZEOF_INT == 4 */
+#endif /* __U32_TYPEDEF */
+
+#ifdef __S32_TYPEDEF
+typedef __S32_TYPEDEF __s32;
+#else
+#if (@SIZEOF_INT@ == 4)
+typedef        int             __s32;
+#else
+#if (@SIZEOF_LONG@ == 4)
+typedef        long            __s32;
+#else
+#if (@SIZEOF_SHORT@ == 4)
+typedef        short           __s32;
+#else
+ ?== error: undefined 32 bit type
+#endif /* SIZEOF_SHORT == 4 */
+#endif /* SIZEOF_LONG == 4 */
+#endif /* SIZEOF_INT == 4 */
+#endif /* __S32_TYPEDEF */
+
+#ifdef __U64_TYPEDEF
+typedef __U64_TYPEDEF __u64;
+#else
+#if (@SIZEOF_INT@ == 8)
+typedef unsigned int   __u64;
+#else
+#if (@SIZEOF_LONG@ == 8)
+typedef unsigned long  __u64;
+#else
+#if (@SIZEOF_LONG_LONG@ == 8)
+typedef unsigned long long     __u64;
+#endif /* SIZEOF_LONG_LONG == 8 */
+#endif /* SIZEOF_LONG == 8 */
+#endif /* SIZEOF_INT == 8 */
+#endif /* __U64_TYPEDEF */
+
+#ifdef __S64_TYPEDEF
+typedef __S64_TYPEDEF __s64;
+#else
+#if (@SIZEOF_INT@ == 8)
+typedef int            __s64;
+#else
+#if (@SIZEOF_LONG@ == 8)
+typedef long           __s64;
+#else
+#if (@SIZEOF_LONG_LONG@ == 8)
+#if defined(__GNUC__)
+typedef __signed__ long long   __s64;
+#else
+typedef signed long long       __s64;
+#endif /* __GNUC__ */
+#endif /* SIZEOF_LONG_LONG == 8 */
+#endif /* SIZEOF_LONG == 8 */
+#endif /* SIZEOF_INT == 8 */
+#endif /* __S64_TYPEDEF */
+
+#undef __S8_TYPEDEF
+#undef __U8_TYPEDEF
+#undef __S16_TYPEDEF
+#undef __U16_TYPEDEF
+#undef __S32_TYPEDEF
+#undef __U32_TYPEDEF
+#undef __S64_TYPEDEF
+#undef __U64_TYPEDEF
+
+#endif /* _*_TYPES_H */
diff --git a/libs/blkid/src/cache.c b/libs/blkid/src/cache.c
new file mode 100644 (file)
index 0000000..7c95726
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * 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%
+ */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#else
+#define PR_GET_DUMPABLE 3
+#endif
+#if (!defined(HAVE_PRCTL) && defined(linux))
+#include <sys/syscall.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "blkidP.h"
+
+int blkid_debug_mask = 0;
+
+
+static char *safe_getenv(const char *arg)
+{
+       if ((getuid() != geteuid()) || (getgid() != getegid()))
+               return NULL;
+#if HAVE_PRCTL
+       if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+               return NULL;
+#else
+#if (defined(linux) && defined(SYS_prctl))
+       if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+               return NULL;
+#endif
+#endif
+
+#ifdef HAVE___SECURE_GETENV
+       return __secure_getenv(arg);
+#else
+       return getenv(arg);
+#endif
+}
+
+#if 0 /* ifdef CONFIG_BLKID_DEBUG */
+static blkid_debug_dump_cache(int mask, blkid_cache cache)
+{
+       struct list_head *p;
+
+       if (!cache) {
+               printf("cache: NULL\n");
+               return;
+       }
+
+       printf("cache: time = %lu\n", cache->bic_time);
+       printf("cache: flags = 0x%08X\n", cache->bic_flags);
+
+       list_for_each(p, &cache->bic_devs) {
+               blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
+               blkid_debug_dump_dev(dev);
+       }
+}
+#endif
+
+int blkid_get_cache(blkid_cache *ret_cache, const char *filename)
+{
+       blkid_cache cache;
+
+#ifdef CONFIG_BLKID_DEBUG
+       if (!(blkid_debug_mask & DEBUG_INIT)) {
+               char *dstr = getenv("BLKID_DEBUG");
+
+               if (dstr)
+                       blkid_debug_mask = strtoul(dstr, 0, 0);
+               blkid_debug_mask |= DEBUG_INIT;
+       }
+#endif
+
+       DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n",
+                               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 && !strlen(filename))
+               filename = 0;
+       if (!filename)
+               filename = safe_getenv("BLKID_FILE");
+       if (!filename)
+               filename = BLKID_CACHE_FILE;
+       cache->bic_filename = blkid_strdup(filename);
+
+       blkid_read_cache(cache);
+
+       *ret_cache = cache;
+       return 0;
+}
+
+void blkid_put_cache(blkid_cache cache)
+{
+       if (!cache)
+               return;
+
+       (void) blkid_flush_cache(cache);
+
+       DBG(DEBUG_CACHE, printf("freeing cache struct\n"));
+
+       /* DBG(DEBUG_CACHE, blkid_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(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n",
+                                               bad->bit_name, bad->bit_val));
+                       blkid_free_tag(bad);
+               }
+               blkid_free_tag(tag);
+       }
+       if (cache->bic_filename)
+               free(cache->bic_filename);
+
+       free(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 (!p)
+                       break;
+               if (stat(dev->bid_name, &st) < 0) {
+                       DBG(DEBUG_CACHE,
+                           printf("freeing %s\n", dev->bid_name));
+                       blkid_free_dev(dev);
+                       cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+               } else {
+                       DBG(DEBUG_CACHE,
+                           printf("Device %s exists\n", dev->bid_name));
+               }
+       }
+}
+
+
+#ifdef TEST_PROGRAM
+int main(int argc, char** argv)
+{
+       blkid_cache cache = NULL;
+       int ret;
+
+       blkid_debug_mask = 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_CACHE_FILE);
+               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/libs/blkid/src/dev.c b/libs/blkid/src/dev.c
new file mode 100644 (file)
index 0000000..fb8d852
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * 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"
+
+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(DEBUG_DEV,
+           printf("  freeing dev %s (%s)\n", dev->bid_name, dev->bid_type ?
+                  dev->bid_type : "(null)"));
+       DBG(DEBUG_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);
+       }
+       if (dev->bid_name)
+               free(dev->bid_name);
+       free(dev);
+}
+
+/*
+ * Given a blkid device, return its name
+ */
+extern const char *blkid_dev_devname(blkid_dev dev)
+{
+       return dev->bid_name;
+}
+
+#ifdef CONFIG_BLKID_DEBUG
+void blkid_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\"\n", (long)dev->bid_time);
+       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");
+}
+#endif
+
+/*
+ * 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;
+};
+
+extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
+{
+       blkid_dev_iterate       iter;
+
+       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);
+}
+
+extern 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) {
+               if (new_type)
+                       free(new_type);
+               if (new_value)
+                       free(new_value);
+               return -1;
+       }
+       strcpy(new_type, search_type);
+       strcpy(new_value, search_value);
+       if (iter->search_type)
+               free(iter->search_type);
+       if (iter->search_value)
+               free(iter->search_value);
+       iter->search_type = new_type;
+       iter->search_value = new_value;
+       return 0;
+}
+
+/*
+ * Return 0 on success, -1 on error
+ */
+extern int blkid_dev_next(blkid_dev_iterate iter,
+                         blkid_dev *ret_dev)
+{
+       blkid_dev               dev;
+
+       *ret_dev = 0;
+       if (!iter || iter->magic != DEV_ITERATE_MAGIC)
+               return -1;
+       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;
+}
+
+extern void blkid_dev_iterate_end(blkid_dev_iterate iter)
+{
+       if (!iter || iter->magic != DEV_ITERATE_MAGIC)
+               return;
+       iter->magic = 0;
+       free(iter);
+}
+
+#ifdef TEST_PROGRAM
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+
+void 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':
+                       blkid_debug_mask = strtoul (optarg, &tmp, 0);
+                       if (*tmp) {
+                               fprintf(stderr, "Invalid debug mask: %s\n",
+                                       optarg);
+                               exit(1);
+                       }
+                       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/libs/blkid/src/devname.c b/libs/blkid/src/devname.c
new file mode 100644 (file)
index 0000000..106c743
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+ * 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>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+#include <time.h>
+
+#include "blkidP.h"
+
+#ifdef HAVE_DEVMAPPER
+#include <libdevmapper.h>
+#endif
+
+/*
+ * 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(DEBUG_DEVNAME,
+                   printf("found devname %s in cache\n", tmp->bid_name));
+               dev = tmp;
+               break;
+       }
+
+       if (!dev && (flags & BLKID_DEV_CREATE)) {
+               dev = blkid_new_dev();
+               if (!dev)
+                       return NULL;
+               dev->bid_time = INT_MIN;
+               dev->bid_name = blkid_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;
+                       if (!p)
+                               break;
+                       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;
+}
+
+#ifdef HAVE_DEVMAPPER
+static int dm_device_is_leaf(const dev_t dev);
+#endif
+
+/*
+ * 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)
+{
+       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);
+#ifdef HAVE_DEVMAPPER
+               if (!dm_device_is_leaf(devno))
+                       continue;
+#endif
+               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;
+
+       /*
+        * 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 = blkid_devdirs; *dir; dir++) {
+               struct stat st;
+               char device[256];
+
+               sprintf(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) &&
+                   st.st_rdev == devno) {
+                       devname = blkid_strdup(device);
+                       break;
+               }
+       }
+       if (!devname) {
+               devname = blkid_devno_to_devname(devno);
+               if (!devname)
+                       return;
+       }
+       dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL);
+       free(devname);
+
+set_pri:
+       if (!pri && !strncmp(ptname, "md", 2))
+               pri = BLKID_PRI_MD;
+       if (dev)
+               dev->bid_pri = pri;
+       return;
+}
+
+#ifdef HAVE_DEVMAPPER
+static void dm_quiet_log(int level __BLKID_ATTR((unused)),
+                        const char *file __BLKID_ATTR((unused)),
+                        int line __BLKID_ATTR((unused)),
+                        const char *f __BLKID_ATTR((unused)), ...)
+{
+       return;
+}
+
+/*
+ * device-mapper support
+ */
+static int dm_device_has_dep(const dev_t dev, const char *name)
+{
+       struct dm_task *task;
+       struct dm_deps *deps;
+       struct dm_info info;
+       unsigned int i;
+       int ret = 0;
+
+       task = dm_task_create(DM_DEVICE_DEPS);
+       if (!task)
+               goto out;
+
+       if (!dm_task_set_name(task, name))
+               goto out;
+
+       if (!dm_task_run(task))
+               goto out;
+
+       if (!dm_task_get_info(task, &info))
+               goto out;
+
+       if  (!info.exists)
+               goto out;
+
+       deps = dm_task_get_deps(task);
+       if (!deps || deps->count == 0)
+               goto out;
+
+       for (i = 0; i < deps->count; i++) {
+               dev_t dep_dev = deps->device[i];
+
+               if (dev == dep_dev) {
+                       ret = 1;
+                       goto out;
+               }
+       }
+
+out:
+       if (task)
+               dm_task_destroy(task);
+
+       return ret;
+}
+
+static int dm_device_is_leaf(const dev_t dev)
+{
+       struct dm_task *task;
+       struct dm_names *names;
+       unsigned int next = 0;
+       int n, ret = 1;
+
+       dm_log_init(dm_quiet_log);
+       task = dm_task_create(DM_DEVICE_LIST);
+       if (!task)
+               goto out;
+
+       dm_log_init(0);
+
+       if (!dm_task_run(task))
+               goto out;
+
+       names = dm_task_get_names(task);
+       if (!names || !names->dev)
+               goto out;
+
+       n = 0;
+       do {
+               names = (struct dm_names *) ((char *)names + next);
+
+               if (dm_device_has_dep(dev, names->name))
+                       ret = 0;
+
+               next = names->next;
+       } while (next);
+
+out:
+       if (task)
+               dm_task_destroy(task);
+
+       return ret;
+}
+
+static dev_t dm_get_devno(const char *name)
+{
+       struct dm_task *task;
+       struct dm_info info;
+       dev_t ret = 0;
+
+       task = dm_task_create(DM_DEVICE_INFO);
+       if (!task)
+               goto out;
+
+       if (!dm_task_set_name(task, name))
+               goto out;
+
+       if (!dm_task_run(task))
+               goto out;
+
+       if (!dm_task_get_info(task, &info))
+               goto out;
+
+       if (!info.exists)
+               goto out;
+
+       ret = makedev(info.major, info.minor);
+
+out:
+       if (task)
+               dm_task_destroy(task);
+
+       return ret;
+}
+
+static void dm_probe_all(blkid_cache cache, int only_if_new)
+{
+       struct dm_task *task;
+       struct dm_names *names;
+       unsigned int next = 0;
+       int n;
+
+       dm_log_init(dm_quiet_log);
+       task = dm_task_create(DM_DEVICE_LIST);
+       if (!task)
+               goto out;
+       dm_log_init(0);
+
+       if (!dm_task_run(task))
+               goto out;
+
+       names = dm_task_get_names(task);
+       if (!names || !names->dev)
+               goto out;
+
+       n = 0;
+       do {
+               int rc;
+               char *device = NULL;
+               dev_t dev = 0;
+
+               names = (struct dm_names *) ((char *)names + next);
+
+               rc = asprintf(&device, "mapper/%s", names->name);
+               if (rc < 0)
+                       goto try_next;
+
+               dev = dm_get_devno(names->name);
+               if (dev == 0)
+                       goto try_next;
+
+               if (!dm_device_is_leaf(dev))
+                       goto try_next;
+
+               probe_one(cache, device, dev, BLKID_PRI_DM, only_if_new);
+
+try_next:
+               free(device);
+               next = names->next;
+       } while (next);
+
+out:
+       if (task)
+               dm_task_destroy(task);
+}
+#endif /* HAVE_DEVMAPPER */
+
+#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
+#include <dirent.h>
+static dev_t lvm_get_devno(const char *lvm_device)
+{
+       FILE *lvf;
+       char buf[1024];
+       int ma, mi;
+       dev_t ret = 0;
+
+       DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device));
+       if ((lvf = fopen(lvm_device, "r")) == NULL) {
+               DBG(DEBUG_DEVNAME, printf("%s: (%d) %s\n", lvm_device, errno,
+                                         strerror(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(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", 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(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n",
+                                                 lvm_device,
+                                                 (unsigned int) dev));
+                       probe_one(cache, lvm_device, dev, BLKID_PRI_LVM,
+                                 only_if_new);
+                       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");
+       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(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n",
+                                         device, ma, mi));
+
+               probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS,
+                         only_if_new);
+               num++;
+       }
+       fclose(procpt);
+       return num;
+}
+
+/*
+ * 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], ptname1[128], *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;
+
+       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);
+#ifdef HAVE_DEVMAPPER
+       dm_probe_all(cache, only_if_new);
+#endif
+       evms_probe_all(cache, only_if_new);
+#ifdef VG_DIR
+       lvm_probe_all(cache, only_if_new);
+#endif
+
+       proc = fopen(PROC_PARTITIONS, "r");
+       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(DEBUG_DEVNAME, printf("read partition name %s\n", 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(DEBUG_DEVNAME,
+                           printf("partition dev %s, devno 0x%04X\n",
+                                  ptname, (unsigned int) devs[which]));
+
+                       if (sz > 1)
+                               probe_one(cache, ptname, devs[which], 0,
+                                         only_if_new);
+                       lens[which] = 0;        /* mark as checked */
+               }
+
+               /*
+                * 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(DEBUG_DEVNAME,
+                           printf("whole dev %s, devno 0x%04X\n",
+                                  ptnames[last], (unsigned int) devs[last]));
+                       probe_one(cache, ptnames[last], devs[last], 0,
+                                 only_if_new);
+                       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);
+
+       fclose(proc);
+       blkid_flush_cache(cache);
+       return 0;
+}
+
+int blkid_probe_all(blkid_cache cache)
+{
+       int ret;
+
+       DBG(DEBUG_PROBE, printf("Begin blkid_probe_all()\n"));
+       ret = probe_all(cache, 0);
+       cache->bic_time = time(0);
+       cache->bic_flags |= BLKID_BIC_FL_PROBED;
+       DBG(DEBUG_PROBE, printf("End blkid_probe_all()\n"));
+       return ret;
+}
+
+int blkid_probe_all_new(blkid_cache cache)
+{
+       int ret;
+
+       DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_new()\n"));
+       ret = probe_all(cache, 1);
+       DBG(DEBUG_PROBE, printf("End blkid_probe_all_new()\n"));
+       return ret;
+}
+
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+       blkid_cache cache = NULL;
+       int ret;
+
+       blkid_debug_mask = 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]);
+
+       blkid_put_cache(cache);
+       return (0);
+}
+#endif
diff --git a/libs/blkid/src/devno.c b/libs/blkid/src/devno.c
new file mode 100644 (file)
index 0000000..259ec93
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * 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>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <dirent.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+
+#include "blkidP.h"
+
+struct dir_list {
+       char    *name;
+       struct dir_list *next;
+};
+
+char *blkid_strndup(const char *s, int length)
+{
+       char *ret;
+
+       if (!s)
+               return NULL;
+
+       if (!length)
+               length = strlen(s);
+
+       ret = malloc(length + 1);
+       if (ret) {
+               strncpy(ret, s, length);
+               ret[length] = '\0';
+       }
+       return ret;
+}
+
+char *blkid_strdup(const char *s)
+{
+       return blkid_strndup(s, 0);
+}
+
+/*
+ * This function adds an entry to the directory list
+ */
+static void add_to_dirlist(const char *name, struct dir_list **list)
+{
+       struct dir_list *dp;
+
+       dp = malloc(sizeof(struct dir_list));
+       if (!dp)
+               return;
+       dp->name = blkid_strdup(name);
+       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;
+}
+
+static void scan_dir(char *dirname, dev_t devno, struct dir_list **list,
+                           char **devname)
+{
+       DIR     *dir;
+       struct dirent *dp;
+       char    path[1024];
+       int     dirlen;
+       struct stat st;
+
+       if ((dir = opendir(dirname)) == NULL)
+               return;
+       dirlen = strlen(dirname) + 2;
+       while ((dp = readdir(dir)) != 0) {
+               if (dirlen + strlen(dp->d_name) >= sizeof(path))
+                       continue;
+
+               if (dp->d_name[0] == '.' &&
+                   ((dp->d_name[1] == 0) ||
+                    ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
+                       continue;
+
+               sprintf(path, "%s/%s", dirname, dp->d_name);
+               if (stat(path, &st) < 0)
+                       continue;
+
+               if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
+                       *devname = blkid_strdup(path);
+                       DBG(DEBUG_DEVNO,
+                           printf("found 0x%llx at %s (%p)\n", (long long)devno,
+                                  path, *devname));
+                       break;
+               }
+               if (S_ISDIR(st.st_mode) && !lstat(path, &st) &&
+                   S_ISDIR(st.st_mode))
+                       add_to_dirlist(path, list);
+       }
+       closedir(dir);
+       return;
+}
+
+/* Directories where we will try to search for device numbers */
+const char *blkid_devdirs[] = { "/devices", "/devfs", "/dev", NULL };
+
+/*
+ * This function finds the pathname to a block device with a given
+ * device number.  It returns a pointer to allocated memory to the
+ * pathname on success, and NULL on failure.
+ */
+char *blkid_devno_to_devname(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 = blkid_devdirs; *dir; dir++)
+               add_to_dirlist(*dir, &list);
+
+       while (list) {
+               struct dir_list *current = list;
+
+               list = list->next;
+               DBG(DEBUG_DEVNO, printf("directory %s\n", current->name));
+               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);
+
+       if (!devname) {
+               DBG(DEBUG_DEVNO,
+                   printf("blkid: couldn't find devno 0x%04lx\n",
+                          (unsigned long) devno));
+       } else {
+               DBG(DEBUG_DEVNO,
+                   printf("found devno 0x%04llx as %s\n", (long long)devno, devname));
+       }
+
+
+       return devname;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char** argv)
+{
+       char    *devname, *tmp;
+       int     major, minor;
+       dev_t   devno;
+       const char *errmsg = "Couldn't parse %s: %s\n";
+
+       blkid_debug_mask = 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);
+       if (devname)
+               free(devname);
+       return 0;
+}
+#endif
diff --git a/libs/blkid/src/getsize.c b/libs/blkid/src/getsize.c
new file mode 100644 (file)
index 0000000..10ba7ec
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * getsize.c --- get the size of a partition.
+ *
+ * Copyright (C) 1995, 1995 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
+
+/* include this before sys/queues.h! */
+#include "blkidP.h"
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_LINUX_FD_H
+#include <linux/fd.h>
+#endif
+#ifdef HAVE_SYS_DISKLABEL_H
+#include <sys/disklabel.h>
+#endif
+#ifdef HAVE_SYS_DISK_H
+#ifdef HAVE_SYS_QUEUE_H
+#include <sys/queue.h> /* for LIST_HEAD */
+#endif
+#include <sys/disk.h>
+#endif
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+
+#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
+#define BLKGETSIZE _IO(0x12,96)        /* return device size */
+#endif
+
+#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)     /* return device size in bytes (u64 *arg) */
+#endif
+
+#ifdef APPLE_DARWIN
+#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
+#endif /* APPLE_DARWIN */
+
+static int valid_offset(int fd, blkid_loff_t offset)
+{
+       char ch;
+
+       if (blkid_llseek(fd, offset, 0) < 0)
+               return 0;
+       if (read(fd, &ch, 1) < 1)
+               return 0;
+       return 1;
+}
+
+/*
+ * Returns the number of bytes in a partition
+ */
+blkid_loff_t blkid_get_dev_size(int fd)
+{
+       int valid_blkgetsize64 = 1;
+#ifdef __linux__
+       struct          utsname ut;
+#endif
+       unsigned long long size64;
+       unsigned long size;
+       blkid_loff_t high, low;
+#ifdef FDGETPRM
+       struct floppy_struct this_floppy;
+#endif
+#ifdef HAVE_SYS_DISKLABEL_H
+       int part = -1;
+       struct disklabel lab;
+       struct partition *pp;
+       char ch;
+       struct stat st;
+#endif /* HAVE_SYS_DISKLABEL_H */
+
+#ifdef DKIOCGETBLOCKCOUNT      /* For Apple Darwin */
+       if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
+               if ((sizeof(blkid_loff_t) < sizeof(unsigned long long))
+                   && (size64 << 9 > 0xFFFFFFFF))
+                       return 0; /* EFBIG */
+               return (blkid_loff_t) size64 << 9;
+       }
+#endif
+
+#ifdef BLKGETSIZE64
+#ifdef __linux__
+       if ((uname(&ut) == 0) &&
+           ((ut.release[0] == '2') && (ut.release[1] == '.') &&
+            (ut.release[2] < '6') && (ut.release[3] == '.')))
+               valid_blkgetsize64 = 0;
+#endif
+       if (valid_blkgetsize64 &&
+           ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
+               if ((sizeof(blkid_loff_t) < sizeof(unsigned long long))
+                   && ((size64) > 0xFFFFFFFF))
+                       return 0; /* EFBIG */
+               return size64;
+       }
+#endif
+
+#ifdef BLKGETSIZE
+       if (ioctl(fd, BLKGETSIZE, &size) >= 0)
+               return (blkid_loff_t)size << 9;
+#endif
+
+/* tested on FreeBSD 6.1-RELEASE i386 */
+#ifdef DIOCGMEDIASIZE
+       if (ioctl(fd, DIOCGMEDIASIZE, &size64) >= 0)
+               return (off_t)size64;
+#endif /* DIOCGMEDIASIZE */
+
+#ifdef FDGETPRM
+       if (ioctl(fd, FDGETPRM, &this_floppy) >= 0)
+               return (blkid_loff_t)this_floppy.size << 9;
+#endif
+#ifdef HAVE_SYS_DISKLABEL_H
+       /*
+        * This code works for FreeBSD 4.11 i386, except for the full device
+        * (such as /dev/ad0). It doesn't work properly for newer FreeBSD
+        * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE
+        * above however.
+        *
+        * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw,
+        * character) devices, so we need to check for S_ISCHR, too.
+        */
+       if ((fstat(fd, &st) >= 0) && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)))
+               part = st.st_rdev & 7;
+       if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
+               pp = &lab.d_partitions[part];
+               if (pp->p_size)
+                       return pp->p_size << 9;
+       }
+#endif /* HAVE_SYS_DISKLABEL_H */
+       {
+#ifdef HAVE_FSTAT64
+               struct stat64   st;
+               if (fstat64(fd, &st) == 0)
+#else
+               struct stat     st;
+               if (fstat(fd, &st) == 0)
+#endif
+                       if (S_ISREG(st.st_mode))
+                               return st.st_size;
+       }
+
+
+       /*
+        * OK, we couldn't figure it out by using a specialized ioctl,
+        * which is generally the best way.  So do binary search to
+        * find the size of the partition.
+        */
+       low = 0;
+       for (high = 1024; valid_offset(fd, high); high *= 2)
+               low = high;
+       while (low < high - 1)
+       {
+               const blkid_loff_t mid = (low + high) / 2;
+
+               if (valid_offset(fd, mid))
+                       low = mid;
+               else
+                       high = mid;
+       }
+       return low + 1;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+       long long bytes;
+       int     fd;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage: %s device\n"
+                       "Determine the size of a device\n", argv[0]);
+               return 1;
+       }
+
+       if ((fd = open(argv[1], O_RDONLY)) < 0)
+               perror(argv[0]);
+
+       bytes = blkid_get_dev_size(fd);
+       printf("Device %s has %Ld 1k blocks.\n", argv[1],
+              (unsigned long long) bytes >> 10);
+
+       return 0;
+}
+#endif
diff --git a/libs/blkid/src/list.h b/libs/blkid/src/list.h
new file mode 100644 (file)
index 0000000..c1cbfec
--- /dev/null
@@ -0,0 +1,179 @@
+#if !defined(_BLKID_LIST_H) && !defined(LIST_HEAD)
+#define _BLKID_LIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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_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) \
+       ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * 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_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)
+
+#undef _INLINE_
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BLKID_LIST_H */
diff --git a/libs/blkid/src/llseek.c b/libs/blkid/src/llseek.c
new file mode 100644 (file)
index 0000000..5bd0e51
--- /dev/null
@@ -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
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if 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 = my_llseek(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/libs/blkid/src/probe.c b/libs/blkid/src/probe.c
new file mode 100644 (file)
index 0000000..ec72153
--- /dev/null
@@ -0,0 +1,1581 @@
+/*
+ * probe.c - identify a block device by its contents, and return a dev
+ *           struct with the details
+ *
+ * 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>
+ *
+ * %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 <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+#include <sys/utsname.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include "blkidP.h"
+#include "uuid/uuid.h"
+#include "probe.h"
+
+static int figure_label_len(const unsigned char *label, int len)
+{
+       const unsigned char *end = label + len - 1;
+
+       while ((*end == ' ' || *end == 0) && end >= label)
+               --end;
+       if (end >= label) {
+               label = label;
+               return end - label + 1;
+       }
+       return 0;
+}
+
+static unsigned char *get_buffer(struct blkid_probe *pr,
+                         blkid_loff_t off, size_t len)
+{
+       ssize_t         ret_read;
+       unsigned char   *newbuf;
+
+       if (off + len <= SB_BUFFER_SIZE) {
+               if (!pr->sbbuf) {
+                       pr->sbbuf = malloc(SB_BUFFER_SIZE);
+                       if (!pr->sbbuf)
+                               return NULL;
+                       if (lseek(pr->fd, 0, SEEK_SET) < 0)
+                               return NULL;
+                       ret_read = read(pr->fd, pr->sbbuf, SB_BUFFER_SIZE);
+                       if (ret_read < 0)
+                               ret_read = 0;
+                       pr->sb_valid = ret_read;
+               }
+               if (off+len > pr->sb_valid)
+                       return NULL;
+               return pr->sbbuf + off;
+       } else {
+               if (len > pr->buf_max) {
+                       newbuf = realloc(pr->buf, len);
+                       if (newbuf == NULL)
+                               return NULL;
+                       pr->buf = newbuf;
+                       pr->buf_max = len;
+               }
+               if (blkid_llseek(pr->fd, off, SEEK_SET) < 0)
+                       return NULL;
+               ret_read = read(pr->fd, pr->buf, len);
+               if (ret_read != (ssize_t) len)
+                       return NULL;
+               return pr->buf;
+       }
+}
+
+
+/*
+ * This is a special case code to check for an MDRAID device.  We do
+ * this special since it requires checking for a superblock at the end
+ * of the device.
+ */
+static int check_mdraid(int fd, unsigned char *ret_uuid)
+{
+       struct mdp_superblock_s *md;
+       blkid_loff_t            offset;
+       char                    buf[4096];
+
+       if (fd < 0)
+               return -BLKID_ERR_PARAM;
+
+       offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536;
+
+       if (blkid_llseek(fd, offset, 0) < 0 ||
+           read(fd, buf, 4096) != 4096)
+               return -BLKID_ERR_IO;
+
+       /* Check for magic number */
+       if (memcmp("\251+N\374", buf, 4) && memcmp("\374N+\251", buf, 4))
+               return -BLKID_ERR_PARAM;
+
+       if (!ret_uuid)
+               return 0;
+       *ret_uuid = 0;
+
+       /* The MD UUID is not contiguous in the superblock, make it so */
+       md = (struct mdp_superblock_s *)buf;
+       if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) {
+               memcpy(ret_uuid, &md->set_uuid0, 4);
+               memcpy(ret_uuid + 4, &md->set_uuid1, 12);
+       }
+       return 0;
+}
+
+static void set_uuid(blkid_dev dev, uuid_t uuid, const char *tag)
+{
+       char    str[37];
+
+       if (!uuid_is_null(uuid)) {
+               uuid_unparse(uuid, str);
+               blkid_set_tag(dev, tag ? tag : "UUID", str, sizeof(str));
+       }
+}
+
+static void get_ext2_info(blkid_dev dev, struct blkid_magic *id,
+                         unsigned char *buf)
+{
+       struct ext2_super_block *es = (struct ext2_super_block *) buf;
+       const char *label = 0;
+
+       DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n",
+                  blkid_le32(es->s_feature_compat),
+                  blkid_le32(es->s_feature_incompat),
+                  blkid_le32(es->s_feature_ro_compat)));
+
+       if (strlen(es->s_volume_name))
+               label = es->s_volume_name;
+       blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name));
+
+       set_uuid(dev, es->s_uuid, 0);
+
+       if ((es->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+           !uuid_is_null(es->s_journal_uuid))
+               set_uuid(dev, es->s_journal_uuid, "EXT_JOURNAL");
+
+       if (strcmp(id->bim_type, "ext2") &&
+           ((blkid_le32(es->s_feature_incompat) &
+             EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0))
+               blkid_set_tag(dev, "SEC_TYPE", "ext2", sizeof("ext2"));
+}
+
+/*
+ * 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)
+{
+       struct utsname  uts;
+       FILE            *f;
+       char            buf[1024], *cp, *t;
+       int             i;
+
+       if (uname(&uts))
+               return (0);
+       snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release);
+
+       f = fopen(buf, "r");
+       if (!f)
+               return (0);
+       while (!feof(f)) {
+               if (!fgets(buf, sizeof(buf), f))
+                       break;
+               if ((cp = strchr(buf, ':')) != NULL)
+                       *cp = 0;
+               else
+                       continue;
+               if ((cp = strrchr(buf, '/')) != NULL)
+                       cp++;
+               i = strlen(cp);
+               if (i > 3) {
+                       t = cp + i - 3;
+                       if (!strcmp(t, ".ko"))
+                               *t = 0;
+               }
+               if (!strcmp(cp, fs_name))
+                       return (1);
+       }
+       fclose(f);
+       return (0);
+}
+
+static int system_supports_ext4(void)
+{
+       static time_t   last_check = 0;
+       static int      ret = -1;
+       time_t          now = time(0);
+
+       if (ret != -1 || (last_check - now) < 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 || (last_check - now) < 5)
+               return ret;
+       last_check = now;
+       ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev"));
+       return ret;
+}
+
+static int probe_ext4dev(struct blkid_probe *probe,
+                        struct blkid_magic *id,
+                        unsigned char *buf)
+{
+       struct ext2_super_block *es;
+       es = (struct ext2_super_block *)buf;
+
+       /* Distinguish from jbd */
+       if (blkid_le32(es->s_feature_incompat) &
+           EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+               return -BLKID_ERR_PARAM;
+
+       /* ext4dev requires a journal */
+       if (!(blkid_le32(es->s_feature_compat) &
+             EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+               return -BLKID_ERR_PARAM;
+
+       /*
+        * 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 (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
+               if (!system_supports_ext4dev() && system_supports_ext4())
+                       return -BLKID_ERR_PARAM;
+       } else
+               return -BLKID_ERR_PARAM;
+
+       get_ext2_info(probe->dev, id, buf);
+       return 0;
+}
+
+static int probe_ext4(struct blkid_probe *probe, struct blkid_magic *id,
+                     unsigned char *buf)
+{
+       struct ext2_super_block *es;
+       es = (struct ext2_super_block *)buf;
+
+       /* Distinguish from jbd */
+       if (blkid_le32(es->s_feature_incompat) &
+           EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+               return -BLKID_ERR_PARAM;
+
+       /* ext4 requires journal */
+       if (!(blkid_le32(es->s_feature_compat) &
+             EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+               return -BLKID_ERR_PARAM;
+
+       /* Ext4 has at least one feature which ext3 doesn't understand */
+       if (!(blkid_le32(es->s_feature_ro_compat) &
+             EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
+           !(blkid_le32(es->s_feature_incompat) &
+             EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+               return -BLKID_ERR_PARAM;
+
+       /*
+        * 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 (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
+               if (system_supports_ext4dev() || !system_supports_ext4())
+                       return -BLKID_ERR_PARAM;
+       }
+       get_ext2_info(probe->dev, id, buf);
+       return 0;
+}
+
+static int probe_ext3(struct blkid_probe *probe, struct blkid_magic *id,
+                     unsigned char *buf)
+{
+       struct ext2_super_block *es;
+       es = (struct ext2_super_block *)buf;
+
+       /* Distinguish from ext4dev */
+       if (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)
+               return -BLKID_ERR_PARAM;
+
+       /* ext3 requires journal */
+       if (!(blkid_le32(es->s_feature_compat) &
+             EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+               return -BLKID_ERR_PARAM;
+
+       /* Any features which ext3 doesn't understand */
+       if ((blkid_le32(es->s_feature_ro_compat) &
+            EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) ||
+           (blkid_le32(es->s_feature_incompat) &
+            EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
+               return -BLKID_ERR_PARAM;
+
+       get_ext2_info(probe->dev, id, buf);
+       return 0;
+}
+
+static int probe_ext2(struct blkid_probe *probe, struct blkid_magic *id,
+                     unsigned char *buf)
+{
+       struct ext2_super_block *es;
+
+       es = (struct ext2_super_block *)buf;
+
+       /* Distinguish between ext3 and ext2 */
+       if ((blkid_le32(es->s_feature_compat) &
+             EXT3_FEATURE_COMPAT_HAS_JOURNAL))
+               return -BLKID_ERR_PARAM;
+
+       /* Any features which ext2 doesn't understand */
+       if ((blkid_le32(es->s_feature_ro_compat) &
+            EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
+           (blkid_le32(es->s_feature_incompat) &
+            EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
+               return -BLKID_ERR_PARAM;
+
+       get_ext2_info(probe->dev, id, buf);
+       return 0;
+}
+
+static int probe_jbd(struct blkid_probe *probe, struct blkid_magic *id,
+                    unsigned char *buf)
+{
+       struct ext2_super_block *es = (struct ext2_super_block *) buf;
+
+       if (!(blkid_le32(es->s_feature_incompat) &
+             EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
+               return -BLKID_ERR_PARAM;
+
+       get_ext2_info(probe->dev, id, buf);
+
+       return 0;
+}
+
+#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    ";
+
+static unsigned char *search_fat_label(struct vfat_dir_entry *dir, int count)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               if (dir[i].name[0] == 0x00)
+                       break;
+
+               if ((dir[i].name[0] == FAT_ENTRY_FREE) ||
+                   (dir[i].cluster_high != 0 || dir[i].cluster_low != 0) ||
+                   ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME))
+                       continue;
+
+               if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) ==
+                   FAT_ATTR_VOLUME_ID) {
+                       return dir[i].name;
+               }
+       }
+       return 0;
+}
+
+/* FAT label extraction from the root directory taken from Kay
+ * Sievers's volume_id library */
+static int probe_fat(struct blkid_probe *probe,
+                     struct blkid_magic *id __BLKID_ATTR((unused)),
+                     unsigned char *buf)
+{
+       struct vfat_super_block *vs = (struct vfat_super_block *) buf;
+       struct msdos_super_block *ms = (struct msdos_super_block *) buf;
+       struct vfat_dir_entry *dir;
+       char serno[10];
+       const unsigned char *label = 0, *vol_label = 0, *tmp;
+       unsigned char   *vol_serno;
+       int label_len = 0, maxloop = 100;
+       __u16 sector_size, dir_entries, reserved;
+       __u32 sect_count, fat_size, dir_size, cluster_count, fat_length;
+       __u32 buf_size, start_data_sect, next, root_start, root_dir_entries;
+
+       /* sector size check */
+       tmp = (unsigned char *)&ms->ms_sector_size;
+       sector_size = tmp[0] + (tmp[1] << 8);
+       if (sector_size != 0x200 && sector_size != 0x400 &&
+           sector_size != 0x800 && sector_size != 0x1000)
+               return 1;
+
+       tmp = (unsigned char *)&ms->ms_dir_entries;
+       dir_entries = tmp[0] + (tmp[1] << 8);
+       reserved =  blkid_le16(ms->ms_reserved);
+       tmp = (unsigned char *)&ms->ms_sectors;
+       sect_count = tmp[0] + (tmp[1] << 8);
+       if (sect_count == 0)
+               sect_count = blkid_le32(ms->ms_total_sect);
+
+       fat_length = blkid_le16(ms->ms_fat_length);
+       if (fat_length == 0)
+               fat_length = blkid_le32(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);
+       if (ms->ms_cluster_size == 0)
+               return 1;
+       cluster_count /= ms->ms_cluster_size;
+
+       if (cluster_count > FAT32_MAX)
+               return 1;
+
+       if (ms->ms_fat_length) {
+               /* the label may be an attribute in the root directory */
+               root_start = (reserved + fat_size) * sector_size;
+               root_dir_entries = vs->vs_dir_entries[0] +
+                       (vs->vs_dir_entries[1] << 8);
+
+               buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
+               dir = (struct vfat_dir_entry *) get_buffer(probe, root_start,
+                                                          buf_size);
+               if (dir)
+                       vol_label = search_fat_label(dir, root_dir_entries);
+
+               if (!vol_label || !memcmp(vol_label, no_name, 11))
+                       vol_label = ms->ms_label;
+               vol_serno = ms->ms_serno;
+
+               blkid_set_tag(probe->dev, "SEC_TYPE", "msdos",
+                             sizeof("msdos"));
+       } else {
+               /* Search the FAT32 root dir for the label attribute */
+               buf_size = vs->vs_cluster_size * sector_size;
+               start_data_sect = reserved + fat_size;
+
+               next = blkid_le32(vs->vs_root_cluster);
+               while (next && --maxloop) {
+                       __u32 next_sect_off;
+                       __u64 next_off, fat_entry_off;
+                       int count;
+
+                       next_sect_off = (next - 2) * vs->vs_cluster_size;
+                       next_off = (start_data_sect + next_sect_off) *
+                               sector_size;
+
+                       dir = (struct vfat_dir_entry *)
+                               get_buffer(probe, next_off, buf_size);
+                       if (dir == NULL)
+                               break;
+
+                       count = buf_size / sizeof(struct vfat_dir_entry);
+
+                       vol_label = search_fat_label(dir, count);
+                       if (vol_label)
+                               break;
+
+                       /* get FAT entry */
+                       fat_entry_off = (reserved * sector_size) +
+                               (next * sizeof(__u32));
+                       buf = get_buffer(probe, fat_entry_off, buf_size);
+                       if (buf == NULL)
+                               break;
+
+                       /* set next cluster */
+                       next = blkid_le32(*((__u32 *) buf) & 0x0fffffff);
+               }
+
+               if (!vol_label || !memcmp(vol_label, no_name, 11))
+                       vol_label = vs->vs_label;
+               vol_serno = vs->vs_serno;
+       }
+
+       if (vol_label && memcmp(vol_label, no_name, 11)) {
+               if ((label_len = figure_label_len(vol_label, 11)))
+                       label = vol_label;
+       }
+
+       /* We can't just print them as %04X, because they are unaligned */
+       sprintf(serno, "%02X%02X-%02X%02X", vol_serno[3], vol_serno[2],
+               vol_serno[1], vol_serno[0]);
+
+       blkid_set_tag(probe->dev, "LABEL", (const char *) label, label_len);
+       blkid_set_tag(probe->dev, "UUID", serno, sizeof(serno)-1);
+
+       return 0;
+}
+
+/*
+ * The FAT filesystem could be without a magic string in superblock
+ * (e.g. old floppies).  This heuristic for FAT detection is inspired
+ * by http://vrfy.org/projects/volume_id/ and Linux kernel.
+ * [7-Jul-2005, Karel Zak <kzak@redhat.com>]
+ */
+static int probe_fat_nomagic(struct blkid_probe *probe,
+                            struct blkid_magic *id __BLKID_ATTR((unused)),
+                            unsigned char *buf)
+{
+       struct msdos_super_block *ms;
+
+       ms = (struct msdos_super_block *)buf;
+
+       /* heads check */
+       if (ms->ms_heads == 0)
+               return 1;
+
+       /* cluster size check*/
+       if (ms->ms_cluster_size == 0 ||
+           (ms->ms_cluster_size & (ms->ms_cluster_size-1)))
+               return 1;
+
+       /* media check */
+       if (ms->ms_media < 0xf8 && ms->ms_media != 0xf0)
+               return 1;
+
+       /* fat counts(Linux kernel expects at least 1 FAT table) */
+       if (!ms->ms_fats)
+               return 1;
+
+       /*
+        * 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 1;
+
+       return probe_fat(probe, id, buf);
+}
+
+static int probe_ntfs(struct blkid_probe *probe,
+                     struct blkid_magic *id __BLKID_ATTR((unused)),
+                     unsigned char *buf)
+{
+       struct ntfs_super_block *ns;
+       struct master_file_table_record *mft;
+       struct file_attribute *attr;
+       char            uuid_str[17], label_str[129], *cp;
+       int             bytes_per_sector, sectors_per_cluster;
+       int             mft_record_size, attr_off, attr_len;
+       unsigned int    i, attr_type, val_len;
+       int             val_off;
+       __u64           nr_clusters;
+       blkid_loff_t off;
+       unsigned char *buf_mft, *val;
+
+       ns = (struct ntfs_super_block *) buf;
+
+       bytes_per_sector = ns->bios_parameter_block[0] +
+               (ns->bios_parameter_block[1]  << 8);
+       sectors_per_cluster = ns->bios_parameter_block[2];
+
+       if ((bytes_per_sector < 512) || (sectors_per_cluster == 0))
+               return 1;
+
+       if (ns->cluster_per_mft_record < 0)
+               mft_record_size = 1 << (0-ns->cluster_per_mft_record);
+       else
+               mft_record_size = ns->cluster_per_mft_record *
+                       sectors_per_cluster * bytes_per_sector;
+       nr_clusters = blkid_le64(ns->number_of_sectors) / sectors_per_cluster;
+
+       if ((blkid_le64(ns->mft_cluster_location) > nr_clusters) ||
+           (blkid_le64(ns->mft_mirror_cluster_location) > nr_clusters))
+               return 1;
+
+       off = blkid_le64(ns->mft_mirror_cluster_location) *
+               bytes_per_sector * sectors_per_cluster;
+
+       buf_mft = get_buffer(probe, off, mft_record_size);
+       if (!buf_mft)
+               return 1;
+
+       if (memcmp(buf_mft, "FILE", 4))
+               return 1;
+
+       off = blkid_le64(ns->mft_cluster_location) * bytes_per_sector *
+               sectors_per_cluster;
+
+       buf_mft = get_buffer(probe, off, mft_record_size);
+       if (!buf_mft)
+               return 1;
+
+       if (memcmp(buf_mft, "FILE", 4))
+               return 1;
+
+       off += MFT_RECORD_VOLUME * mft_record_size;
+
+       buf_mft = get_buffer(probe, off, mft_record_size);
+       if (!buf_mft)
+               return 1;
+
+       if (memcmp(buf_mft, "FILE", 4))
+               return 1;
+
+       mft = (struct master_file_table_record *) buf_mft;
+
+       attr_off = blkid_le16(mft->attrs_offset);
+       label_str[0] = 0;
+
+       while (1) {
+               attr = (struct file_attribute *) (buf_mft + attr_off);
+               attr_len = blkid_le16(attr->len);
+               attr_type = blkid_le32(attr->type);
+               val_off = blkid_le16(attr->value_offset);
+               val_len = blkid_le32(attr->value_len);
+
+               attr_off += attr_len;
+
+               if ((attr_off > mft_record_size) ||
+                   (attr_len == 0))
+                       break;
+
+               if (attr_type == MFT_RECORD_ATTR_END)
+                       break;
+
+               if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
+                       if (val_len > sizeof(label_str))
+                               val_len = sizeof(label_str)-1;
+
+                       for (i=0, cp=label_str; i < val_len; i+=2,cp++) {
+                               val = ((__u8 *) attr) + val_off + i;
+                               *cp = val[0];
+                               if (val[1])
+                                       *cp = '?';
+                       }
+                       *cp = 0;
+               }
+       }
+
+       sprintf(uuid_str, "%016llX", blkid_le64(ns->volume_serial));
+       blkid_set_tag(probe->dev, "UUID", uuid_str, 0);
+       if (label_str[0])
+               blkid_set_tag(probe->dev, "LABEL", label_str, 0);
+       return 0;
+}
+
+
+static int probe_xfs(struct blkid_probe *probe,
+                    struct blkid_magic *id __BLKID_ATTR((unused)),
+                    unsigned char *buf)
+{
+       struct xfs_super_block *xs;
+       const char *label = 0;
+
+       xs = (struct xfs_super_block *)buf;
+
+       if (strlen(xs->xs_fname))
+               label = xs->xs_fname;
+       blkid_set_tag(probe->dev, "LABEL", label, sizeof(xs->xs_fname));
+       set_uuid(probe->dev, xs->xs_uuid, 0);
+       return 0;
+}
+
+static int probe_reiserfs(struct blkid_probe *probe,
+                         struct blkid_magic *id, unsigned char *buf)
+{
+       struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf;
+       unsigned int blocksize;
+       const char *label = 0;
+
+       blocksize = blkid_le16(rs->rs_blocksize);
+
+       /* The blocksize must be at least 1k */
+       if ((blocksize >> 10) == 0)
+               return -BLKID_ERR_PARAM;
+
+       /* If the superblock is inside the journal, we have the wrong one */
+       if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block))
+               return -BLKID_ERR_BIG;
+
+       /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
+       if (id->bim_magic[6] == '2' || id->bim_magic[6] == '3') {
+               if (strlen(rs->rs_label))
+                       label = rs->rs_label;
+               set_uuid(probe->dev, rs->rs_uuid, 0);
+       }
+       blkid_set_tag(probe->dev, "LABEL", label, sizeof(rs->rs_label));
+
+       return 0;
+}
+
+static int probe_reiserfs4(struct blkid_probe *probe,
+                          struct blkid_magic *id __BLKID_ATTR((unused)),
+                          unsigned char *buf)
+{
+       struct reiser4_super_block *rs4 = (struct reiser4_super_block *) buf;
+       const unsigned char *label = 0;
+
+       if (strlen((char *) rs4->rs4_label))
+               label = rs4->rs4_label;
+       set_uuid(probe->dev, rs4->rs4_uuid, 0);
+       blkid_set_tag(probe->dev, "LABEL", (const char *) label,
+                     sizeof(rs4->rs4_label));
+
+       return 0;
+}
+
+static int probe_jfs(struct blkid_probe *probe,
+                    struct blkid_magic *id __BLKID_ATTR((unused)),
+                    unsigned char *buf)
+{
+       struct jfs_super_block *js;
+       const char *label = 0;
+
+       js = (struct jfs_super_block *)buf;
+
+       if (blkid_le32(js->js_bsize) != (1 << blkid_le16(js->js_l2bsize)))
+               return 1;
+
+       if (blkid_le32(js->js_pbsize) != (1 << blkid_le16(js->js_l2pbsize)))
+               return 1;
+
+       if ((blkid_le16(js->js_l2bsize) - blkid_le16(js->js_l2pbsize)) !=
+           blkid_le16(js->js_l2bfactor))
+               return 1;
+
+       if (strlen((char *) js->js_label))
+               label = (char *) js->js_label;
+       blkid_set_tag(probe->dev, "LABEL", label, sizeof(js->js_label));
+       set_uuid(probe->dev, js->js_uuid, 0);
+       return 0;
+}
+
+static int probe_zfs(struct blkid_probe *probe, struct blkid_magic *id,
+                    unsigned char *buf)
+{
+#if 0
+       char *vdev_label;
+       const char *pool_name = 0;
+
+       /* read nvpair data for pool name, pool GUID (complex) */
+       blkid_set_tag(probe->dev, "LABEL", pool_name, sizeof(pool_name));
+       set_uuid(probe->dev, pool_guid, 0);
+#endif
+       return 0;
+}
+
+static int probe_luks(struct blkid_probe *probe,
+                      struct blkid_magic *id __BLKID_ATTR((unused)),
+                      unsigned char *buf)
+{
+       char uuid[40];
+
+       /* 168 is the offset to the 40 character uuid:
+        * http://luks.endorphin.org/LUKS-on-disk-format.pdf */
+       strncpy(uuid, (char *) buf+168, 40);
+       blkid_set_tag(probe->dev, "UUID", uuid, sizeof(uuid));
+       return 0;
+}
+
+static int probe_romfs(struct blkid_probe *probe,
+                      struct blkid_magic *id __BLKID_ATTR((unused)),
+                      unsigned char *buf)
+{
+       struct romfs_super_block *ros;
+       const char *label = 0;
+
+       ros = (struct romfs_super_block *)buf;
+
+       if (strlen((char *) ros->ros_volume))
+               label = (char *) ros->ros_volume;
+       blkid_set_tag(probe->dev, "LABEL", label, 0);
+       return 0;
+}
+
+static int probe_cramfs(struct blkid_probe *probe,
+                       struct blkid_magic *id __BLKID_ATTR((unused)),
+                       unsigned char *buf)
+{
+       struct cramfs_super_block *csb;
+       const char *label = 0;
+
+       csb = (struct cramfs_super_block *)buf;
+
+       if (strlen((char *) csb->name))
+               label = (char *) csb->name;
+       blkid_set_tag(probe->dev, "LABEL", label, 0);
+       return 0;
+}
+
+static int probe_swap0(struct blkid_probe *probe,
+                      struct blkid_magic *id __BLKID_ATTR((unused)),
+                      unsigned char *buf __BLKID_ATTR((unused)))
+{
+       blkid_set_tag(probe->dev, "UUID", 0, 0);
+       blkid_set_tag(probe->dev, "LABEL", 0, 0);
+       return 0;
+}
+
+static int probe_swap1(struct blkid_probe *probe,
+                      struct blkid_magic *id,
+                      unsigned char *buf __BLKID_ATTR((unused)))
+{
+       struct swap_id_block *sws;
+
+       probe_swap0(probe, id, buf);
+       /*
+        * Version 1 swap headers are always located at offset of 1024
+        * bytes, although the swap signature itself is located at the
+        * end of the page (which may vary depending on hardware
+        * pagesize).
+        */
+       sws = (struct swap_id_block *) get_buffer(probe, 1024, 1024);
+       if (!sws)
+               return 1;
+
+       /* check for wrong version or zeroed pagecount, for sanity */
+       if (!memcmp(id->bim_magic, "SWAPSPACE2", id->bim_len) &&
+                       (sws->sws_version != 1 || sws->sws_lastpage == 0))
+               return 1;
+
+       /* arbitrary sanity check.. is there any garbage down there? */
+       if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0)  {
+               if (sws->sws_volume[0])
+                       blkid_set_tag(probe->dev, "LABEL", sws->sws_volume,
+                                     sizeof(sws->sws_volume));
+               if (sws->sws_uuid[0])
+                       set_uuid(probe->dev, sws->sws_uuid, 0);
+       }
+       return 0;
+}
+
+static int probe_iso9660(struct blkid_probe *probe,
+                        struct blkid_magic *id __BLKID_ATTR((unused)),
+                        unsigned char *buf)
+{
+       struct iso_volume_descriptor *iso;
+       const unsigned char *label;
+
+       iso = (struct iso_volume_descriptor *) buf;
+       label = iso->volume_id;
+
+       blkid_set_tag(probe->dev, "LABEL", (const char *) label,
+                     figure_label_len(label, 32));
+       return 0;
+}
+
+
+static const char
+*udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02",
+                "NSR03", "TEA01", 0 };
+
+static int probe_udf(struct blkid_probe *probe,
+                    struct blkid_magic *id __BLKID_ATTR((unused)),
+                    unsigned char *buf __BLKID_ATTR((unused)))
+{
+       int j, bs;
+       struct iso_volume_descriptor *isosb;
+       const char ** m;
+
+       /* determine the block size by scanning in 2K increments
+          (block sizes larger than 2K will be null padded) */
+       for (bs = 1; bs < 16; bs++) {
+               isosb = (struct iso_volume_descriptor *)
+                       get_buffer(probe, bs*2048+32768, sizeof(isosb));
+               if (!isosb)
+                       return 1;
+               if (isosb->vd_id[0])
+                       break;
+       }
+
+       /* Scan up to another 64 blocks looking for additional VSD's */
+       for (j = 1; j < 64; j++) {
+               if (j > 1) {
+                       isosb = (struct iso_volume_descriptor *)
+                               get_buffer(probe, j*bs*2048+32768,
+                                          sizeof(isosb));
+                       if (!isosb)
+                               return 1;
+               }
+               /* If we find NSR0x then call it udf:
+                  NSR01 for UDF 1.00
+                  NSR02 for UDF 1.50
+                  NSR03 for UDF 2.00 */
+               if (!memcmp(isosb->vd_id, "NSR0", 4))
+                       return probe_iso9660(probe, id, buf);
+               for (m = udf_magic; *m; m++)
+                       if (!memcmp(*m, isosb->vd_id, 5))
+                               break;
+               if (*m == 0)
+                       return 1;
+       }
+       return 1;
+}
+
+static int probe_ocfs(struct blkid_probe *probe,
+                     struct blkid_magic *id __BLKID_ATTR((unused)),
+                     unsigned char *buf)
+{
+       struct ocfs_volume_header ovh;
+       struct ocfs_volume_label ovl;
+       __u32 major;
+
+       memcpy(&ovh, buf, sizeof(ovh));
+       memcpy(&ovl, buf+512, sizeof(ovl));
+
+       major = ocfsmajor(ovh);
+       if (major == 1)
+               blkid_set_tag(probe->dev,"SEC_TYPE","ocfs1",sizeof("ocfs1"));
+       else if (major >= 9)
+               blkid_set_tag(probe->dev,"SEC_TYPE","ntocfs",sizeof("ntocfs"));
+
+       blkid_set_tag(probe->dev, "LABEL", ovl.label, ocfslabellen(ovl));
+       blkid_set_tag(probe->dev, "MOUNT", ovh.mount, ocfsmountlen(ovh));
+       set_uuid(probe->dev, ovl.vol_id, 0);
+       return 0;
+}
+
+static int probe_ocfs2(struct blkid_probe *probe,
+                      struct blkid_magic *id __BLKID_ATTR((unused)),
+                      unsigned char *buf)
+{
+       struct ocfs2_super_block *osb;
+
+       osb = (struct ocfs2_super_block *)buf;
+
+       blkid_set_tag(probe->dev, "LABEL", osb->s_label, sizeof(osb->s_label));
+       set_uuid(probe->dev, osb->s_uuid, 0);
+       return 0;
+}
+
+static int probe_oracleasm(struct blkid_probe *probe,
+                          struct blkid_magic *id __BLKID_ATTR((unused)),
+                          unsigned char *buf)
+{
+       struct oracle_asm_disk_label *dl;
+
+       dl = (struct oracle_asm_disk_label *)buf;
+
+       blkid_set_tag(probe->dev, "LABEL", dl->dl_id, sizeof(dl->dl_id));
+       return 0;
+}
+
+static int probe_gfs(struct blkid_probe *probe,
+                    struct blkid_magic *id __BLKID_ATTR((unused)),
+                    unsigned char *buf)
+{
+       struct gfs2_sb *sbd;
+       const char *label = 0;
+
+       sbd = (struct gfs2_sb *)buf;
+
+       if (blkid_be32(sbd->sb_fs_format) == GFS_FORMAT_FS &&
+           blkid_be32(sbd->sb_multihost_format) == GFS_FORMAT_MULTI)
+       {
+               blkid_set_tag(probe->dev, "UUID", 0, 0);
+
+               if (strlen(sbd->sb_locktable))
+                       label = sbd->sb_locktable;
+               blkid_set_tag(probe->dev, "LABEL", label, sizeof(sbd->sb_locktable));
+               return 0;
+       }
+       return 1;
+}
+
+static int probe_gfs2(struct blkid_probe *probe,
+                    struct blkid_magic *id __BLKID_ATTR((unused)),
+                    unsigned char *buf)
+{
+       struct gfs2_sb *sbd;
+       const char *label = 0;
+
+       sbd = (struct gfs2_sb *)buf;
+
+       if (blkid_be32(sbd->sb_fs_format) == GFS2_FORMAT_FS &&
+           blkid_be32(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI)
+       {
+               blkid_set_tag(probe->dev, "UUID", 0, 0);
+
+               if (strlen(sbd->sb_locktable))
+                       label = sbd->sb_locktable;
+               blkid_set_tag(probe->dev, "LABEL", label, sizeof(sbd->sb_locktable));
+               return 0;
+       }
+       return 1;
+}
+
+static void unicode_16be_to_utf8(unsigned char *str, int out_len,
+                                const unsigned char *buf, int in_len)
+{
+       int i, j;
+       unsigned int c;
+
+       for (i = j = 0; i + 2 <= in_len; i += 2) {
+               c = (buf[i] << 8) | buf[i+1];
+               if (c == 0) {
+                       str[j] = '\0';
+                       break;
+               } else if (c < 0x80) {
+                       if (j+1 >= out_len)
+                               break;
+                       str[j++] = (unsigned char) c;
+               } else if (c < 0x800) {
+                       if (j+2 >= out_len)
+                               break;
+                       str[j++] = (unsigned char) (0xc0 | (c >> 6));
+                       str[j++] = (unsigned char) (0x80 | (c & 0x3f));
+               } else {
+                       if (j+3 >= out_len)
+                               break;
+                       str[j++] = (unsigned char) (0xe0 | (c >> 12));
+                       str[j++] = (unsigned char) (0x80 | ((c >> 6) & 0x3f));
+                       str[j++] = (unsigned char) (0x80 | (c & 0x3f));
+               }
+       }
+       str[j] = '\0';
+}
+
+static int probe_hfs(struct blkid_probe *probe __BLKID_ATTR((unused)),
+                        struct blkid_magic *id __BLKID_ATTR((unused)),
+                        unsigned char *buf)
+{
+       struct hfs_mdb *hfs = (struct hfs_mdb *) buf;
+       char    uuid_str[17];
+       __u64   uuid;
+
+       if ((memcmp(hfs->embed_sig, "H+", 2) == 0) ||
+           (memcmp(hfs->embed_sig, "HX", 2) == 0))
+               return 1;       /* Not hfs, but an embedded HFS+ */
+
+       uuid = blkid_le64(*((unsigned long long *) hfs->finder_info.id));
+       if (uuid) {
+               sprintf(uuid_str, "%016llX", uuid);
+               blkid_set_tag(probe->dev, "UUID", uuid_str, 0);
+       }
+       blkid_set_tag(probe->dev, "LABEL", hfs->label, hfs->label_len);
+       return 0;
+}
+
+
+static int probe_hfsplus(struct blkid_probe *probe,
+                        struct blkid_magic *id,
+                        unsigned char *buf)
+{
+       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 = (struct hfs_mdb *) buf;
+       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;
+       unsigned int label_len;
+       int ext;
+       __u64 leaf_off, uuid;
+       char    uuid_str[17], label[512];
+
+       /* 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 = blkid_be32(sbd->al_blk_size);
+               alloc_first_block = blkid_be16(sbd->al_bl_st);
+               embed_first_block = blkid_be16(sbd->embed_startblock);
+               off = (alloc_first_block * 512) +
+                       (embed_first_block * alloc_block_size);
+               buf = get_buffer(probe, off + (id->bim_kboff * 1024),
+                                sizeof(sbd));
+               if (!buf)
+                       return 1;
+
+               hfsplus = (struct hfsplus_vol_header *) buf;
+       }
+
+       hfsplus = (struct hfsplus_vol_header *) buf;
+
+       if ((memcmp(hfsplus->signature, "H+", 2) != 0) &&
+           (memcmp(hfsplus->signature, "HX", 2) != 0))
+               return 1;
+
+       uuid = blkid_le64(*((unsigned long long *) hfsplus->finder_info.id));
+       if (uuid) {
+               sprintf(uuid_str, "%016llX", uuid);
+               blkid_set_tag(probe->dev, "UUID", uuid_str, 0);
+       }
+
+       blocksize = blkid_be32(hfsplus->blocksize);
+       memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
+       cat_block = blkid_be32(extents[0].start_block);
+
+       buf = get_buffer(probe, off + (cat_block * blocksize), 0x2000);
+       if (!buf)
+               return 0;
+
+       bnode = (struct hfsplus_bheader_record *)
+               &buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+       leaf_node_head = blkid_be32(bnode->leaf_head);
+       leaf_node_size = blkid_be16(bnode->node_size);
+       leaf_node_count = blkid_be32(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 = blkid_be32(extents[ext].start_block);
+               ext_block_count = blkid_be32(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 = get_buffer(probe, off + leaf_off, leaf_node_size);
+       if (!buf)
+               return 0;
+
+       descr = (struct hfsplus_bnode_descriptor *) buf;
+       record_count = blkid_be16(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 (blkid_be32(key->parent_id) != HFSPLUS_POR_CNID)
+               return 0;
+
+       label_len = blkid_be16(key->unicode_len) * 2;
+       unicode_16be_to_utf8(label, sizeof(label), key->unicode, label_len);
+       blkid_set_tag(probe->dev, "LABEL", label, 0);
+       return 0;
+}
+
+#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 __u8 *data = (const __u8 *) buf;
+
+       for (i = 0; i < size; i++) {
+               crc ^= *data++;
+               crc = (crc >> 4) ^ crctab[crc & 0xf];
+               crc = (crc >> 4) ^ crctab[crc & 0xf];
+       }
+       return crc;
+}
+
+static int probe_lvm2(struct blkid_probe *probe,
+                       struct blkid_magic *id,
+                       unsigned char *buf)
+{
+       int sector = (id->bim_kboff) << 1;
+       struct lvm2_pv_label_header *label= (struct lvm2_pv_label_header *)buf;
+       char *p, *q, uuid[40];
+       unsigned int i, b;
+
+       /* 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 (blkid_le64(label->sector_xl) != (unsigned) sector) {
+               DBG(DEBUG_PROBE,
+                   printf("LVM2: label for sector %llu found at sector %d\n",
+                          blkid_le64(label->sector_xl), sector));
+               return 1;
+       }
+
+       if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE -
+                         ((char *)&label->offset_xl - (char *)label)) !=
+                       blkid_le32(label->crc_xl)) {
+               DBG(DEBUG_PROBE,
+                   printf("LVM2: label checksum incorrect at sector %d\n",
+                          sector));
+               return 1;
+       }
+
+       for (i=0, b=1, p=uuid, q= (char *) label->pv_uuid; i <= 32;
+            i++, b <<= 1) {
+               if (b & 0x4444440)
+                       *p++ = '-';
+               *p++ = *q++;
+       }
+
+       blkid_set_tag(probe->dev, "UUID", uuid, LVM2_ID_LEN+6);
+
+       return 0;
+}
+/*
+ * Various filesystem magics that we can check for.  Note that kboff and
+ * sboff are in kilobytes and bytes respectively.  All magics are in
+ * byte strings so we don't worry about endian issues.
+ */
+static struct blkid_magic type_array[] = {
+/*  type     kboff   sboff len  magic                  probe */
+  { "oracleasm", 0,    32,  8, "ORCLDISK",             probe_oracleasm },
+  { "ntfs",     0,      3,  8, "NTFS    ",             probe_ntfs },
+  { "jbd",      1,   0x38,  2, "\123\357",             probe_jbd },
+  { "ext4dev",  1,   0x38,  2, "\123\357",             probe_ext4dev },
+  { "ext4",     1,   0x38,  2, "\123\357",             probe_ext4 },
+  { "ext3",     1,   0x38,  2, "\123\357",             probe_ext3 },
+  { "ext2",     1,   0x38,  2, "\123\357",             probe_ext2 },
+  { "reiserfs",         8,   0x34,  8, "ReIsErFs",             probe_reiserfs },
+  { "reiserfs", 64,   0x34,  9, "ReIsEr2Fs",           probe_reiserfs },
+  { "reiserfs", 64,   0x34,  9, "ReIsEr3Fs",           probe_reiserfs },
+  { "reiserfs", 64,   0x34,  8, "ReIsErFs",            probe_reiserfs },
+  { "reiserfs",         8,     20,  8, "ReIsErFs",             probe_reiserfs },
+  { "reiser4",  64,     0,  7, "ReIsEr4",              probe_reiserfs4 },
+  { "gfs2",     64,      0,  4, "\x01\x16\x19\x70",     probe_gfs2 },
+  { "gfs",      64,      0,  4, "\x01\x16\x19\x70",     probe_gfs },
+  { "vfat",      0,   0x52,  5, "MSWIN",                probe_fat },
+  { "vfat",      0,   0x52,  8, "FAT32   ",             probe_fat },
+  { "vfat",      0,   0x36,  5, "MSDOS",                probe_fat },
+  { "vfat",      0,   0x36,  8, "FAT16   ",             probe_fat },
+  { "vfat",      0,   0x36,  8, "FAT12   ",             probe_fat },
+  { "vfat",      0,      0,  1, "\353",                 probe_fat_nomagic },
+  { "vfat",      0,      0,  1, "\351",                 probe_fat_nomagic },
+  { "vfat",      0,  0x1fe,  2, "\125\252",             probe_fat_nomagic },
+  { "minix",     1,   0x10,  2, "\177\023",             0 },
+  { "minix",     1,   0x10,  2, "\217\023",             0 },
+  { "minix",    1,   0x10,  2, "\150\044",             0 },
+  { "minix",    1,   0x10,  2, "\170\044",             0 },
+  { "vxfs",     1,      0,  4, "\365\374\001\245",     0 },
+  { "xfs",      0,      0,  4, "XFSB",                 probe_xfs },
+  { "romfs",    0,      0,  8, "-rom1fs-",             probe_romfs },
+  { "bfs",      0,      0,  4, "\316\372\173\033",     0 },
+  { "cramfs",   0,      0,  4, "E=\315\050",           probe_cramfs },
+  { "qnx4",     0,      4,  6, "QNX4FS",               0 },
+  { "udf",     32,      1,  5, "BEA01",                probe_udf },
+  { "udf",     32,      1,  5, "BOOT2",                probe_udf },
+  { "udf",     32,      1,  5, "CD001",                probe_udf },
+  { "udf",     32,      1,  5, "CDW02",                probe_udf },
+  { "udf",     32,      1,  5, "NSR02",                probe_udf },
+  { "udf",     32,      1,  5, "NSR03",                probe_udf },
+  { "udf",     32,      1,  5, "TEA01",                probe_udf },
+  { "iso9660", 32,      1,  5, "CD001",                probe_iso9660 },
+  { "iso9660", 32,      9,  5, "CDROM",                probe_iso9660 },
+  { "jfs",     32,      0,  4, "JFS1",                 probe_jfs },
+  { "zfs",       8,     0,  8, "\0\0\x02\xf5\xb0\x07\xb1\x0c", probe_zfs },
+  { "zfs",       8,     0,  8, "\x0c\xb1\x07\xb0\xf5\x02\0\0", probe_zfs },
+  { "zfs",     264,     0,  8, "\0\0\x02\xf5\xb0\x07\xb1\x0c", probe_zfs },
+  { "zfs",     264,     0,  8, "\x0c\xb1\x07\xb0\xf5\x02\0\0", probe_zfs },
+  { "hfsplus",  1,      0,  2, "BD",                   probe_hfsplus },
+  { "hfsplus",  1,      0,  2, "H+",                   probe_hfsplus },
+  { "hfsplus",  1,      0,  2, "HX",                   probe_hfsplus },
+  { "hfs",      1,      0,  2, "BD",                   probe_hfs },
+  { "ufs",      8,  0x55c,  4, "T\031\001\000",        0 },
+  { "hpfs",     8,      0,  4, "I\350\225\371",        0 },
+  { "sysv",     0,  0x3f8,  4, "\020~\030\375",        0 },
+  { "swap",     0,  0xff6, 10, "SWAP-SPACE",           probe_swap0 },
+  { "swap",     0,  0xff6, 10, "SWAPSPACE2",           probe_swap1 },
+  { "swsuspend", 0,  0xff6,  9, "S1SUSPEND",           probe_swap1 },
+  { "swsuspend", 0,  0xff6,  9, "S2SUSPEND",           probe_swap1 },
+  { "swap",     0, 0x1ff6, 10, "SWAP-SPACE",           probe_swap0 },
+  { "swap",     0, 0x1ff6, 10, "SWAPSPACE2",           probe_swap1 },
+  { "swsuspend", 0, 0x1ff6,  9, "S1SUSPEND",           probe_swap1 },
+  { "swsuspend", 0, 0x1ff6,  9, "S2SUSPEND",           probe_swap1 },
+  { "swap",     0, 0x3ff6, 10, "SWAP-SPACE",           probe_swap0 },
+  { "swap",     0, 0x3ff6, 10, "SWAPSPACE2",           probe_swap1 },
+  { "swsuspend", 0, 0x3ff6,  9, "S1SUSPEND",           probe_swap1 },
+  { "swsuspend", 0, 0x3ff6,  9, "S2SUSPEND",           probe_swap1 },
+  { "swap",     0, 0x7ff6, 10, "SWAP-SPACE",           probe_swap0 },
+  { "swap",     0, 0x7ff6, 10, "SWAPSPACE2",           probe_swap1 },
+  { "swsuspend", 0, 0x7ff6,  9, "S1SUSPEND",           probe_swap1 },
+  { "swsuspend", 0, 0x7ff6,  9, "S2SUSPEND",           probe_swap1 },
+  { "swap",     0, 0xfff6, 10, "SWAP-SPACE",           probe_swap0 },
+  { "swap",     0, 0xfff6, 10, "SWAPSPACE2",           probe_swap1 },
+  { "swsuspend", 0, 0xfff6,  9, "S1SUSPEND",           probe_swap1 },
+  { "swsuspend", 0, 0xfff6,  9, "S2SUSPEND",           probe_swap1 },
+  { "ocfs",     0,      8,  9, "OracleCFS",            probe_ocfs },
+  { "ocfs2",    1,      0,  6, "OCFSV2",               probe_ocfs2 },
+  { "ocfs2",    2,      0,  6, "OCFSV2",               probe_ocfs2 },
+  { "ocfs2",    4,      0,  6, "OCFSV2",               probe_ocfs2 },
+  { "ocfs2",    8,      0,  6, "OCFSV2",               probe_ocfs2 },
+  { "crypt_LUKS", 0,    0,  6, "LUKS\xba\xbe",         probe_luks },
+  { "squashfs",         0,      0,  4, "sqsh",                 0 },
+  { "squashfs",         0,      0,  4, "hsqs",                 0 },
+  { "lvm2pv",   0,  0x218,  8, "LVM2 001",             probe_lvm2 },
+  { "lvm2pv",   0,  0x018,  8, "LVM2 001",             probe_lvm2 },
+  { "lvm2pv",   1,  0x018,  8, "LVM2 001",             probe_lvm2 },
+  { "lvm2pv",   1,  0x218,  8, "LVM2 001",             probe_lvm2 },
+  {   NULL,     0,      0,  0, NULL,                   NULL }
+};
+
+/*
+ * 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)
+{
+       struct blkid_magic *id;
+       struct blkid_probe probe;
+       blkid_tag_iterate iter;
+       unsigned char *buf;
+       const char *type, *value;
+       struct stat st;
+       time_t diff, now;
+       int idx;
+
+       if (!dev)
+               return NULL;
+
+       now = time(0);
+       diff = now - dev->bid_time;
+
+       if (stat(dev->bid_name, &st) < 0) {
+               DBG(DEBUG_PROBE,
+                   printf("blkid_verify: error %s (%d) while "
+                          "trying to stat %s\n", strerror(errno), errno,
+                          dev->bid_name));
+       open_err:
+               if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) {
+                       /* We don't have read permission, just return cache data. */
+                       DBG(DEBUG_PROBE, printf("returning unverified data for %s\n",
+                                               dev->bid_name));
+                       return dev;
+               }
+               blkid_free_dev(dev);
+               return NULL;
+       }
+
+       if ((now >= dev->bid_time) &&
+           (st.st_mtime <= dev->bid_time) &&
+           ((diff < BLKID_PROBE_MIN) ||
+            (dev->bid_flags & BLKID_BID_FL_VERIFIED &&
+             diff < BLKID_PROBE_INTERVAL)))
+               return dev;
+
+       DBG(DEBUG_PROBE,
+           printf("need to revalidate %s (cache time %lu, stat time %lu,\n\t"
+                  "time since last check %lu)\n",
+                  dev->bid_name, (unsigned long)dev->bid_time,
+                  (unsigned long)st.st_mtime, (unsigned long)diff));
+
+       if ((probe.fd = open(dev->bid_name, O_RDONLY)) < 0) {
+               DBG(DEBUG_PROBE, printf("blkid_verify: error %s (%d) while "
+                                       "opening %s\n", strerror(errno), errno,
+                                       dev->bid_name));
+               goto open_err;
+       }
+
+       probe.cache = cache;
+       probe.dev = dev;
+       probe.sbbuf = 0;
+       probe.buf = 0;
+       probe.buf_max = 0;
+
+       /*
+        * Iterate over the type array.  If we already know the type,
+        * then try that first.  If it doesn't work, then blow away
+        * the type information, and try again.
+        *
+        */
+try_again:
+       type = 0;
+       if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) {
+               uuid_t  uuid;
+
+               if (check_mdraid(probe.fd, uuid) == 0) {
+                       set_uuid(dev, uuid, 0);
+                       type = "mdraid";
+                       goto found_type;
+               }
+       }
+       for (id = type_array; id->bim_type; id++) {
+               if (dev->bid_type &&
+                   strcmp(id->bim_type, dev->bid_type))
+                       continue;
+
+               idx = id->bim_kboff + (id->bim_sboff >> 10);
+               buf = get_buffer(&probe, idx << 10, 1024);
+               if (!buf)
+                       continue;
+
+               if (memcmp(id->bim_magic, buf + (id->bim_sboff & 0x3ff),
+                          id->bim_len))
+                       continue;
+
+               if ((id->bim_probe == NULL) ||
+                   (id->bim_probe(&probe, id, buf) == 0)) {
+                       type = id->bim_type;
+                       goto found_type;
+               }
+       }
+
+       if (!id->bim_type && dev->bid_type) {
+               /*
+                * Zap the device filesystem information and try again
+                */
+               DBG(DEBUG_PROBE,
+                   printf("previous fs type %s not valid, "
+                          "trying full probe\n", dev->bid_type));
+               iter = blkid_tag_iterate_begin(dev);
+               while (blkid_tag_next(iter, &type, &value) == 0)
+                       blkid_set_tag(dev, type, 0, 0);
+               blkid_tag_iterate_end(iter);
+               goto try_again;
+       }
+
+       if (!dev->bid_type) {
+               blkid_free_dev(dev);
+               dev = 0;
+               goto found_type;
+       }
+
+found_type:
+       if (dev && type) {
+               dev->bid_devno = st.st_rdev;
+               dev->bid_time = time(0);
+               dev->bid_flags |= BLKID_BID_FL_VERIFIED;
+               cache->bic_flags |= BLKID_BIC_FL_CHANGED;
+
+               blkid_set_tag(dev, "TYPE", type, 0);
+
+               DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n",
+                          dev->bid_name, (long long)st.st_rdev, type));
+       }
+
+       if (probe.sbbuf)
+               free(probe.sbbuf);
+       if (probe.buf)
+               free(probe.buf);
+       if (probe.fd >= 0)
+               close(probe.fd);
+
+       return dev;
+}
+
+int blkid_known_fstype(const char *fstype)
+{
+       struct blkid_magic *id;
+
+       for (id = type_array; id->bim_type; id++) {
+               if (strcmp(fstype, id->bim_type) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+#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/libs/blkid/src/probe.h b/libs/blkid/src/probe.h
new file mode 100644 (file)
index 0000000..bee5a51
--- /dev/null
@@ -0,0 +1,711 @@
+/*
+ * probe.h - constants and on-disk structures for extracting device data
+ *
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ * %End-Header%
+ */
+
+#ifndef _BLKID_PROBE_H
+#define _BLKID_PROBE_H
+
+#include <blkid/blkid_types.h>
+
+struct blkid_magic;
+
+#define SB_BUFFER_SIZE         0x11000
+
+struct blkid_probe {
+       int                     fd;
+       blkid_cache             cache;
+       blkid_dev               dev;
+       unsigned char           *sbbuf;
+       size_t                  sb_valid;
+       unsigned char           *buf;
+       size_t                  buf_max;
+};
+
+typedef int (*blkid_probe_t)(struct blkid_probe *probe,
+                            struct blkid_magic *id, unsigned char *buf);
+
+struct blkid_magic {
+       const char      *bim_type;      /* type name for this magic */
+       long            bim_kboff;      /* kilobyte offset of superblock */
+       unsigned        bim_sboff;      /* byte offset within superblock */
+       unsigned        bim_len;        /* length of magic */
+       const char      *bim_magic;     /* magic string */
+       blkid_probe_t   bim_probe;      /* probe function */
+};
+
+/*
+ * Structures for each of the content types we want to extract information
+ * from.  We do not necessarily need the magic field here, because we have
+ * already identified the content type before we get this far.  It may still
+ * be useful if there are probe functions which handle multiple content types.
+ */
+struct ext2_super_block {
+       __u32           s_inodes_count;
+       __u32           s_blocks_count;
+       __u32           s_r_blocks_count;
+       __u32           s_free_blocks_count;
+       __u32           s_free_inodes_count;
+       __u32           s_first_data_block;
+       __u32           s_log_block_size;
+       __u32           s_dummy3[7];
+       unsigned char   s_magic[2];
+       __u16           s_state;
+       __u32           s_dummy5[8];
+       __u32           s_feature_compat;
+       __u32           s_feature_incompat;
+       __u32           s_feature_ro_compat;
+       unsigned char   s_uuid[16];
+       char       s_volume_name[16];
+       char    s_last_mounted[64];
+       __u32   s_algorithm_usage_bitmap;
+       __u8    s_prealloc_blocks;
+       __u8    s_prealloc_dir_blocks;
+       __u16   s_reserved_gdt_blocks;
+       __u8    s_journal_uuid[16];
+       __u32   s_journal_inum;
+       __u32   s_journal_dev;
+       __u32   s_last_orphan;
+       __u32   s_hash_seed[4];
+       __u8    s_def_hash_version;
+       __u8    s_jnl_backup_type;
+       __u16   s_reserved_word_pad;
+       __u32   s_default_mount_opts;
+       __u32   s_first_meta_bg;
+       __u32   s_mkfs_time;
+       __u32   s_jnl_blocks[17];
+       __u32   s_blocks_count_hi;
+       __u32   s_r_blocks_count_hi;
+       __u32   s_free_blocks_hi;
+       __u16   s_min_extra_isize;
+       __u16   s_want_extra_isize;
+       __u32   s_flags;
+       __u16   s_raid_stride;
+       __u16   s_mmp_interval;
+       __u64   s_mmp_block;
+       __u32   s_raid_stripe_width;
+       __u32   s_reserved[163];
+};
+
+/* 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
+
+
+struct xfs_super_block {
+       unsigned char   xs_magic[4];
+       __u32           xs_blocksize;
+       __u64           xs_dblocks;
+       __u64           xs_rblocks;
+       __u32           xs_dummy1[2];
+       unsigned char   xs_uuid[16];
+       __u32           xs_dummy2[15];
+       char            xs_fname[12];
+       __u32           xs_dummy3[2];
+       __u64           xs_icount;
+       __u64           xs_ifree;
+       __u64           xs_fdblocks;
+};
+
+struct reiserfs_super_block {
+       __u32           rs_blocks_count;
+       __u32           rs_free_blocks;
+       __u32           rs_root_block;
+       __u32           rs_journal_block;
+       __u32           rs_journal_dev;
+       __u32           rs_orig_journal_size;
+       __u32           rs_dummy2[5];
+       __u16           rs_blocksize;
+       __u16           rs_dummy3[3];
+       unsigned char   rs_magic[12];
+       __u32           rs_dummy4[5];
+       unsigned char   rs_uuid[16];
+       char            rs_label[16];
+};
+
+struct reiser4_super_block {
+       unsigned char   rs4_magic[16];
+       __u16           rs4_dummy[2];
+       unsigned char   rs4_uuid[16];
+       unsigned char   rs4_label[16];
+       __u64           rs4_dummy2;
+};
+
+struct jfs_super_block {
+       unsigned char   js_magic[4];
+       __u32           js_version;
+       __u64           js_size;
+       __u32           js_bsize;       /* 4: aggregate block size in bytes */
+       __u16           js_l2bsize;     /* 2: log2 of s_bsize */
+       __u16           js_l2bfactor;   /* 2: log2(s_bsize/hardware block size) */
+       __u32           js_pbsize;      /* 4: hardware/LVM block size in bytes */
+       __u16           js_l2pbsize;    /* 2: log2 of s_pbsize */
+       __u16           js_pad;         /* 2: padding necessary for alignment */
+       __u32           js_dummy2[26];
+       unsigned char   js_uuid[16];
+       unsigned char   js_label[16];
+       unsigned char   js_loguuid[16];
+};
+
+struct romfs_super_block {
+       unsigned char   ros_magic[8];
+       __u32           ros_dummy1[2];
+       unsigned char   ros_volume[16];
+};
+
+struct cramfs_super_block {
+       __u8            magic[4];
+       __u32           size;
+       __u32           flags;
+       __u32           future;
+       __u8            signature[16];
+       struct cramfs_info {
+               __u32           crc;
+               __u32           edition;
+               __u32           blocks;
+               __u32           files;
+       } info;
+       __u8            name[16];
+};
+
+struct swap_id_block {
+/*     unsigned char   sws_boot[1024]; */
+       __u32           sws_version;
+       __u32           sws_lastpage;
+       __u32           sws_nrbad;
+       unsigned char   sws_uuid[16];
+       char            sws_volume[16];
+       unsigned char   sws_pad[117];
+       __u32           sws_badpg;
+};
+
+/* 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*/        __u8            vs_cluster_size;
+/* 0e*/        __u16           vs_reserved;
+/* 10*/        __u8            vs_fats;
+/* 11*/        unsigned char   vs_dir_entries[2];
+/* 13*/        unsigned char   vs_sectors[2];
+/* 15*/        unsigned char   vs_media;
+/* 16*/        __u16           vs_fat_length;
+/* 18*/        __u16           vs_secs_track;
+/* 1a*/        __u16           vs_heads;
+/* 1c*/        __u32           vs_hidden;
+/* 20*/        __u32           vs_total_sect;
+/* 24*/        __u32           vs_fat32_length;
+/* 28*/        __u16           vs_flags;
+/* 2a*/        __u8            vs_version[2];
+/* 2c*/        __u32           vs_root_cluster;
+/* 30*/        __u16           vs_insfo_sector;
+/* 32*/        __u16           vs_backup_boot;
+/* 34*/        __u16           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[164];
+/*1fe*/        unsigned char   vs_pmagic[2];
+};
+
+/* 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*/        __u8            ms_cluster_size;
+/* 0e*/        __u16           ms_reserved;
+/* 10*/        __u8            ms_fats;
+/* 11*/        unsigned char   ms_dir_entries[2];
+/* 13*/        unsigned char   ms_sectors[2];
+/* 15*/        unsigned char   ms_media;
+/* 16*/        __u16           ms_fat_length;
+/* 18*/        __u16           ms_secs_track;
+/* 1a*/        __u16           ms_heads;
+/* 1c*/        __u32           ms_hidden;
+/* 20*/        __u32           ms_total_sect;
+/* 24*/        unsigned char   ms_unknown[3];
+/* 27*/        unsigned char   ms_serno[4];
+/* 2b*/        unsigned char   ms_label[11];
+/* 36*/        unsigned char   ms_magic[8];
+/* 3d*/        unsigned char   ms_dummy2[192];
+/*1fe*/        unsigned char   ms_pmagic[2];
+};
+
+struct vfat_dir_entry {
+       __u8    name[11];
+       __u8    attr;
+       __u16   time_creat;
+       __u16   date_creat;
+       __u16   time_acc;
+       __u16   date_acc;
+       __u16   cluster_high;
+       __u16   time_write;
+       __u16   date_write;
+       __u16   cluster_low;
+       __u32   size;
+};
+
+/* maximum number of clusters */
+#define FAT12_MAX 0xFF4
+#define FAT16_MAX 0xFFF4
+#define FAT32_MAX 0x0FFFFFF6
+
+struct minix_super_block {
+       __u16           ms_ninodes;
+       __u16           ms_nzones;
+       __u16           ms_imap_blocks;
+       __u16           ms_zmap_blocks;
+       __u16           ms_firstdatazone;
+       __u16           ms_log_zone_size;
+       __u32           ms_max_size;
+       unsigned char   ms_magic[2];
+       __u16           ms_state;
+       __u32           ms_zones;
+};
+
+struct mdp_superblock_s {
+       __u32 md_magic;
+       __u32 major_version;
+       __u32 minor_version;
+       __u32 patch_version;
+       __u32 gvalid_words;
+       __u32 set_uuid0;
+       __u32 ctime;
+       __u32 level;
+       __u32 size;
+       __u32 nr_disks;
+       __u32 raid_disks;
+       __u32 md_minor;
+       __u32 not_persistent;
+       __u32 set_uuid1;
+       __u32 set_uuid2;
+       __u32 set_uuid3;
+};
+
+struct hfs_super_block {
+       char    h_magic[2];
+       char    h_dummy[18];
+       __u32   h_blksize;
+};
+
+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];
+};
+
+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];
+};
+
+#define ocfsmajor(o) ((__u32)o.major_version[0] \
+                   + (((__u32) o.major_version[1]) << 8) \
+                   + (((__u32) o.major_version[2]) << 16) \
+                   + (((__u32) o.major_version[3]) << 24))
+#define ocfslabellen(o)        ((__u32)o.label_len[0] + (((__u32) o.label_len[1]) << 8))
+#define ocfsmountlen(o)        ((__u32)o.mount_len[0] + (((__u32) o.mount_len[1])<<8))
+
+#define OCFS_MAGIC "OracleCFS"
+
+struct ocfs2_super_block {
+       unsigned char  signature[8];
+       unsigned char  s_dummy1[184];
+       unsigned char  s_dummy2[80];
+       char           s_label[64];
+       unsigned char  s_uuid[16];
+};
+
+#define OCFS2_MIN_BLOCKSIZE             512
+#define OCFS2_MAX_BLOCKSIZE             4096
+
+#define OCFS2_SUPER_BLOCK_BLKNO         2
+
+#define OCFS2_SUPER_BLOCK_SIGNATURE     "OCFSV2"
+
+struct oracle_asm_disk_label {
+       char dummy[32];
+       char dl_tag[8];
+       char dl_id[24];
+};
+
+#define ORACLE_ASM_DISK_LABEL_MARKED    "ORCLDISK"
+#define ORACLE_ASM_DISK_LABEL_OFFSET    32
+
+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];
+};
+
+/* Common gfs/gfs2 constants: */
+#define GFS_MAGIC               0x01161970
+#define GFS_DEFAULT_BSIZE       4096
+#define GFS_SUPERBLOCK_OFFSET  (0x10 * GFS_DEFAULT_BSIZE)
+#define GFS_METATYPE_SB         1
+#define GFS_FORMAT_SB           100
+#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 {
+       __u32 mh_magic;
+       __u32 mh_type;
+       __u64 __pad0;          /* Was generation number in gfs1 */
+       __u32 mh_format;
+       __u32 __pad1;          /* Was incarnation number in gfs1 */
+};
+
+struct gfs2_inum {
+       __u64 no_formal_ino;
+       __u64 no_addr;
+};
+
+struct gfs2_sb {
+       struct gfs2_meta_header sb_header;
+
+       __u32 sb_fs_format;
+       __u32 sb_multihost_format;
+       __u32  __pad0;  /* Was superblock flags in gfs1 */
+
+       __u32 sb_bsize;
+       __u32 sb_bsize_shift;
+       __u32 __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];
+       /* In gfs1, quota and license dinodes followed */
+};
+
+struct ntfs_super_block {
+       __u8    jump[3];
+       __u8    oem_id[8];
+       __u8    bios_parameter_block[25];
+       __u16   unused[2];
+       __u64   number_of_sectors;
+       __u64   mft_cluster_location;
+       __u64   mft_mirror_cluster_location;
+       __s8    cluster_per_mft_record;
+       __u8    reserved1[3];
+       __s8    cluster_per_index_record;
+       __u8    reserved2[3];
+       __u64   volume_serial;
+       __u16   checksum;
+};
+
+struct master_file_table_record {
+       __u32   magic;
+       __u16   usa_ofs;
+       __u16   usa_count;
+       __u64   lsn;
+       __u16   sequence_number;
+       __u16   link_count;
+       __u16   attrs_offset;
+       __u16   flags;
+       __u32   bytes_in_use;
+       __u32   bytes_allocated;
+} __attribute__((__packed__));
+
+struct file_attribute {
+       __u32   type;
+       __u32   len;
+       __u8    non_resident;
+       __u8    name_len;
+       __u16   name_offset;
+       __u16   flags;
+       __u16   instance;
+       __u32   value_len;
+       __u16   value_offset;
+} __attribute__((__packed__));
+
+#define MFT_RECORD_VOLUME                      3
+#define MFT_RECORD_ATTR_VOLUME_NAME            0x60
+#define MFT_RECORD_ATTR_VOLUME_INFO            0x70
+#define MFT_RECORD_ATTR_OBJECT_ID              0x40
+#define MFT_RECORD_ATTR_END                    0xffffffffu
+
+/* HFS / HFS+ */
+struct hfs_finder_info {
+        __u32        boot_folder;
+        __u32        start_app;
+        __u32        open_folder;
+        __u32        os9_folder;
+        __u32        reserved;
+        __u32        osx_folder;
+        __u8         id[8];
+} __attribute__((packed));
+
+struct hfs_mdb {
+        __u8         signature[2];
+        __u32        cr_date;
+        __u32        ls_Mod;
+        __u16        atrb;
+        __u16        nm_fls;
+        __u16        vbm_st;
+        __u16        alloc_ptr;
+        __u16        nm_al_blks;
+        __u32        al_blk_size;
+        __u32        clp_size;
+        __u16        al_bl_st;
+        __u32        nxt_cnid;
+        __u16        free_bks;
+        __u8         label_len;
+        __u8         label[27];
+        __u32        vol_bkup;
+        __u16        vol_seq_num;
+        __u32        wr_cnt;
+        __u32        xt_clump_size;
+        __u32        ct_clump_size;
+        __u16        num_root_dirs;
+        __u32        file_count;
+        __u32        dir_count;
+        struct hfs_finder_info finder_info;
+        __u8         embed_sig[2];
+        __u16        embed_startblock;
+        __u16        embed_blockcount;
+} __attribute__((packed));
+
+
+#define HFS_NODE_LEAF                  0xff
+#define HFSPLUS_POR_CNID               1
+
+struct hfsplus_bnode_descriptor {
+       __u32           next;
+       __u32           prev;
+       __u8            type;
+       __u8            height;
+       __u16           num_recs;
+       __u16           reserved;
+} __attribute__((packed));
+
+struct hfsplus_bheader_record {
+       __u16           depth;
+       __u32           root;
+       __u32           leaf_count;
+       __u32           leaf_head;
+       __u32           leaf_tail;
+       __u16           node_size;
+} __attribute__((packed));
+
+struct hfsplus_catalog_key {
+       __u16   key_len;
+       __u32   parent_id;
+       __u16   unicode_len;
+       __u8            unicode[255 * 2];
+} __attribute__((packed));
+
+struct hfsplus_extent {
+       __u32           start_block;
+       __u32           block_count;
+} __attribute__((packed));
+
+#define HFSPLUS_EXTENT_COUNT           8
+struct hfsplus_fork {
+       __u64           total_size;
+       __u32           clump_size;
+       __u32           total_blocks;
+       struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+} __attribute__((packed));
+
+struct hfsplus_vol_header {
+       __u8            signature[2];
+       __u16           version;
+       __u32           attributes;
+       __u32           last_mount_vers;
+       __u32           reserved;
+       __u32           create_date;
+       __u32           modify_date;
+       __u32           backup_date;
+       __u32           checked_date;
+       __u32           file_count;
+       __u32           folder_count;
+       __u32           blocksize;
+       __u32           total_blocks;
+       __u32           free_blocks;
+       __u32           next_alloc;
+       __u32           rsrc_clump_sz;
+       __u32           data_clump_sz;
+       __u32           next_cnid;
+       __u32           write_count;
+       __u64           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));
+
+
+/* this is lvm's label_header & pv_header combined. */
+
+#define LVM2_ID_LEN 32
+
+struct lvm2_pv_label_header {
+       /* label_header */
+       __u8    id[8];          /* LABELONE */
+       __u64   sector_xl;      /* Sector number of this label */
+       __u32   crc_xl;         /* From next field to end of sector */
+       __u32   offset_xl;      /* Offset from start of struct to contents */
+       __u8    type[8];        /* LVM2 001 */
+       /* pv_header */
+       __u8    pv_uuid[LVM2_ID_LEN];
+} __attribute__ ((packed));
+
+/*
+ * Byte swap functions
+ */
+#ifdef __GNUC__
+#define _INLINE_ static __inline__
+#else                          /* For Watcom C */
+#define _INLINE_ static inline
+#endif
+
+static __u16 blkid_swab16(__u16 val);
+static __u32 blkid_swab32(__u32 val);
+static __u64 blkid_swab64(__u64 val);
+
+#if ((defined __GNUC__) && \
+     (defined(__i386__) || defined(__i486__) || defined(__i586__)))
+
+#define _BLKID_HAVE_ASM_BITOPS_
+
+_INLINE_ __u32 blkid_swab32(__u32 val)
+{
+#ifdef EXT2FS_REQUIRE_486
+       __asm__("bswap %0" : "=r" (val) : "0" (val));
+#else
+       __asm__("xchgb %b0,%h0\n\t"     /* swap lower bytes     */
+               "rorl $16,%0\n\t"       /* swap words           */
+               "xchgb %b0,%h0"         /* swap higher bytes    */
+               :"=q" (val)
+               : "0" (val));
+#endif
+       return val;
+}
+
+_INLINE_ __u16 blkid_swab16(__u16 val)
+{
+       __asm__("xchgb %b0,%h0"         /* swap bytes           */ \
+               : "=q" (val) \
+               :  "0" (val)); \
+               return val;
+}
+
+_INLINE_ __u64 blkid_swab64(__u64 val)
+{
+       return (blkid_swab32(val >> 32) |
+               (((__u64) blkid_swab32(val & 0xFFFFFFFFUL)) << 32));
+}
+#endif
+
+#if !defined(_BLKID_HAVE_ASM_BITOPS_)
+
+_INLINE_  __u16 blkid_swab16(__u16 val)
+{
+       return (val >> 8) | (val << 8);
+}
+
+_INLINE_ __u32 blkid_swab32(__u32 val)
+{
+       return ((val>>24) | ((val>>8)&0xFF00) |
+               ((val<<8)&0xFF0000) | (val<<24));
+}
+
+_INLINE_ __u64 blkid_swab64(__u64 val)
+{
+       return (blkid_swab32(val >> 32) |
+               (((__u64) blkid_swab32(val & 0xFFFFFFFFUL)) << 32));
+}
+#endif
+
+
+
+#ifdef WORDS_BIGENDIAN
+#define blkid_le16(x) blkid_swab16(x)
+#define blkid_le32(x) blkid_swab32(x)
+#define blkid_le64(x) blkid_swab64(x)
+#define blkid_be16(x) (x)
+#define blkid_be32(x) (x)
+#define blkid_be64(x) (x)
+#else
+#define blkid_le16(x) (x)
+#define blkid_le32(x) (x)
+#define blkid_le64(x) (x)
+#define blkid_be16(x) blkid_swab16(x)
+#define blkid_be32(x) blkid_swab32(x)
+#define blkid_be64(x) blkid_swab64(x)
+#endif
+
+#undef _INLINE_
+
+#endif /* _BLKID_PROBE_H */
diff --git a/libs/blkid/src/read.c b/libs/blkid/src/read.c
new file mode 100644 (file)
index 0000000..ca2798f
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * 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%
+ */
+
+#define _XOPEN_SOURCE 600 /* for inclusion of strtoull */
+
+#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>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "blkidP.h"
+#include "uuid/uuid.h"
+
+#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
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#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="time">   (ascii time_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(DEBUG_READ, printf("found device header: %8s\n", 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(DEBUG_READ, printf("found device trailer %9s\n", *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(DEBUG_READ,
+                   printf("blkid: short line parsing dev: %s\n", *cp));
+               return -BLKID_ERR_CACHE;
+       }
+       start = skip_over_blank(start + 1);
+       end = skip_over_word(start);
+
+       DBG(DEBUG_READ, printf("device should be %*s\n",
+                              (int)(end - start), start));
+
+       if (**cp == '>')
+               *cp = end;
+       else
+               (*cp)++;
+
+       *tmp = '\0';
+
+       if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) {
+               DBG(DEBUG_READ,
+                   printf("blkid: missing </device> ending: %s\n", end));
+       } else if (tmp)
+               *tmp = '\0';
+
+       if (end - start <= 1) {
+               DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp));
+               return -BLKID_ERR_CACHE;
+       }
+
+       name = blkid_strndup(start, end-start);
+       if (name == NULL)
+               return -BLKID_ERR_MEM;
+
+       DBG(DEBUG_READ, printf("found dev %s\n", 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 == '"') {
+               end = strchr(*value + 1, '"');
+               if (!end) {
+                       DBG(DEBUG_READ,
+                           printf("unbalanced quotes at: %s\n", *value));
+                       *cp = *value;
+                       return -BLKID_ERR_CACHE;
+               }
+               (*value)++;
+               *end = '\0';
+               end++;
+       } 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;
+       char *value;
+       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"))
+               dev->bid_time = STRTOULL(value, 0, 0);
+       else
+               ret = blkid_set_tag(dev, name, value, strlen(value));
+
+       DBG(DEBUG_READ, printf("    tag: %s=\"%s\"\n", 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(DEBUG_READ, printf("line: %s\n", 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(DEBUG_READ,
+                   printf("blkid: device %s has no TYPE\n",dev->bid_name));
+               blkid_free_dev(dev);
+       }
+
+       DBG(DEBUG_READ, blkid_debug_dump_dev(dev));
+
+       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)) < 0)
+               return;
+       if (fstat(fd, &st) < 0)
+               goto errout;
+       if ((st.st_mtime == cache->bic_ftime) ||
+           (cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
+               DBG(DEBUG_CACHE, printf("skipping re-read of %s\n",
+                                       cache->bic_filename));
+               goto errout;
+       }
+
+       DBG(DEBUG_CACHE, printf("reading cache file %s\n",
+                               cache->bic_filename));
+
+       file = fdopen(fd, "r");
+       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 (buf[end] == '\\' && end < sizeof(buf) - 2 &&
+                      fgets(buf + end, sizeof(buf) - end, file)) {
+                       end = strlen(buf) - 1;
+                       lineno++;
+               }
+
+               if (blkid_parse_line(cache, &dev, buf) < 0) {
+                       DBG(DEBUG_READ,
+                           printf("blkid: bad format on line %d\n", 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=\"%lld\"\n", (long long)dev->bid_time);
+       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_debug_mask = 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_CACHE_FILE);
+
+       blkid_put_cache(cache);
+
+       return ret;
+}
+#endif
diff --git a/libs/blkid/src/resolve.c b/libs/blkid/src/resolve.c
new file mode 100644 (file)
index 0000000..678f34e
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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>
+#if 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(DEBUG_RESOLVE, printf("looking for %s on %s\n", tagname, devname));
+
+       if (!devname)
+               return NULL;
+
+       if (!cache) {
+               if (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 = blkid_strdup(found->bit_val);
+
+       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) {
+               if (blkid_get_cache(&c, NULL) < 0)
+                       return NULL;
+       }
+
+       DBG(DEBUG_RESOLVE,
+           printf("looking for %s%s%s %s\n", token, value ? "=" : "",
+                  value ? value : "", cache ? "in cache" : "from disk"));
+
+       if (!value) {
+               if (!strchr(token, '=')) {
+                       ret = blkid_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 = blkid_strdup(blkid_dev_devname(dev));
+
+out:
+       if (t)
+               free(t);
+       if (v)
+               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_debug_mask = 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/libs/blkid/src/save.c b/libs/blkid/src/save.c
new file mode 100644 (file)
index 0000000..656bb0b
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include "blkidP.h"
+
+static int save_dev(blkid_dev dev, FILE *file)
+{
+       struct list_head *p;
+
+       if (!dev || dev->bid_name[0] != '/')
+               return 0;
+
+       DBG(DEBUG_SAVE,
+           printf("device %s, type %s\n", dev->bid_name, dev->bid_type ?
+                  dev->bid_type : "(null)"));
+
+       fprintf(file,
+               "<device DEVNO=\"0x%04lx\" TIME=\"%ld\"",
+               (unsigned long) dev->bid_devno, (long) dev->bid_time);
+       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);
+               fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val);
+       }
+       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;
+       const char *opened = NULL;
+       const 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(DEBUG_SAVE, printf("skipping cache file write\n"));
+               return 0;
+       }
+
+       filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE;
+
+       /* 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(DEBUG_SAVE,
+                   printf("can't write to cache file %s\n", 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) {
+                               file = fdopen(fd, "w");
+                               opened = tmp;
+                       }
+                       fchmod(fd, 0644);
+               }
+       }
+
+       if (!file) {
+               file = fopen(filename, "w");
+               opened = filename;
+       }
+
+       DBG(DEBUG_SAVE,
+           printf("writing cache file %s (really %s)\n",
+                  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)
+                       continue;
+               if ((ret = save_dev(dev, file)) < 0)
+                       break;
+       }
+
+       if (ret >= 0) {
+               cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
+               ret = 1;
+       }
+
+       fclose(file);
+       if (opened != filename) {
+               if (ret < 0) {
+                       unlink(opened);
+                       DBG(DEBUG_SAVE,
+                           printf("unlinked temp cache %s\n", opened));
+               } else {
+                       char *backup;
+
+                       backup = malloc(strlen(filename) + 5);
+                       if (backup) {
+                               sprintf(backup, "%s.old", filename);
+                               unlink(backup);
+                               link(filename, backup);
+                               free(backup);
+                       }
+                       rename(opened, filename);
+                       DBG(DEBUG_SAVE,
+                           printf("moved temp cache %s\n", opened));
+               }
+       }
+
+errout:
+       if (tmp)
+               free(tmp);
+       return ret;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+       blkid_cache cache = NULL;
+       int ret;
+
+       blkid_debug_mask = 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 = blkid_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/libs/blkid/src/tag.c b/libs/blkid/src/tag.c
new file mode 100644 (file)
index 0000000..b305ab4
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * 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;
+}
+
+#ifdef CONFIG_BLKID_DEBUG
+void blkid_debug_dump_tag(blkid_tag tag)
+{
+       if (!tag) {
+               printf("    tag: NULL\n");
+               return;
+       }
+
+       printf("    tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
+}
+#endif
+
+void blkid_free_tag(blkid_tag tag)
+{
+       if (!tag)
+               return;
+
+       DBG(DEBUG_TAG, printf("    freeing tag %s=%s\n", tag->bit_name,
+                  tag->bit_val ? tag->bit_val : "(NULL)"));
+       DBG(DEBUG_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 */
+
+       if (tag->bit_name)
+               free(tag->bit_name);
+       if (tag->bit_val)
+               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;
+}
+
+extern int blkid_dev_has_tag(blkid_dev dev, const char *type,
+                            const char *value)
+{
+       blkid_tag               tag;
+
+       if (!dev || !type)
+               return -1;
+
+       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(DEBUG_TAG,
+                           printf("    found cache tag head %s\n", 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 (!(val = blkid_strndup(value, vlength)) && value)
+               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 = blkid_strdup(name);
+               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(DEBUG_TAG,
+                                   printf("    creating new cache tag head %s\n", name));
+                               head->bit_name = blkid_strdup(name);
+                               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 if (val)
+               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(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token));
+
+       if (!token || !(cp = strchr(token, '=')))
+               return -1;
+
+       name = blkid_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';
+       }
+       value = blkid_strdup(value);
+       if (!value)
+               goto errout;
+
+       *ret_type = name;
+       *ret_val = value;
+
+       return 0;
+
+errout:
+       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;
+};
+
+extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
+{
+       blkid_tag_iterate       iter;
+
+       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
+ */
+extern int blkid_tag_next(blkid_tag_iterate iter,
+                         const char **type, const char **value)
+{
+       blkid_tag tag;
+
+       *type = 0;
+       *value = 0;
+       if (!iter || iter->magic != TAG_ITERATE_MAGIC ||
+           iter->p == &iter->dev->bid_tags)
+               return -1;
+       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;
+}
+
+extern 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.
+ */
+extern 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(DEBUG_TAG, printf("looking for %s=%s in cache\n", 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 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':
+                       blkid_debug_mask = strtoul (optarg, &tmp, 0);
+                       if (*tmp) {
+                               fprintf(stderr, "Invalid debug mask: %s\n",
+                                       optarg);
+                               exit(1);
+                       }
+                       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/libs/blkid/src/tst_types.c b/libs/blkid/src/tst_types.c
new file mode 100644 (file)
index 0000000..3003c8b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * This testing program makes sure the blkid_types header file
+ *
+ * Copyright (C) 2006 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <sys/types.h>
+#include "blkid/blkid_types.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+       if (sizeof(__u8) != 1) {
+               printf("Sizeof(__u8) is %d should be 1\n",
+                      (int)sizeof(__u8));
+               exit(1);
+       }
+       if (sizeof(__s8) != 1) {
+               printf("Sizeof(_s8) is %d should be 1\n",
+                      (int)sizeof(__s8));
+               exit(1);
+       }
+       if (sizeof(__u16) != 2) {
+               printf("Sizeof(__u16) is %d should be 2\n",
+                      (int)sizeof(__u16));
+               exit(1);
+       }
+       if (sizeof(__s16) != 2) {
+               printf("Sizeof(__s16) is %d should be 2\n",
+                      (int)sizeof(__s16));
+               exit(1);
+       }
+       if (sizeof(__u32) != 4) {
+               printf("Sizeof(__u32) is %d should be 4\n",
+                      (int)sizeof(__u32));
+               exit(1);
+       }
+       if (sizeof(__s32) != 4) {
+               printf("Sizeof(__s32) is %d should be 4\n",
+                      (int)sizeof(__s32));
+               exit(1);
+       }
+       if (sizeof(__u64) != 8) {
+               printf("Sizeof(__u64) is %d should be 8\n",
+                      (int)sizeof(__u64));
+               exit(1);
+       }
+       if (sizeof(__s64) != 8) {
+               printf("Sizeof(__s64) is %d should be 8\n",
+                      (int)sizeof(__s64));
+               exit(1);
+       }
+       printf("The blkid_types.h types are correct.\n");
+       exit(0);
+}
+
diff --git a/libs/blkid/src/version.c b/libs/blkid/src/version.c
new file mode 100644 (file)
index 0000000..5d75e8f
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 Public
+ * License.
+ * %End-Header%
+ */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "blkid.h"
+
+static const char *lib_version = BLKID_VERSION;
+static const char *lib_date = BLKID_DATE;
+
+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;
+}
+
+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);
+}