Hi folks iddev currently only returns a human readable string of the device content. This makes it rather unusable in contexts where you need to have to do decitions on the content. Changes: - Add three enums which describe the content. - identify_device get a struct which contains the enums and the human readable text. - Get the block size. The struct also contains a field for the uuid, but it is not set yet. - Add xfs support. - Make the ext2/3 check differ between ext2 and ext3. I currently try to do some cleanups in lvm2/fsadm. This tool currently relies on an entry in /etc/fstab to get the filesystem type and a temporary mount to get the block size. With this changes I can just use iddev to gather the informations. Bastian -- Conquest is easy. Control is not. -- Kirk, "Mirror, Mirror", stardate unknown
Index: lib/iddev.h =================================================================== --- lib/iddev.h (revision 413) +++ lib/iddev.h (working copy) @@ -16,19 +16,64 @@ /** + * 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]; + size_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); /** Index: lib/identify_device.c =================================================================== --- lib/identify_device.c (revision 413) +++ lib/identify_device.c (working copy) @@ -50,7 +50,7 @@ int main(int argc, char *argv[]) { int fd; - char buf[BUFSIZE]; + struct device_info info; uint64 bytes; int error; @@ -63,18 +63,18 @@ 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"); + strcpy(info.display, "unknown"); 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:", info.display, " bytes:", bytes); close(fd); Index: lib/iddev.c =================================================================== --- lib/iddev.c (revision 413) +++ lib/iddev.c (working copy) @@ -25,24 +25,37 @@ #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(int fd, 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) +static check check_for_gfs; +static int check_for_gfs(int fd, struct device_info *info) { unsigned char buf[512]; uint32 *p = (uint32 *)buf; @@ -66,7 +79,7 @@ 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,15 +87,10 @@ /** * 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) +static check check_for_pool; +static int check_for_pool(int fd, struct device_info *info) { unsigned char buf[512]; uint64 *p = (uint64 *)buf; @@ -106,23 +114,18 @@ 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_msdos - check to see if Partition is on this device */ -static int check_for_partition(int fd, char *type, unsigned type_len) +static check check_for_partition_msdos; +static int check_for_partition_msdos(int fd, struct device_info *info) { unsigned char buf[512]; int error; @@ -145,29 +148,42 @@ 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 +{ + BLOCK_SIZE_BITS = 10, + BLOCK_SIZE = (1 << BLOCK_SIZE_BITS), + EXT3_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(int fd, struct device_info *info) { unsigned char buf[512]; - uint16 *p = (uint16 *)buf; + struct ext23_superblock *p = (struct ext23_superblock *)buf; int error; error = lseek(fd, 1024, SEEK_SET); @@ -185,26 +201,78 @@ else if (error < 58) return 1; - if (osi_le16_to_cpu(p[28]) != 0xEF53) + if (osi_le16_to_cpu(p->s_magic) != EXT3_SUPER_MAGIC) return 1; - snprintf(type, type_len, "EXT2/3 filesystem"); + info->block_size = (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_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(int fd, struct device_info *info) +{ + unsigned char buf[512]; + struct xfs_superblock *p = (struct xfs_superblock *)buf; + int error; + + error = lseek(fd, 0, SEEK_SET); + if (error < 0) + return (errno == EINVAL) ? 1 : error; + else if (error != 0) + { + errno = EINVAL; + return -1; + } + + error = read(fd, buf, 512); + if (error < 0) + return error; + else if (error < 58) + return 1; + + 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(int fd, struct device_info *info) { unsigned char buf[8192]; int error; @@ -227,7 +295,7 @@ 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; } @@ -235,15 +303,10 @@ /** * 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(int fd, struct device_info *info) { unsigned char buf[512]; int error; @@ -266,7 +329,7 @@ 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,15 +337,10 @@ /** * 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(int fd, struct device_info *info) { unsigned char buf[512]; int error; @@ -315,7 +373,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, "LVM1 subdevice"); return 0; } @@ -326,15 +384,10 @@ /** * 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(int fd, struct device_info *info) { unsigned char buf[512]; uint32 *p = (uint32 *)buf; @@ -358,7 +411,7 @@ 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; } @@ -366,15 +419,10 @@ /** * 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(int fd, struct device_info *info) { unsigned char buf[512]; uint32 *p = (uint32 *)buf; @@ -398,7 +446,7 @@ 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; } @@ -406,15 +454,10 @@ /** * 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(int fd, struct device_info *info) { unsigned int pass; uint64 offset; @@ -444,7 +487,7 @@ 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 +496,40 @@ } -/** - * 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; - 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; + for (i = 0; i < sizeof (checks) / sizeof (*checks); ++i) + { + int error = checks[i](fd, info); + if (error <= 0) + return error; + } - error = check_for_lvm2(fd, type, type_len); - if(error <= 0) - return error; - - error = check_for_cidev(fd, type, type_len); - if (error <= 0) - return error; - - error = check_for_cca(fd, type, type_len); - 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