summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Jones <rjones@redhat.com>2009-04-07 06:50:31 +0100
committerRichard Jones <rjones@redhat.com>2009-04-07 09:14:17 +0100
commit73d6932ab2dd3f9120a1f4a532621c07cb174705 (patch)
tree8c24e36ca7c776611bc2278954b20b59143784b1
parent8e570870f577ff0c3db074f88924633b559af5d4 (diff)
downloadlibguestfs-73d6932ab2dd3f9120a1f4a532621c07cb174705.tar.gz
libguestfs-73d6932ab2dd3f9120a1f4a532621c07cb174705.tar.xz
libguestfs-73d6932ab2dd3f9120a1f4a532621c07cb174705.zip
pvs/vgs/lvs commands working now.
-rw-r--r--Makefile.am13
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/actions.h5
-rw-r--r--daemon/daemon.h5
-rw-r--r--daemon/lvm.c50
-rw-r--r--daemon/proto.c2
-rw-r--r--daemon/stubs.c989
-rw-r--r--fish/cmds.c170
-rw-r--r--fish/fish.c2
-rw-r--r--guestfs-actions.pod30
-rw-r--r--guestfs-structs.pod87
-rw-r--r--guestfs.pod4
-rw-r--r--src/Makefile.am2
-rwxr-xr-xsrc/generator.ml509
-rw-r--r--src/guestfs-actions.c213
-rw-r--r--src/guestfs-actions.h3
-rw-r--r--src/guestfs-structs.h94
-rw-r--r--src/guestfs.c61
-rw-r--r--src/guestfs.h5
-rw-r--r--src/guestfs_protocol.c188
-rw-r--r--src/guestfs_protocol.h114
-rw-r--r--src/guestfs_protocol.x85
22 files changed, 2610 insertions, 22 deletions
diff --git a/Makefile.am b/Makefile.am
index 8e2b49d6..39cf86cf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -21,7 +21,7 @@ SUBDIRS = src daemon fish examples
EXTRA_DIST = \
make-initramfs.sh update-initramfs.sh \
- guestfs.pod guestfs-actions.pod \
+ guestfs.pod guestfs-actions.pod guestfs-structs.pod \
libguestfs.spec \
HACKING
@@ -57,13 +57,16 @@ clean-local:
rm -rf initramfs
# Manual page.
-# guestfs-actions.pod is autogenerated. There is no include mechanism
-# for POD, so we have to do it by hand.
+# guestfs-actions.pod and guestfs-structs are autogenerated. There is
+# no include mechanism for POD, so we have to do it by hand.
man_MANS = guestfs.3
-guestfs.3: guestfs.pod guestfs-actions.pod
- sed -e '/@ACTIONS@/rguestfs-actions.pod' -e 's/@ACTIONS@//' < $< | \
+guestfs.3: guestfs.pod guestfs-actions.pod guestfs-structs.pod
+ sed \
+ -e '/@ACTIONS@/rguestfs-actions.pod' -e 's/@ACTIONS@//' \
+ -e '/@STRUCTS@/rguestfs-structs.pod' -e 's/@STRUCTS@//' \
+ < $< | \
$(POD2MAN) \
--section 3 \
-c "Virtualization Support" \
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 5faa6523..4d56034d 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -25,6 +25,7 @@ guestfsd_SOURCES = \
file.c \
guestfsd.c \
ls.c \
+ lvm.c \
mount.c \
proto.c \
stubs.c \
diff --git a/daemon/actions.h b/daemon/actions.h
index 58b8a24c..6527e0c2 100644
--- a/daemon/actions.h
+++ b/daemon/actions.h
@@ -19,6 +19,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "../src/guestfs_protocol.h"
+
extern int do_mount (const char *device, const char *mountpoint);
extern int do_sync ();
extern int do_touch (const char *path);
@@ -27,3 +29,6 @@ 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 guestfs_lvm_int_pv_list *do_pvs ();
+extern guestfs_lvm_int_vg_list *do_vgs ();
+extern guestfs_lvm_int_lv_list *do_lvs ();
diff --git a/daemon/daemon.h b/daemon/daemon.h
index 60e1982b..e2b6a2a3 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -19,6 +19,8 @@
#ifndef GUESTFSD_DAEMON_H
#define GUESTFSD_DAEMON_H
+#include "../src/guestfs_protocol.h"
+
#include <stdarg.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
@@ -44,6 +46,9 @@ extern int root_mounted;
/* in stubs.c (auto-generated) */
extern void dispatch_incoming_message (XDR *);
+extern guestfs_lvm_int_pv_list *parse_command_line_pvs (void);
+extern guestfs_lvm_int_vg_list *parse_command_line_vgs (void);
+extern guestfs_lvm_int_lv_list *parse_command_line_lvs (void);
/* in proto.c */
extern void main_loop (int sock);
diff --git a/daemon/lvm.c b/daemon/lvm.c
new file mode 100644
index 00000000..1b888f24
--- /dev/null
+++ b/daemon/lvm.c
@@ -0,0 +1,50 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "daemon.h"
+#include "actions.h"
+
+/* LVM actions. Keep an eye on liblvm, although at the time
+ * of writing it hasn't progressed very far.
+ */
+
+guestfs_lvm_int_pv_list *
+do_pvs (void)
+{
+ return parse_command_line_pvs ();
+}
+
+guestfs_lvm_int_vg_list *
+do_vgs (void)
+{
+ return parse_command_line_vgs ();
+}
+
+guestfs_lvm_int_lv_list *
+do_lvs (void)
+{
+ return parse_command_line_lvs ();
+}
diff --git a/daemon/proto.c b/daemon/proto.c
index 62d8da5a..93d33c2c 100644
--- a/daemon/proto.c
+++ b/daemon/proto.c
@@ -35,7 +35,7 @@
/* XXX We should make this configurable from /proc/cmdline so that the
* verbose setting of the guestfs_h can be inherited here.
*/
-#define DEBUG 1
+#define DEBUG 0
/* The message currently being processed. */
int proc_nr;
diff --git a/daemon/stubs.c b/daemon/stubs.c
index faece82d..24f60427 100644
--- a/daemon/stubs.c
+++ b/daemon/stubs.c
@@ -19,8 +19,16 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#define _GNU_SOURCE // for strchrnul
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <ctype.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
+
#include "daemon.h"
#include "../src/guestfs_protocol.h"
#include "actions.h"
@@ -191,6 +199,51 @@ static void list_partitions_stub (XDR *xdr_in)
free_strings (r);
}
+static void pvs_stub (XDR *xdr_in)
+{
+ guestfs_lvm_int_pv_list *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 = *r;
+ reply ((xdrproc_t) &xdr_guestfs_pvs_ret, (char *) &ret);
+ xdr_free ((xdrproc_t) xdr_guestfs_pvs_ret, (char *) &ret);
+}
+
+static void vgs_stub (XDR *xdr_in)
+{
+ guestfs_lvm_int_vg_list *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 = *r;
+ reply ((xdrproc_t) &xdr_guestfs_vgs_ret, (char *) &ret);
+ xdr_free ((xdrproc_t) xdr_guestfs_vgs_ret, (char *) &ret);
+}
+
+static void lvs_stub (XDR *xdr_in)
+{
+ guestfs_lvm_int_lv_list *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 = *r;
+ reply ((xdrproc_t) &xdr_guestfs_lvs_ret, (char *) &ret);
+ xdr_free ((xdrproc_t) xdr_guestfs_lvs_ret, (char *) &ret);
+}
+
void dispatch_incoming_message (XDR *xdr_in)
{
switch (proc_nr) {
@@ -218,7 +271,943 @@ 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;
default:
reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
}
}
+
+static const char *lvm_pv_cols = "pv_name,pv_uuid,pv_fmt,pv_size,dev_size,pv_free,pv_used,pv_attr,pv_pe_count,pv_pe_alloc_count,pv_tags,pe_start,pv_mda_count,pv_mda_free";
+
+static int lvm_tokenize_pv (char *str, struct guestfs_lvm_int_pv *r)
+{
+ char *tok, *p, *next;
+ int i, j;
+
+ if (!str) {
+ fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
+ return -1;
+ }
+ if (!*str || isspace (*str)) {
+ fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
+ return -1;
+ }
+ tok = str;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_name");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->pv_name = strdup (tok);
+ if (r->pv_name == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_uuid");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ for (i = j = 0; i < 32; ++j) {
+ if (tok[j] == '\0') {
+ fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
+ return -1;
+ } else if (tok[j] != '-')
+ r->pv_uuid[i++] = tok[j];
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_fmt");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->pv_fmt = strdup (tok);
+ if (r->pv_fmt == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_size");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->pv_size) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_size");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "dev_size");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->dev_size) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "dev_size");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_free");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->pv_free) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_free");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_used");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->pv_used) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_used");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_attr");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->pv_attr = strdup (tok);
+ if (r->pv_attr == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_pe_count");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->pv_pe_count) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_pe_count");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_pe_alloc_count");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->pv_pe_alloc_count) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_pe_alloc_count");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_tags");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->pv_tags = strdup (tok);
+ if (r->pv_tags == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pe_start");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->pe_start) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pe_start");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_mda_count");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->pv_mda_count) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_mda_count");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_mda_free");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->pv_mda_free) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "pv_mda_free");
+ return -1;
+ }
+ tok = next;
+ if (tok != NULL) {
+ fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+guestfs_lvm_int_pv_list *
+parse_command_line_pvs (void)
+{
+ char *out, *err;
+ char *p, *pend;
+ int r, i;
+ guestfs_lvm_int_pv_list *ret;
+ void *newp;
+
+ ret = malloc (sizeof *ret);
+ if (!ret) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ ret->guestfs_lvm_int_pv_list_len = 0;
+ ret->guestfs_lvm_int_pv_list_val = NULL;
+
+ r = command (&out, &err,
+ "/sbin/lvm", "pvs",
+ "-o", lvm_pv_cols, "--unbuffered", "--noheadings",
+ "--nosuffix", "--separator", ",", "--units", "b", NULL);
+ if (r == -1) {
+ reply_with_error ("%s", err);
+ free (out);
+ free (err);
+ return NULL;
+ }
+
+ free (err);
+
+ /* Tokenize each line of the output. */
+ p = out;
+ i = 0;
+ 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;
+ }
+
+ /* Allocate some space to store this next entry. */
+ newp = realloc (ret->guestfs_lvm_int_pv_list_val,
+ sizeof (guestfs_lvm_int_pv) * (i+1));
+ if (newp == NULL) {
+ reply_with_perror ("realloc");
+ free (ret->guestfs_lvm_int_pv_list_val);
+ free (ret);
+ free (out);
+ return NULL;
+ }
+ ret->guestfs_lvm_int_pv_list_val = newp;
+
+ /* Tokenize the next entry. */
+ r = lvm_tokenize_pv (p, &ret->guestfs_lvm_int_pv_list_val[i]);
+ if (r == -1) {
+ reply_with_error ("failed to parse output of 'pvs' command");
+ free (ret->guestfs_lvm_int_pv_list_val);
+ free (ret);
+ free (out);
+ return NULL;
+ }
+
+ ++i;
+ p = pend;
+ }
+
+ ret->guestfs_lvm_int_pv_list_len = i;
+
+ free (out);
+ return ret;
+}
+static const char *lvm_vg_cols = "vg_name,vg_uuid,vg_fmt,vg_attr,vg_size,vg_free,vg_sysid,vg_extent_size,vg_extent_count,vg_free_count,max_lv,max_pv,pv_count,lv_count,snap_count,vg_seqno,vg_tags,vg_mda_count,vg_mda_free";
+
+static int lvm_tokenize_vg (char *str, struct guestfs_lvm_int_vg *r)
+{
+ char *tok, *p, *next;
+ int i, j;
+
+ if (!str) {
+ fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
+ return -1;
+ }
+ if (!*str || isspace (*str)) {
+ fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
+ return -1;
+ }
+ tok = str;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_name");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->vg_name = strdup (tok);
+ if (r->vg_name == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_uuid");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ for (i = j = 0; i < 32; ++j) {
+ if (tok[j] == '\0') {
+ fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
+ return -1;
+ } else if (tok[j] != '-')
+ r->vg_uuid[i++] = tok[j];
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_fmt");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->vg_fmt = strdup (tok);
+ if (r->vg_fmt == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_attr");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->vg_attr = strdup (tok);
+ if (r->vg_attr == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_size");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->vg_size) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_size");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_free");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->vg_free) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_free");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_sysid");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->vg_sysid = strdup (tok);
+ if (r->vg_sysid == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_extent_size");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->vg_extent_size) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_extent_size");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_extent_count");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->vg_extent_count) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_extent_count");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_free_count");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->vg_free_count) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_free_count");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "max_lv");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->max_lv) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "max_lv");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "max_pv");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->max_pv) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "max_pv");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "pv_count");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->pv_count) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "pv_count");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_count");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->lv_count) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_count");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "snap_count");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->snap_count) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "snap_count");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_seqno");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->vg_seqno) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_seqno");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_tags");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->vg_tags = strdup (tok);
+ if (r->vg_tags == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_mda_count");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->vg_mda_count) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "vg_mda_count");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "vg_mda_free");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->vg_mda_free) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "vg_mda_free");
+ return -1;
+ }
+ tok = next;
+ if (tok != NULL) {
+ fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+guestfs_lvm_int_vg_list *
+parse_command_line_vgs (void)
+{
+ char *out, *err;
+ char *p, *pend;
+ int r, i;
+ guestfs_lvm_int_vg_list *ret;
+ void *newp;
+
+ ret = malloc (sizeof *ret);
+ if (!ret) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ ret->guestfs_lvm_int_vg_list_len = 0;
+ ret->guestfs_lvm_int_vg_list_val = NULL;
+
+ r = command (&out, &err,
+ "/sbin/lvm", "vgs",
+ "-o", lvm_vg_cols, "--unbuffered", "--noheadings",
+ "--nosuffix", "--separator", ",", "--units", "b", NULL);
+ if (r == -1) {
+ reply_with_error ("%s", err);
+ free (out);
+ free (err);
+ return NULL;
+ }
+
+ free (err);
+
+ /* Tokenize each line of the output. */
+ p = out;
+ i = 0;
+ 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;
+ }
+
+ /* Allocate some space to store this next entry. */
+ newp = realloc (ret->guestfs_lvm_int_vg_list_val,
+ sizeof (guestfs_lvm_int_vg) * (i+1));
+ if (newp == NULL) {
+ reply_with_perror ("realloc");
+ free (ret->guestfs_lvm_int_vg_list_val);
+ free (ret);
+ free (out);
+ return NULL;
+ }
+ ret->guestfs_lvm_int_vg_list_val = newp;
+
+ /* Tokenize the next entry. */
+ r = lvm_tokenize_vg (p, &ret->guestfs_lvm_int_vg_list_val[i]);
+ if (r == -1) {
+ reply_with_error ("failed to parse output of 'vgs' command");
+ free (ret->guestfs_lvm_int_vg_list_val);
+ free (ret);
+ free (out);
+ return NULL;
+ }
+
+ ++i;
+ p = pend;
+ }
+
+ ret->guestfs_lvm_int_vg_list_len = i;
+
+ free (out);
+ return ret;
+}
+static const char *lvm_lv_cols = "lv_name,lv_uuid,lv_attr,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,lv_size,seg_count,origin,snap_percent,copy_percent,move_pv,lv_tags,mirror_log,modules";
+
+static int lvm_tokenize_lv (char *str, struct guestfs_lvm_int_lv *r)
+{
+ char *tok, *p, *next;
+ int i, j;
+
+ if (!str) {
+ fprintf (stderr, "%s: failed: passed a NULL string\n", __func__);
+ return -1;
+ }
+ if (!*str || isspace (*str)) {
+ fprintf (stderr, "%s: failed: passed a empty string or one beginning with whitespace\n", __func__);
+ return -1;
+ }
+ tok = str;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_name");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->lv_name = strdup (tok);
+ if (r->lv_name == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_uuid");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ for (i = j = 0; i < 32; ++j) {
+ if (tok[j] == '\0') {
+ fprintf (stderr, "%s: failed to parse UUID from '%s'\n", __func__, tok);
+ return -1;
+ } else if (tok[j] != '-')
+ r->lv_uuid[i++] = tok[j];
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_attr");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->lv_attr = strdup (tok);
+ if (r->lv_attr == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_major");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->lv_major) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_major");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_minor");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->lv_minor) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_minor");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_kernel_major");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->lv_kernel_major) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_kernel_major");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_kernel_minor");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->lv_kernel_minor) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "lv_kernel_minor");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_size");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNu64, &r->lv_size) != 1) {
+ fprintf (stderr, "%s: failed to parse size '%s' from token %s\n", __func__, tok, "lv_size");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "seg_count");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (sscanf (tok, "%"SCNi64, &r->seg_count) != 1) {
+ fprintf (stderr, "%s: failed to parse int '%s' from token %s\n", __func__, tok, "seg_count");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "origin");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->origin = strdup (tok);
+ if (r->origin == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "snap_percent");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (tok[0] == '\0')
+ r->snap_percent = -1;
+ else if (sscanf (tok, "%f", &r->snap_percent) != 1) {
+ fprintf (stderr, "%s: failed to parse float '%s' from token %s\n", __func__, tok, "snap_percent");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "copy_percent");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ if (tok[0] == '\0')
+ r->copy_percent = -1;
+ else if (sscanf (tok, "%f", &r->copy_percent) != 1) {
+ fprintf (stderr, "%s: failed to parse float '%s' from token %s\n", __func__, tok, "copy_percent");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "move_pv");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->move_pv = strdup (tok);
+ if (r->move_pv == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "lv_tags");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->lv_tags = strdup (tok);
+ if (r->lv_tags == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "mirror_log");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->mirror_log = strdup (tok);
+ if (r->mirror_log == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (!tok) {
+ fprintf (stderr, "%s: failed: string finished early, around token %s\n", __func__, "modules");
+ return -1;
+ }
+ p = strchrnul (tok, ',');
+ if (*p) next = p+1; else next = NULL;
+ *p = '\0';
+ r->modules = strdup (tok);
+ if (r->modules == NULL) {
+ perror ("strdup");
+ return -1;
+ }
+ tok = next;
+ if (tok != NULL) {
+ fprintf (stderr, "%s: failed: extra tokens at end of string\n", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+guestfs_lvm_int_lv_list *
+parse_command_line_lvs (void)
+{
+ char *out, *err;
+ char *p, *pend;
+ int r, i;
+ guestfs_lvm_int_lv_list *ret;
+ void *newp;
+
+ ret = malloc (sizeof *ret);
+ if (!ret) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ ret->guestfs_lvm_int_lv_list_len = 0;
+ ret->guestfs_lvm_int_lv_list_val = NULL;
+
+ r = command (&out, &err,
+ "/sbin/lvm", "lvs",
+ "-o", lvm_lv_cols, "--unbuffered", "--noheadings",
+ "--nosuffix", "--separator", ",", "--units", "b", NULL);
+ if (r == -1) {
+ reply_with_error ("%s", err);
+ free (out);
+ free (err);
+ return NULL;
+ }
+
+ free (err);
+
+ /* Tokenize each line of the output. */
+ p = out;
+ i = 0;
+ 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;
+ }
+
+ /* Allocate some space to store this next entry. */
+ newp = realloc (ret->guestfs_lvm_int_lv_list_val,
+ sizeof (guestfs_lvm_int_lv) * (i+1));
+ if (newp == NULL) {
+ reply_with_perror ("realloc");
+ free (ret->guestfs_lvm_int_lv_list_val);
+ free (ret);
+ free (out);
+ return NULL;
+ }
+ ret->guestfs_lvm_int_lv_list_val = newp;
+
+ /* Tokenize the next entry. */
+ r = lvm_tokenize_lv (p, &ret->guestfs_lvm_int_lv_list_val[i]);
+ if (r == -1) {
+ reply_with_error ("failed to parse output of 'lvs' command");
+ free (ret->guestfs_lvm_int_lv_list_val);
+ free (ret);
+ free (out);
+ return NULL;
+ }
+
+ ++i;
+ p = pend;
+ }
+
+ ret->guestfs_lvm_int_lv_list_len = i;
+
+ free (out);
+ return ret;
+}
diff --git a/fish/cmds.c b/fish/cmds.c
index 28dd9563..6d8e4543 100644
--- a/fish/cmds.c
+++ b/fish/cmds.c
@@ -22,7 +22,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <inttypes.h>
+#include <guestfs.h>
#include "fish.h"
void list_commands (void)
@@ -34,9 +36,12 @@ 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", "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", "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 (" Use -h <cmd> / help <cmd> to show detailed help for a command.\n");
}
@@ -66,9 +71,120 @@ 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.");
+ 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.");
+ 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.");
+ else
display_builtin_command (cmd);
}
+static void print_pv (struct guestfs_lvm_pv *pv)
+{
+ int i;
+
+ printf ("pv_name: %s\n", pv->pv_name);
+ printf ("pv_uuid: ");
+ for (i = 0; i < 32; ++i)
+ printf ("%c", pv->pv_uuid[i]);
+ printf ("\n");
+ printf ("pv_fmt: %s\n", pv->pv_fmt);
+ printf ("pv_size: %" PRIu64 "\n", pv->pv_size);
+ printf ("dev_size: %" PRIu64 "\n", pv->dev_size);
+ printf ("pv_free: %" PRIu64 "\n", pv->pv_free);
+ printf ("pv_used: %" PRIu64 "\n", pv->pv_used);
+ printf ("pv_attr: %s\n", pv->pv_attr);
+ printf ("pv_pe_count: %" PRIi64 "\n", pv->pv_pe_count);
+ printf ("pv_pe_alloc_count: %" PRIi64 "\n", pv->pv_pe_alloc_count);
+ printf ("pv_tags: %s\n", pv->pv_tags);
+ printf ("pe_start: %" PRIu64 "\n", pv->pe_start);
+ printf ("pv_mda_count: %" PRIi64 "\n", pv->pv_mda_count);
+ printf ("pv_mda_free: %" PRIu64 "\n", pv->pv_mda_free);
+}
+
+static void print_pv_list (struct guestfs_lvm_pv_list *pvs)
+{
+ int i;
+
+ for (i = 0; i < pvs->len; ++i)
+ print_pv (&pvs->val[i]);
+}
+
+static void print_vg (struct guestfs_lvm_vg *vg)
+{
+ int i;
+
+ printf ("vg_name: %s\n", vg->vg_name);
+ printf ("vg_uuid: ");
+ for (i = 0; i < 32; ++i)
+ printf ("%c", vg->vg_uuid[i]);
+ printf ("\n");
+ printf ("vg_fmt: %s\n", vg->vg_fmt);
+ printf ("vg_attr: %s\n", vg->vg_attr);
+ printf ("vg_size: %" PRIu64 "\n", vg->vg_size);
+ printf ("vg_free: %" PRIu64 "\n", vg->vg_free);
+ printf ("vg_sysid: %s\n", vg->vg_sysid);
+ printf ("vg_extent_size: %" PRIu64 "\n", vg->vg_extent_size);
+ printf ("vg_extent_count: %" PRIi64 "\n", vg->vg_extent_count);
+ printf ("vg_free_count: %" PRIi64 "\n", vg->vg_free_count);
+ printf ("max_lv: %" PRIi64 "\n", vg->max_lv);
+ printf ("max_pv: %" PRIi64 "\n", vg->max_pv);
+ printf ("pv_count: %" PRIi64 "\n", vg->pv_count);
+ printf ("lv_count: %" PRIi64 "\n", vg->lv_count);
+ printf ("snap_count: %" PRIi64 "\n", vg->snap_count);
+ printf ("vg_seqno: %" PRIi64 "\n", vg->vg_seqno);
+ printf ("vg_tags: %s\n", vg->vg_tags);
+ printf ("vg_mda_count: %" PRIi64 "\n", vg->vg_mda_count);
+ printf ("vg_mda_free: %" PRIu64 "\n", vg->vg_mda_free);
+}
+
+static void print_vg_list (struct guestfs_lvm_vg_list *vgs)
+{
+ int i;
+
+ for (i = 0; i < vgs->len; ++i)
+ print_vg (&vgs->val[i]);
+}
+
+static void print_lv (struct guestfs_lvm_lv *lv)
+{
+ int i;
+
+ printf ("lv_name: %s\n", lv->lv_name);
+ printf ("lv_uuid: ");
+ for (i = 0; i < 32; ++i)
+ printf ("%c", lv->lv_uuid[i]);
+ printf ("\n");
+ printf ("lv_attr: %s\n", lv->lv_attr);
+ printf ("lv_major: %" PRIi64 "\n", lv->lv_major);
+ printf ("lv_minor: %" PRIi64 "\n", lv->lv_minor);
+ printf ("lv_kernel_major: %" PRIi64 "\n", lv->lv_kernel_major);
+ printf ("lv_kernel_minor: %" PRIi64 "\n", lv->lv_kernel_minor);
+ printf ("lv_size: %" PRIu64 "\n", lv->lv_size);
+ printf ("seg_count: %" PRIi64 "\n", lv->seg_count);
+ printf ("origin: %s\n", lv->origin);
+ if (lv->snap_percent >= 0) printf ("snap_percent: %g %%\n", lv->snap_percent);
+ else printf ("snap_percent: \n");
+ if (lv->copy_percent >= 0) printf ("copy_percent: %g %%\n", lv->copy_percent);
+ else printf ("copy_percent: \n");
+ printf ("move_pv: %s\n", lv->move_pv);
+ printf ("lv_tags: %s\n", lv->lv_tags);
+ printf ("mirror_log: %s\n", lv->mirror_log);
+ printf ("modules: %s\n", lv->modules);
+}
+
+static void print_lv_list (struct guestfs_lvm_lv_list *lvs)
+{
+ int i;
+
+ for (i = 0; i < lvs->len; ++i)
+ print_lv (&lvs->val[i]);
+}
+
static int run_mount (const char *cmd, int argc, char *argv[])
{
int r;
@@ -192,6 +308,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[])
+{
+ struct guestfs_lvm_pv_list *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_pv_list (r);
+ guestfs_free_lvm_pv_list (r);
+ return 0;
+}
+
+static int run_vgs (const char *cmd, int argc, char *argv[])
+{
+ struct guestfs_lvm_vg_list *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_vg_list (r);
+ guestfs_free_lvm_vg_list (r);
+ return 0;
+}
+
+static int run_lvs (const char *cmd, int argc, char *argv[])
+{
+ struct guestfs_lvm_lv_list *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_lv_list (r);
+ guestfs_free_lvm_lv_list (r);
+ return 0;
+}
+
int run_action (const char *cmd, int argc, char *argv[])
{
if (strcasecmp (cmd, "mount") == 0)
@@ -218,6 +379,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
{
fprintf (stderr, "%s: unknown command\n", cmd);
return -1;
diff --git a/fish/fish.c b/fish/fish.c
index 374416e7..e0d04706 100644
--- a/fish/fish.c
+++ b/fish/fish.c
@@ -165,7 +165,7 @@ main (int argc, char *argv[])
mp->mountpoint = "/";
mp->device = optarg;
mp->next = mps;
- mps = mp->next;
+ mps = mp;
break;
case 'n':
diff --git a/guestfs-actions.pod b/guestfs-actions.pod
index f89ae26b..a2a19ba4 100644
--- a/guestfs-actions.pod
+++ b/guestfs-actions.pod
@@ -75,6 +75,16 @@ 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
+
+ struct guestfs_lvm_lv_list *guestfs_lvs (guestfs_h *handle);
+
+List all the logical volumes detected. This is the equivalent
+of the L<lvs(8)> command.
+
+This function returns a C<struct guestfs_lvm_lv_list>.
+I<The caller must call C<guestfs_free_lvm_lv_list> after use.>.
+
=head2 guestfs_mount
int guestfs_mount (guestfs_h *handle,
@@ -100,6 +110,16 @@ call, in order to improve reliability.
This function returns 0 on success or -1 on error.
+=head2 guestfs_pvs
+
+ struct guestfs_lvm_pv_list *guestfs_pvs (guestfs_h *handle);
+
+List all the physical volumes detected. This is the equivalent
+of the L<pvs(8)> command.
+
+This function returns a C<struct guestfs_lvm_pv_list>.
+I<The caller must call C<guestfs_free_lvm_pv_list> after use.>.
+
=head2 guestfs_sync
int guestfs_sync (guestfs_h *handle);
@@ -123,3 +143,13 @@ to create a new zero-length file.
This function returns 0 on success or -1 on error.
+=head2 guestfs_vgs
+
+ struct guestfs_lvm_vg_list *guestfs_vgs (guestfs_h *handle);
+
+List all the volumes groups detected. This is the equivalent
+of the L<vgs(8)> command.
+
+This function returns a C<struct guestfs_lvm_vg_list>.
+I<The caller must call C<guestfs_free_lvm_vg_list> after use.>.
+
diff --git a/guestfs-structs.pod b/guestfs-structs.pod
new file mode 100644
index 00000000..31b9ff28
--- /dev/null
+++ b/guestfs-structs.pod
@@ -0,0 +1,87 @@
+=head2 guestfs_lvm_pv
+
+ struct guestfs_lvm_pv {
+ char *pv_name;
+ /* The next field is NOT nul-terminated, be careful when printing it: */
+ char pv_uuid[32];
+ char *pv_fmt;
+ uint64_t pv_size;
+ uint64_t dev_size;
+ uint64_t pv_free;
+ uint64_t pv_used;
+ char *pv_attr;
+ int64_t pv_pe_count;
+ int64_t pv_pe_alloc_count;
+ char *pv_tags;
+ uint64_t pe_start;
+ int64_t pv_mda_count;
+ uint64_t pv_mda_free;
+
+ struct guestfs_lvm_pv_list {
+ uint32_t len; /* Number of elements in list. */
+ struct guestfs_lvm_pv *val; /* Elements. */
+ };
+
+ void guestfs_free_lvm_pv_list (struct guestfs_free_lvm_pv_list *);
+
+=head2 guestfs_lvm_vg
+
+ struct guestfs_lvm_vg {
+ char *vg_name;
+ /* The next field is NOT nul-terminated, be careful when printing it: */
+ char vg_uuid[32];
+ char *vg_fmt;
+ char *vg_attr;
+ uint64_t vg_size;
+ uint64_t vg_free;
+ char *vg_sysid;
+ uint64_t vg_extent_size;
+ int64_t vg_extent_count;
+ int64_t vg_free_count;
+ int64_t max_lv;
+ int64_t max_pv;
+ int64_t pv_count;
+ int64_t lv_count;
+ int64_t snap_count;
+ int64_t vg_seqno;
+ char *vg_tags;
+ int64_t vg_mda_count;
+ uint64_t vg_mda_free;
+
+ struct guestfs_lvm_vg_list {
+ uint32_t len; /* Number of elements in list. */
+ struct guestfs_lvm_vg *val; /* Elements. */
+ };
+
+ void guestfs_free_lvm_vg_list (struct guestfs_free_lvm_vg_list *);
+
+=head2 guestfs_lvm_lv
+
+ struct guestfs_lvm_lv {
+ char *lv_name;
+ /* The next field is NOT nul-terminated, be careful when printing it: */
+ char lv_uuid[32];
+ char *lv_attr;
+ int64_t lv_major;
+ int64_t lv_minor;
+ int64_t lv_kernel_major;
+ int64_t lv_kernel_minor;
+ uint64_t lv_size;
+ int64_t seg_count;
+ char *origin;
+ /* The next field is [0..100] or -1 meaning 'not present': */
+ float snap_percent;
+ /* The next field is [0..100] or -1 meaning 'not present': */
+ float copy_percent;
+ char *move_pv;
+ char *lv_tags;
+ char *mirror_log;
+ char *modules;
+
+ struct guestfs_lvm_lv_list {
+ uint32_t len; /* Number of elements in list. */
+ struct guestfs_lvm_lv *val; /* Elements. */
+ };
+
+ void guestfs_free_lvm_lv_list (struct guestfs_free_lvm_lv_list *);
+
diff --git a/guestfs.pod b/guestfs.pod
index 3c28b04d..7396644d 100644
--- a/guestfs.pod
+++ b/guestfs.pod
@@ -312,6 +312,10 @@ This returns the verbose messages flag.
@ACTIONS@
+=head1 STRUCTURES
+
+@STRUCTS@
+
=head1 STATE MACHINE AND LOW-LEVEL EVENT API
Internally, libguestfs is implemented by running a virtual machine
diff --git a/src/Makefile.am b/src/Makefile.am
index 566fa410..7a4e360a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,7 +23,7 @@ EXTRA_DIST += guestfs_protocol.x \
guestfs_protocol.c \
guestfs_protocol.h
-include_HEADERS = guestfs.h guestfs-actions.h
+include_HEADERS = guestfs.h guestfs-actions.h guestfs-structs.h
lib_LTLIBRARIES = libguestfs.la
diff --git a/src/generator.ml b/src/generator.ml
index 12c51fc8..8d1dc046 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -1,4 +1,4 @@
-#!/usr/bin/ocamlrun ocaml
+#!/usr/bin/env ocaml
(* libguestfs
* Copyright (C) 2009 Red Hat Inc.
*
@@ -37,6 +37,10 @@ and ret =
*)
| RString of string
| RStringList of string
+ (* LVM PVs, VGs and LVs. *)
+ | RPVList of string
+ | RVGList of string
+ | RLVList of string
and args =
(* 0 arguments, 1 argument, etc. The guestfs_h param is implicit. *)
| P0
@@ -130,6 +134,87 @@ 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, [],
+ "list the LVM physical volumes (PVs)",
+ "\
+List all the physical volumes detected. This is the equivalent
+of the L<pvs(8)> command.");
+
+ ("vgs", (RVGList "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.");
+
+ ("lvs", (RLVList "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.");
+]
+
+(* Column names and types from LVM PVs/VGs/LVs. *)
+let pv_cols = [
+ "pv_name", `String;
+ "pv_uuid", `UUID;
+ "pv_fmt", `String;
+ "pv_size", `Bytes;
+ "dev_size", `Bytes;
+ "pv_free", `Bytes;
+ "pv_used", `Bytes;
+ "pv_attr", `String (* XXX *);
+ "pv_pe_count", `Int;
+ "pv_pe_alloc_count", `Int;
+ "pv_tags", `String;
+ "pe_start", `Bytes;
+ "pv_mda_count", `Int;
+ "pv_mda_free", `Bytes;
+(* Not in Fedora 10:
+ "pv_mda_size", `Bytes;
+*)
+]
+let vg_cols = [
+ "vg_name", `String;
+ "vg_uuid", `UUID;
+ "vg_fmt", `String;
+ "vg_attr", `String (* XXX *);
+ "vg_size", `Bytes;
+ "vg_free", `Bytes;
+ "vg_sysid", `String;
+ "vg_extent_size", `Bytes;
+ "vg_extent_count", `Int;
+ "vg_free_count", `Int;
+ "max_lv", `Int;
+ "max_pv", `Int;
+ "pv_count", `Int;
+ "lv_count", `Int;
+ "snap_count", `Int;
+ "vg_seqno", `Int;
+ "vg_tags", `String;
+ "vg_mda_count", `Int;
+ "vg_mda_free", `Bytes;
+(* Not in Fedora 10:
+ "vg_mda_size", `Bytes;
+*)
+]
+let lv_cols = [
+ "lv_name", `String;
+ "lv_uuid", `UUID;
+ "lv_attr", `String (* XXX *);
+ "lv_major", `Int;
+ "lv_minor", `Int;
+ "lv_kernel_major", `Int;
+ "lv_kernel_minor", `Int;
+ "lv_size", `Bytes;
+ "seg_count", `Int;
+ "origin", `String;
+ "snap_percent", `OptPercent;
+ "copy_percent", `OptPercent;
+ "move_pv", `String;
+ "lv_tags", `String;
+ "mirror_log", `String;
+ "modules", `String;
]
(* In some places we want the functions to be displayed sorted
@@ -250,7 +335,7 @@ let rec generate_header comment license =
pr "\n"
(* Generate the pod documentation for the C API. *)
-and generate_pod () =
+and generate_actions_pod () =
List.iter (
fun (shortname, style, _, flags, _, longdesc) ->
let name = "guestfs_" ^ shortname in
@@ -269,6 +354,15 @@ I<The caller must free the returned string after use>.\n\n"
pr "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>.\n\n"
+ | RPVList _ ->
+ pr "This function returns a C<struct guestfs_lvm_pv_list>.
+I<The caller must call C<guestfs_free_lvm_pv_list> after use.>.\n\n"
+ | RVGList _ ->
+ pr "This function returns a C<struct guestfs_lvm_vg_list>.
+I<The caller must call C<guestfs_free_lvm_vg_list> after use.>.\n\n"
+ | RLVList _ ->
+ pr "This function returns a C<struct guestfs_lvm_lv_list>.
+I<The caller must call C<guestfs_free_lvm_lv_list> after use.>.\n\n"
);
if List.mem ProtocolLimitWarning flags then
pr "Because of the message protocol, there is a transfer limit
@@ -276,7 +370,43 @@ of somewhere between 2MB and 4MB. To transfer large files you should use
FTP.\n\n";
) sorted_functions
-(* Generate the protocol (XDR) file. *)
+and generate_structs_pod () =
+ (* LVM structs documentation. *)
+ List.iter (
+ fun (typ, cols) ->
+ pr "=head2 guestfs_lvm_%s\n" typ;
+ pr "\n";
+ pr " struct guestfs_lvm_%s {\n" typ;
+ List.iter (
+ function
+ | name, `String -> pr " char *%s;\n" name
+ | name, `UUID ->
+ pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
+ pr " char %s[32];\n" name
+ | name, `Bytes -> pr " uint64_t %s;\n" name
+ | name, `Int -> pr " int64_t %s;\n" name
+ | name, `OptPercent ->
+ pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
+ pr " float %s;\n" name
+ ) cols;
+ pr " \n";
+ pr " struct guestfs_lvm_%s_list {\n" typ;
+ pr " uint32_t len; /* Number of elements in list. */\n";
+ pr " struct guestfs_lvm_%s *val; /* Elements. */\n" typ;
+ pr " };\n";
+ pr " \n";
+ pr " void guestfs_free_lvm_%s_list (struct guestfs_free_lvm_%s_list *);\n"
+ typ typ;
+ pr "\n"
+ ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
+
+(* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
+ * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'. We
+ * have to use an underscore instead of a dash because otherwise
+ * rpcgen generates incorrect code.
+ *
+ * This header is NOT exported to clients, but see also generate_structs_h.
+ *)
and generate_xdr () =
generate_header CStyle LGPLv2;
@@ -284,6 +414,24 @@ and generate_xdr () =
pr "typedef string str<>;\n";
pr "\n";
+ (* LVM internal structures. *)
+ List.iter (
+ function
+ | typ, cols ->
+ pr "struct guestfs_lvm_int_%s {\n" typ;
+ List.iter (function
+ | name, `String -> pr " string %s<>;\n" name
+ | name, `UUID -> pr " opaque %s[32];\n" name
+ | name, `Bytes -> pr " hyper %s;\n" name
+ | name, `Int -> pr " hyper %s;\n" name
+ | name, `OptPercent -> pr " float %s;\n" name
+ ) cols;
+ pr "};\n";
+ pr "\n";
+ pr "typedef struct guestfs_lvm_int_%s guestfs_lvm_int_%s_list<>;\n" typ typ;
+ pr "\n";
+ ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
+
List.iter (
fun (shortname, style, _, _, _, _) ->
let name = "guestfs_" ^ shortname in
@@ -308,6 +456,18 @@ and generate_xdr () =
pr "struct %s_ret {\n" name;
pr " str %s<>;\n" n;
pr "};\n\n"
+ | RPVList n ->
+ pr "struct %s_ret {\n" name;
+ pr " guestfs_lvm_int_pv_list %s;\n" n;
+ pr "};\n\n"
+ | RVGList n ->
+ pr "struct %s_ret {\n" name;
+ pr " guestfs_lvm_int_vg_list %s;\n" n;
+ pr "};\n\n"
+ | RLVList n ->
+ pr "struct %s_ret {\n" name;
+ pr " guestfs_lvm_int_lv_list %s;\n" n;
+ pr "};\n\n"
);
) functions;
@@ -361,6 +521,46 @@ struct guestfs_message_header {
};
"
+(* Generate the guestfs-structs.h file. *)
+and generate_structs_h () =
+ generate_header CStyle LGPLv2;
+
+ (* This is a public exported header file containing various
+ * structures. The structures are carefully written to have
+ * exactly the same in-memory format as the XDR structures that
+ * we use on the wire to the daemon. The reason for creating
+ * copies of these structures here is just so we don't have to
+ * export the whole of guestfs_protocol.h (which includes much
+ * unrelated and XDR-dependent stuff that we don't want to be
+ * public, or required by clients).
+ *
+ * To reiterate, we will pass these structures to and from the
+ * client with a simple assignment or memcpy, so the format
+ * must be identical to what rpcgen / the RFC defines.
+ *)
+
+ (* LVM public structures. *)
+ List.iter (
+ function
+ | typ, cols ->
+ pr "struct guestfs_lvm_%s {\n" typ;
+ List.iter (
+ function
+ | name, `String -> pr " char *%s;\n" name
+ | name, `UUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
+ | name, `Bytes -> pr " uint64_t %s;\n" name
+ | name, `Int -> pr " int64_t %s;\n" name
+ | name, `OptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
+ ) cols;
+ pr "};\n";
+ pr "\n";
+ pr "struct guestfs_lvm_%s_list {\n" typ;
+ pr " uint32_t len;\n";
+ pr " struct guestfs_lvm_%s *val;\n" typ;
+ pr "};\n";
+ pr "\n"
+ ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
+
(* Generate the guestfs-actions.h file. *)
and generate_actions_h () =
generate_header CStyle LGPLv2;
@@ -374,6 +574,8 @@ and generate_actions_h () =
(* Generate the client-side dispatch stubs. *)
and generate_client_actions () =
generate_header CStyle LGPLv2;
+
+ (* Client-side stubs for each function. *)
List.iter (
fun (shortname, style, _, _, _, _) ->
let name = "guestfs_" ^ shortname in
@@ -385,7 +587,8 @@ and generate_client_actions () =
pr " struct guestfs_message_error err;\n";
(match fst style with
| Err -> ()
- | RString _ | RStringList _ -> pr " struct %s_ret ret;\n" name;
+ | RString _ | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
+ pr " struct %s_ret ret;\n" name
);
pr "};\n\n";
@@ -408,7 +611,7 @@ and generate_client_actions () =
(match fst style with
| Err -> ()
- | RString _ | RStringList _ ->
+ | RString _ | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
pr " if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
pr " error (g, \"%s: failed to parse reply\");\n" name;
pr " return;\n";
@@ -427,7 +630,8 @@ and generate_client_actions () =
let error_code =
match fst style with
| Err -> "-1"
- | RString _ | RStringList _ -> "NULL" in
+ | RString _ | RStringList _ | RPVList _ | RVGList _ | RLVList _ ->
+ "NULL" in
pr "{\n";
@@ -499,6 +703,15 @@ and generate_client_actions () =
pr " rv.ret.%s.%s_val = safe_realloc (g, rv.ret.%s.%s_val, rv.ret.%s.%s_len + 1);\n" n n n n n n;
pr " rv.ret.%s.%s_val[rv.ret.%s.%s_len] = NULL;\n" n n n n;
pr " return rv.ret.%s.%s_val;\n" n n
+ | RPVList n ->
+ pr " /* caller will free this */\n";
+ pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
+ | RVGList n ->
+ pr " /* caller will free this */\n";
+ pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
+ | RLVList n ->
+ pr " /* caller will free this */\n";
+ pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
);
pr "}\n\n"
@@ -507,17 +720,30 @@ and generate_client_actions () =
(* Generate daemon/actions.h. *)
and generate_daemon_actions_h () =
generate_header CStyle GPLv2;
+
+ pr "#include \"../src/guestfs_protocol.h\"\n";
+ pr "\n";
+
List.iter (
fun (name, style, _, _, _, _) ->
- generate_prototype ~single_line:true ~newline:true ("do_" ^ name) style;
+ generate_prototype
+ ~single_line:true ~newline:true ~in_daemon:true ("do_" ^ name) style;
) functions
(* Generate the server-side stubs. *)
and generate_daemon_actions () =
generate_header CStyle GPLv2;
+ pr "#define _GNU_SOURCE // for strchrnul\n";
+ pr "\n";
+ pr "#include <stdio.h>\n";
+ pr "#include <stdlib.h>\n";
+ pr "#include <string.h>\n";
+ pr "#include <inttypes.h>\n";
+ pr "#include <ctype.h>\n";
pr "#include <rpc/types.h>\n";
pr "#include <rpc/xdr.h>\n";
+ pr "\n";
pr "#include \"daemon.h\"\n";
pr "#include \"../src/guestfs_protocol.h\"\n";
pr "#include \"actions.h\"\n";
@@ -532,7 +758,11 @@ and generate_daemon_actions () =
match fst style with
| Err -> pr " int r;\n"; "-1"
| RString _ -> pr " char *r;\n"; "NULL"
- | RStringList _ -> pr " char **r;\n"; "NULL" in
+ | RStringList _ -> pr " char **r;\n"; "NULL"
+ | RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
+ | RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
+ | RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL" in
+
(match snd style with
| P0 -> ()
| args ->
@@ -582,6 +812,21 @@ and generate_daemon_actions () =
pr " ret.%s.%s_val = r;\n" n n;
pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
pr " free_strings (r);\n"
+ | RPVList n ->
+ pr " struct guestfs_%s_ret ret;\n" name;
+ pr " ret.%s = *r;\n" n;
+ pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
+ pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
+ | RVGList n ->
+ pr " struct guestfs_%s_ret ret;\n" name;
+ pr " ret.%s = *r;\n" n;
+ pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
+ pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
+ | RLVList n ->
+ pr " struct guestfs_%s_ret ret;\n" name;
+ pr " ret.%s = *r;\n" n;
+ pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n" name;
+ pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
);
pr "}\n\n";
@@ -602,7 +847,173 @@ and generate_daemon_actions () =
pr " default:\n";
pr " reply_with_error (\"dispatch_incoming_message: unknown procedure number %%d\", proc_nr);\n";
pr " }\n";
- pr "}\n"
+ pr "}\n";
+ pr "\n";
+
+ (* LVM columns and tokenization functions. *)
+ (* XXX This generates crap code. We should rethink how we
+ * do this parsing.
+ *)
+ List.iter (
+ function
+ | typ, cols ->
+ pr "static const char *lvm_%s_cols = \"%s\";\n"
+ typ (String.concat "," (List.map fst cols));
+ pr "\n";
+
+ pr "static int lvm_tokenize_%s (char *str, struct guestfs_lvm_int_%s *r)\n" typ typ;
+ pr "{\n";
+ pr " char *tok, *p, *next;\n";
+ pr " int i, j;\n";
+ pr "\n";
+ (*
+ pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
+ pr "\n";
+ *)
+ pr " if (!str) {\n";
+ pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
+ pr " return -1;\n";
+ pr " }\n";
+ pr " if (!*str || isspace (*str)) {\n";
+ pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
+ pr " return -1;\n";
+ pr " }\n";
+ pr " tok = str;\n";
+ List.iter (
+ fun (name, coltype) ->
+ pr " if (!tok) {\n";
+ pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
+ pr " return -1;\n";
+ pr " }\n";
+ pr " p = strchrnul (tok, ',');\n";
+ pr " if (*p) next = p+1; else next = NULL;\n";
+ pr " *p = '\\0';\n";
+ (match coltype with
+ | `String ->
+ pr " r->%s = strdup (tok);\n" name;
+ pr " if (r->%s == NULL) {\n" name;
+ pr " perror (\"strdup\");\n";
+ pr " return -1;\n";
+ pr " }\n"
+ | `UUID ->
+ pr " for (i = j = 0; i < 32; ++j) {\n";
+ pr " if (tok[j] == '\\0') {\n";
+ pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
+ pr " return -1;\n";
+ pr " } else if (tok[j] != '-')\n";
+ pr " r->%s[i++] = tok[j];\n" name;
+ pr " }\n";
+ | `Bytes ->
+ pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
+ pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
+ pr " return -1;\n";
+ pr " }\n";
+ | `Int ->
+ pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
+ pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
+ pr " return -1;\n";
+ pr " }\n";
+ | `OptPercent ->
+ pr " if (tok[0] == '\\0')\n";
+ pr " r->%s = -1;\n" name;
+ pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
+ pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
+ pr " return -1;\n";
+ pr " }\n";
+ );
+ pr " tok = next;\n";
+ ) cols;
+
+ pr " if (tok != NULL) {\n";
+ pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
+ pr " return -1;\n";
+ pr " }\n";
+ pr " return 0;\n";
+ pr "}\n";
+ pr "\n";
+
+ pr "guestfs_lvm_int_%s_list *\n" typ;
+ pr "parse_command_line_%ss (void)\n" typ;
+ pr "{\n";
+ pr " char *out, *err;\n";
+ pr " char *p, *pend;\n";
+ pr " int r, i;\n";
+ pr " guestfs_lvm_int_%s_list *ret;\n" typ;
+ pr " void *newp;\n";
+ pr "\n";
+ pr " ret = malloc (sizeof *ret);\n";
+ pr " if (!ret) {\n";
+ pr " reply_with_perror (\"malloc\");\n";
+ pr " return NULL;\n";
+ pr " }\n";
+ pr "\n";
+ pr " ret->guestfs_lvm_int_%s_list_len = 0;\n" typ;
+ pr " ret->guestfs_lvm_int_%s_list_val = NULL;\n" typ;
+ pr "\n";
+ pr " r = command (&out, &err,\n";
+ pr " \"/sbin/lvm\", \"%ss\",\n" typ;
+ pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
+ pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
+ pr " if (r == -1) {\n";
+ pr " reply_with_error (\"%%s\", err);\n";
+ pr " free (out);\n";
+ pr " free (err);\n";
+ pr " return NULL;\n";
+ pr " }\n";
+ pr "\n";
+ pr " free (err);\n";
+ pr "\n";
+ pr " /* Tokenize each line of the output. */\n";
+ pr " p = out;\n";
+ pr " i = 0;\n";
+ pr " while (p) {\n";
+ pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
+ pr " if (pend) {\n";
+ pr " *pend = '\\0';\n";
+ pr " pend++;\n";
+ pr " }\n";
+ pr "\n";
+ pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
+ pr " p++;\n";
+ pr "\n";
+ pr " if (!*p) { /* Empty line? Skip it. */\n";
+ pr " p = pend;\n";
+ pr " continue;\n";
+ pr " }\n";
+ pr "\n";
+ pr " /* Allocate some space to store this next entry. */\n";
+ pr " newp = realloc (ret->guestfs_lvm_int_%s_list_val,\n" typ;
+ pr " sizeof (guestfs_lvm_int_%s) * (i+1));\n" typ;
+ pr " if (newp == NULL) {\n";
+ pr " reply_with_perror (\"realloc\");\n";
+ pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
+ pr " free (ret);\n";
+ pr " free (out);\n";
+ pr " return NULL;\n";
+ pr " }\n";
+ pr " ret->guestfs_lvm_int_%s_list_val = newp;\n" typ;
+ pr "\n";
+ pr " /* Tokenize the next entry. */\n";
+ pr " r = lvm_tokenize_%s (p, &ret->guestfs_lvm_int_%s_list_val[i]);\n" typ typ;
+ pr " if (r == -1) {\n";
+ pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
+ pr " free (ret->guestfs_lvm_int_%s_list_val);\n" typ;
+ pr " free (ret);\n";
+ pr " free (out);\n";
+ pr " return NULL;\n";
+ pr " }\n";
+ pr "\n";
+ pr " ++i;\n";
+ pr " p = pend;\n";
+ pr " }\n";
+ pr "\n";
+ pr " ret->guestfs_lvm_int_%s_list_len = i;\n" typ;
+ pr "\n";
+ pr " free (out);\n";
+ pr " return ret;\n";
+ pr "}\n"
+
+ ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
(* Generate a lot of different functions for guestfish. *)
and generate_fish_cmds () =
@@ -611,7 +1022,9 @@ and generate_fish_cmds () =
pr "#include <stdio.h>\n";
pr "#include <stdlib.h>\n";
pr "#include <string.h>\n";
+ pr "#include <inttypes.h>\n";
pr "\n";
+ pr "#include <guestfs.h>\n";
pr "#include \"fish.h\"\n";
pr "\n";
@@ -669,6 +1082,45 @@ FTP."
pr "}\n";
pr "\n";
+ (* print_{pv,vg,lv}_list functions *)
+ List.iter (
+ function
+ | typ, cols ->
+ pr "static void print_%s (struct guestfs_lvm_%s *%s)\n" typ typ typ;
+ pr "{\n";
+ pr " int i;\n";
+ pr "\n";
+ List.iter (
+ function
+ | name, `String ->
+ pr " printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
+ | name, `UUID ->
+ pr " printf (\"%s: \");\n" name;
+ pr " for (i = 0; i < 32; ++i)\n";
+ pr " printf (\"%%c\", %s->%s[i]);\n" typ name;
+ pr " printf (\"\\n\");\n"
+ | name, `Bytes ->
+ pr " printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
+ | name, `Int ->
+ pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
+ | name, `OptPercent ->
+ pr " if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
+ typ name name typ name;
+ pr " else printf (\"%s: \\n\");\n" name
+ ) cols;
+ pr "}\n";
+ pr "\n";
+ pr "static void print_%s_list (struct guestfs_lvm_%s_list *%ss)\n"
+ typ typ typ;
+ pr "{\n";
+ pr " int i;\n";
+ pr "\n";
+ pr " for (i = 0; i < %ss->len; ++i)\n" typ;
+ pr " print_%s (&%ss->val[i]);\n" typ typ;
+ pr "}\n";
+ pr "\n";
+ ) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
+
(* run_<action> actions *)
List.iter (
fun (name, style, _, _, _, _) ->
@@ -678,6 +1130,9 @@ FTP."
| Err -> pr " int r;\n"
| RString _ -> pr " char *r;\n"
| RStringList _ -> pr " char **r;\n"
+ | RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
+ | RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
+ | RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
);
iter_args (
function
@@ -716,6 +1171,21 @@ FTP."
pr " print_strings (r);\n";
pr " free_strings (r);\n";
pr " return 0;\n"
+ | RPVList _ ->
+ pr " if (r == NULL) return -1;\n";
+ pr " print_pv_list (r);\n";
+ pr " guestfs_free_lvm_pv_list (r);\n";
+ pr " return 0;\n"
+ | RVGList _ ->
+ pr " if (r == NULL) return -1;\n";
+ pr " print_vg_list (r);\n";
+ pr " guestfs_free_lvm_vg_list (r);\n";
+ pr " return 0;\n"
+ | RLVList _ ->
+ pr " if (r == NULL) return -1;\n";
+ pr " print_lv_list (r);\n";
+ pr " guestfs_free_lvm_lv_list (r);\n";
+ pr " return 0;\n"
);
pr "}\n";
pr "\n"
@@ -745,7 +1215,7 @@ FTP."
(* Generate a C function prototype. *)
and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
- ?(single_line = false) ?(newline = false)
+ ?(single_line = false) ?(newline = false) ?(in_daemon = false)
?handle name style =
if extern then pr "extern ";
if static then pr "static ";
@@ -753,6 +1223,15 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
| Err -> pr "int "
| RString _ -> pr "char *"
| RStringList _ -> pr "char **"
+ | RPVList _ ->
+ if not in_daemon then pr "struct guestfs_lvm_pv_list *"
+ else pr "guestfs_lvm_int_pv_list *"
+ | RVGList _ ->
+ if not in_daemon then pr "struct guestfs_lvm_vg_list *"
+ else pr "guestfs_lvm_int_vg_list *"
+ | RLVList _ ->
+ if not in_daemon then pr "struct guestfs_lvm_lv_list *"
+ else pr "guestfs_lvm_int_lv_list *"
);
pr "%s (" name;
let comma = ref false in
@@ -810,6 +1289,10 @@ let () =
generate_xdr ();
close ();
+ let close = output_to "src/guestfs-structs.h" in
+ generate_structs_h ();
+ close ();
+
let close = output_to "src/guestfs-actions.h" in
generate_actions_h ();
close ();
@@ -830,6 +1313,10 @@ let () =
generate_fish_cmds ();
close ();
+ let close = output_to "guestfs-structs.pod" in
+ generate_structs_pod ();
+ close ();
+
let close = output_to "guestfs-actions.pod" in
- generate_pod ();
+ generate_actions_pod ();
close ()
diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c
index d2ec0c76..83f5ec15 100644
--- a/src/guestfs-actions.c
+++ b/src/guestfs-actions.c
@@ -595,3 +595,216 @@ 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);
+}
+
+struct guestfs_lvm_pv_list *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 */
+ return safe_memdup (g, &rv.ret.physvols, sizeof (rv.ret.physvols));
+}
+
+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);
+}
+
+struct guestfs_lvm_vg_list *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 */
+ return safe_memdup (g, &rv.ret.volgroups, sizeof (rv.ret.volgroups));
+}
+
+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);
+}
+
+struct guestfs_lvm_lv_list *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 */
+ return safe_memdup (g, &rv.ret.logvols, sizeof (rv.ret.logvols));
+}
+
diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h
index 7019d988..d48cd9bf 100644
--- a/src/guestfs-actions.h
+++ b/src/guestfs-actions.h
@@ -27,3 +27,6 @@ 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 struct guestfs_lvm_pv_list *guestfs_pvs (guestfs_h *handle);
+extern struct guestfs_lvm_vg_list *guestfs_vgs (guestfs_h *handle);
+extern struct guestfs_lvm_lv_list *guestfs_lvs (guestfs_h *handle);
diff --git a/src/guestfs-structs.h b/src/guestfs-structs.h
new file mode 100644
index 00000000..45ce1316
--- /dev/null
+++ b/src/guestfs-structs.h
@@ -0,0 +1,94 @@
+/* libguestfs generated file
+ * WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.
+ * ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+struct guestfs_lvm_pv {
+ char *pv_name;
+ char pv_uuid[32]; /* this is NOT nul-terminated, be careful when printing */
+ char *pv_fmt;
+ uint64_t pv_size;
+ uint64_t dev_size;
+ uint64_t pv_free;
+ uint64_t pv_used;
+ char *pv_attr;
+ int64_t pv_pe_count;
+ int64_t pv_pe_alloc_count;
+ char *pv_tags;
+ uint64_t pe_start;
+ int64_t pv_mda_count;
+ uint64_t pv_mda_free;
+};
+
+struct guestfs_lvm_pv_list {
+ uint32_t len;
+ struct guestfs_lvm_pv *val;
+};
+
+struct guestfs_lvm_vg {
+ char *vg_name;
+ char vg_uuid[32]; /* this is NOT nul-terminated, be careful when printing */
+ char *vg_fmt;
+ char *vg_attr;
+ uint64_t vg_size;
+ uint64_t vg_free;
+ char *vg_sysid;
+ uint64_t vg_extent_size;
+ int64_t vg_extent_count;
+ int64_t vg_free_count;
+ int64_t max_lv;
+ int64_t max_pv;
+ int64_t pv_count;
+ int64_t lv_count;
+ int64_t snap_count;
+ int64_t vg_seqno;
+ char *vg_tags;
+ int64_t vg_mda_count;
+ uint64_t vg_mda_free;
+};
+
+struct guestfs_lvm_vg_list {
+ uint32_t len;
+ struct guestfs_lvm_vg *val;
+};
+
+struct guestfs_lvm_lv {
+ char *lv_name;
+ char lv_uuid[32]; /* this is NOT nul-terminated, be careful when printing */
+ char *lv_attr;
+ int64_t lv_major;
+ int64_t lv_minor;
+ int64_t lv_kernel_major;
+ int64_t lv_kernel_minor;
+ uint64_t lv_size;
+ int64_t seg_count;
+ char *origin;
+ float snap_percent; /* [0..100] or -1 */
+ float copy_percent; /* [0..100] or -1 */
+ char *move_pv;
+ char *lv_tags;
+ char *mirror_log;
+ char *modules;
+};
+
+struct guestfs_lvm_lv_list {
+ uint32_t len;
+ struct guestfs_lvm_lv *val;
+};
+
diff --git a/src/guestfs.c b/src/guestfs.c
index 3492c624..092e405e 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -58,9 +58,10 @@
static void error (guestfs_h *g, const char *fs, ...);
static void perrorf (guestfs_h *g, const char *fs, ...);
-static void *safe_malloc (guestfs_h *g, int nbytes);
+static void *safe_malloc (guestfs_h *g, size_t nbytes);
static void *safe_realloc (guestfs_h *g, void *ptr, int nbytes);
static char *safe_strdup (guestfs_h *g, const char *str);
+static void *safe_memdup (guestfs_h *g, void *ptr, size_t size);
static void default_error_cb (guestfs_h *g, void *data, const char *msg);
static void stdout_event (void *data, int watch, int fd, int events);
@@ -328,7 +329,7 @@ perrorf (guestfs_h *g, const char *fs, ...)
}
static void *
-safe_malloc (guestfs_h *g, int nbytes)
+safe_malloc (guestfs_h *g, size_t nbytes)
{
void *ptr = malloc (nbytes);
if (!ptr) g->abort_cb ();
@@ -351,6 +352,15 @@ safe_strdup (guestfs_h *g, const char *str)
return s;
}
+static void *
+safe_memdup (guestfs_h *g, void *ptr, size_t size)
+{
+ void *p = malloc (size);
+ if (!p) g->abort_cb ();
+ memcpy (p, ptr, size);
+ return p;
+}
+
void
guestfs_set_out_of_memory_handler (guestfs_h *g, guestfs_abort_cb cb)
{
@@ -1019,6 +1029,28 @@ sock_read_event (void *data, int watch, int fd, int events)
goto cleanup;
}
+ /* Got the full message, begin processing it. */
+ if (g->verbose) {
+ int i, j;
+
+ for (i = 0; i < g->msg_in_size; i += 16) {
+ printf ("%04x: ", i);
+ for (j = i; j < MIN (i+16, g->msg_in_size); ++j)
+ printf ("%02x ", (unsigned char) g->msg_in[j]);
+ for (; j < i+16; ++j)
+ printf (" ");
+ printf ("|");
+ for (j = i; j < MIN (i+16, g->msg_in_size); ++j)
+ if (isprint (g->msg_in[j]))
+ printf ("%c", g->msg_in[j]);
+ else
+ printf (".");
+ for (; j < i+16; ++j)
+ printf (" ");
+ printf ("|\n");
+ }
+ }
+
/* Not in the expected state. */
if (g->state != BUSY)
error (g, "state %d != BUSY", g->state);
@@ -1231,6 +1263,31 @@ check_reply_header (guestfs_h *g,
*/
#include "guestfs-actions.c"
+/* Structure-freeing functions. These rely on the fact that the
+ * structure format is identical to the XDR format. See note in
+ * generator.ml.
+ */
+void
+guestfs_free_lvm_pv_list (struct guestfs_lvm_pv_list *x)
+{
+ xdr_free ((xdrproc_t) xdr_guestfs_lvm_int_pv_list, (char *) x);
+ free (x);
+}
+
+void
+guestfs_free_lvm_vg_list (struct guestfs_lvm_vg_list *x)
+{
+ xdr_free ((xdrproc_t) xdr_guestfs_lvm_int_vg_list, (char *) x);
+ free (x);
+}
+
+void
+guestfs_free_lvm_lv_list (struct guestfs_lvm_lv_list *x)
+{
+ xdr_free ((xdrproc_t) xdr_guestfs_lvm_int_lv_list, (char *) x);
+ free (x);
+}
+
/* This is the default main loop implementation, using select(2). */
struct handle_cb_data {
diff --git a/src/guestfs.h b/src/guestfs.h
index 575e0c72..cbe2c82c 100644
--- a/src/guestfs.h
+++ b/src/guestfs.h
@@ -59,8 +59,13 @@ extern int guestfs_get_autosync (guestfs_h *g);
extern void guestfs_set_path (guestfs_h *g, const char *path);
extern const char *guestfs_get_path (guestfs_h *g);
+#include <guestfs-structs.h>
#include <guestfs-actions.h>
+extern void guestfs_free_lvm_pv_list (struct guestfs_lvm_pv_list *);
+extern void guestfs_free_lvm_vg_list (struct guestfs_lvm_vg_list *);
+extern void guestfs_free_lvm_lv_list (struct guestfs_lvm_lv_list *);
+
/* Low-level event API. */
typedef void (*guestfs_reply_cb) (guestfs_h *g, void *data, XDR *xdr);
typedef void (*guestfs_log_message_cb) (guestfs_h *g, void *data, char *buf, int len);
diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c
index 80f618b1..dfdd0d8b 100644
--- a/src/guestfs_protocol.c
+++ b/src/guestfs_protocol.c
@@ -16,6 +16,164 @@ xdr_str (XDR *xdrs, str *objp)
}
bool_t
+xdr_guestfs_lvm_int_pv (XDR *xdrs, guestfs_lvm_int_pv *objp)
+{
+ register int32_t *buf;
+
+ int i;
+ if (!xdr_string (xdrs, &objp->pv_name, ~0))
+ return FALSE;
+ if (!xdr_opaque (xdrs, objp->pv_uuid, 32))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->pv_fmt, ~0))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->pv_size))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->dev_size))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->pv_free))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->pv_used))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->pv_attr, ~0))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->pv_pe_count))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->pv_pe_alloc_count))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->pv_tags, ~0))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->pe_start))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->pv_mda_count))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->pv_mda_free))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_lvm_int_pv_list (XDR *xdrs, guestfs_lvm_int_pv_list *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_array (xdrs, (char **)&objp->guestfs_lvm_int_pv_list_val, (u_int *) &objp->guestfs_lvm_int_pv_list_len, ~0,
+ sizeof (guestfs_lvm_int_pv), (xdrproc_t) xdr_guestfs_lvm_int_pv))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_lvm_int_vg (XDR *xdrs, guestfs_lvm_int_vg *objp)
+{
+ register int32_t *buf;
+
+ int i;
+ if (!xdr_string (xdrs, &objp->vg_name, ~0))
+ return FALSE;
+ if (!xdr_opaque (xdrs, objp->vg_uuid, 32))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->vg_fmt, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->vg_attr, ~0))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->vg_size))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->vg_free))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->vg_sysid, ~0))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->vg_extent_size))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->vg_extent_count))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->vg_free_count))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->max_lv))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->max_pv))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->pv_count))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->lv_count))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->snap_count))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->vg_seqno))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->vg_tags, ~0))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->vg_mda_count))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->vg_mda_free))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_lvm_int_vg_list (XDR *xdrs, guestfs_lvm_int_vg_list *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_array (xdrs, (char **)&objp->guestfs_lvm_int_vg_list_val, (u_int *) &objp->guestfs_lvm_int_vg_list_len, ~0,
+ sizeof (guestfs_lvm_int_vg), (xdrproc_t) xdr_guestfs_lvm_int_vg))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_lvm_int_lv (XDR *xdrs, guestfs_lvm_int_lv *objp)
+{
+ register int32_t *buf;
+
+ int i;
+ if (!xdr_string (xdrs, &objp->lv_name, ~0))
+ return FALSE;
+ if (!xdr_opaque (xdrs, objp->lv_uuid, 32))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->lv_attr, ~0))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->lv_major))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->lv_minor))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->lv_kernel_major))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->lv_kernel_minor))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->lv_size))
+ return FALSE;
+ if (!xdr_quad_t (xdrs, &objp->seg_count))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->origin, ~0))
+ return FALSE;
+ if (!xdr_float (xdrs, &objp->snap_percent))
+ return FALSE;
+ if (!xdr_float (xdrs, &objp->copy_percent))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->move_pv, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->lv_tags, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->mirror_log, ~0))
+ return FALSE;
+ if (!xdr_string (xdrs, &objp->modules, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_lvm_int_lv_list (XDR *xdrs, guestfs_lvm_int_lv_list *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_array (xdrs, (char **)&objp->guestfs_lvm_int_lv_list_val, (u_int *) &objp->guestfs_lvm_int_lv_list_len, ~0,
+ sizeof (guestfs_lvm_int_lv), (xdrproc_t) xdr_guestfs_lvm_int_lv))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_guestfs_mount_args (XDR *xdrs, guestfs_mount_args *objp)
{
register int32_t *buf;
@@ -121,6 +279,36 @@ 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_guestfs_lvm_int_pv_list (xdrs, &objp->physvols))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_vgs_ret (XDR *xdrs, guestfs_vgs_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_guestfs_lvm_int_vg_list (xdrs, &objp->volgroups))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_guestfs_lvs_ret (XDR *xdrs, guestfs_lvs_ret *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_guestfs_lvm_int_lv_list (xdrs, &objp->logvols))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
{
register int32_t *buf;
diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h
index 3e192127..a168e43a 100644
--- a/src/guestfs_protocol.h
+++ b/src/guestfs_protocol.h
@@ -16,6 +16,82 @@ extern "C" {
typedef char *str;
+struct guestfs_lvm_int_pv {
+ char *pv_name;
+ char pv_uuid[32];
+ char *pv_fmt;
+ quad_t pv_size;
+ quad_t dev_size;
+ quad_t pv_free;
+ quad_t pv_used;
+ char *pv_attr;
+ quad_t pv_pe_count;
+ quad_t pv_pe_alloc_count;
+ char *pv_tags;
+ quad_t pe_start;
+ quad_t pv_mda_count;
+ quad_t pv_mda_free;
+};
+typedef struct guestfs_lvm_int_pv guestfs_lvm_int_pv;
+
+typedef struct {
+ u_int guestfs_lvm_int_pv_list_len;
+ guestfs_lvm_int_pv *guestfs_lvm_int_pv_list_val;
+} guestfs_lvm_int_pv_list;
+
+struct guestfs_lvm_int_vg {
+ char *vg_name;
+ char vg_uuid[32];
+ char *vg_fmt;
+ char *vg_attr;
+ quad_t vg_size;
+ quad_t vg_free;
+ char *vg_sysid;
+ quad_t vg_extent_size;
+ quad_t vg_extent_count;
+ quad_t vg_free_count;
+ quad_t max_lv;
+ quad_t max_pv;
+ quad_t pv_count;
+ quad_t lv_count;
+ quad_t snap_count;
+ quad_t vg_seqno;
+ char *vg_tags;
+ quad_t vg_mda_count;
+ quad_t vg_mda_free;
+};
+typedef struct guestfs_lvm_int_vg guestfs_lvm_int_vg;
+
+typedef struct {
+ u_int guestfs_lvm_int_vg_list_len;
+ guestfs_lvm_int_vg *guestfs_lvm_int_vg_list_val;
+} guestfs_lvm_int_vg_list;
+
+struct guestfs_lvm_int_lv {
+ char *lv_name;
+ char lv_uuid[32];
+ char *lv_attr;
+ quad_t lv_major;
+ quad_t lv_minor;
+ quad_t lv_kernel_major;
+ quad_t lv_kernel_minor;
+ quad_t lv_size;
+ quad_t seg_count;
+ char *origin;
+ float snap_percent;
+ float copy_percent;
+ char *move_pv;
+ char *lv_tags;
+ char *mirror_log;
+ char *modules;
+};
+typedef struct guestfs_lvm_int_lv guestfs_lvm_int_lv;
+
+typedef struct {
+ u_int guestfs_lvm_int_lv_list_len;
+ guestfs_lvm_int_lv *guestfs_lvm_int_lv_list_val;
+} guestfs_lvm_int_lv_list;
+
struct guestfs_mount_args {
char *device;
char *mountpoint;
@@ -76,6 +152,21 @@ struct guestfs_list_partitions_ret {
};
typedef struct guestfs_list_partitions_ret guestfs_list_partitions_ret;
+struct guestfs_pvs_ret {
+ guestfs_lvm_int_pv_list physvols;
+};
+typedef struct guestfs_pvs_ret guestfs_pvs_ret;
+
+struct guestfs_vgs_ret {
+ guestfs_lvm_int_vg_list volgroups;
+};
+typedef struct guestfs_vgs_ret guestfs_vgs_ret;
+
+struct guestfs_lvs_ret {
+ guestfs_lvm_int_lv_list logvols;
+};
+typedef struct guestfs_lvs_ret guestfs_lvs_ret;
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
@@ -85,7 +176,10 @@ enum guestfs_procedure {
GUESTFS_PROC_LS = 6,
GUESTFS_PROC_LIST_DEVICES = 7,
GUESTFS_PROC_LIST_PARTITIONS = 8,
- GUESTFS_PROC_dummy = 8 + 1,
+ GUESTFS_PROC_PVS = 9,
+ GUESTFS_PROC_VGS = 10,
+ GUESTFS_PROC_LVS = 11,
+ GUESTFS_PROC_dummy = 11 + 1,
};
typedef enum guestfs_procedure guestfs_procedure;
#define GUESTFS_MESSAGE_MAX 4194304
@@ -124,6 +218,12 @@ typedef struct guestfs_message_header guestfs_message_header;
#if defined(__STDC__) || defined(__cplusplus)
extern bool_t xdr_str (XDR *, str*);
+extern bool_t xdr_guestfs_lvm_int_pv (XDR *, guestfs_lvm_int_pv*);
+extern bool_t xdr_guestfs_lvm_int_pv_list (XDR *, guestfs_lvm_int_pv_list*);
+extern bool_t xdr_guestfs_lvm_int_vg (XDR *, guestfs_lvm_int_vg*);
+extern bool_t xdr_guestfs_lvm_int_vg_list (XDR *, guestfs_lvm_int_vg_list*);
+extern bool_t xdr_guestfs_lvm_int_lv (XDR *, guestfs_lvm_int_lv*);
+extern bool_t xdr_guestfs_lvm_int_lv_list (XDR *, guestfs_lvm_int_lv_list*);
extern bool_t xdr_guestfs_mount_args (XDR *, guestfs_mount_args*);
extern bool_t xdr_guestfs_touch_args (XDR *, guestfs_touch_args*);
extern bool_t xdr_guestfs_cat_args (XDR *, guestfs_cat_args*);
@@ -134,6 +234,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_procedure (XDR *, guestfs_procedure*);
extern bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*);
extern bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*);
@@ -142,6 +245,12 @@ extern bool_t xdr_guestfs_message_header (XDR *, guestfs_message_header*);
#else /* K&R C */
extern bool_t xdr_str ();
+extern bool_t xdr_guestfs_lvm_int_pv ();
+extern bool_t xdr_guestfs_lvm_int_pv_list ();
+extern bool_t xdr_guestfs_lvm_int_vg ();
+extern bool_t xdr_guestfs_lvm_int_vg_list ();
+extern bool_t xdr_guestfs_lvm_int_lv ();
+extern bool_t xdr_guestfs_lvm_int_lv_list ();
extern bool_t xdr_guestfs_mount_args ();
extern bool_t xdr_guestfs_touch_args ();
extern bool_t xdr_guestfs_cat_args ();
@@ -152,6 +261,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_procedure ();
extern bool_t xdr_guestfs_message_direction ();
extern bool_t xdr_guestfs_message_status ();
diff --git a/src/guestfs_protocol.x b/src/guestfs_protocol.x
index be0efdbb..fedc6f2d 100644
--- a/src/guestfs_protocol.x
+++ b/src/guestfs_protocol.x
@@ -21,6 +21,70 @@
typedef string str<>;
+struct guestfs_lvm_int_pv {
+ string pv_name<>;
+ opaque pv_uuid[32];
+ string pv_fmt<>;
+ hyper pv_size;
+ hyper dev_size;
+ hyper pv_free;
+ hyper pv_used;
+ string pv_attr<>;
+ hyper pv_pe_count;
+ hyper pv_pe_alloc_count;
+ string pv_tags<>;
+ hyper pe_start;
+ hyper pv_mda_count;
+ hyper pv_mda_free;
+};
+
+typedef struct guestfs_lvm_int_pv guestfs_lvm_int_pv_list<>;
+
+struct guestfs_lvm_int_vg {
+ string vg_name<>;
+ opaque vg_uuid[32];
+ string vg_fmt<>;
+ string vg_attr<>;
+ hyper vg_size;
+ hyper vg_free;
+ string vg_sysid<>;
+ hyper vg_extent_size;
+ hyper vg_extent_count;
+ hyper vg_free_count;
+ hyper max_lv;
+ hyper max_pv;
+ hyper pv_count;
+ hyper lv_count;
+ hyper snap_count;
+ hyper vg_seqno;
+ string vg_tags<>;
+ hyper vg_mda_count;
+ hyper vg_mda_free;
+};
+
+typedef struct guestfs_lvm_int_vg guestfs_lvm_int_vg_list<>;
+
+struct guestfs_lvm_int_lv {
+ string lv_name<>;
+ opaque lv_uuid[32];
+ string lv_attr<>;
+ hyper lv_major;
+ hyper lv_minor;
+ hyper lv_kernel_major;
+ hyper lv_kernel_minor;
+ hyper lv_size;
+ hyper seg_count;
+ string origin<>;
+ float snap_percent;
+ float copy_percent;
+ string move_pv<>;
+ string lv_tags<>;
+ string mirror_log<>;
+ string modules<>;
+};
+
+typedef struct guestfs_lvm_int_lv guestfs_lvm_int_lv_list<>;
+
/* guestfs_mount */
struct guestfs_mount_args {
@@ -78,6 +142,24 @@ struct guestfs_list_partitions_ret {
str partitions<>;
};
+/* guestfs_pvs */
+
+struct guestfs_pvs_ret {
+ guestfs_lvm_int_pv_list physvols;
+};
+
+/* guestfs_vgs */
+
+struct guestfs_vgs_ret {
+ guestfs_lvm_int_vg_list volgroups;
+};
+
+/* guestfs_lvs */
+
+struct guestfs_lvs_ret {
+ guestfs_lvm_int_lv_list logvols;
+};
+
enum guestfs_procedure {
GUESTFS_PROC_MOUNT = 1,
GUESTFS_PROC_SYNC = 2,
@@ -87,6 +169,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_dummy
};