import more libs to prep for new e2fsprogs
No binary (build failed)
—
(log yok)
| @@ -0,0 +1,105 @@ | |
| + | /* |
| + | * blkid.h - Interface for libblkid, a library to identify block devices |
| + | * |
| + | * Copyright (C) 2001 Andreas Dilger |
| + | * Copyright (C) 2003 Theodore Ts'o |
| + | * |
| + | * %Begin-Header% |
| + | * This file may be redistributed under the terms of the |
| + | * GNU Lesser General Public License. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #ifndef _BLKID_BLKID_H |
| + | #define _BLKID_BLKID_H |
| + | |
| + | #include <sys/types.h> |
| + | #include <linux/types.h> |
| + | |
| + | #ifdef __cplusplus |
| + | extern "C" { |
| + | #endif |
| + | |
| + | #define BLKID_VERSION "1.0.0" |
| + | #define BLKID_DATE "12-Feb-2003" |
| + | |
| + | typedef struct blkid_struct_dev *blkid_dev; |
| + | typedef struct blkid_struct_cache *blkid_cache; |
| + | typedef __s64 blkid_loff_t; |
| + | |
| + | typedef struct blkid_struct_tag_iterate *blkid_tag_iterate; |
| + | typedef struct blkid_struct_dev_iterate *blkid_dev_iterate; |
| + | |
| + | /* |
| + | * Flags for blkid_get_dev |
| + | * |
| + | * BLKID_DEV_CREATE Create an empty device structure if not found |
| + | * in the cache. |
| + | * BLKID_DEV_VERIFY Make sure the device structure corresponds |
| + | * with reality. |
| + | * BLKID_DEV_FIND Just look up a device entry, and return NULL |
| + | * if it is not found. |
| + | * BLKID_DEV_NORMAL Get a valid device structure, either from the |
| + | * cache or by probing the device. |
| + | */ |
| + | #define BLKID_DEV_FIND 0x0000 |
| + | #define BLKID_DEV_CREATE 0x0001 |
| + | #define BLKID_DEV_VERIFY 0x0002 |
| + | #define BLKID_DEV_NORMAL (BLKID_DEV_CREATE | BLKID_DEV_VERIFY) |
| + | |
| + | /* cache.c */ |
| + | extern void blkid_put_cache(blkid_cache cache); |
| + | extern int blkid_get_cache(blkid_cache *cache, const char *filename); |
| + | |
| + | /* 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_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 blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, |
| + | int flags); |
| + | |
| + | /* getsize.c */ |
| + | extern blkid_loff_t blkid_get_dev_size(int fd); |
| + | |
| + | /* probe.c */ |
| + | int blkid_known_fstype(const char *fstype); |
| + | extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev); |
| + | |
| + | /* read.c */ |
| + | |
| + | /* resolve.c */ |
| + | extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname, |
| + | const char *devname); |
| + | extern char *blkid_get_devname(blkid_cache cache, const char *token, |
| + | const char *value); |
| + | |
| + | /* tag.c */ |
| + | extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev); |
| + | extern int blkid_tag_next(blkid_tag_iterate iterate, |
| + | const char **type, const char **value); |
| + | extern void blkid_tag_iterate_end(blkid_tag_iterate iterate); |
| + | |
| + | extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache, |
| + | const char *type, |
| + | const char *value); |
| + | extern int blkid_parse_tag_string(const char *token, char **ret_type, |
| + | char **ret_val); |
| + | |
| + | /* version.c */ |
| + | extern int blkid_parse_version_string(const char *ver_string); |
| + | extern int blkid_get_library_version(const char **ver_string, |
| + | const char **date_string); |
| + | |
| + | #ifdef __cplusplus |
| + | } |
| + | #endif |
| + | |
| + | #endif /* _BLKID_BLKID_H */ |
| @@ -0,0 +1,239 @@ | |
| + | /* |
| + | * blkidP.h - Internal interfaces for libblkid |
| + | * |
| + | * Copyright (C) 2001 Andreas Dilger |
| + | * Copyright (C) 2003 Theodore Ts'o |
| + | * |
| + | * %Begin-Header% |
| + | * This file may be redistributed under the terms of the |
| + | * GNU Lesser General Public License. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #ifndef _BLKID_BLKIDP_H |
| + | #define _BLKID_BLKIDP_H |
| + | |
| + | #include <sys/types.h> |
| + | #include <stdio.h> |
| + | |
| + | #include <blkid/blkid.h> |
| + | |
| + | #include <blkid/list.h> |
| + | |
| + | #ifdef __GNUC__ |
| + | #define __BLKID_ATTR(x) __attribute__(x) |
| + | #else |
| + | #define __BLKID_ATTR(x) |
| + | #endif |
| + | |
| + | |
| + | /* |
| + | * This describes the attributes of a specific device. |
| + | * We can traverse all of the tags by bid_tags (linking to the tag bit_names). |
| + | * The bid_label and bid_uuid fields are shortcuts to the LABEL and UUID tag |
| + | * values, if they exist. |
| + | */ |
| + | struct blkid_struct_dev |
| + | { |
| + | struct list_head bid_devs; /* All devices in the cache */ |
| + | struct list_head bid_tags; /* All tags for this device */ |
| + | blkid_cache bid_cache; /* Dev belongs to this cache */ |
| + | char *bid_name; /* Device inode pathname */ |
| + | char *bid_type; /* Preferred device TYPE */ |
| + | int bid_pri; /* Device priority */ |
| + | dev_t bid_devno; /* Device major/minor number */ |
| + | time_t bid_time; /* Last update time of device */ |
| + | unsigned int bid_flags; /* Device status bitflags */ |
| + | char *bid_label; /* Shortcut to device LABEL */ |
| + | char *bid_uuid; /* Shortcut to binary UUID */ |
| + | }; |
| + | |
| + | #define BLKID_BID_FL_VERIFIED 0x0001 /* Device data validated from disk */ |
| + | #define BLKID_BID_FL_INVALID 0x0004 /* Device is invalid */ |
| + | |
| + | /* |
| + | * Each tag defines a NAME=value pair for a particular device. The tags |
| + | * are linked via bit_names for a single device, so that traversing the |
| + | * names list will get you a list of all tags associated with a device. |
| + | * They are also linked via bit_values for all devices, so one can easily |
| + | * search all tags with a given NAME for a specific value. |
| + | */ |
| + | struct blkid_struct_tag |
| + | { |
| + | struct list_head bit_tags; /* All tags for this device */ |
| + | struct list_head bit_names; /* All tags with given NAME */ |
| + | char *bit_name; /* NAME of tag (shared) */ |
| + | char *bit_val; /* value of tag */ |
| + | blkid_dev bit_dev; /* pointer to device */ |
| + | }; |
| + | typedef struct blkid_struct_tag *blkid_tag; |
| + | |
| + | /* |
| + | * Minimum number of seconds between device probes, even when reading |
| + | * from the cache. This is to avoid re-probing all devices which were |
| + | * just probed by another program that does not share the cache. |
| + | */ |
| + | #define BLKID_PROBE_MIN 2 |
| + | |
| + | /* |
| + | * Time in seconds an entry remains verified in the in-memory cache |
| + | * before being reverified (in case of long-running processes that |
| + | * keep a cache in memory and continue to use it for a long time). |
| + | */ |
| + | #define BLKID_PROBE_INTERVAL 200 |
| + | |
| + | /* This describes an entire blkid cache file and probed devices. |
| + | * We can traverse all of the found devices via bic_list. |
| + | * We can traverse all of the tag types by bic_tags, which hold empty tags |
| + | * for each tag type. Those tags can be used as list_heads for iterating |
| + | * through all devices with a specific tag type (e.g. LABEL). |
| + | */ |
| + | struct blkid_struct_cache |
| + | { |
| + | struct list_head bic_devs; /* List head of all devices */ |
| + | struct list_head bic_tags; /* List head of all tag types */ |
| + | time_t bic_time; /* Last probe time */ |
| + | time_t bic_ftime; /* Mod time of the cachefile */ |
| + | unsigned int bic_flags; /* Status flags of the cache */ |
| + | char *bic_filename; /* filename of cache */ |
| + | }; |
| + | |
| + | #define BLKID_BIC_FL_PROBED 0x0002 /* We probed /proc/partition devices */ |
| + | #define BLKID_BIC_FL_CHANGED 0x0004 /* Cache has changed from disk */ |
| + | |
| + | extern char *blkid_strdup(const char *s); |
| + | extern char *blkid_strndup(const char *s, const int length); |
| + | |
| + | #define BLKID_CACHE_FILE "/etc/blkid.tab" |
| + | extern const char *blkid_devdirs[]; |
| + | |
| + | #define BLKID_ERR_IO 5 |
| + | #define BLKID_ERR_PROC 9 |
| + | #define BLKID_ERR_MEM 12 |
| + | #define BLKID_ERR_CACHE 14 |
| + | #define BLKID_ERR_DEV 19 |
| + | #define BLKID_ERR_PARAM 22 |
| + | #define BLKID_ERR_BIG 27 |
| + | |
| + | /* |
| + | * Priority settings for different types of devices |
| + | */ |
| + | #define BLKID_PRI_EVMS 30 |
| + | #define BLKID_PRI_LVM 20 |
| + | #define BLKID_PRI_MD 10 |
| + | |
| + | #if defined(TEST_PROGRAM) && !defined(CONFIG_BLKID_DEBUG) |
| + | #define CONFIG_BLKID_DEBUG |
| + | #endif |
| + | |
| + | #define DEBUG_CACHE 0x0001 |
| + | #define DEBUG_DUMP 0x0002 |
| + | #define DEBUG_DEV 0x0004 |
| + | #define DEBUG_DEVNAME 0x0008 |
| + | #define DEBUG_DEVNO 0x0010 |
| + | #define DEBUG_PROBE 0x0020 |
| + | #define DEBUG_READ 0x0040 |
| + | #define DEBUG_RESOLVE 0x0080 |
| + | #define DEBUG_SAVE 0x0100 |
| + | #define DEBUG_TAG 0x0200 |
| + | #define DEBUG_INIT 0x8000 |
| + | #define DEBUG_ALL 0xFFFF |
| + | |
| + | #ifdef CONFIG_BLKID_DEBUG |
| + | #include <stdio.h> |
| + | extern int blkid_debug_mask; |
| + | #define DBG(m,x) if ((m) & blkid_debug_mask) x; |
| + | #else |
| + | #define DBG(m,x) |
| + | #endif |
| + | |
| + | #ifdef CONFIG_BLKID_DEBUG |
| + | static inline void DEB_DUMP_TAG(int mask, blkid_tag tag) |
| + | { |
| + | if (!(mask & blkid_debug_mask)) |
| + | return; |
| + | |
| + | if (!tag) { |
| + | printf(" tag: NULL\n"); |
| + | return; |
| + | } |
| + | |
| + | printf(" tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val); |
| + | } |
| + | |
| + | static inline void DEB_DUMP_DEV(int mask, blkid_dev dev) |
| + | { |
| + | struct list_head *p; |
| + | |
| + | if (!(mask & blkid_debug_mask)) |
| + | return; |
| + | |
| + | if (!dev) { |
| + | printf(" dev: NULL\n"); |
| + | return; |
| + | } |
| + | |
| + | printf(" dev: name = %s\n", dev->bid_name); |
| + | printf(" dev: DEVNO=\"0x%0Lx\"\n", dev->bid_devno); |
| + | printf(" dev: TIME=\"%lu\"\n", 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); |
| + | DEB_DUMP_TAG(mask, tag); |
| + | } |
| + | printf("\n"); |
| + | } |
| + | |
| + | static inline void DEB_DUMP_CACHE(int mask, blkid_cache cache) |
| + | { |
| + | struct list_head *p; |
| + | |
| + | if (!cache || !(mask & blkid_debug_mask)) { |
| + | 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); |
| + | DEB_DUMP_DEV(mask, dev); |
| + | } |
| + | } |
| + | #else |
| + | #define DEB_DUMP_TAG(mask, tag) do {} while (0) |
| + | #define DEB_DUMP_DEV(mask, dev) do {} while (0) |
| + | #define DEB_DUMP_CACHE(mask, cache) do {} while (0) |
| + | #endif |
| + | |
| + | /* lseek.c */ |
| + | extern blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence); |
| + | |
| + | /* read.c */ |
| + | extern void blkid_read_cache(blkid_cache cache); |
| + | |
| + | /* save.c */ |
| + | extern int blkid_flush_cache(blkid_cache cache); |
| + | |
| + | /* |
| + | * Functions to create and find a specific tag type: tag.c |
| + | */ |
| + | extern void blkid_free_tag(blkid_tag tag); |
| + | extern blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type); |
| + | extern int blkid_set_tag(blkid_dev dev, const char *name, |
| + | const char *value, const int vlength); |
| + | |
| + | /* |
| + | * Functions to create and find a specific tag type: dev.c |
| + | */ |
| + | extern blkid_dev blkid_new_dev(void); |
| + | extern void blkid_free_dev(blkid_dev dev); |
| + | |
| + | #ifdef __cplusplus |
| + | } |
| + | #endif |
| + | |
| + | #endif /* _BLKID_BLKIDP_H */ |
| @@ -0,0 +1,126 @@ | |
| + | /* |
| + | * 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% |
| + | */ |
| + | |
| + | #include <stdlib.h> |
| + | #include <string.h> |
| + | #include <unistd.h> |
| + | #include "blkidP.h" |
| + | |
| + | int blkid_debug_mask = 0; |
| + | |
| + | int blkid_get_cache(blkid_cache *ret_cache, const char *filename) |
| + | { |
| + | blkid_cache cache; |
| + | |
| + | #ifdef CONFIG_BLKID_DEBUG |
| + | if (!(blkid_debug_mask & DEBUG_INIT)) { |
| + | char *dstr = getenv("BLKID_DEBUG"); |
| + | |
| + | if (dstr) |
| + | blkid_debug_mask = strtoul(dstr, 0, 0); |
| + | blkid_debug_mask |= DEBUG_INIT; |
| + | } |
| + | #endif |
| + | |
| + | DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n", |
| + | filename ? filename : "default cache")); |
| + | |
| + | if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache)))) |
| + | return -BLKID_ERR_MEM; |
| + | |
| + | INIT_LIST_HEAD(&cache->bic_devs); |
| + | INIT_LIST_HEAD(&cache->bic_tags); |
| + | |
| + | if (filename && !strlen(filename)) |
| + | filename = 0; |
| + | if (!filename && (getuid() == geteuid())) |
| + | filename = getenv("BLKID_FILE"); |
| + | if (!filename) |
| + | filename = BLKID_CACHE_FILE; |
| + | cache->bic_filename = blkid_strdup(filename); |
| + | |
| + | blkid_read_cache(cache); |
| + | |
| + | *ret_cache = cache; |
| + | return 0; |
| + | } |
| + | |
| + | void blkid_put_cache(blkid_cache cache) |
| + | { |
| + | if (!cache) |
| + | return; |
| + | |
| + | (void) blkid_flush_cache(cache); |
| + | |
| + | DBG(DEBUG_CACHE, printf("freeing cache struct\n")); |
| + | |
| + | /* DEB_DUMP_CACHE(cache); */ |
| + | |
| + | while (!list_empty(&cache->bic_devs)) { |
| + | blkid_dev dev = list_entry(cache->bic_devs.next, |
| + | struct blkid_struct_dev, |
| + | bid_devs); |
| + | blkid_free_dev(dev); |
| + | } |
| + | |
| + | while (!list_empty(&cache->bic_tags)) { |
| + | blkid_tag tag = list_entry(cache->bic_tags.next, |
| + | struct blkid_struct_tag, |
| + | bit_tags); |
| + | |
| + | while (!list_empty(&tag->bit_names)) { |
| + | blkid_tag bad = list_entry(tag->bit_names.next, |
| + | struct blkid_struct_tag, |
| + | bit_names); |
| + | |
| + | DBG(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n", |
| + | bad->bit_name, bad->bit_val)); |
| + | blkid_free_tag(bad); |
| + | } |
| + | blkid_free_tag(tag); |
| + | } |
| + | if (cache->bic_filename) |
| + | free(cache->bic_filename); |
| + | |
| + | free(cache); |
| + | } |
| + | |
| + | #ifdef TEST_PROGRAM |
| + | int main(int argc, char** argv) |
| + | { |
| + | blkid_cache cache = NULL; |
| + | int ret; |
| + | |
| + | blkid_debug_mask = DEBUG_ALL; |
| + | if ((argc > 2)) { |
| + | fprintf(stderr, "Usage: %s [filename] \n", argv[0]); |
| + | exit(1); |
| + | } |
| + | |
| + | if ((ret = blkid_get_cache(&cache, argv[1])) < 0) { |
| + | fprintf(stderr, "error %d parsing cache file %s\n", ret, |
| + | argv[1] ? argv[1] : BLKID_CACHE_FILE); |
| + | exit(1); |
| + | } |
| + | if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { |
| + | fprintf(stderr, "%s: error creating cache (%d)\n", |
| + | argv[0], ret); |
| + | exit(1); |
| + | } |
| + | if ((ret = blkid_probe_all(cache) < 0)) |
| + | fprintf(stderr, "error probing devices\n"); |
| + | |
| + | blkid_put_cache(cache); |
| + | |
| + | return ret; |
| + | } |
| + | #endif |
| @@ -0,0 +1,118 @@ | |
| + | /* |
| + | * 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)); |
| + | DEB_DUMP_DEV(DEBUG_DEV, dev); |
| + | |
| + | list_del(&dev->bid_devs); |
| + | while (!list_empty(&dev->bid_tags)) { |
| + | blkid_tag tag = list_entry(dev->bid_tags.next, |
| + | struct blkid_struct_tag, |
| + | bit_tags); |
| + | blkid_free_tag(tag); |
| + | } |
| + | if (dev->bid_name) |
| + | free(dev->bid_name); |
| + | free(dev); |
| + | } |
| + | |
| + | /* |
| + | * Given a blkid device, return its name |
| + | */ |
| + | extern const char *blkid_dev_devname(blkid_dev dev) |
| + | { |
| + | return dev->bid_name; |
| + | } |
| + | |
| + | /* |
| + | * 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; |
| + | 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; |
| + | } |
| + | return (iter); |
| + | } |
| + | |
| + | /* |
| + | * Return 0 on success, -1 on error |
| + | */ |
| + | extern int blkid_dev_next(blkid_dev_iterate iter, |
| + | blkid_dev *dev) |
| + | { |
| + | *dev = 0; |
| + | if (!iter || iter->magic != DEV_ITERATE_MAGIC || |
| + | iter->p == &iter->cache->bic_devs) |
| + | return -1; |
| + | *dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs); |
| + | iter->p = iter->p->next; |
| + | return 0; |
| + | } |
| + | |
| + | extern void blkid_dev_iterate_end(blkid_dev_iterate iter) |
| + | { |
| + | if (!iter || iter->magic != DEV_ITERATE_MAGIC) |
| + | return; |
| + | iter->magic = 0; |
| + | free(iter); |
| + | } |
| + | |
| @@ -0,0 +1,376 @@ | |
| + | /* |
| + | * 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% |
| + | */ |
| + | |
| + | #include <stdio.h> |
| + | #include <string.h> |
| + | #if HAVE_UNISTD_H |
| + | #include <unistd.h> |
| + | #endif |
| + | #include <stdlib.h> |
| + | #include <string.h> |
| + | #include <ctype.h> |
| + | #if HAVE_SYS_TYPES_H |
| + | #include <sys/types.h> |
| + | #endif |
| + | #if HAVE_SYS_STAT_H |
| + | #include <sys/stat.h> |
| + | #endif |
| + | #if HAVE_ERRNO_H |
| + | #include <errno.h> |
| + | #endif |
| + | #if HAVE_SYS_MKDEV_H |
| + | #include <sys/mkdev.h> |
| + | #endif |
| + | #include <time.h> |
| + | |
| + | #include "blkidP.h" |
| + | |
| + | /* |
| + | * 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; |
| + | |
| + | if (!cache || !devname) |
| + | return NULL; |
| + | |
| + | list_for_each(p, &cache->bic_devs) { |
| + | tmp = list_entry(p, struct blkid_struct_dev, bid_devs); |
| + | if (strcmp(tmp->bid_name, devname)) |
| + | continue; |
| + | |
| + | DBG(DEBUG_DEVNAME, |
| + | printf("found devname %s in cache\n", tmp->bid_name)); |
| + | dev = tmp; |
| + | break; |
| + | } |
| + | |
| + | if (!dev && (flags & BLKID_DEV_CREATE)) { |
| + | dev = blkid_new_dev(); |
| + | if (!dev) |
| + | return NULL; |
| + | dev->bid_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); |
| + | return dev; |
| + | } |
| + | |
| + | /* |
| + | * 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) |
| + | { |
| + | blkid_dev dev = NULL; |
| + | struct list_head *p; |
| + | const char **dir; |
| + | char *devname = NULL; |
| + | |
| + | /* See if we already have this device number in the cache. */ |
| + | list_for_each(p, &cache->bic_devs) { |
| + | blkid_dev tmp = list_entry(p, struct blkid_struct_dev, |
| + | bid_devs); |
| + | if (tmp->bid_devno == devno) { |
| + | dev = blkid_verify(cache, tmp); |
| + | break; |
| + | } |
| + | } |
| + | if (dev && dev->bid_devno == devno) |
| + | goto set_pri; |
| + | |
| + | /* |
| + | * Take a quick look at /dev/ptname for the device number. We check |
| + | * all of the likely device directories. If we don't find it, or if |
| + | * the stat information doesn't check out, use blkid_devno_to_devname() |
| + | * to find it via an exhaustive search for the device major/minor. |
| + | */ |
| + | for (dir = blkid_devdirs; *dir; dir++) { |
| + | struct stat st; |
| + | char device[256]; |
| + | |
| + | sprintf(device, "%s/%s", *dir, ptname); |
| + | if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) && |
| + | dev->bid_devno == devno) |
| + | goto set_pri; |
| + | |
| + | if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) && |
| + | st.st_rdev == devno) { |
| + | devname = blkid_strdup(device); |
| + | break; |
| + | } |
| + | } |
| + | if (!devname) { |
| + | devname = blkid_devno_to_devname(devno); |
| + | if (!devname) |
| + | return; |
| + | } |
| + | dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); |
| + | free(devname); |
| + | |
| + | set_pri: |
| + | if (!pri && !strncmp(ptname, "md", 2)) |
| + | pri = BLKID_PRI_MD; |
| + | if (dev) |
| + | dev->bid_pri = pri; |
| + | return; |
| + | } |
| + | |
| + | #define PROC_PARTITIONS "/proc/partitions" |
| + | #define VG_DIR "/proc/lvm/VGs" |
| + | |
| + | /* |
| + | * This function initializes the UUID cache with devices from the LVM |
| + | * proc hierarchy. We currently depend on the names of the LVM |
| + | * hierarchy giving us the device structure in /dev. (XXX is this a |
| + | * safe thing to do?) |
| + | */ |
| + | #ifdef VG_DIR |
| + | #include <dirent.h> |
| + | static dev_t lvm_get_devno(const char *lvm_device) |
| + | { |
| + | FILE *lvf; |
| + | char buf[1024]; |
| + | int ma, mi; |
| + | dev_t ret = 0; |
| + | |
| + | DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device)); |
| + | if ((lvf = fopen(lvm_device, "r")) == NULL) { |
| + | DBG(DEBUG_DEVNAME, printf("%s: (%d) %s\n", lvm_device, errno, |
| + | strerror(errno))); |
| + | return 0; |
| + | } |
| + | |
| + | while (fgets(buf, sizeof(buf), lvf)) { |
| + | if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) { |
| + | ret = makedev(ma, mi); |
| + | break; |
| + | } |
| + | } |
| + | fclose(lvf); |
| + | |
| + | return ret; |
| + | } |
| + | |
| + | static void lvm_probe_all(blkid_cache cache) |
| + | { |
| + | 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); |
| + | 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) |
| + | { |
| + | 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); |
| + | num++; |
| + | } |
| + | fclose(procpt); |
| + | return num; |
| + | } |
| + | |
| + | /* |
| + | * Read the device data for all available block devices in the system. |
| + | */ |
| + | int blkid_probe_all(blkid_cache cache) |
| + | { |
| + | FILE *proc; |
| + | char line[1024]; |
| + | char ptname0[128], ptname1[128], *ptname = 0; |
| + | char *ptnames[2]; |
| + | dev_t devs[2]; |
| + | int ma, mi; |
| + | unsigned long long sz; |
| + | int lens[2] = { 0, 0 }; |
| + | int which = 0, last = 0; |
| + | |
| + | ptnames[0] = ptname0; |
| + | ptnames[1] = ptname1; |
| + | |
| + | if (!cache) |
| + | return -BLKID_ERR_PARAM; |
| + | |
| + | if (cache->bic_flags & BLKID_BIC_FL_PROBED && |
| + | time(0) - cache->bic_time < BLKID_PROBE_INTERVAL) |
| + | return 0; |
| + | |
| + | blkid_read_cache(cache); |
| + | evms_probe_all(cache); |
| + | #ifdef VG_DIR |
| + | lvm_probe_all(cache); |
| + | #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 we don't have a partition on this dev, also |
| + | * check previous dev to see if it didn't have a partn. |
| + | * heuristic: partition name ends in a digit. |
| + | * |
| + | * Skip extended partitions. |
| + | * heuristic: size is 1 |
| + | * |
| + | * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs |
| + | */ |
| + | |
| + | lens[which] = strlen(ptname); |
| + | 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); |
| + | lens[which] = 0; |
| + | lens[last] = 0; |
| + | } else 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); |
| + | lens[last] = 0; |
| + | } |
| + | } |
| + | |
| + | /* Handle the last device if it wasn't partitioned */ |
| + | if (lens[which]) |
| + | probe_one(cache, ptname, devs[which], 0); |
| + | |
| + | fclose(proc); |
| + | |
| + | cache->bic_time = time(0); |
| + | cache->bic_flags |= BLKID_BIC_FL_PROBED; |
| + | blkid_flush_cache(cache); |
| + | return 0; |
| + | } |
| + | |
| + | #ifdef TEST_PROGRAM |
| + | int main(int argc, char **argv) |
| + | { |
| + | blkid_cache cache = NULL; |
| + | int ret; |
| + | |
| + | blkid_debug_mask = DEBUG_ALL; |
| + | if (argc != 1) { |
| + | fprintf(stderr, "Usage: %s\n" |
| + | "Probe all devices and exit\n", argv[0]); |
| + | exit(1); |
| + | } |
| + | if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { |
| + | fprintf(stderr, "%s: error creating cache (%d)\n", |
| + | argv[0], ret); |
| + | exit(1); |
| + | } |
| + | if (blkid_probe_all(cache) < 0) |
| + | printf("%s: error probing devices\n", argv[0]); |
| + | |
| + | blkid_put_cache(cache); |
| + | return (0); |
| + | } |
| + | #endif |
| @@ -0,0 +1,233 @@ | |
| + | /* |
| + | * devno.c - find a particular device by its device number (major/minor) |
| + | * |
| + | * Copyright (C) 2000, 2001, 2003 Theodore Ts'o |
| + | * Copyright (C) 2001 Andreas Dilger |
| + | * |
| + | * %Begin-Header% |
| + | * This file may be redistributed under the terms of the |
| + | * GNU Lesser General Public License. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include <stdio.h> |
| + | #include <string.h> |
| + | #if HAVE_UNISTD_H |
| + | #include <unistd.h> |
| + | #endif |
| + | #include <stdlib.h> |
| + | #include <string.h> |
| + | #if HAVE_SYS_TYPES_H |
| + | #include <sys/types.h> |
| + | #endif |
| + | #if HAVE_SYS_STAT_H |
| + | #include <sys/stat.h> |
| + | #endif |
| + | #include <dirent.h> |
| + | #if HAVE_ERRNO_H |
| + | #include <errno.h> |
| + | #endif |
| + | #if HAVE_SYS_MKDEV_H |
| + | #include <sys/mkdev.h> |
| + | #endif |
| + | |
| + | #include "blkidP.h" |
| + | |
| + | struct dir_list { |
| + | char *name; |
| + | struct dir_list *next; |
| + | }; |
| + | |
| + | char *blkid_strndup(const char *s, int length) |
| + | { |
| + | char *ret; |
| + | |
| + | if (!s) |
| + | return NULL; |
| + | |
| + | if (!length) |
| + | length = strlen(s); |
| + | |
| + | ret = malloc(length + 1); |
| + | if (ret) { |
| + | strncpy(ret, s, length); |
| + | ret[length] = '\0'; |
| + | } |
| + | return ret; |
| + | } |
| + | |
| + | char *blkid_strdup(const char *s) |
| + | { |
| + | return blkid_strndup(s, 0); |
| + | } |
| + | |
| + | /* |
| + | * This function adds an entry to the directory list |
| + | */ |
| + | static void add_to_dirlist(const char *name, struct dir_list **list) |
| + | { |
| + | struct dir_list *dp; |
| + | |
| + | dp = malloc(sizeof(struct dir_list)); |
| + | if (!dp) |
| + | return; |
| + | dp->name = blkid_strdup(name); |
| + | if (!dp->name) { |
| + | free(dp); |
| + | return; |
| + | } |
| + | dp->next = *list; |
| + | *list = dp; |
| + | } |
| + | |
| + | /* |
| + | * This function frees a directory list |
| + | */ |
| + | static void free_dirlist(struct dir_list **list) |
| + | { |
| + | struct dir_list *dp, *next; |
| + | |
| + | for (dp = *list; dp; dp = next) { |
| + | next = dp->next; |
| + | free(dp->name); |
| + | free(dp); |
| + | } |
| + | *list = NULL; |
| + | } |
| + | |
| + | static void scan_dir(char *dir_name, 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(dir_name)) == NULL) |
| + | return; |
| + | dirlen = strlen(dir_name) + 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", dir_name, dp->d_name); |
| + | if (stat(path, &st) < 0) |
| + | continue; |
| + | |
| + | if (S_ISDIR(st.st_mode)) |
| + | add_to_dirlist(path, list); |
| + | else if (S_ISBLK(st.st_mode) && st.st_rdev == devno) { |
| + | *devname = blkid_strdup(path); |
| + | DBG(DEBUG_DEVNO, |
| + | printf("found 0x%Lx at %s (%p)\n", devno, |
| + | path, *devname)); |
| + | break; |
| + | } |
| + | } |
| + | closedir(dir); |
| + | return; |
| + | } |
| + | |
| + | /* Directories where we will try to search for device numbers */ |
| + | const char *blkid_devdirs[] = { "/devices", "/devfs", "/dev", NULL }; |
| + | |
| + | /* |
| + | * This function finds the pathname to a block device with a given |
| + | * device number. It returns a pointer to allocated memory to the |
| + | * pathname on success, and NULL on failure. |
| + | */ |
| + | char *blkid_devno_to_devname(dev_t devno) |
| + | { |
| + | struct dir_list *list = NULL, *new_list = NULL; |
| + | char *devname = NULL; |
| + | const char **dir; |
| + | |
| + | /* |
| + | * Add the starting directories to search in reverse order of |
| + | * importance, since we are using a stack... |
| + | */ |
| + | for (dir = blkid_devdirs; *dir; dir++) |
| + | add_to_dirlist(*dir, &list); |
| + | |
| + | while (list) { |
| + | struct dir_list *current = list; |
| + | |
| + | list = list->next; |
| + | DBG(DEBUG_DEVNO, printf("directory %s\n", current->name)); |
| + | scan_dir(current->name, devno, &new_list, &devname); |
| + | free(current->name); |
| + | free(current); |
| + | if (devname) |
| + | break; |
| + | /* |
| + | * If we're done checking at this level, descend to |
| + | * the next level of subdirectories. (breadth-first) |
| + | */ |
| + | if (list == NULL) { |
| + | list = new_list; |
| + | new_list = NULL; |
| + | } |
| + | } |
| + | free_dirlist(&list); |
| + | free_dirlist(&new_list); |
| + | |
| + | if (!devname) { |
| + | DBG(DEBUG_DEVNO, |
| + | printf("blkid: couldn't find devno 0x%04lx\n", |
| + | (unsigned long) devno)); |
| + | } else { |
| + | DBG(DEBUG_DEVNO, |
| + | printf("found devno 0x%04Lx as %s\n", devno, devname)); |
| + | } |
| + | |
| + | |
| + | return devname; |
| + | } |
| + | |
| + | #ifdef TEST_PROGRAM |
| + | int main(int argc, char** argv) |
| + | { |
| + | char *devname, *tmp; |
| + | int major, minor; |
| + | dev_t devno; |
| + | const char *errmsg = "Couldn't parse %s: %s\n"; |
| + | |
| + | blkid_debug_mask = DEBUG_ALL; |
| + | if ((argc != 2) && (argc != 3)) { |
| + | fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n" |
| + | "Resolve a device number to a device name\n", |
| + | argv[0], argv[0]); |
| + | exit(1); |
| + | } |
| + | if (argc == 2) { |
| + | devno = strtoul(argv[1], &tmp, 0); |
| + | if (*tmp) { |
| + | fprintf(stderr, errmsg, "device number", argv[1]); |
| + | exit(1); |
| + | } |
| + | } else { |
| + | major = strtoul(argv[1], &tmp, 0); |
| + | if (*tmp) { |
| + | fprintf(stderr, errmsg, "major number", argv[1]); |
| + | exit(1); |
| + | } |
| + | minor = strtoul(argv[2], &tmp, 0); |
| + | if (*tmp) { |
| + | fprintf(stderr, errmsg, "minor number", argv[2]); |
| + | exit(1); |
| + | } |
| + | devno = makedev(major, minor); |
| + | } |
| + | printf("Looking for device 0x%04Lx\n", devno); |
| + | devname = blkid_devno_to_devname(devno); |
| + | if (devname) |
| + | free(devname); |
| + | return 0; |
| + | } |
| + | #endif |
| @@ -0,0 +1,180 @@ | |
| + | /* |
| + | * 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% |
| + | */ |
| + | |
| + | /* 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> |
| + | #include <sys/stat.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 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 blocks 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 |
| + | |
| + | #ifdef FDGETPRM |
| + | if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) |
| + | return (blkid_loff_t)this_floppy.size << 9; |
| + | #endif |
| + | #ifdef HAVE_SYS_DISKLABEL_H |
| + | #if 0 |
| + | /* |
| + | * This should work in theory but I haven't tested it. Anyone |
| + | * on a BSD system want to test this for me? In the meantime, |
| + | * binary search mechanism should work just fine. |
| + | */ |
| + | if ((fstat(fd, &st) >= 0) && S_ISBLK(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 |
| + | #endif /* HAVE_SYS_DISKLABEL_H */ |
| + | |
| + | /* |
| + | * 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) |
| + | { |
| + | blkid_loff_t 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], bytes >> 10); |
| + | |
| + | return 0; |
| + | } |
| + | #endif |
| @@ -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 */ |
| @@ -0,0 +1,139 @@ | |
| + | /* |
| + | * 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% |
| + | */ |
| + | |
| + | #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 defined(__alpha__) || defined(__ia64__) |
| + | |
| + | #define llseek lseek |
| + | |
| + | #else /* !__alpha__ && !__ia64__*/ |
| + | |
| + | #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 */ |
| + | |
| + | |
| @@ -0,0 +1,704 @@ | |
| + | /* |
| + | * probe.c - identify a block device by its contents, and return a dev |
| + | * struct with the details |
| + | * |
| + | * Copyright (C) 1999 by Andries Brouwer |
| + | * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o |
| + | * Copyright (C) 2001 by Andreas Dilger |
| + | * |
| + | * %Begin-Header% |
| + | * This file may be redistributed under the terms of the |
| + | * GNU Lesser General Public License. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include <stdio.h> |
| + | #include <string.h> |
| + | #include <stdlib.h> |
| + | #include <unistd.h> |
| + | #include <fcntl.h> |
| + | #include <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" |
| + | #include "uuid/uuid.h" |
| + | #include "probe.h" |
| + | |
| + | /* |
| + | * This is a special case code to check for an MDRAID device. We do |
| + | * this special since it requires checking for a superblock at the end |
| + | * of the device. |
| + | */ |
| + | static int check_mdraid(int fd, unsigned char *ret_uuid) |
| + | { |
| + | struct mdp_superblock_s *md; |
| + | blkid_loff_t offset; |
| + | char buf[4096]; |
| + | |
| + | if (fd < 0) |
| + | return -BLKID_ERR_PARAM; |
| + | |
| + | offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536; |
| + | |
| + | if (blkid_llseek(fd, offset, 0) < 0 || |
| + | read(fd, buf, 4096) != 4096) |
| + | return -BLKID_ERR_IO; |
| + | |
| + | /* Check for magic number */ |
| + | if (memcmp("\251+N\374", buf, 4)) |
| + | return -BLKID_ERR_PARAM; |
| + | |
| + | if (!ret_uuid) |
| + | return 0; |
| + | *ret_uuid = 0; |
| + | |
| + | /* The MD UUID is not contiguous in the superblock, make it so */ |
| + | md = (struct mdp_superblock_s *)buf; |
| + | if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) { |
| + | memcpy(ret_uuid, &md->set_uuid0, 4); |
| + | memcpy(ret_uuid, &md->set_uuid1, 12); |
| + | } |
| + | return 0; |
| + | } |
| + | |
| + | static void set_uuid(blkid_dev dev, uuid_t uuid) |
| + | { |
| + | char str[37]; |
| + | |
| + | if (!uuid_is_null(uuid)) { |
| + | uuid_unparse(uuid, str); |
| + | blkid_set_tag(dev, "UUID", str, sizeof(str)); |
| + | } |
| + | } |
| + | |
| + | static void get_ext2_info(blkid_dev dev, unsigned char *buf) |
| + | { |
| + | struct ext2_super_block *es = (struct ext2_super_block *) buf; |
| + | const char *label = 0; |
| + | |
| + | DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n", |
| + | blkid_le32(es->s_feature_compat), |
| + | blkid_le32(es->s_feature_incompat), |
| + | blkid_le32(es->s_feature_ro_compat))); |
| + | |
| + | if (strlen(es->s_volume_name)) |
| + | label = es->s_volume_name; |
| + | blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name)); |
| + | |
| + | set_uuid(dev, es->s_uuid); |
| + | } |
| + | |
| + | static int probe_ext3(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id, unsigned char *buf) |
| + | { |
| + | struct ext2_super_block *es; |
| + | |
| + | es = (struct ext2_super_block *)buf; |
| + | |
| + | /* Distinguish between jbd and ext2/3 fs */ |
| + | if (blkid_le32(es->s_feature_incompat) & |
| + | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) |
| + | return -BLKID_ERR_PARAM; |
| + | |
| + | /* Distinguish between ext3 and ext2 */ |
| + | if (!(blkid_le32(es->s_feature_compat) & |
| + | EXT3_FEATURE_COMPAT_HAS_JOURNAL)) |
| + | return -BLKID_ERR_PARAM; |
| + | |
| + | get_ext2_info(dev, buf); |
| + | |
| + | blkid_set_tag(dev, "SEC_TYPE", "ext2", sizeof("ext2")); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_ext2(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id, unsigned char *buf) |
| + | { |
| + | struct ext2_super_block *es; |
| + | // const char *sec_type = 0, *label = 0; |
| + | |
| + | es = (struct ext2_super_block *)buf; |
| + | |
| + | /* Distinguish between jbd and ext2/3 fs */ |
| + | if (blkid_le32(es->s_feature_incompat) & |
| + | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) |
| + | return -BLKID_ERR_PARAM; |
| + | |
| + | get_ext2_info(dev, buf); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_jbd(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf) |
| + | { |
| + | struct ext2_super_block *es = (struct ext2_super_block *) buf; |
| + | |
| + | if (!(blkid_le32(es->s_feature_incompat) & |
| + | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) |
| + | return -BLKID_ERR_PARAM; |
| + | |
| + | get_ext2_info(dev, buf); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_vfat(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf) |
| + | { |
| + | struct vfat_super_block *vs; |
| + | char serno[10]; |
| + | const char *label = 0; |
| + | int label_len = 0; |
| + | |
| + | vs = (struct vfat_super_block *)buf; |
| + | |
| + | if (strncmp(vs->vs_label, "NO NAME", 7)) { |
| + | char *end = vs->vs_label + sizeof(vs->vs_label) - 1; |
| + | |
| + | while (*end == ' ' && end >= vs->vs_label) |
| + | --end; |
| + | if (end >= vs->vs_label) { |
| + | label = vs->vs_label; |
| + | label_len = end - vs->vs_label + 1; |
| + | } |
| + | } |
| + | |
| + | /* We can't just print them as %04X, because they are unaligned */ |
| + | sprintf(serno, "%02X%02X-%02X%02X", vs->vs_serno[3], vs->vs_serno[2], |
| + | vs->vs_serno[1], vs->vs_serno[0]); |
| + | blkid_set_tag(dev, "LABEL", label, label_len); |
| + | blkid_set_tag(dev, "UUID", serno, sizeof(serno)); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_msdos(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf) |
| + | { |
| + | struct msdos_super_block *ms = (struct msdos_super_block *) buf; |
| + | char serno[10]; |
| + | const char *label = 0; |
| + | int label_len = 0; |
| + | |
| + | if (strncmp(ms->ms_label, "NO NAME", 7)) { |
| + | char *end = ms->ms_label + sizeof(ms->ms_label) - 1; |
| + | |
| + | while (*end == ' ' && end >= ms->ms_label) |
| + | --end; |
| + | if (end >= ms->ms_label) { |
| + | label = ms->ms_label; |
| + | label_len = end - ms->ms_label + 1; |
| + | } |
| + | } |
| + | |
| + | /* We can't just print them as %04X, because they are unaligned */ |
| + | sprintf(serno, "%02X%02X-%02X%02X", ms->ms_serno[3], ms->ms_serno[2], |
| + | ms->ms_serno[1], ms->ms_serno[0]); |
| + | blkid_set_tag(dev, "UUID", serno, 0); |
| + | blkid_set_tag(dev, "LABEL", label, label_len); |
| + | blkid_set_tag(dev, "SEC_TYPE", "msdos", sizeof("msdos")); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_xfs(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf) |
| + | { |
| + | struct xfs_super_block *xs; |
| + | const char *label = 0; |
| + | |
| + | xs = (struct xfs_super_block *)buf; |
| + | |
| + | if (strlen(xs->xs_fname)) |
| + | label = xs->xs_fname; |
| + | blkid_set_tag(dev, "LABEL", label, sizeof(xs->xs_fname)); |
| + | set_uuid(dev, xs->xs_uuid); |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_reiserfs(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id, unsigned char *buf) |
| + | { |
| + | struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf; |
| + | unsigned int blocksize; |
| + | const char *label = 0; |
| + | |
| + | blocksize = blkid_le16(rs->rs_blocksize); |
| + | |
| + | /* If the superblock is inside the journal, we have the wrong one */ |
| + | if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block)) |
| + | return -BLKID_ERR_BIG; |
| + | |
| + | /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ |
| + | if (!strcmp(id->bim_magic, "ReIsEr2Fs") || |
| + | !strcmp(id->bim_magic, "ReIsEr3Fs")) { |
| + | if (strlen(rs->rs_label)) |
| + | label = rs->rs_label; |
| + | set_uuid(dev, rs->rs_uuid); |
| + | } |
| + | blkid_set_tag(dev, "LABEL", label, sizeof(rs->rs_label)); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_jfs(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf) |
| + | { |
| + | struct jfs_super_block *js; |
| + | const char *label = 0; |
| + | |
| + | js = (struct jfs_super_block *)buf; |
| + | |
| + | if (strlen((char *) js->js_label)) |
| + | label = (char *) js->js_label; |
| + | blkid_set_tag(dev, "LABEL", label, sizeof(js->js_label)); |
| + | set_uuid(dev, js->js_uuid); |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_romfs(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf) |
| + | { |
| + | struct romfs_super_block *ros; |
| + | const char *label = 0; |
| + | |
| + | ros = (struct romfs_super_block *)buf; |
| + | |
| + | if (strlen((char *) ros->ros_volume)) |
| + | label = (char *) ros->ros_volume; |
| + | blkid_set_tag(dev, "LABEL", label, 0); |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_swap0(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf __BLKID_ATTR((unused))) |
| + | { |
| + | blkid_set_tag(dev, "UUID", 0, 0); |
| + | blkid_set_tag(dev, "LABEL", 0, 0); |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_swap1(int fd, |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf __BLKID_ATTR((unused))) |
| + | { |
| + | struct swap_id_block *sws; |
| + | // const char *label = 0; |
| + | |
| + | probe_swap0(fd, cache, dev, id, buf); |
| + | /* |
| + | * Version 1 swap headers are always located at offset of 1024 |
| + | * bytes, although the swap signature itself is located at the |
| + | * end of the page (which may vary depending on hardware |
| + | * pagesize). |
| + | */ |
| + | if (lseek(fd, 1024, SEEK_SET) < 0) return 1; |
| + | if (!(sws = (struct swap_id_block *)malloc(1024))) return 1; |
| + | if (read(fd, sws, 1024) != 1024) { |
| + | free(sws); |
| + | return 1; |
| + | } |
| + | |
| + | /* arbitrary sanity check.. is there any garbage down there? */ |
| + | if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0) { |
| + | if (sws->sws_volume[0]) |
| + | blkid_set_tag(dev, "LABEL", sws->sws_volume, |
| + | sizeof(sws->sws_volume)); |
| + | if (sws->sws_uuid[0]) |
| + | set_uuid(dev, sws->sws_uuid); |
| + | } |
| + | free(sws); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | static const char |
| + | *udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02", |
| + | "NSR03", "TEA01", 0 }; |
| + | |
| + | static int probe_udf(int fd, blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev __BLKID_ATTR((unused)), |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf __BLKID_ATTR((unused))) |
| + | { |
| + | int j, bs; |
| + | struct iso_volume_descriptor isosb; |
| + | const char ** m; |
| + | |
| + | /* determine the block size by scanning in 2K increments |
| + | (block sizes larger than 2K will be null padded) */ |
| + | for (bs = 1; bs < 16; bs++) { |
| + | lseek(fd, bs*2048+32768, SEEK_SET); |
| + | if (read(fd, (char *)&isosb, sizeof(isosb)) != sizeof(isosb)) |
| + | return 1; |
| + | if (isosb.id[0]) |
| + | break; |
| + | } |
| + | |
| + | /* Scan up to another 64 blocks looking for additional VSD's */ |
| + | for (j = 1; j < 64; j++) { |
| + | if (j > 1) { |
| + | lseek(fd, j*bs*2048+32768, SEEK_SET); |
| + | if (read(fd, (char *)&isosb, sizeof(isosb)) |
| + | != sizeof(isosb)) |
| + | return 1; |
| + | } |
| + | /* If we find NSR0x then call it udf: |
| + | NSR01 for UDF 1.00 |
| + | NSR02 for UDF 1.50 |
| + | NSR03 for UDF 2.00 */ |
| + | if (!strncmp(isosb.id, "NSR0", 4)) |
| + | return 0; |
| + | for (m = udf_magic; *m; m++) |
| + | if (!strncmp(*m, isosb.id, 5)) |
| + | break; |
| + | if (*m == 0) |
| + | return 1; |
| + | } |
| + | return 1; |
| + | } |
| + | |
| + | static int probe_ocfs(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf) |
| + | { |
| + | struct ocfs_volume_header ovh; |
| + | struct ocfs_volume_label ovl; |
| + | __u32 major; |
| + | |
| + | memcpy(&ovh, buf, sizeof(ovh)); |
| + | memcpy(&ovl, buf+512, sizeof(ovl)); |
| + | |
| + | major = ocfsmajor(ovh); |
| + | if (major == 1) |
| + | blkid_set_tag(dev,"SEC_TYPE","ocfs1",sizeof("ocfs1")); |
| + | else if (major >= 9) |
| + | blkid_set_tag(dev,"SEC_TYPE","ntocfs",sizeof("ntocfs")); |
| + | |
| + | blkid_set_tag(dev, "LABEL", ovl.label, ocfslabellen(ovl)); |
| + | blkid_set_tag(dev, "MOUNT", ovh.mount, ocfsmountlen(ovh)); |
| + | set_uuid(dev, ovl.vol_id); |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_ocfs2(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf) |
| + | { |
| + | struct ocfs2_super_block *osb; |
| + | |
| + | osb = (struct ocfs2_super_block *)buf; |
| + | |
| + | blkid_set_tag(dev, "LABEL", osb->s_label, sizeof(osb->s_label)); |
| + | set_uuid(dev, osb->s_uuid); |
| + | return 0; |
| + | } |
| + | |
| + | static int probe_oracleasm(int fd __BLKID_ATTR((unused)), |
| + | blkid_cache cache __BLKID_ATTR((unused)), |
| + | blkid_dev dev, |
| + | struct blkid_magic *id __BLKID_ATTR((unused)), |
| + | unsigned char *buf) |
| + | { |
| + | struct oracle_asm_disk_label *dl; |
| + | |
| + | dl = (struct oracle_asm_disk_label *)buf; |
| + | |
| + | blkid_set_tag(dev, "LABEL", dl->dl_id, sizeof(dl->dl_id)); |
| + | return 0; |
| + | } |
| + | |
| + | /* |
| + | * BLKID_BLK_OFFS is at least as large as the highest bim_kboff defined |
| + | * in the type_array table below + bim_kbalign. |
| + | * |
| + | * When probing for a lot of magics, we handle everything in 1kB buffers so |
| + | * that we don't have to worry about reading each combination of block sizes. |
| + | */ |
| + | #define BLKID_BLK_OFFS 64 /* currently reiserfs */ |
| + | |
| + | /* |
| + | * Various filesystem magics that we can check for. Note that kboff and |
| + | * sboff are in kilobytes and bytes respectively. All magics are in |
| + | * byte strings so we don't worry about endian issues. |
| + | */ |
| + | static struct blkid_magic type_array[] = { |
| + | /* type kboff sboff len magic probe */ |
| + | { "oracleasm", 0, 32, 8, "ORCLDISK", probe_oracleasm }, |
| + | { "ntfs", 0, 3, 8, "NTFS ", 0 }, |
| + | { "jbd", 1, 0x38, 2, "\123\357", probe_jbd }, |
| + | { "ext3", 1, 0x38, 2, "\123\357", probe_ext3 }, |
| + | { "ext2", 1, 0x38, 2, "\123\357", probe_ext2 }, |
| + | { "reiserfs", 8, 0x34, 8, "ReIsErFs", probe_reiserfs }, |
| + | { "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", probe_reiserfs }, |
| + | { "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", probe_reiserfs }, |
| + | { "reiserfs", 64, 0x34, 8, "ReIsErFs", probe_reiserfs }, |
| + | { "reiserfs", 8, 20, 8, "ReIsErFs", probe_reiserfs }, |
| + | { "vfat", 0, 0x52, 5, "MSWIN", probe_vfat }, |
| + | { "vfat", 0, 0x52, 8, "FAT32 ", probe_vfat }, |
| + | { "vfat", 0, 0x36, 5, "MSDOS", probe_msdos }, |
| + | { "vfat", 0, 0x36, 8, "FAT16 ", probe_msdos }, |
| + | { "vfat", 0, 0x36, 8, "FAT12 ", probe_msdos }, |
| + | { "minix", 1, 0x10, 2, "\177\023", 0 }, |
| + | { "minix", 1, 0x10, 2, "\217\023", 0 }, |
| + | { "minix", 1, 0x10, 2, "\150\044", 0 }, |
| + | { "minix", 1, 0x10, 2, "\170\044", 0 }, |
| + | { "vxfs", 1, 0, 4, "\365\374\001\245", 0 }, |
| + | { "xfs", 0, 0, 4, "XFSB", probe_xfs }, |
| + | { "romfs", 0, 0, 8, "-rom1fs-", probe_romfs }, |
| + | { "bfs", 0, 0, 4, "\316\372\173\033", 0 }, |
| + | { "cramfs", 0, 0, 4, "E=\315\034", 0 }, |
| + | { "qnx4", 0, 4, 6, "QNX4FS", 0 }, |
| + | { "udf", 32, 1, 5, "BEA01", probe_udf }, |
| + | { "udf", 32, 1, 5, "BOOT2", probe_udf }, |
| + | { "udf", 32, 1, 5, "CD001", probe_udf }, |
| + | { "udf", 32, 1, 5, "CDW02", probe_udf }, |
| + | { "udf", 32, 1, 5, "NSR02", probe_udf }, |
| + | { "udf", 32, 1, 5, "NSR03", probe_udf }, |
| + | { "udf", 32, 1, 5, "TEA01", probe_udf }, |
| + | { "iso9660", 32, 1, 5, "CD001", 0 }, |
| + | { "iso9660", 32, 9, 5, "CDROM", 0 }, |
| + | { "jfs", 32, 0, 4, "JFS1", probe_jfs }, |
| + | { "hfs", 1, 0, 2, "BD", 0 }, |
| + | { "ufs", 8, 0x55c, 4, "T\031\001\000", 0 }, |
| + | { "hpfs", 8, 0, 4, "I\350\225\371", 0 }, |
| + | { "sysv", 0, 0x3f8, 4, "\020~\030\375", 0 }, |
| + | { "swap", 0, 0xff6, 10, "SWAP-SPACE", probe_swap0 }, |
| + | { "swap", 0, 0xff6, 10, "SWAPSPACE2", probe_swap1 }, |
| + | { "swap", 0, 0x1ff6, 10, "SWAP-SPACE", probe_swap0 }, |
| + | { "swap", 0, 0x1ff6, 10, "SWAPSPACE2", probe_swap1 }, |
| + | { "swap", 0, 0x3ff6, 10, "SWAP-SPACE", probe_swap0 }, |
| + | { "swap", 0, 0x3ff6, 10, "SWAPSPACE2", probe_swap1 }, |
| + | { "swap", 0, 0x7ff6, 10, "SWAP-SPACE", probe_swap0 }, |
| + | { "swap", 0, 0x7ff6, 10, "SWAPSPACE2", probe_swap1 }, |
| + | { "swap", 0, 0xfff6, 10, "SWAP-SPACE", probe_swap0 }, |
| + | { "swap", 0, 0xfff6, 10, "SWAPSPACE2", probe_swap1 }, |
| + | { "ocfs", 0, 8, 9, "OracleCFS", probe_ocfs }, |
| + | { "ocfs2", 1, 0, 6, "OCFSV2", probe_ocfs2 }, |
| + | { "ocfs2", 2, 0, 6, "OCFSV2", probe_ocfs2 }, |
| + | { "ocfs2", 4, 0, 6, "OCFSV2", probe_ocfs2 }, |
| + | { "ocfs2", 8, 0, 6, "OCFSV2", probe_ocfs2 }, |
| + | { NULL, 0, 0, 0, NULL, NULL } |
| + | }; |
| + | |
| + | /* |
| + | * Verify that the data in dev is consistent with what is on the actual |
| + | * block device (using the devname field only). Normally this will be |
| + | * called when finding items in the cache, but for long running processes |
| + | * is also desirable to revalidate an item before use. |
| + | * |
| + | * If we are unable to revalidate the data, we return the old data and |
| + | * do not set the BLKID_BID_FL_VERIFIED flag on it. |
| + | */ |
| + | blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) |
| + | { |
| + | struct blkid_magic *id; |
| + | unsigned char *bufs[BLKID_BLK_OFFS + 1], *buf; |
| + | const char *type; |
| + | struct stat st; |
| + | time_t diff, now; |
| + | int fd, idx; |
| + | |
| + | if (!dev) |
| + | return NULL; |
| + | |
| + | now = time(0); |
| + | diff = now - dev->bid_time; |
| + | |
| + | if ((now < 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 (time since last check %lu)\n", |
| + | dev->bid_name, diff)); |
| + | |
| + | if (((fd = open(dev->bid_name, O_RDONLY)) < 0) || |
| + | (fstat(fd, &st) < 0)) { |
| + | if (errno == ENXIO || errno == ENODEV || errno == ENOENT) { |
| + | blkid_free_dev(dev); |
| + | return NULL; |
| + | } |
| + | /* 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; |
| + | } |
| + | |
| + | memset(bufs, 0, sizeof(bufs)); |
| + | |
| + | /* |
| + | * Iterate over the type array. If we already know the type, |
| + | * then try that first. If it doesn't work, then blow away |
| + | * the type information, and try again. |
| + | * |
| + | */ |
| + | try_again: |
| + | type = 0; |
| + | if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) { |
| + | uuid_t uuid; |
| + | |
| + | if (check_mdraid(fd, uuid) == 0) { |
| + | set_uuid(dev, uuid); |
| + | type = "mdraid"; |
| + | goto found_type; |
| + | } |
| + | } |
| + | for (id = type_array; id->bim_type; id++) { |
| + | if (dev->bid_type && |
| + | strcmp(id->bim_type, dev->bid_type)) |
| + | continue; |
| + | |
| + | idx = id->bim_kboff + (id->bim_sboff >> 10); |
| + | if (idx > BLKID_BLK_OFFS || idx < 0) |
| + | continue; |
| + | buf = bufs[idx]; |
| + | if (!buf) { |
| + | if (lseek(fd, idx << 10, SEEK_SET) < 0) |
| + | continue; |
| + | |
| + | if (!(buf = (unsigned char *)malloc(1024))) |
| + | continue; |
| + | |
| + | if (read(fd, buf, 1024) != 1024) { |
| + | free(buf); |
| + | continue; |
| + | } |
| + | bufs[idx] = buf; |
| + | } |
| + | |
| + | if (memcmp(id->bim_magic, buf + (id->bim_sboff&0x3ff), |
| + | id->bim_len)) |
| + | continue; |
| + | |
| + | if ((id->bim_probe == NULL) || |
| + | (id->bim_probe(fd, cache, dev, id, buf) == 0)) { |
| + | type = id->bim_type; |
| + | goto found_type; |
| + | } |
| + | } |
| + | |
| + | if (!id->bim_type && dev->bid_type) { |
| + | /* |
| + | * Zap the device filesystem type and try again |
| + | */ |
| + | blkid_set_tag(dev, "TYPE", 0, 0); |
| + | blkid_set_tag(dev, "SEC_TYPE", 0, 0); |
| + | blkid_set_tag(dev, "LABEL", 0, 0); |
| + | blkid_set_tag(dev, "UUID", 0, 0); |
| + | goto try_again; |
| + | } |
| + | |
| + | if (!dev->bid_type) { |
| + | blkid_free_dev(dev); |
| + | return NULL; |
| + | } |
| + | |
| + | found_type: |
| + | if (dev && type) { |
| + | dev->bid_devno = st.st_rdev; |
| + | dev->bid_time = time(0); |
| + | dev->bid_flags |= BLKID_BID_FL_VERIFIED; |
| + | cache->bic_flags |= BLKID_BIC_FL_CHANGED; |
| + | |
| + | blkid_set_tag(dev, "TYPE", type, 0); |
| + | |
| + | DBG(DEBUG_PROBE, printf("%s: devno 0x%04Lx, type %s\n", |
| + | dev->bid_name, st.st_rdev, type)); |
| + | } |
| + | |
| + | close(fd); |
| + | |
| + | return dev; |
| + | } |
| + | |
| + | int blkid_known_fstype(const char *fstype) |
| + | { |
| + | struct blkid_magic *id; |
| + | |
| + | for (id = type_array; id->bim_type; id++) { |
| + | if (strcmp(fstype, id->bim_type) == 0) |
| + | return 1; |
| + | } |
| + | return 0; |
| + | } |
| + | |
| + | #ifdef TEST_PROGRAM |
| + | int main(int argc, char **argv) |
| + | { |
| + | blkid_dev dev; |
| + | blkid_cache cache; |
| + | int ret; |
| + | |
| + | blkid_debug_mask = DEBUG_ALL; |
| + | 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("%s is type %s\n", argv[1], dev->bid_type ? |
| + | dev->bid_type : "(null)"); |
| + | if (dev->bid_label) |
| + | printf("\tlabel is '%s'\n", dev->bid_label); |
| + | if (dev->bid_uuid) |
| + | printf("\tuuid is %s\n", dev->bid_uuid); |
| + | |
| + | blkid_free_dev(dev); |
| + | return (0); |
| + | } |
| + | #endif |
| @@ -0,0 +1,359 @@ | |
| + | /* |
| + | * probe.h - constants and on-disk structures for extracting device data |
| + | * |
| + | * Copyright (C) 1999 by Andries Brouwer |
| + | * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o |
| + | * Copyright (C) 2001 by Andreas Dilger |
| + | * |
| + | * %Begin-Header% |
| + | * This file may be redistributed under the terms of the |
| + | * GNU Lesser General Public License. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #ifndef _BLKID_PROBE_H |
| + | #define _BLKID_PROBE_H |
| + | |
| + | #include <linux/types.h> |
| + | |
| + | struct blkid_magic; |
| + | |
| + | typedef int (*blkid_probe_t)(int fd, blkid_cache cache, blkid_dev dev, |
| + | struct blkid_magic *id, unsigned char *buf); |
| + | |
| + | struct blkid_magic { |
| + | const char *bim_type; /* type name for this magic */ |
| + | long bim_kboff; /* kilobyte offset of superblock */ |
| + | unsigned bim_sboff; /* byte offset within superblock */ |
| + | unsigned bim_len; /* length of magic */ |
| + | const char *bim_magic; /* magic string */ |
| + | blkid_probe_t bim_probe; /* probe function */ |
| + | }; |
| + | |
| + | /* |
| + | * Structures for each of the content types we want to extract information |
| + | * from. We do not necessarily need the magic field here, because we have |
| + | * already identified the content type before we get this far. It may still |
| + | * be useful if there are probe functions which handle multiple content types. |
| + | */ |
| + | struct ext2_super_block { |
| + | __u32 s_inodes_count; |
| + | __u32 s_blocks_count; |
| + | __u32 s_r_blocks_count; |
| + | __u32 s_free_blocks_count; |
| + | __u32 s_free_inodes_count; |
| + | __u32 s_first_data_block; |
| + | __u32 s_log_block_size; |
| + | __u32 s_dummy3[7]; |
| + | unsigned char s_magic[2]; |
| + | __u16 s_state; |
| + | __u32 s_dummy5[8]; |
| + | __u32 s_feature_compat; |
| + | __u32 s_feature_incompat; |
| + | __u32 s_feature_ro_compat; |
| + | unsigned char s_uuid[16]; |
| + | char s_volume_name[16]; |
| + | }; |
| + | #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004 |
| + | #define EXT3_FEATURE_INCOMPAT_RECOVER 0x00000004 |
| + | #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008 |
| + | |
| + | struct xfs_super_block { |
| + | unsigned char xs_magic[4]; |
| + | __u32 xs_blocksize; |
| + | __u64 xs_dblocks; |
| + | __u64 xs_rblocks; |
| + | __u32 xs_dummy1[2]; |
| + | unsigned char xs_uuid[16]; |
| + | __u32 xs_dummy2[15]; |
| + | char xs_fname[12]; |
| + | __u32 xs_dummy3[2]; |
| + | __u64 xs_icount; |
| + | __u64 xs_ifree; |
| + | __u64 xs_fdblocks; |
| + | }; |
| + | |
| + | struct reiserfs_super_block { |
| + | __u32 rs_blocks_count; |
| + | __u32 rs_free_blocks; |
| + | __u32 rs_root_block; |
| + | __u32 rs_journal_block; |
| + | __u32 rs_journal_dev; |
| + | __u32 rs_orig_journal_size; |
| + | __u32 rs_dummy2[5]; |
| + | __u16 rs_blocksize; |
| + | __u16 rs_dummy3[3]; |
| + | unsigned char rs_magic[12]; |
| + | __u32 rs_dummy4[5]; |
| + | unsigned char rs_uuid[16]; |
| + | char rs_label[16]; |
| + | }; |
| + | |
| + | struct jfs_super_block { |
| + | unsigned char js_magic[4]; |
| + | __u32 js_version; |
| + | __u64 js_size; |
| + | __u32 js_bsize; |
| + | __u32 js_dummy1; |
| + | __u32 js_pbsize; |
| + | __u32 js_dummy2[27]; |
| + | unsigned char js_uuid[16]; |
| + | unsigned char js_label[16]; |
| + | unsigned char js_loguuid[16]; |
| + | }; |
| + | |
| + | struct romfs_super_block { |
| + | unsigned char ros_magic[8]; |
| + | __u32 ros_dummy1[2]; |
| + | unsigned char ros_volume[16]; |
| + | }; |
| + | |
| + | struct swap_id_block { |
| + | /* unsigned char sws_boot[1024]; */ |
| + | __u32 sws_version; |
| + | __u32 sws_lastpage; |
| + | __u32 sws_nrbad; |
| + | unsigned char sws_uuid[16]; |
| + | unsigned char sws_volume[16]; |
| + | unsigned char sws_pad[117]; |
| + | __u32 sws_badpg; |
| + | }; |
| + | |
| + | /* Yucky misaligned values */ |
| + | struct vfat_super_block { |
| + | /* 00*/ unsigned char vs_ignored[3]; |
| + | /* 03*/ unsigned char vs_sysid[8]; |
| + | /* 0b*/ unsigned char vs_sector_size[2]; |
| + | /* 0d*/ __u8 vs_cluster_size; |
| + | /* 0e*/ __u16 vs_reserved; |
| + | /* 10*/ __u8 vs_fats; |
| + | /* 11*/ unsigned char vs_dir_entries[2]; |
| + | /* 13*/ unsigned char vs_sectors[2]; |
| + | /* 15*/ unsigned char vs_media; |
| + | /* 16*/ __u16 vs_fat_length; |
| + | /* 18*/ __u16 vs_secs_track; |
| + | /* 1a*/ __u16 vs_heads; |
| + | /* 1c*/ __u32 vs_hidden; |
| + | /* 20*/ __u32 vs_total_sect; |
| + | /* 24*/ __u32 vs_fat32_length; |
| + | /* 28*/ __u16 vs_flags; |
| + | /* 2a*/ __u8 vs_version[2]; |
| + | /* 2c*/ __u32 vs_root_cluster; |
| + | /* 30*/ __u16 vs_insfo_sector; |
| + | /* 32*/ __u16 vs_backup_boot; |
| + | /* 34*/ __u16 vs_reserved2[6]; |
| + | /* 40*/ unsigned char vs_unknown[3]; |
| + | /* 43*/ unsigned char vs_serno[4]; |
| + | /* 47*/ char vs_label[11]; |
| + | /* 52*/ unsigned char vs_magic[8]; |
| + | /* 5a*/ unsigned char vs_dummy2[164]; |
| + | /*1fe*/ unsigned char vs_pmagic[2]; |
| + | }; |
| + | |
| + | /* Yucky misaligned values */ |
| + | struct msdos_super_block { |
| + | /* 00*/ unsigned char ms_ignored[3]; |
| + | /* 03*/ unsigned char ms_sysid[8]; |
| + | /* 0b*/ unsigned char ms_sector_size[2]; |
| + | /* 0d*/ __u8 ms_cluster_size; |
| + | /* 0e*/ __u16 ms_reserved; |
| + | /* 10*/ __u8 ms_fats; |
| + | /* 11*/ unsigned char ms_dir_entries[2]; |
| + | /* 13*/ unsigned char ms_sectors[2]; |
| + | /* 15*/ unsigned char ms_media; |
| + | /* 16*/ __u16 ms_fat_length; |
| + | /* 18*/ __u16 ms_secs_track; |
| + | /* 1a*/ __u16 ms_heads; |
| + | /* 1c*/ __u32 ms_hidden; |
| + | /* 20*/ __u32 ms_total_sect; |
| + | /* 24*/ unsigned char ms_unknown[3]; |
| + | /* 27*/ unsigned char ms_serno[4]; |
| + | /* 2b*/ char ms_label[11]; |
| + | /* 36*/ unsigned char ms_magic[8]; |
| + | /* 3d*/ unsigned char ms_dummy2[192]; |
| + | /*1fe*/ unsigned char ms_pmagic[2]; |
| + | }; |
| + | |
| + | struct minix_super_block { |
| + | __u16 ms_ninodes; |
| + | __u16 ms_nzones; |
| + | __u16 ms_imap_blocks; |
| + | __u16 ms_zmap_blocks; |
| + | __u16 ms_firstdatazone; |
| + | __u16 ms_log_zone_size; |
| + | __u32 ms_max_size; |
| + | unsigned char ms_magic[2]; |
| + | __u16 ms_state; |
| + | __u32 ms_zones; |
| + | }; |
| + | |
| + | struct mdp_superblock_s { |
| + | __u32 md_magic; |
| + | __u32 major_version; |
| + | __u32 minor_version; |
| + | __u32 patch_version; |
| + | __u32 gvalid_words; |
| + | __u32 set_uuid0; |
| + | __u32 ctime; |
| + | __u32 level; |
| + | __u32 size; |
| + | __u32 nr_disks; |
| + | __u32 raid_disks; |
| + | __u32 md_minor; |
| + | __u32 not_persistent; |
| + | __u32 set_uuid1; |
| + | __u32 set_uuid2; |
| + | __u32 set_uuid3; |
| + | }; |
| + | |
| + | struct hfs_super_block { |
| + | char h_magic[2]; |
| + | char h_dummy[18]; |
| + | __u32 h_blksize; |
| + | }; |
| + | |
| + | struct ocfs_volume_header { |
| + | unsigned char minor_version[4]; |
| + | unsigned char major_version[4]; |
| + | unsigned char signature[128]; |
| + | unsigned char mount[128]; |
| + | unsigned char mount_len[2]; |
| + | }; |
| + | |
| + | struct ocfs_volume_label { |
| + | unsigned char disk_lock[48]; |
| + | unsigned char label[64]; |
| + | unsigned char label_len[2]; |
| + | unsigned char vol_id[16]; |
| + | unsigned char vol_id_len[2]; |
| + | }; |
| + | |
| + | #define ocfsmajor(o) ((__u32)o.major_version[0] \ |
| + | + (((__u32) o.major_version[1]) << 8) \ |
| + | + (((__u32) o.major_version[2]) << 16) \ |
| + | + (((__u32) o.major_version[3]) << 24)) |
| + | #define ocfslabellen(o) ((__u32)o.label_len[0] + (((__u32) o.label_len[1]) << 8)) |
| + | #define ocfsmountlen(o) ((__u32)o.mount_len[0] + (((__u32) o.mount_len[1])<<8)) |
| + | |
| + | #define OCFS_MAGIC "OracleCFS" |
| + | |
| + | struct ocfs2_super_block { |
| + | unsigned char signature[8]; |
| + | unsigned char s_dummy1[184]; |
| + | unsigned char s_dummy2[80]; |
| + | unsigned char s_label[64]; |
| + | unsigned char s_uuid[16]; |
| + | }; |
| + | |
| + | #define OCFS2_MIN_BLOCKSIZE 512 |
| + | #define OCFS2_MAX_BLOCKSIZE 4096 |
| + | |
| + | #define OCFS2_SUPER_BLOCK_BLKNO 2 |
| + | |
| + | #define OCFS2_SUPER_BLOCK_SIGNATURE "OCFSV2" |
| + | |
| + | struct oracle_asm_disk_label { |
| + | char dummy[32]; |
| + | char dl_tag[8]; |
| + | char dl_id[24]; |
| + | }; |
| + | |
| + | #define ORACLE_ASM_DISK_LABEL_MARKED "ORCLDISK" |
| + | #define ORACLE_ASM_DISK_LABEL_OFFSET 32 |
| + | |
| + | #define ISODCL(from, to) (to - from + 1) |
| + | struct iso_volume_descriptor { |
| + | char type[ISODCL(1,1)]; /* 711 */ |
| + | char id[ISODCL(2,6)]; |
| + | char version[ISODCL(7,7)]; |
| + | char data[ISODCL(8,2048)]; |
| + | }; |
| + | |
| + | /* |
| + | * Byte swap functions |
| + | */ |
| + | #ifdef __GNUC__ |
| + | #define _INLINE_ static __inline__ |
| + | #else /* For Watcom C */ |
| + | #define _INLINE_ static inline |
| + | #endif |
| + | |
| + | static __u16 blkid_swab16(__u16 val); |
| + | static __u32 blkid_swab32(__u32 val); |
| + | static __u64 blkid_swab64(__u64 val); |
| + | |
| + | #if ((defined __GNUC__) && \ |
| + | (defined(__i386__) || defined(__i486__) || defined(__i586__))) |
| + | |
| + | #define _BLKID_HAVE_ASM_BITOPS_ |
| + | |
| + | _INLINE_ __u32 blkid_swab32(__u32 val) |
| + | { |
| + | #ifdef EXT2FS_REQUIRE_486 |
| + | __asm__("bswap %0" : "=r" (val) : "0" (val)); |
| + | #else |
| + | __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ |
| + | "rorl $16,%0\n\t" /* swap words */ |
| + | "xchgb %b0,%h0" /* swap higher bytes */ |
| + | :"=q" (val) |
| + | : "0" (val)); |
| + | #endif |
| + | return val; |
| + | } |
| + | |
| + | _INLINE_ __u16 blkid_swab16(__u16 val) |
| + | { |
| + | __asm__("xchgb %b0,%h0" /* swap bytes */ \ |
| + | : "=q" (val) \ |
| + | : "0" (val)); \ |
| + | return val; |
| + | } |
| + | |
| + | _INLINE_ __u64 blkid_swab64(__u64 val) |
| + | { |
| + | return (blkid_swab32(val >> 32) | |
| + | (((__u64) blkid_swab32(val & 0xFFFFFFFFUL)) << 32)); |
| + | } |
| + | #endif |
| + | |
| + | #if !defined(_BLKID_HAVE_ASM_BITOPS_) |
| + | |
| + | _INLINE_ __u16 blkid_swab16(__u16 val) |
| + | { |
| + | return (val >> 8) | (val << 8); |
| + | } |
| + | |
| + | _INLINE_ __u32 blkid_swab32(__u32 val) |
| + | { |
| + | return ((val>>24) | ((val>>8)&0xFF00) | |
| + | ((val<<8)&0xFF0000) | (val<<24)); |
| + | } |
| + | |
| + | _INLINE_ __u64 blkid_swab64(__u64 val) |
| + | { |
| + | return (blkid_swab32(val >> 32) | |
| + | (((__u64) blkid_swab32(val & 0xFFFFFFFFUL)) << 32)); |
| + | } |
| + | #endif |
| + | |
| + | |
| + | |
| + | #if __BYTE_ORDER == __BIG_ENDIAN |
| + | #define blkid_le16(x) blkid_swab16(x) |
| + | #define blkid_le32(x) blkid_swab32(x) |
| + | #define blkid_le64(x) blkid_swab64(x) |
| + | #define blkid_be16(x) (x) |
| + | #define blkid_be32(x) (x) |
| + | #define blkid_be64(x) (x) |
| + | #else |
| + | #define blkid_le16(x) (x) |
| + | #define blkid_le32(x) (x) |
| + | #define blkid_le64(x) (x) |
| + | #define blkid_be16(x) blkid_swab16(x) |
| + | #define blkid_be32(x) blkid_swab32(x) |
| + | #define blkid_be64(x) blkid_swab64(x) |
| + | #endif |
| + | |
| + | #undef _INLINE_ |
| + | |
| + | #endif /* _BLKID_PROBE_H */ |
| @@ -0,0 +1,459 @@ | |
| + | /* |
| + | * read.c - read the blkid cache from disk, to avoid scanning all devices |
| + | * |
| + | * Copyright (C) 2001, 2003 Theodore Y. Ts'o |
| + | * Copyright (C) 2001 Andreas Dilger |
| + | * |
| + | * %Begin-Header% |
| + | * This file may be redistributed under the terms of the |
| + | * GNU Lesser General Public License. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include <stdio.h> |
| + | #include <ctype.h> |
| + | #include <string.h> |
| + | #include <time.h> |
| + | #include <sys/types.h> |
| + | #include <sys/stat.h> |
| + | #include <fcntl.h> |
| + | #include <unistd.h> |
| + | #if HAVE_ERRNO_H |
| + | #include <errno.h> |
| + | #endif |
| + | |
| + | #include "blkidP.h" |
| + | #include "uuid/uuid.h" |
| + | |
| + | #ifdef HAVE_STRTOULL |
| + | #define __USE_ISOC9X |
| + | #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 |
| + | |
| + | /* |
| + | * 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", 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))) |
| + | 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")) |
| + | /* FIXME: need to parse a long long eventually */ |
| + | dev->bid_time = strtol(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); |
| + | } |
| + | |
| + | DEB_DUMP_DEV(DEBUG_READ, 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 |
| + | int main(int argc, char**argv) |
| + | { |
| + | blkid_cache cache = NULL; |
| + | int ret; |
| + | |
| + | blkid_debug_mask = DEBUG_ALL; |
| + | if (argc > 2) { |
| + | fprintf(stderr, "Usage: %s [filename]\n" |
| + | "Test parsing of the cache (filename)\n", argv[0]); |
| + | exit(1); |
| + | } |
| + | if ((ret = blkid_get_cache(&cache, argv[1])) < 0) |
| + | fprintf(stderr, "error %d reading cache file %s\n", ret, |
| + | argv[1] ? argv[1] : BLKID_CACHE_FILE); |
| + | |
| + | blkid_put_cache(cache); |
| + | |
| + | return ret; |
| + | } |
| + | #endif |
| @@ -0,0 +1,140 @@ | |
| + | /* |
| + | * 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" |
| + | #include "probe.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, '=')) |
| + | return blkid_strdup(token); |
| + | blkid_parse_tag_string(token, &t, &v); |
| + | if (!t || !v) |
| + | goto errout; |
| + | token = t; |
| + | value = v; |
| + | } |
| + | |
| + | dev = blkid_find_dev_with_tag(c, token, value); |
| + | if (!dev) |
| + | goto errout; |
| + | |
| + | ret = blkid_strdup(blkid_dev_devname(dev)); |
| + | |
| + | errout: |
| + | if (t) |
| + | free(t); |
| + | if (v) |
| + | free(v); |
| + | if (!cache) { |
| + | blkid_put_cache(c); |
| + | } |
| + | return (ret); |
| + | } |
| + | |
| + | #ifdef TEST_PROGRAM |
| + | int main(int argc, char **argv) |
| + | { |
| + | char *value; |
| + | blkid_cache cache; |
| + | |
| + | blkid_debug_mask = DEBUG_ALL; |
| + | if (argc != 2 && argc != 3) { |
| + | fprintf(stderr, "Usage:\t%s tagname=value\n" |
| + | "\t%s tagname devname\n" |
| + | "Find which device holds a given token or\n" |
| + | "Find what the value of a tag is in a device\n", |
| + | argv[0], argv[0]); |
| + | exit(1); |
| + | } |
| + | if (blkid_get_cache(&cache, "/dev/null") < 0) { |
| + | fprintf(stderr, "Couldn't get blkid cache\n"); |
| + | exit(1); |
| + | } |
| + | |
| + | if (argv[2]) { |
| + | value = blkid_get_tag_value(cache, argv[1], argv[2]); |
| + | printf("%s has tag %s=%s\n", argv[2], argv[1], |
| + | value ? value : "<missing>"); |
| + | } else { |
| + | value = blkid_get_devname(cache, argv[1], NULL); |
| + | printf("%s has tag %s\n", value ? value : "<none>", argv[1]); |
| + | } |
| + | blkid_put_cache(cache); |
| + | return value ? 0 : 1; |
| + | } |
| + | #endif |
| @@ -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)); |
| + | |
| + | fprintf(file, |
| + | "<device DEVNO=\"0x%04lx\" TIME=\"%lu\"", |
| + | (unsigned long) dev->bid_devno, dev->bid_time); |
| + | if (dev->bid_pri) |
| + | fprintf(file, " PRI=\"%d\"", dev->bid_pri); |
| + | list_for_each(p, &dev->bid_tags) { |
| + | blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); |
| + | fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val); |
| + | } |
| + | fprintf(file, ">%s</device>\n", dev->bid_name); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | /* |
| + | * Write out the cache struct to the cache file on disk. |
| + | */ |
| + | int blkid_flush_cache(blkid_cache cache) |
| + | { |
| + | struct list_head *p; |
| + | char *tmp = NULL; |
| + | const char *opened = NULL; |
| + | const char *filename; |
| + | FILE *file = NULL; |
| + | int fd, ret = 0; |
| + | struct stat st; |
| + | |
| + | if (!cache) |
| + | return -BLKID_ERR_PARAM; |
| + | |
| + | if (list_empty(&cache->bic_devs) || |
| + | !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) { |
| + | DBG(DEBUG_SAVE, printf("skipping cache file write\n")); |
| + | return 0; |
| + | } |
| + | |
| + | filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE; |
| + | |
| + | /* If we can't write to the cache file, then don't even try */ |
| + | if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) || |
| + | (ret == 0 && access(filename, W_OK) < 0)) { |
| + | DBG(DEBUG_SAVE, |
| + | printf("can't write to cache file %s\n", filename)); |
| + | return 0; |
| + | } |
| + | |
| + | /* |
| + | * Try and create a temporary file in the same directory so |
| + | * that in case of error we don't overwrite the cache file. |
| + | * If the cache file doesn't yet exist, it isn't a regular |
| + | * file (e.g. /dev/null or a socket), or we couldn't create |
| + | * a temporary file then we open it directly. |
| + | */ |
| + | if (ret == 0 && S_ISREG(st.st_mode)) { |
| + | tmp = malloc(strlen(filename) + 8); |
| + | if (tmp) { |
| + | sprintf(tmp, "%s-XXXXXX", filename); |
| + | fd = mkstemp(tmp); |
| + | if (fd >= 0) { |
| + | file = fdopen(fd, "w"); |
| + | opened = tmp; |
| + | } |
| + | fchmod(fd, 0644); |
| + | } |
| + | } |
| + | |
| + | if (!file) { |
| + | file = fopen(filename, "w"); |
| + | opened = filename; |
| + | } |
| + | |
| + | DBG(DEBUG_SAVE, |
| + | printf("writing cache file %s (really %s)\n", |
| + | filename, opened)); |
| + | |
| + | if (!file) { |
| + | ret = errno; |
| + | goto errout; |
| + | } |
| + | |
| + | list_for_each(p, &cache->bic_devs) { |
| + | blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); |
| + | if (!dev->bid_type) |
| + | continue; |
| + | if ((ret = save_dev(dev, file)) < 0) |
| + | break; |
| + | } |
| + | |
| + | if (ret >= 0) { |
| + | cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; |
| + | ret = 1; |
| + | } |
| + | |
| + | fclose(file); |
| + | if (opened != filename) { |
| + | if (ret < 0) { |
| + | unlink(opened); |
| + | DBG(DEBUG_SAVE, |
| + | printf("unlinked temp cache %s\n", opened)); |
| + | } else { |
| + | char *backup; |
| + | |
| + | backup = malloc(strlen(filename) + 5); |
| + | if (backup) { |
| + | sprintf(backup, "%s.old", filename); |
| + | unlink(backup); |
| + | link(filename, backup); |
| + | free(backup); |
| + | } |
| + | rename(opened, filename); |
| + | DBG(DEBUG_SAVE, |
| + | printf("moved temp cache %s\n", opened)); |
| + | } |
| + | } |
| + | |
| + | errout: |
| + | if (tmp) |
| + | free(tmp); |
| + | return ret; |
| + | } |
| + | |
| + | #ifdef TEST_PROGRAM |
| + | int main(int argc, char **argv) |
| + | { |
| + | blkid_cache cache = NULL; |
| + | int ret; |
| + | |
| + | blkid_debug_mask = DEBUG_ALL; |
| + | if (argc > 2) { |
| + | fprintf(stderr, "Usage: %s [filename]\n" |
| + | "Test loading/saving a cache (filename)\n", argv[0]); |
| + | exit(1); |
| + | } |
| + | |
| + | if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { |
| + | fprintf(stderr, "%s: error creating cache (%d)\n", |
| + | argv[0], ret); |
| + | exit(1); |
| + | } |
| + | if ((ret = blkid_probe_all(cache)) < 0) { |
| + | fprintf(stderr, "error (%d) probing devices\n", ret); |
| + | exit(1); |
| + | } |
| + | cache->bic_filename = blkid_strdup(argv[1]); |
| + | |
| + | if ((ret = blkid_flush_cache(cache)) < 0) { |
| + | fprintf(stderr, "error (%d) saving cache\n", ret); |
| + | exit(1); |
| + | } |
| + | |
| + | blkid_put_cache(cache); |
| + | |
| + | return ret; |
| + | } |
| + | #endif |
| @@ -0,0 +1,340 @@ | |
| + | /* |
| + | * 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 <stdlib.h> |
| + | #include <string.h> |
| + | #include <stdio.h> |
| + | |
| + | #include "blkidP.h" |
| + | |
| + | static blkid_tag blkid_new_tag(void) |
| + | { |
| + | blkid_tag tag; |
| + | |
| + | if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag)))) |
| + | return NULL; |
| + | |
| + | INIT_LIST_HEAD(&tag->bit_tags); |
| + | INIT_LIST_HEAD(&tag->bit_names); |
| + | |
| + | return tag; |
| + | } |
| + | |
| + | void blkid_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)")); |
| + | DEB_DUMP_TAG(DEBUG_TAG, tag); |
| + | |
| + | list_del(&tag->bit_tags); /* list of tags for this device */ |
| + | list_del(&tag->bit_names); /* list of tags with this type */ |
| + | |
| + | if (tag->bit_name) |
| + | free(tag->bit_name); |
| + | if (tag->bit_val) |
| + | free(tag->bit_val); |
| + | |
| + | free(tag); |
| + | } |
| + | |
| + | /* |
| + | * Find the desired tag on a device. If value is NULL, then the |
| + | * first such tag is returned, otherwise return only exact tag if found. |
| + | */ |
| + | blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type) |
| + | { |
| + | struct list_head *p; |
| + | |
| + | if (!dev || !type) |
| + | return NULL; |
| + | |
| + | list_for_each(p, &dev->bid_tags) { |
| + | blkid_tag tmp = list_entry(p, struct blkid_struct_tag, |
| + | bit_tags); |
| + | |
| + | if (!strcmp(tmp->bit_name, type)) |
| + | return tmp; |
| + | } |
| + | return NULL; |
| + | } |
| + | |
| + | /* |
| + | * 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; |
| + | |
| + | if (!dev || !name) |
| + | return -BLKID_ERR_PARAM; |
| + | |
| + | if (!(val = blkid_strndup(value, vlength)) && value) |
| + | return -BLKID_ERR_MEM; |
| + | 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 (!strcmp(name, "TYPE")) |
| + | dev->bid_type = val; |
| + | else if (!strcmp(name, "LABEL")) |
| + | dev->bid_label = val; |
| + | else if (!strcmp(name, "UUID")) |
| + | dev->bid_uuid = val; |
| + | |
| + | if (dev->bid_cache) |
| + | dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED; |
| + | return 0; |
| + | |
| + | errout: |
| + | if (t) |
| + | blkid_free_tag(t); |
| + | else if (val) |
| + | free(val); |
| + | if (head) |
| + | blkid_free_tag(head); |
| + | return -BLKID_ERR_MEM; |
| + | } |
| + | |
| + | |
| + | /* |
| + | * Parse a "NAME=value" string. This is slightly different than |
| + | * parse_token, because that will end an unquoted value at a space, while |
| + | * this will assume that an unquoted value is the rest of the token (e.g. |
| + | * if we are passed an already quoted string from the command-line we don't |
| + | * have to both quote and escape quote so that the quotes make it to |
| + | * us). |
| + | * |
| + | * Returns 0 on success, and -1 on failure. |
| + | */ |
| + | int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val) |
| + | { |
| + | char *name, *value, *cp; |
| + | |
| + | DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token)); |
| + | |
| + | if (!token || !(cp = strchr(token, '='))) |
| + | return -1; |
| + | |
| + | name = blkid_strdup(token); |
| + | if (!name) |
| + | return -1; |
| + | value = name + (cp - token); |
| + | *value++ = '\0'; |
| + | if (*value == '"' || *value == '\'') { |
| + | char c = *value++; |
| + | if (!(cp = strrchr(value, c))) |
| + | goto errout; /* missing closing quote */ |
| + | *cp = '\0'; |
| + | } |
| + | value = blkid_strdup(value); |
| + | if (!value) |
| + | goto errout; |
| + | |
| + | *ret_type = name; |
| + | *ret_val = value; |
| + | |
| + | return 0; |
| + | |
| + | errout: |
| + | free(name); |
| + | return -1; |
| + | } |
| + | |
| + | /* |
| + | * Tag iteration routines for the public libblkid interface. |
| + | * |
| + | * These routines do not expose the list.h implementation, which are a |
| + | * contamination of the namespace, and which force us to reveal far, far |
| + | * too much of our internal implemenation. I'm not convinced I want |
| + | * to keep list.h in the long term, anyway. It's fine for kernel |
| + | * programming, but performance is not the #1 priority for this |
| + | * library, and I really don't like the tradeoff of type-safety for |
| + | * performance for this application. [tytso:20030125.2007EST] |
| + | */ |
| + | |
| + | /* |
| + | * This series of functions iterate over all tags in a device |
| + | */ |
| + | #define TAG_ITERATE_MAGIC 0x01a5284c |
| + | |
| + | struct blkid_struct_tag_iterate { |
| + | int magic; |
| + | blkid_dev dev; |
| + | struct list_head *p; |
| + | }; |
| + | |
| + | extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev) |
| + | { |
| + | blkid_tag_iterate iter; |
| + | |
| + | iter = malloc(sizeof(struct blkid_struct_tag_iterate)); |
| + | if (iter) { |
| + | iter->magic = TAG_ITERATE_MAGIC; |
| + | iter->dev = dev; |
| + | iter->p = dev->bid_tags.next; |
| + | } |
| + | return (iter); |
| + | } |
| + | |
| + | /* |
| + | * Return 0 on success, -1 on error |
| + | */ |
| + | extern int blkid_tag_next(blkid_tag_iterate iter, |
| + | const char **type, const char **value) |
| + | { |
| + | blkid_tag tag; |
| + | |
| + | *type = 0; |
| + | *value = 0; |
| + | if (!iter || iter->magic != TAG_ITERATE_MAGIC || |
| + | iter->p == &iter->dev->bid_tags) |
| + | return -1; |
| + | tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags); |
| + | *type = tag->bit_name; |
| + | *value = tag->bit_val; |
| + | iter->p = iter->p->next; |
| + | return 0; |
| + | } |
| + | |
| + | extern void blkid_tag_iterate_end(blkid_tag_iterate iter) |
| + | { |
| + | if (!iter || iter->magic != TAG_ITERATE_MAGIC) |
| + | return; |
| + | iter->magic = 0; |
| + | free(iter); |
| + | } |
| + | |
| + | /* |
| + | * This function returns a device which matches a particular |
| + | * type/value pair. If there is more than one device that matches the |
| + | * search specification, it returns the one with the highest priority |
| + | * value. This allows us to give preference to EVMS or LVM devices. |
| + | * |
| + | * XXX there should also be an interface which uses an iterator so we |
| + | * can get all of the devices which match a type/value search parameter. |
| + | */ |
| + | 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; |
| + | |
| + | 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) { |
| + | 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->bid_flags & BLKID_BID_FL_VERIFIED)) |
| + | 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; |
| + | } |
| @@ -0,0 +1,49 @@ | |
| + | /* |
| + | * 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" |
| + | #include "../../version.h" |
| + | |
| + | static const char *lib_version = E2FSPROGS_VERSION; |
| + | static const char *lib_date = E2FSPROGS_DATE; |
| + | |
| + | int blkid_parse_version_string(const char *ver_string) |
| + | { |
| + | const char *cp; |
| + | int version = 0; |
| + | |
| + | for (cp = ver_string; *cp; cp++) { |
| + | if (*cp == '.') |
| + | continue; |
| + | if (!isdigit(*cp)) |
| + | break; |
| + | version = (version * 10) + (*cp - '0'); |
| + | } |
| + | return version; |
| + | } |
| + | |
| + | int blkid_get_library_version(const char **ver_string, |
| + | const char **date_string) |
| + | { |
| + | if (ver_string) |
| + | *ver_string = lib_version; |
| + | if (date_string) |
| + | *date_string = lib_date; |
| + | |
| + | return blkid_parse_version_string(lib_version); |
| + | } |
| @@ -0,0 +1,207 @@ | |
| + | /* |
| + | * util.c --- helper functions used by tune2fs and mke2fs |
| + | * |
| + | * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * This file may be redistributed under the terms of the GNU Public |
| + | * License. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include <stdio.h> |
| + | #include <string.h> |
| + | #include <errno.h> |
| + | #include <linux/major.h> |
| + | #include <sys/stat.h> |
| + | |
| + | #include "e2fsbb.h" |
| + | #include "e2p/e2p.h" |
| + | #include "ext2fs/ext2_fs.h" |
| + | #include "ext2fs/ext2fs.h" |
| + | #include "blkid/blkid.h" |
| + | #include "util.h" |
| + | |
| + | void proceed_question(void) |
| + | { |
| + | fputs("Proceed anyway? (y,n) ", stdout); |
| + | if (bb_ask_confirmation() == 0) |
| + | exit(1); |
| + | } |
| + | |
| + | void check_plausibility(const char *device) |
| + | { |
| + | int val; |
| + | #ifdef CONFIG_LFS |
| + | struct stat64 s; |
| + | val = stat64(device, &s); |
| + | #else |
| + | struct stat s; |
| + | val = stat(device, &s); |
| + | #endif |
| + | |
| + | if(val == -1) |
| + | bb_perror_msg_and_die("Could not stat %s", device); |
| + | if (!S_ISBLK(s.st_mode)) { |
| + | printf("%s is not a block special device.\n", device); |
| + | proceed_question(); |
| + | return; |
| + | } |
| + | |
| + | #ifdef HAVE_LINUX_MAJOR_H |
| + | #ifndef MAJOR |
| + | #define MAJOR(dev) ((dev)>>8) |
| + | #define MINOR(dev) ((dev) & 0xff) |
| + | #endif |
| + | #ifndef SCSI_BLK_MAJOR |
| + | #ifdef SCSI_DISK0_MAJOR |
| + | #ifdef SCSI_DISK8_MAJOR |
| + | #define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ |
| + | ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \ |
| + | ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR)) |
| + | #else |
| + | #define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ |
| + | ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) |
| + | #endif /* defined(SCSI_DISK8_MAJOR) */ |
| + | #define SCSI_BLK_MAJOR(M) (SCSI_DISK_MAJOR((M)) || (M) == SCSI_CDROM_MAJOR) |
| + | #else |
| + | #define SCSI_BLK_MAJOR(M) ((M) == SCSI_DISK_MAJOR || (M) == SCSI_CDROM_MAJOR) |
| + | #endif /* defined(SCSI_DISK0_MAJOR) */ |
| + | #endif /* defined(SCSI_BLK_MAJOR) */ |
| + | if (((MAJOR(s.st_rdev) == HD_MAJOR && |
| + | MINOR(s.st_rdev)%64 == 0) || |
| + | (SCSI_BLK_MAJOR(MAJOR(s.st_rdev)) && |
| + | MINOR(s.st_rdev)%16 == 0))) { |
| + | printf("%s is entire device, not just one partition!\n", device); |
| + | proceed_question(); |
| + | } |
| + | #endif |
| + | } |
| + | |
| + | void check_mount(const char *device, int force, const char *type) |
| + | { |
| + | errcode_t retval; |
| + | int mount_flags; |
| + | |
| + | retval = ext2fs_check_if_mounted(device, &mount_flags); |
| + | if (retval) { |
| + | bb_error_msg("Could not determine if %s is mounted", device); |
| + | return; |
| + | } |
| + | if (!(mount_flags & EXT2_MF_MOUNTED)) |
| + | return; |
| + | |
| + | bb_error_msg("%s is mounted !", device); |
| + | if (force) |
| + | bb_error_msg("forcing anyways and ignoring /etc/mtab status"); |
| + | else |
| + | bb_error_msg_and_die("will not make a %s here!", type); |
| + | } |
| + | |
| + | void parse_journal_opts(char **journal_device, int *journal_flags, |
| + | int *journal_size, const char *opts) |
| + | { |
| + | char *buf, *token, *next, *p, *arg; |
| + | int journal_usage = 0; |
| + | #if 0 |
| + | int len; |
| + | len = strlen(opts); |
| + | buf = xmalloc(len+1); |
| + | strcpy(buf, opts); |
| + | #else |
| + | buf = bb_xstrdup(opts); |
| + | #endif |
| + | for (token = buf; token && *token; token = next) { |
| + | p = strchr(token, ','); |
| + | next = 0; |
| + | if (p) { |
| + | *p = 0; |
| + | next = p+1; |
| + | } |
| + | arg = strchr(token, '='); |
| + | if (arg) { |
| + | *arg = 0; |
| + | arg++; |
| + | } |
| + | if (strcmp(token, "device") == 0) { |
| + | *journal_device = blkid_get_devname(NULL, arg, NULL); |
| + | if (!journal_device) { |
| + | journal_usage++; |
| + | continue; |
| + | } |
| + | } else if (strcmp(token, "size") == 0) { |
| + | if (!arg) { |
| + | journal_usage++; |
| + | continue; |
| + | } |
| + | (*journal_size) = strtoul(arg, &p, 0); |
| + | if (*p) |
| + | journal_usage++; |
| + | } else if (strcmp(token, "v1_superblock") == 0) { |
| + | (*journal_flags) |= EXT2_MKJOURNAL_V1_SUPER; |
| + | continue; |
| + | } else |
| + | journal_usage++; |
| + | } |
| + | if (journal_usage) |
| + | bb_error_msg_and_die( |
| + | "\nBad journal options specified.\n\n" |
| + | "Journal options are separated by commas, " |
| + | "and may take an argument which\n" |
| + | "\tis set off by an equals ('=') sign.\n\n" |
| + | "Valid journal options are:\n" |
| + | "\tsize=<journal size in megabytes>\n" |
| + | "\tdevice=<journal device>\n\n" |
| + | "The journal size must be between " |
| + | "1024 and 102400 filesystem blocks.\n\n"); |
| + | } |
| + | |
| + | /* |
| + | * Determine the number of journal blocks to use, either via |
| + | * user-specified # of megabytes, or via some intelligently selected |
| + | * defaults. |
| + | * |
| + | * Find a reasonable journal file size (in blocks) given the number of blocks |
| + | * in the filesystem. For very small filesystems, it is not reasonable to |
| + | * have a journal that fills more than half of the filesystem. |
| + | */ |
| + | int figure_journal_size(int size, ext2_filsys fs) |
| + | { |
| + | blk_t j_blocks; |
| + | |
| + | if (fs->super->s_blocks_count < 2048) { |
| + | bb_error_msg("Filesystem too small for a journal"); |
| + | return 0; |
| + | } |
| + | |
| + | if (size >= 0) { |
| + | j_blocks = size * 1024 / (fs->blocksize / 1024); |
| + | if (j_blocks < 1024 || j_blocks > 102400) |
| + | bb_error_msg_and_die("\nThe requested journal " |
| + | "size is %d blocks;\n it must be " |
| + | "between 1024 and 102400 blocks; Aborting", |
| + | j_blocks); |
| + | if (j_blocks > fs->super->s_free_blocks_count) |
| + | bb_error_msg_and_die("Journal size too big for filesystem"); |
| + | return j_blocks; |
| + | } |
| + | |
| + | if (fs->super->s_blocks_count < 32768) |
| + | j_blocks = 1024; |
| + | else if (fs->super->s_blocks_count < 262144) |
| + | j_blocks = 4096; |
| + | else |
| + | j_blocks = 8192; |
| + | |
| + | return j_blocks; |
| + | } |
| + | |
| + | void print_check_message(ext2_filsys fs) |
| + | { |
| + | printf("This filesystem will be automatically " |
| + | "checked every %d mounts or\n" |
| + | "%g days, whichever comes first. " |
| + | "Use tune2fs -c or -i to override.\n", |
| + | fs->super->s_max_mnt_count, |
| + | (double)fs->super->s_checkinterval / (3600 * 24)); |
| + | } |
| @@ -0,0 +1,18 @@ | |
| + | /* |
| + | * util.h --- header file defining prototypes for helper functions |
| + | * used by tune2fs and mke2fs |
| + | * |
| + | * Copyright 2000 by Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * This file may be redistributed under the terms of the GNU Public |
| + | * License. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | extern void proceed_question(void); |
| + | extern void check_plausibility(const char *device); |
| + | extern void parse_journal_opts(char **, int *, int *, const char *opts); |
| + | extern void check_mount(const char *device, int force, const char *type); |
| + | extern int figure_journal_size(int size, ext2_filsys fs); |
| + | extern void print_check_message(ext2_filsys fs); |
| @@ -0,0 +1,43 @@ | |
| + | /* |
| + | * clear.c -- Clear a UUID |
| + | * |
| + | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include "string.h" |
| + | |
| + | #include "uuidP.h" |
| + | |
| + | void uuid_clear(uuid_t uu) |
| + | { |
| + | memset(uu, 0, 16); |
| + | } |
| + | |
| @@ -0,0 +1,55 @@ | |
| + | /* |
| + | * compare.c --- compare whether or not two UUID's are the same |
| + | * |
| + | * Returns 0 if the two UUID's are different, and 1 if they are the same. |
| + | * |
| + | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include "uuidP.h" |
| + | #include <string.h> |
| + | |
| + | #define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1); |
| + | |
| + | int uuid_compare(const uuid_t uu1, const uuid_t uu2) |
| + | { |
| + | struct uuid uuid1, uuid2; |
| + | |
| + | uuid_unpack(uu1, &uuid1); |
| + | uuid_unpack(uu2, &uuid2); |
| + | |
| + | UUCMP(uuid1.time_low, uuid2.time_low); |
| + | UUCMP(uuid1.time_mid, uuid2.time_mid); |
| + | UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version); |
| + | UUCMP(uuid1.clock_seq, uuid2.clock_seq); |
| + | return memcmp(uuid1.node, uuid2.node, 6); |
| + | } |
| + | |
| @@ -0,0 +1,45 @@ | |
| + | /* |
| + | * copy.c --- copy UUIDs |
| + | * |
| + | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include "uuidP.h" |
| + | |
| + | void uuid_copy(uuid_t dst, const uuid_t src) |
| + | { |
| + | unsigned char *cp1; |
| + | const unsigned char *cp2; |
| + | int i; |
| + | |
| + | for (i=0, cp1 = dst, cp2 = src; i < 16; i++) |
| + | *cp1++ = *cp2++; |
| + | } |
| @@ -0,0 +1,310 @@ | |
| + | /* |
| + | * gen_uuid.c --- generate a DCE-compatible uuid |
| + | * |
| + | * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #ifdef HAVE_UNISTD_H |
| + | #include <unistd.h> |
| + | #endif |
| + | #ifdef HAVE_STDLIB_H |
| + | #include <stdlib.h> |
| + | #endif |
| + | #include <string.h> |
| + | #include <fcntl.h> |
| + | #include <errno.h> |
| + | #include <sys/types.h> |
| + | #include <sys/time.h> |
| + | #include <sys/stat.h> |
| + | #include <sys/file.h> |
| + | #ifdef HAVE_SYS_IOCTL_H |
| + | #include <sys/ioctl.h> |
| + | #endif |
| + | #ifdef HAVE_SYS_SOCKET_H |
| + | #include <sys/socket.h> |
| + | #endif |
| + | #ifdef HAVE_SYS_SOCKIO_H |
| + | #include <sys/sockio.h> |
| + | #endif |
| + | #ifdef HAVE_NET_IF_H |
| + | #include <net/if.h> |
| + | #endif |
| + | #ifdef HAVE_NETINET_IN_H |
| + | #include <netinet/in.h> |
| + | #endif |
| + | #ifdef HAVE_NET_IF_DL_H |
| + | #include <net/if_dl.h> |
| + | #endif |
| + | |
| + | #include "uuidP.h" |
| + | |
| + | #ifdef HAVE_SRANDOM |
| + | #define srand(x) srandom(x) |
| + | #define rand() random() |
| + | #endif |
| + | |
| + | static int get_random_fd(void) |
| + | { |
| + | struct timeval tv; |
| + | static int fd = -2; |
| + | int i; |
| + | |
| + | if (fd == -2) { |
| + | gettimeofday(&tv, 0); |
| + | fd = open("/dev/urandom", O_RDONLY); |
| + | if (fd == -1) |
| + | fd = open("/dev/random", O_RDONLY | O_NONBLOCK); |
| + | srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); |
| + | } |
| + | /* Crank the random number generator a few times */ |
| + | gettimeofday(&tv, 0); |
| + | for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) |
| + | rand(); |
| + | return fd; |
| + | } |
| + | |
| + | |
| + | /* |
| + | * Generate a series of random bytes. Use /dev/urandom if possible, |
| + | * and if not, use srandom/random. |
| + | */ |
| + | static void get_random_bytes(void *buf, int nbytes) |
| + | { |
| + | int i, n = nbytes, fd = get_random_fd(); |
| + | int lose_counter = 0; |
| + | unsigned char *cp = (unsigned char *) buf; |
| + | |
| + | if (fd >= 0) { |
| + | while (n > 0) { |
| + | i = read(fd, cp, n); |
| + | if (i <= 0) { |
| + | if (lose_counter++ > 16) |
| + | break; |
| + | continue; |
| + | } |
| + | n -= i; |
| + | cp += i; |
| + | lose_counter = 0; |
| + | } |
| + | } |
| + | |
| + | /* |
| + | * We do this all the time, but this is the only source of |
| + | * randomness if /dev/random/urandom is out to lunch. |
| + | */ |
| + | for (cp = buf, i = 0; i < nbytes; i++) |
| + | *cp++ ^= (rand() >> 7) & 0xFF; |
| + | return; |
| + | } |
| + | |
| + | /* |
| + | * Get the ethernet hardware address, if we can find it... |
| + | */ |
| + | static int get_node_id(unsigned char *node_id) |
| + | { |
| + | #ifdef HAVE_NET_IF_H |
| + | int sd; |
| + | struct ifreq ifr, *ifrp; |
| + | struct ifconf ifc; |
| + | char buf[1024]; |
| + | int n, i; |
| + | unsigned char *a; |
| + | #ifdef HAVE_NET_IF_DL_H |
| + | struct sockaddr_dl *sdlp; |
| + | #endif |
| + | |
| + | /* |
| + | * BSD 4.4 defines the size of an ifreq to be |
| + | * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len |
| + | * However, under earlier systems, sa_len isn't present, so the size is |
| + | * just sizeof(struct ifreq) |
| + | */ |
| + | #ifdef HAVE_SA_LEN |
| + | #ifndef max |
| + | #define max(a,b) ((a) > (b) ? (a) : (b)) |
| + | #endif |
| + | #define ifreq_size(i) max(sizeof(struct ifreq),\ |
| + | sizeof((i).ifr_name)+(i).ifr_addr.sa_len) |
| + | #else |
| + | #define ifreq_size(i) sizeof(struct ifreq) |
| + | #endif /* HAVE_SA_LEN*/ |
| + | |
| + | sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); |
| + | if (sd < 0) { |
| + | return -1; |
| + | } |
| + | memset(buf, 0, sizeof(buf)); |
| + | ifc.ifc_len = sizeof(buf); |
| + | ifc.ifc_buf = buf; |
| + | if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { |
| + | close(sd); |
| + | return -1; |
| + | } |
| + | n = ifc.ifc_len; |
| + | for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { |
| + | ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); |
| + | strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); |
| + | #ifdef SIOCGIFHWADDR |
| + | if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) |
| + | continue; |
| + | a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; |
| + | #else |
| + | #ifdef SIOCGENADDR |
| + | if (ioctl(sd, SIOCGENADDR, &ifr) < 0) |
| + | continue; |
| + | a = (unsigned char *) ifr.ifr_enaddr; |
| + | #else |
| + | #ifdef HAVE_NET_IF_DL_H |
| + | sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; |
| + | if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) |
| + | continue; |
| + | a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; |
| + | #else |
| + | /* |
| + | * XXX we don't have a way of getting the hardware |
| + | * address |
| + | */ |
| + | close(sd); |
| + | return 0; |
| + | #endif /* HAVE_NET_IF_DL_H */ |
| + | #endif /* SIOCGENADDR */ |
| + | #endif /* SIOCGIFHWADDR */ |
| + | if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) |
| + | continue; |
| + | if (node_id) { |
| + | memcpy(node_id, a, 6); |
| + | close(sd); |
| + | return 1; |
| + | } |
| + | } |
| + | close(sd); |
| + | #endif |
| + | return 0; |
| + | } |
| + | |
| + | /* Assume that the gettimeofday() has microsecond granularity */ |
| + | #define MAX_ADJUSTMENT 10 |
| + | |
| + | static int get_clock(uint32_t *clock_high, uint32_t *clock_low, uint16_t *ret_clock_seq) |
| + | { |
| + | static int adjustment = 0; |
| + | static struct timeval last = {0, 0}; |
| + | static uint16_t clock_seq; |
| + | struct timeval tv; |
| + | unsigned long long clock_reg; |
| + | |
| + | try_again: |
| + | gettimeofday(&tv, 0); |
| + | if ((last.tv_sec == 0) && (last.tv_usec == 0)) { |
| + | get_random_bytes(&clock_seq, sizeof(clock_seq)); |
| + | clock_seq &= 0x3FFF; |
| + | last = tv; |
| + | last.tv_sec--; |
| + | } |
| + | if ((tv.tv_sec < last.tv_sec) || |
| + | ((tv.tv_sec == last.tv_sec) && |
| + | (tv.tv_usec < last.tv_usec))) { |
| + | clock_seq = (clock_seq+1) & 0x3FFF; |
| + | adjustment = 0; |
| + | last = tv; |
| + | } else if ((tv.tv_sec == last.tv_sec) && |
| + | (tv.tv_usec == last.tv_usec)) { |
| + | if (adjustment >= MAX_ADJUSTMENT) |
| + | goto try_again; |
| + | adjustment++; |
| + | } else { |
| + | adjustment = 0; |
| + | last = tv; |
| + | } |
| + | |
| + | clock_reg = tv.tv_usec*10 + adjustment; |
| + | clock_reg += ((unsigned long long) tv.tv_sec)*10000000; |
| + | clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; |
| + | |
| + | *clock_high = clock_reg >> 32; |
| + | *clock_low = clock_reg; |
| + | *ret_clock_seq = clock_seq; |
| + | return 0; |
| + | } |
| + | |
| + | void uuid_generate_time(uuid_t out) |
| + | { |
| + | static unsigned char node_id[6]; |
| + | static int has_init = 0; |
| + | struct uuid uu; |
| + | uint32_t clock_mid; |
| + | |
| + | if (!has_init) { |
| + | if (get_node_id(node_id) <= 0) { |
| + | get_random_bytes(node_id, 6); |
| + | /* |
| + | * Set multicast bit, to prevent conflicts |
| + | * with IEEE 802 addresses obtained from |
| + | * network cards |
| + | */ |
| + | node_id[0] |= 0x01; |
| + | } |
| + | has_init = 1; |
| + | } |
| + | get_clock(&clock_mid, &uu.time_low, &uu.clock_seq); |
| + | uu.clock_seq |= 0x8000; |
| + | uu.time_mid = (uint16_t) clock_mid; |
| + | uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; |
| + | memcpy(uu.node, node_id, 6); |
| + | uuid_pack(&uu, out); |
| + | } |
| + | |
| + | void uuid_generate_random(uuid_t out) |
| + | { |
| + | uuid_t buf; |
| + | struct uuid uu; |
| + | |
| + | get_random_bytes(buf, sizeof(buf)); |
| + | uuid_unpack(buf, &uu); |
| + | |
| + | uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; |
| + | uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000; |
| + | uuid_pack(&uu, out); |
| + | } |
| + | |
| + | /* |
| + | * This is the generic front-end to uuid_generate_random and |
| + | * uuid_generate_time. It uses uuid_generate_random only if |
| + | * /dev/urandom is available, since otherwise we won't have |
| + | * high-quality randomness. |
| + | */ |
| + | void uuid_generate(uuid_t out) |
| + | { |
| + | if (get_random_fd() >= 0) |
| + | uuid_generate_random(out); |
| + | else |
| + | uuid_generate_time(out); |
| + | } |
| @@ -0,0 +1,48 @@ | |
| + | /* |
| + | * isnull.c --- Check whether or not the UUID is null |
| + | * |
| + | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include "uuidP.h" |
| + | |
| + | /* Returns 1 if the uuid is the NULL uuid */ |
| + | int uuid_is_null(const uuid_t uu) |
| + | { |
| + | const unsigned char *cp; |
| + | int i; |
| + | |
| + | for (i=0, cp = uu; i < 16; i++) |
| + | if (*cp++) |
| + | return 0; |
| + | return 1; |
| + | } |
| + | |
| @@ -0,0 +1,69 @@ | |
| + | /* |
| + | * Internal routine for packing UUID's |
| + | * |
| + | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include <string.h> |
| + | #include "uuidP.h" |
| + | |
| + | void uuid_pack(const struct uuid *uu, uuid_t ptr) |
| + | { |
| + | uint32_t tmp; |
| + | unsigned char *out = ptr; |
| + | |
| + | tmp = uu->time_low; |
| + | out[3] = (unsigned char) tmp; |
| + | tmp >>= 8; |
| + | out[2] = (unsigned char) tmp; |
| + | tmp >>= 8; |
| + | out[1] = (unsigned char) tmp; |
| + | tmp >>= 8; |
| + | out[0] = (unsigned char) tmp; |
| + | |
| + | tmp = uu->time_mid; |
| + | out[5] = (unsigned char) tmp; |
| + | tmp >>= 8; |
| + | out[4] = (unsigned char) tmp; |
| + | |
| + | tmp = uu->time_hi_and_version; |
| + | out[7] = (unsigned char) tmp; |
| + | tmp >>= 8; |
| + | out[6] = (unsigned char) tmp; |
| + | |
| + | tmp = uu->clock_seq; |
| + | out[9] = (unsigned char) tmp; |
| + | tmp >>= 8; |
| + | out[8] = (unsigned char) tmp; |
| + | |
| + | memcpy(out+10, uu->node, 6); |
| + | } |
| + | |
| @@ -0,0 +1,79 @@ | |
| + | /* |
| + | * parse.c --- UUID parsing |
| + | * |
| + | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include <stdlib.h> |
| + | #include <stdio.h> |
| + | #include <ctype.h> |
| + | #include <string.h> |
| + | |
| + | #include "uuidP.h" |
| + | |
| + | int uuid_parse(const char *in, uuid_t uu) |
| + | { |
| + | struct uuid uuid; |
| + | int i; |
| + | const char *cp; |
| + | char buf[3]; |
| + | |
| + | if (strlen(in) != 36) |
| + | return -1; |
| + | for (i=0, cp = in; i <= 36; i++,cp++) { |
| + | if ((i == 8) || (i == 13) || (i == 18) || |
| + | (i == 23)) { |
| + | if (*cp == '-') |
| + | continue; |
| + | else |
| + | return -1; |
| + | } |
| + | if (i== 36) |
| + | if (*cp == 0) |
| + | continue; |
| + | if (!isxdigit(*cp)) |
| + | return -1; |
| + | } |
| + | uuid.time_low = strtoul(in, NULL, 16); |
| + | uuid.time_mid = strtoul(in+9, NULL, 16); |
| + | uuid.time_hi_and_version = strtoul(in+14, NULL, 16); |
| + | uuid.clock_seq = strtoul(in+19, NULL, 16); |
| + | cp = in+24; |
| + | buf[2] = 0; |
| + | for (i=0; i < 6; i++) { |
| + | buf[0] = *cp++; |
| + | buf[1] = *cp++; |
| + | uuid.node[i] = strtoul(buf, NULL, 16); |
| + | } |
| + | |
| + | uuid_pack(&uuid, uu); |
| + | return 0; |
| + | } |
| @@ -0,0 +1,63 @@ | |
| + | /* |
| + | * Internal routine for unpacking UUID |
| + | * |
| + | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include <string.h> |
| + | #include "uuidP.h" |
| + | |
| + | void uuid_unpack(const uuid_t in, struct uuid *uu) |
| + | { |
| + | const uint8_t *ptr = in; |
| + | uint32_t tmp; |
| + | |
| + | tmp = *ptr++; |
| + | tmp = (tmp << 8) | *ptr++; |
| + | tmp = (tmp << 8) | *ptr++; |
| + | tmp = (tmp << 8) | *ptr++; |
| + | uu->time_low = tmp; |
| + | |
| + | tmp = *ptr++; |
| + | tmp = (tmp << 8) | *ptr++; |
| + | uu->time_mid = tmp; |
| + | |
| + | tmp = *ptr++; |
| + | tmp = (tmp << 8) | *ptr++; |
| + | uu->time_hi_and_version = tmp; |
| + | |
| + | tmp = *ptr++; |
| + | tmp = (tmp << 8) | *ptr++; |
| + | uu->clock_seq = tmp; |
| + | |
| + | memcpy(uu->node, ptr, 6); |
| + | } |
| + | |
| @@ -0,0 +1,76 @@ | |
| + | /* |
| + | * unparse.c -- convert a UUID to string |
| + | * |
| + | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include <stdio.h> |
| + | |
| + | #include "uuidP.h" |
| + | |
| + | static const char *fmt_lower = |
| + | "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; |
| + | |
| + | static const char *fmt_upper = |
| + | "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"; |
| + | |
| + | #ifdef UUID_UNPARSE_DEFAULT_UPPER |
| + | #define FMT_DEFAULT fmt_upper |
| + | #else |
| + | #define FMT_DEFAULT fmt_lower |
| + | #endif |
| + | |
| + | static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt) |
| + | { |
| + | struct uuid uuid; |
| + | |
| + | uuid_unpack(uu, &uuid); |
| + | sprintf(out, fmt, |
| + | uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, |
| + | uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, |
| + | uuid.node[0], uuid.node[1], uuid.node[2], |
| + | uuid.node[3], uuid.node[4], uuid.node[5]); |
| + | } |
| + | |
| + | void uuid_unparse_lower(const uuid_t uu, char *out) |
| + | { |
| + | uuid_unparse_x(uu, out, fmt_lower); |
| + | } |
| + | |
| + | void uuid_unparse_upper(const uuid_t uu, char *out) |
| + | { |
| + | uuid_unparse_x(uu, out, fmt_upper); |
| + | } |
| + | |
| + | void uuid_unparse(const uuid_t uu, char *out) |
| + | { |
| + | uuid_unparse_x(uu, out, FMT_DEFAULT); |
| + | } |
| @@ -0,0 +1,101 @@ | |
| + | /* |
| + | * Public include file for the UUID library |
| + | * |
| + | * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #ifndef _UUID_UUID_H |
| + | #define _UUID_UUID_H |
| + | |
| + | #include <sys/types.h> |
| + | #include <sys/time.h> |
| + | #include <time.h> |
| + | |
| + | typedef unsigned char uuid_t[16]; |
| + | |
| + | /* UUID Variant definitions */ |
| + | #define UUID_VARIANT_NCS 0 |
| + | #define UUID_VARIANT_DCE 1 |
| + | #define UUID_VARIANT_MICROSOFT 2 |
| + | #define UUID_VARIANT_OTHER 3 |
| + | |
| + | /* UUID Type definitions */ |
| + | #define UUID_TYPE_DCE_TIME 1 |
| + | #define UUID_TYPE_DCE_RANDOM 4 |
| + | |
| + | /* Allow UUID constants to be defined */ |
| + | #ifdef __GNUC__ |
| + | #define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \ |
| + | static const uuid_t name __attribute__ ((unused)) = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15} |
| + | #else |
| + | #define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \ |
| + | static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15} |
| + | #endif |
| + | |
| + | #ifdef __cplusplus |
| + | extern "C" { |
| + | #endif |
| + | |
| + | /* clear.c */ |
| + | void uuid_clear(uuid_t uu); |
| + | |
| + | /* compare.c */ |
| + | int uuid_compare(const uuid_t uu1, const uuid_t uu2); |
| + | |
| + | /* copy.c */ |
| + | void uuid_copy(uuid_t dst, const uuid_t src); |
| + | |
| + | /* gen_uuid.c */ |
| + | void uuid_generate(uuid_t out); |
| + | void uuid_generate_random(uuid_t out); |
| + | void uuid_generate_time(uuid_t out); |
| + | |
| + | /* isnull.c */ |
| + | int uuid_is_null(const uuid_t uu); |
| + | |
| + | /* parse.c */ |
| + | int uuid_parse(const char *in, uuid_t uu); |
| + | |
| + | /* unparse.c */ |
| + | void uuid_unparse(const uuid_t uu, char *out); |
| + | void uuid_unparse_lower(const uuid_t uu, char *out); |
| + | void uuid_unparse_upper(const uuid_t uu, char *out); |
| + | |
| + | /* uuid_time.c */ |
| + | time_t uuid_time(const uuid_t uu, struct timeval *ret_tv); |
| + | int uuid_type(const uuid_t uu); |
| + | int uuid_variant(const uuid_t uu); |
| + | |
| + | #ifdef __cplusplus |
| + | } |
| + | #endif |
| + | |
| + | #endif /* _UUID_UUID_H */ |
| @@ -0,0 +1,63 @@ | |
| + | /* |
| + | * uuid.h -- private header file for uuids |
| + | * |
| + | * Copyright (C) 1996, 1997 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #ifdef HAVE_INTTYPES_H |
| + | #include <inttypes.h> |
| + | #else |
| + | #include <uuid/uuid_types.h> |
| + | #endif |
| + | #include <sys/types.h> |
| + | |
| + | #include "uuid.h" |
| + | |
| + | /* |
| + | * Offset between 15-Oct-1582 and 1-Jan-70 |
| + | */ |
| + | #define TIME_OFFSET_HIGH 0x01B21DD2 |
| + | #define TIME_OFFSET_LOW 0x13814000 |
| + | |
| + | struct uuid { |
| + | uint32_t time_low; |
| + | uint16_t time_mid; |
| + | uint16_t time_hi_and_version; |
| + | uint16_t clock_seq; |
| + | uint8_t node[6]; |
| + | }; |
| + | |
| + | |
| + | /* |
| + | * prototypes |
| + | */ |
| + | void uuid_pack(const struct uuid *uu, uuid_t ptr); |
| + | void uuid_unpack(const uuid_t in, struct uuid *uu); |
| @@ -0,0 +1,161 @@ | |
| + | /* |
| + | * uuid_time.c --- Interpret the time field from a uuid. This program |
| + | * violates the UUID abstraction barrier by reaching into the guts |
| + | * of a UUID and interpreting it. |
| + | * |
| + | * Copyright (C) 1998, 1999 Theodore Ts'o. |
| + | * |
| + | * %Begin-Header% |
| + | * Redistribution and use in source and binary forms, with or without |
| + | * modification, are permitted provided that the following conditions |
| + | * are met: |
| + | * 1. Redistributions of source code must retain the above copyright |
| + | * notice, and the entire permission notice in its entirety, |
| + | * including the disclaimer of warranties. |
| + | * 2. Redistributions in binary form must reproduce the above copyright |
| + | * notice, this list of conditions and the following disclaimer in the |
| + | * documentation and/or other materials provided with the distribution. |
| + | * 3. The name of the author may not be used to endorse or promote |
| + | * products derived from this software without specific prior |
| + | * written permission. |
| + | * |
| + | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| + | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| + | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF |
| + | * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE |
| + | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| + | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| + | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| + | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
| + | * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH |
| + | * DAMAGE. |
| + | * %End-Header% |
| + | */ |
| + | |
| + | #include <stdio.h> |
| + | #include <unistd.h> |
| + | #include <stdlib.h> |
| + | #include <sys/types.h> |
| + | #include <sys/time.h> |
| + | #include <time.h> |
| + | |
| + | #include "uuidP.h" |
| + | |
| + | time_t uuid_time(const uuid_t uu, struct timeval *ret_tv) |
| + | { |
| + | struct uuid uuid; |
| + | uint32_t high; |
| + | struct timeval tv; |
| + | unsigned long long clock_reg; |
| + | |
| + | uuid_unpack(uu, &uuid); |
| + | |
| + | high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16); |
| + | clock_reg = uuid.time_low | ((unsigned long long) high << 32); |
| + | |
| + | clock_reg -= (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; |
| + | tv.tv_sec = clock_reg / 10000000; |
| + | tv.tv_usec = (clock_reg % 10000000) / 10; |
| + | |
| + | if (ret_tv) |
| + | *ret_tv = tv; |
| + | |
| + | return tv.tv_sec; |
| + | } |
| + | |
| + | int uuid_type(const uuid_t uu) |
| + | { |
| + | struct uuid uuid; |
| + | |
| + | uuid_unpack(uu, &uuid); |
| + | return ((uuid.time_hi_and_version >> 12) & 0xF); |
| + | } |
| + | |
| + | int uuid_variant(const uuid_t uu) |
| + | { |
| + | struct uuid uuid; |
| + | int var; |
| + | |
| + | uuid_unpack(uu, &uuid); |
| + | var = uuid.clock_seq; |
| + | |
| + | if ((var & 0x8000) == 0) |
| + | return UUID_VARIANT_NCS; |
| + | if ((var & 0x4000) == 0) |
| + | return UUID_VARIANT_DCE; |
| + | if ((var & 0x2000) == 0) |
| + | return UUID_VARIANT_MICROSOFT; |
| + | return UUID_VARIANT_OTHER; |
| + | } |
| + | |
| + | #ifdef DEBUG |
| + | static const char *variant_string(int variant) |
| + | { |
| + | switch (variant) { |
| + | case UUID_VARIANT_NCS: |
| + | return "NCS"; |
| + | case UUID_VARIANT_DCE: |
| + | return "DCE"; |
| + | case UUID_VARIANT_MICROSOFT: |
| + | return "Microsoft"; |
| + | default: |
| + | return "Other"; |
| + | } |
| + | } |
| + | |
| + | |
| + | int |
| + | main(int argc, char **argv) |
| + | { |
| + | uuid_t buf; |
| + | time_t time_reg; |
| + | struct timeval tv; |
| + | int type, variant; |
| + | |
| + | if (argc != 2) { |
| + | fprintf(stderr, "Usage: %s uuid\n", argv[0]); |
| + | exit(1); |
| + | } |
| + | if (uuid_parse(argv[1], buf)) { |
| + | fprintf(stderr, "Invalid UUID: %s\n", argv[1]); |
| + | exit(1); |
| + | } |
| + | variant = uuid_variant(buf); |
| + | type = uuid_type(buf); |
| + | time_reg = uuid_time(buf, &tv); |
| + | |
| + | printf("UUID variant is %d (%s)\n", variant, variant_string(variant)); |
| + | if (variant != UUID_VARIANT_DCE) { |
| + | printf("Warning: This program only knows how to interpret " |
| + | "DCE UUIDs.\n\tThe rest of the output is likely " |
| + | "to be incorrect!!\n"); |
| + | } |
| + | printf("UUID type is %d", type); |
| + | switch (type) { |
| + | case 1: |
| + | printf(" (time based)\n"); |
| + | break; |
| + | case 2: |
| + | printf(" (DCE)\n"); |
| + | break; |
| + | case 3: |
| + | printf(" (name-based)\n"); |
| + | break; |
| + | case 4: |
| + | printf(" (random)\n"); |
| + | break; |
| + | default: |
| + | printf("\n"); |
| + | } |
| + | if (type != 1) { |
| + | printf("Warning: not a time-based UUID, so UUID time " |
| + | "decoding will likely not work!\n"); |
| + | } |
| + | printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, tv.tv_usec, |
| + | ctime(&time_reg)); |
| + | |
| + | return 0; |
| + | } |
| + | #endif |