Implement simple lvs/vgs/pvs commands.
authorRichard Jones <rjones@redhat.com>
Tue, 7 Apr 2009 09:25:46 +0000 (10:25 +0100)
committerRichard Jones <rjones@redhat.com>
Tue, 7 Apr 2009 09:25:46 +0000 (10:25 +0100)
daemon/actions.h
daemon/lvm.c
daemon/stubs.c
fish/cmds.c
guestfs-actions.pod
src/generator.ml
src/guestfs-actions.c
src/guestfs-actions.h
src/guestfs_protocol.c
src/guestfs_protocol.h
src/guestfs_protocol.x

index 194986f..02fe55e 100644 (file)
@@ -29,6 +29,9 @@ extern char *do_ll (const char *directory);
 extern char **do_ls (const char *directory);
 extern char **do_list_devices ();
 extern char **do_list_partitions ();
+extern char **do_pvs ();
+extern char **do_vgs ();
+extern char **do_lvs ();
 extern guestfs_lvm_int_pv_list *do_pvs_full ();
 extern guestfs_lvm_int_vg_list *do_vgs_full ();
 extern guestfs_lvm_int_lv_list *do_lvs_full ();
index 43f5cd1..bc38547 100644 (file)
  * of writing it hasn't progressed very far.
  */
 
+static char **
+convert_lvm_output (char *out, char *prefix)
+{
+  char *p, *pend;
+  char **r = NULL;
+  int size = 0, alloc = 0;
+  char buf[256];
+  char *str;
+
+  p = out;
+  while (p) {
+    pend = strchr (p, '\n');   /* Get the next line of output. */
+    if (pend) {
+      *pend = '\0';
+      pend++;
+    }
+
+    while (*p && isspace (*p)) /* Skip any leading whitespace. */
+      p++;
+
+    if (!*p) {                 /* Empty line?  Skip it. */
+      p = pend;
+      continue;
+    }
+
+    /* Prefix? */
+    if (prefix) {
+      snprintf (buf, sizeof buf, "%s%s", prefix, p);
+      str = buf;
+    } else
+      str = p;
+
+    if (add_string (&r, &size, &alloc, str) == -1) {
+      free (out);
+      return NULL;
+    }
+
+    p = pend;
+  }
+
+  free (out);
+
+  if (add_string (&r, &size, &alloc, NULL) == -1)
+    return NULL;
+
+  sort_strings (r, size-1);
+  return r;
+}
+
+char **
+do_pvs (void)
+{
+  char *out, *err;
+  int r;
+
+  r = command (&out, &err,
+              "/sbin/lvm", "pvs", "-o", "pv_name", "--noheadings", NULL);
+  if (r == -1) {
+    reply_with_error ("%s", err);
+    free (out);
+    free (err);
+    return NULL;
+  }
+
+  free (err);
+
+  return convert_lvm_output (out, NULL);
+}
+
+char **
+do_vgs (void)
+{
+  char *out, *err;
+  int r;
+
+  r = command (&out, &err,
+              "/sbin/lvm", "vgs", "-o", "vg_name", "--noheadings", NULL);
+  if (r == -1) {
+    reply_with_error ("%s", err);
+    free (out);
+    free (err);
+    return NULL;
+  }
+
+  free (err);
+
+  return convert_lvm_output (out, NULL);
+}
+
+char **
+do_lvs (void)
+{
+  char *out, *err;
+  int r;
+
+  r = command (&out, &err,
+              "/sbin/lvm", "lvs",
+              "-o", "vg_name,lv_name", "--noheadings",
+              "--separator", "/", NULL);
+  if (r == -1) {
+    reply_with_error ("%s", err);
+    free (out);
+    free (err);
+    return NULL;
+  }
+
+  free (err);
+
+  return convert_lvm_output (out, "/dev/");
+}
+
+/* These were so complex to implement that I ended up auto-generating
+ * the code.  That code is in stubs.c, and it is generated as usual
+ * by generator.ml.
+ */
 guestfs_lvm_int_pv_list *
 do_pvs_full (void)
 {
index 63ca770..06a8600 100644 (file)
@@ -199,6 +199,54 @@ static void list_partitions_stub (XDR *xdr_in)
   free_strings (r);
 }
 
