diff options
Diffstat (limited to 'shlibs/blkid/src')
60 files changed, 10476 insertions, 0 deletions
diff --git a/shlibs/blkid/src/Makefile.am b/shlibs/blkid/src/Makefile.am new file mode 100644 index 00000000..bd040ce9 --- /dev/null +++ b/shlibs/blkid/src/Makefile.am @@ -0,0 +1,65 @@ +include $(top_srcdir)/config/include-Makefile.am + +SUBDIRS = probers . + +common_ldadd = +common_cflags = + +if HAVE_UUID +if BUILD_LIBUUID +common_ldadd += $(ul_libuuid_la) +common_cflags += -I$(ul_libuuid_srcdir) +else +common_ldadd += $(UUID_LIBS) +common_cflags += $(UUID_CFLAGS) +endif +endif + +AM_CPPFLAGS += -I$(ul_libblkid_srcdir) $(common_cflags) + +# includes +blkidincdir = $(includedir)/blkid +blkidinc_HEADERS = blkid.h + +usrlib_exec_LTLIBRARIES = libblkid.la +libblkid_la_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 verify.c \ + encode.c blkid.h list.h blkidP.h probers/probers.h \ + config.c evaluate.c \ + $(blkidinc_HEADERS) \ + $(top_srcdir)/lib/blkdev.c \ + $(top_srcdir)/lib/linux_version.c \ + $(top_srcdir)/lib/canonicalize.c \ + $(top_srcdir)/lib/md5.c + +libblkid_la_LIBADD = probers/libblkid_probers.la $(common_ldadd) +libblkid_la_DEPENDENCIES = $(libblkid_la_LIBADD) blkid.sym + +libblkid_la_LDFLAGS = -Wl,--version-script=$(ul_libblkid_srcdir)/blkid.sym \ + -version-info $(LIBBLKID_VERSION_INFO) + +tests = test_cache test_config test_dev test_devname test_devno test_getsize \ + test_read test_resolve test_save test_tag test_verify test_evaluate + +EXTRA_DIST = blkid.sym tst_types.c +CLEANFILES = $(tests) + +tests: all $(tests) +test_%: %.c + $(COMPILE) -DTEST_PROGRAM $< .libs/libblkid.a -o $@ $(UUID_LIBS) + + +# move lib from $(usrlib_execdir) to $(libdir) if needed +install-exec-hook: + if test "$(usrlib_execdir)" != "$(libdir)"; then \ + mkdir -p $(DESTDIR)$(libdir); \ + mv $(DESTDIR)$(usrlib_execdir)/libblkid.so.* $(DESTDIR)$(libdir); \ + so_img_name=$$(readlink $(DESTDIR)$(usrlib_execdir)/libblkid.so); \ + so_img_rel_target=$$(echo $(usrlib_execdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \ + (cd $(DESTDIR)$(usrlib_execdir) && \ + rm -f libblkid.so && \ + $(LN_S) $$so_img_rel_target$(libdir)/$$so_img_name libblkid.so); \ + fi + +uninstall-hook: + rm -f $(DESTDIR)$(libdir)/libblkid.so* diff --git a/shlibs/blkid/src/blkid.h b/shlibs/blkid/src/blkid.h new file mode 100644 index 00000000..43b2b552 --- /dev/null +++ b/shlibs/blkid/src/blkid.h @@ -0,0 +1,171 @@ +/* + * blkid.h - Interface for libblkid, a library to identify block devices + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _BLKID_BLKID_H +#define _BLKID_BLKID_H + +#include <stdint.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct blkid_struct_dev *blkid_dev; +typedef struct blkid_struct_cache *blkid_cache; +typedef struct blkid_struct_probe *blkid_probe; + +typedef int64_t 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); + +/* verify.c */ +extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev); + +/* read.c */ + +/* resolve.c */ +extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname, + const char *devname); +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); + +/* encode.c */ +extern int blkid_encode_string(const char *str, char *str_enc, size_t len); +extern int blkid_safe_string(const char *str, char *str_safe, size_t len); + +/* evaluate.c */ +extern int blkid_send_uevent(const char *devname, const char *action); +extern char *blkid_evaluate_tag(const char *token, const char *value, + blkid_cache *cache); + +/* probe.c */ +extern int blkid_known_fstype(const char *fstype); +extern blkid_probe blkid_new_probe(void); +extern void blkid_free_probe(blkid_probe pr); +extern void blkid_reset_probe(blkid_probe pr); + +extern int blkid_probe_set_device(blkid_probe pr, int fd, + blkid_loff_t off, blkid_loff_t size); + +#define BLKID_PROBREQ_LABEL (1 << 1) +#define BLKID_PROBREQ_LABELRAW (1 << 2) +#define BLKID_PROBREQ_UUID (1 << 3) +#define BLKID_PROBREQ_UUIDRAW (1 << 4) +#define BLKID_PROBREQ_TYPE (1 << 5) +#define BLKID_PROBREQ_SECTYPE (1 << 6) +#define BLKID_PROBREQ_USAGE (1 << 7) +#define BLKID_PROBREQ_VERSION (1 << 8) +extern int blkid_probe_set_request(blkid_probe pr, int flags); + +#define BLKID_USAGE_FILESYSTEM (1 << 1) +#define BLKID_USAGE_RAID (1 << 2) +#define BLKID_USAGE_CRYPTO (1 << 3) +#define BLKID_USAGE_OTHER (1 << 4) +extern int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage); + +#define BLKID_FLTR_NOTIN 1 +#define BLKID_FLTR_ONLYIN 2 +extern int blkid_probe_filter_types(blkid_probe pr, + int flag, char *names[]); + + +extern int blkid_probe_invert_filter(blkid_probe pr); +extern int blkid_probe_reset_filter(blkid_probe pr); + +extern int blkid_do_probe(blkid_probe pr); +extern int blkid_do_safeprobe(blkid_probe pr); + +extern int blkid_probe_numof_values(blkid_probe pr); +extern int blkid_probe_get_value(blkid_probe pr, int num, const char **name, + const char **data, size_t *len); +extern int blkid_probe_lookup_value(blkid_probe pr, const char *name, + const char **data, size_t *len); +extern int blkid_probe_has_value(blkid_probe pr, const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* _BLKID_BLKID_H */ diff --git a/shlibs/blkid/src/blkid.sym b/shlibs/blkid/src/blkid.sym new file mode 100644 index 00000000..562f44d0 --- /dev/null +++ b/shlibs/blkid/src/blkid.sym @@ -0,0 +1,68 @@ +/* + * The symbol versioning ensures that a new application requiring symbol foo() + * can't run with old libblkid.so not providing foo() - the global SONAME + * version info can't enforce this since we never change the SONAME. + * + * The original libblkid from e2fsprogs (<=1.41.4) does not to use + * symbol versioning -- all the original symbols are in BLKID_1.0 now. + */ +BLKID_1.0 { +global: + blkid_dev_devname; + blkid_dev_has_tag; + blkid_dev_iterate_begin; + blkid_dev_iterate_end; + blkid_dev_next; + blkid_devno_to_devname; + blkid_dev_set_search; + blkid_find_dev_with_tag; + blkid_gc_cache; + blkid_get_cache; + blkid_get_dev; + blkid_get_devname; + blkid_get_dev_size; + blkid_get_library_version; + blkid_get_tag_value; + blkid_known_fstype; + blkid_parse_tag_string; + blkid_parse_version_string; + blkid_probe_all; + blkid_probe_all_new; + blkid_put_cache; + blkid_tag_iterate_begin; + blkid_tag_iterate_end; + blkid_tag_next; + blkid_verify; +local: + *; +}; + + +/* + * version(s) since util-linux-ng 2.15 + */ +BLKID_2.15 { +global: + blkid_do_probe; + blkid_do_safeprobe; + blkid_encode_string; + blkid_evaluate_tag; + blkid_free_probe; + blkid_new_probe; + blkid_probe_all; + blkid_probe_all_new; + blkid_probe_filter_types; + blkid_probe_filter_usage; + blkid_probe_get_value; + blkid_probe_has_value; + blkid_probe_invert_filter; + blkid_probe_lookup_value; + blkid_probe_numof_values; + blkid_probe_reset_filter; + blkid_probe_set_device; + blkid_probe_set_request; + blkid_reset_probe; + blkid_safe_string; + blkid_send_uevent; +} BLKID_1.0; + diff --git a/shlibs/blkid/src/blkidP.h b/shlibs/blkid/src/blkidP.h new file mode 100644 index 00000000..67e7f53a --- /dev/null +++ b/shlibs/blkid/src/blkidP.h @@ -0,0 +1,344 @@ +/* + * 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 + + +#define CONFIG_BLKID_DEBUG 1 + +#include <sys/types.h> +#include <stdio.h> +#include <stdarg.h> + +#include "bitops.h" /* $(top_srcdir)/include/ */ +#include "blkid.h" +#include "list.h" + +#ifdef __GNUC__ +#define __BLKID_ATTR(x) __attribute__(x) +#else +#define __BLKID_ATTR(x) +#endif + +#ifndef TRUE +#define TRUE 1 +#define FALSE 1 +#endif + +#include <limits.h> +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + +/* TODO: move to some top-level util-linux include file */ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#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; + +/* + * Low-level probe result + */ +#define BLKID_PROBVAL_BUFSIZ 64 +#define BLKID_PROBVAL_NVALS 8 /* see blkid.h BLKID_PROBREQ_* */ + +struct blkid_prval +{ + const char *name; /* value name */ + unsigned char data[BLKID_PROBVAL_BUFSIZ]; /* value data */ + size_t len; /* length of value data */ +}; + +/* + * Low-level probing control struct + */ +struct blkid_struct_probe +{ + int fd; /* device file descriptor */ + blkid_loff_t off; /* begin of data on the device */ + blkid_loff_t size; /* end of data on the device */ + + unsigned char *sbbuf; /* superblok buffer */ + size_t sbbuf_len; /* size of data in superblock buffer */ + + unsigned char *buf; /* seek buffer */ + blkid_loff_t buf_off; /* offset of seek buffer */ + size_t buf_len; /* size of data in seek buffer */ + size_t buf_max; /* allocated size of seek buffer */ + + struct blkid_prval vals[BLKID_PROBVAL_NVALS]; + int nvals; + + int probreq; /* BLKID_PROBREQ_* flags */ + int idx; /* index of the last prober */ + + unsigned long *fltr; /* filter */ +}; + +#define BLKID_SB_BUFSIZ 0x11000 + +/* + * Filesystem / Raid magic strings + */ +struct blkid_idmag +{ + const char *magic; /* magic string */ + unsigned len; /* length of magic */ + + long kboff; /* kilobyte offset of superblock */ + unsigned sboff; /* byte offset within superblock */ +}; + +/* + * Filesystem / Raid description + */ +struct blkid_idinfo +{ + const char *name; /* FS/RAID name */ + int usage; /* BLKID_USAGE_* flag */ + int flags; /* BLKID_IDINFO_* flags */ + + /* probe function */ + int (*probefunc)(blkid_probe pr, const struct blkid_idmag *mag); + + struct blkid_idmag magics[]; /* NULL or array with magic strings */ +}; + +#define BLKID_NONE_MAGIC {{ NULL }} + +/* + * tolerant FS - can share the same device with more filesystems (e.g. typical + * on CD-ROMs). We need this flag to detect ambivalent results (e.g. valid fat + * and valid linux swap on the same device). + */ +#define BLKID_IDINFO_TOLERANT (1 << 1) + +/* + * Evaluation methods (for blkid_eval_* API) + */ +enum { + BLKID_EVAL_UDEV = 0, + BLKID_EVAL_SCAN, + + __BLKID_EVAL_LAST +}; + +/* + * Library config options + */ +struct blkid_config { + int eval[__BLKID_EVAL_LAST]; /* array with EVALUATION=<udev,cache> options */ + int nevals; /* number of elems in eval array */ + int uevent; /* SEND_UEVENT=<yes|not> option */ + char *cachefile; /* CACHE_FILE=<path> option */ +}; + +extern struct blkid_config *blkid_read_config(const char *filename); +extern void blkid_free_config(struct blkid_config *conf); + +/* + * Minimum number of seconds between device probes, even when reading + * from the cache. This is to avoid re-probing all devices which were + * just probed by another program that does not share the cache. + */ +#define BLKID_PROBE_MIN 2 + +/* + * Time in seconds an entry remains verified in the in-memory cache + * before being reverified (in case of long-running processes that + * keep a cache in memory and continue to use it for a long time). + */ +#define BLKID_PROBE_INTERVAL 200 + +/* This describes an entire blkid cache file and probed devices. + * We can traverse all of the found devices via bic_list. + * We can traverse all of the tag types by bic_tags, which hold empty tags + * for each tag type. Those tags can be used as list_heads for iterating + * through all devices with a specific tag type (e.g. LABEL). + */ +struct blkid_struct_cache +{ + struct list_head bic_devs; /* List head of all devices */ + struct list_head bic_tags; /* List head of all tag types */ + time_t bic_time; /* Last probe time */ + time_t bic_ftime; /* Mod time of the cachefile */ + unsigned int bic_flags; /* Status flags of the cache */ + char *bic_filename; /* filename of cache */ + blkid_probe probe; /* low-level probing stuff */ +}; + +#define BLKID_BIC_FL_PROBED 0x0002 /* We probed /proc/partition devices */ +#define BLKID_BIC_FL_CHANGED 0x0004 /* Cache has changed from disk */ + +extern char *blkid_strdup(const char *s); +extern char *blkid_strndup(const char *s, const int length); + +#define BLKID_CACHE_FILE "/etc/blkid.tab" +#define BLKID_CONFIG_FILE "/etc/blkid.conf" + +#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_LOWPROBE 0x0400 +#define DEBUG_CONFIG 0x0800 +#define DEBUG_EVALUATE 0x1000 +#define DEBUG_INIT 0x8000 +#define DEBUG_ALL 0xFFFF + +#ifdef CONFIG_BLKID_DEBUG +#include <stdio.h> +extern int blkid_debug_mask; +extern void blkid_init_debug(int mask); +extern void blkid_debug_dump_dev(blkid_dev dev); +extern void blkid_debug_dump_tag(blkid_tag tag); + +#define DBG(m,x) if ((m) & blkid_debug_mask) x; + +#else /* !CONFIG_BLKID_DEBUG */ +#define DBG(m,x) +#define blkid_init_debug(x) +#endif /* CONFIG_BLKID_DEBUG */ + +/* devno.c */ +struct dir_list { + char *name; + struct dir_list *next; +}; +extern void blkid__scan_dir(char *, dev_t, struct dir_list **, char **); + +/* 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); + +/* cache */ +extern char *blkid_safe_getenv(const char *arg); +extern char *blkid_get_cache_filename(struct blkid_config *conf); + +/* + * 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); + +/* probe.c */ +unsigned char *blkid_probe_get_buffer(blkid_probe pr, + blkid_loff_t off, blkid_loff_t len); + +/* returns superblok according to 'struct blkid_idmag' */ +#define blkid_probe_get_sb(_pr, _mag, type) \ + ((type *) blkid_probe_get_buffer((_pr),\ + (_mag)->kboff << 10, sizeof(type))) + +extern int blkid_probe_set_value(blkid_probe pr, const char *name, + unsigned char *data, size_t len); +extern int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, + const char *fmt, va_list ap); +extern int blkid_probe_set_version(blkid_probe pr, const char *version); +extern int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +extern int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len); +extern int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label, + size_t len, int enc); +extern int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid, + size_t len, const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); +extern int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len); + +extern int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid); +extern int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name); + +#define BLKID_ENC_UTF16BE 0 +#define BLKID_ENC_UTF16LE 1 + +#endif /* _BLKID_BLKIDP_H */ diff --git a/shlibs/blkid/src/cache.c b/shlibs/blkid/src/cache.c new file mode 100644 index 00000000..01e4be06 --- /dev/null +++ b/shlibs/blkid/src/cache.c @@ -0,0 +1,243 @@ +/* + * cache.c - allocation/initialization/free routines for cache + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#else +#define PR_GET_DUMPABLE 3 +#endif +#if (!defined(HAVE_PRCTL) && defined(linux)) +#include <sys/syscall.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#include "blkidP.h" + +int blkid_debug_mask = 0; + + +char *blkid_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 + +#ifdef CONFIG_BLKID_DEBUG +void blkid_init_debug(int mask) +{ + if (blkid_debug_mask & DEBUG_INIT) + return; + + if (!mask) + { + char *dstr = getenv("BLKID_DEBUG"); + + if (dstr) + blkid_debug_mask = strtoul(dstr, 0, 0); + } else + blkid_debug_mask = mask; + + if (blkid_debug_mask) + printf("libblkid: debug mask set to 0x%04x.\n", blkid_debug_mask); + + blkid_debug_mask |= DEBUG_INIT; +} +#endif + +/* returns allocated path to cache */ +char *blkid_get_cache_filename(struct blkid_config *conf) +{ + char *filename; + + filename = blkid_safe_getenv("BLKID_FILE"); + if (filename) + filename = blkid_strdup(filename); + else if (conf) + filename = blkid_strdup(conf->cachefile); + else { + struct blkid_config *c = blkid_read_config(NULL); + if (!c) + filename = blkid_strdup(BLKID_CONFIG_FILE); + else { + filename = c->cachefile; /* already allocated */ + c->cachefile = NULL; + blkid_free_config(c); + } + } + return filename; +} + +int blkid_get_cache(blkid_cache *ret_cache, const char *filename) +{ + blkid_cache cache; + + blkid_init_debug(0); + + 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 && !*filename) + filename = NULL; + if (filename) + cache->bic_filename = blkid_strdup(filename); + else + cache->bic_filename = blkid_get_cache_filename(NULL); + + 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); + } + 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_init_debug(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/shlibs/blkid/src/config.c b/shlibs/blkid/src/config.c new file mode 100644 index 00000000..9091736b --- /dev/null +++ b/shlibs/blkid/src/config.c @@ -0,0 +1,205 @@ +/* + * config.c - blkid.conf routines + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_SYS_MKDEV_H +#include <sys/mkdev.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdint.h> +#include <stdarg.h> + +#include "blkdev.h" +#include "blkidP.h" + + +static int parse_evaluate(struct blkid_config *conf, char *s) +{ + while(s && *s) { + char *sep; + + if (conf->nevals >= __BLKID_EVAL_LAST) + goto err; + sep = strchr(s, ','); + if (sep) + *sep = '\0'; + if (strcmp(s, "udev") == 0) + conf->eval[conf->nevals] = BLKID_EVAL_UDEV; + else if (strcmp(s, "scan") == 0) + conf->eval[conf->nevals] = BLKID_EVAL_SCAN; + else + goto err; + conf->nevals++; + if (sep) + s = sep + 1; + else + break; + } + return 0; +err: + DBG(DEBUG_CONFIG, printf( + "config file: unknown evaluation method '%s'.\n", s)); + return -1; +} + +static int parse_next(FILE *fd, struct blkid_config *conf) +{ + char buf[BUFSIZ]; + char *s; + + /* read the next non-blank non-comment line */ + do { + if (fgets (buf, sizeof(buf), fd) == NULL) + return feof(fd) ? 0 : -1; + s = index (buf, '\n'); + if (!s) { + /* Missing final newline? Otherwise extremely */ + /* long line - assume file was corrupted */ + if (feof(fd)) + s = index (buf, '\0'); + else { + DBG(DEBUG_CONFIG, fprintf(stderr, + "libblkid: config file: missing newline at line '%s'.\n", + buf)); + return -1; + } + } + *s = '\0'; + if (--s >= buf && *s == '\r') + *s = '\0'; + + s = buf; + while (*s == ' ' || *s == '\t') /* skip space */ + s++; + + } while (*s == '\0' || *s == '#'); + + if (!strncmp(s, "SEND_UEVENT=", 12)) { + s += 13; + if (*s && !strcasecmp(s, "yes")) + conf->uevent = TRUE; + else if (*s) + conf->uevent = FALSE; + } else if (!strncmp(s, "CACHE_FILE=", 11)) { + s += 11; + if (*s) + conf->cachefile = blkid_strdup(s); + } else if (!strncmp(s, "EVALUATE=", 9)) { + s += 9; + if (*s && parse_evaluate(conf, s) == -1) + return -1; + } else { + DBG(DEBUG_CONFIG, printf( + "config file: unknown option '%s'.\n", s)); + return -1; + } + return 0; +} + +/* return real config data or built-in default */ +struct blkid_config *blkid_read_config(const char *filename) +{ + struct blkid_config *conf; + FILE *f; + + if (!filename) + filename = blkid_safe_getenv("BLKID_CONF"); + if (!filename) + filename = BLKID_CONFIG_FILE; + + conf = (struct blkid_config *) calloc(1, sizeof(*conf)); + if (!conf) + return NULL; + conf->uevent = -1; + + DBG(DEBUG_CONFIG, fprintf(stderr, + "reading config file: %s.\n", filename)); + + f = fopen(filename, "r"); + if (!f) { + DBG(DEBUG_CONFIG, fprintf(stderr, + "%s: does not exist, using built-in default\n", filename)); + goto dflt; + } + while (!feof(f)) { + if (parse_next(f, conf)) { + DBG(DEBUG_CONFIG, fprintf(stderr, + "%s: parse error\n", filename)); + goto err; + } + } +dflt: + if (!conf->nevals) { + conf->eval[0] = BLKID_EVAL_UDEV; + conf->eval[1] = BLKID_EVAL_SCAN; + conf->nevals = 2; + } + if (!conf->cachefile) + conf->cachefile = blkid_strdup(BLKID_CACHE_FILE); + if (conf->uevent == -1) + conf->uevent = TRUE; + if (f) + fclose(f); + return conf; +err: + free(conf); + fclose(f); + return NULL; +} + +void blkid_free_config(struct blkid_config *conf) +{ + if (!conf) + return; + free(conf->cachefile); + free(conf); +} + +#ifdef TEST_PROGRAM +/* + * usage: tst_config [<filename>] + */ +int main(int argc, char *argv[]) +{ + int i; + struct blkid_config *conf; + char *filename = NULL; + + blkid_init_debug(DEBUG_ALL); + + if (argc == 2) + filename = argv[1]; + + conf = blkid_read_config(filename); + if (!conf) + return EXIT_FAILURE; + + printf("EVALUATE: "); + for (i = 0; i < conf->nevals; i++) + printf("%s ", conf->eval[i] == BLKID_EVAL_UDEV ? "udev" : "scan"); + printf("\n"); + + printf("SEND UEVENT: %s\n", conf->uevent ? "TRUE" : "FALSE"); + printf("CACHE_FILE: %s\n", conf->cachefile); + + blkid_free_config(conf); + return EXIT_SUCCESS; +} +#endif diff --git a/shlibs/blkid/src/dev.c b/shlibs/blkid/src/dev.c new file mode 100644 index 00000000..31b9fe86 --- /dev/null +++ b/shlibs/blkid/src/dev.c @@ -0,0 +1,255 @@ +/* + * dev.c - allocation/initialization/free routines for dev + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <stdlib.h> +#include <string.h> + +#include "blkidP.h" + +blkid_dev blkid_new_dev(void) +{ + blkid_dev dev; + + if (!(dev = (blkid_dev) calloc(1, sizeof(struct blkid_struct_dev)))) + return NULL; + + INIT_LIST_HEAD(&dev->bid_devs); + INIT_LIST_HEAD(&dev->bid_tags); + + return dev; +} + +void blkid_free_dev(blkid_dev dev) +{ + if (!dev) + return; + + DBG(DEBUG_DEV, + printf(" freeing dev %s (%s)\n", dev->bid_name, dev->bid_type ? + dev->bid_type : "(null)")); + DBG(DEBUG_DEV, blkid_debug_dump_dev(dev)); + + list_del(&dev->bid_devs); + while (!list_empty(&dev->bid_tags)) { + blkid_tag tag = list_entry(dev->bid_tags.next, + struct blkid_struct_tag, + bit_tags); + blkid_free_tag(tag); + } + 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) { + free(new_type); + free(new_value); + return -1; + } + strcpy(new_type, search_type); + strcpy(new_value, search_value); + free(iter->search_type); + free(iter->search_value); + iter->search_type = new_type; + iter->search_value = new_value; + return 0; +} + +/* + * Return 0 on success, -1 on error + */ +extern int blkid_dev_next(blkid_dev_iterate iter, + blkid_dev *ret_dev) +{ + blkid_dev dev; + + *ret_dev = 0; + if (!iter || iter->magic != DEV_ITERATE_MAGIC) + return -1; + while (iter->p != &iter->cache->bic_devs) { + dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs); + iter->p = iter->p->next; + if (iter->search_type && + !blkid_dev_has_tag(dev, iter->search_type, + iter->search_value)) + continue; + *ret_dev = dev; + return 0; + } + return -1; +} + +extern void blkid_dev_iterate_end(blkid_dev_iterate iter) +{ + if (!iter || iter->magic != DEV_ITERATE_MAGIC) + return; + iter->magic = 0; + free(iter); +} + +#ifdef TEST_PROGRAM +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#else +extern char *optarg; +extern int optind; +#endif + +void usage(char *prog) +{ + fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog); + fprintf(stderr, "\tList all devices and exit\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + blkid_dev_iterate iter; + blkid_cache cache = NULL; + blkid_dev dev; + int c, ret; + char *tmp; + char *file = NULL; + char *search_type = NULL; + char *search_value = NULL; + + while ((c = getopt (argc, argv, "m:f:")) != EOF) + switch (c) { + case 'f': + file = optarg; + break; + case 'm': + { + int mask = strtoul (optarg, &tmp, 0); + if (*tmp) { + fprintf(stderr, "Invalid debug mask: %s\n", + optarg); + exit(1); + } + blkid_init_debug(mask); + break; + } + case '?': + usage(argv[0]); + } + if (argc >= optind+2) { + search_type = argv[optind]; + search_value = argv[optind+1]; + optind += 2; + } + if (argc != optind) + usage(argv[0]); + + if ((ret = blkid_get_cache(&cache, file)) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + + iter = blkid_dev_iterate_begin(cache); + if (search_type) + blkid_dev_set_search(iter, search_type, search_value); + while (blkid_dev_next(iter, &dev) == 0) { + printf("Device: %s\n", blkid_dev_devname(dev)); + } + blkid_dev_iterate_end(iter); + + + blkid_put_cache(cache); + return (0); +} +#endif diff --git a/shlibs/blkid/src/devname.c b/shlibs/blkid/src/devname.c new file mode 100644 index 00000000..ef686f4b --- /dev/null +++ b/shlibs/blkid/src/devname.c @@ -0,0 +1,558 @@ +/* + * devname.c - get a dev by its device inode name + * + * Copyright (C) Andries Brouwer + * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <string.h> +#include <limits.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#include <dirent.h> +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_MKDEV_H +#include <sys/mkdev.h> +#endif +#include <time.h> + +#include "blkidP.h" + +/* + * 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)) { + if (access(devname, F_OK) < 0) + return NULL; + 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; +} + +/* Directories where we will try to search for device names */ +static const char *dirlist[] = { "/dev", "/devfs", "/devices", NULL }; + +static int is_dm_leaf(const char *devname) +{ + struct dirent *de, *d_de; + DIR *dir, *d_dir; + char path[256]; + int ret = 1; + + if ((dir = opendir("/sys/block")) == NULL) + return 0; + while ((de = readdir(dir)) != NULL) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") || + !strcmp(de->d_name, devname) || + strncmp(de->d_name, "dm-", 3) || + strlen(de->d_name) > sizeof(path)-32) + continue; + sprintf(path, "/sys/block/%s/slaves", de->d_name); + if ((d_dir = opendir(path)) == NULL) + continue; + while ((d_de = readdir(d_dir)) != NULL) { + if (!strcmp(d_de->d_name, devname)) { + ret = 0; + break; + } + } + closedir(d_dir); + if (!ret) + break; + } + closedir(dir); + return ret; +} + +/* + * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs + * provides the real DM device names in /sys/block/<ptname>/dm/name + */ +static char *get_dm_name(const char *ptname) +{ + FILE *f; + size_t sz; + char path[256], name[256], *res = NULL; + + snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname); + if ((f = fopen(path, "r")) == NULL) + return NULL; + + /* read "<name>\n" from sysfs */ + if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) { + name[sz - 1] = '\0'; + snprintf(path, sizeof(path), "/dev/mapper/%s", name); + res = blkid_strdup(path); + } + fclose(f); + return res; +} + +/* + * 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); + if (tmp->bid_devno == devno) { + if (only_if_new && !access(tmp->bid_name, F_OK)) + return; + dev = blkid_verify(cache, tmp); + if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)) + break; + dev = 0; + } + } + if (dev && dev->bid_devno == devno) + goto set_pri; + + /* Try to translate private device-mapper dm-<N> names + * to standard /dev/mapper/<name>. + */ + if (!strncmp(ptname, "dm-", 3) && isdigit(ptname[3])) { + devname = get_dm_name(ptname); + if (!devname) + blkid__scan_dir("/dev/mapper", devno, 0, &devname); + if (devname) + goto get_dev; + } + + /* + * Take a quick look at /dev/ptname for the device number. We check + * all of the likely device directories. If we don't find it, or if + * the stat information doesn't check out, use blkid_devno_to_devname() + * to find it via an exhaustive search for the device major/minor. + */ + for (dir = dirlist; *dir; dir++) { + struct stat st; + char device[256]; + + 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); + goto get_dev; + } + } + /* Do a short-cut scan of /dev/mapper first */ + if (!devname) + blkid__scan_dir("/dev/mapper", devno, 0, &devname); + if (!devname) { + devname = blkid_devno_to_devname(devno); + if (!devname) + return; + } + +get_dev: + dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); + free(devname); + +set_pri: + if (dev) { + if (pri) + dev->bid_pri = pri; + else if (!strncmp(dev->bid_name, "/dev/mapper/", 11)) { + dev->bid_pri = BLKID_PRI_DM; + if (is_dm_leaf(ptname)) + dev->bid_pri += 5; + } else if (!strncmp(ptname, "md", 2)) + dev->bid_pri = BLKID_PRI_MD; + } + return; +} + +#define PROC_PARTITIONS "/proc/partitions" +#define VG_DIR "/proc/lvm/VGs" + +/* + * This function initializes the UUID cache with devices from the LVM + * proc hierarchy. We currently depend on the names of the LVM + * hierarchy giving us the device structure in /dev. (XXX is this a + * safe thing to do?) + */ +#ifdef VG_DIR +static dev_t lvm_get_devno(const char *lvm_device) +{ + FILE *lvf; + char buf[1024]; + int ma, mi; + dev_t ret = 0; + + DBG(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; + struct list_head *p, *pnext; + + ptnames[0] = ptname0; + ptnames[1] = ptname1; + + if (!cache) + return -BLKID_ERR_PARAM; + + if (cache->bic_flags & BLKID_BIC_FL_PROBED && + time(0) - cache->bic_time < BLKID_PROBE_INTERVAL) + return 0; + + blkid_read_cache(cache); + evms_probe_all(cache, only_if_new); +#ifdef VG_DIR + lvm_probe_all(cache, only_if_new); +#endif + + 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 a whole disk and we just found a partition + * on it, remove the whole-disk dev from the cache if + * it exists. + */ + if (lens[last] && !strncmp(ptnames[last], ptname, lens[last])) { + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev tmp; + + /* find blkid dev for the whole-disk devno */ + tmp = list_entry(p, struct blkid_struct_dev, + bid_devs); + if (tmp->bid_devno == devs[last]) { + DBG(DEBUG_DEVNAME, + printf("freeing %s\n", + tmp->bid_name)); + blkid_free_dev(tmp); + cache->bic_flags |= BLKID_BIC_FL_CHANGED; + break; + } + } + lens[last] = 0; + } + /* + * If last was not checked because it looked like a whole-disk + * dev, and the device's base name has changed, + * check last as well. + */ + if (lens[last] && strncmp(ptnames[last], ptname, lens[last])) { + DBG(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_init_debug(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/shlibs/blkid/src/devno.c b/shlibs/blkid/src/devno.c new file mode 100644 index 00000000..8ffdb835 --- /dev/null +++ b/shlibs/blkid/src/devno.c @@ -0,0 +1,228 @@ +/* + * devno.c - find a particular device by its device number (major/minor) + * + * Copyright (C) 2000, 2001, 2003 Theodore Ts'o + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <stdio.h> +#include <string.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <string.h> +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#include <dirent.h> +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_MKDEV_H +#include <sys/mkdev.h> +#endif + +#include "blkidP.h" + +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; +} + +void blkid__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 (list && 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 */ +static const char *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 = 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)); + blkid__scan_dir(current->name, devno, &new_list, &devname); + free(current->name); + free(current); + if (devname) + break; + /* + * If we're done checking at this level, descend to + * the next level of subdirectories. (breadth-first) + */ + if (list == NULL) { + list = new_list; + new_list = NULL; + } + } + free_dirlist(&list); + free_dirlist(&new_list); + + 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_init_debug(DEBUG_ALL); + if ((argc != 2) && (argc != 3)) { + fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n" + "Resolve a device number to a device name\n", + argv[0], argv[0]); + exit(1); + } + if (argc == 2) { + devno = strtoul(argv[1], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "device number", argv[1]); + exit(1); + } + } else { + major = strtoul(argv[1], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "major number", argv[1]); + exit(1); + } + minor = strtoul(argv[2], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "minor number", argv[2]); + exit(1); + } + devno = makedev(major, minor); + } + printf("Looking for device 0x%04llx\n", (long long)devno); + devname = blkid_devno_to_devname(devno); + free(devname); + return 0; +} +#endif diff --git a/shlibs/blkid/src/encode.c b/shlibs/blkid/src/encode.c new file mode 100644 index 00000000..d45a292e --- /dev/null +++ b/shlibs/blkid/src/encode.c @@ -0,0 +1,288 @@ + +/* + * encode.c - string convertion routines (mostly for compatibility with + * udev/volume_id) + * + * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> + +#include "blkdev.h" +#include "blkidP.h" + +#define UDEV_ALLOWED_CHARS_INPUT "/ $%?," + +/* count of characters used to encode one unicode char */ +static int utf8_encoded_expected_len(const char *str) +{ + unsigned char c = (unsigned char)str[0]; + + if (c < 0x80) + return 1; + if ((c & 0xe0) == 0xc0) + return 2; + if ((c & 0xf0) == 0xe0) + return 3; + if ((c & 0xf8) == 0xf0) + return 4; + if ((c & 0xfc) == 0xf8) + return 5; + if ((c & 0xfe) == 0xfc) + return 6; + return 0; +} + +/* decode one unicode char */ +static int utf8_encoded_to_unichar(const char *str) +{ + int unichar; + int len; + int i; + + len = utf8_encoded_expected_len(str); + switch (len) { + case 1: + return (int)str[0]; + case 2: + unichar = str[0] & 0x1f; + break; + case 3: + unichar = (int)str[0] & 0x0f; + break; + case 4: + unichar = (int)str[0] & 0x07; + break; + case 5: + unichar = (int)str[0] & 0x03; + break; + case 6: + unichar = (int)str[0] & 0x01; + break; + default: + return -1; + } + + for (i = 1; i < len; i++) { + if (((int)str[i] & 0xc0) != 0x80) + return -1; + unichar <<= 6; + unichar |= (int)str[i] & 0x3f; + } + + return unichar; +} + +/* expected size used to encode one unicode char */ +static int utf8_unichar_to_encoded_len(int unichar) +{ + if (unichar < 0x80) + return 1; + if (unichar < 0x800) + return 2; + if (unichar < 0x10000) + return 3; + if (unichar < 0x200000) + return 4; + if (unichar < 0x4000000) + return 5; + return 6; +} + +/* check if unicode char has a valid numeric range */ +static int utf8_unichar_valid_range(int unichar) +{ + if (unichar > 0x10ffff) + return 0; + if ((unichar & 0xfffff800) == 0xd800) + return 0; + if ((unichar > 0xfdcf) && (unichar < 0xfdf0)) + return 0; + if ((unichar & 0xffff) == 0xffff) + return 0; + return 1; +} + +/* validate one encoded unicode char and return its length */ +static int utf8_encoded_valid_unichar(const char *str) +{ + int len; + int unichar; + int i; + + len = utf8_encoded_expected_len(str); + if (len == 0) + return -1; + + /* ascii is valid */ + if (len == 1) + return 1; + + /* check if expected encoded chars are available */ + for (i = 0; i < len; i++) + if ((str[i] & 0x80) != 0x80) + return -1; + + unichar = utf8_encoded_to_unichar(str); + + /* check if encoded length matches encoded value */ + if (utf8_unichar_to_encoded_len(unichar) != len) + return -1; + + /* check if value has valid range */ + if (!utf8_unichar_valid_range(unichar)) + return -1; + + return len; +} + +static int replace_whitespace(const char *str, char *to, size_t len) +{ + size_t i, j; + + /* strip trailing whitespace */ + len = strnlen(str, len); + while (len && isspace(str[len-1])) + len--; + + /* strip leading whitespace */ + i = 0; + while (isspace(str[i]) && (i < len)) + i++; + + j = 0; + while (i < len) { + /* substitute multiple whitespace with a single '_' */ + if (isspace(str[i])) { + while (isspace(str[i])) + i++; + to[j++] = '_'; + } + to[j++] = str[i++]; + } + to[j] = '\0'; + return 0; +} + +static int is_whitelisted(char c, const char *white) +{ + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + strchr("#+-.:=@_", c) != NULL || + (white != NULL && strchr(white, c) != NULL)) + return 1; + return 0; +} + +/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */ +static int replace_chars(char *str, const char *white) +{ + size_t i = 0; + int replaced = 0; + + while (str[i] != '\0') { + int len; + + if (is_whitelisted(str[i], white)) { + i++; + continue; + } + + /* accept hex encoding */ + if (str[i] == '\\' && str[i+1] == 'x') { + i += 2; + continue; + } + + /* accept valid utf8 */ + len = utf8_encoded_valid_unichar(&str[i]); + if (len > 1) { + i += len; + continue; + } + + /* if space is allowed, replace whitespace with ordinary space */ + if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) { + str[i] = ' '; + i++; + replaced++; + continue; + } + + /* everything else is replaced with '_' */ + str[i] = '_'; + i++; + replaced++; + } + return replaced; +} + +/** + * blkid_encode_string: + * @str: input string to be encoded + * @str_enc: output string to store the encoded input string + * @len: maximum size of the output string, which may be + * four times as long as the input string + * + * Encode all potentially unsafe characters of a string to the + * corresponding hex value prefixed by '\x'. + * + * Returns: 0 if the entire string was copied, non-zero otherwise. + **/ +int blkid_encode_string(const char *str, char *str_enc, size_t len) +{ + size_t i, j; + + if (str == NULL || str_enc == NULL || len == 0) + return -1; + + str_enc[0] = '\0'; + for (i = 0, j = 0; str[i] != '\0'; i++) { + int seqlen; + + seqlen = utf8_encoded_valid_unichar(&str[i]); + if (seqlen > 1) { + memcpy(&str_enc[j], &str[i], seqlen); + j += seqlen; + i += (seqlen-1); + } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) { + sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]); + j += 4; + } else { + str_enc[j] = str[i]; + j++; + } + if (j+3 >= len) + goto err; + } + str_enc[j] = '\0'; + return 0; +err: + return -1; +} + +/** + * blkid_safe_string: + * @str: input string + * @str_safe: output string + * @len: size of output string + * + * Allows plain ascii, hex-escaping and valid utf8. Replaces all whitespaces + * with '_'. + */ +int blkid_safe_string(const char *str, char *str_safe, size_t len) +{ + replace_whitespace(str, str_safe, len); + replace_chars(str_safe, UDEV_ALLOWED_CHARS_INPUT); + return 0; +} diff --git a/shlibs/blkid/src/evaluate.c b/shlibs/blkid/src/evaluate.c new file mode 100644 index 00000000..b8154e47 --- /dev/null +++ b/shlibs/blkid/src/evaluate.c @@ -0,0 +1,269 @@ +/* + * evaluate.c - very high-level API to evaluate LABELs or UUIDs + * + * This is simular to blkid_get_devname() from resolve.c, but this + * API supports udev /dev/disk/by-{label,uuid} links. + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_SYS_MKDEV_H +#include <sys/mkdev.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdint.h> +#include <stdarg.h> + +#include "pathnames.h" +#include "canonicalize.h" + +#include "blkdev.h" +#include "blkidP.h" + +/* returns zero when the device has NAME=value (LABEL/UUID) */ +static int verify_tag(const char *devname, const char *name, const char *value) +{ + blkid_probe pr; + int fd = -1, rc = -1; + size_t len; + const char *data; + int errsv = 0; + + pr = blkid_new_probe(); + if (!pr) + return -1; + + blkid_probe_set_request(pr, BLKID_PROBREQ_LABEL | BLKID_PROBREQ_UUID); + + fd = open(devname, O_RDONLY); + if (fd < 0) { + errsv = errno; + goto done; + } + if (blkid_probe_set_device(pr, fd, 0, 0)) + goto done; + rc = blkid_do_safeprobe(pr); + if (rc) + goto done; + rc = blkid_probe_lookup_value(pr, name, &data, &len); + if (!rc) + rc = memcmp(value, data, len); +done: + DBG(DEBUG_EVALUATE, printf("%s: %s verification %s\n", + devname, name, rc == 0 ? "PASS" : "FAILED")); + if (fd >= 0) + close(fd); + blkid_free_probe(pr); + + /* for non-root users we use unverified udev links */ + return errsv == EACCES ? 0 : rc; +} + +/** + * blkid_send_uevent: + * @devname: absolute path to the device + * + * Returns -1 in case of failure, or 0 on success. + */ +int blkid_send_uevent(const char *devname, const char *action) +{ + char uevent[PATH_MAX]; + struct stat st; + FILE *f; + int rc = -1; + + DBG(DEBUG_EVALUATE, printf("%s: uevent '%s' requested\n", devname, action)); + + if (!devname || !action) + return -1; + if (stat(devname, &st) || !S_ISBLK(st.st_mode)) + return -1; + + snprintf(uevent, sizeof(uevent), "/sys/dev/block/%d:%d/uevent", + major(st.st_rdev), minor(st.st_rdev)); + + f = fopen(uevent, "w"); + if (f) { + rc = 0; + if (fputs(action, f) >= 0) + rc = 0; + fclose(f); + } + DBG(DEBUG_EVALUATE, printf("%s: send uevent %s\n", + uevent, rc == 0 ? "SUCCES" : "FAILED")); + return rc; +} + +static char *evaluate_by_udev(const char *token, const char *value, int uevent) +{ + char dev[PATH_MAX]; + char *path = NULL; + size_t len; + struct stat st; + + DBG(DEBUG_EVALUATE, + printf("evaluating by udev %s=%s\n", token, value)); + + if (!strcmp(token, "UUID")) + strcpy(dev, _PATH_DEV_BYUUID "/"); + else if (!strcmp(token, "LABEL")) + strcpy(dev, _PATH_DEV_BYLABEL "/"); + else { + DBG(DEBUG_EVALUATE, + printf("unsupported token %s\n", token)); + return NULL; /* unsupported tag */ + } + + len = strlen(dev); + if (blkid_encode_string(value, &dev[len], sizeof(dev) - len) != 0) + return NULL; + + DBG(DEBUG_EVALUATE, + printf("expected udev link: %s\n", dev)); + + if (stat(dev, &st)) + goto failed; /* link or device does not exist */ + + if (!S_ISBLK(st.st_mode)) + return NULL; + + path = canonicalize_path(dev); + if (!path) + return NULL; + + if (verify_tag(path, token, value)) + goto failed; + return path; + +failed: + DBG(DEBUG_EVALUATE, printf("failed to evaluate by udev\n")); + + if (uevent && path) + blkid_send_uevent(path, "change"); + free(path); + return NULL; +} + +static char *evaluate_by_scan(const char *token, const char *value, + blkid_cache *cache, struct blkid_config *conf) +{ + blkid_cache c = cache ? *cache : NULL; + char *res; + + DBG(DEBUG_EVALUATE, + printf("evaluating by blkid scan %s=%s\n", token, value)); + + if (!c) { + char *cachefile = blkid_get_cache_filename(conf); + blkid_get_cache(&c, cachefile); + free(cachefile); + } + if (!c) + return NULL; + + res = blkid_get_devname(c, token, value); + + if (cache) + *cache = c; + else + blkid_put_cache(c); + + return res; +} + +/** + * blkid_evaluate_tag: + * @token: token name (e.g "LABEL" or "UUID") + * @value: token data + * @cache: pointer to cache (or NULL when you don't want to re-use the cache) + * + * Returns allocated string with device name. + */ +char *blkid_evaluate_tag(const char *token, const char *value, blkid_cache *cache) +{ + struct blkid_config *conf = NULL; + char *t = NULL, *v = NULL; + char *ret = NULL; + int i; + + if (!token) + return NULL; + + if (!cache || !*cache) + blkid_init_debug(0); + + DBG(DEBUG_EVALUATE, + printf("evaluating %s%s%s\n", token, value ? "=" : "", + value ? value : "")); + + 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; + } + + conf = blkid_read_config(NULL); + if (!conf) + goto out; + + for (i = 0; i < conf->nevals; i++) { + if (conf->eval[i] == BLKID_EVAL_UDEV) + ret = evaluate_by_udev(token, value, conf->uevent); + else if (conf->eval[i] == BLKID_EVAL_SCAN) + ret = evaluate_by_scan(token, value, cache, conf); + if (ret) + break; + } + + DBG(DEBUG_EVALUATE, + printf("%s=%s evaluated as %s\n", token, value, ret)); +out: + blkid_free_config(conf); + free(t); + free(v); + return ret; +} + +#ifdef TEST_PROGRAM +int main(int argc, char *argv[]) +{ + blkid_cache cache = NULL; + char *res; + + if (argc < 3) { + fprintf(stderr, "usage: %s <token> <value>\n", argv[0]); + return EXIT_FAILURE; + } + + blkid_init_debug(0); + + res = blkid_evaluate_tag(argv[1], argv[2], &cache); + if (res) + printf("%s\n", res); + if (cache) + blkid_put_cache(cache); + + return res ? EXIT_SUCCESS : EXIT_FAILURE; +} +#endif diff --git a/shlibs/blkid/src/getsize.c b/shlibs/blkid/src/getsize.c new file mode 100644 index 00000000..10ba7ecf --- /dev/null +++ b/shlibs/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 <stdio.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#include <fcntl.h> +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif +#ifdef HAVE_LINUX_FD_H +#include <linux/fd.h> +#endif +#ifdef HAVE_SYS_DISKLABEL_H +#include <sys/disklabel.h> +#endif +#ifdef HAVE_SYS_DISK_H +#ifdef HAVE_SYS_QUEUE_H +#include <sys/queue.h> /* for LIST_HEAD */ +#endif +#include <sys/disk.h> +#endif +#ifdef __linux__ +#include <sys/utsname.h> +#endif +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + + +#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) +#define BLKGETSIZE _IO(0x12,96) /* return device size */ +#endif + +#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) +#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ +#endif + +#ifdef APPLE_DARWIN +#define BLKGETSIZE DKIOCGETBLOCKCOUNT32 +#endif /* APPLE_DARWIN */ + +static int valid_offset(int fd, blkid_loff_t offset) +{ + char ch; + + if (blkid_llseek(fd, offset, 0) < 0) + return 0; + if (read(fd, &ch, 1) < 1) + return 0; + return 1; +} + +/* + * Returns the number of bytes in a partition + */ +blkid_loff_t blkid_get_dev_size(int fd) +{ + int valid_blkgetsize64 = 1; +#ifdef __linux__ + struct utsname ut; +#endif + unsigned long long size64; + unsigned long size; + blkid_loff_t high, low; +#ifdef FDGETPRM + struct floppy_struct this_floppy; +#endif +#ifdef HAVE_SYS_DISKLABEL_H + int part = -1; + struct disklabel lab; + struct partition *pp; + char ch; + struct stat st; +#endif /* HAVE_SYS_DISKLABEL_H */ + +#ifdef DKIOCGETBLOCKCOUNT /* For Apple Darwin */ + if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) { + if ((sizeof(blkid_loff_t) < sizeof(unsigned long long)) + && (size64 << 9 > 0xFFFFFFFF)) + return 0; /* EFBIG */ + return (blkid_loff_t) size64 << 9; + } +#endif + +#ifdef BLKGETSIZE64 +#ifdef __linux__ + if ((uname(&ut) == 0) && + ((ut.release[0] == '2') && (ut.release[1] == '.') && + (ut.release[2] < '6') && (ut.release[3] == '.'))) + valid_blkgetsize64 = 0; +#endif + if (valid_blkgetsize64 && + ioctl(fd, BLKGETSIZE64, &size64) >= 0) { + if ((sizeof(blkid_loff_t) < sizeof(unsigned long long)) + && ((size64) > 0xFFFFFFFF)) + return 0; /* EFBIG */ + return size64; + } +#endif + +#ifdef BLKGETSIZE + if (ioctl(fd, BLKGETSIZE, &size) >= 0) + return (blkid_loff_t)size << 9; +#endif + +/* tested on FreeBSD 6.1-RELEASE i386 */ +#ifdef DIOCGMEDIASIZE + if (ioctl(fd, DIOCGMEDIASIZE, &size64) >= 0) + return (off_t)size64; +#endif /* DIOCGMEDIASIZE */ + +#ifdef FDGETPRM + if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) + return (blkid_loff_t)this_floppy.size << 9; +#endif +#ifdef HAVE_SYS_DISKLABEL_H + /* + * This code works for FreeBSD 4.11 i386, except for the full device + * (such as /dev/ad0). It doesn't work properly for newer FreeBSD + * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE + * above however. + * + * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw, + * character) devices, so we need to check for S_ISCHR, too. + */ + if ((fstat(fd, &st) >= 0) && (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) + part = st.st_rdev & 7; + if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { + pp = &lab.d_partitions[part]; + if (pp->p_size) + return pp->p_size << 9; + } +#endif /* HAVE_SYS_DISKLABEL_H */ + { +#ifdef HAVE_FSTAT64 + struct stat64 st; + if (fstat64(fd, &st) == 0) +#else + struct stat st; + if (fstat(fd, &st) == 0) +#endif + if (S_ISREG(st.st_mode)) + return st.st_size; + } + + + /* + * OK, we couldn't figure it out by using a specialized ioctl, + * which is generally the best way. So do binary search to + * find the size of the partition. + */ + low = 0; + for (high = 1024; valid_offset(fd, high); high *= 2) + low = high; + while (low < high - 1) + { + const blkid_loff_t mid = (low + high) / 2; + + if (valid_offset(fd, mid)) + low = mid; + else + high = mid; + } + return low + 1; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + long long bytes; + int fd; + + if (argc < 2) { + fprintf(stderr, "Usage: %s device\n" + "Determine the size of a device\n", argv[0]); + return 1; + } + + if ((fd = open(argv[1], O_RDONLY)) < 0) + perror(argv[0]); + + bytes = blkid_get_dev_size(fd); + printf("Device %s has %Ld 1k blocks.\n", argv[1], + (unsigned long long) bytes >> 10); + + return 0; +} +#endif diff --git a/shlibs/blkid/src/list.h b/shlibs/blkid/src/list.h new file mode 100644 index 00000000..c1cbfec5 --- /dev/null +++ b/shlibs/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/shlibs/blkid/src/llseek.c b/shlibs/blkid/src/llseek.c new file mode 100644 index 00000000..5bd0e516 --- /dev/null +++ b/shlibs/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 <sys/types.h> +#endif + +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef __MSDOS__ +#include <io.h> +#endif + +#include "blkidP.h" + +#ifdef __linux__ + +#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) + +#define my_llseek lseek64 + +#elif defined(HAVE_LLSEEK) +#include <syscall.h> + +#ifndef HAVE_LLSEEK_PROTOTYPE +extern long long llseek(int fd, long long offset, int origin); +#endif + +#define my_llseek llseek + +#else /* ! HAVE_LLSEEK */ + +#if SIZEOF_LONG == SIZEOF_LONG_LONG + +#define llseek lseek + +#else /* SIZEOF_LONG != SIZEOF_LONG_LONG */ + +#include <linux/unistd.h> + +#ifndef __NR__llseek +#define __NR__llseek 140 +#endif + +#ifndef __i386__ +static int _llseek(unsigned int, unsigned long, unsigned long, + blkid_loff_t *, unsigned int); + +static _syscall5(int, _llseek, unsigned int, fd, unsigned long, offset_high, + unsigned long, offset_low, blkid_loff_t *, result, + unsigned int, origin) +#endif + +static blkid_loff_t my_llseek(int fd, blkid_loff_t offset, int origin) +{ + blkid_loff_t result; + int retval; + +#ifndef __i386__ + retval = _llseek(fd, ((unsigned long long) offset) >> 32, + ((unsigned long long)offset) & 0xffffffff, + &result, origin); +#else + retval = syscall(__NR__llseek, fd, ((unsigned long long) offset) >> 32, + ((unsigned long long)offset) & 0xffffffff, + &result, origin); +#endif + return (retval == -1 ? (blkid_loff_t) retval : result); +} + +#endif /* __alpha__ || __ia64__ */ + +#endif /* HAVE_LLSEEK */ + +blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence) +{ + blkid_loff_t result; + static int do_compat = 0; + + if ((sizeof(off_t) >= sizeof(blkid_loff_t)) || + (offset < ((blkid_loff_t) 1 << ((sizeof(off_t)*8) -1)))) + return lseek(fd, (off_t) offset, whence); + + if (do_compat) { + errno = EOVERFLOW; + return -1; + } + + result = my_llseek(fd, offset, whence); + if (result == -1 && errno == ENOSYS) { + /* + * Just in case this code runs on top of an old kernel + * which does not support the llseek system call + */ + do_compat++; + errno = EOVERFLOW; + } + return result; +} + +#else /* !linux */ + +#ifndef EOVERFLOW +#ifdef EXT2_ET_INVALID_ARGUMENT +#define EOVERFLOW EXT2_ET_INVALID_ARGUMENT +#else +#define EOVERFLOW 112 +#endif +#endif + +blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int origin) +{ +#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) + return lseek64 (fd, offset, origin); +#else + if ((sizeof(off_t) < sizeof(blkid_loff_t)) && + (offset >= ((blkid_loff_t) 1 << ((sizeof(off_t)*8) - 1)))) { + errno = EOVERFLOW; + return -1; + } + return lseek(fd, (off_t) offset, origin); +#endif +} + +#endif /* linux */ + + diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c new file mode 100644 index 00000000..10fcb003 --- /dev/null +++ b/shlibs/blkid/src/probe.c @@ -0,0 +1,936 @@ +/* + * probe.c - reads tags (LABEL, UUID, FS type, ..) from a block device + * + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_SYS_MKDEV_H +#include <sys/mkdev.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdint.h> +#include <stdarg.h> + +#ifdef HAVE_LIBUUID +# ifdef HAVE_UUID_UUID_H +# include <uuid/uuid.h> +# else +# include <uuid.h> +# endif +#endif + +#include "blkdev.h" +#include "blkidP.h" +#include "probers/probers.h" + +static const struct blkid_idinfo *idinfos[] = +{ + /* RAIDs */ + &linuxraid_idinfo, + &ddfraid_idinfo, + &iswraid_idinfo, + &lsiraid_idinfo, + &viaraid_idinfo, + &silraid_idinfo, + &nvraid_idinfo, + &pdcraid_idinfo, + &highpoint45x_idinfo, + &highpoint37x_idinfo, + &adraid_idinfo, + &jmraid_idinfo, + &lvm2_idinfo, + &lvm1_idinfo, + &snapcow_idinfo, + &luks_idinfo, + + /* Filesystems */ + &vfat_idinfo, + &swsuspend_idinfo, + &swap_idinfo, + &xfs_idinfo, + &ext4dev_idinfo, + &ext4_idinfo, + &ext3_idinfo, + &ext2_idinfo, + &jbd_idinfo, + &reiser_idinfo, + &reiser4_idinfo, + &jfs_idinfo, + &udf_idinfo, + &iso9660_idinfo, + &zfs_idinfo, + &hfsplus_idinfo, + &hfs_idinfo, + &ufs_idinfo, + &hpfs_idinfo, + &sysv_idinfo, + &xenix_idinfo, + &ntfs_idinfo, + &cramfs_idinfo, + &romfs_idinfo, + &minix_idinfo, + &gfs_idinfo, + &gfs2_idinfo, + &ocfs_idinfo, + &ocfs2_idinfo, + &oracleasm_idinfo, + &vxfs_idinfo, + &squashfs_idinfo, + &netware_idinfo, + &btrfs_idinfo +}; + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +/* filter bitmap macros */ +#define blkid_bmp_wordsize (8 * sizeof(unsigned long)) +#define blkid_bmp_idx_bit(item) (1UL << ((item) % blkid_bmp_wordsize)) +#define blkid_bmp_idx_byte(item) ((item) / blkid_bmp_wordsize) + +#define blkid_bmp_set_item(bmp, item) \ + ((bmp)[ blkid_bmp_idx_byte(item) ] |= blkid_bmp_idx_bit(item)) + +#define blkid_bmp_unset_item(bmp, item) \ + ((bmp)[ bmp_idx_byte(item) ] &= ~bmp_idx_bit(item)) + +#define blkid_bmp_get_item(bmp, item) \ + ((bmp)[ blkid_bmp_idx_byte(item) ] & blkid_bmp_idx_bit(item)) + +#define blkid_bmp_size(max_items) \ + (((max_items) + blkid_bmp_wordsize) / blkid_bmp_wordsize) + +#define BLKID_FLTR_ITEMS ARRAY_SIZE(idinfos) +#define BLKID_FLTR_SIZE blkid_bmp_size(BLKID_FLTR_ITEMS) + + +static int blkid_probe_set_usage(blkid_probe pr, int usage); + +int blkid_known_fstype(const char *fstype) +{ + int i; + + if (!fstype) + return 0; + + for (i = 0; i < ARRAY_SIZE(idinfos); i++) { + const struct blkid_idinfo *id = idinfos[i]; + if (strcmp(id->name, fstype) == 0) + return 1; + } + return 0; +} + +/* + * Returns a pointer to the newly allocated probe struct + */ +blkid_probe blkid_new_probe(void) +{ + blkid_init_debug(0); + return calloc(1, sizeof(struct blkid_struct_probe)); +} + +/* + * Deallocates probe struct, buffers and all allocated + * data that are associated with this probing control struct. + */ +void blkid_free_probe(blkid_probe pr) +{ + if (!pr) + return; + free(pr->fltr); + free(pr->buf); + free(pr->sbbuf); + free(pr); +} + +static void blkid_probe_reset_vals(blkid_probe pr) +{ + memset(pr->vals, 0, sizeof(pr->vals)); + pr->nvals = 0; +} + +static void blkid_probe_reset_idx(blkid_probe pr) +{ + pr->idx = -1; +} + +void blkid_reset_probe(blkid_probe pr) +{ + if (!pr) + return; + DBG(DEBUG_LOWPROBE, printf("reseting blkid_probe\n")); + if (pr->buf) + memset(pr->buf, 0, pr->buf_max); + pr->buf_off = 0; + pr->buf_len = 0; + if (pr->sbbuf) + memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ); + pr->sbbuf_len = 0; + blkid_probe_reset_vals(pr); + blkid_probe_reset_idx(pr); +} + +/* + * Note that we have two offsets: + * + * 1/ general device offset (pr->off), that's useful for example when we + * probe a partition from whole disk image: + * blkid-low --offset <partition_position> disk.img + * + * 2/ buffer offset (the 'off' argument), that useful for offsets in + * superbloks, ... + * + * That means never use lseek(fd, 0, SEEK_SET), the zero position is always + * pr->off, so lseek(fd, pr->off, SEEK_SET). + * + */ +unsigned char *blkid_probe_get_buffer(blkid_probe pr, + blkid_loff_t off, blkid_loff_t len) +{ + ssize_t ret_read = 0; + + if (off < 0 || len < 0) { + DBG(DEBUG_LOWPROBE, + printf("unexpected offset or length of buffer requested\n")); + return NULL; + } + if (off + len <= BLKID_SB_BUFSIZ) { + if (!pr->sbbuf) { + pr->sbbuf = malloc(BLKID_SB_BUFSIZ); + if (!pr->sbbuf) + return NULL; + } + if (!pr->sbbuf_len) { + if (lseek(pr->fd, pr->off, SEEK_SET) < 0) + return NULL; + ret_read = read(pr->fd, pr->sbbuf, BLKID_SB_BUFSIZ); + if (ret_read < 0) + ret_read = 0; + pr->sbbuf_len = ret_read; + } + if (off + len > pr->sbbuf_len) + return NULL; + return pr->sbbuf + off; + } else { + unsigned char *newbuf = NULL; + + if (len > pr->buf_max) { + newbuf = realloc(pr->buf, len); + if (!newbuf) + return NULL; + pr->buf = newbuf; + pr->buf_max = len; + pr->buf_off = 0; + pr->buf_len = 0; + } + if (newbuf || off < pr->buf_off || + off + len > pr->buf_off + pr->buf_len) { + + if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) + return NULL; + + ret_read = read(pr->fd, pr->buf, len); + if (ret_read != (ssize_t) len) + return NULL; + pr->buf_off = off; + pr->buf_len = len; + } + return off ? pr->buf + (off - pr->buf_off) : pr->buf; + } +} + +/* + * Assignes the device to probe control struct, resets internal buffers and + * reads 512 bytes from device to the buffers. + * + * Returns -1 in case of failure, or 0 on success. + */ +int blkid_probe_set_device(blkid_probe pr, int fd, + blkid_loff_t off, blkid_loff_t size) +{ + if (!pr) + return -1; + + blkid_reset_probe(pr); + + pr->fd = fd; + pr->off = off; + pr->size = 0; + + if (size) + pr->size = size; + else { + struct stat sb; + + if (fstat(fd, &sb)) + return -1; + + if (S_ISBLK(sb.st_mode)) + blkdev_get_size(fd, (unsigned long long *) &pr->size); + else + pr->size = sb.st_size; + } + if (!pr->size) + return -1; + + /* read SB to test if the device is readable */ + if (!blkid_probe_get_buffer(pr, 0, 0x200)) { + DBG(DEBUG_LOWPROBE, + printf("failed to prepare a device for low-probing\n")); + return -1; + } + + DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n", + pr->off, pr->size)); + return 0; +} + +int blkid_probe_set_request(blkid_probe pr, int flags) +{ + if (!pr) + return -1; + pr->probreq = flags; + return 0; +} + +int blkid_probe_reset_filter(blkid_probe pr) +{ + if (!pr) + return -1; + if (pr->fltr) + memset(pr->fltr, 0, BLKID_FLTR_SIZE * sizeof(unsigned long)); + blkid_probe_reset_idx(pr); + return 0; +} + +/* + * flag: + * + * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN names[] + * + * BLKID_FLTR_ONLYIN - probe filesystem which are IN names[] + */ +int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[]) +{ + int i; + + if (!pr || !names) + return -1; + if (!pr->fltr) { + pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long)); + blkid_probe_reset_idx(pr); + } else + blkid_probe_reset_filter(pr); + + if (!pr->fltr) + return -1; + + for (i = 0; i < ARRAY_SIZE(idinfos); i++) { + int has = 0; + const struct blkid_idinfo *id = idinfos[i]; + char **n; + + for (n = names; *n; n++) { + if (!strcmp(id->name, *n)) { + has = 1; + break; + } + } + /* The default is enable all filesystems, + * set relevant bitmap bit means disable the filesystem. + */ + if (flag & BLKID_FLTR_ONLYIN) { + if (!has) + blkid_bmp_set_item(pr->fltr, i); + } else if (flag & BLKID_FLTR_NOTIN) { + if (has) + blkid_bmp_set_item(pr->fltr, i); + } + } + DBG(DEBUG_LOWPROBE, printf("a new probing type-filter initialized\n")); + return 0; +} + +/* + * flag: + * + * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN "usage" + * + * BLKID_FLTR_ONLYIN - probe filesystem which are IN "usage" + * + * where the "usage" is a set of filesystem according the usage flag (crypto, + * raid, filesystem, ...) + */ +int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage) +{ + int i; + + if (!pr || !usage) + return -1; + if (!pr->fltr) { + pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long)); + blkid_probe_reset_idx(pr); + } else + blkid_probe_reset_filter(pr); + + if (!pr->fltr) + return -1; + + for (i = 0; i < ARRAY_SIZE(idinfos); i++) { + const struct blkid_idinfo *id = idinfos[i]; + + if (id->usage & usage) { + if (flag & BLKID_FLTR_NOTIN) + blkid_bmp_set_item(pr->fltr, i); + } else if (flag & BLKID_FLTR_ONLYIN) + blkid_bmp_set_item(pr->fltr, i); + } + DBG(DEBUG_LOWPROBE, printf("a new probing usage-filter initialized\n")); + return 0; +} + + +int blkid_probe_invert_filter(blkid_probe pr) +{ + int i; + + if (!pr || !pr->fltr) + return -1; + for (i = 0; i < BLKID_FLTR_SIZE; i++) + pr->fltr[i] = ~pr->fltr[i]; + + blkid_probe_reset_idx(pr); + DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n")); + return 0; +} + +/* + * The blkid_do_probe() calls the probe functions. This routine could be used + * in a loop when you need to probe for all possible filesystems/raids. + * + * 1/ basic case -- use the first result: + * + * if (blkid_do_probe(pr) == 0) { + * int nvals = blkid_probe_numof_values(pr); + * for (n = 0; n < nvals; n++) { + * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0) + * printf("%s = %s\n", name, data); + * } + * } + * + * 2/ advanced case -- probe for all signatures (don't forget that some + * filesystems can co-exist on one volume (e.g. CD-ROM). + * + * while (blkid_do_probe(pr) == 0) { + * int nvals = blkid_probe_numof_values(pr); + * ... + * } + * + * The internal probing index (pointer to the last probing function) is + * always reseted when you touch probing filter or set a new device. It + * means you cannot use: + * + * blkid_probe_invert_filter() + * blkid_probe_filter_usage() + * blkid_probe_filter_types() + * blkid_probe_reset_filter() + * blkid_probe_set_device() + * + * in the loop (e.g while()) when you iterate on all signatures. + */ +int blkid_do_probe(blkid_probe pr) +{ + int i = 0; + + if (!pr || pr->idx < -1) + return -1; + + blkid_probe_reset_vals(pr); + + DBG(DEBUG_LOWPROBE, + printf("--> starting probing loop [idx=%d]\n", + pr->idx)); + + i = pr->idx + 1; + + for ( ; i < ARRAY_SIZE(idinfos); i++) { + const struct blkid_idinfo *id; + const struct blkid_idmag *mag; + int hasmag = 0; + + pr->idx = i; + + if (pr->fltr && blkid_bmp_get_item(pr->fltr, i)) + continue; + + id = idinfos[i]; + mag = id->magics ? &id->magics[0] : NULL; + + /* try to detect by magic string */ + while(mag && mag->magic) { + int idx; + unsigned char *buf; + + idx = mag->kboff + (mag->sboff >> 10); + buf = blkid_probe_get_buffer(pr, idx << 10, 1024); + + if (buf && !memcmp(mag->magic, + buf + (mag->sboff & 0x3ff), mag->len)) { + DBG(DEBUG_LOWPROBE, printf( + "%s: magic sboff=%u, kboff=%ld\n", + id->name, mag->sboff, mag->kboff)); + hasmag = 1; + break; + } + mag++; + } + + if (hasmag == 0 && id->magics && id->magics[0].magic) + /* magic string(s) defined, but not found */ + continue; + + /* final check by probing function */ + if (id->probefunc) { + DBG(DEBUG_LOWPROBE, printf( + "%s: call probefunc()\n", id->name)); + if (id->probefunc(pr, mag) != 0) + continue; + } + + /* all cheks passed */ + if (pr->probreq & BLKID_PROBREQ_TYPE) + blkid_probe_set_value(pr, "TYPE", + (unsigned char *) id->name, + strlen(id->name) + 1); + if (pr->probreq & BLKID_PROBREQ_USAGE) + blkid_probe_set_usage(pr, id->usage); + + DBG(DEBUG_LOWPROBE, + printf("<-- leaving probing loop (type=%s) [idx=%d]\n", + id->name, pr->idx)); + return 0; + } + DBG(DEBUG_LOWPROBE, + printf("<-- leaving probing loop (failed) [idx=%d]\n", + pr->idx)); + return 1; +} + +/* + * This is the same function as blkid_do_probe(), but returns only one result + * (cannot be used in while()) and checks for ambivalen results (more + * filesystems on the device) -- in such case returns -2. + * + * The function does not check for filesystems when a RAID signature is + * detected. The function also does not check for collision between RAIDs. The + * first detected RAID is returned. + */ +int blkid_do_safeprobe(blkid_probe pr) +{ + struct blkid_struct_probe first; + int count = 0; + int intol = 0; + int rc; + + while ((rc = blkid_do_probe(pr)) == 0) { + if (!count) { + /* store the fist result */ + memcpy(first.vals, pr->vals, sizeof(first.vals)); + first.nvals = pr->nvals; + first.idx = pr->idx; + } + count++; + + if (idinfos[pr->idx]->usage & BLKID_USAGE_RAID) + break; + if (!(idinfos[pr->idx]->flags & BLKID_IDINFO_TOLERANT)) + intol++; + } + if (rc < 0) + return rc; /* error */ + if (count > 1 && intol) { + DBG(DEBUG_LOWPROBE, + printf("ERROR: ambivalent result detected (%d filesystems)!\n", + count)); + return -2; /* error, ambivalent result (more FS) */ + } + if (!count) + return 1; /* nothing detected */ + + /* restore the first result */ + memcpy(pr->vals, first.vals, sizeof(first.vals)); + pr->nvals = first.nvals; + pr->idx = first.idx; + + return 0; +} + +int blkid_probe_numof_values(blkid_probe pr) +{ + if (!pr) + return -1; + return pr->nvals; +} + + +static struct blkid_prval *blkid_probe_assign_value( + blkid_probe pr, const char *name) +{ + struct blkid_prval *v; + + if (!name) + return NULL; + if (pr->nvals >= BLKID_PROBVAL_NVALS) + return NULL; + + v = &pr->vals[pr->nvals]; + v->name = name; + pr->nvals++; + + DBG(DEBUG_LOWPROBE, printf("assigning %s\n", name)); + return v; +} + +int blkid_probe_set_value(blkid_probe pr, const char *name, + unsigned char *data, size_t len) +{ + struct blkid_prval *v; + + if (len > BLKID_PROBVAL_BUFSIZ) + len = BLKID_PROBVAL_BUFSIZ; + + v = blkid_probe_assign_value(pr, name); + if (!v) + return -1; + + memcpy(v->data, data, len); + v->len = len; + return 0; +} + +int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, + const char *fmt, va_list ap) +{ + struct blkid_prval *v; + size_t len; + + v = blkid_probe_assign_value(pr, name); + if (!v) + return -1; + + len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap); + + if (len <= 0) { + pr->nvals--; /* reset the latest assigned value */ + return -1; + } + v->len = len + 1; + return 0; +} + +int blkid_probe_set_version(blkid_probe pr, const char *version) +{ + if (pr->probreq & BLKID_PROBREQ_VERSION) + return blkid_probe_set_value(pr, "VERSION", + (unsigned char *) version, strlen(version) + 1); + return 0; +} + +int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...) +{ + int rc = 0; + + if (pr->probreq & BLKID_PROBREQ_VERSION) { + va_list ap; + + va_start(ap, fmt); + rc = blkid_probe_vsprintf_value(pr, "VERSION", fmt, ap); + va_end(ap); + } + return rc; +} + +static int blkid_probe_set_usage(blkid_probe pr, int usage) +{ + char *u = NULL; + + if (usage & BLKID_USAGE_FILESYSTEM) + u = "filesystem"; + else if (usage & BLKID_USAGE_RAID) + u = "raid"; + else if (usage & BLKID_USAGE_CRYPTO) + u = "crypto"; + else if (usage & BLKID_USAGE_OTHER) + u = "other"; + else + u = "unknown"; + + return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1); +} + +int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len) +{ + struct blkid_prval *v; + int i; + + if (len > BLKID_PROBVAL_BUFSIZ) + len = BLKID_PROBVAL_BUFSIZ; + + if ((pr->probreq & BLKID_PROBREQ_LABELRAW) && + blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0) + return -1; + if (!(pr->probreq & BLKID_PROBREQ_LABEL)) + return 0; + v = blkid_probe_assign_value(pr, "LABEL"); + if (!v) + return -1; + + memcpy(v->data, label, len); + v->data[len] = '\0'; + + /* remove trailing whitespace */ + i = strnlen((char *) v->data, len); + while (i--) { + if (!isspace(v->data[i])) + break; + } + v->data[++i] = '\0'; + v->len = i + 1; + return 0; +} + +static size_t encode_to_utf8(int enc, unsigned char *dest, size_t len, + unsigned char *src, size_t count) +{ + size_t i, j; + uint16_t c; + + for (j = i = 0; i + 2 <= count; i += 2) { + if (enc == BLKID_ENC_UTF16LE) + c = (src[i+1] << 8) | src[i]; + else /* BLKID_ENC_UTF16BE */ + c = (src[i] << 8) | src[i+1]; + if (c == 0) { + dest[j] = '\0'; + break; + } else if (c < 0x80) { + if (j+1 >= len) + break; + dest[j++] = (uint8_t) c; + } else if (c < 0x800) { + if (j+2 >= len) + break; + dest[j++] = (uint8_t) (0xc0 | (c >> 6)); + dest[j++] = (uint8_t) (0x80 | (c & 0x3f)); + } else { + if (j+3 >= len) + break; + dest[j++] = (uint8_t) (0xe0 | (c >> 12)); + dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); + dest[j++] = (uint8_t) (0x80 | (c & 0x3f)); + } + } + dest[j] = '\0'; + return j; +} + +int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label, + size_t len, int enc) +{ + struct blkid_prval *v; + + if ((pr->probreq & BLKID_PROBREQ_LABELRAW) && + blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0) + return -1; + if (!(pr->probreq & BLKID_PROBREQ_LABEL)) + return 0; + v = blkid_probe_assign_value(pr, "LABEL"); + if (!v) + return -1; + + v->len = encode_to_utf8(enc, v->data, sizeof(v->data), label, len); + return 0; +} + +/* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */ +static int uuid_is_empty(const unsigned char *buf, size_t len) +{ + int i; + + for (i = 0; i < len; i++) + if (buf[i]) + return 0; + return 1; +} + +int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid, + size_t len, const char *fmt, ...) +{ + int rc = -1; + va_list ap; + + if (len > BLKID_PROBVAL_BUFSIZ) + len = BLKID_PROBVAL_BUFSIZ; + + if (uuid_is_empty(uuid, len)) + return 0; + + if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) && + blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0) + return -1; + if (!(pr->probreq & BLKID_PROBREQ_UUID)) + return 0; + + va_start(ap, fmt); + rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap); + va_end(ap); + + /* convert to lower case (..be paranoid) */ + if (!rc) { + int i; + struct blkid_prval *v = &pr->vals[pr->nvals]; + + for (i = 0; i < v->len; i++) + if (v->data[i] >= 'A' && v->data[i] <= 'F') + v->data[i] = (v->data[i] - 'A') + 'a'; + } + return rc; +} + +/* function to set UUIDs that are in suberblocks stored as strings */ +int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len) +{ + struct blkid_prval *v; + + if (str == NULL || *str == '\0') + return -1; + if (!len) + len = strlen((char *) str); + if (len > BLKID_PROBVAL_BUFSIZ) + len = BLKID_PROBVAL_BUFSIZ; + + if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) && + blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0) + return -1; + if (!(pr->probreq & BLKID_PROBREQ_UUID)) + return 0; + + v = blkid_probe_assign_value(pr, "UUID"); + if (v) { + memcpy((char *) v->data, str, len); + *(v->data + len) = '\0'; + v->len = len; + return 0; + } + return -1; +} + +/* default _set_uuid function to set DCE UUIDs */ +int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name) +{ + struct blkid_prval *v; + + if (uuid_is_empty(uuid, 16)) + return 0; + + if (!name) { + if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) && + blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0) + return -1; + if (!(pr->probreq & BLKID_PROBREQ_UUID)) + return 0; + + v = blkid_probe_assign_value(pr, "UUID"); + } else + v = blkid_probe_assign_value(pr, name); + +#ifdef HAVE_LIBUUID + { + uuid_unparse(uuid, (char *) v->data); + v->len = 37; + } +#else + v->len = snprintf(v->data, sizeof(v->data), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], + uuid[6], uuid[7], + uuid[8], uuid[9], + uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]); + v->len++; +#endif + return 0; +} + +int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid) +{ + return blkid_probe_set_uuid_as(pr, uuid, NULL); +} + +int blkid_probe_get_value(blkid_probe pr, int num, const char **name, + const char **data, size_t *len) +{ + struct blkid_prval *v; + + if (pr == NULL || num < 0 || num >= pr->nvals) + return -1; + + v = &pr->vals[num]; + if (name) + *name = v->name; + if (data) + *data = (char *) v->data; + if (len) + *len = v->len; + + DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); + return 0; +} + +int blkid_probe_lookup_value(blkid_probe pr, const char *name, + const char **data, size_t *len) +{ + int i; + + if (pr == NULL || pr->nvals == 0 || name == NULL) + return -1; + + for (i = 0; i < pr->nvals; i++) { + struct blkid_prval *v = &pr->vals[i]; + + if (v->name && strcmp(name, v->name) == 0) { + if (data) + *data = (char *) v->data; + if (len) + *len = v->len; + DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); + return 0; + } + } + return -1; +} + +int blkid_probe_has_value(blkid_probe pr, const char *name) +{ + if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0) + return 1; + return 0; +} + diff --git a/shlibs/blkid/src/probers/Makefile.am b/shlibs/blkid/src/probers/Makefile.am new file mode 100644 index 00000000..4591db6a --- /dev/null +++ b/shlibs/blkid/src/probers/Makefile.am @@ -0,0 +1,43 @@ +include $(top_srcdir)/config/include-Makefile.am + +AM_CPPFLAGS += -I$(ul_libblkid_srcdir) + +noinst_LTLIBRARIES = libblkid_probers.la +libblkid_probers_la_SOURCES = \ + probers.h \ + cramfs.c \ + swap.c \ + adaptec_raid.c \ + ddf_raid.c \ + isw_raid.c \ + jmicron_raid.c \ + lsi_raid.c \ + nvidia_raid.c \ + promise_raid.c \ + silicon_raid.c \ + via_raid.c \ + linux_raid.c \ + jfs.c \ + xfs.c \ + ext.c \ + gfs.c \ + ocfs.c \ + reiserfs.c \ + romfs.c \ + ntfs.c \ + hfs.c \ + iso9660.c \ + udf.c \ + vfat.c \ + luks.c \ + highpoint_raid.c \ + vxfs.c \ + minix.c \ + ufs.c \ + hpfs.c \ + squashfs.c \ + netware.c \ + sysv.c \ + btrfs.c \ + lvm.c \ + zfs.c diff --git a/shlibs/blkid/src/probers/adaptec_raid.c b/shlibs/blkid/src/probers/adaptec_raid.c new file mode 100644 index 00000000..5e8b3a75 --- /dev/null +++ b/shlibs/blkid/src/probers/adaptec_raid.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct adaptec_metadata { + uint32_t b0idcode; + uint8_t lunsave[8]; + uint16_t sdtype; + uint16_t ssavecyl; + uint8_t ssavehed; + uint8_t ssavesec; + uint8_t sb0flags; + uint8_t jbodEnable; + uint8_t lundsave; + uint8_t svpdirty; + uint16_t biosInfo; + uint16_t svwbskip; + uint16_t svwbcln; + uint16_t svwbmax; + uint16_t res3; + uint16_t svwbmin; + uint16_t res4; + uint16_t svrcacth; + uint16_t svwcacth; + uint16_t svwbdly; + uint8_t svsdtime; + uint8_t res5; + uint16_t firmval; + uint16_t firmbln; + uint32_t firmblk; + uint32_t fstrsvrb; + uint16_t svBlockStorageTid; + uint16_t svtid; + uint8_t svseccfl; + uint8_t res6; + uint8_t svhbanum; + uint8_t resver; + uint32_t drivemagic; + uint8_t reserved[20]; + uint8_t testnum; + uint8_t testflags; + uint16_t maxErrorCount; + uint32_t count; + uint32_t startTime; + uint32_t interval; + uint8_t tstxt0; + uint8_t tstxt1; + uint8_t serNum[32]; + uint8_t res8[102]; + uint32_t fwTestMagic; + uint32_t fwTestSeqNum; + uint8_t fwTestRes[8]; + uint8_t smagic[4]; + uint32_t raidtbl; + uint16_t raidline; + uint8_t res9[0xF6]; +}; + +#define AD_SIGNATURE "DPTM" +#define AD_MAGIC 0x37FC4D1E + +static int probe_adraid(blkid_probe pr, const struct blkid_idmag *mag) +{ + uint64_t off; + struct adaptec_metadata *ad; + + if (pr->size < 0x10000) + return -1; + + off = ((pr->size / 0x200)-1) * 0x200; + ad = (struct adaptec_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct adaptec_metadata)); + if (!ad) + return -1; + if (memcmp(ad->smagic, AD_SIGNATURE, sizeof(AD_SIGNATURE)) != 0) + return -1; + if (ad->b0idcode != be32_to_cpu(AD_MAGIC)) + return -1; + if (blkid_probe_sprintf_version(pr, "%u", ad->resver) != 0) + return -1; + + return 0; +} + +const struct blkid_idinfo adraid_idinfo = { + .name = "adaptec_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_adraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/shlibs/blkid/src/probers/btrfs.c b/shlibs/blkid/src/probers/btrfs.c new file mode 100644 index 00000000..3205e3d9 --- /dev/null +++ b/shlibs/blkid/src/probers/btrfs.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct btrfs_super_block { + uint8_t csum[32]; + uint8_t fsid[16]; + uint64_t bytenr; + uint64_t flags; + uint8_t magic[8]; + uint64_t generation; + uint64_t root; + uint64_t chunk_root; + uint64_t log_root; + uint64_t log_root_transid; + uint64_t total_bytes; + uint64_t bytes_used; + uint64_t root_dir_objectid; + uint64_t num_devices; + uint32_t sectorsize; + uint32_t nodesize; + uint32_t leafsize; + uint32_t stripesize; + uint32_t sys_chunk_array_size; + uint64_t chunk_root_generation; + uint64_t compat_flags; + uint64_t compat_ro_flags; + uint64_t incompat_flags; + uint16_t csum_type; + uint8_t root_level; + uint8_t chunk_root_level; + uint8_t log_root_level; + struct btrfs_dev_item { + uint64_t devid; + uint64_t total_bytes; + uint64_t bytes_used; + uint32_t io_align; + uint32_t io_width; + uint32_t sector_size; + uint64_t type; + uint64_t generation; + uint64_t start_offset; + uint32_t dev_group; + uint8_t seek_speed; + uint8_t bandwidth; + uint8_t uuid[16]; + uint8_t fsid[16]; + } __attribute__ ((__packed__)) dev_item; + uint8_t label[256]; +} __attribute__ ((__packed__)); + +static int probe_btrfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct btrfs_super_block *bfs; + + bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block); + if (!bfs) + return -1; + + if (*bfs->label) + blkid_probe_set_label(pr, + (unsigned char *) bfs->label, + sizeof(bfs->label)); + + blkid_probe_set_uuid(pr, bfs->fsid); + blkid_probe_set_uuid_as(pr, bfs->dev_item.uuid, "UUID_SUB"); + + return 0; +} + +const struct blkid_idinfo btrfs_idinfo = +{ + .name = "btrfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_btrfs, + .magics = + { + { .magic = "_BHRfS_M", .len = 8, .kboff = 64, .sboff = 0x40 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/cramfs.c b/shlibs/blkid/src/probers/cramfs.c new file mode 100644 index 00000000..0ea124b3 --- /dev/null +++ b/shlibs/blkid/src/probers/cramfs.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct cramfs_super +{ + uint8_t magic[4]; + uint32_t size; + uint32_t flags; + uint32_t future; + uint8_t signature[16]; + struct cramfs_info + { + uint32_t crc; + uint32_t edition; + uint32_t blocks; + uint32_t files; + } info; + uint8_t name[16]; +}; + +static int probe_cramfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct cramfs_super *cs; + + cs = blkid_probe_get_sb(pr, mag, struct cramfs_super); + if (!cs) + return -1; + + blkid_probe_set_label(pr, cs->name, sizeof(cs->name)); + return 0; +} + +const struct blkid_idinfo cramfs_idinfo = +{ + .name = "cramfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_cramfs, + .magics = + { + { "\x45\x3d\xcd\x28", 4, 0, 0 }, + { "\x28\xcd\x3d\x45", 4, 0, 0 }, + { NULL } + } +}; + + diff --git a/shlibs/blkid/src/probers/ddf_raid.c b/shlibs/blkid/src/probers/ddf_raid.c new file mode 100644 index 00000000..41d6e123 --- /dev/null +++ b/shlibs/blkid/src/probers/ddf_raid.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +/* http://www.snia.org/standards/home */ +#define DDF_GUID_LENGTH 24 +#define DDF_REV_LENGTH 8 + +struct ddf_header { + uint8_t signature[4]; + uint32_t crc; + uint8_t guid[DDF_GUID_LENGTH]; + uint8_t ddf_rev[DDF_REV_LENGTH]; +} __attribute__((packed)); + +static int probe_ddf(blkid_probe pr, const struct blkid_idmag *mag) +{ + int hdrs[] = { 1, 257 }; + int i; + struct ddf_header *ddf = NULL; + char version[DDF_REV_LENGTH + 1]; + + if (pr->size < 0x30000) + return -1; + + for (i = 0; i < ARRAY_SIZE(hdrs); i++) { + uint64_t off = ((pr->size / 0x200) - hdrs[i]) * 0x200; + + ddf = (struct ddf_header *) blkid_probe_get_buffer(pr, + off, + sizeof(struct ddf_header)); + if (!ddf) + return -1; + + if (memcmp(ddf->signature, "\x11\xde\x11\xde", 4) == 0 || + memcmp(ddf->signature, "\xde\x11\xde\x11", 4) == 0) + break; + ddf = NULL; + } + + if (!ddf) + return -1; + + blkid_probe_strncpy_uuid(pr, ddf->guid, sizeof(ddf->guid)); + + memcpy(version, ddf->ddf_rev, sizeof(ddf->ddf_rev)); + *(version + sizeof(ddf->ddf_rev)) = '\0'; + + if (blkid_probe_set_version(pr, version) != 0) + return -1; + return 0; +} + +const struct blkid_idinfo ddfraid_idinfo = { + .name = "ddf_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_ddf, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/shlibs/blkid/src/probers/ext.c b/shlibs/blkid/src/probers/ext.c new file mode 100644 index 00000000..671e556c --- /dev/null +++ b/shlibs/blkid/src/probers/ext.c @@ -0,0 +1,571 @@ +/* + * Copyright (C) 1999, 2001 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> +#ifdef __linux__ +#include <sys/utsname.h> +#endif +#include <time.h> + +#include "linux_version.h" +#include "blkidP.h" + +struct ext2_super_block { + uint32_t s_inodes_count; + uint32_t s_blocks_count; + uint32_t s_r_blocks_count; + uint32_t s_free_blocks_count; + uint32_t s_free_inodes_count; + uint32_t s_first_data_block; + uint32_t s_log_block_size; + uint32_t s_dummy3[7]; + unsigned char s_magic[2]; + uint16_t s_state; + uint16_t s_errors; + uint16_t s_minor_rev_level; + uint32_t s_lastcheck; + uint32_t s_checkinterval; + uint32_t s_creator_os; + uint32_t s_rev_level; + uint16_t s_def_resuid; + uint16_t s_def_resgid; + uint32_t s_first_ino; + uint16_t s_inode_size; + uint16_t s_block_group_nr; + uint32_t s_feature_compat; + uint32_t s_feature_incompat; + uint32_t s_feature_ro_compat; + unsigned char s_uuid[16]; + char s_volume_name[16]; + char s_last_mounted[64]; + uint32_t s_algorithm_usage_bitmap; + uint8_t s_prealloc_blocks; + uint8_t s_prealloc_dir_blocks; + uint16_t s_reserved_gdt_blocks; + uint8_t s_journal_uuid[16]; + uint32_t s_journal_inum; + uint32_t s_journal_dev; + uint32_t s_last_orphan; + uint32_t s_hash_seed[4]; + uint8_t s_def_hash_version; + uint8_t s_jnl_backup_type; + uint16_t s_reserved_word_pad; + uint32_t s_default_mount_opts; + uint32_t s_first_meta_bg; + uint32_t s_mkfs_time; + uint32_t s_jnl_blocks[17]; + uint32_t s_blocks_count_hi; + uint32_t s_r_blocks_count_hi; + uint32_t s_free_blocks_hi; + uint16_t s_min_extra_isize; + uint16_t s_want_extra_isize; + uint32_t s_flags; + uint16_t s_raid_stride; + uint16_t s_mmp_interval; + uint64_t s_mmp_block; + uint32_t s_raid_stripe_width; + uint32_t s_reserved[163]; +}; + +/* magic string */ +#define EXT_SB_MAGIC "\123\357" +/* supper block offset */ +#define EXT_SB_OFF 0x400 +/* supper block offset in kB */ +#define EXT_SB_KBOFF (EXT_SB_OFF >> 10) +/* magic string offset within super block */ +#define EXT_MAG_OFF 0x38 + + + +/* for s_flags */ +#define EXT2_FLAGS_TEST_FILESYS 0x0004 + +/* for s_feature_compat */ +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 + +/* for s_feature_ro_compat */ +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 +#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 +#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 +#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 + +/* for s_feature_incompat */ +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 +#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 + +#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT2_FEATURE_INCOMPAT_META_BG) +#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP +#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP + +#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT3_FEATURE_INCOMPAT_RECOVER| \ + EXT2_FEATURE_INCOMPAT_META_BG) +#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED ~EXT3_FEATURE_INCOMPAT_SUPP +#define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT3_FEATURE_RO_COMPAT_SUPP + + +#ifdef FUCK + +/* 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) + +#endif + +/* + * Check to see if a filesystem is in /proc/filesystems. + * Returns 1 if found, 0 if not + */ +static int fs_proc_check(const char *fs_name) +{ + FILE *f; + char buf[80], *cp, *t; + + f = fopen("/proc/filesystems", "r"); + if (!f) + return 0; + while (!feof(f)) { + if (!fgets(buf, sizeof(buf), f)) + break; + cp = buf; + if (!isspace(*cp)) { + while (*cp && !isspace(*cp)) + cp++; + } + while (*cp && isspace(*cp)) + cp++; + if ((t = strchr(cp, '\n')) != NULL) + *t = 0; + if ((t = strchr(cp, '\t')) != NULL) + *t = 0; + if ((t = strchr(cp, ' ')) != NULL) + *t = 0; + if (!strcmp(fs_name, cp)) { + fclose(f); + return 1; + } + } + fclose(f); + return (0); +} + +/* + * Check to see if a filesystem is available as a module + * Returns 1 if found, 0 if not + */ +static int check_for_modules(const char *fs_name) +{ +#ifdef __linux__ + struct utsname uts; + FILE *f; + char buf[1024], *cp, *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) + continue; + cp++; + i = strlen(cp); + if (i > 3) { + t = cp + i - 3; + if (!strcmp(t, ".ko")) + *t = 0; + } + if (!strcmp(cp, fs_name)) { + fclose(f); + return 1; + } + } + fclose(f); +#endif /* __linux__ */ + return 0; +} + +/* + * Starting in 2.6.29, ext4 can be used to support filesystems + * without a journal. + */ +#define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29) + +static int system_supports_ext2(void) +{ + static time_t last_check = 0; + static int ret = -1; + time_t now = time(0); + + if (ret != -1 || (now - last_check) < 5) + return ret; + last_check = now; + ret = (fs_proc_check("ext2") || check_for_modules("ext2")); + return ret; +} + +static int system_supports_ext4(void) +{ + static time_t last_check = 0; + static int ret = -1; + time_t now = time(0); + + if (ret != -1 || (now - last_check) < 5) + return ret; + last_check = now; + ret = (fs_proc_check("ext4") || check_for_modules("ext4")); + return ret; +} + +static int system_supports_ext4dev(void) +{ + static time_t last_check = 0; + static int ret = -1; + time_t now = time(0); + + if (ret != -1 || (now - last_check) < 5) + return ret; + last_check = now; + ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev")); + return ret; +} +/* + * reads superblock and returns: + * fc = feature_compat + * fi = feature_incompat + * frc = feature_ro_compat + */ +static struct ext2_super_block *ext_get_super( + blkid_probe pr, uint32_t *fc, uint32_t *fi, uint32_t *frc) +{ + struct ext2_super_block *es; + + es = (struct ext2_super_block *) + blkid_probe_get_buffer(pr, EXT_SB_OFF, 0x200); + if (!es) + return NULL; + if (fc) + *fc = le32_to_cpu(es->s_feature_compat); + if (fi) + *fi = le32_to_cpu(es->s_feature_incompat); + if (frc) + *frc = le32_to_cpu(es->s_feature_ro_compat); + + return es; +} + +static void ext_get_info(blkid_probe pr, int ver, struct ext2_super_block *es) +{ + DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n", + le32_to_cpu(es->s_feature_compat), + le32_to_cpu(es->s_feature_incompat), + le32_to_cpu(es->s_feature_ro_compat))); + + if (strlen(es->s_volume_name)) + blkid_probe_set_label(pr, (unsigned char *) es->s_volume_name, + sizeof(es->s_volume_name)); + blkid_probe_set_uuid(pr, es->s_uuid); + + if (le32_to_cpu(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) + blkid_probe_set_uuid_as(pr, es->s_journal_uuid, "EXT_JOURNAL"); + + if (ver != 2 && (pr->probreq & BLKID_PROBREQ_SECTYPE) && + ((le32_to_cpu(es->s_feature_incompat) & EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0)) + blkid_probe_set_value(pr, "SEC_TYPE", + (unsigned char *) "ext2", + sizeof("ext2")); + + blkid_probe_sprintf_version(pr, "%u.%u", + le32_to_cpu(es->s_rev_level), + le16_to_cpu(es->s_minor_rev_level)); +} + + +static int probe_jbd(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ext2_super_block *es; + uint32_t fi; + + es = ext_get_super(pr, NULL, &fi, NULL); + if (!es) + return -BLKID_ERR_PARAM; + if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) + return -BLKID_ERR_PARAM; + + ext_get_info(pr, 2, es); + return 0; +} + +static int probe_ext2(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ext2_super_block *es; + uint32_t fc, frc, fi; + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) + return -BLKID_ERR_PARAM; + + /* Distinguish between ext3 and ext2 */ + if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) + return -BLKID_ERR_PARAM; + + /* Any features which ext2 doesn't understand */ + if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) || + (fi & EXT2_FEATURE_INCOMPAT_UNSUPPORTED)) + return -BLKID_ERR_PARAM; + + /* + * If ext2 is not present, but ext4 or ext4dev are, then + * disclaim we are ext2 + */ + if (!system_supports_ext2() && + (system_supports_ext4() || system_supports_ext4dev()) && + get_linux_version() >= EXT4_SUPPORTS_EXT2) + return -BLKID_ERR_PARAM; + + ext_get_info(pr, 2, es); + return 0; +} + +static int probe_ext3(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ext2_super_block *es; + uint32_t fc, frc, fi; + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) + return -BLKID_ERR_PARAM; + + /* ext3 requires journal */ + if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) + return -BLKID_ERR_PARAM; + + /* Any features which ext3 doesn't understand */ + if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) || + (fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) + return -BLKID_ERR_PARAM; + + ext_get_info(pr, 3, es); + return 0; +} + + +static int probe_ext4dev(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ext2_super_block *es; + uint32_t fc, frc, fi; + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) + return -BLKID_ERR_PARAM; + + /* Distinguish from jbd */ + if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + return -BLKID_ERR_PARAM; + + /* + * If the filesystem does not have a journal and ext2 and ext4 + * is not present, then force this to be detected as an + * ext4dev filesystem. + */ + if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && + !system_supports_ext2() && !system_supports_ext4() && + system_supports_ext4dev() && + get_linux_version() >= EXT4_SUPPORTS_EXT2) + goto force_ext4dev; + + /* + * If the filesystem is marked as OK for use by in-development + * filesystem code, but ext4dev is not supported, and ext4 is, + * then don't call ourselves ext4dev, since we should be + * detected as ext4 in that case. + * + * If the filesystem is marked as in use by production + * filesystem, then it can only be used by ext4 and NOT by + * ext4dev, so always disclaim we are ext4dev in that case. + */ + if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { + if (!system_supports_ext4dev() && system_supports_ext4()) + return -BLKID_ERR_PARAM; + } else + return -BLKID_ERR_PARAM; + +force_ext4dev: + ext_get_info(pr, 4, es); + return 0; +} + +static int probe_ext4(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ext2_super_block *es; + uint32_t fc, frc, fi; + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) + return -1; + + /* Distinguish from jbd */ + if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + return -BLKID_ERR_PARAM; + + /* Ext4 has at least one feature which ext3 doesn't understand */ + if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) && + !(fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) + return -BLKID_ERR_PARAM; + + /* + * If the filesystem does not have a journal and ext2 is not + * present, then force this to be detected as an ext2 + * filesystem. + */ + if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && + !system_supports_ext2() && system_supports_ext4() && + get_linux_version() >= EXT4_SUPPORTS_EXT2) + goto force_ext4; + + /* + * If the filesystem is a OK for use by in-development + * filesystem code, and ext4dev is supported or ext4 is not + * supported, then don't call ourselves ext4, so we can redo + * the detection and mark the filesystem as ext4dev. + * + * If the filesystem is marked as in use by production + * filesystem, then it can only be used by ext4 and NOT by + * ext4dev. + */ + if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { + if (system_supports_ext4dev() || !system_supports_ext4()) + return -BLKID_ERR_PARAM; + } + +force_ext4: + ext_get_info(pr, 4, es); + return 0; +} + +#define BLKID_EXT_MAGICS \ + { \ + { \ + .magic = EXT_SB_MAGIC, \ + .len = sizeof(EXT_SB_MAGIC) - 1, \ + .kboff = EXT_SB_KBOFF, \ + .sboff = EXT_MAG_OFF \ + }, \ + { NULL } \ + } + +const struct blkid_idinfo jbd_idinfo = +{ + .name = "jbd", + .usage = BLKID_USAGE_OTHER, + .probefunc = probe_jbd, + .magics = BLKID_EXT_MAGICS +}; + +const struct blkid_idinfo ext2_idinfo = +{ + .name = "ext2", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ext2, + .magics = BLKID_EXT_MAGICS +}; + +const struct blkid_idinfo ext3_idinfo = +{ + .name = "ext3", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ext3, + .magics = BLKID_EXT_MAGICS +}; + +const struct blkid_idinfo ext4_idinfo = +{ + .name = "ext4", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ext4, + .magics = BLKID_EXT_MAGICS +}; + +const struct blkid_idinfo ext4dev_idinfo = +{ + .name = "ext4dev", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ext4dev, + .magics = BLKID_EXT_MAGICS +}; + diff --git a/shlibs/blkid/src/probers/gfs.c b/shlibs/blkid/src/probers/gfs.c new file mode 100644 index 00000000..584561cf --- /dev/null +++ b/shlibs/blkid/src/probers/gfs.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +/* Common gfs/gfs2 constants: */ +#define GFS_LOCKNAME_LEN 64 + +/* gfs1 constants: */ +#define GFS_FORMAT_FS 1309 +#define GFS_FORMAT_MULTI 1401 +/* gfs2 constants: */ +#define GFS2_FORMAT_FS 1801 +#define GFS2_FORMAT_MULTI 1900 + +struct gfs2_meta_header { + uint32_t mh_magic; + uint32_t mh_type; + uint64_t __pad0; /* Was generation number in gfs1 */ + uint32_t mh_format; + uint32_t __pad1; /* Was incarnation number in gfs1 */ +}; + +struct gfs2_inum { + uint64_t no_formal_ino; + uint64_t no_addr; +}; + +struct gfs2_sb { + struct gfs2_meta_header sb_header; + + uint32_t sb_fs_format; + uint32_t sb_multihost_format; + uint32_t __pad0; /* Was superblock flags in gfs1 */ + + uint32_t sb_bsize; + uint32_t sb_bsize_shift; + uint32_t __pad1; /* Was journal segment size in gfs1 */ + + struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ + struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */ + struct gfs2_inum sb_root_dir; + + char sb_lockproto[GFS_LOCKNAME_LEN]; + char sb_locktable[GFS_LOCKNAME_LEN]; + + struct gfs2_inum __pad3; /* Was quota inode in gfs1 */ + struct gfs2_inum __pad4; /* Was licence inode in gfs1 */ + uint8_t sb_uuid[16]; /* The UUID maybe 0 for backwards compat */ +}; + +static int probe_gfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct gfs2_sb *sbd; + + sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb); + if (!sbd) + return -1; + + if (be32_to_cpu(sbd->sb_fs_format) == GFS_FORMAT_FS && + be32_to_cpu(sbd->sb_multihost_format) == GFS_FORMAT_MULTI) + { + if (*sbd->sb_locktable) + blkid_probe_set_label(pr, + (unsigned char *) sbd->sb_locktable, + sizeof(sbd->sb_locktable)); + + blkid_probe_set_uuid(pr, sbd->sb_uuid); + return 0; + } + + return -1; +} + +static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct gfs2_sb *sbd; + + sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb); + if (!sbd) + return -1; + + if (be32_to_cpu(sbd->sb_fs_format) == GFS2_FORMAT_FS && + be32_to_cpu(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI) + { + if (*sbd->sb_locktable) + blkid_probe_set_label(pr, + (unsigned char *) sbd->sb_locktable, + sizeof(sbd->sb_locktable)); + blkid_probe_set_uuid(pr, sbd->sb_uuid); + blkid_probe_set_version(pr, "1"); + return 0; + } + return -1; +} + +const struct blkid_idinfo gfs_idinfo = +{ + .name = "gfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_gfs, + .magics = + { + { .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 }, + { NULL } + } +}; + +const struct blkid_idinfo gfs2_idinfo = +{ + .name = "gfs2", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_gfs2, + .magics = + { + { .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/hfs.c b/shlibs/blkid/src/probers/hfs.c new file mode 100644 index 00000000..4cdef0ee --- /dev/null +++ b/shlibs/blkid/src/probers/hfs.c @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <inttypes.h> + +#include "blkidP.h" +#include "md5.h" + +/* HFS / HFS+ */ +struct hfs_finder_info { + uint32_t boot_folder; + uint32_t start_app; + uint32_t open_folder; + uint32_t os9_folder; + uint32_t reserved; + uint32_t osx_folder; + uint8_t id[8]; +} __attribute__((packed)); + +struct hfs_mdb { + uint8_t signature[2]; + uint32_t cr_date; + uint32_t ls_Mod; + uint16_t atrb; + uint16_t nm_fls; + uint16_t vbm_st; + uint16_t alloc_ptr; + uint16_t nm_al_blks; + uint32_t al_blk_size; + uint32_t clp_size; + uint16_t al_bl_st; + uint32_t nxt_cnid; + uint16_t free_bks; + uint8_t label_len; + uint8_t label[27]; + uint32_t vol_bkup; + uint16_t vol_seq_num; + uint32_t wr_cnt; + uint32_t xt_clump_size; + uint32_t ct_clump_size; + uint16_t num_root_dirs; + uint32_t file_count; + uint32_t dir_count; + struct hfs_finder_info finder_info; + uint8_t embed_sig[2]; + uint16_t embed_startblock; + uint16_t embed_blockcount; +} __attribute__((packed)); + + +#define HFS_NODE_LEAF 0xff +#define HFSPLUS_POR_CNID 1 + +struct hfsplus_bnode_descriptor { + uint32_t next; + uint32_t prev; + uint8_t type; + uint8_t height; + uint16_t num_recs; + uint16_t reserved; +} __attribute__((packed)); + +struct hfsplus_bheader_record { + uint16_t depth; + uint32_t root; + uint32_t leaf_count; + uint32_t leaf_head; + uint32_t leaf_tail; + uint16_t node_size; +} __attribute__((packed)); + +struct hfsplus_catalog_key { + uint16_t key_len; + uint32_t parent_id; + uint16_t unicode_len; + uint8_t unicode[255 * 2]; +} __attribute__((packed)); + +struct hfsplus_extent { + uint32_t start_block; + uint32_t block_count; +} __attribute__((packed)); + +#define HFSPLUS_EXTENT_COUNT 8 +struct hfsplus_fork { + uint64_t total_size; + uint32_t clump_size; + uint32_t total_blocks; + struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; +} __attribute__((packed)); + +struct hfsplus_vol_header { + uint8_t signature[2]; + uint16_t version; + uint32_t attributes; + uint32_t last_mount_vers; + uint32_t reserved; + uint32_t create_date; + uint32_t modify_date; + uint32_t backup_date; + uint32_t checked_date; + uint32_t file_count; + uint32_t folder_count; + uint32_t blocksize; + uint32_t total_blocks; + uint32_t free_blocks; + uint32_t next_alloc; + uint32_t rsrc_clump_sz; + uint32_t data_clump_sz; + uint32_t next_cnid; + uint32_t write_count; + uint64_t encodings_bmp; + struct hfs_finder_info finder_info; + struct hfsplus_fork alloc_file; + struct hfsplus_fork ext_file; + struct hfsplus_fork cat_file; + struct hfsplus_fork attr_file; + struct hfsplus_fork start_file; +} __attribute__((packed)); + +static int hfs_set_uuid(blkid_probe pr, unsigned char const *hfs_info, size_t len) +{ + static unsigned char const hash_init[16] = { + 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6, + 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac + }; + unsigned char uuid[16]; + struct MD5Context md5c; + + if (memcmp(hfs_info, "\0\0\0\0\0\0\0\0", len) == 0) + return -1; + MD5Init(&md5c); + MD5Update(&md5c, hash_init, 16); + MD5Update(&md5c, hfs_info, len); + MD5Final(uuid, &md5c); + uuid[6] = 0x30 | (uuid[6] & 0x0f); + uuid[8] = 0x80 | (uuid[8] & 0x3f); + return blkid_probe_set_uuid(pr, uuid); +} + +static int probe_hfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct hfs_mdb *hfs; + + hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb); + if (!hfs) + return -1; + + if ((memcmp(hfs->embed_sig, "H+", 2) == 0) || + (memcmp(hfs->embed_sig, "HX", 2) == 0)) + return 1; /* Not hfs, but an embedded HFS+ */ + + hfs_set_uuid(pr, hfs->finder_info.id, sizeof(hfs->finder_info.id)); + + blkid_probe_set_label(pr, hfs->label, hfs->label_len); + return 0; +} + +static int probe_hfsplus(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; + struct hfsplus_bnode_descriptor *descr; + struct hfsplus_bheader_record *bnode; + struct hfsplus_catalog_key *key; + struct hfsplus_vol_header *hfsplus; + struct hfs_mdb *sbd; + unsigned int alloc_block_size; + unsigned int alloc_first_block; + unsigned int embed_first_block; + unsigned int off = 0; + unsigned int blocksize; + unsigned int cat_block; + unsigned int ext_block_start; + unsigned int ext_block_count; + unsigned int record_count; + unsigned int leaf_node_head; + unsigned int leaf_node_count; + unsigned int leaf_node_size; + unsigned int leaf_block; + int ext; + uint64_t leaf_off; + unsigned char *buf; + + sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb); + if (!sbd) + return -1; + + /* Check for a HFS+ volume embedded in a HFS volume */ + if (memcmp(sbd->signature, "BD", 2) == 0) { + if ((memcmp(sbd->embed_sig, "H+", 2) != 0) && + (memcmp(sbd->embed_sig, "HX", 2) != 0)) + /* This must be an HFS volume, so fail */ + return 1; + + alloc_block_size = be32_to_cpu(sbd->al_blk_size); + alloc_first_block = be16_to_cpu(sbd->al_bl_st); + embed_first_block = be16_to_cpu(sbd->embed_startblock); + off = (alloc_first_block * 512) + + (embed_first_block * alloc_block_size); + + buf = blkid_probe_get_buffer(pr, + off + (mag->kboff * 1024), + sizeof(struct hfsplus_vol_header)); + hfsplus = (struct hfsplus_vol_header *) buf; + + } else + hfsplus = blkid_probe_get_sb(pr, mag, + struct hfsplus_vol_header); + + if (!hfsplus) + return -1; + + if ((memcmp(hfsplus->signature, "H+", 2) != 0) && + (memcmp(hfsplus->signature, "HX", 2) != 0)) + return 1; + + hfs_set_uuid(pr, hfsplus->finder_info.id, sizeof(hfsplus->finder_info.id)); + + blocksize = be32_to_cpu(hfsplus->blocksize); + memcpy(extents, hfsplus->cat_file.extents, sizeof(extents)); + cat_block = be32_to_cpu(extents[0].start_block); + + buf = blkid_probe_get_buffer(pr, + off + (cat_block * blocksize), 0x2000); + if (!buf) + return 0; + + bnode = (struct hfsplus_bheader_record *) + &buf[sizeof(struct hfsplus_bnode_descriptor)]; + + leaf_node_head = be32_to_cpu(bnode->leaf_head); + leaf_node_size = be16_to_cpu(bnode->node_size); + leaf_node_count = be32_to_cpu(bnode->leaf_count); + if (leaf_node_count == 0) + return 0; + + leaf_block = (leaf_node_head * leaf_node_size) / blocksize; + + /* get physical location */ + for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) { + ext_block_start = be32_to_cpu(extents[ext].start_block); + ext_block_count = be32_to_cpu(extents[ext].block_count); + if (ext_block_count == 0) + return 0; + + /* this is our extent */ + if (leaf_block < ext_block_count) + break; + + leaf_block -= ext_block_count; + } + if (ext == HFSPLUS_EXTENT_COUNT) + return 0; + + leaf_off = (ext_block_start + leaf_block) * blocksize; + + buf = blkid_probe_get_buffer(pr, off + leaf_off, leaf_node_size); + if (!buf) + return 0; + + descr = (struct hfsplus_bnode_descriptor *) buf; + record_count = be16_to_cpu(descr->num_recs); + if (record_count == 0) + return 0; + + if (descr->type != HFS_NODE_LEAF) + return 0; + + key = (struct hfsplus_catalog_key *) + &buf[sizeof(struct hfsplus_bnode_descriptor)]; + + if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID) + return 0; + + blkid_probe_set_utf8label(pr, key->unicode, + be16_to_cpu(key->unicode_len) * 2, + BLKID_ENC_UTF16BE); + return 0; +} + +const struct blkid_idinfo hfs_idinfo = +{ + .name = "hfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_hfs, + .magics = + { + { .magic = "BD", .len = 2, .kboff = 1 }, + { NULL } + } +}; + +const struct blkid_idinfo hfsplus_idinfo = +{ + .name = "hfsplus", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_hfsplus, + .magics = + { + { .magic = "BD", .len = 2, .kboff = 1 }, + { .magic = "H+", .len = 2, .kboff = 1 }, + { .magic = "HX", .len = 2, .kboff = 1 }, + { NULL } + } +}; diff --git a/shlibs/blkid/src/probers/highpoint_raid.c b/shlibs/blkid/src/probers/highpoint_raid.c new file mode 100644 index 00000000..c7c92db4 --- /dev/null +++ b/shlibs/blkid/src/probers/highpoint_raid.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct hpt45x_metadata { + uint32_t magic; +}; + +#define HPT45X_MAGIC_OK 0x5a7816f3 +#define HPT45X_MAGIC_BAD 0x5a7816fd + +static int probe_highpoint45x(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct hpt45x_metadata *hpt; + uint64_t off; + uint32_t magic; + + if (pr->size < 0x10000) + return -1; + + off = ((pr->size / 0x200) - 11) * 0x200; + hpt = (struct hpt45x_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct hpt45x_metadata)); + if (!hpt) + return -1; + magic = le32_to_cpu(hpt->magic); + if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD) + return -1; + return 0; +} + +const struct blkid_idinfo highpoint45x_idinfo = { + .name = "highpoint_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_highpoint45x, + .magics = BLKID_NONE_MAGIC +}; + +const struct blkid_idinfo highpoint37x_idinfo = { + .name = "highpoint_raid_member", + .usage = BLKID_USAGE_RAID, + .magics = { + { .magic = "\xf0\x16\x78\x5a", .len = 4, .kboff = 4 }, + { .magic = "\xfd\x16\x78\x5a", .len = 4, .kboff = 4 }, + { NULL } + } +}; + + diff --git a/shlibs/blkid/src/probers/hpfs.c b/shlibs/blkid/src/probers/hpfs.c new file mode 100644 index 00000000..2f5f0d19 --- /dev/null +++ b/shlibs/blkid/src/probers/hpfs.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct hpfs_boot_block +{ + uint8_t jmp[3]; + uint8_t oem_id[8]; + uint8_t bytes_per_sector[2]; + uint8_t sectors_per_cluster; + uint8_t n_reserved_sectors[2]; + uint8_t n_fats; + uint8_t n_rootdir_entries[2]; + uint8_t n_sectors_s[2]; + uint8_t media_byte; + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t heads_per_cyl; + uint32_t n_hidden_sectors; + uint32_t n_sectors_l; + uint8_t drive_number; + uint8_t mbz; + uint8_t sig_28h; + uint8_t vol_serno[4]; + uint8_t vol_label[11]; + uint8_t sig_hpfs[8]; + uint8_t pad[448]; + uint8_t magic[2]; +}; + +struct hpfs_super_block +{ + uint8_t magic[4]; + uint8_t magic1[4]; + uint8_t version; +}; + +struct hpfs_spare_super +{ + uint8_t magic[4]; + uint8_t magic1[4]; +}; + + +#define HPFS_SB_OFFSET 0x2000 +#define HPFS_SBSPARE_OFFSET 0x2200 + +static int probe_hpfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct hpfs_super_block *hs; + struct hpfs_spare_super *hss; + struct hpfs_boot_block *hbb; + uint8_t version; + + /* super block */ + hs = blkid_probe_get_sb(pr, mag, struct hpfs_super_block); + if (!hs) + return -1; + version = hs->version; + + /* spare super block */ + hss = (struct hpfs_spare_super *) + blkid_probe_get_buffer(pr, + HPFS_SBSPARE_OFFSET, + sizeof(struct hpfs_spare_super)); + if (!hss) + return -1; + if (memcmp(hss->magic, "\x49\x18\x91\xf9", 4) != 0) + return -1; + + /* boot block (with UUID and LABEL) */ + hbb = (struct hpfs_boot_block *) + blkid_probe_get_buffer(pr, + 0, + sizeof(struct hpfs_boot_block)); + if (!hbb) + return -1; + if (memcmp(hbb->magic, "\x55\xaa", 2) == 0 && + memcmp(hbb->sig_hpfs, "HPFS", 4) == 0 && + hbb->sig_28h == 0x28) { + blkid_probe_set_label(pr, hbb->vol_label, sizeof(hbb->vol_label)); + blkid_probe_sprintf_uuid(pr, + hbb->vol_serno, sizeof(hbb->vol_serno), + "%02X%02X-%02X%02X", + hbb->vol_serno[3], hbb->vol_serno[2], + hbb->vol_serno[1], hbb->vol_serno[0]); + } + blkid_probe_sprintf_version(pr, "%u", version); + + return 0; +} + +const struct blkid_idinfo hpfs_idinfo = +{ + .name = "hpfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_hpfs, + .magics = + { + { + .magic = "\x49\xe8\x95\xf9", + .len = 4, + .kboff = (HPFS_SB_OFFSET >> 10) + }, + { NULL } + } +}; + + diff --git a/shlibs/blkid/src/probers/iso9660.c b/shlibs/blkid/src/probers/iso9660.c new file mode 100644 index 00000000..ca53e3ae --- /dev/null +++ b/shlibs/blkid/src/probers/iso9660.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired also by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +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]; +}; + +#define ISO_SUPERBLOCK_OFFSET 0x8000 +#define ISO_SECTOR_SIZE 0x800 +#define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE) +#define ISO_VD_SUPPLEMENTARY 0x2 +#define ISO_VD_END 0xff +#define ISO_VD_MAX 16 + +struct high_sierra_volume_descriptor { + unsigned char foo[8]; + unsigned char type; + unsigned char id[5]; + unsigned char version; + unsigned char unused1; + unsigned char system_id[32]; + unsigned char volume_id[32]; +}; + +/* old High Sierra format */ +static int probe_iso9660_hsfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct high_sierra_volume_descriptor *iso; + + iso = blkid_probe_get_sb(pr, mag, struct high_sierra_volume_descriptor); + if (!iso) + return -1; + + blkid_probe_set_version(pr, "High Sierra"); + blkid_probe_set_label(pr, iso->volume_id, sizeof(iso->volume_id)); + return 0; +} + +/* iso9660 [+ Microsoft Joliet Extension] */ +static int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct iso_volume_descriptor *iso; + unsigned char label[32]; + int i; + int off; + + if (strcmp(mag->magic, "CDROM") == 0) + return probe_iso9660_hsfs(pr, mag); + + iso = blkid_probe_get_sb(pr, mag, struct iso_volume_descriptor); + if (!iso) + return -1; + + memcpy(label, iso->volume_id, sizeof(label)); + + /* Joliet Extension */ + off = ISO_VD_OFFSET; + for (i = 0; i < ISO_VD_MAX; i++) { + uint8_t svd_label[64]; + + iso = (struct iso_volume_descriptor *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct iso_volume_descriptor)); + + if (iso == NULL || iso->vd_type == ISO_VD_END) + break; + if (iso->vd_type != ISO_VD_SUPPLEMENTARY) + continue; + + if (memcmp(iso->escape_sequences, "%/@", 3) == 0 || + memcmp(iso->escape_sequences, "%/C", 3) == 0 || + memcmp(iso->escape_sequences, "%/E", 3) == 0) { + + blkid_probe_set_utf8label(pr, + iso->volume_id, + sizeof(svd_label), + BLKID_ENC_UTF16BE); + + blkid_probe_set_version(pr, "Joliet Extension"); + goto has_label; + } + off += ISO_SECTOR_SIZE; + } + + /* Joliet not found, let use standard iso label */ + blkid_probe_set_label(pr, label, sizeof(label)); + +has_label: + return 0; +} + + +const struct blkid_idinfo iso9660_idinfo = +{ + .name = "iso9660", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_iso9660, + .flags = BLKID_IDINFO_TOLERANT, + .magics = + { + { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "CDROM", .len = 5, .kboff = 32, .sboff = 9 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/isw_raid.c b/shlibs/blkid/src/probers/isw_raid.c new file mode 100644 index 00000000..f9ae7453 --- /dev/null +++ b/shlibs/blkid/src/probers/isw_raid.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct isw_metadata { + uint8_t sig[32]; + uint32_t check_sum; + uint32_t mpb_size; + uint32_t family_num; + uint32_t generation_num; +}; + +#define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. " + + +static int probe_iswraid(blkid_probe pr, const struct blkid_idmag *mag) +{ + uint64_t off; + struct isw_metadata *isw; + + if (pr->size < 0x10000) + return -1; + + off = ((pr->size / 0x200) - 2) * 0x200; + isw = (struct isw_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct isw_metadata)); + if (!isw) + return -1; + if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0) + return -1; + if (blkid_probe_sprintf_version(pr, "%6s", + &isw->sig[sizeof(ISW_SIGNATURE)-1]) != 0) + return -1; + + return 0; +} + +const struct blkid_idinfo iswraid_idinfo = { + .name = "isw_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_iswraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/shlibs/blkid/src/probers/jfs.c b/shlibs/blkid/src/probers/jfs.c new file mode 100644 index 00000000..5d9b39ac --- /dev/null +++ b/shlibs/blkid/src/probers/jfs.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +struct jfs_super_block { + unsigned char js_magic[4]; + uint32_t js_version; + uint64_t js_size; + uint32_t js_bsize; /* 4: aggregate block size in bytes */ + uint16_t js_l2bsize; /* 2: log2 of s_bsize */ + uint16_t js_l2bfactor; /* 2: log2(s_bsize/hardware block size) */ + uint32_t js_pbsize; /* 4: hardware/LVM block size in bytes */ + uint16_t js_l2pbsize; /* 2: log2 of s_pbsize */ + uint16_t js_pad; /* 2: padding necessary for alignment */ + uint32_t js_dummy2[26]; + unsigned char js_uuid[16]; + unsigned char js_label[16]; + unsigned char js_loguuid[16]; +}; + +static int probe_jfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct jfs_super_block *js; + + js = blkid_probe_get_sb(pr, mag, struct jfs_super_block); + if (!js) + return -1; + if (le32_to_cpu(js->js_bsize) != (1 << le16_to_cpu(js->js_l2bsize))) + return 1; + if (le32_to_cpu(js->js_pbsize) != (1 << le16_to_cpu(js->js_l2pbsize))) + return 1; + if ((le16_to_cpu(js->js_l2bsize) - le16_to_cpu(js->js_l2pbsize)) != + le16_to_cpu(js->js_l2bfactor)) + return 1; + + if (strlen((char *) js->js_label)) + blkid_probe_set_label(pr, js->js_label, sizeof(js->js_label)); + blkid_probe_set_uuid(pr, js->js_uuid); + return 0; +} + + +const struct blkid_idinfo jfs_idinfo = +{ + .name = "jfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_jfs, + .magics = + { + { .magic = "JFS1", .len = 4, .kboff = 32 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/jmicron_raid.c b/shlibs/blkid/src/probers/jmicron_raid.c new file mode 100644 index 00000000..ae852f8f --- /dev/null +++ b/shlibs/blkid/src/probers/jmicron_raid.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct jm_metadata { + int8_t signature[2]; + uint8_t minor_version; + uint8_t major_version; + uint16_t checksum; +}; + +#define JM_SIGNATURE "JM" + +static int probe_jmraid(blkid_probe pr, const struct blkid_idmag *mag) +{ + uint64_t off; + struct jm_metadata *jm; + + if (pr->size < 0x10000) + return -1; + + off = ((pr->size / 0x200) - 1) * 0x200; + jm = (struct jm_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct jm_metadata)); + if (!jm) + return -1; + if (memcmp(jm->signature, JM_SIGNATURE, sizeof(JM_SIGNATURE) - 1) != 0) + return -1; + if (blkid_probe_sprintf_version(pr, "%u.%u", + jm->major_version, jm->minor_version) != 0) + return -1; + + return 0; +} + +const struct blkid_idinfo jmraid_idinfo = { + .name = "jmicron_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_jmraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/shlibs/blkid/src/probers/linux_raid.c b/shlibs/blkid/src/probers/linux_raid.c new file mode 100644 index 00000000..a5926561 --- /dev/null +++ b/shlibs/blkid/src/probers/linux_raid.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct mdp0_super_block { + uint32_t md_magic; + uint32_t major_version; + uint32_t minor_version; + uint32_t patch_version; + uint32_t gvalid_words; + uint32_t set_uuid0; + uint32_t ctime; + uint32_t level; + uint32_t size; + uint32_t nr_disks; + uint32_t raid_disks; + uint32_t md_minor; + uint32_t not_persistent; + uint32_t set_uuid1; + uint32_t set_uuid2; + uint32_t set_uuid3; +}; + +struct mdp1_super_block { + uint32_t magic; + uint32_t major_version; + uint32_t feature_map; + uint32_t pad0; + uint8_t set_uuid[16]; + uint8_t set_name[32]; +}; + +#define MD_RESERVED_BYTES 0x10000 +#define MD_SB_MAGIC 0xa92b4efc + +static int probe_raid0(blkid_probe pr, off_t off) +{ + struct mdp0_super_block *mdp0; + union { + uint32_t ints[4]; + uint8_t bytes[16]; + } uuid; + + if (pr->size < 0x10000) + return -1; + mdp0 = (struct mdp0_super_block *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct mdp0_super_block)); + if (!mdp0) + return -1; + + memset(uuid.ints, 0, sizeof(uuid.ints)); + + if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { + uuid.ints[0] = swab32(mdp0->set_uuid0); + if (le32_to_cpu(mdp0->minor_version >= 90)) { + uuid.ints[1] = swab32(mdp0->set_uuid1); + uuid.ints[2] = swab32(mdp0->set_uuid2); + uuid.ints[3] = swab32(mdp0->set_uuid3); + } + if (blkid_probe_sprintf_version(pr, "%u.%u.%u", + le32_to_cpu(mdp0->major_version), + le32_to_cpu(mdp0->minor_version), + le32_to_cpu(mdp0->patch_version)) != 0) + return -1; + + } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { + uuid.ints[0] = mdp0->set_uuid0; + if (be32_to_cpu(mdp0->minor_version >= 90)) { + uuid.ints[1] = mdp0->set_uuid1; + uuid.ints[2] = mdp0->set_uuid2; + uuid.ints[3] = mdp0->set_uuid3; + } + if (blkid_probe_sprintf_version(pr, "%u.%u.%u", + be32_to_cpu(mdp0->major_version), + be32_to_cpu(mdp0->minor_version), + be32_to_cpu(mdp0->patch_version)) != 0) + return -1; + } else + return -1; + + if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0) + return -1; + + return 0; +} + +static int probe_raid1(blkid_probe pr, off_t off) +{ + struct mdp1_super_block *mdp1; + + mdp1 = (struct mdp1_super_block *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct mdp1_super_block)); + if (!mdp1) + return -1; + if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC) + return -1; + if (le32_to_cpu(mdp1->major_version) != 1) + return -1; + if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0) + return -1; + if (blkid_probe_set_label(pr, mdp1->set_name, + sizeof(mdp1->set_name)) != 0) + return -1; + + return 0; +} + +int probe_raid(blkid_probe pr, const struct blkid_idmag *mag) +{ + const char *ver = NULL; + + if (pr->size > MD_RESERVED_BYTES) { + /* version 0 at the end of the device */ + uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1)) + - MD_RESERVED_BYTES; + if (probe_raid0(pr, sboff) == 0) + return 0; + + /* version 1.0 at the end of the device */ + sboff = (pr->size & ~(0x1000 - 1)) - 0x2000; + if (probe_raid1(pr, sboff) == 0) + ver = "1.0"; + } + + if (!ver) { + /* version 1.1 at the start of the device */ + if (probe_raid1(pr, 0) == 0) + ver = "1.1"; + + /* version 1.2 at 4k offset from the start */ + else if (probe_raid1(pr, 0x1000) == 0) + ver = "1.2"; + } + + if (ver) { + blkid_probe_set_version(pr, ver); + return 0; + } + return -1; +} + + +const struct blkid_idinfo linuxraid_idinfo = { + .name = "linux_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_raid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/shlibs/blkid/src/probers/lsi_raid.c b/shlibs/blkid/src/probers/lsi_raid.c new file mode 100644 index 00000000..d9ac4e12 --- /dev/null +++ b/shlibs/blkid/src/probers/lsi_raid.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct lsi_metadata { + uint8_t sig[6]; +}; + + +#define LSI_SIGNATURE "$XIDE$" + +static int probe_lsiraid(blkid_probe pr, const struct blkid_idmag *mag) +{ + uint64_t off; + struct lsi_metadata *lsi; + + if (pr->size < 0x10000) + return -1; + + off = ((pr->size / 0x200) - 1) * 0x200; + lsi = (struct lsi_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct lsi_metadata)); + if (!lsi) + return -1; + + if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0) + return -1; + + return 0; +} + +const struct blkid_idinfo lsiraid_idinfo = { + .name = "lsi_mega_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_lsiraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/shlibs/blkid/src/probers/luks.c b/shlibs/blkid/src/probers/luks.c new file mode 100644 index 00000000..2fe4ff3b --- /dev/null +++ b/shlibs/blkid/src/probers/luks.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +#define LUKS_CIPHERNAME_L 32 +#define LUKS_CIPHERMODE_L 32 +#define LUKS_HASHSPEC_L 32 +#define LUKS_DIGESTSIZE 20 +#define LUKS_SALTSIZE 32 +#define LUKS_MAGIC_L 6 +#define UUID_STRING_L 40 + +struct luks_phdr { + uint8_t magic[LUKS_MAGIC_L]; + uint16_t version; + uint8_t cipherName[LUKS_CIPHERNAME_L]; + uint8_t cipherMode[LUKS_CIPHERMODE_L]; + uint8_t hashSpec[LUKS_HASHSPEC_L]; + uint32_t payloadOffset; + uint32_t keyBytes; + uint8_t mkDigest[LUKS_DIGESTSIZE]; + uint8_t mkDigestSalt[LUKS_SALTSIZE]; + uint32_t mkDigestIterations; + uint8_t uuid[UUID_STRING_L]; +}; + +static int probe_luks(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct luks_phdr *header; + + header = blkid_probe_get_sb(pr, mag, struct luks_phdr); + if (header == NULL) + return -1; + + blkid_probe_strncpy_uuid(pr, (unsigned char *) header->uuid, + sizeof(header->uuid)); + blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(header->version)); + return 0; +} + +const struct blkid_idinfo luks_idinfo = +{ + .name = "crypto_LUKS", + .usage = BLKID_USAGE_CRYPTO, + .probefunc = probe_luks, + .magics = + { + { .magic = "LUKS\xba\xbe", .len = 6 }, + { NULL } + } +}; diff --git a/shlibs/blkid/src/probers/lvm.c b/shlibs/blkid/src/probers/lvm.c new file mode 100644 index 00000000..d8edc37a --- /dev/null +++ b/shlibs/blkid/src/probers/lvm.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +#define LVM1_ID_LEN 128 +#define LVM2_ID_LEN 32 + +struct lvm2_pv_label_header { + /* label_header */ + uint8_t id[8]; /* LABELONE */ + uint64_t sector_xl; /* Sector number of this label */ + uint32_t crc_xl; /* From next field to end of sector */ + uint32_t offset_xl; /* Offset from start of struct to contents */ + uint8_t type[8]; /* LVM2 001 */ + /* pv_header */ + uint8_t pv_uuid[LVM2_ID_LEN]; +} __attribute__ ((packed)); + +struct lvm1_pv_label_header { + uint8_t id[2]; /* HM */ + uint16_t version; /* version 1 or 2 */ + uint32_t _notused[10]; /* lvm1 internals */ + uint8_t pv_uuid[LVM1_ID_LEN]; +} __attribute__ ((packed)); + +#define LVM2_LABEL_SIZE 512 +static unsigned int lvm2_calc_crc(const void *buf, unsigned int size) +{ + static const unsigned int crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + unsigned int i, crc = 0xf597a6cf; + const uint8_t *data = (const uint8_t *) buf; + + for (i = 0; i < size; i++) { + crc ^= *data++; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + return crc; +} + +/* Length of real UUID is always LVM2_ID_LEN */ +static void format_lvm_uuid(char *dst_uuid, char *src_uuid) +{ + unsigned int i, b; + + for (i = 0, b = 1; i < LVM2_ID_LEN; i++, b <<= 1) { + if (b & 0x4444440) + *dst_uuid++ = '-'; + *dst_uuid++ = *src_uuid++; + } + *dst_uuid = '\0'; +} + +static int probe_lvm2(blkid_probe pr, const struct blkid_idmag *mag) +{ + int sector = mag->kboff << 1; + struct lvm2_pv_label_header *label; + char uuid[LVM2_ID_LEN + 7]; + unsigned char *buf; + + buf = blkid_probe_get_buffer(pr, + mag->kboff << 10, + 512 + sizeof(struct lvm2_pv_label_header)); + if (!buf) + return -1; + + /* buf is at 0k or 1k offset; find label inside */ + if (memcmp(buf, "LABELONE", 8) == 0) { + label = (struct lvm2_pv_label_header *) buf; + } else if (memcmp(buf + 512, "LABELONE", 8) == 0) { + label = (struct lvm2_pv_label_header *)(buf + 512); + sector++; + } else { + return 1; + } + + if (le64_to_cpu(label->sector_xl) != (unsigned) sector) + return 1; + + if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE - + ((char *) &label->offset_xl - (char *) label)) != + le32_to_cpu(label->crc_xl)) { + DBG(DEBUG_PROBE, + printf("LVM2: label checksum incorrect at sector %d\n", + sector)); + return 1; + } + + format_lvm_uuid(uuid, (char *) label->pv_uuid); + blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid), + "%s", uuid); + + /* the mag->magic is the same string as label->type, + * but zero terminated */ + blkid_probe_set_version(pr, mag->magic); + return 0; +} + +static int probe_lvm1(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct lvm1_pv_label_header *label; + char uuid[LVM2_ID_LEN + 7]; + unsigned int version; + + label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header); + if (!label) + return -1; + + version = le16_to_cpu(label->version); + if (version != 1 && version != 2) + return 1; + + format_lvm_uuid(uuid, (char *) label->pv_uuid); + blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid), + "%s", uuid); + + return 0; +} + +/* NOTE: the original libblkid uses "lvm2pv" as a name */ +const struct blkid_idinfo lvm2_idinfo = +{ + .name = "LVM2_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_lvm2, + .magics = + { + { .magic = "LVM2 001", .len = 8, .sboff = 0x218 }, + { .magic = "LVM2 001", .len = 8, .sboff = 0x018 }, + { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x018 }, + { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x218 }, + { NULL } + } +}; + +const struct blkid_idinfo lvm1_idinfo = +{ + .name = "LVM1_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_lvm1, + .magics = + { + { .magic = "HM", .len = 2 }, + { NULL } + } +}; + +const struct blkid_idinfo snapcow_idinfo = +{ + .name = "DM_snapshot_cow", + .usage = BLKID_USAGE_OTHER, + .magics = + { + { .magic = "SnAp", .len = 4 }, + { NULL } + } +}; diff --git a/shlibs/blkid/src/probers/minix.c b/shlibs/blkid/src/probers/minix.c new file mode 100644 index 00000000..b29b9a42 --- /dev/null +++ b/shlibs/blkid/src/probers/minix.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include "blkidP.h" + +static int probe_minix(blkid_probe pr, const struct blkid_idmag *mag) +{ + /* for more details see magic strings below */ + switch(mag->magic[1]) { + case '\023': + blkid_probe_set_version(pr, "1"); + break; + case '\044': + blkid_probe_set_version(pr, "2"); + break; + case '\115': + blkid_probe_set_version(pr, "3"); + break; + } + return 0; +} + +const struct blkid_idinfo minix_idinfo = +{ + .name = "minix", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_minix, + .magics = + { + /* version 1 */ + { .magic = "\177\023", .len = 2, .kboff = 1, .sboff = 0x10 }, + { .magic = "\217\023", .len = 2, .kboff = 1, .sboff = 0x10 }, + + /* version 2 */ + { .magic = "\150\044", .len = 2, .kboff = 1, .sboff = 0x10 }, + { .magic = "\170\044", .len = 2, .kboff = 1, .sboff = 0x10 }, + + /* version 3 */ + { .magic = "\132\115", .len = 2, .kboff = 1, .sboff = 0x18 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/netware.c b/shlibs/blkid/src/probers/netware.c new file mode 100644 index 00000000..722506f8 --- /dev/null +++ b/shlibs/blkid/src/probers/netware.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct netware_super_block { + uint8_t SBH_Signature[4]; + uint16_t SBH_VersionMajor; + uint16_t SBH_VersionMinor; + uint16_t SBH_VersionMediaMajor; + uint16_t SBH_VersionMediaMinor; + uint32_t SBH_ItemsMoved; + uint8_t SBH_InternalID[16]; + uint32_t SBH_PackedSize; + uint32_t SBH_Checksum; + uint32_t supersyncid; + int64_t superlocation[4]; + uint32_t physSizeUsed; + uint32_t sizeUsed; + uint32_t superTimeStamp; + uint32_t reserved0[1]; + int64_t SBH_LoggedPoolDataBlk; + int64_t SBH_PoolDataBlk; + uint8_t SBH_OldInternalID[16]; + uint32_t SBH_PoolToLVStartUTC; + uint32_t SBH_PoolToLVEndUTC; + uint16_t SBH_VersionMediaMajorCreate; + uint16_t SBH_VersionMediaMinorCreate; + uint32_t SBH_BlocksMoved; + uint32_t SBH_TempBTSpBlk; + uint32_t SBH_TempFTSpBlk; + uint32_t SBH_TempFTSpBlk1; + uint32_t SBH_TempFTSpBlk2; + uint32_t nssMagicNumber; + uint32_t poolClassID; + uint32_t poolID; + uint32_t createTime; + int64_t SBH_LoggedVolumeDataBlk; + int64_t SBH_VolumeDataBlk; + int64_t SBH_SystemBeastBlkNum; + uint64_t totalblocks; + uint16_t SBH_Name[64]; + uint8_t SBH_VolumeID[16]; + uint8_t SBH_PoolID[16]; + uint8_t SBH_PoolInternalID[16]; + uint64_t SBH_Lsn; + uint32_t SBH_SS_Enabled; + uint32_t SBH_SS_CreateTime; + uint8_t SBH_SS_OriginalPoolID[16]; + uint8_t SBH_SS_OriginalVolumeID[16]; + uint8_t SBH_SS_Guid[16]; + uint16_t SBH_SS_OriginalName[64]; + uint32_t reserved2[64-(2+46)]; +} __attribute__((__packed__)); + +static int probe_netware(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct netware_super_block *nw; + + nw = blkid_probe_get_sb(pr, mag, struct netware_super_block); + if (!nw) + return -1; + + blkid_probe_set_uuid(pr, nw->SBH_PoolID); + + blkid_probe_sprintf_version(pr, "%u.%02u", + le16_to_cpu(nw->SBH_VersionMediaMajor), + le16_to_cpu(nw->SBH_VersionMediaMinor)); + + return 0; +} + +const struct blkid_idinfo netware_idinfo = +{ + .name = "nss", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_netware, + .magics = + { + { .magic = "SPB5", .len = 4, .kboff = 4 }, + { NULL } + } +}; + + diff --git a/shlibs/blkid/src/probers/ntfs.c b/shlibs/blkid/src/probers/ntfs.c new file mode 100644 index 00000000..55a186a3 --- /dev/null +++ b/shlibs/blkid/src/probers/ntfs.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <inttypes.h> + +#include "blkidP.h" + +struct ntfs_super_block { + uint8_t jump[3]; + uint8_t oem_id[8]; + uint8_t bios_parameter_block[25]; + uint16_t unused[2]; + uint64_t number_of_sectors; + uint64_t mft_cluster_location; + uint64_t mft_mirror_cluster_location; + int8_t cluster_per_mft_record; + uint8_t reserved1[3]; + int8_t cluster_per_index_record; + uint8_t reserved2[3]; + uint64_t volume_serial; + uint16_t checksum; +}; + +struct master_file_table_record { + uint32_t magic; + uint16_t usa_ofs; + uint16_t usa_count; + uint64_t lsn; + uint16_t sequence_number; + uint16_t link_count; + uint16_t attrs_offset; + uint16_t flags; + uint32_t bytes_in_use; + uint32_t bytes_allocated; +} __attribute__((__packed__)); + +struct file_attribute { + uint32_t type; + uint32_t len; + uint8_t non_resident; + uint8_t name_len; + uint16_t name_offset; + uint16_t flags; + uint16_t instance; + uint32_t value_len; + uint16_t value_offset; +} __attribute__((__packed__)); + +#define MFT_RECORD_VOLUME 3 +#define 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 + +static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ntfs_super_block *ns; + struct master_file_table_record *mft; + struct file_attribute *attr; + unsigned char 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; + uint64_t nr_clusters; + blkid_loff_t off; + unsigned char *buf_mft, *val; + + ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block); + if (!ns) + return -1; + + 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 = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster; + + if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) || + (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters)) + return 1; + + off = le64_to_cpu(ns->mft_mirror_cluster_location) * + bytes_per_sector * sectors_per_cluster; + + buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); + if (!buf_mft) + return 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + + off = le64_to_cpu(ns->mft_cluster_location) * bytes_per_sector * + sectors_per_cluster; + + buf_mft = blkid_probe_get_buffer(pr, 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 = blkid_probe_get_buffer(pr, 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 = le16_to_cpu(mft->attrs_offset); + label_str[0] = 0; + + while (1) { + attr = (struct file_attribute *) (buf_mft + attr_off); + attr_len = le16_to_cpu(attr->len); + attr_type = le32_to_cpu(attr->type); + val_off = le16_to_cpu(attr->value_offset); + val_len = le32_to_cpu(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 = ((uint8_t *) attr) + val_off + i; + *cp = val[0]; + if (val[1]) + *cp = '?'; + } + *cp = 0; + } + } + + blkid_probe_sprintf_uuid(pr, + (unsigned char *) &ns->volume_serial, + sizeof(ns->volume_serial), + "%016" PRIX64, le64_to_cpu(ns->volume_serial)); + if (label_str[0]) + blkid_probe_set_label(pr, label_str, strlen((char *)label_str)); + return 0; +} + + +const struct blkid_idinfo ntfs_idinfo = +{ + .name = "ntfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ntfs, + .magics = + { + { .magic = "NTFS ", .len = 8, .sboff = 3 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/nvidia_raid.c b/shlibs/blkid/src/probers/nvidia_raid.c new file mode 100644 index 00000000..76361763 --- /dev/null +++ b/shlibs/blkid/src/probers/nvidia_raid.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct nv_metadata { + uint8_t vendor[8]; + uint32_t size; + uint32_t chksum; + uint16_t version; +}; + +#define NVIDIA_SIGNATURE "NVIDIA" + +static int probe_nvraid(blkid_probe pr, const struct blkid_idmag *mag) +{ + uint64_t off; + struct nv_metadata *nv; + + if (pr->size < 0x10000) + return -1; + + off = ((pr->size / 0x200) - 2) * 0x200; + nv = (struct nv_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct nv_metadata)); + if (!nv) + return -1; + + if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0) + return -1; + + if (blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(nv->version)) != 0) + return -1; + + return 0; +} + +const struct blkid_idinfo nvraid_idinfo = { + .name = "nvidia_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_nvraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/shlibs/blkid/src/probers/ocfs.c b/shlibs/blkid/src/probers/ocfs.c new file mode 100644 index 00000000..f9bd11aa --- /dev/null +++ b/shlibs/blkid/src/probers/ocfs.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 1999, 2001 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct ocfs_volume_header { + unsigned char minor_version[4]; + unsigned char major_version[4]; + unsigned char signature[128]; + char mount[128]; + unsigned char mount_len[2]; +} __attribute__((packed)); + +struct ocfs_volume_label { + unsigned char disk_lock[48]; + char label[64]; + unsigned char label_len[2]; + unsigned char vol_id[16]; + unsigned char vol_id_len[2]; +} __attribute__((packed)); + +#define ocfsmajor(o) ( (uint32_t) o.major_version[0] \ + + (((uint32_t) o.major_version[1]) << 8) \ + + (((uint32_t) o.major_version[2]) << 16) \ + + (((uint32_t) o.major_version[3]) << 24)) + +#define ocfsminor(o) ( (uint32_t) o.minor_version[0] \ + + (((uint32_t) o.minor_version[1]) << 8) \ + + (((uint32_t) o.minor_version[2]) << 16) \ + + (((uint32_t) o.minor_version[3]) << 24)) + +#define ocfslabellen(o) ((uint32_t)o.label_len[0] + (((uint32_t) o.label_len[1]) << 8)) +#define ocfsmountlen(o) ((uint32_t)o.mount_len[0] + (((uint32_t) o.mount_len[1]) << 8)) + +struct ocfs2_super_block { + uint8_t i_signature[8]; + uint32_t i_generation; + int16_t i_suballoc_slot; + uint16_t i_suballoc_bit; + uint32_t i_reserved0; + uint32_t i_clusters; + uint32_t i_uid; + uint32_t i_gid; + uint64_t i_size; + uint16_t i_mode; + uint16_t i_links_count; + uint32_t i_flags; + uint64_t i_atime; + uint64_t i_ctime; + uint64_t i_mtime; + uint64_t i_dtime; + uint64_t i_blkno; + uint64_t i_last_eb_blk; + uint32_t i_fs_generation; + uint32_t i_atime_nsec; + uint32_t i_ctime_nsec; + uint32_t i_mtime_nsec; + uint64_t i_reserved1[9]; + uint64_t i_pad1; + uint16_t s_major_rev_level; + uint16_t s_minor_rev_level; + uint16_t s_mnt_count; + int16_t s_max_mnt_count; + uint16_t s_state; + uint16_t s_errors; + uint32_t s_checkinterval; + uint64_t s_lastcheck; + uint32_t s_creator_os; + uint32_t s_feature_compat; + uint32_t s_feature_incompat; + uint32_t s_feature_ro_compat; + uint64_t s_root_blkno; + uint64_t s_system_dir_blkno; + uint32_t s_blocksize_bits; + uint32_t s_clustersize_bits; + uint16_t s_max_slots; + uint16_t s_reserved1; + uint32_t s_reserved2; + uint64_t s_first_cluster_group; + uint8_t s_label[64]; + uint8_t s_uuid[16]; +} __attribute__((packed)); + +struct oracle_asm_disk_label { + char dummy[32]; + char dl_tag[8]; + char dl_id[24]; +} __attribute__((packed)); + +static int probe_ocfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + unsigned char *buf; + struct ocfs_volume_header ovh; + struct ocfs_volume_label ovl; + uint32_t maj, min; + + /* header */ + buf = blkid_probe_get_buffer(pr, mag->kboff << 10, + sizeof(struct ocfs_volume_header)); + if (!buf) + return -1; + memcpy(&ovh, buf, sizeof(ovh)); + + /* label */ + buf = blkid_probe_get_buffer(pr, (mag->kboff << 10) + 512, + sizeof(struct ocfs_volume_label)); + if (!buf) + return -1; + memcpy(&ovl, buf, sizeof(ovl)); + + maj = ocfsmajor(ovh); + min = ocfsminor(ovh); + + if (maj == 1) + blkid_probe_set_value(pr, "SEC_TYPE", + (unsigned char *) "ocfs1", sizeof("ocfs1")); + else if (maj >= 9) + blkid_probe_set_value(pr, "SEC_TYPE", + (unsigned char *) "ntocfs", sizeof("ntocfs")); + + blkid_probe_set_label(pr, (unsigned char *) ovl.label, + ocfslabellen(ovl)); + blkid_probe_set_value(pr, "MOUNT", (unsigned char *) ovh.mount, + ocfsmountlen(ovh)); + blkid_probe_set_uuid(pr, ovl.vol_id); + blkid_probe_sprintf_version(pr, "%u.%u", maj, min); + return 0; +} + +static int probe_ocfs2(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ocfs2_super_block *osb; + + osb = blkid_probe_get_sb(pr, mag, struct ocfs2_super_block); + if (!osb) + return -1; + + blkid_probe_set_label(pr, (unsigned char *) osb->s_label, sizeof(osb->s_label)); + blkid_probe_set_uuid(pr, osb->s_uuid); + + blkid_probe_sprintf_version(pr, "%u.%u", + le16_to_cpu(osb->s_major_rev_level), + le16_to_cpu(osb->s_minor_rev_level)); + + return 0; +} + +static int probe_oracleasm(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct oracle_asm_disk_label *dl; + + dl = blkid_probe_get_sb(pr, mag, struct oracle_asm_disk_label); + if (!dl) + return -1; + + blkid_probe_set_label(pr, (unsigned char *) dl->dl_id, sizeof(dl->dl_id)); + return 0; +} + + +const struct blkid_idinfo ocfs_idinfo = +{ + .name = "ocfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ocfs, + .magics = + { + { .magic = "OracleCFS", .len = 9, .kboff = 8 }, + { NULL } + } +}; + +const struct blkid_idinfo ocfs2_idinfo = +{ + .name = "ocfs2", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ocfs2, + .magics = + { + { .magic = "OCFSV2", .len = 6, .kboff = 1 }, + { .magic = "OCFSV2", .len = 6, .kboff = 2 }, + { .magic = "OCFSV2", .len = 6, .kboff = 4 }, + { .magic = "OCFSV2", .len = 6, .kboff = 8 }, + { NULL } + } +}; + +const struct blkid_idinfo oracleasm_idinfo = +{ + .name = "oracleasm", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_oracleasm, + .magics = + { + { .magic = "ORCLDISK", .len = 8, .sboff = 32 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/probers.h b/shlibs/blkid/src/probers/probers.h new file mode 100644 index 00000000..78dbd406 --- /dev/null +++ b/shlibs/blkid/src/probers/probers.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#ifndef _BLKID_PROBE_H +#define _BLKID_PROBE_H + +extern const struct blkid_idinfo cramfs_idinfo; +extern const struct blkid_idinfo swap_idinfo; +extern const struct blkid_idinfo swsuspend_idinfo; +extern const struct blkid_idinfo adraid_idinfo; +extern const struct blkid_idinfo ddfraid_idinfo; +extern const struct blkid_idinfo iswraid_idinfo; +extern const struct blkid_idinfo jmraid_idinfo; +extern const struct blkid_idinfo lsiraid_idinfo; +extern const struct blkid_idinfo nvraid_idinfo; +extern const struct blkid_idinfo pdcraid_idinfo; +extern const struct blkid_idinfo silraid_idinfo; +extern const struct blkid_idinfo viaraid_idinfo; +extern const struct blkid_idinfo linuxraid_idinfo; +extern const struct blkid_idinfo ext4dev_idinfo; +extern const struct blkid_idinfo ext4_idinfo; +extern const struct blkid_idinfo ext3_idinfo; +extern const struct blkid_idinfo ext2_idinfo; +extern const struct blkid_idinfo jbd_idinfo; +extern const struct blkid_idinfo jfs_idinfo; +extern const struct blkid_idinfo xfs_idinfo; +extern const struct blkid_idinfo gfs_idinfo; +extern const struct blkid_idinfo gfs2_idinfo; +extern const struct blkid_idinfo romfs_idinfo; +extern const struct blkid_idinfo ocfs_idinfo; +extern const struct blkid_idinfo ocfs2_idinfo; +extern const struct blkid_idinfo oracleasm_idinfo; +extern const struct blkid_idinfo reiser_idinfo; +extern const struct blkid_idinfo reiser4_idinfo; +extern const struct blkid_idinfo hfs_idinfo; +extern const struct blkid_idinfo hfsplus_idinfo; +extern const struct blkid_idinfo ntfs_idinfo; +extern const struct blkid_idinfo iso9660_idinfo; +extern const struct blkid_idinfo udf_idinfo; +extern const struct blkid_idinfo vxfs_idinfo; +extern const struct blkid_idinfo minix_idinfo; +extern const struct blkid_idinfo vfat_idinfo; +extern const struct blkid_idinfo ufs_idinfo; +extern const struct blkid_idinfo hpfs_idinfo; +extern const struct blkid_idinfo lvm2_idinfo; +extern const struct blkid_idinfo lvm1_idinfo; +extern const struct blkid_idinfo snapcow_idinfo; +extern const struct blkid_idinfo luks_idinfo; +extern const struct blkid_idinfo highpoint37x_idinfo; +extern const struct blkid_idinfo highpoint45x_idinfo; +extern const struct blkid_idinfo squashfs_idinfo; +extern const struct blkid_idinfo netware_idinfo; +extern const struct blkid_idinfo sysv_idinfo; +extern const struct blkid_idinfo xenix_idinfo; +extern const struct blkid_idinfo btrfs_idinfo; +extern const struct blkid_idinfo zfs_idinfo; + +#endif /* _BLKID_PROBE_H */ diff --git a/shlibs/blkid/src/probers/promise_raid.c b/shlibs/blkid/src/probers/promise_raid.c new file mode 100644 index 00000000..29540092 --- /dev/null +++ b/shlibs/blkid/src/probers/promise_raid.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +struct promise_metadata { + uint8_t sig[24]; +}; + +#define PDC_CONFIG_OFF 0x1200 +#define PDC_SIGNATURE "Promise Technology, Inc." + +static int probe_pdcraid(blkid_probe pr, const struct blkid_idmag *mag) +{ + unsigned int i; + static unsigned int sectors[] = { + 63, 255, 256, 16, 399, 0 + }; + + if (pr->size < 0x40000) + return -1; + + for (i = 0; sectors[i] != 0; i++) { + uint64_t off; + struct promise_metadata *pdc; + + off = ((pr->size / 0x200) - sectors[i]) * 0x200; + pdc = (struct promise_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct promise_metadata)); + if (!pdc) + return -1; + + if (memcmp(pdc->sig, PDC_SIGNATURE, + sizeof(PDC_SIGNATURE) - 1) == 0) + return 0; + } + return -1; +} + +const struct blkid_idinfo pdcraid_idinfo = { + .name = "promise_fasttrack_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_pdcraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/shlibs/blkid/src/probers/reiserfs.c b/shlibs/blkid/src/probers/reiserfs.c new file mode 100644 index 00000000..f9a46787 --- /dev/null +++ b/shlibs/blkid/src/probers/reiserfs.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 1999, 2001 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "blkidP.h" + +struct reiserfs_super_block { + uint32_t rs_blocks_count; + uint32_t rs_free_blocks; + uint32_t rs_root_block; + uint32_t rs_journal_block; + uint32_t rs_journal_dev; + uint32_t rs_orig_journal_size; + uint32_t rs_dummy2[5]; + uint16_t rs_blocksize; + uint16_t rs_dummy3[3]; + unsigned char rs_magic[12]; + uint32_t rs_dummy4[5]; + unsigned char rs_uuid[16]; + char rs_label[16]; +}; + +struct reiser4_super_block { + unsigned char rs4_magic[16]; + uint16_t rs4_dummy[2]; + unsigned char rs4_uuid[16]; + unsigned char rs4_label[16]; + uint64_t rs4_dummy2; +}; + +static int probe_reiser(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct reiserfs_super_block *rs; + unsigned int blocksize; + + rs = blkid_probe_get_sb(pr, mag, struct reiserfs_super_block); + if (!rs) + return -1; + + blocksize = le16_to_cpu(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 (mag->kboff / (blocksize >> 10) > le32_to_cpu(rs->rs_journal_block)) + return -BLKID_ERR_BIG; + + /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ + if (mag->magic[6] == '2' || mag->magic[6] == '3') { + if (*rs->rs_label) + blkid_probe_set_label(pr, + (unsigned char *) rs->rs_label, + sizeof(rs->rs_label)); + blkid_probe_set_uuid(pr, rs->rs_uuid); + } + + if (mag->magic[6] == '3') + blkid_probe_set_version(pr, "JR"); + else if (mag->magic[6] == '2') + blkid_probe_set_version(pr, "3.6"); + else + blkid_probe_set_version(pr, "3.5"); + + return 0; +} + +static int probe_reiser4(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct reiser4_super_block *rs4; + + rs4 = blkid_probe_get_sb(pr, mag, struct reiser4_super_block); + if (!rs4) + return -1; + + if (*rs4->rs4_label) + blkid_probe_set_label(pr, rs4->rs4_label, sizeof(rs4->rs4_label)); + blkid_probe_set_uuid(pr, rs4->rs4_uuid); + blkid_probe_set_version(pr, "4"); + + return 0; +} + + +const struct blkid_idinfo reiser_idinfo = +{ + .name = "reiserfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_reiser, + .magics = + { + { .magic = "ReIsErFs", .len = 8, .kboff = 8, .sboff = 0x34 }, + { .magic = "ReIsEr2Fs", .len = 9, .kboff = 64, .sboff = 0x34 }, + { .magic = "ReIsEr3Fs", .len = 9, .kboff = 64, .sboff = 0x34 }, + { .magic = "ReIsErFs", .len = 8, .kboff = 64, .sboff = 0x34 }, + { .magic = "ReIsErFs", .len = 8, .kboff = 8, .sboff = 20 }, + { NULL } + } +}; + +const struct blkid_idinfo reiser4_idinfo = +{ + .name = "reiser4", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_reiser4, + .magics = + { + { .magic = "ReIsEr4", .len = 7, .kboff = 64 }, + { NULL } + } +}; + + + + diff --git a/shlibs/blkid/src/probers/romfs.c b/shlibs/blkid/src/probers/romfs.c new file mode 100644 index 00000000..b5c20ab7 --- /dev/null +++ b/shlibs/blkid/src/probers/romfs.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 1999, 2001 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +struct romfs_super_block { + unsigned char ros_magic[8]; + uint32_t ros_dummy1[2]; + unsigned char ros_volume[16]; +}; + +static int probe_romfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct romfs_super_block *ros; + + ros = blkid_probe_get_sb(pr, mag, struct romfs_super_block); + if (!ros) + return -1; + + if (strlen((char *) ros->ros_volume)) + blkid_probe_set_label(pr, ros->ros_volume, + sizeof(ros->ros_volume)); + return 0; +} + +const struct blkid_idinfo romfs_idinfo = +{ + .name = "romfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_romfs, + .magics = + { + { .magic = "-rom1fs-", .len = 8 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/silicon_raid.c b/shlibs/blkid/src/probers/silicon_raid.c new file mode 100644 index 00000000..a65d79a8 --- /dev/null +++ b/shlibs/blkid/src/probers/silicon_raid.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +struct silicon_metadata { + uint8_t unknown0[0x2E]; + uint8_t ascii_version[0x36 - 0x2E]; + uint8_t diskname[0x56 - 0x36]; + uint8_t unknown1[0x60 - 0x56]; + uint32_t magic; + uint32_t unknown1a[0x6C - 0x64]; + uint32_t array_sectors_low; + uint32_t array_sectors_high; + uint8_t unknown2[0x78 - 0x74]; + uint32_t thisdisk_sectors; + uint8_t unknown3[0x100 - 0x7C]; + uint8_t unknown4[0x104 - 0x100]; + uint16_t product_id; + uint16_t vendor_id; + uint16_t minor_ver; + uint16_t major_ver; +}; + +#define SILICON_MAGIC 0x2F000000 + + +static int probe_silraid(blkid_probe pr, const struct blkid_idmag *mag) +{ + uint64_t off; + struct silicon_metadata *sil; + + if (pr->size < 0x10000) + return -1; + + off = ((pr->size / 0x200) - 1) * 0x200; + + sil = (struct silicon_metadata *) + blkid_probe_get_buffer(pr, off, + sizeof(struct silicon_metadata)); + if (!sil) + return -1; + + if (le32_to_cpu(sil->magic) != SILICON_MAGIC) + return -1; + + if (blkid_probe_sprintf_version(pr, "%u.%u", + le16_to_cpu(sil->major_ver), + le16_to_cpu(sil->minor_ver)) != 0) + return -1; + + return 0; +} + +const struct blkid_idinfo silraid_idinfo = { + .name = "silicon_medley_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_silraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/shlibs/blkid/src/probers/squashfs.c b/shlibs/blkid/src/probers/squashfs.c new file mode 100644 index 00000000..74f53bfb --- /dev/null +++ b/shlibs/blkid/src/probers/squashfs.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "bitops.h" /* swab16() */ +#include "blkidP.h" + +struct sqsh_super_block { + uint32_t s_magic; + uint32_t inodes; + uint32_t bytes_used_2; + uint32_t uid_start_2; + uint32_t guid_start_2; + uint32_t inode_table_start_2; + uint32_t directory_table_start_2; + uint16_t s_major; + uint16_t s_minor; +}; + +static int probe_squashfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct sqsh_super_block *sq; + + sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block); + if (!sq) + return -1; + + if (strcmp(mag->magic, "sqsh") == 0 || + strcmp(mag->magic, "qshs") == 0) + blkid_probe_sprintf_version(pr, "%u.%u", + sq->s_major, + sq->s_minor); + else + blkid_probe_sprintf_version(pr, "%u.%u", + swab16(sq->s_major), + swab16(sq->s_minor)); + return 0; +} + +const struct blkid_idinfo squashfs_idinfo = +{ + .name = "squashfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_squashfs, + .magics = + { + { .magic = "sqsh", .len = 4 }, + { .magic = "hsqs", .len = 4 }, /* swap */ + + /* LZMA version */ + { .magic = "qshs", .len = 4 }, + { .magic = "shsq", .len = 4 }, /* swap */ + { NULL } + } +}; + + diff --git a/shlibs/blkid/src/probers/swap.c b/shlibs/blkid/src/probers/swap.c new file mode 100644 index 00000000..86eb94c6 --- /dev/null +++ b/shlibs/blkid/src/probers/swap.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +/* linux-2.6/include/linux/swap.h */ +struct swap_header_v1_2 { + /* char bootbits[1024]; */ /* Space for disklabel etc. */ + uint32_t version; + uint32_t lastpage; + uint32_t nr_badpages; + unsigned char uuid[16]; + unsigned char volume[16]; + uint32_t padding[117]; + uint32_t badpages[1]; +}; + +#define PAGESIZE_MIN 0xff6 /* 4086 (arm, i386, ...) */ +#define PAGESIZE_MAX 0xfff6 /* 65526 (ia64) */ + + +static int swap_set_info(blkid_probe pr, const char *version) +{ + struct swap_header_v1_2 *hdr; + + /* Swap header always located at offset of 1024 bytes */ + hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024, + sizeof(struct swap_header_v1_2)); + if (!hdr) + return -1; + + /* SWAPSPACE2 - check for wrong version or zeroed pagecount */ + if (strcmp(version, "2") == 0 && + (hdr->version != 1 || hdr->lastpage == 0)) + return -1; + + /* arbitrary sanity check.. is there any garbage down there? */ + if (hdr->padding[32] == 0 && hdr->padding[33] == 0) { + if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume, + sizeof(hdr->volume)) < 0) + return -1; + if (hdr->uuid[0] && blkid_probe_set_uuid(pr, hdr->uuid) < 0) + return -1; + } + + blkid_probe_set_version(pr, version); + return 0; +} + +static int probe_swap(blkid_probe pr, const struct blkid_idmag *mag) +{ + if (!mag) + return -1; + + if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) { + /* swap v0 doesn't support LABEL or UUID */ + blkid_probe_set_version(pr, "1"); + return 0; + + } else if (!memcmp(mag->magic, "SWAPSPACE2", mag->len)) + return swap_set_info(pr, "2"); + + return -1; +} + +static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag) +{ + if (!mag) + return -1; + if (!memcmp(mag->magic, "S1SUSPEND", mag->len)) + return swap_set_info(pr, "s1suspend"); + if (!memcmp(mag->magic, "S2SUSPEND", mag->len)) + return swap_set_info(pr, "s2suspend"); + if (!memcmp(mag->magic, "ULSUSPEND", mag->len)) + return swap_set_info(pr, "ulsuspend"); + if (!memcmp(mag->magic, "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", mag->len)) + return swap_set_info(pr, "tuxonice"); + + return -1; /* no signature detected */ +} + +const struct blkid_idinfo swap_idinfo = +{ + .name = "swap", + .usage = BLKID_USAGE_OTHER, + .probefunc = probe_swap, + .magics = + { + { "SWAP-SPACE", 10, 0, 0xff6 }, + { "SWAPSPACE2", 10, 0, 0xff6 }, + { "SWAP-SPACE", 10, 0, 0x1ff6 }, + { "SWAPSPACE2", 10, 0, 0x1ff6 }, + { "SWAP-SPACE", 10, 0, 0x3ff6 }, + { "SWAPSPACE2", 10, 0, 0x3ff6 }, + { "SWAP-SPACE", 10, 0, 0x7ff6 }, + { "SWAPSPACE2", 10, 0, 0x7ff6 }, + { "SWAP-SPACE", 10, 0, 0xfff6 }, + { "SWAPSPACE2", 10, 0, 0xfff6 }, + { NULL } + } +}; + + +const struct blkid_idinfo swsuspend_idinfo = +{ + .name = "swsupend", + .usage = BLKID_USAGE_OTHER, + .probefunc = probe_swsuspend, + .magics = + { + { "S1SUSPEND", 9, 0, 0xff6 }, + { "S2SUSPEND", 9, 0, 0xff6 }, + { "ULSUSPEND", 9, 0, 0xff6 }, + { "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8, 0, 0xff6 }, + { "S1SUSPEND", 9, 0, 0x1ff6 }, + { "S2SUSPEND", 9, 0, 0x1ff6 }, + { "ULSUSPEND", 9, 0, 0x1ff6 }, + { "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8, 0, 0x1ff6 }, + { "S1SUSPEND", 9, 0, 0x3ff6 }, + { "S2SUSPEND", 9, 0, 0x3ff6 }, + { "ULSUSPEND", 9, 0, 0x3ff6 }, + { "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8, 0, 0x3ff6 }, + { "S1SUSPEND", 9, 0, 0x7ff6 }, + { "S2SUSPEND", 9, 0, 0x7ff6 }, + { "ULSUSPEND", 9, 0, 0x7ff6 }, + { "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8, 0, 0x7ff6 }, + { "S1SUSPEND", 9, 0, 0xfff6 }, + { "S2SUSPEND", 9, 0, 0xfff6 }, + { "ULSUSPEND", 9, 0, 0xfff6 }, + { "\xed\xc3\x02\xe9\x98\x56\xe5\x0c", 8, 0, 0xfff6 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/sysv.c b/shlibs/blkid/src/probers/sysv.c new file mode 100644 index 00000000..933163a2 --- /dev/null +++ b/shlibs/blkid/src/probers/sysv.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This is written from sratch according to Linux kernel fs/sysv/super.c file. + * It seems that sysv probing code in libvolume_id and also in the original + * blkid is useless. + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> + +#include "blkidP.h" + +#define XENIX_NICINOD 100 +#define XENIX_NICFREE 100 + +struct xenix_super_block { + uint16_t s_isize; + uint32_t s_fsize; + uint16_t s_nfree; + uint32_t s_free[XENIX_NICFREE]; + uint16_t s_ninode; + uint16_t s_inode[XENIX_NICINOD]; + uint8_t s_flock; + uint8_t s_ilock; + uint8_t s_fmod; + uint8_t s_ronly; + uint32_t s_time; + uint32_t s_tfree; + uint16_t s_tinode; + uint16_t s_dinfo[4]; + uint8_t s_fname[6]; + uint8_t s_fpack[6]; + uint8_t s_clean; + uint8_t s_fill[371]; + uint32_t s_magic; + uint32_t s_type; +}; + + +#define SYSV_NICINOD 100 +#define SYSV_NICFREE 50 + +struct sysv_super_block +{ + uint16_t s_isize; + uint16_t s_pad0; + uint32_t s_fsize; + uint16_t s_nfree; + uint16_t s_pad1; + uint32_t s_free[SYSV_NICFREE]; + uint16_t s_ninode; + uint16_t s_pad2; + uint16_t s_inode[SYSV_NICINOD]; + uint8_t s_flock; + uint8_t s_ilock; + uint8_t s_fmod; + uint8_t s_ronly; + uint32_t s_time; + uint16_t s_dinfo[4]; + uint32_t s_tfree; + uint16_t s_tinode; + uint16_t s_pad3; + uint8_t s_fname[6]; + uint8_t s_fpack[6]; + uint32_t s_fill[12]; + uint32_t s_state; + uint32_t s_magic; + uint32_t s_type; +}; + +static int probe_xenix(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct xenix_super_block *sb; + + sb = blkid_probe_get_sb(pr, mag, struct xenix_super_block); + if (!sb) + return -1; + blkid_probe_set_label(pr, sb->s_fname, sizeof(sb->s_fname)); + return 0; +} + +#define SYSV_BLOCK_SIZE 1024 + +/* Note that we don't probe for Coherent FS, this FS does not have + * magic string. (It requires to probe fname/fpack field..) + */ +static int probe_sysv(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct sysv_super_block *sb; + int blocks[] = {0, 9, 15, 18}; + int i; + + for (i = 0; i < ARRAY_SIZE(blocks); i++) { + int off = blocks[i] * SYSV_BLOCK_SIZE + SYSV_BLOCK_SIZE/2; + + sb = (struct sysv_super_block *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct sysv_super_block)); + if (!sb) + return -1; + + if (sb->s_magic == cpu_to_le32(0xfd187e20) || + sb->s_magic == cpu_to_be32(0xfd187e20)) { + blkid_probe_set_label(pr, sb->s_fname, sizeof(sb->s_fname)); + return 0; + } + } + return 1; +} + +const struct blkid_idinfo xenix_idinfo = +{ + .name = "xenix", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_xenix, + .magics = + { + { .magic = "\x2b\x55\x44", .len = 3, .kboff = 1, .sboff = 0x400 }, + { .magic = "\x44\x55\x2b", .len = 3, .kboff = 1, .sboff = 0x400 }, + { NULL } + } +}; + +const struct blkid_idinfo sysv_idinfo = +{ + .name = "sysv", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_sysv, + + /* SYSV is BE and LE and superblock could be on four positions. It's + * simpler to probe for the magic string by .probefunc(). + */ + .magics = BLKID_NONE_MAGIC +}; + diff --git a/shlibs/blkid/src/probers/udf.c b/shlibs/blkid/src/probers/udf.c new file mode 100644 index 00000000..5f4046d6 --- /dev/null +++ b/shlibs/blkid/src/probers/udf.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +struct volume_descriptor { + struct descriptor_tag { + uint16_t id; + uint16_t version; + uint8_t checksum; + uint8_t reserved; + uint16_t serial; + uint16_t crc; + uint16_t crc_len; + uint32_t location; + } tag; + union { + struct anchor_descriptor { + uint32_t length; + uint32_t location; + } anchor; + struct primary_descriptor { + uint32_t seq_num; + uint32_t desc_num; + struct dstring { + uint8_t clen; + uint8_t c[31]; + } ident; + } primary; + } type; +}; + +struct volume_structure_descriptor { + uint8_t type; + uint8_t id[5]; + uint8_t version; +}; + +#define UDF_VSD_OFFSET 0x8000 + +static int probe_udf(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct volume_descriptor *vd; + struct volume_structure_descriptor *vsd; + unsigned int bs; + unsigned int b; + unsigned int type; + unsigned int count; + unsigned int loc; + + /* search Volume Sequence Descriptor (VSD) to get the logical + * block size of the volume */ + for (bs = 0x800; bs < 0x8000; bs += 0x800) { + vsd = (struct volume_structure_descriptor *) + blkid_probe_get_buffer(pr, + UDF_VSD_OFFSET + bs, + sizeof(*vsd)); + if (!vsd) + return 1; + if (vsd->id[0] != '\0') + goto nsr; + } + return -1; + +nsr: + /* search the list of VSDs for a NSR descriptor */ + for (b = 0; b < 64; b++) { + vsd = (struct volume_structure_descriptor *) + blkid_probe_get_buffer(pr, + UDF_VSD_OFFSET + (b * bs), + sizeof(*vsd)); + if (!vsd) + return -1; + if (vsd->id[0] == '\0') + return -1; + if (memcmp(vsd->id, "NSR02", 5) == 0) + goto anchor; + if (memcmp(vsd->id, "NSR03", 5) == 0) + goto anchor; + } + return -1; + +anchor: + /* read Anchor Volume Descriptor (AVDP) */ + vd = (struct volume_descriptor *) + blkid_probe_get_buffer(pr, 256 * bs, sizeof(*vd)); + if (!vd) + return -1; + + type = le16_to_cpu(vd->tag.id); + if (type != 2) /* TAG_ID_AVDP */ + return 0; + + /* get desriptor list address and block count */ + count = le32_to_cpu(vd->type.anchor.length) / bs; + loc = le32_to_cpu(vd->type.anchor.location); + + /* pick the primary descriptor from the list */ + for (b = 0; b < count; b++) { + vd = (struct volume_descriptor *) + blkid_probe_get_buffer(pr, (loc + b) * bs, sizeof(*vd)); + if (!vd) + return -1; + + type = le16_to_cpu(vd->tag.id); + if (type == 0) + break; + if (le32_to_cpu(vd->tag.location) != loc + b) + break; + if (type == 1) { /* TAG_ID_PVD */ + uint8_t clen = vd->type.primary.ident.clen; + + if (clen == 8) + blkid_probe_set_label(pr, + vd->type.primary.ident.c, 31); + else if (clen == 16) + blkid_probe_set_utf8label(pr, + vd->type.primary.ident.c, + 31, BLKID_ENC_UTF16BE); + } + } + + return 0; +} + + +const struct blkid_idinfo udf_idinfo = +{ + .name = "udf", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_udf, + .flags = BLKID_IDINFO_TOLERANT, + .magics = + { + { .magic = "BEA01", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "BOOT2", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "CDW02", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "NSR02", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "NSR03", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "TEA01", .len = 5, .kboff = 32, .sboff = 1 }, + { NULL } + } +}; diff --git a/shlibs/blkid/src/probers/ufs.c b/shlibs/blkid/src/probers/ufs.c new file mode 100644 index 00000000..fe9870d8 --- /dev/null +++ b/shlibs/blkid/src/probers/ufs.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +struct ufs_super_block { + uint32_t fs_link; + uint32_t fs_rlink; + uint32_t fs_sblkno; + uint32_t fs_cblkno; + uint32_t fs_iblkno; + uint32_t fs_dblkno; + uint32_t fs_cgoffset; + uint32_t fs_cgmask; + uint32_t fs_time; + uint32_t fs_size; + uint32_t fs_dsize; + uint32_t fs_ncg; + uint32_t fs_bsize; + uint32_t fs_fsize; + uint32_t fs_frag; + uint32_t fs_minfree; + uint32_t fs_rotdelay; + uint32_t fs_rps; + uint32_t fs_bmask; + uint32_t fs_fmask; + uint32_t fs_bshift; + uint32_t fs_fshift; + uint32_t fs_maxcontig; + uint32_t fs_maxbpg; + uint32_t fs_fragshift; + uint32_t fs_fsbtodb; + uint32_t fs_sbsize; + uint32_t fs_csmask; + uint32_t fs_csshift; + uint32_t fs_nindir; + uint32_t fs_inopb; + uint32_t fs_nspf; + uint32_t fs_optim; + uint32_t fs_npsect_state; + uint32_t fs_interleave; + uint32_t fs_trackskew; + uint32_t fs_id[2]; + uint32_t fs_csaddr; + uint32_t fs_cssize; + uint32_t fs_cgsize; + uint32_t fs_ntrak; + uint32_t fs_nsect; + uint32_t fs_spc; + uint32_t fs_ncyl; + uint32_t fs_cpg; + uint32_t fs_ipg; + uint32_t fs_fpg; + struct ufs_csum { + uint32_t cs_ndir; + uint32_t cs_nbfree; + uint32_t cs_nifree; + uint32_t cs_nffree; + } fs_cstotal; + int8_t fs_fmod; + int8_t fs_clean; + int8_t fs_ronly; + int8_t fs_flags; + union { + struct { + int8_t fs_fsmnt[512]; + uint32_t fs_cgrotor; + uint32_t fs_csp[31]; + uint32_t fs_maxcluster; + uint32_t fs_cpc; + uint16_t fs_opostbl[16][8]; + } fs_u1; + struct { + int8_t fs_fsmnt[468]; + uint8_t fs_volname[32]; + uint64_t fs_swuid; + int32_t fs_pad; + uint32_t fs_cgrotor; + uint32_t fs_ocsp[28]; + uint32_t fs_contigdirs; + uint32_t fs_csp; + uint32_t fs_maxcluster; + uint32_t fs_active; + int32_t fs_old_cpc; + int32_t fs_maxbsize; + int64_t fs_sparecon64[17]; + int64_t fs_sblockloc; + struct ufs2_csum_total { + uint64_t cs_ndir; + uint64_t cs_nbfree; + uint64_t cs_nifree; + uint64_t cs_nffree; + uint64_t cs_numclusters; + uint64_t cs_spare[3]; + } fs_cstotal; + struct ufs_timeval { + int32_t tv_sec; + int32_t tv_usec; + } fs_time; + int64_t fs_size; + int64_t fs_dsize; + uint64_t fs_csaddr; + int64_t fs_pendingblocks; + int32_t fs_pendinginodes; + } fs_u2; + } fs_u11; + union { + struct { + int32_t fs_sparecon[53]; + int32_t fs_reclaim; + int32_t fs_sparecon2[1]; + int32_t fs_state; + uint32_t fs_qbmask[2]; + uint32_t fs_qfmask[2]; + } fs_sun; + struct { + int32_t fs_sparecon[53]; + int32_t fs_reclaim; + int32_t fs_sparecon2[1]; + uint32_t fs_npsect; + uint32_t fs_qbmask[2]; + uint32_t fs_qfmask[2]; + } fs_sunx86; + struct { + int32_t fs_sparecon[50]; + int32_t fs_contigsumsize; + int32_t fs_maxsymlinklen; + int32_t fs_inodefmt; + uint32_t fs_maxfilesize[2]; + uint32_t fs_qbmask[2]; + uint32_t fs_qfmask[2]; + int32_t fs_state; + } fs_44; + } fs_u2; + int32_t fs_postblformat; + int32_t fs_nrpos; + int32_t fs_postbloff; + int32_t fs_rotbloff; + uint32_t fs_magic; + uint8_t fs_space[1]; +}; + +#define UFS_MAGIC 0x00011954 +#define UFS2_MAGIC 0x19540119 +#define UFS_MAGIC_FEA 0x00195612 +#define UFS_MAGIC_LFN 0x00095014 + +static int probe_ufs(blkid_probe pr, const struct blkid_idmag *mag) +{ + int offsets[] = { 0, 8, 64, 256 }; + int mags[] = { UFS2_MAGIC, UFS_MAGIC, UFS_MAGIC_FEA, UFS_MAGIC_LFN }; + int i; + uint32_t magic; + struct ufs_super_block *ufs; + + for (i = 0; i < ARRAY_SIZE(offsets); i++) { + uint32_t magLE, magBE; + int y; + + ufs = (struct ufs_super_block *) + blkid_probe_get_buffer(pr, + offsets[i] * 1024, + sizeof(struct ufs_super_block)); + if (!ufs) + return -1; + + magBE = be32_to_cpu(ufs->fs_magic); + magLE = le32_to_cpu(ufs->fs_magic); + + for (y = 0; y < ARRAY_SIZE(mags); y++) { + if (magLE == mags[y] || magBE == mags[y]) { + magic = mags[y]; + goto found; + } + } + } + + return 1; + +found: + if (magic == UFS2_MAGIC) { + blkid_probe_set_version(pr, "2"); + blkid_probe_set_label(pr, ufs->fs_u11.fs_u2.fs_volname, + sizeof(ufs->fs_u11.fs_u2.fs_volname)); + } else + blkid_probe_set_version(pr, "1"); + + return 0; +} + +/* + * According to libvolume_id the UFS superblock could be on four positions. + * The original libblkid has checked one position (.kboff=8) only. + * + * We know four UFS magic strings and UFS could be both little-endian and + * big-endian. ... so we have: + * + * 4 position * 4 string * 2 version = 32 magic strings + * + * It seems simpler to check for these string in probing function that hardcode + * all in the .magic array. + */ +const struct blkid_idinfo ufs_idinfo = +{ + .name = "ufs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ufs, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/shlibs/blkid/src/probers/vfat.c b/shlibs/blkid/src/probers/vfat.c new file mode 100644 index 00000000..a83175c0 --- /dev/null +++ b/shlibs/blkid/src/probers/vfat.c @@ -0,0 +1,364 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +/* Yucky misaligned values */ +struct vfat_super_block { +/* 00*/ unsigned char vs_ignored[3]; +/* 03*/ unsigned char vs_sysid[8]; +/* 0b*/ unsigned char vs_sector_size[2]; +/* 0d*/ uint8_t vs_cluster_size; +/* 0e*/ uint16_t vs_reserved; +/* 10*/ uint8_t vs_fats; +/* 11*/ unsigned char vs_dir_entries[2]; +/* 13*/ unsigned char vs_sectors[2]; +/* 15*/ unsigned char vs_media; +/* 16*/ uint16_t vs_fat_length; +/* 18*/ uint16_t vs_secs_track; +/* 1a*/ uint16_t vs_heads; +/* 1c*/ uint32_t vs_hidden; +/* 20*/ uint32_t vs_total_sect; +/* 24*/ uint32_t vs_fat32_length; +/* 28*/ uint16_t vs_flags; +/* 2a*/ uint8_t vs_version[2]; +/* 2c*/ uint32_t vs_root_cluster; +/* 30*/ uint16_t vs_fsinfo_sector; +/* 32*/ uint16_t vs_backup_boot; +/* 34*/ uint16_t vs_reserved2[6]; +/* 40*/ unsigned char vs_unknown[3]; +/* 43*/ unsigned char vs_serno[4]; +/* 47*/ unsigned char vs_label[11]; +/* 52*/ unsigned char vs_magic[8]; +/* 5a*/ unsigned char vs_dummy2[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*/ uint8_t ms_cluster_size; +/* 0e*/ uint16_t ms_reserved; +/* 10*/ uint8_t ms_fats; +/* 11*/ unsigned char ms_dir_entries[2]; +/* 13*/ unsigned char ms_sectors[2]; +/* 15*/ unsigned char ms_media; +/* 16*/ uint16_t ms_fat_length; +/* 18*/ uint16_t ms_secs_track; +/* 1a*/ uint16_t ms_heads; +/* 1c*/ uint32_t ms_hidden; +/* 20*/ uint32_t 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 { + uint8_t name[11]; + uint8_t attr; + uint16_t time_creat; + uint16_t date_creat; + uint16_t time_acc; + uint16_t date_acc; + uint16_t cluster_high; + uint16_t time_write; + uint16_t date_write; + uint16_t cluster_low; + uint32_t size; +}; + +struct fat32_fsinfo { + uint8_t signature1[4]; + uint32_t reserved1[120]; + uint8_t signature2[4]; + uint32_t free_clusters; + uint32_t next_cluster; + uint32_t reserved2[4]; +}; + +/* maximum number of clusters */ +#define FAT12_MAX 0xFF4 +#define FAT16_MAX 0xFFF4 +#define FAT32_MAX 0x0FFFFFF6 + +#define FAT_ATTR_VOLUME_ID 0x08 +#define FAT_ATTR_DIR 0x10 +#define FAT_ATTR_LONG_NAME 0x0f +#define FAT_ATTR_MASK 0x3f +#define FAT_ENTRY_FREE 0xe5 + +static const char *no_name = "NO NAME "; + +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; +} + +/* + * The FAT filesystem could be without a magic string in superblock + * (e.g. old floppies). This heuristic for FAT detection is inspired + * by libvolume_id and the Linux kernel. + */ +static int probe_fat_nomagic(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct msdos_super_block *ms; + + ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); + if (!ms) + return -1; + + /* 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 0; +} + +/* FAT label extraction from the root directory taken from Kay + * Sievers's volume_id library */ +static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct vfat_super_block *vs; + struct msdos_super_block *ms; + struct vfat_dir_entry *dir; + const unsigned char *vol_label = 0, *tmp; + unsigned char *vol_serno; + int maxloop = 100; + uint16_t sector_size, dir_entries, reserved; + uint32_t sect_count, fat_size, dir_size, cluster_count, fat_length; + uint32_t buf_size, start_data_sect, next, root_start, root_dir_entries; + const char *version = NULL; + + + /* non-standard magic strings */ + if (mag->len <= 2 && probe_fat_nomagic(pr, mag) != 0) + return 1; + + vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); + if (!vs) + return -1; + + ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); + if (!ms) + return -1; + + /* 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 = le16_to_cpu(ms->ms_reserved); + tmp = (unsigned char *) &ms->ms_sectors; + sect_count = tmp[0] + (tmp[1] << 8); + if (sect_count == 0) + sect_count = le32_to_cpu(ms->ms_total_sect); + + fat_length = le16_to_cpu(ms->ms_fat_length); + if (fat_length == 0) + fat_length = le32_to_cpu(vs->vs_fat32_length); + + fat_size = fat_length * ms->ms_fats; + dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + + (sector_size-1)) / sector_size; + + cluster_count = sect_count - (reserved + fat_size + dir_size); + 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 *) + blkid_probe_get_buffer(pr, 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_probe_set_value(pr, "SEC_TYPE", (unsigned char *) "msdos", + sizeof("msdos")); + + if (cluster_count < FAT12_MAX) + version = "FAT12"; + else if (cluster_count < FAT16_MAX) + version = "FAT16"; + } else { + unsigned char *buf; + uint16_t fsinfo_sect; + + /* Search the FAT32 root dir for the label attribute */ + buf_size = vs->vs_cluster_size * sector_size; + start_data_sect = reserved + fat_size; + + version = "FAT32"; + + next = le32_to_cpu(vs->vs_root_cluster); + while (next && --maxloop) { + uint32_t next_sect_off; + uint64_t next_off, fat_entry_off; + int count; + + next_sect_off = (next - 2) * vs->vs_cluster_size; + next_off = (start_data_sect + next_sect_off) * + sector_size; + + dir = (struct vfat_dir_entry *) + blkid_probe_get_buffer(pr, 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(uint32_t)); + buf = blkid_probe_get_buffer(pr, fat_entry_off, buf_size); + if (buf == NULL) + break; + + /* set next cluster */ + next = le32_to_cpu(*((uint32_t *) buf) & 0x0fffffff); + } + + if (!vol_label || !memcmp(vol_label, no_name, 11)) + vol_label = vs->vs_label; + vol_serno = vs->vs_serno; + + /* + * FAT32 should have a valid signature in the fsinfo block, + * but also allow all bytes set to '\0', because some volumes + * do not set the signature at all. + */ + fsinfo_sect = le16_to_cpu(vs->vs_fsinfo_sector); + if (fsinfo_sect) { + struct fat32_fsinfo *fsinfo; + + buf = blkid_probe_get_buffer(pr, + fsinfo_sect * sector_size, + sizeof(struct fat32_fsinfo)); + if (buf == NULL) + return -1; + + fsinfo = (struct fat32_fsinfo *) buf; + if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0 && + memcmp(fsinfo->signature1, "\x00\x00\x00\x00", 4) != 0) + return -1; + if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0 && + memcmp(fsinfo->signature2, "\x00\x00\x00\x00", 4) != 0) + return -1; + } + } + + if (vol_label && memcmp(vol_label, no_name, 11)) + blkid_probe_set_label(pr, (unsigned char *) vol_label, 11); + + /* We can't just print them as %04X, because they are unaligned */ + blkid_probe_sprintf_uuid(pr, vol_serno, 4, "%02X%02X-%02X%02X", + vol_serno[3], vol_serno[2], vol_serno[1], vol_serno[0]); + + if (version) + blkid_probe_set_version(pr, version); + + return 0; +} + + +const struct blkid_idinfo vfat_idinfo = +{ + .name = "vfat", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_vfat, + .magics = + { + { .magic = "MSWIN", .len = 5, .sboff = 0x52 }, + { .magic = "FAT32 ", .len = 8, .sboff = 0x52 }, + { .magic = "MSDOS", .len = 5, .sboff = 0x36 }, + { .magic = "FAT16 ", .len = 8, .sboff = 0x36 }, + { .magic = "FAT12 ", .len = 8, .sboff = 0x36 }, + { .magic = "\353", .len = 1, }, + { .magic = "\351", .len = 1, }, + { .magic = "\125\252", .len = 2, .sboff = 0x1fe }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/via_raid.c b/shlibs/blkid/src/probers/via_raid.c new file mode 100644 index 00000000..22022fdd --- /dev/null +++ b/shlibs/blkid/src/probers/via_raid.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +struct via_metadata { + uint16_t signature; + uint8_t version_number; + struct via_array { + uint16_t disk_bit_mask; + uint8_t disk_array_ex; + uint32_t capacity_low; + uint32_t capacity_high; + uint32_t serial_checksum; + } array; + uint32_t serial_checksum[8]; + uint8_t checksum; +}; + +#define VIA_SIGNATURE 0xAA55 + +/* 8 bit checksum on first 50 bytes of metadata. */ +static uint8_t via_checksum(struct via_metadata *v) +{ + uint8_t i = 50, cs = 0; + + while (i--) + cs += ((uint8_t*) v)[i]; + + return cs == v->checksum; +} + +static int probe_viaraid(blkid_probe pr, const struct blkid_idmag *mag) +{ + uint64_t off; + struct via_metadata *v; + + if (pr->size < 0x10000) + return -1; + + off = ((pr->size / 0x200)-1) * 0x200; + + v = (struct via_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct via_metadata)); + if (!v) + return -1; + if (le16_to_cpu(v->signature) != VIA_SIGNATURE) + return -1; + if (v->version_number > 2) + return -1; + if (!via_checksum(v)) + return -1; + if (blkid_probe_sprintf_version(pr, "%u", v->version_number) != 0) + return -1; + return 0; +} + +const struct blkid_idinfo viaraid_idinfo = { + .name = "via_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_viaraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/shlibs/blkid/src/probers/vxfs.c b/shlibs/blkid/src/probers/vxfs.c new file mode 100644 index 00000000..7a27b6c9 --- /dev/null +++ b/shlibs/blkid/src/probers/vxfs.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> + +#include "blkidP.h" + +struct vxfs_super_block { + uint32_t vs_magic; + int32_t vs_version; +}; + +static int probe_vxfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct vxfs_super_block *vxs; + + vxs = blkid_probe_get_sb(pr, mag, struct vxfs_super_block); + if (!vxs) + return -1; + + blkid_probe_sprintf_version(pr, "%u", (unsigned int) vxs->vs_version); + return 0; +} + + +const struct blkid_idinfo vxfs_idinfo = +{ + .name = "vxfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_vxfs, + .magics = + { + { .magic = "\365\374\001\245", .len = 4, .kboff = 1 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/xfs.c b/shlibs/blkid/src/probers/xfs.c new file mode 100644 index 00000000..fa7914e2 --- /dev/null +++ b/shlibs/blkid/src/probers/xfs.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "blkidP.h" + +struct xfs_super_block { + unsigned char xs_magic[4]; + uint32_t xs_blocksize; + uint64_t xs_dblocks; + uint64_t xs_rblocks; + uint32_t xs_dummy1[2]; + unsigned char xs_uuid[16]; + uint32_t xs_dummy2[15]; + char xs_fname[12]; + uint32_t xs_dummy3[2]; + uint64_t xs_icount; + uint64_t xs_ifree; + uint64_t xs_fdblocks; +}; + +static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct xfs_super_block *xs; + + xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block); + if (!xs) + return -1; + + if (strlen(xs->xs_fname)) + blkid_probe_set_label(pr, (unsigned char *) xs->xs_fname, + sizeof(xs->xs_fname)); + blkid_probe_set_uuid(pr, xs->xs_uuid); + return 0; +} + +const struct blkid_idinfo xfs_idinfo = +{ + .name = "xfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_xfs, + .magics = + { + { .magic = "XFSB", .len = 4 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/probers/zfs.c b/shlibs/blkid/src/probers/zfs.c new file mode 100644 index 00000000..7d39034f --- /dev/null +++ b/shlibs/blkid/src/probers/zfs.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2009 by Andreas Dilger <adilger@sun.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <inttypes.h> + +#include "blkidP.h" + +/* #include <sys/uberblock_impl.h> */ +#define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */ +struct zfs_uberblock { + uint64_t ub_magic; /* UBERBLOCK_MAGIC */ + uint64_t ub_version; /* SPA_VERSION */ + uint64_t ub_txg; /* txg of last sync */ + uint64_t ub_guid_sum; /* sum of all vdev guids */ + uint64_t ub_timestamp; /* UTC time of last sync */ + /*blkptr_t ub_rootbp;*/ /* MOS objset_phys_t */ +}; + +static int probe_zfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct zfs_uberblock *ub; + int swab_endian; + uint64_t spa_version; + + ub = blkid_probe_get_sb(pr, mag, struct zfs_uberblock); + if (!ub) + return -1; + + swab_endian = (ub->ub_magic == swab64(UBERBLOCK_MAGIC)); + spa_version = swab_endian ? swab64(ub->ub_version) : ub->ub_version; + + blkid_probe_sprintf_version(pr, "%" PRIu64, spa_version); +#if 0 + /* read nvpair data for pool name, pool GUID from the MOS, but + * unfortunately this is more complex than it could be */ + blkid_probe_set_label(pr, pool_name, pool_len)); + blkid_probe_set_uuid(pr, pool_guid); +#endif + return 0; +} + +const struct blkid_idinfo zfs_idinfo = +{ + .name = "zfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_zfs, + .magics = + { + { .magic = "\0\0\x02\xf5\xb0\x07\xb1\x0c", .len = 8, .kboff = 8 }, + { .magic = "\x1c\xb1\x07\xb0\xf5\x02\0\0", .len = 8, .kboff = 8 }, + { .magic = "\0\0\x02\xf5\xb0\x07\xb1\x0c", .len = 8, .kboff = 264 }, + { .magic = "\x0c\xb1\x07\xb0\xf5\x02\0\0", .len = 8, .kboff = 264 }, + { NULL } + } +}; + diff --git a/shlibs/blkid/src/read.c b/shlibs/blkid/src/read.c new file mode 100644 index 00000000..b5e9cd02 --- /dev/null +++ b/shlibs/blkid/src/read.c @@ -0,0 +1,492 @@ +/* + * read.c - read the blkid cache from disk, to avoid scanning all devices + * + * Copyright (C) 2001, 2003 Theodore Y. Ts'o + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#define _XOPEN_SOURCE 600 /* for inclusion of strtoull */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#if HAVE_ERRNO_H +#include <errno.h> +#endif + +#include "blkidP.h" + +#ifdef HAVE_STRTOULL +#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */ +#else +/* FIXME: need to support real strtoull here */ +#define STRTOULL strtoul +#endif + +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef TEST_PROGRAM +#define blkid_debug_dump_dev(dev) (debug_dump_dev(dev)) +static void debug_dump_dev(blkid_dev dev); +#endif + +/* + * File format: + * + * <device [<NAME="value"> ...]>device_name</device> + * + * The following tags are required for each entry: + * <ID="id"> unique (within this file) ID number of this device + * <TIME="time"> (ascii time_t) time this entry was last read from disk + * <TYPE="type"> (detected) type of filesystem/data for this partition + * + * The following tags may be present, depending on the device contents + * <LABEL="label"> (user supplied) label (volume name, etc) + * <UUID="uuid"> (generated) universally unique identifier (serial no) + */ + +static char *skip_over_blank(char *cp) +{ + while (*cp && isspace(*cp)) + cp++; + return cp; +} + +static char *skip_over_word(char *cp) +{ + char ch; + + while ((ch = *cp)) { + /* If we see a backslash, skip the next character */ + if (ch == '\\') { + cp++; + if (*cp == '\0') + break; + cp++; + continue; + } + if (isspace(ch) || ch == '<' || ch == '>') + break; + cp++; + } + return cp; +} + +static char *strip_line(char *line) +{ + char *p; + + line = skip_over_blank(line); + + p = line + strlen(line) - 1; + + while (*line) { + if (isspace(*p)) + *p-- = '\0'; + else + break; + } + + return line; +} + +#if 0 +static char *parse_word(char **buf) +{ + char *word, *next; + + word = *buf; + if (*word == '\0') + return NULL; + + word = skip_over_blank(word); + next = skip_over_word(word); + if (*next) { + char *end = next - 1; + if (*end == '"' || *end == '\'') + *end = '\0'; + *next++ = '\0'; + } + *buf = next; + + if (*word == '"' || *word == '\'') + word++; + return word; +} +#endif + +/* + * Start parsing a new line from the cache. + * + * line starts with "<device" return 1 -> continue parsing line + * line starts with "<foo", empty, or # return 0 -> skip line + * line starts with other, return -BLKID_ERR_CACHE -> error + */ +static int parse_start(char **cp) +{ + char *p; + + p = strip_line(*cp); + + /* Skip comment or blank lines. We can't just NUL the first '#' char, + * in case it is inside quotes, or escaped. + */ + if (*p == '\0' || *p == '#') + return 0; + + if (!strncmp(p, "<device", 7)) { + DBG(DEBUG_READ, printf("found device header: %8s\n", p)); + p += 7; + + *cp = p; + return 1; + } + + if (*p == '<') + return 0; + + return -BLKID_ERR_CACHE; +} + +/* Consume the remaining XML on the line (cosmetic only) */ +static int parse_end(char **cp) +{ + *cp = skip_over_blank(*cp); + + if (!strncmp(*cp, "</device>", 9)) { + DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp)); + *cp += 9; + return 0; + } + + return -BLKID_ERR_CACHE; +} + +/* + * Allocate a new device struct with device name filled in. Will handle + * finding the device on lines of the form: + * <device foo=bar>devname</device> + * <device>devname<foo>bar</foo></device> + */ +static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp) +{ + char *start, *tmp, *end, *name; + int ret; + + if ((ret = parse_start(cp)) <= 0) + return ret; + + start = tmp = strchr(*cp, '>'); + if (!start) { + DBG(DEBUG_READ, + printf("blkid: short line parsing dev: %s\n", *cp)); + return -BLKID_ERR_CACHE; + } + start = skip_over_blank(start + 1); + end = skip_over_word(start); + + DBG(DEBUG_READ, printf("device should be %*s\n", + (int)(end - start), start)); + + if (**cp == '>') + *cp = end; + else + (*cp)++; + + *tmp = '\0'; + + if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) { + DBG(DEBUG_READ, + printf("blkid: missing </device> ending: %s\n", end)); + } else if (tmp) + *tmp = '\0'; + + if (end - start <= 1) { + DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp)); + return -BLKID_ERR_CACHE; + } + + name = blkid_strndup(start, end-start); + if (name == NULL) + return -BLKID_ERR_MEM; + + DBG(DEBUG_READ, printf("found dev %s\n", name)); + + if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE))) { + free(name); + return -BLKID_ERR_MEM; + } + + free(name); + return 1; +} + +/* + * Extract a tag of the form NAME="value" from the line. + */ +static int parse_token(char **name, char **value, char **cp) +{ + char *end; + + if (!name || !value || !cp) + return -BLKID_ERR_PARAM; + + if (!(*value = strchr(*cp, '='))) + return 0; + + **value = '\0'; + *name = strip_line(*cp); + *value = skip_over_blank(*value + 1); + + if (**value == '"') { + end = strchr(*value + 1, '"'); + if (!end) { + DBG(DEBUG_READ, + printf("unbalanced quotes at: %s\n", *value)); + *cp = *value; + return -BLKID_ERR_CACHE; + } + (*value)++; + *end = '\0'; + end++; + } else { + end = skip_over_word(*value); + if (*end) { + *end = '\0'; + end++; + } + } + *cp = end; + + return 1; +} + +/* + * Extract a tag of the form <NAME>value</NAME> from the line. + */ +/* +static int parse_xml(char **name, char **value, char **cp) +{ + char *end; + + if (!name || !value || !cp) + return -BLKID_ERR_PARAM; + + *name = strip_line(*cp); + + if ((*name)[0] != '<' || (*name)[1] == '/') + return 0; + + FIXME: finish this. +} +*/ + +/* + * Extract a tag from the line. + * + * Return 1 if a valid tag was found. + * Return 0 if no tag found. + * Return -ve error code. + */ +static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp) +{ + char *name; + char *value; + int ret; + + if (!cache || !dev) + return -BLKID_ERR_PARAM; + + if ((ret = parse_token(&name, &value, cp)) <= 0 /* && + (ret = parse_xml(&name, &value, cp)) <= 0 */) + return ret; + + /* Some tags are stored directly in the device struct */ + if (!strcmp(name, "DEVNO")) + dev->bid_devno = STRTOULL(value, 0, 0); + else if (!strcmp(name, "PRI")) + dev->bid_pri = strtol(value, 0, 0); + else if (!strcmp(name, "TIME")) + dev->bid_time = STRTOULL(value, 0, 0); + else + ret = blkid_set_tag(dev, name, value, strlen(value)); + + DBG(DEBUG_READ, printf(" tag: %s=\"%s\"\n", name, value)); + + return ret < 0 ? ret : 1; +} + +/* + * Parse a single line of data, and return a newly allocated dev struct. + * Add the new device to the cache struct, if one was read. + * + * Lines are of the form <device [TAG="value" ...]>/dev/foo</device> + * + * Returns -ve value on error. + * Returns 0 otherwise. + * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL + * (e.g. comment lines, unknown XML content, etc). + */ +static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp) +{ + blkid_dev dev; + int ret; + + if (!cache || !dev_p) + return -BLKID_ERR_PARAM; + + *dev_p = NULL; + + DBG(DEBUG_READ, printf("line: %s\n", cp)); + + if ((ret = parse_dev(cache, dev_p, &cp)) <= 0) + return ret; + + dev = *dev_p; + + while ((ret = parse_tag(cache, dev, &cp)) > 0) { + ; + } + + if (dev->bid_type == NULL) { + DBG(DEBUG_READ, + printf("blkid: device %s has no TYPE\n",dev->bid_name)); + blkid_free_dev(dev); + } + + DBG(DEBUG_READ, blkid_debug_dump_dev(dev)); + + return ret; +} + +/* + * Parse the specified filename, and return the data in the supplied or + * a newly allocated cache struct. If the file doesn't exist, return a + * new empty cache struct. + */ +void blkid_read_cache(blkid_cache cache) +{ + FILE *file; + char buf[4096]; + int fd, lineno = 0; + struct stat st; + + if (!cache) + return; + + /* + * If the file doesn't exist, then we just return an empty + * struct so that the cache can be populated. + */ + if ((fd = open(cache->bic_filename, O_RDONLY)) < 0) + return; + if (fstat(fd, &st) < 0) + goto errout; + if ((st.st_mtime == cache->bic_ftime) || + (cache->bic_flags & BLKID_BIC_FL_CHANGED)) { + DBG(DEBUG_CACHE, printf("skipping re-read of %s\n", + cache->bic_filename)); + goto errout; + } + + DBG(DEBUG_CACHE, printf("reading cache file %s\n", + cache->bic_filename)); + + file = fdopen(fd, "r"); + if (!file) + goto errout; + + while (fgets(buf, sizeof(buf), file)) { + blkid_dev dev; + unsigned int end; + + lineno++; + if (buf[0] == 0) + continue; + end = strlen(buf) - 1; + /* Continue reading next line if it ends with a backslash */ + while (buf[end] == '\\' && end < sizeof(buf) - 2 && + fgets(buf + end, sizeof(buf) - end, file)) { + end = strlen(buf) - 1; + lineno++; + } + + if (blkid_parse_line(cache, &dev, buf) < 0) { + DBG(DEBUG_READ, + printf("blkid: bad format on line %d\n", lineno)); + continue; + } + } + fclose(file); + + /* + * Initially we do not need to write out the cache file. + */ + cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; + cache->bic_ftime = st.st_mtime; + + return; +errout: + close(fd); + return; +} + +#ifdef TEST_PROGRAM +static void debug_dump_dev(blkid_dev dev) +{ + struct list_head *p; + + if (!dev) { + printf(" dev: NULL\n"); + return; + } + + printf(" dev: name = %s\n", dev->bid_name); + printf(" dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno); + printf(" dev: TIME=\"%lld\"\n", (long long)dev->bid_time); + printf(" dev: PRI=\"%d\"\n", dev->bid_pri); + printf(" dev: flags = 0x%08X\n", dev->bid_flags); + + list_for_each(p, &dev->bid_tags) { + blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); + if (tag) + printf(" tag: %s=\"%s\"\n", tag->bit_name, + tag->bit_val); + else + printf(" tag: NULL\n"); + } + printf("\n"); +} + +int main(int argc, char**argv) +{ + blkid_cache cache = NULL; + int ret; + + blkid_init_debug(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/shlibs/blkid/src/resolve.c b/shlibs/blkid/src/resolve.c new file mode 100644 index 00000000..bf13b864 --- /dev/null +++ b/shlibs/blkid/src/resolve.c @@ -0,0 +1,139 @@ +/* + * resolve.c - resolve names and tags into specific devices + * + * Copyright (C) 2001, 2003 Theodore Ts'o. + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <stdio.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "blkidP.h" + +/* + * Find a tagname (e.g. LABEL or UUID) on a specific device. + */ +char *blkid_get_tag_value(blkid_cache cache, const char *tagname, + const char *devname) +{ + blkid_tag found; + blkid_dev dev; + blkid_cache c = cache; + char *ret = NULL; + + DBG(DEBUG_RESOLVE, printf("looking for %s on %s\n", tagname, devname)); + + if (!devname) + return NULL; + + if (!cache) { + if (blkid_get_cache(&c, NULL) < 0) + return NULL; + } + + if ((dev = blkid_get_dev(c, devname, BLKID_DEV_NORMAL)) && + (found = blkid_find_tag_dev(dev, tagname))) + ret = blkid_strdup(found->bit_val); + + if (!cache) + blkid_put_cache(c); + + return ret; +} + +/* + * Locate a device name from a token (NAME=value string), or (name, value) + * pair. In the case of a token, value is ignored. If the "token" is not + * of the form "NAME=value" and there is no value given, then it is assumed + * to be the actual devname and a copy is returned. + */ +char *blkid_get_devname(blkid_cache cache, const char *token, + const char *value) +{ + blkid_dev dev; + blkid_cache c = cache; + char *t = 0, *v = 0; + char *ret = NULL; + + if (!token) + return NULL; + + if (!cache) { + if (blkid_get_cache(&c, NULL) < 0) + return NULL; + } + + DBG(DEBUG_RESOLVE, + printf("looking for %s%s%s %s\n", token, value ? "=" : "", + value ? value : "", cache ? "in cache" : "from disk")); + + if (!value) { + if (!strchr(token, '=')) { + ret = blkid_strdup(token); + goto out; + } + blkid_parse_tag_string(token, &t, &v); + if (!t || !v) + goto out; + token = t; + value = v; + } + + dev = blkid_find_dev_with_tag(c, token, value); + if (!dev) + goto out; + + ret = blkid_strdup(blkid_dev_devname(dev)); + +out: + free(t); + free(v); + if (!cache) { + blkid_put_cache(c); + } + return (ret); +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + char *value; + blkid_cache cache; + + blkid_init_debug(DEBUG_ALL); + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage:\t%s tagname=value\n" + "\t%s tagname devname\n" + "Find which device holds a given token or\n" + "Find what the value of a tag is in a device\n", + argv[0], argv[0]); + exit(1); + } + if (blkid_get_cache(&cache, "/dev/null") < 0) { + fprintf(stderr, "Couldn't get blkid cache\n"); + exit(1); + } + + if (argv[2]) { + value = blkid_get_tag_value(cache, argv[1], argv[2]); + printf("%s has tag %s=%s\n", argv[2], argv[1], + value ? value : "<missing>"); + } else { + value = blkid_get_devname(cache, argv[1], NULL); + printf("%s has tag %s\n", value ? value : "<none>", argv[1]); + } + blkid_put_cache(cache); + return value ? 0 : 1; +} +#endif diff --git a/shlibs/blkid/src/save.c b/shlibs/blkid/src/save.c new file mode 100644 index 00000000..bbe6f488 --- /dev/null +++ b/shlibs/blkid/src/save.c @@ -0,0 +1,193 @@ +/* + * save.c - write the cache struct to disk + * + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_SYS_MKDEV_H +#include <sys/mkdev.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include "blkidP.h" + +static int save_dev(blkid_dev dev, FILE *file) +{ + struct list_head *p; + + if (!dev || dev->bid_name[0] != '/') + return 0; + + DBG(DEBUG_SAVE, + printf("device %s, type %s\n", dev->bid_name, dev->bid_type ? + dev->bid_type : "(null)")); + + fprintf(file, + "<device DEVNO=\"0x%04lx\" TIME=\"%ld\"", + (unsigned long) dev->bid_devno, (long) dev->bid_time); + if (dev->bid_pri) + fprintf(file, " PRI=\"%d\"", dev->bid_pri); + list_for_each(p, &dev->bid_tags) { + blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); + fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val); + } + fprintf(file, ">%s</device>\n", dev->bid_name); + + return 0; +} + +/* + * Write out the cache struct to the cache file on disk. + */ +int blkid_flush_cache(blkid_cache cache) +{ + struct list_head *p; + char *tmp = NULL; + const char *opened = NULL; + const char *filename; + FILE *file = NULL; + int fd, ret = 0; + struct stat st; + + if (!cache) + return -BLKID_ERR_PARAM; + + if (list_empty(&cache->bic_devs) || + !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) { + DBG(DEBUG_SAVE, printf("skipping cache file write\n")); + return 0; + } + + filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE; + + /* If we can't write to the cache file, then don't even try */ + if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) || + (ret == 0 && access(filename, W_OK) < 0)) { + DBG(DEBUG_SAVE, + printf("can't write to cache file %s\n", filename)); + return 0; + } + + /* + * Try and create a temporary file in the same directory so + * that in case of error we don't overwrite the cache file. + * If the cache file doesn't yet exist, it isn't a regular + * file (e.g. /dev/null or a socket), or we couldn't create + * a temporary file then we open it directly. + */ + if (ret == 0 && S_ISREG(st.st_mode)) { + tmp = malloc(strlen(filename) + 8); + if (tmp) { + sprintf(tmp, "%s-XXXXXX", filename); + fd = mkstemp(tmp); + if (fd >= 0) { + file = fdopen(fd, "w"); + opened = tmp; + } + fchmod(fd, 0644); + } + } + + if (!file) { + file = fopen(filename, "w"); + opened = filename; + } + + DBG(DEBUG_SAVE, + printf("writing cache file %s (really %s)\n", + filename, opened)); + + if (!file) { + ret = errno; + goto errout; + } + + list_for_each(p, &cache->bic_devs) { + blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); + if (!dev->bid_type) + continue; + if ((ret = save_dev(dev, file)) < 0) + break; + } + + if (ret >= 0) { + cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; + ret = 1; + } + + fclose(file); + if (opened != filename) { + if (ret < 0) { + unlink(opened); + DBG(DEBUG_SAVE, + printf("unlinked temp cache %s\n", opened)); + } else { + char *backup; + + backup = malloc(strlen(filename) + 5); + if (backup) { + sprintf(backup, "%s.old", filename); + unlink(backup); + link(filename, backup); + free(backup); + } + rename(opened, filename); + DBG(DEBUG_SAVE, + printf("moved temp cache %s\n", opened)); + } + } + +errout: + free(tmp); + return ret; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + blkid_cache cache = NULL; + int ret; + + blkid_init_debug(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/shlibs/blkid/src/tag.c b/shlibs/blkid/src/tag.c new file mode 100644 index 00000000..0dbe1ff5 --- /dev/null +++ b/shlibs/blkid/src/tag.c @@ -0,0 +1,474 @@ +/* + * tag.c - allocation/initialization/free routines for tag structs + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "blkidP.h" + +static blkid_tag blkid_new_tag(void) +{ + blkid_tag tag; + + if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag)))) + return NULL; + + INIT_LIST_HEAD(&tag->bit_tags); + INIT_LIST_HEAD(&tag->bit_names); + + return tag; +} + +#ifdef CONFIG_BLKID_DEBUG +void blkid_debug_dump_tag(blkid_tag tag) +{ + if (!tag) { + printf(" tag: NULL\n"); + return; + } + + printf(" tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val); +} +#endif + +void blkid_free_tag(blkid_tag tag) +{ + if (!tag) + return; + + DBG(DEBUG_TAG, printf(" freeing tag %s=%s\n", tag->bit_name, + tag->bit_val ? tag->bit_val : "(NULL)")); + DBG(DEBUG_TAG, blkid_debug_dump_tag(tag)); + + list_del(&tag->bit_tags); /* list of tags for this device */ + list_del(&tag->bit_names); /* list of tags with this type */ + + free(tag->bit_name); + free(tag->bit_val); + + free(tag); +} + +/* + * Find the desired tag on a device. If value is NULL, then the + * first such tag is returned, otherwise return only exact tag if found. + */ +blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type) +{ + struct list_head *p; + + if (!dev || !type) + return NULL; + + list_for_each(p, &dev->bid_tags) { + blkid_tag tmp = list_entry(p, struct blkid_struct_tag, + bit_tags); + + if (!strcmp(tmp->bit_name, type)) + return tmp; + } + return NULL; +} + +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 + free(val); + if (head) + blkid_free_tag(head); + return -BLKID_ERR_MEM; +} + + +/* + * Parse a "NAME=value" string. This is slightly different than + * parse_token, because that will end an unquoted value at a space, while + * this will assume that an unquoted value is the rest of the token (e.g. + * if we are passed an already quoted string from the command-line we don't + * have to both quote and escape quote so that the quotes make it to + * us). + * + * Returns 0 on success, and -1 on failure. + */ +int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val) +{ + char *name, *value, *cp; + + DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token)); + + if (!token || !(cp = strchr(token, '='))) + return -1; + + name = blkid_strdup(token); + if (!name) + return -1; + value = name + (cp - token); + *value++ = '\0'; + if (*value == '"' || *value == '\'') { + char c = *value++; + if (!(cp = strrchr(value, c))) + goto errout; /* missing closing quote */ + *cp = '\0'; + } + value = blkid_strdup(value); + if (!value) + goto errout; + + *ret_type = name; + *ret_val = value; + + return 0; + +errout: + free(name); + return -1; +} + +/* + * Tag iteration routines for the public libblkid interface. + * + * These routines do not expose the list.h implementation, which are a + * contamination of the namespace, and which force us to reveal far, far + * too much of our internal implemenation. I'm not convinced I want + * to keep list.h in the long term, anyway. It's fine for kernel + * programming, but performance is not the #1 priority for this + * library, and I really don't like the tradeoff of type-safety for + * performance for this application. [tytso:20030125.2007EST] + */ + +/* + * This series of functions iterate over all tags in a device + */ +#define TAG_ITERATE_MAGIC 0x01a5284c + +struct blkid_struct_tag_iterate { + int magic; + blkid_dev dev; + struct list_head *p; +}; + +extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev) +{ + blkid_tag_iterate iter; + + iter = malloc(sizeof(struct blkid_struct_tag_iterate)); + if (iter) { + iter->magic = TAG_ITERATE_MAGIC; + iter->dev = dev; + iter->p = dev->bid_tags.next; + } + return (iter); +} + +/* + * Return 0 on success, -1 on error + */ +extern int blkid_tag_next(blkid_tag_iterate iter, + const char **type, const char **value) +{ + blkid_tag tag; + + *type = 0; + *value = 0; + if (!iter || iter->magic != TAG_ITERATE_MAGIC || + iter->p == &iter->dev->bid_tags) + return -1; + tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags); + *type = tag->bit_name; + *value = tag->bit_val; + iter->p = iter->p->next; + return 0; +} + +extern void blkid_tag_iterate_end(blkid_tag_iterate iter) +{ + if (!iter || iter->magic != TAG_ITERATE_MAGIC) + return; + iter->magic = 0; + free(iter); +} + +/* + * This function returns a device which matches a particular + * type/value pair. If there is more than one device that matches the + * search specification, it returns the one with the highest priority + * value. This allows us to give preference to EVMS or LVM devices. + */ +extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache, + const char *type, + const char *value) +{ + blkid_tag head; + blkid_dev dev; + int pri; + struct list_head *p; + int probe_new = 0; + + if (!cache || !type || !value) + return NULL; + + blkid_read_cache(cache); + + DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value)); + +try_again: + pri = -1; + dev = 0; + head = blkid_find_head_cache(cache, type); + + if (head) { + list_for_each(p, &head->bit_names) { + blkid_tag tmp = list_entry(p, struct blkid_struct_tag, + bit_names); + + if (!strcmp(tmp->bit_val, value) && + (tmp->bit_dev->bid_pri > pri) && + !access(tmp->bit_dev->bid_name, F_OK)) { + dev = tmp->bit_dev; + pri = dev->bid_pri; + } + } + } + if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) { + dev = blkid_verify(cache, dev); + if (!dev || (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))) + goto try_again; + } + + if (!dev && !probe_new) { + if (blkid_probe_all_new(cache) < 0) + return NULL; + probe_new++; + goto try_again; + } + + if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) { + if (blkid_probe_all(cache) < 0) + return NULL; + goto try_again; + } + return dev; +} + +#ifdef TEST_PROGRAM +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#else +extern char *optarg; +extern int optind; +#endif + +void usage(char *prog) +{ + fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device " + "[type value]\n", + prog); + fprintf(stderr, "\tList all tags for a device and exit\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + blkid_tag_iterate iter; + blkid_cache cache = NULL; + blkid_dev dev; + int c, ret, found; + int flags = BLKID_DEV_FIND; + char *tmp; + char *file = NULL; + char *devname = NULL; + char *search_type = NULL; + char *search_value = NULL; + const char *type, *value; + + while ((c = getopt (argc, argv, "m:f:")) != EOF) + switch (c) { + case 'f': + file = optarg; + break; + case 'm': + { + int mask = strtoul (optarg, &tmp, 0); + if (*tmp) { + fprintf(stderr, "Invalid debug mask: %s\n", + optarg); + exit(1); + } + blkid_init_debug(mask); + break; + } + case '?': + usage(argv[0]); + } + if (argc > optind) + devname = argv[optind++]; + if (argc > optind) + search_type = argv[optind++]; + if (argc > optind) + search_value = argv[optind++]; + if (!devname || (argc != optind)) + usage(argv[0]); + + if ((ret = blkid_get_cache(&cache, file)) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + + dev = blkid_get_dev(cache, devname, flags); + if (!dev) { + fprintf(stderr, "%s: Can not find device in blkid cache\n", + devname); + exit(1); + } + if (search_type) { + found = blkid_dev_has_tag(dev, search_type, search_value); + printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev), + search_type, search_value ? search_value : "NULL", + found ? "FOUND" : "NOT FOUND"); + return(!found); + } + printf("Device %s...\n", blkid_dev_devname(dev)); + + iter = blkid_tag_iterate_begin(dev); + while (blkid_tag_next(iter, &type, &value) == 0) { + printf("\tTag %s has value %s\n", type, value); + } + blkid_tag_iterate_end(iter); + + blkid_put_cache(cache); + return (0); +} +#endif diff --git a/shlibs/blkid/src/tst_types.c b/shlibs/blkid/src/tst_types.c new file mode 100644 index 00000000..ecbc0321 --- /dev/null +++ b/shlibs/blkid/src/tst_types.c @@ -0,0 +1,63 @@ +/* + * This testing program makes sure the stdint.h header file + * + * Copyright (C) 2006 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <sys/types.h> +#include <stdint.h> + +#include <stdlib.h> +#include <stdio.h> + +int main(int argc, char **argv) +{ + if (sizeof(uint8_t) != 1) { + printf("Sizeof(uint8_t) is %d should be 1\n", + (int)sizeof(uint8_t)); + exit(1); + } + if (sizeof(int8_t) != 1) { + printf("Sizeof(int8_t) is %d should be 1\n", + (int)sizeof(int8_t)); + exit(1); + } + if (sizeof(uint16_t) != 2) { + printf("Sizeof(uint16_t) is %d should be 2\n", + (int)sizeof(uint16_t)); + exit(1); + } + if (sizeof(int16_t) != 2) { + printf("Sizeof(int16_t) is %d should be 2\n", + (int)sizeof(int16_t)); + exit(1); + } + if (sizeof(uint32_t) != 4) { + printf("Sizeof(uint32_t) is %d should be 4\n", + (int)sizeof(uint32_t)); + exit(1); + } + if (sizeof(int32_t) != 4) { + printf("Sizeof(int32_t) is %d should be 4\n", + (int)sizeof(int32_t)); + exit(1); + } + if (sizeof(uint64_t) != 8) { + printf("Sizeof(uint64_t) is %d should be 8\n", + (int)sizeof(uint64_t)); + exit(1); + } + if (sizeof(int64_t) != 8) { + printf("Sizeof(int64_t) is %d should be 8\n", + (int)sizeof(int64_t)); + exit(1); + } + printf("The stdint.h types are correct.\n"); + exit(0); +} + diff --git a/shlibs/blkid/src/verify.c b/shlibs/blkid/src/verify.c new file mode 100644 index 00000000..40ab4c67 --- /dev/null +++ b/shlibs/blkid/src/verify.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include "blkidP.h" + +static void blkid_probe_to_tags(blkid_probe pr, blkid_dev dev) +{ + const char *data; + const char *name; + int nvals, n; + size_t len; + + nvals = blkid_probe_numof_values(pr); + + for (n = 0; n < nvals; n++) { + if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0) + blkid_set_tag(dev, name, data, len); + } +} + +/* + * Verify that the data in dev is consistent with what is on the actual + * block device (using the devname field only). Normally this will be + * called when finding items in the cache, but for long running processes + * is also desirable to revalidate an item before use. + * + * If we are unable to revalidate the data, we return the old data and + * do not set the BLKID_BID_FL_VERIFIED flag on it. + */ +blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) +{ + struct stat st; + time_t diff, now; + char *fltr[2]; + int fd; + + 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 (!cache->probe) + cache->probe = blkid_new_probe(); + + fd = open(dev->bid_name, O_RDONLY); + if (fd < 0) { + DBG(DEBUG_PROBE, printf("blkid_verify: error %s (%d) while " + "opening %s\n", strerror(errno), errno, + dev->bid_name)); + goto open_err; + } + + if (blkid_probe_set_device(cache->probe, fd, 0, 0)) { + /* failed to read the device */ + close(fd); + blkid_free_dev(dev); + return NULL; + } + + blkid_probe_set_request(cache->probe, + BLKID_PROBREQ_LABEL | BLKID_PROBREQ_UUID | + BLKID_PROBREQ_TYPE | BLKID_PROBREQ_SECTYPE); + + /* + * If we already know the type, then try that first. + */ + if (dev->bid_type) { + blkid_tag_iterate iter; + const char *type, *value; + + fltr[0] = dev->bid_type; + fltr[1] = NULL; + + blkid_probe_filter_types(cache->probe, + BLKID_FLTR_ONLYIN, fltr); + + if (!blkid_do_probe(cache->probe)) + goto found_type; + blkid_probe_invert_filter(cache->probe); + + /* + * 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); + } + + /* + * Probe for all types. + */ + if (blkid_do_safeprobe(cache->probe)) { + /* found nothing or error */ + blkid_free_dev(dev); + dev = NULL; + } + +found_type: + if (dev) { + 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_probe_to_tags(cache->probe, dev); + + DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n", + dev->bid_name, (long long)st.st_rdev, dev->bid_type)); + } + + blkid_reset_probe(cache->probe); + blkid_probe_reset_filter(cache->probe); + close(fd); + return dev; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + blkid_dev dev; + blkid_cache cache; + int ret; + + if (argc != 2) { + fprintf(stderr, "Usage: %s device\n" + "Probe a single device to determine type\n", argv[0]); + exit(1); + } + if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL); + if (!dev) { + printf("%s: %s has an unsupported type\n", argv[0], argv[1]); + return (1); + } + printf("TYPE='%s'\n", dev->bid_type ? dev->bid_type : "(null)"); + if (dev->bid_label) + printf("LABEL='%s'\n", dev->bid_label); + if (dev->bid_uuid) + printf("UUID='%s'\n", dev->bid_uuid); + + blkid_free_dev(dev); + return (0); +} +#endif diff --git a/shlibs/blkid/src/version.c b/shlibs/blkid/src/version.c new file mode 100644 index 00000000..838af114 --- /dev/null +++ b/shlibs/blkid/src/version.c @@ -0,0 +1,56 @@ +/* + * version.c --- Return the version of the blkid library + * + * Copyright (C) 2004 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include "blkid.h" + +/* LIBBLKID_* defined in the global config.h */ +static const char *lib_version = LIBBLKID_VERSION; /* release version */ +static const char *lib_date = LIBBLKID_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; +} + +/** + * blkid_get_library_version: + * @ver_string: returns relese version (!= SONAME version) + * @date_string: returns date + * + * Returns release version code. + */ +int blkid_get_library_version(const char **ver_string, + const char **date_string) +{ + if (ver_string) + *ver_string = lib_version; + if (date_string) + *date_string = lib_date; + + return blkid_parse_version_string(lib_version); +} |