[Linux-cluster] [PATCH] iddev - convert to general purpose device identifier

Bastian Blank bastian at waldi.eu.org
Fri Apr 1 14:20:31 UTC 2005


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
-------------- next part --------------
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;
 }
 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 197 bytes
Desc: Digital signature
URL: <http://listman.redhat.com/archives/linux-cluster/attachments/20050401/da52aee0/attachment.sig>


More information about the Linux-cluster mailing list