+static void pvs_stub (XDR *xdr_in)
+{
+  char **r;
+
+  r = do_pvs ();
+  if (r == NULL)
+    /* do_pvs has already called reply_with_error, so just return */
+    return;
+
+  struct guestfs_pvs_ret ret;
+  ret.physvols.physvols_len = count_strings (r);
+  ret.physvols.physvols_val = r;
+  reply ((xdrproc_t) &xdr_guestfs_pvs_ret, (char *) &ret);
+  free_strings (r);
+}
+
+static void vgs_stub (XDR *xdr_in)
+{
+  char **r;
+
+  r = do_vgs ();
+  if (r == NULL)
+    /* do_vgs has already called reply_with_error, so just return */
+    return;
+
+  struct guestfs_vgs_ret ret;
+  ret.volgroups.volgroups_len = count_strings (r);
+  ret.volgroups.volgroups_val = r;
+  reply ((xdrproc_t) &xdr_guestfs_vgs_ret, (char *) &ret);
+  free_strings (r);
+}
+
+static void lvs_stub (XDR *xdr_in)
+{
+  char **r;
+
+  r = do_lvs ();
+  if (r == NULL)
+    /* do_lvs has already called reply_with_error, so just return */
+    return;
+
+  struct guestfs_lvs_ret ret;
+  ret.logvols.logvols_len = count_strings (r);
+  ret.logvols.logvols_val = r;
+  reply ((xdrproc_t) &xdr_guestfs_lvs_ret, (char *) &ret);
+  free_strings (r);
+}
+
 static void pvs_full_stub (XDR *xdr_in)
 {
   guestfs_lvm_int_pv_list *r;
@@ -271,6 +319,15 @@ void dispatch_incoming_message (XDR *xdr_in)
     case GUESTFS_PROC_LIST_PARTITIONS:
       list_partitions_stub (xdr_in);
       break;
+    case GUESTFS_PROC_PVS:
+      pvs_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_VGS:
+      vgs_stub (xdr_in);
+      break;
+    case GUESTFS_PROC_LVS:
+      lvs_stub (xdr_in);
+      break;
     case GUESTFS_PROC_PVS_FULL:
       pvs_full_stub (xdr_in);
       break;
index dc951e3..1035b67 100644 (file)
@@ -36,11 +36,14 @@ void list_commands (void)
   printf ("%-20s %s\n", "list-partitions", "list the partitions");
   printf ("%-20s %s\n", "ll", "list the files in a directory (long format)");
   printf ("%-20s %s\n", "ls", "list the files in a directory");
+  printf ("%-20s %s\n", "lvs", "list the LVM logical volumes (LVs)");
   printf ("%-20s %s\n", "lvs-full", "list the LVM logical volumes (LVs)");
   printf ("%-20s %s\n", "mount", "mount a guest disk at a position in the filesystem");
+  printf ("%-20s %s\n", "pvs", "list the LVM physical volumes (PVs)");
   printf ("%-20s %s\n", "pvs-full", "list the LVM physical volumes (PVs)");
   printf ("%-20s %s\n", "sync", "sync disks, writes are flushed through to the disk image");
   printf ("%-20s %s\n", "touch", "update file timestamps or create a new file");
+  printf ("%-20s %s\n", "vgs", "list the LVM volume groups (VGs)");
   printf ("%-20s %s\n", "vgs-full", "list the LVM volume groups (VGs)");
   printf ("    Use -h <cmd> / help <cmd> to show detailed help for a command.\n");
 }
@@ -71,14 +74,23 @@ void display_command (const char *cmd)
   if (strcasecmp (cmd, "list_partitions") == 0 || strcasecmp (cmd, "list-partitions") == 0)
     pod2text ("list-partitions - list the partitions", " list-partitions\n\nList all the partitions detected on all block devices.\n\nThe full partition device names are returned, eg. C</dev/sda1>\n\nThis does not return logical volumes.  For that you will need to\ncall C<guestfs_lvs>.");
   else
+  if (strcasecmp (cmd, "pvs") == 0)
+    pod2text ("pvs - list the LVM physical volumes (PVs)", " pvs\n\nList all the physical volumes detected.  This is the equivalent\nof the L<pvs(8)> command.\n\nThis returns a list of just the device names that contain\nPVs (eg. C</dev/sda2>).\n\nSee also C<guestfs_pvs_full>.");
+  else
+  if (strcasecmp (cmd, "vgs") == 0)
+    pod2text ("vgs - list the LVM volume groups (VGs)", " vgs\n\nList all the volumes groups detected.  This is the equivalent\nof the L<vgs(8)> command.\n\nThis returns a list of just the volume group names that were\ndetected (eg. C<VolGroup00>).\n\nSee also C<guestfs_vgs_full>.");
+  else
+  if (strcasecmp (cmd, "lvs") == 0)
+    pod2text ("lvs - list the LVM logical volumes (LVs)", " lvs\n\nList all the logical volumes detected.  This is the equivalent\nof the L<lvs(8)> command.\n\nThis returns a list of the logical volume device names\n(eg. C</dev/VolGroup00/LogVol00>).\n\nSee also C<guestfs_lvs_full>.");
+  else
   if (strcasecmp (cmd, "pvs_full") == 0 || strcasecmp (cmd, "pvs-full") == 0)
-    pod2text ("pvs-full - list the LVM physical volumes (PVs)", " pvs-full\n\nList all the physical volumes detected.  This is the equivalent\nof the L<pvs(8)> command.");
+    pod2text ("pvs-full - list the LVM physical volumes (PVs)", " pvs-full\n\nList all the physical volumes detected.  This is the equivalent\nof the L<pvs(8)> command.  The \"full\" version includes all fields.");
   else
   if (strcasecmp (cmd, "vgs_full") == 0 || strcasecmp (cmd, "vgs-full") == 0)
-    pod2text ("vgs-full - list the LVM volume groups (VGs)", " vgs-full\n\nList all the volumes groups detected.  This is the equivalent\nof the L<vgs(8)> command.");
+    pod2text ("vgs-full - list the LVM volume groups (VGs)", " vgs-full\n\nList all the volumes groups detected.  This is the equivalent\nof the L<vgs(8)> command.  The \"full\" version includes all fields.");
   else
   if (strcasecmp (cmd, "lvs_full") == 0 || strcasecmp (cmd, "lvs-full") == 0)
-    pod2text ("lvs-full - list the LVM logical volumes (LVs)", " lvs-full\n\nList all the logical volumes detected.  This is the equivalent\nof the L<lvs(8)> command.");
+    pod2text ("lvs-full - list the LVM logical volumes (LVs)", " lvs-full\n\nList all the logical volumes detected.  This is the equivalent\nof the L<lvs(8)> command.  The \"full\" version includes all fields.");
   else
     display_builtin_command (cmd);
 }
@@ -308,6 +320,51 @@ static int run_list_partitions (const char *cmd, int argc, char *argv[])
   return 0;
 }
 
