New API: is-lv: check if a block device is a logical volume (RHBZ#619793)
authorRichard Jones <rjones@redhat.com>
Fri, 30 Jul 2010 15:32:35 +0000 (16:32 +0100)
committerRichard Jones <rjones@redhat.com>
Fri, 30 Jul 2010 15:32:35 +0000 (16:32 +0100)
This adds a new API, guestfs_is_lv (g, device), which returns true iff
the named device is an LVM2 logical volume.

A sample guestfish session:

><fs> lvs
/dev/vg_f13x64/lv_root
/dev/vg_f13x64/lv_swap
><fs> list-devices
/dev/vda
><fs> list-partitions
/dev/vda1
/dev/vda2
><fs> is-lv /dev/vg_f13x64/lv_root
true
><fs> is-lv /dev/vg_f13x64/lv_swap
true
><fs> is-lv /dev/vda
false
><fs> is-lv /dev/vda1
false
><fs> is-lv /dev/vda2
false

daemon/lvm.c
src/MAX_PROC_NR
src/generator.ml

index 70c3c90..0df27e2 100644 (file)
@@ -23,6 +23,7 @@
 #include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
 #include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/stat.h>
 
 #include "daemon.h"
 #include "c-ctype.h"
 
 #include "daemon.h"
 #include "c-ctype.h"
@@ -662,3 +663,49 @@ do_vgscan (void)
   free (err);
   return 0;
 }
   free (err);
   return 0;
 }
+
+/* Test if a device is a logical volume (RHBZ#619793).
+ *
+ * This is harder than it should be.  A LV device like /dev/VG/LV is
+ * really a symlink to a device-mapper device like /dev/dm-0.  However
+ * at the device-mapper (kernel) level, nothing is really known about
+ * LVM (a userspace concept).  Therefore we use a convoluted method to
+ * determine this, by listing out known LVs and checking whether the
+ * rdev (major/minor) of the device we are passed matches any of them.
+ *
+ * Note use of 'stat' instead of 'lstat' so that symlinks are fully
+ * resolved.
+ */
+int
+do_is_lv (const char *device)
+{
+  struct stat stat1, stat2;
+
+  int r = stat (device, &stat1);
+  if (r == -1) {
+    reply_with_perror ("stat: %s", device);
+    return -1;
+  }
+
+  char **lvs = do_lvs ();
+  if (lvs == NULL)
+    return -1;
+
+  size_t i;
+  for (i = 0; lvs[i] != NULL; ++i) {
+    r = stat (lvs[i], &stat2);
+    if (r == -1) {
+      reply_with_perror ("stat: %s", lvs[i]);
+      free_strings (lvs);
+      return -1;
+    }
+    if (stat1.st_rdev == stat2.st_rdev) { /* found it */
+      free_strings (lvs);
+      return 1;
+    }
+  }
+
+  /* not found */
+  free_strings (lvs);
+  return 0;
+}
index 175b6c5..10b0c0d 100644 (file)
@@ -1 +1 @@
-263
+264
index d537945..20f7ac0 100755 (executable)
@@ -4953,6 +4953,16 @@ This command deletes the key in key slot C<keyslot> from the
 encrypted LUKS device C<device>.  C<key> must be one of the
 I<other> keys.");
 
 encrypted LUKS device C<device>.  C<key> must be one of the
 I<other> keys.");
 
+  ("is_lv", (RBool "lvflag", [Device "device"]), 264, [Optional "lvm2"],
+   [InitBasicFSonLVM, IfAvailable "lvm2", TestOutputTrue (
+      [["is_lv"; "/dev/VG/LV"]]);
+    InitBasicFSonLVM, IfAvailable "lvm2", TestOutputFalse (
+      [["is_lv"; "/dev/sda1"]])],
+   "test if device is a logical volume",
+   "\
+This command tests whether C<device> is a logical volume, and
+returns true iff this is the case.");
+
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions