summaryrefslogtreecommitdiffstats
path: root/perl
diff options
context:
space:
mode:
authorRichard Jones <rjones@redhat.com>2009-04-08 13:44:13 +0100
committerRichard Jones <rjones@redhat.com>2009-04-08 13:44:13 +0100
commit1ee6da96efe8340a7d3904a865d80cd59d9d3fde (patch)
tree41b5b106d06c65d24bd8216b88005654abc0e98d /perl
parent8dcc88f867ab0bed24df49d8c0f347f1357bfffd (diff)
downloadlibguestfs-1ee6da96efe8340a7d3904a865d80cd59d9d3fde.tar.gz
libguestfs-1ee6da96efe8340a7d3904a865d80cd59d9d3fde.tar.xz
libguestfs-1ee6da96efe8340a7d3904a865d80cd59d9d3fde.zip
First version of Perl bindings, compiled but not tested.
Diffstat (limited to 'perl')
-rw-r--r--perl/Guestfs.xs361
-rw-r--r--perl/Makefile.PL.in28
-rw-r--r--perl/Makefile.am20
-rw-r--r--perl/lib/Sys/Guestfs.pm235
-rw-r--r--perl/typemap17
5 files changed, 661 insertions, 0 deletions
diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs
new file mode 100644
index 00000000..e3f17c25
--- /dev/null
+++ b/perl/Guestfs.xs
@@ -0,0 +1,361 @@
+/* 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
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <guestfs.h>
+
+/* #include cannot be used for local files in XS */
+
+#ifndef PRId64
+#define PRId64 "lld"
+#endif
+
+static SV *
+my_newSVll(long long val) {
+#ifdef USE_64_BIT_ALL
+ return newSViv(val);
+#else
+ char buf[100];
+ int len;
+ len = snprintf(buf, 100, "%" PRId64, val);
+ return newSVpv(buf, len);
+#endif
+}
+
+#ifndef PRIu64
+#define PRIu64 "llu"
+#endif
+
+static SV *
+my_newSVull(unsigned long long val) {
+#ifdef USE_64_BIT_ALL
+ return newSVuv(val);
+#else
+ char buf[100];
+ int len;
+ len = snprintf(buf, 100, "%" PRIu64, val);
+ return newSVpv(buf, len);
+#endif
+}
+
+/* XXX Not thread-safe, and in general not safe if the caller is
+ * issuing multiple requests in parallel (on different guestfs
+ * handles). We should use the guestfs_h handle passed to the
+ * error handle to distinguish these cases.
+ */
+static char *last_error = NULL;
+
+static void
+error_handler (guestfs_h *g,
+ void *data,
+ const char *msg)
+{
+ if (last_error != NULL) free (last_error);
+ last_error = strdup (msg);
+}
+
+MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
+
+guestfs_h *
+_create ()
+CODE:
+ RETVAL = guestfs_create ();
+ if (!RETVAL)
+ croak ("could not create guestfs handle");
+ guestfs_set_error_handler (RETVAL, error_handler, NULL);
+OUTPUT:
+ RETVAL
+
+void
+DESTROY (g)
+ guestfs_h *g;
+PPCODE:
+ guestfs_close (g);
+
+void
+mount (g, device, mountpoint)
+ guestfs_h *g;
+ char *device;
+ char *mountpoint;
+ PPCODE:
+ if (guestfs_mount (g, device, mountpoint) == -1)
+ croak ("mount: %s", last_error);
+
+void
+sync (g)
+ guestfs_h *g;
+ PPCODE:
+ if (guestfs_sync (g) == -1)
+ croak ("sync: %s", last_error);
+
+void
+touch (g, path)
+ guestfs_h *g;
+ char *path;
+ PPCODE:
+ if (guestfs_touch (g, path) == -1)
+ croak ("touch: %s", last_error);
+
+SV *
+cat (g, path)
+ guestfs_h *g;
+ char *path;
+PREINIT:
+ char *content;
+ CODE:
+ content = guestfs_cat (g, path);
+ if (content == NULL)
+ croak ("cat: %s", last_error);
+ RETVAL = newSVpv (content, 0);
+ free (content);
+ OUTPUT:
+ RETVAL
+
+SV *
+ll (g, directory)
+ guestfs_h *g;
+ char *directory;
+PREINIT:
+ char *listing;
+ CODE:
+ listing = guestfs_ll (g, directory);
+ if (listing == NULL)
+ croak ("ll: %s", last_error);
+ RETVAL = newSVpv (listing, 0);
+ free (listing);
+ OUTPUT:
+ RETVAL
+
+void
+ls (g, directory)
+ guestfs_h *g;
+ char *directory;
+PREINIT:
+ char **listing;
+ int i, n;
+ PPCODE:
+ listing = guestfs_ls (g, directory);
+ if (listing == NULL)
+ croak ("ls: %s", last_error);
+ for (n = 0; listing[n] != NULL; ++n) /**/;
+ EXTEND (SP, n);
+ for (i = 0; i < n; ++i) {
+ PUSHs (sv_2mortal (newSVpv (listing[i], 0)));
+ free (listing[i]);
+ }
+ free (listing);
+
+void
+list_devices (g)
+ guestfs_h *g;
+PREINIT:
+ char **devices;
+ int i, n;
+ PPCODE:
+ devices = guestfs_list_devices (g);
+ if (devices == NULL)
+ croak ("list_devices: %s", last_error);
+ for (n = 0; devices[n] != NULL; ++n) /**/;
+ EXTEND (SP, n);
+ for (i = 0; i < n; ++i) {
+ PUSHs (sv_2mortal (newSVpv (devices[i], 0)));
+ free (devices[i]);
+ }
+ free (devices);
+
+void
+list_partitions (g)
+ guestfs_h *g;
+PREINIT:
+ char **partitions;
+ int i, n;
+ PPCODE:
+ partitions = guestfs_list_partitions (g);
+ if (partitions == NULL)
+ croak ("list_partitions: %s", last_error);
+ for (n = 0; partitions[n] != NULL; ++n) /**/;
+ EXTEND (SP, n);
+ for (i = 0; i < n; ++i) {
+ PUSHs (sv_2mortal (newSVpv (partitions[i], 0)));
+ free (partitions[i]);
+ }
+ free (partitions);
+
+void
+pvs (g)
+ guestfs_h *g;
+PREINIT:
+ char **physvols;
+ int i, n;
+ PPCODE:
+ physvols = guestfs_pvs (g);
+ if (physvols == NULL)
+ croak ("pvs: %s", last_error);
+ for (n = 0; physvols[n] != NULL; ++n) /**/;
+ EXTEND (SP, n);
+ for (i = 0; i < n; ++i) {
+ PUSHs (sv_2mortal (newSVpv (physvols[i], 0)));
+ free (physvols[i]);
+ }
+ free (physvols);
+
+void
+vgs (g)
+ guestfs_h *g;
+PREINIT:
+ char **volgroups;
+ int i, n;
+ PPCODE:
+ volgroups = guestfs_vgs (g);
+ if (volgroups == NULL)
+ croak ("vgs: %s", last_error);
+ for (n = 0; volgroups[n] != NULL; ++n) /**/;
+ EXTEND (SP, n);
+ for (i = 0; i < n; ++i) {
+ PUSHs (sv_2mortal (newSVpv (volgroups[i], 0)));
+ free (volgroups[i]);
+ }
+ free (volgroups);
+
+void
+lvs (g)
+ guestfs_h *g;
+PREINIT:
+ char **logvols;
+ int i, n;
+ PPCODE:
+ logvols = guestfs_lvs (g);
+ if (logvols == NULL)
+ croak ("lvs: %s", last_error);
+ for (n = 0; logvols[n] != NULL; ++n) /**/;
+ EXTEND (SP, n);
+ for (i = 0; i < n; ++i) {
+ PUSHs (sv_2mortal (newSVpv (logvols[i], 0)));
+ free (logvols[i]);
+ }
+ free (logvols);
+
+void
+pvs_full (g)
+ guestfs_h *g;
+PREINIT:
+ struct guestfs_lvm_pv_list *physvols;
+ int i;
+ HV *hv;
+ PPCODE:
+ physvols = guestfs_pvs_full (g);
+ if (physvols == NULL)
+ croak ("pvs_full: %s", last_error);
+ EXTEND (SP, physvols->len);
+ for (i = 0; i < physvols->len; ++i) {
+ hv = newHV ();
+ (void) hv_store (hv, "pv_name", 7, newSVpv (physvols->val[i].pv_name, 0), 0);
+ (void) hv_store (hv, "pv_uuid", 7, newSVpv (physvols->val[i].pv_uuid, 32), 0);
+ (void) hv_store (hv, "pv_fmt", 6, newSVpv (physvols->val[i].pv_fmt, 0), 0);
+ (void) hv_store (hv, "pv_size", 7, my_newSVull (physvols->val[i].pv_size), 0);
+ (void) hv_store (hv, "dev_size", 8, my_newSVull (physvols->val[i].dev_size), 0);
+ (void) hv_store (hv, "pv_free", 7, my_newSVull (physvols->val[i].pv_free), 0);
+ (void) hv_store (hv, "pv_used", 7, my_newSVull (physvols->val[i].pv_used), 0);
+ (void) hv_store (hv, "pv_attr", 7, newSVpv (physvols->val[i].pv_attr, 0), 0);
+ (void) hv_store (hv, "pv_pe_count", 11, my_newSVll (physvols->val[i].pv_pe_count), 0);
+ (void) hv_store (hv, "pv_pe_alloc_count", 17, my_newSVll (physvols->val[i].pv_pe_alloc_count), 0);
+ (void) hv_store (hv, "pv_tags", 7, newSVpv (physvols->val[i].pv_tags, 0), 0);
+ (void) hv_store (hv, "pe_start", 8, my_newSVull (physvols->val[i].pe_start), 0);
+ (void) hv_store (hv, "pv_mda_count", 12, my_newSVll (physvols->val[i].pv_mda_count), 0);
+ (void) hv_store (hv, "pv_mda_free", 11, my_newSVull (physvols->val[i].pv_mda_free), 0);
+ PUSHs (sv_2mortal ((SV *) hv));
+ }
+ guestfs_free_lvm_pv_list (physvols);
+
+void
+vgs_full (g)
+ guestfs_h *g;
+PREINIT:
+ struct guestfs_lvm_vg_list *volgroups;
+ int i;
+ HV *hv;
+ PPCODE:
+ volgroups = guestfs_vgs_full (g);
+ if (volgroups == NULL)
+ croak ("vgs_full: %s", last_error);
+ EXTEND (SP, volgroups->len);
+ for (i = 0; i < volgroups->len; ++i) {
+ hv = newHV ();
+ (void) hv_store (hv, "vg_name", 7, newSVpv (volgroups->val[i].vg_name, 0), 0);
+ (void) hv_store (hv, "vg_uuid", 7, newSVpv (volgroups->val[i].vg_uuid, 32), 0);
+ (void) hv_store (hv, "vg_fmt", 6, newSVpv (volgroups->val[i].vg_fmt, 0), 0);
+ (void) hv_store (hv, "vg_attr", 7, newSVpv (volgroups->val[i].vg_attr, 0), 0);
+ (void) hv_store (hv, "vg_size", 7, my_newSVull (volgroups->val[i].vg_size), 0);
+ (void) hv_store (hv, "vg_free", 7, my_newSVull (volgroups->val[i].vg_free), 0);
+ (void) hv_store (hv, "vg_sysid", 8, newSVpv (volgroups->val[i].vg_sysid, 0), 0);
+ (void) hv_store (hv, "vg_extent_size", 14, my_newSVull (volgroups->val[i].vg_extent_size), 0);
+ (void) hv_store (hv, "vg_extent_count", 15, my_newSVll (volgroups->val[i].vg_extent_count), 0);
+ (void) hv_store (hv, "vg_free_count", 13, my_newSVll (volgroups->val[i].vg_free_count), 0);
+ (void) hv_store (hv, "max_lv", 6, my_newSVll (volgroups->val[i].max_lv), 0);
+ (void) hv_store (hv, "max_pv", 6, my_newSVll (volgroups->val[i].max_pv), 0);
+ (void) hv_store (hv, "pv_count", 8, my_newSVll (volgroups->val[i].pv_count), 0);
+ (void) hv_store (hv, "lv_count", 8, my_newSVll (volgroups->val[i].lv_count), 0);
+ (void) hv_store (hv, "snap_count", 10, my_newSVll (volgroups->val[i].snap_count), 0);
+ (void) hv_store (hv, "vg_seqno", 8, my_newSVll (volgroups->val[i].vg_seqno), 0);
+ (void) hv_store (hv, "vg_tags", 7, newSVpv (volgroups->val[i].vg_tags, 0), 0);
+ (void) hv_store (hv, "vg_mda_count", 12, my_newSVll (volgroups->val[i].vg_mda_count), 0);
+ (void) hv_store (hv, "vg_mda_free", 11, my_newSVull (volgroups->val[i].vg_mda_free), 0);
+ PUSHs (sv_2mortal ((SV *) hv));
+ }
+ guestfs_free_lvm_vg_list (volgroups);
+
+void
+lvs_full (g)
+ guestfs_h *g;
+PREINIT:
+ struct guestfs_lvm_lv_list *logvols;
+ int i;
+ HV *hv;
+ PPCODE:
+ logvols = guestfs_lvs_full (g);
+ if (logvols == NULL)
+ croak ("lvs_full: %s", last_error);
+ EXTEND (SP, logvols->len);
+ for (i = 0; i < logvols->len; ++i) {
+ hv = newHV ();
+ (void) hv_store (hv, "lv_name", 7, newSVpv (logvols->val[i].lv_name, 0), 0);
+ (void) hv_store (hv, "lv_uuid", 7, newSVpv (logvols->val[i].lv_uuid, 32), 0);
+ (void) hv_store (hv, "lv_attr", 7, newSVpv (logvols->val[i].lv_attr, 0), 0);
+ (void) hv_store (hv, "lv_major", 8, my_newSVll (logvols->val[i].lv_major), 0);
+ (void) hv_store (hv, "lv_minor", 8, my_newSVll (logvols->val[i].lv_minor), 0);
+ (void) hv_store (hv, "lv_kernel_major", 15, my_newSVll (logvols->val[i].lv_kernel_major), 0);
+ (void) hv_store (hv, "lv_kernel_minor", 15, my_newSVll (logvols->val[i].lv_kernel_minor), 0);
+ (void) hv_store (hv, "lv_size", 7, my_newSVull (logvols->val[i].lv_size), 0);
+ (void) hv_store (hv, "seg_count", 9, my_newSVll (logvols->val[i].seg_count), 0);
+ (void) hv_store (hv, "origin", 6, newSVpv (logvols->val[i].origin, 0), 0);
+ (void) hv_store (hv, "snap_percent", 12, newSVnv (logvols->val[i].snap_percent), 0);
+ (void) hv_store (hv, "copy_percent", 12, newSVnv (logvols->val[i].copy_percent), 0);
+ (void) hv_store (hv, "move_pv", 7, newSVpv (logvols->val[i].move_pv, 0), 0);
+ (void) hv_store (hv, "lv_tags", 7, newSVpv (logvols->val[i].lv_tags, 0), 0);
+ (void) hv_store (hv, "mirror_log", 10, newSVpv (logvols->val[i].mirror_log, 0), 0);
+ (void) hv_store (hv, "modules", 7, newSVpv (logvols->val[i].modules, 0), 0);
+ PUSHs (sv_2mortal ((SV *) hv));
+ }
+ guestfs_free_lvm_lv_list (logvols);
+
diff --git a/perl/Makefile.PL.in b/perl/Makefile.PL.in
new file mode 100644
index 00000000..423b4a18
--- /dev/null
+++ b/perl/Makefile.PL.in
@@ -0,0 +1,28 @@
+# libguestfs Perl bindings
+# 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.
+
+use ExtUtils::MakeMaker;
+
+WriteMakefile (
+ FIRST_MAKEFILE => 'Makefile-pl',
+
+ NAME => 'Sys::Guestfs',
+ VERSION => '@PACKAGE_VERSION@',
+
+ LIBS => '-L@abs_top_builddir@/src/.libs -lguestfs',
+ INC => '-Wall @CFLAGS@ -I@abs_top_builddir@/src',
+ );
diff --git a/perl/Makefile.am b/perl/Makefile.am
index 6b12064a..ea9835b0 100644
--- a/perl/Makefile.am
+++ b/perl/Makefile.am
@@ -14,3 +14,23 @@
# 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.
+
+EXTRA_DIST = \
+ Makefile.PL.in \
+ Guestfs.xs \
+ guestfs_perl.c \
+ typemap \
+ perl/lib/Sys/Guestfs.pm
+
+if HAVE_PERL
+
+# Interfacing automake and ExtUtils::MakeMaker known to be
+# a nightmare, news at 11.
+all:
+ perl Makefile.PL
+ make -f Makefile-pl
+
+install-data-hook:
+ make -f Makefile-pl DESTDIR=$(DESTDIR) install
+
+endif
diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm
new file mode 100644
index 00000000..c0a9b79f
--- /dev/null
+++ b/perl/lib/Sys/Guestfs.pm
@@ -0,0 +1,235 @@
+# 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
+
+=pod
+
+=head1 NAME
+
+Sys::Guestfs - Perl bindings for libguestfs
+
+=head1 SYNOPSIS
+
+ use Sys::Guestfs;
+
+ my $h = Sys::Guestfs->new ();
+ $h->add_drive ('guest.img');
+ $h->launch ();
+ $h->wait_ready ();
+ $h->mount ('/dev/sda1', '/');
+ $h->touch ('/hello');
+ $h->sync ();
+
+=head1 DESCRIPTION
+
+The C<Sys::Guestfs> module provides a Perl XS binding to the
+libguestfs API for examining and modifying virtual machine
+disk images.
+
+Amongst the things this is good for: making batch configuration
+changes to guests, getting disk used/free statistics (see also:
+virt-df), migrating between virtualization systems (see also:
+virt-p2v), performing partial backups, performing partial guest
+clones, cloning guests and changing registry/UUID/hostname info, and
+much else besides.
+
+Libguestfs uses Linux kernel and qemu code, and can access any type of
+guest filesystem that Linux and qemu can, including but not limited
+to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
+schemes, qcow, qcow2, vmdk.
+
+Libguestfs provides ways to enumerate guest storage (eg. partitions,
+LVs, what filesystem is in each LV, etc.). It can also run commands
+in the context of the guest. Also you can access filesystems over FTP.
+
+=head1 ERRORS
+
+All errors turn into calls to C<croak> (see L<Carp(3)>).
+
+=head1 METHODS
+
+=over 4
+
+=cut
+
+package Sys::Guestfs;
+
+use strict;
+use warnings;
+
+require XSLoader;
+XSLoader::load ('Sys::Guestfs');
+
+=item $h = Sys::Guestfs->new ();
+
+Create a new guestfs handle.
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref ($proto) || $proto;
+
+ my $self = Sys::Guestfs::_create ();
+ bless $self, $class;
+ return $self;
+}
+
+=item $content = $h->cat (path);
+
+Return the contents of the file named C<path>.
+
+Note that this function cannot correctly handle binary files
+(specifically, files containing C<\0> character which is treated
+as end of string). For those you need to use the C<$h-E<gt>read_file>
+function which has a more complex interface.
+
+Because of the message protocol, there is a transfer limit
+of somewhere between 2MB and 4MB. To transfer large files you should use
+FTP.
+
+=item @devices = $h->list_devices ();
+
+List all the block devices.
+
+The full block device names are returned, eg. C</dev/sda>
+
+=item @partitions = $h->list_partitions ();
+
+List all the partitions detected on all block devices.
+
+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<$h-E<gt>lvs>.
+
+=item $listing = $h->ll (directory);
+
+List the files in C<directory> (relative to the root directory,
+there is no cwd) in the format of 'ls -la'.
+
+This command is mostly useful for interactive sessions. It
+is I<not> intended that you try to parse the output string.
+
+=item @listing = $h->ls (directory);
+
+List the files in C<directory> (relative to the root directory,
+there is no cwd). The '.' and '..' entries are not returned, but
+hidden files are shown.
+
+This command is mostly useful for interactive sessions. Programs
+should probably use C<$h-E<gt>readdir> instead.
+
+=item @logvols = $h->lvs ();
+
+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<$h-E<gt>lvs_full>.
+
+=item @logvols = $h->lvs_full ();
+
+List all the logical volumes detected. This is the equivalent
+of the L<lvs(8)> command. The "full" version includes all fields.
+
+=item $h->mount (device, mountpoint);
+
+Mount a guest disk at a position in the filesystem. Block devices
+are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
+the guest. If those block devices contain partitions, they will have
+the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
+names can be used.
+
+The rules are the same as for L<mount(2)>: A filesystem must
+first be mounted on C</> before others can be mounted. Other
+filesystems can only be mounted on directories which already
+exist.
+
+The mounted filesystem is writable, if we have sufficient permissions
+on the underlying device.
+
+The filesystem options C<sync> and C<noatime> are set with this
+call, in order to improve reliability.
+
+=item @physvols = $h->pvs ();
+
+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<$h-E<gt>pvs_full>.
+
+=item @physvols = $h->pvs_full ();
+
+List all the physical volumes detected. This is the equivalent
+of the L<pvs(8)> command. The "full" version includes all fields.
+
+=item $h->sync ();
+
+This syncs the disk, so that any writes are flushed through to the
+underlying disk image.
+
+You should always call this if you have modified a disk image, before
+closing the handle.
+
+=item $h->touch (path);
+
+Touch acts like the L<touch(1)> command. It can be used to
+update the timestamps on a file, or, if the file does not exist,
+to create a new zero-length file.
+
+=item @volgroups = $h->vgs ();
+
+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<$h-E<gt>vgs_full>.
+
+=item @volgroups = $h->vgs_full ();
+
+List all the volumes groups detected. This is the equivalent
+of the L<vgs(8)> command. The "full" version includes all fields.
+
+=cut
+
+1;
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright (C) 2009 Red Hat Inc.
+
+=head1 LICENSE
+
+Please see the file COPYING.LIB for the full license.
+
+=head1 SEE ALSO
+
+L<guestfs(3)>, L<guestfish(1)>.
+
+=cut
diff --git a/perl/typemap b/perl/typemap
new file mode 100644
index 00000000..421e73a2
--- /dev/null
+++ b/perl/typemap
@@ -0,0 +1,17 @@
+TYPEMAP
+char * T_PV
+const char * T_PV
+guestfs_h * O_OBJECT_guestfs_h
+
+INPUT
+O_OBJECT_guestfs_h
+ if (sv_isobject ($arg) && SvTYPE (SvRV ($arg)) == SVt_PVMG)
+ $var = ($type) SvIV ((SV *) SvRV ($arg));
+ else {
+ warn (\"${Package}::$func_name(): $var is not a blessed SV reference\");
+ XSRETURN_UNDEF;
+ }
+
+OUTPUT
+O_OBJECT_guestfs_h
+ sv_setref_pv ($arg, "Sys::Guestfs", (void *) $var);