Updated patch. Changes: - Use mmap. - Add the device size to the exported information. Bastian -- A princess should not be afraid -- not with a brave knight to protect her. -- McCoy, "Shore Leave", stardate 3025.3
=== lib/iddev.h ================================================================== --- lib/iddev.h (/iddev/trunk) (revision 29) +++ lib/iddev.h (/iddev/local/branches/refactor) (revision 29) @@ -16,19 +16,65 @@ /** + * device_info - + */ + +enum device_info_family +{ + DEVICE_INFO_UNDEFINED_FAMILY = 0, + DEVICE_INFO_CONTAINER, + DEVICE_INFO_FILESYSTEM, + DEVICE_INFO_SWAP, +}; + +enum device_info_type +{ + DEVICE_INFO_UNDEFINED_TYPE = 0, + DEVICE_INFO_CONTAINER_CCA, + DEVICE_INFO_CONTAINER_CIDEV, + DEVICE_INFO_CONTAINER_LVM1, + DEVICE_INFO_CONTAINER_LVM2, + DEVICE_INFO_CONTAINER_PARTITION, + DEVICE_INFO_CONTAINER_POOL, + DEVICE_INFO_FILESYSTEM_EXT23, + DEVICE_INFO_FILESYSTEM_GFS, + DEVICE_INFO_FILESYSTEM_REISERFS, + DEVICE_INFO_FILESYSTEM_XFS, +}; + +enum device_info_subtype +{ + DEVICE_INFO_UNDEFINED_SUBTYPE = 0, + DEVICE_INFO_CONTAINER_PARTITION_MSDOS, + DEVICE_INFO_FILESYSTEM_EXT2, + DEVICE_INFO_FILESYSTEM_EXT3, +}; + +struct device_info +{ + enum device_info_family family; + enum device_info_type type; + enum device_info_subtype subtype; + + char display[128]; + unsigned char uuid[16]; + uint64_t device_size; + uint32_t block_size; +}; + +/** * indentify_device - figure out what's on a device * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type + * @info: a buffer * * The offset of @fd will be changed by the function. * This routine will not write to this device. * * Returns: -1 on error (with errno set), 1 if unabled to identify, - * 0 if device identified (with @type set) + * 0 if device identified (with @info set) */ -int identify_device(int fd, char *type, unsigned type_len); +int identify_device(int fd, struct device_info *info); /** @@ -39,7 +85,7 @@ * Returns: -1 on error (with errno set), 0 on success (with @bytes set) */ -int device_size(int fd, uint64 *bytes); +int device_size(int fd, uint64_t *bytes); #endif /* __IDDEV_DOT_H__ */ === lib/identify_device.c ================================================================== --- lib/identify_device.c (/iddev/trunk) (revision 29) +++ lib/identify_device.c (/iddev/local/branches/refactor) (revision 29) @@ -50,8 +50,8 @@ int main(int argc, char *argv[]) { int fd; - char buf[BUFSIZE]; - uint64 bytes; + struct device_info info; + const char *display; int error; prog_name = argv[0]; @@ -63,18 +63,16 @@ if (fd < 0) die("can't open %s: %s\n", argv[1], strerror(errno)); - error = identify_device(fd, buf, BUFSIZE); + error = identify_device(fd, &info); if (error < 0) die("error identifying the contents of %s: %s\n", argv[1], strerror(errno)); else if (error) - strcpy(buf, "unknown"); + display = "unknown"; + else + display = info.display; - error = device_size(fd, &bytes); - if (error < 0) - die("error determining the size of %s: %s\n", argv[1], strerror(errno)); - printf("%s:\n%-15s%s\n%-15s%"PRIu64"\n", - argv[1], " contents:", buf, " bytes:", bytes); + argv[1], " contents:", display, " bytes:", info.device_size); close(fd); === lib/iddev.c ================================================================== --- lib/iddev.c (/iddev/trunk) (revision 29) +++ lib/iddev.c (/iddev/local/branches/refactor) (revision 29) @@ -14,6 +14,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -25,48 +26,53 @@ #include "iddev.h" +static void info_set_display(struct device_info *info, const char *display) +{ + snprintf(info->display, sizeof (info->display), display); +} +static inline void info_set(struct device_info *info, const enum device_info_family family, const enum device_info_type type, const enum device_info_subtype subtype, const char *display) +{ + info->family = family; + info->type = type; + info->subtype = subtype; + info_set_display(info, display); +} +static inline void info_set_container(struct device_info *info, const enum device_info_type type, const enum device_info_subtype subtype, const char *display) +{ + info_set(info, DEVICE_INFO_CONTAINER, type, subtype, display); +} +static inline void info_set_filesystem(struct device_info *info, const enum device_info_type type, const enum device_info_subtype subtype, const char *display) +{ + info_set(info, DEVICE_INFO_FILESYSTEM, type, subtype, display); +} +typedef int check(const void *mem, size_t len, struct device_info *info); + /** * check_for_gfs - check to see if GFS is on this device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * An EINVAL returned from lseek means that the device was too - * small -- at least on Linux. - * - * Returns: -1 on error (with errno set), 1 if not GFS, - * 0 if GFS found (with type set) */ -static int check_for_gfs(int fd, char *type, unsigned type_len) +enum { - unsigned char buf[512]; - uint32 *p = (uint32 *)buf; - int error; + GFS_OFFSET = 64*1024, + GFS_SB_SIZE = 512, +}; - error = lseek(fd, 65536, SEEK_SET); - if (error < 0) - return (errno == EINVAL) ? 1 : error; - else if (error != 65536) - { - errno = EINVAL; - return -1; - } +static check check_for_gfs; +static int check_for_gfs(const void *mem, size_t len, struct device_info *info) +{ + const uint32_t *p = (const uint32_t *)((const unsigned char *)mem + GFS_OFFSET); - error = read(fd, buf, 512); - if (error < 0) - return error; - else if (error < 8) + if (len < GFS_OFFSET + GFS_SB_SIZE) return 1; if (osi_be32_to_cpu(*p) != 0x01161970 || osi_be32_to_cpu(*(p + 1)) != 1) return 1; - snprintf(type, type_len, "GFS filesystem"); + info_set_filesystem(info, DEVICE_INFO_FILESYSTEM_GFS, 0, "GFS filesystem"); return 0; } @@ -74,199 +80,186 @@ /** * check_for_pool - check to see if Pool is on this device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * Returns: -1 on error (with errno set), 1 if not Pool, - * 0 if Pool found (with type set) */ -static int check_for_pool(int fd, char *type, unsigned type_len) +enum { - unsigned char buf[512]; - uint64 *p = (uint64 *)buf; - int error; + POOL_SB_SIZE = 512, +}; - error = lseek(fd, 0, SEEK_SET); - if (error < 0) - return error; - else if (error != 0) - { - errno = EINVAL; - return -1; - } +static check check_for_pool; +static int check_for_pool(const void *mem, size_t len, struct device_info *info) +{ + const uint64_t *p = mem; - error = read(fd, buf, 512); - if (error < 0) - return error; - else if (error < 8) + if (len < POOL_SB_SIZE) return 1; if (osi_be64_to_cpu(*p) != 0x11670) return 1; - snprintf(type, type_len, "Pool subdevice"); + info_set_container(info, DEVICE_INFO_CONTAINER_POOL, 0, "Pool subdevice"); return 0; } /** - * check_for_paritition - check to see if Partition is on this device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * Returns: -1 on error (with errno set), 1 if not Partition, - * 0 if Partition found (with type set) + * check_for_partition_msdos - check to see if Partition is on this device */ -static int check_for_partition(int fd, char *type, unsigned type_len) +enum { - unsigned char buf[512]; - int error; + PARTITION_MSDOS_SB_SIZE = 512, +}; - error = lseek(fd, 0, SEEK_SET); - if (error < 0) - return error; - else if (error != 0) - { - errno = EINVAL; - return -1; - } +static check check_for_partition_msdos; +static int check_for_partition_msdos(const void *mem, size_t len, struct device_info *info) +{ + const unsigned char *buf = mem; - error = read(fd, buf, 512); - if (error < 0) - return error; - else if (error < 512) + if (len < PARTITION_MSDOS_SB_SIZE) return 1; if (buf[510] != 0x55 || buf[511] != 0xAA) return 1; - snprintf(type, type_len, "partition information"); + info_set_container(info, DEVICE_INFO_CONTAINER_PARTITION, DEVICE_INFO_CONTAINER_PARTITION_MSDOS, "MSDOS partition information"); return 0; } +enum +{ + EXT23_OFFSET = 1024, + EXT23_SB_SIZE = 512, + EXT23_BLOCK_SIZE_BITS = 10, + EXT23_BLOCK_SIZE = (1 << EXT23_BLOCK_SIZE_BITS), + EXT23_SUPER_MAGIC = 0xEF53, + EXT23_FEATURE_COMPAT_HAS_JOURNAL = 0x4, +}; +struct ext23_superblock +{ + uint32_t _r1[6]; /**< 0x00 - 0x14 */ + uint32_t s_log_block_size; /**< 0x18 */ + uint32_t _r2[7]; /**< 0x1c - 0x34 */ + uint16_t s_magic; /**< 0x38 */ + uint16_t s_state; /**< 0x3a */ + uint32_t _r3[8]; /**< 0x3c - 0x58 */ + uint32_t s_feature_compat; /**< 0x5c */ + uint32_t s_feature_incompat; /**< 0x60 */ + uint32_t s_feature_ro_compat; /**< 0x64 */ + uint8_t s_uuid[16]; /**< 0x68 - 0x77 */ +}; + /** * check_for_ext23 - check to see if EXT23 is on this device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * An EINVAL returned from lseek means that the device was too - * small -- at least on Linux. - * - * Returns: -1 on error (with errno set), 1 if not EXT23, - * 0 if EXT23 found (with type set) */ -static int check_for_ext23(int fd, char *type, unsigned type_len) +static check check_for_ext23; +static int check_for_ext23(const void *mem, size_t len, struct device_info *info) { - unsigned char buf[512]; - uint16 *p = (uint16 *)buf; - int error; + const struct ext23_superblock *p = (const struct ext23_superblock *)((const unsigned char *)mem + EXT23_OFFSET); - error = lseek(fd, 1024, SEEK_SET); - if (error < 0) - return (errno == EINVAL) ? 1 : error; - else if (error != 1024) - { - errno = EINVAL; - return -1; - } + if (len < EXT23_OFFSET + EXT23_SB_SIZE) + return 1; - error = read(fd, buf, 512); - if (error < 0) - return error; - else if (error < 58) + if (osi_le16_to_cpu(p->s_magic) != EXT23_SUPER_MAGIC) return 1; - if (osi_le16_to_cpu(p[28]) != 0xEF53) + info->block_size = (EXT23_BLOCK_SIZE << osi_le32_to_cpu(p->s_log_block_size)); + + if (osi_le16_to_cpu(p->s_feature_compat) & EXT23_FEATURE_COMPAT_HAS_JOURNAL) + info_set_filesystem(info, DEVICE_INFO_FILESYSTEM_EXT23, DEVICE_INFO_FILESYSTEM_EXT3, "EXT3 filesystem"); + else + info_set_filesystem(info, DEVICE_INFO_FILESYSTEM_EXT23, DEVICE_INFO_FILESYSTEM_EXT2, "EXT2 filesystem"); + + return 0; +} + + +enum +{ + XFS_SB_SIZE = 512, + XFS_SB_MAGIC = 0x58465342, +}; + +struct xfs_superblock +{ + uint32_t sb_magicnum; + uint32_t sb_blocksize; + uint64_t sb_dblocks; + uint64_t sb_rblocks; + uint64_t sb_rextents; + uint8_t sb_uuid[16]; +}; + +/** + * check_for_xfs - check to see if XFS is on this device + */ + +static check check_for_xfs; +static int check_for_xfs(const void *mem, size_t len, struct device_info *info) +{ + const struct xfs_superblock *p = mem; + + if (len < XFS_SB_SIZE) return 1; - snprintf(type, type_len, "EXT2/3 filesystem"); + if (osi_be32_to_cpu(p->sb_magicnum) != XFS_SB_MAGIC) + return 1; + info->block_size = osi_be32_to_cpu(p->sb_blocksize); + + info_set_filesystem(info, DEVICE_INFO_FILESYSTEM_XFS, 0, "XFS filesystem"); + return 0; } /** * check_for_swap - check to see if SWAP is on this device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * Returns: -1 on error (with errno set), 1 if not SWAP, - * 0 if SWAP found (with type set) */ -static int check_for_swap(int fd, char *type, unsigned type_len) +static check check_for_swap; +static int check_for_swap(const void *mem, size_t len, struct device_info *info) { - unsigned char buf[8192]; - int error; + const unsigned char *buf = mem; - error = lseek(fd, 0, SEEK_SET); - if (error < 0) - return error; - else if (error != 0) - { - errno = EINVAL; - return -1; - } - - error = read(fd, buf, 8192); - if (error < 0) - return error; - else if (error < 4096) + if (len < 8192) return 1; if (memcmp(buf + 4086, "SWAP-SPACE", 10) && memcmp(buf + 4086, "SWAPSPACE2", 10)) return 1; - snprintf(type, type_len, "swap device"); + info_set(info, DEVICE_INFO_SWAP, 0, 0, "swap device"); return 0; } +enum +{ + LVM1_SB_SIZE = 512, +}; + /** * check_for_lvm1 - check to see if LVM1 is on this device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * Returns: -1 on error (with errno set), 1 if not LVM1, - * 0 if LVM1 found (with type set) */ -static int check_for_lvm1(int fd, char *type, unsigned type_len) +static check check_for_lvm1; +static int check_for_lvm1(const void *mem, size_t len, struct device_info *info) { - unsigned char buf[512]; - int error; + const unsigned char *buf = mem; - error = lseek(fd, 0, SEEK_SET); - if (error < 0) - return error; - else if (error != 0) - { - errno = EINVAL; - return -1; - } - - error = read(fd, buf, 512); - if (error < 0) - return error; - else if (error < 2) + if (len < LVM1_SB_SIZE) return 1; if (buf[0] != 'H' || buf[1] != 'M') return 1; - snprintf(type, type_len, "lvm1 subdevice"); + info_set_container(info, DEVICE_INFO_CONTAINER_LVM1, 0, "LVM1 subdevice"); return 0; } @@ -274,39 +267,22 @@ /** * check_for_lvm2 - check to see if LVM2 is on this device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * Returns: -1 on error (with errno set), 1 if not LVM2, - * 0 if LVM1 found (with type set) */ -static int check_for_lvm2(int fd, char *type, unsigned type_len) +static check check_for_lvm2; +static int check_for_lvm2(const void *mem, size_t len, struct device_info *info) { - unsigned char buf[512]; - int error; int i; + if (len < 6 * 512) + return 1; + /* LVM 2 labels can start in sectors 1-4 */ for (i = 1; i < 5; i++) { - error = lseek(fd, 512 * i, SEEK_SET); - if (error < 0) - return (errno == EINVAL) ? 1 : error; - else if (error != 512 * i) - { - errno = EINVAL; - return -1; - } + const unsigned char *buf = (const unsigned char *)mem + 512 * i; - error = read(fd, buf, 512); - if (error < 0) - return error; - else if (error < 32) - return 1; - if (strncmp(buf, "LABELONE", 8) != 0) continue; if (((uint64_t *)buf)[1] != i) @@ -315,7 +291,7 @@ if (strncmp(&buf[24], "LVM2 001", 8) != 0) continue; - snprintf(type, type_len, "lvm2 subdevice"); + info_set_container(info, DEVICE_INFO_CONTAINER_LVM2, 0, "LVM2 subdevice"); return 0; } @@ -324,127 +300,85 @@ } +enum +{ + CIDEV_SB_SIZE = 512, +}; + /** * check_for_cidev - check to see if CIDEV is on this device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * Returns: -1 on error (with errno set), 1 if not CIDEV, - * 0 if CIDEV found (with type set) */ -static int check_for_cidev(int fd, char *type, unsigned type_len) +static check check_for_cidev; +static int check_for_cidev(const void *mem, size_t len, struct device_info *info) { - unsigned char buf[512]; - uint32 *p = (uint32 *)buf; - int error; + const uint32_t *p = mem; - error = lseek(fd, 0, SEEK_SET); - if (error < 0) - return error; - else if (error != 0) - { - errno = EINVAL; - return -1; - } - - error = read(fd, buf, 512); - if (error < 0) - return error; - else if (error < 4) + if (len < CIDEV_SB_SIZE) return 1; if (osi_be32_to_cpu(*p) != 0x47465341) return 1; - snprintf(type, type_len, "CIDEV"); + info_set_container(info, DEVICE_INFO_CONTAINER_CIDEV, 0, "CIDEV"); return 0; } +enum +{ + CCA_SB_SIZE = 512, +}; + /** * check_for_cca - check to see if CCA is on this device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * Returns: -1 on error (with errno set), 1 if not CCA, - * 0 if CCA found (with type set) */ -static int check_for_cca(int fd, char *type, unsigned type_len) +static check check_for_cca; +static int check_for_cca(const void *mem, size_t len, struct device_info *info) { - unsigned char buf[512]; - uint32 *p = (uint32 *)buf; - int error; + const uint32_t *p = mem; - error = lseek(fd, 0, SEEK_SET); - if (error < 0) - return error; - else if (error != 0) - { - errno = EINVAL; - return -1; - } - - error = read(fd, buf, 512); - if (error < 0) - return error; - else if (error < 4) + if (len < CCA_SB_SIZE) return 1; if (osi_be32_to_cpu(*p) != 0x122473) return 1; - snprintf(type, type_len, "CCA device"); + info_set_container(info, DEVICE_INFO_CONTAINER_CCA, 0, "CCA device"); return 0; } +enum +{ + REISERFS_SB_SIZE = 65 * 1024, +}; + /** * check_for_reiserfs - check to see if reisterfs is on this device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * Returns: -1 on error (with errno set), 1 if not reiserfs, - * 0 if CCA found (with type set) */ -static int check_for_reiserfs(int fd, char *type, unsigned type_len) +static check check_for_reiserfs; +static int check_for_reiserfs(const void *mem, size_t len, struct device_info *info) { - unsigned int pass; - uint64 offset; - unsigned char buf[512]; - int error; + int pass; + if (len < REISERFS_SB_SIZE) + return 1; + for (pass = 0; pass < 2; pass++) { - offset = (pass) ? 65536 : 8192; + unsigned int offset = (pass) ? 65536 : 8192; + const unsigned char *p = (const unsigned char *)mem + offset; - error = lseek(fd, offset, SEEK_SET); - if (error < 0) - return (errno == EINVAL) ? 1 : error; - else if (error != offset) + if (strncmp(p + 52, "ReIsErFs", 8) == 0 || + strncmp(p + 52, "ReIsEr2Fs", 9) == 0 || + strncmp(p + 52, "ReIsEr3Fs", 9) == 0) { - errno = EINVAL; - return -1; - } - - error = read(fd, buf, 512); - if (error < 0) - return error; - else if (error < 62) - return 1; - - if (strncmp(buf + 52, "ReIsErFs", 8) == 0 || - strncmp(buf + 52, "ReIsEr2Fs", 9) == 0 || - strncmp(buf + 52, "ReIsEr3Fs", 9) == 0) - { - snprintf(type, type_len, "Reiserfs filesystem"); + info_set_filesystem(info, DEVICE_INFO_FILESYSTEM_REISERFS, 0, "ReiserFS filesystem"); return 0; } } @@ -453,69 +387,49 @@ } -/** - * identify_device - figure out what's on a device - * @fd: a file descriptor open on a device open for (at least) reading - * @type: a buffer that contains the type of filesystem - * @type_len: the amount of space pointed to by @type - * - * The offset of @fd will be changed by this function. - * This routine will not write to the device. - * - * Returns: -1 on error (with errno set), 1 if unabled to identify, - * 0 if device identified (with type set) - */ +static check *checks[] = +{ + check_for_partition_msdos, + check_for_pool, + check_for_lvm1, + check_for_lvm2, + check_for_cidev, + check_for_cca, + check_for_ext23, + check_for_gfs, + check_for_reiserfs, + check_for_xfs, + check_for_swap, +}; -int identify_device(int fd, char *type, unsigned type_len) +int identify_device(int fd, struct device_info *info) { - int error; + int i; + const void *mem; + size_t len; - if (!type || !type_len) + if (!info) { errno = EINVAL; return -1; } - error = check_for_pool(fd, type, type_len); - if (error <= 0) - return error; + memset(info, sizeof (struct device_info), 0); - error = check_for_lvm1(fd, type, type_len); - if (error <= 0) - return error; + if (device_size(fd, &info->device_size) < 0) + return -1; - error = check_for_lvm2(fd, type, type_len); - if(error <= 0) - return error; + len = info->device_size <= 256*1024 ? info->device_size : 256*1024; - error = check_for_cidev(fd, type, type_len); - if (error <= 0) - return error; + mem = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); - error = check_for_cca(fd, type, type_len); - if (error <= 0) - return error; + for (i = 0; i < sizeof (checks) / sizeof (*checks); ++i) + { + int error = checks[i](mem, len, info); + if (error <= 0) + return error; + } - error = check_for_gfs(fd, type, type_len); - if (error <= 0) - return error; - - error = check_for_ext23(fd, type, type_len); - if (error <= 0) - return error; - - error = check_for_reiserfs(fd, type, type_len); - if (error <= 0) - return error; - - error = check_for_swap(fd, type, type_len); - if (error <= 0) - return error; - - error = check_for_partition(fd, type, type_len); - if (error <= 0) - return error; - return 1; }
Attachment:
signature.asc
Description: Digital signature