From a0948ffe403658f567a9267f50a26a694fe417da Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 27 Aug 2008 15:09:47 +0200 Subject: [PATCH] blkid: merge libblkid code from e2fsprogs/lib/blkid Signed-off-by: Karel Zak --- configure.ac | 65 +- libs/blkid/Makefile.am | 7 +- libs/blkid/blkid.pc.in | 2 +- libs/blkid/libblkid.3.in | 80 ++ libs/blkid/src/Makefile.am | 52 + libs/blkid/src/blkid.h | 107 +++ libs/blkid/src/blkid.sym | 29 + libs/blkid/src/blkidP.h | 182 ++++ libs/blkid/src/blkid_types.h.in | 134 +++ libs/blkid/src/cache.c | 209 ++++ libs/blkid/src/dev.c | 257 +++++ libs/blkid/src/devname.c | 643 +++++++++++++ libs/blkid/src/devno.c | 234 +++++ libs/blkid/src/getsize.c | 207 ++++ libs/blkid/src/list.h | 179 ++++ libs/blkid/src/llseek.c | 142 +++ libs/blkid/src/probe.c | 1581 +++++++++++++++++++++++++++++++ libs/blkid/src/probe.h | 711 ++++++++++++++ libs/blkid/src/read.c | 493 ++++++++++ libs/blkid/src/resolve.c | 141 +++ libs/blkid/src/save.c | 194 ++++ libs/blkid/src/tag.c | 473 +++++++++ libs/blkid/src/tst_types.c | 63 ++ libs/blkid/src/version.c | 48 + 24 files changed, 6220 insertions(+), 13 deletions(-) create mode 100644 libs/blkid/libblkid.3.in create mode 100644 libs/blkid/src/Makefile.am create mode 100644 libs/blkid/src/blkid.h create mode 100644 libs/blkid/src/blkid.sym create mode 100644 libs/blkid/src/blkidP.h create mode 100644 libs/blkid/src/blkid_types.h.in create mode 100644 libs/blkid/src/cache.c create mode 100644 libs/blkid/src/dev.c create mode 100644 libs/blkid/src/devname.c create mode 100644 libs/blkid/src/devno.c create mode 100644 libs/blkid/src/getsize.c create mode 100644 libs/blkid/src/list.h create mode 100644 libs/blkid/src/llseek.c create mode 100644 libs/blkid/src/probe.c create mode 100644 libs/blkid/src/probe.h create mode 100644 libs/blkid/src/read.c create mode 100644 libs/blkid/src/resolve.c create mode 100644 libs/blkid/src/save.c create mode 100644 libs/blkid/src/tag.c create mode 100644 libs/blkid/src/tst_types.c create mode 100644 libs/blkid/src/version.c diff --git a/configure.ac b/configure.ac index aa145cfc..490e84f3 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/libs/blkid/Makefile.am b/libs/blkid/Makefile.am index 28558d43..05ab8daa 100644 --- a/libs/blkid/Makefile.am +++ b/libs/blkid/Makefile.am @@ -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 + diff --git a/libs/blkid/blkid.pc.in b/libs/blkid/blkid.pc.in index 5195539e..db03cc13 100644 --- a/libs/blkid/blkid.pc.in +++ b/libs/blkid/blkid.pc.in @@ -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 index 00000000..bd24cb1a --- /dev/null +++ b/libs/blkid/libblkid.3.in @@ -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 +.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 index 00000000..d5396d44 --- /dev/null +++ b/libs/blkid/src/Makefile.am @@ -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 index 00000000..4582879b --- /dev/null +++ b/libs/blkid/src/blkid.h @@ -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 +#include + +#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 index 00000000..3687ae0b --- /dev/null +++ b/libs/blkid/src/blkid.sym @@ -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 index 00000000..7ac2b82f --- /dev/null +++ b/libs/blkid/src/blkidP.h @@ -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 +#include + +#include +#include + +#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 +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 index 00000000..4efffba3 --- /dev/null +++ b/libs/blkid/src/blkid_types.h.in @@ -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 index 00000000..7c95726d --- /dev/null +++ b/libs/blkid/src/cache.c @@ -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 +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_PRCTL_H +#include +#else +#define PR_GET_DUMPABLE 3 +#endif +#if (!defined(HAVE_PRCTL) && defined(linux)) +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#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 index 00000000..fb8d8527 --- /dev/null +++ b/libs/blkid/src/dev.c @@ -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 +#include + +#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 +#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 index 00000000..106c743c --- /dev/null +++ b/libs/blkid/src/devname.c @@ -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 +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_SYS_MKDEV_H +#include +#endif +#include + +#include "blkidP.h" + +#ifdef HAVE_DEVMAPPER +#include +#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 +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 index 00000000..259ec93c --- /dev/null +++ b/libs/blkid/src/devno.c @@ -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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#include +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_SYS_MKDEV_H +#include +#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 index 00000000..10ba7ecf --- /dev/null +++ b/libs/blkid/src/getsize.c @@ -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 +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_LINUX_FD_H +#include +#endif +#ifdef HAVE_SYS_DISKLABEL_H +#include +#endif +#ifdef HAVE_SYS_DISK_H +#ifdef HAVE_SYS_QUEUE_H +#include /* for LIST_HEAD */ +#endif +#include +#endif +#ifdef __linux__ +#include +#endif +#if HAVE_SYS_STAT_H +#include +#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 index 00000000..c1cbfec5 --- /dev/null +++ b/libs/blkid/src/list.h @@ -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 index 00000000..5bd0e516 --- /dev/null +++ b/libs/blkid/src/llseek.c @@ -0,0 +1,142 @@ +/* + * llseek.c -- stub calling the llseek system call + * + * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE + +#if HAVE_SYS_TYPES_H +#include +#endif + +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#ifdef __MSDOS__ +#include +#endif + +#include "blkidP.h" + +#ifdef __linux__ + +#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) + +#define my_llseek lseek64 + +#elif defined(HAVE_LLSEEK) +#include + +#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 + +#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 index 00000000..ec721538 --- /dev/null +++ b/libs/blkid/src/probe.c @@ -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 + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif +#include +#ifdef HAVE_ERRNO_H +#include +#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 ] + */ +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 index 00000000..bee5a518 --- /dev/null +++ b/libs/blkid/src/probe.h @@ -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 + +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 index 00000000..ca2798f0 --- /dev/null +++ b/libs/blkid/src/read.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#if HAVE_ERRNO_H +#include +#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 +#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 + * + * The following tags are required for each entry: + * unique (within this file) ID number of this device + * (ascii time_t) time this entry was last read from disk + * (detected) type of filesystem/data for this partition + * + * The following tags may be present, depending on the device contents + * (user supplied) label (volume name, etc) + * (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 " continue parsing line + * line starts with " 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, "", 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: + * devname + * devnamebar + */ +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 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 value 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 /dev/foo + * + * 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 index 00000000..678f34e7 --- /dev/null +++ b/libs/blkid/src/resolve.c @@ -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 +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include +#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 : ""); + } else { + value = blkid_get_devname(cache, argv[1], NULL); + printf("%s has tag %s\n", value ? value : "", 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 index 00000000..656bb0bb --- /dev/null +++ b/libs/blkid/src/save.c @@ -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 +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_MKDEV_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#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, + "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\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 index 00000000..b305ab48 --- /dev/null +++ b/libs/blkid/src/tag.c @@ -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 +#include +#include +#include + +#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 +#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 index 00000000..3003c8b5 --- /dev/null +++ b/libs/blkid/src/tst_types.c @@ -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 +#include "blkid/blkid_types.h" + +#include +#include + +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 index 00000000..5d75e8f6 --- /dev/null +++ b/libs/blkid/src/version.c @@ -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 +#endif +#include +#include +#include + +#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); +} -- 2.39.5