+static int run_pvs (const char *cmd, int argc, char *argv[])
+{
+  char **r;
+  if (argc != 0) {
+    fprintf (stderr, "%s should have 0 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  r = guestfs_pvs (g);
+  if (r == NULL) return -1;
+  print_strings (r);
+  free_strings (r);
+  return 0;
+}
+
+static int run_vgs (const char *cmd, int argc, char *argv[])
+{
+  char **r;
+  if (argc != 0) {
+    fprintf (stderr, "%s should have 0 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  r = guestfs_vgs (g);
+  if (r == NULL) return -1;
+  print_strings (r);
+  free_strings (r);
+  return 0;
+}
+
+static int run_lvs (const char *cmd, int argc, char *argv[])
+{
+  char **r;
+  if (argc != 0) {
+    fprintf (stderr, "%s should have 0 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  r = guestfs_lvs (g);
+  if (r == NULL) return -1;
+  print_strings (r);
+  free_strings (r);
+  return 0;
+}
+
 static int run_pvs_full (const char *cmd, int argc, char *argv[])
 {
   struct guestfs_lvm_pv_list *r;
@@ -379,6 +436,15 @@ int run_action (const char *cmd, int argc, char *argv[])
   if (strcasecmp (cmd, "list_partitions") == 0 || strcasecmp (cmd, "list-partitions") == 0)
     return run_list_partitions (cmd, argc, argv);
   else
+  if (strcasecmp (cmd, "pvs") == 0)
+    return run_pvs (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "vgs") == 0)
+    return run_vgs (cmd, argc, argv);
+  else
+  if (strcasecmp (cmd, "lvs") == 0)
+    return run_lvs (cmd, argc, argv);
+  else
   if (strcasecmp (cmd, "pvs_full") == 0 || strcasecmp (cmd, "pvs-full") == 0)
     return run_pvs_full (cmd, argc, argv);
   else
index 1a57ae2..eb3898a 100644 (file)
@@ -75,12 +75,28 @@ This function returns a NULL-terminated array of strings
 (like L<environ(3)>), or NULL if there was an error.
 I<The caller must free the strings and the array after use>.
 
+=head2 guestfs_lvs
+
+ char **guestfs_lvs (guestfs_h *handle);
+
+List all the logical volumes detected.  This is the equivalent
+of the L<lvs(8)> command.
+
+This returns a list of the logical volume device names
+(eg. C</dev/VolGroup00/LogVol00>).
+
+See also C<guestfs_lvs_full>.
+
+This function returns a NULL-terminated array of strings
+(like L<environ(3)>), or NULL if there was an error.
+I<The caller must free the strings and the array after use>.
+
 =head2 guestfs_lvs_full
 
  struct guestfs_lvm_lv_list *guestfs_lvs_full (guestfs_h *handle);
 
 List all the logical volumes detected.  This is the equivalent
-of the L<lvs(8)> command.
+of the L<lvs(8)> command.  The "full" version includes all fields.
 
 This function returns a C<struct guestfs_lvm_lv_list>.
 I<The caller must call C<guestfs_free_lvm_lv_list> after use.>.
@@ -110,12 +126,28 @@ call, in order to improve reliability.
 
 This function returns 0 on success or -1 on error.
 
+=head2 guestfs_pvs
+
+ char **guestfs_pvs (guestfs_h *handle);
+
+List all the physical volumes detected.  This is the equivalent
+of the L<pvs(8)> command.
+
+This returns a list of just the device names that contain
+PVs (eg. C</dev/sda2>).
+
+See also C<guestfs_pvs_full>.
+
+This function returns a NULL-terminated array of strings
+(like L<environ(3)>), or NULL if there was an error.
+I<The caller must free the strings and the array after use>.
+
 =head2 guestfs_pvs_full
 
  struct guestfs_lvm_pv_list *guestfs_pvs_full (guestfs_h *handle);
 
 List all the physical volumes detected.  This is the equivalent
-of the L<pvs(8)> command.
+of the L<pvs(8)> command.  The "full" version includes all fields.
 
 This function returns a C<struct guestfs_lvm_pv_list>.
 I<The caller must call C<guestfs_free_lvm_pv_list> after use.>.
@@ -143,12 +175,28 @@ to create a new zero-length file.
 
 This function returns 0 on success or -1 on error.
 
+=head2 guestfs_vgs
+
+ char **guestfs_vgs (guestfs_h *handle);
+
+List all the volumes groups detected.  This is the equivalent
+of the L<vgs(8)> command.
+
+This returns a list of just the volume group names that were
+detected (eg. C<VolGroup00>).
+
+See also C<guestfs_vgs_full>.
+
+This function returns a NULL-terminated array of strings
+(like L<environ(3)>), or NULL if there was an error.
+I<The caller must free the strings and the array after use>.
+
 =head2 guestfs_vgs_full
 
  struct guestfs_lvm_vg_list *guestfs_vgs_full (guestfs_h *handle);
 
 List all the volumes groups detected.  This is the equivalent
-of the L<vgs(8)> command.
+of the L<vgs(8)> command.  The "full" version includes all fields.
 
 This function returns a C<struct guestfs_lvm_vg_list>.
 I<The caller must call C<guestfs_free_lvm_vg_list> after use.>.
index 69981f0..d598975 100755 (executable)
@@ -135,43 +135,56 @@ The full partition device names are returned, eg. C</dev/sda1>
 This does not return logical volumes.  For that you will need to
 call C<guestfs_lvs>.");
 
-(*
-  ("pvs", (RPVList "physvols", P0), 9, [],
+  ("pvs", (RStringList "physvols", P0), 9, [],
    "list the LVM physical volumes (PVs)",
    "\
 List all the physical volumes detected.  This is the equivalent
-of the L<pvs(8)> command.");
+of the L<pvs(8)> command.
 
-  ("vgs", (RVGList "volgroups", P0), 10, [],
+This returns a list of just the device names that contain
+PVs (eg. C</dev/sda2>).
+
+See also C<guestfs_pvs_full>.");
+
+  ("vgs", (RStringList "volgroups", P0), 10, [],
    "list the LVM volume groups (VGs)",
    "\
 List all the volumes groups detected.  This is the equivalent
-of the L<vgs(8)> command.");
+of the L<vgs(8)> command.
+
+This returns a list of just the volume group names that were
+detected (eg. C<VolGroup00>).
+
+See also C<guestfs_vgs_full>.");
 
-  ("lvs", (RLVList "logvols", P0), 11, [],
+  ("lvs", (RStringList "logvols", P0), 11, [],
    "list the LVM logical volumes (LVs)",
    "\
 List all the logical volumes detected.  This is the equivalent
-of the L<lvs(8)> command.");
-*)
+of the L<lvs(8)> command.
+
+This returns a list of the logical volume device names
+(eg. C</dev/VolGroup00/LogVol00>).
+
+See also C<guestfs_lvs_full>.");
 
   ("pvs_full", (RPVList "physvols", P0), 12, [],
    "list the LVM physical volumes (PVs)",
    "\
 List all the physical volumes detected.  This is the equivalent
-of the L<pvs(8)> command.");
+of the L<pvs(8)> command.  The \"full\" version includes all fields.");
 
   ("vgs_full", (RVGList "volgroups", P0), 13, [],
    "list the LVM volume groups (VGs)",
    "\
 List all the volumes groups detected.  This is the equivalent
-of the L<vgs(8)> command.");
+of the L<vgs(8)> command.  The \"full\" version includes all fields.");
 
   ("lvs_full", (RLVList "logvols", P0), 14, [],
    "list the LVM logical volumes (LVs)",
    "\
 List all the logical volumes detected.  This is the equivalent
-of the L<lvs(8)> command.");
+of the L<lvs(8)> command.  The \"full\" version includes all fields.");
 ]
 
 (* Column names and types from LVM PVs/VGs/LVs. *)
index e3598eb..3446a2d 100644 (file)
@@ -595,6 +595,225 @@ char **guestfs_list_partitions (guestfs_h *g)
   return rv.ret.partitions.partitions_val;
 }
 
+struct pvs_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_pvs_ret ret;
+};
+
+static void pvs_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct pvs_rv *rv = (struct pvs_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_pvs: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_pvs: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_pvs_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_pvs: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+char **guestfs_pvs (guestfs_h *g)
+{
+  struct pvs_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_pvs called from the wrong state, %d != READY",
+      g->state);
+    return NULL;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  serial = dispatch (g, GUESTFS_PROC_PVS, NULL, NULL);
+  if (serial == -1)
+    return NULL;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = pvs_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_pvs failed, see earlier error messages");
+    return NULL;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_PVS, serial) == -1)
+    return NULL;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return NULL;
+  }
+
+  /* caller will free this, but we need to add a NULL entry */
+  rv.ret.physvols.physvols_val = safe_realloc (g, rv.ret.physvols.physvols_val, rv.ret.physvols.physvols_len + 1);
+  rv.ret.physvols.physvols_val[rv.ret.physvols.physvols_len] = NULL;
+  return rv.ret.physvols.physvols_val;
+}
+
+struct vgs_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_vgs_ret ret;
+};
+
+static void vgs_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct vgs_rv *rv = (struct vgs_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_vgs: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_vgs: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_vgs_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_vgs: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+char **guestfs_vgs (guestfs_h *g)
+{
+  struct vgs_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_vgs called from the wrong state, %d != READY",
+      g->state);
+    return NULL;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  serial = dispatch (g, GUESTFS_PROC_VGS, NULL, NULL);
+  if (serial == -1)
+    return NULL;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = vgs_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_vgs failed, see earlier error messages");
+    return NULL;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_VGS, serial) == -1)
+    return NULL;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return NULL;
+  }
+
+  /* caller will free this, but we need to add a NULL entry */
+  rv.ret.volgroups.volgroups_val = safe_realloc (g, rv.ret.volgroups.volgroups_val, rv.ret.volgroups.volgroups_len + 1);
+  rv.ret.volgroups.volgroups_val[rv.ret.volgroups.volgroups_len] = NULL;
+  return rv.ret.volgroups.volgroups_val;
+}
+
+struct lvs_rv {
+  int cb_done;  /* flag to indicate callback was called */
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+  struct guestfs_lvs_ret ret;
+};
+
+static void lvs_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  struct lvs_rv *rv = (struct lvs_rv *) data;
+
+  if (!xdr_guestfs_message_header (xdr, &rv->hdr)) {
+    error (g, "guestfs_lvs: failed to parse reply header");
+    return;
+  }
+  if (rv->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &rv->err)) {
+      error (g, "guestfs_lvs: failed to parse reply error");
+      return;
+    }
+    goto done;
+  }
+  if (!xdr_guestfs_lvs_ret (xdr, &rv->ret)) {
+    error (g, "guestfs_lvs: failed to parse reply");
+    return;
+  }
+ done:
+  rv->cb_done = 1;
+  main_loop.main_loop_quit (g);
+}
+
+char **guestfs_lvs (guestfs_h *g)
+{
+  struct lvs_rv rv;
+  int serial;
+
+  if (g->state != READY) {
+    error (g, "guestfs_lvs called from the wrong state, %d != READY",
+      g->state);
+    return NULL;
+  }
+
+  memset (&rv, 0, sizeof rv);
+
+  serial = dispatch (g, GUESTFS_PROC_LVS, NULL, NULL);
+  if (serial == -1)
+    return NULL;
+
+  rv.cb_done = 0;
+  g->reply_cb_internal = lvs_cb;
+  g->reply_cb_internal_data = &rv;
+  main_loop.main_loop_run (g);
+  g->reply_cb_internal = NULL;
+  g->reply_cb_internal_data = NULL;
+  if (!rv.cb_done) {
+    error (g, "guestfs_lvs failed, see earlier error messages");
+    return NULL;
+  }
+
+  if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LVS, serial) == -1)
+    return NULL;
+
+  if (rv.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", rv.err.error);
+    return NULL;
+  }
+
+  /* caller will free this, but we need to add a NULL entry */
+  rv.ret.logvols.logvols_val = safe_realloc (g, rv.ret.logvols.logvols_val, rv.ret.logvols.logvols_len + 1);
+  rv.ret.logvols.logvols_val[rv.ret.logvols.logvols_len] = NULL;
+  return rv.ret.logvols.logvols_val;
+}
+
 struct pvs_full_rv {
   int cb_done;  /* flag to indicate callback was called */
   struct guestfs_message_header hdr;
index 8e73a5e..61eedd3 100644 (file)
@@ -27,6 +27,9 @@ extern char *guestfs_ll (guestfs_h *handle, const char *directory);
 extern char **guestfs_ls (guestfs_h *handle, const char *directory);
 extern char **guestfs_list_devices (guestfs_h *handle);
 extern char **guestfs_list_partitions (guestfs_h *handle);
+extern char **guestfs_pvs (guestfs_h *handle);
+extern char **guestfs_vgs (guestfs_h *handle);
+extern char **guestfs_lvs (guestfs_h *handle);
 extern struct guestfs_lvm_pv_list *guestfs_pvs_full (guestfs_h *handle);
 extern struct guestfs_lvm_vg_list *guestfs_vgs_full (guestfs_h *handle);
 extern struct guestfs_lvm_lv_list *guestfs_lvs_full (guestfs_h *handle);
index a19d7a1..2a194a7 100644 (file)
@@ -279,6 +279,39 @@ xdr_guestfs_list_partitions_ret (XDR *xdrs, guestfs_list_partitions_ret *objp)
 }
 
 bool_t
+xdr_guestfs_pvs_ret (XDR *xdrs, guestfs_pvs_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_array (xdrs, (char **)&objp->physvols.physvols_val, (u_int *) &objp->physvols.physvols_len, ~0,
+               sizeof (str), (xdrproc_t) xdr_str))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_vgs_ret (XDR *xdrs, guestfs_vgs_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_array (xdrs, (char **)&objp->volgroups.volgroups_val, (u_int *) &objp->volgroups.volgroups_len, ~0,
+               sizeof (str), (xdrproc_t) xdr_str))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+xdr_guestfs_lvs_ret (XDR *xdrs, guestfs_lvs_ret *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_array (xdrs, (char **)&objp->logvols.logvols_val, (u_int *) &objp->logvols.logvols_len, ~0,
+               sizeof (str), (xdrproc_t) xdr_str))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
 xdr_guestfs_pvs_full_ret (XDR *xdrs, guestfs_pvs_full_ret *objp)
 {
        register int32_t *buf;
index 55faa85..9a7187d 100644 (file)
@@ -152,6 +152,30 @@ struct guestfs_list_partitions_ret {
 };
 typedef struct guestfs_list_partitions_ret guestfs_list_partitions_ret;
 
+struct guestfs_pvs_ret {
+       struct {
+               u_int physvols_len;
+               str *physvols_val;
+       } physvols;
+};
+typedef struct guestfs_pvs_ret guestfs_pvs_ret;
+
+struct guestfs_vgs_ret {
+       struct {
+               u_int volgroups_len;
+               str *volgroups_val;
+       } volgroups;
+};
+typedef struct guestfs_vgs_ret guestfs_vgs_ret;
+
+struct guestfs_lvs_ret {
+       struct {
+               u_int logvols_len;
+               str *logvols_val;
+       } logvols;
+};
+typedef struct guestfs_lvs_ret guestfs_lvs_ret;
+
 struct guestfs_pvs_full_ret {
        guestfs_lvm_int_pv_list physvols;
 };
@@ -176,6 +200,9 @@ enum guestfs_procedure {
        GUESTFS_PROC_LS = 6,
        GUESTFS_PROC_LIST_DEVICES = 7,
        GUESTFS_PROC_LIST_PARTITIONS = 8,
+       GUESTFS_PROC_PVS = 9,
+       GUESTFS_PROC_VGS = 10,
+       GUESTFS_PROC_LVS = 11,
        GUESTFS_PROC_PVS_FULL = 12,
        GUESTFS_PROC_VGS_FULL = 13,
        GUESTFS_PROC_LVS_FULL = 14,
@@ -234,6 +261,9 @@ extern  bool_t xdr_guestfs_ls_args (XDR *, guestfs_ls_args*);
 extern  bool_t xdr_guestfs_ls_ret (XDR *, guestfs_ls_ret*);
 extern  bool_t xdr_guestfs_list_devices_ret (XDR *, guestfs_list_devices_ret*);
 extern  bool_t xdr_guestfs_list_partitions_ret (XDR *, guestfs_list_partitions_ret*);
+extern  bool_t xdr_guestfs_pvs_ret (XDR *, guestfs_pvs_ret*);
+extern  bool_t xdr_guestfs_vgs_ret (XDR *, guestfs_vgs_ret*);
+extern  bool_t xdr_guestfs_lvs_ret (XDR *, guestfs_lvs_ret*);
 extern  bool_t xdr_guestfs_pvs_full_ret (XDR *, guestfs_pvs_full_ret*);
 extern  bool_t xdr_guestfs_vgs_full_ret (XDR *, guestfs_vgs_full_ret*);
 extern  bool_t xdr_guestfs_lvs_full_ret (XDR *, guestfs_lvs_full_ret*);
@@ -261,6 +291,9 @@ extern bool_t xdr_guestfs_ls_args ();
 extern bool_t xdr_guestfs_ls_ret ();
 extern bool_t xdr_guestfs_list_devices_ret ();
 extern bool_t xdr_guestfs_list_partitions_ret ();
+extern bool_t xdr_guestfs_pvs_ret ();
+extern bool_t xdr_guestfs_vgs_ret ();
+extern bool_t xdr_guestfs_lvs_ret ();
 extern bool_t xdr_guestfs_pvs_full_ret ();
 extern bool_t xdr_guestfs_vgs_full_ret ();
 extern bool_t xdr_guestfs_lvs_full_ret ();
index 9bc556b..b2fe535 100644 (file)
@@ -142,6 +142,24 @@ struct guestfs_list_partitions_ret {
   str partitions<>;
 };
 
+/* guestfs_pvs */
+
+struct guestfs_pvs_ret {
+  str physvols<>;
+};
+
+/* guestfs_vgs */
+
+struct guestfs_vgs_ret {
+  str volgroups<>;
+};
+
+/* guestfs_lvs */
+
+struct guestfs_lvs_ret {
+  str logvols<>;
+};
+
 /* guestfs_pvs_full */
 
 struct guestfs_pvs_full_ret {
@@ -169,6 +187,9 @@ enum guestfs_procedure {
   GUESTFS_PROC_LS = 6,
   GUESTFS_PROC_LIST_DEVICES = 7,
   GUESTFS_PROC_LIST_PARTITIONS = 8,
+  GUESTFS_PROC_PVS = 9,
+  GUESTFS_PROC_VGS = 10,
+  GUESTFS_PROC_LVS = 11,
   GUESTFS_PROC_PVS_FULL = 12,
   GUESTFS_PROC_VGS_FULL = 13,
   GUESTFS_PROC_LVS_FULL = 14,