Ruby bindings.
authorRichard Jones <rjones@redhat.com>
Thu, 16 Apr 2009 21:13:20 +0000 (22:13 +0100)
committerRichard Jones <rjones@redhat.com>
Thu, 16 Apr 2009 21:13:20 +0000 (22:13 +0100)
16 files changed:
.gitignore
Makefile.am
README
TODO
configure.ac
daemon/configure.ac
libguestfs.spec.in
ruby/Makefile.am [new file with mode: 0644]
ruby/Rakefile.in [new file with mode: 0644]
ruby/ext/guestfs/_guestfs.c [new file with mode: 0644]
ruby/ext/guestfs/extconf.rb [new file with mode: 0644]
ruby/lib/guestfs.rb [new file with mode: 0644]
ruby/run-ruby-tests [new file with mode: 0755]
ruby/tests/tc_010_load.rb [new file with mode: 0644]
ruby/tests/tc_050_lvcreate.rb [new file with mode: 0644]
src/generator.ml

index 1b11a24..174489e 100644 (file)
@@ -63,6 +63,9 @@ perl/Makefile.PL
 perl/blib
 perl/pm_to_blib
 python/guestfs.pyc
+ruby/Rakefile
+ruby/ext/guestfs/extconf.h
+ruby/ext/guestfs/mkmf.log
 pod2htm?.tmp
 stamp-h1
 test*.img
index f6289e4..710e39d 100644 (file)
@@ -28,6 +28,9 @@ endif
 if HAVE_PYTHON
 SUBDIRS += python
 endif
+if HAVE_RUBY
+SUBDIRS += ruby
+endif
 
 EXTRA_DIST = \
        make-initramfs.sh update-initramfs.sh \
diff --git a/README b/README
index 2db1725..ec05bdd 100644 (file)
--- a/README
+++ b/README
@@ -50,6 +50,8 @@ also to build the OCaml bindings
 
 - (Optional) Python if you want to build the python bindings
 
+- (Optional) Ruby, rake if you want to build the ruby bindings
+
 Running ./configure will check you have all the requirements installed
 on your machine.
 
diff --git a/TODO b/TODO
index 3655b70..17829c2 100644 (file)
--- a/TODO
+++ b/TODO
@@ -3,10 +3,6 @@ https://www.redhat.com/archives/fedora-virt/2009-April/msg00114.html
 
 ----------------------------------------------------------------------
 
-Several people have asked for Ruby bindings.
-
-----------------------------------------------------------------------
-
 We badly need to actually implement the FTP server mentioned in the
 documentation.
 
index ad9361c..a771cdf 100644 (file)
@@ -15,7 +15,7 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-AC_INIT([libguestfs],[0.9.9])
+AC_INIT([libguestfs],[1.0.0])
 AM_INIT_AUTOMAKE
 
 AC_CONFIG_MACRO_DIR([m4])
@@ -188,7 +188,16 @@ AC_SUBST(PYTHON_INCLUDEDIR)
 AC_SUBST(PYTHON_SITE_PACKAGES)
 
 AM_CONDITIONAL([HAVE_PYTHON],
-    [test "x$PYTHON_INCLUDEDIR" != "x" && test "x$PYTHON_SITE_PACKAGES" != "x"])
+    [test "x$PYTHON_INCLUDEDIR" != "x" -a "x$PYTHON_SITE_PACKAGES" != "x"])
+
+dnl Check for Ruby and rake (optional, for Ruby bindings).
+old_libs="$LIBS"
+AC_CHECK_LIB([ruby],[ruby_init])
+LIBS="$old_libs"
+AC_CHECK_PROG([RAKE],[rake],[rake],[no])
+
+AM_CONDITIONAL([HAVE_RUBY],
+    [test "x$RAKE" != "xno" -a -n "x$HAVE_LIBRUBY"])
 
 dnl Run in subdirs.
 AC_CONFIG_SUBDIRS([daemon])
@@ -200,6 +209,7 @@ AC_CONFIG_FILES([Makefile src/Makefile fish/Makefile examples/Makefile
                 ocaml/Makefile ocaml/examples/Makefile
                 perl/Makefile
                 python/Makefile
+                ruby/Makefile ruby/Rakefile
                 make-initramfs.sh update-initramfs.sh
                 libguestfs.spec
                 ocaml/META perl/Makefile.PL])
index 8edcb2d..0bd37b0 100644 (file)
@@ -15,7 +15,7 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-AC_INIT([libguestfs-daemon],[0.8.2])
+AC_INIT([libguestfs-daemon],[1.0.0])
 AM_INIT_AUTOMAKE
 
 AC_CONFIG_MACRO_DIR([m4])
index fc70b01..c1e3e49 100644 (file)
@@ -35,6 +35,8 @@ BuildRequires: perl-Test-Pod
 BuildRequires: perl-Test-Pod-Coverage
 BuildRequires: perl-ExtUtils-MakeMaker
 BuildRequires: python-devel
+BuildRequires: ruby-devel
+BuildRequires: rubygem-rake
 
 # Runtime requires:
 Requires:    qemu >= 0.10-7
@@ -70,6 +72,8 @@ For OCaml bindings, see 'libguestfs-ocaml-devel'.
 
 For Python bindings, see 'libguestfs-python'.
 
+For Ruby bindings, see 'libguestfs-ruby'.
+
 
 %package devel
 Summary:     Development tools and libraries for %{name}
@@ -143,6 +147,20 @@ Requires:    %{name} = %{version}-%{release}
 %{name}-python contains Python bindings for %{name}.
 
 
+%package ruby
+Summary:     Ruby bindings for %{name}
+Group:       Development/Libraries
+Requires:    %{name} = %{version}-%{release}
+Requires:    ruby(abi) = 1.8
+Provides:    ruby(guestfs) = %{version}
+
+%{!?ruby_sitelib: %define ruby_sitelib %(ruby -rrbconfig -e "puts Config::CONFIG['sitelibdir']")}
+%{!?ruby_sitearch: %define ruby_sitearch %(ruby -rrbconfig -e "puts Config::CONFIG['sitearchdir']")}
+
+%description ruby
+%{name}-ruby contains Ruby bindings for %{name}.
+
+
 %prep
 %setup -q
 
@@ -196,6 +214,12 @@ if [ "$RPM_BUILD_ROOT%{python_sitearch}" != "$RPM_BUILD_ROOT%{python_sitelib}" ]
      $RPM_BUILD_ROOT%{python_sitelib}/
 fi
 
+# Install ruby bindings by hand.
+mkdir -p $RPM_BUILD_ROOT%{ruby_sitelib}
+mkdir -p $RPM_BUILD_ROOT%{ruby_sitearch}
+install -p -m0644 ruby/lib/libvirt.rb $RPM_BUILD_ROOT%{ruby_sitelib}
+install -p -m0755 ruby/ext/libvirt/_libvirt.so $RPM_BUILD_ROOT%{ruby_sitearch}
+
 
 %clean
 rm -rf $RPM_BUILD_ROOT
@@ -266,6 +290,12 @@ rm -rf $RPM_BUILD_ROOT
 %{python_sitelib}/*.pyo
 
 
+%files ruby
+%defattr(-,root,root,-)
+%{ruby_sitelib}/guestfs.rb
+%{ruby_sitearch}/_guestfs.so
+
+
 %changelog
 * Thu Apr 16 2009 Richard Jones <rjones@redhat.com> - @VERSION@-1
 - New upstream version @VERSION@.
diff --git a/ruby/Makefile.am b/ruby/Makefile.am
new file mode 100644 (file)
index 0000000..2b4b201
--- /dev/null
@@ -0,0 +1,43 @@
+# libguestfs Ruby 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.
+
+EXTRA_DIST = \
+       Rakefile.in \
+       ext/guestfs/_guestfs.c \
+       ext/guestfs/extconf.rb \
+       lib/guestfs.rb \
+       run-ruby-tests \
+       tests/tc_*.rb
+
+CLEANFILES = *~ \
+       lib/*~ \
+       tests/*~ \
+       ext/guestfs/*~ \
+       ext/guestfs/extconf.h \
+       ext/guestfs/_guestfs.o \
+       ext/guestfs/_guestfs.so \
+       ext/guestfs/mkmf.log \
+       ext/guestfs/Makefile
+
+if HAVE_RUBY
+
+TESTS = run-ruby-tests
+
+all:
+       rake build
+
+endif
\ No newline at end of file
diff --git a/ruby/Rakefile.in b/ruby/Rakefile.in
new file mode 100644 (file)
index 0000000..fc95f3f
--- /dev/null
@@ -0,0 +1,103 @@
+# libguestfs Ruby bindings -*- ruby -*-
+# @configure_input@
+# 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.
+
+require 'rake/clean'
+require 'rake/rdoctask'
+require 'rake/testtask'
+require 'rake/gempackagetask'
+
+PKG_NAME='@PACKAGE_NAME@'
+PKG_VERSION='@PACKAGE_VERSION@'
+
+EXT_CONF='ext/guestfs/extconf.rb'
+MAKEFILE='ext/guestfs/Makefile'
+GUESTFS_MODULE='ext/guestfs/_guestfs.so'
+GUESTFS_SRC='ext/guestfs/_guestfs.c'
+
+CLEAN.include [ "ext/**/*.o", GUESTFS_MODULE,
+                "ext/**/depend" ]
+
+CLOBBER.include [ "config.save", "ext/**/mkmf.log",
+                  MAKEFILE ]
+
+# Build locally
+
+file MAKEFILE => EXT_CONF do |t|
+    Dir::chdir(File::dirname(EXT_CONF)) do
+         unless sh "ruby #{File::basename(EXT_CONF)}"
+             $stderr.puts "Failed to run extconf"
+             break
+         end
+    end
+end
+file GUESTFS_MODULE => [ MAKEFILE, GUESTFS_SRC ] do |t|
+    Dir::chdir(File::dirname(EXT_CONF)) do
+         unless sh "make"
+             $stderr.puts "make failed"
+             break
+         end
+     end
+end
+desc "Build the native library"
+task :build => GUESTFS_MODULE
+
+Rake::TestTask.new(:test) do |t|
+    t.test_files = FileList['tests/tc_*.rb']
+    t.libs = [ 'lib', 'ext/guestfs' ]
+end
+task :test => :build
+
+Rake::RDocTask.new do |rd|
+    rd.main = "README.rdoc"
+    rd.rdoc_dir = "doc/site/api"
+    rd.rdoc_files.include("README.rdoc", "lib/**/*.rb", "ext/**/*.[ch]")
+end
+
+# Package tasks
+
+PKG_FILES = FileList[
+  "Rakefile", "COPYING", "README", "NEWS", "README.rdoc",
+  "lib/**/*.rb",
+  "ext/**/*.[ch]", "ext/**/MANIFEST", "ext/**/extconf.rb",
+  "tests/**/*",
+  "spec/**/*"
+]
+
+DIST_FILES = FileList[
+  "pkg/*.src.rpm",  "pkg/*.gem",  "pkg/*.zip", "pkg/*.tgz"
+]
+
+SPEC = Gem::Specification.new do |s|
+    s.name = PKG_NAME
+    s.version = PKG_VERSION
+    s.email = "rjones@redhat.com"
+    s.homepage = "http://et.redhat.com/~rjones/libguestfs/"
+    s.summary = "Ruby bindings for libguestfs"
+    s.files = PKG_FILES
+    s.autorequire = "guestfs"
+    s.required_ruby_version = '>= 1.8.1'
+    s.extensions = "ext/guestfs/extconf.rb"
+    s.description = <<EOF
+Ruby bindings for libguestfs.
+EOF
+end
+
+Rake::GemPackageTask.new(SPEC) do |pkg|
+    pkg.need_tar = true
+    pkg.need_zip = true
+end
diff --git a/ruby/ext/guestfs/_guestfs.c b/ruby/ext/guestfs/_guestfs.c
new file mode 100644 (file)
index 0000000..d685046
--- /dev/null
@@ -0,0 +1,2064 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+
+#include <ruby.h>
+
+#include "guestfs.h"
+
+#include "extconf.h"
+
+static VALUE m_guestfs;                        /* guestfs module */
+static VALUE c_guestfs;                        /* guestfs_h handle */
+static VALUE e_Error;                  /* used for all errors */
+
+static void ruby_guestfs_free (void *p)
+{
+  if (!p) return;
+  guestfs_close ((guestfs_h *) p);
+}
+
+static VALUE ruby_guestfs_create (VALUE m)
+{
+  guestfs_h *g;
+
+  g = guestfs_create ();
+  if (!g)
+    rb_raise (e_Error, "failed to create guestfs handle");
+
+  /* Don't print error messages to stderr by default. */
+  guestfs_set_error_handler (g, NULL, NULL);
+
+  /* Wrap it, and make sure the close function is called when the
+   * handle goes away.
+   */
+  return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
+}
+
+static VALUE ruby_guestfs_close (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+
+  ruby_guestfs_free (g);
+  DATA_PTR (gv) = NULL;
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_launch (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "launch");
+
+
+  int r;
+
+  r = guestfs_launch (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_wait_ready (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "wait_ready");
+
+
+  int r;
+
+  r = guestfs_wait_ready (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_kill_subprocess (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "kill_subprocess");
+
+
+  int r;
+
+  r = guestfs_kill_subprocess (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_add_drive (VALUE gv, VALUE filenamev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "add_drive");
+
+  const char *filename = StringValueCStr (filenamev);
+  if (!filename)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "filename", "add_drive");
+
+  int r;
+
+  r = guestfs_add_drive (g, filename);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_add_cdrom (VALUE gv, VALUE filenamev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "add_cdrom");
+
+  const char *filename = StringValueCStr (filenamev);
+  if (!filename)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "filename", "add_cdrom");
+
+  int r;
+
+  r = guestfs_add_cdrom (g, filename);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_config (VALUE gv, VALUE qemuparamv, VALUE qemuvaluev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "config");
+
+  const char *qemuparam = StringValueCStr (qemuparamv);
+  if (!qemuparam)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "qemuparam", "config");
+  const char *qemuvalue = StringValueCStr (qemuvaluev);
+
+  int r;
+
+  r = guestfs_config (g, qemuparam, qemuvalue);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_set_path (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "set_path");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "set_path");
+
+  int r;
+
+  r = guestfs_set_path (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_get_path (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "get_path");
+
+
+  const char *r;
+
+  r = guestfs_get_path (g);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return rb_str_new2 (r);
+}
+
+static VALUE ruby_guestfs_set_autosync (VALUE gv, VALUE autosyncv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "set_autosync");
+
+  int autosync = NUM2INT (autosyncv);
+
+  int r;
+
+  r = guestfs_set_autosync (g, autosync);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_get_autosync (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "get_autosync");
+
+
+  int r;
+
+  r = guestfs_get_autosync (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return INT2NUM (r);
+}
+
+static VALUE ruby_guestfs_set_verbose (VALUE gv, VALUE verbosev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "set_verbose");
+
+  int verbose = NUM2INT (verbosev);
+
+  int r;
+
+  r = guestfs_set_verbose (g, verbose);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_get_verbose (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "get_verbose");
+
+
+  int r;
+
+  r = guestfs_get_verbose (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return INT2NUM (r);
+}
+
+static VALUE ruby_guestfs_mount (VALUE gv, VALUE devicev, VALUE mountpointv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "mount");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "mount");
+  const char *mountpoint = StringValueCStr (mountpointv);
+  if (!mountpoint)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "mountpoint", "mount");
+
+  int r;
+
+  r = guestfs_mount (g, device, mountpoint);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_sync (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "sync");
+
+
+  int r;
+
+  r = guestfs_sync (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_touch (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "touch");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "touch");
+
+  int r;
+
+  r = guestfs_touch (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_cat (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "cat");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "cat");
+
+  char *r;
+
+  r = guestfs_cat (g, path);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_str_new2 (r);
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_ll (VALUE gv, VALUE directoryv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "ll");
+
+  const char *directory = StringValueCStr (directoryv);
+  if (!directory)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "directory", "ll");
+
+  char *r;
+
+  r = guestfs_ll (g, directory);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_str_new2 (r);
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_ls (VALUE gv, VALUE directoryv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "ls");
+
+  const char *directory = StringValueCStr (directoryv);
+  if (!directory)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "directory", "ls");
+
+  char **r;
+
+  r = guestfs_ls (g, directory);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_list_devices (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "list_devices");
+
+
+  char **r;
+
+  r = guestfs_list_devices (g);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_list_partitions (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "list_partitions");
+
+
+  char **r;
+
+  r = guestfs_list_partitions (g);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_pvs (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "pvs");
+
+
+  char **r;
+
+  r = guestfs_pvs (g);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_vgs (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "vgs");
+
+
+  char **r;
+
+  r = guestfs_vgs (g);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_lvs (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "lvs");
+
+
+  char **r;
+
+  r = guestfs_lvs (g);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_pvs_full (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "pvs_full");
+
+
+  struct guestfs_lvm_pv_list *r;
+
+  r = guestfs_pvs_full (g);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_ary_new2 (r->len);
+  int i;
+  for (i = 0; i < r->len; ++i) {
+    VALUE hv = rb_hash_new ();
+    rb_hash_aset (rv, rb_str_new2 ("pv_name"), rb_str_new2 (r->val[i].pv_name));
+    rb_hash_aset (rv, rb_str_new2 ("pv_uuid"), rb_str_new (r->val[i].pv_uuid, 32));
+    rb_hash_aset (rv, rb_str_new2 ("pv_fmt"), rb_str_new2 (r->val[i].pv_fmt));
+    rb_hash_aset (rv, rb_str_new2 ("pv_size"), ULL2NUM (r->val[i].pv_size));
+    rb_hash_aset (rv, rb_str_new2 ("dev_size"), ULL2NUM (r->val[i].dev_size));
+    rb_hash_aset (rv, rb_str_new2 ("pv_free"), ULL2NUM (r->val[i].pv_free));
+    rb_hash_aset (rv, rb_str_new2 ("pv_used"), ULL2NUM (r->val[i].pv_used));
+    rb_hash_aset (rv, rb_str_new2 ("pv_attr"), rb_str_new2 (r->val[i].pv_attr));
+    rb_hash_aset (rv, rb_str_new2 ("pv_pe_count"), ULL2NUM (r->val[i].pv_pe_count));
+    rb_hash_aset (rv, rb_str_new2 ("pv_pe_alloc_count"), ULL2NUM (r->val[i].pv_pe_alloc_count));
+    rb_hash_aset (rv, rb_str_new2 ("pv_tags"), rb_str_new2 (r->val[i].pv_tags));
+    rb_hash_aset (rv, rb_str_new2 ("pe_start"), ULL2NUM (r->val[i].pe_start));
+    rb_hash_aset (rv, rb_str_new2 ("pv_mda_count"), ULL2NUM (r->val[i].pv_mda_count));
+    rb_hash_aset (rv, rb_str_new2 ("pv_mda_free"), ULL2NUM (r->val[i].pv_mda_free));
+    rb_ary_push (rv, hv);
+  }
+  guestfs_free_lvm_pv_list (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_vgs_full (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "vgs_full");
+
+
+  struct guestfs_lvm_vg_list *r;
+
+  r = guestfs_vgs_full (g);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_ary_new2 (r->len);
+  int i;
+  for (i = 0; i < r->len; ++i) {
+    VALUE hv = rb_hash_new ();
+    rb_hash_aset (rv, rb_str_new2 ("vg_name"), rb_str_new2 (r->val[i].vg_name));
+    rb_hash_aset (rv, rb_str_new2 ("vg_uuid"), rb_str_new (r->val[i].vg_uuid, 32));
+    rb_hash_aset (rv, rb_str_new2 ("vg_fmt"), rb_str_new2 (r->val[i].vg_fmt));
+    rb_hash_aset (rv, rb_str_new2 ("vg_attr"), rb_str_new2 (r->val[i].vg_attr));
+    rb_hash_aset (rv, rb_str_new2 ("vg_size"), ULL2NUM (r->val[i].vg_size));
+    rb_hash_aset (rv, rb_str_new2 ("vg_free"), ULL2NUM (r->val[i].vg_free));
+    rb_hash_aset (rv, rb_str_new2 ("vg_sysid"), rb_str_new2 (r->val[i].vg_sysid));
+    rb_hash_aset (rv, rb_str_new2 ("vg_extent_size"), ULL2NUM (r->val[i].vg_extent_size));
+    rb_hash_aset (rv, rb_str_new2 ("vg_extent_count"), ULL2NUM (r->val[i].vg_extent_count));
+    rb_hash_aset (rv, rb_str_new2 ("vg_free_count"), ULL2NUM (r->val[i].vg_free_count));
+    rb_hash_aset (rv, rb_str_new2 ("max_lv"), ULL2NUM (r->val[i].max_lv));
+    rb_hash_aset (rv, rb_str_new2 ("max_pv"), ULL2NUM (r->val[i].max_pv));
+    rb_hash_aset (rv, rb_str_new2 ("pv_count"), ULL2NUM (r->val[i].pv_count));
+    rb_hash_aset (rv, rb_str_new2 ("lv_count"), ULL2NUM (r->val[i].lv_count));
+    rb_hash_aset (rv, rb_str_new2 ("snap_count"), ULL2NUM (r->val[i].snap_count));
+    rb_hash_aset (rv, rb_str_new2 ("vg_seqno"), ULL2NUM (r->val[i].vg_seqno));
+    rb_hash_aset (rv, rb_str_new2 ("vg_tags"), rb_str_new2 (r->val[i].vg_tags));
+    rb_hash_aset (rv, rb_str_new2 ("vg_mda_count"), ULL2NUM (r->val[i].vg_mda_count));
+    rb_hash_aset (rv, rb_str_new2 ("vg_mda_free"), ULL2NUM (r->val[i].vg_mda_free));
+    rb_ary_push (rv, hv);
+  }
+  guestfs_free_lvm_vg_list (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_lvs_full (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "lvs_full");
+
+
+  struct guestfs_lvm_lv_list *r;
+
+  r = guestfs_lvs_full (g);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_ary_new2 (r->len);
+  int i;
+  for (i = 0; i < r->len; ++i) {
+    VALUE hv = rb_hash_new ();
+    rb_hash_aset (rv, rb_str_new2 ("lv_name"), rb_str_new2 (r->val[i].lv_name));
+    rb_hash_aset (rv, rb_str_new2 ("lv_uuid"), rb_str_new (r->val[i].lv_uuid, 32));
+    rb_hash_aset (rv, rb_str_new2 ("lv_attr"), rb_str_new2 (r->val[i].lv_attr));
+    rb_hash_aset (rv, rb_str_new2 ("lv_major"), ULL2NUM (r->val[i].lv_major));
+    rb_hash_aset (rv, rb_str_new2 ("lv_minor"), ULL2NUM (r->val[i].lv_minor));
+    rb_hash_aset (rv, rb_str_new2 ("lv_kernel_major"), ULL2NUM (r->val[i].lv_kernel_major));
+    rb_hash_aset (rv, rb_str_new2 ("lv_kernel_minor"), ULL2NUM (r->val[i].lv_kernel_minor));
+    rb_hash_aset (rv, rb_str_new2 ("lv_size"), ULL2NUM (r->val[i].lv_size));
+    rb_hash_aset (rv, rb_str_new2 ("seg_count"), ULL2NUM (r->val[i].seg_count));
+    rb_hash_aset (rv, rb_str_new2 ("origin"), rb_str_new2 (r->val[i].origin));
+    rb_hash_aset (rv, rb_str_new2 ("snap_percent"), rb_dbl2big (r->val[i].snap_percent));
+    rb_hash_aset (rv, rb_str_new2 ("copy_percent"), rb_dbl2big (r->val[i].copy_percent));
+    rb_hash_aset (rv, rb_str_new2 ("move_pv"), rb_str_new2 (r->val[i].move_pv));
+    rb_hash_aset (rv, rb_str_new2 ("lv_tags"), rb_str_new2 (r->val[i].lv_tags));
+    rb_hash_aset (rv, rb_str_new2 ("mirror_log"), rb_str_new2 (r->val[i].mirror_log));
+    rb_hash_aset (rv, rb_str_new2 ("modules"), rb_str_new2 (r->val[i].modules));
+    rb_ary_push (rv, hv);
+  }
+  guestfs_free_lvm_lv_list (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_read_lines (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "read_lines");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "read_lines");
+
+  char **r;
+
+  r = guestfs_read_lines (g, path);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_aug_init (VALUE gv, VALUE rootv, VALUE flagsv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_init");
+
+  const char *root = StringValueCStr (rootv);
+  if (!root)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "root", "aug_init");
+  int flags = NUM2INT (flagsv);
+
+  int r;
+
+  r = guestfs_aug_init (g, root, flags);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_aug_close (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_close");
+
+
+  int r;
+
+  r = guestfs_aug_close (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_aug_defvar (VALUE gv, VALUE namev, VALUE exprv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_defvar");
+
+  const char *name = StringValueCStr (namev);
+  if (!name)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "name", "aug_defvar");
+  const char *expr = StringValueCStr (exprv);
+
+  int r;
+
+  r = guestfs_aug_defvar (g, name, expr);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return INT2NUM (r);
+}
+
+static VALUE ruby_guestfs_aug_defnode (VALUE gv, VALUE namev, VALUE exprv, VALUE valv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_defnode");
+
+  const char *name = StringValueCStr (namev);
+  if (!name)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "name", "aug_defnode");
+  const char *expr = StringValueCStr (exprv);
+  if (!expr)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "expr", "aug_defnode");
+  const char *val = StringValueCStr (valv);
+  if (!val)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "val", "aug_defnode");
+
+  struct guestfs_int_bool *r;
+
+  r = guestfs_aug_defnode (g, name, expr, val);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_ary_new2 (2);
+  rb_ary_push (rv, INT2NUM (r->i));
+  rb_ary_push (rv, INT2NUM (r->b));
+  guestfs_free_int_bool (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_aug_get (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_get");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "aug_get");
+
+  char *r;
+
+  r = guestfs_aug_get (g, path);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_str_new2 (r);
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_aug_set (VALUE gv, VALUE pathv, VALUE valv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_set");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "aug_set");
+  const char *val = StringValueCStr (valv);
+  if (!val)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "val", "aug_set");
+
+  int r;
+
+  r = guestfs_aug_set (g, path, val);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_aug_insert (VALUE gv, VALUE pathv, VALUE labelv, VALUE beforev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_insert");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "aug_insert");
+  const char *label = StringValueCStr (labelv);
+  if (!label)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "label", "aug_insert");
+  int before = NUM2INT (beforev);
+
+  int r;
+
+  r = guestfs_aug_insert (g, path, label, before);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_aug_rm (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_rm");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "aug_rm");
+
+  int r;
+
+  r = guestfs_aug_rm (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return INT2NUM (r);
+}
+
+static VALUE ruby_guestfs_aug_mv (VALUE gv, VALUE srcv, VALUE destv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_mv");
+
+  const char *src = StringValueCStr (srcv);
+  if (!src)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "src", "aug_mv");
+  const char *dest = StringValueCStr (destv);
+  if (!dest)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "dest", "aug_mv");
+
+  int r;
+
+  r = guestfs_aug_mv (g, src, dest);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_aug_match (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_match");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "aug_match");
+
+  char **r;
+
+  r = guestfs_aug_match (g, path);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_aug_save (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_save");
+
+
+  int r;
+
+  r = guestfs_aug_save (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_aug_load (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_load");
+
+
+  int r;
+
+  r = guestfs_aug_load (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_aug_ls (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "aug_ls");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "aug_ls");
+
+  char **r;
+
+  r = guestfs_aug_ls (g, path);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_rm (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "rm");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "rm");
+
+  int r;
+
+  r = guestfs_rm (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_rmdir (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "rmdir");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "rmdir");
+
+  int r;
+
+  r = guestfs_rmdir (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_rm_rf (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "rm_rf");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "rm_rf");
+
+  int r;
+
+  r = guestfs_rm_rf (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_mkdir (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "mkdir");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "mkdir");
+
+  int r;
+
+  r = guestfs_mkdir (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_mkdir_p (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "mkdir_p");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "mkdir_p");
+
+  int r;
+
+  r = guestfs_mkdir_p (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_chmod (VALUE gv, VALUE modev, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "chmod");
+
+  int mode = NUM2INT (modev);
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "chmod");
+
+  int r;
+
+  r = guestfs_chmod (g, mode, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_chown (VALUE gv, VALUE ownerv, VALUE groupv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "chown");
+
+  int owner = NUM2INT (ownerv);
+  int group = NUM2INT (groupv);
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "chown");
+
+  int r;
+
+  r = guestfs_chown (g, owner, group, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_exists (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "exists");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "exists");
+
+  int r;
+
+  r = guestfs_exists (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return INT2NUM (r);
+}
+
+static VALUE ruby_guestfs_is_file (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "is_file");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "is_file");
+
+  int r;
+
+  r = guestfs_is_file (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return INT2NUM (r);
+}
+
+static VALUE ruby_guestfs_is_dir (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "is_dir");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "is_dir");
+
+  int r;
+
+  r = guestfs_is_dir (g, path);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return INT2NUM (r);
+}
+
+static VALUE ruby_guestfs_pvcreate (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "pvcreate");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "pvcreate");
+
+  int r;
+
+  r = guestfs_pvcreate (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_vgcreate (VALUE gv, VALUE volgroupv, VALUE physvolsv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "vgcreate");
+
+  const char *volgroup = StringValueCStr (volgroupv);
+  if (!volgroup)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "volgroup", "vgcreate");
+  char **physvols;  {
+    int i, len;
+    len = RARRAY_LEN (physvolsv);
+    physvols = malloc (sizeof (char *) * (len+1));
+    for (i = 0; i < len; ++i) {
+      VALUE v = rb_ary_entry (physvolsv, i);
+      physvols[i] = StringValueCStr (v);
+    }
+  }
+
+  int r;
+
+  r = guestfs_vgcreate (g, volgroup, physvols);
+  free (physvols);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_lvcreate (VALUE gv, VALUE logvolv, VALUE volgroupv, VALUE mbytesv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "lvcreate");
+
+  const char *logvol = StringValueCStr (logvolv);
+  if (!logvol)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "logvol", "lvcreate");
+  const char *volgroup = StringValueCStr (volgroupv);
+  if (!volgroup)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "volgroup", "lvcreate");
+  int mbytes = NUM2INT (mbytesv);
+
+  int r;
+
+  r = guestfs_lvcreate (g, logvol, volgroup, mbytes);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_mkfs (VALUE gv, VALUE fstypev, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "mkfs");
+
+  const char *fstype = StringValueCStr (fstypev);
+  if (!fstype)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "fstype", "mkfs");
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "mkfs");
+
+  int r;
+
+  r = guestfs_mkfs (g, fstype, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_sfdisk (VALUE gv, VALUE devicev, VALUE cylsv, VALUE headsv, VALUE sectorsv, VALUE linesv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "sfdisk");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "sfdisk");
+  int cyls = NUM2INT (cylsv);
+  int heads = NUM2INT (headsv);
+  int sectors = NUM2INT (sectorsv);
+  char **lines;  {
+    int i, len;
+    len = RARRAY_LEN (linesv);
+    lines = malloc (sizeof (char *) * (len+1));
+    for (i = 0; i < len; ++i) {
+      VALUE v = rb_ary_entry (linesv, i);
+      lines[i] = StringValueCStr (v);
+    }
+  }
+
+  int r;
+
+  r = guestfs_sfdisk (g, device, cyls, heads, sectors, lines);
+  free (lines);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_write_file (VALUE gv, VALUE pathv, VALUE contentv, VALUE sizev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "write_file");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "write_file");
+  const char *content = StringValueCStr (contentv);
+  if (!content)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "content", "write_file");
+  int size = NUM2INT (sizev);
+
+  int r;
+
+  r = guestfs_write_file (g, path, content, size);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_umount (VALUE gv, VALUE pathordevicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "umount");
+
+  const char *pathordevice = StringValueCStr (pathordevicev);
+  if (!pathordevice)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "pathordevice", "umount");
+
+  int r;
+
+  r = guestfs_umount (g, pathordevice);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_mounts (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "mounts");
+
+
+  char **r;
+
+  r = guestfs_mounts (g);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_umount_all (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "umount_all");
+
+
+  int r;
+
+  r = guestfs_umount_all (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_lvm_remove_all (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "lvm_remove_all");
+
+
+  int r;
+
+  r = guestfs_lvm_remove_all (g);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_file (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "file");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "file");
+
+  char *r;
+
+  r = guestfs_file (g, path);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_str_new2 (r);
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_command (VALUE gv, VALUE argumentsv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "command");
+
+  char **arguments;  {
+    int i, len;
+    len = RARRAY_LEN (argumentsv);
+    arguments = malloc (sizeof (char *) * (len+1));
+    for (i = 0; i < len; ++i) {
+      VALUE v = rb_ary_entry (argumentsv, i);
+      arguments[i] = StringValueCStr (v);
+    }
+  }
+
+  char *r;
+
+  r = guestfs_command (g, arguments);
+  free (arguments);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_str_new2 (r);
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_command_lines (VALUE gv, VALUE argumentsv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "command_lines");
+
+  char **arguments;  {
+    int i, len;
+    len = RARRAY_LEN (argumentsv);
+    arguments = malloc (sizeof (char *) * (len+1));
+    for (i = 0; i < len; ++i) {
+      VALUE v = rb_ary_entry (argumentsv, i);
+      arguments[i] = StringValueCStr (v);
+    }
+  }
+
+  char **r;
+
+  r = guestfs_command_lines (g, arguments);
+  free (arguments);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  int i, len = 0;
+  for (i = 0; r[i] != NULL; ++i) len++;
+  VALUE rv = rb_ary_new2 (len);
+  for (i = 0; r[i] != NULL; ++i) {
+    rb_ary_push (rv, rb_str_new2 (r[i]));
+    free (r[i]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_stat (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "stat");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "stat");
+
+  struct guestfs_stat *r;
+
+  r = guestfs_stat (g, path);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_hash_new ();
+  rb_hash_aset (rv, rb_str_new2 ("dev"), ULL2NUM (r->dev));
+  rb_hash_aset (rv, rb_str_new2 ("ino"), ULL2NUM (r->ino));
+  rb_hash_aset (rv, rb_str_new2 ("mode"), ULL2NUM (r->mode));
+  rb_hash_aset (rv, rb_str_new2 ("nlink"), ULL2NUM (r->nlink));
+  rb_hash_aset (rv, rb_str_new2 ("uid"), ULL2NUM (r->uid));
+  rb_hash_aset (rv, rb_str_new2 ("gid"), ULL2NUM (r->gid));
+  rb_hash_aset (rv, rb_str_new2 ("rdev"), ULL2NUM (r->rdev));
+  rb_hash_aset (rv, rb_str_new2 ("size"), ULL2NUM (r->size));
+  rb_hash_aset (rv, rb_str_new2 ("blksize"), ULL2NUM (r->blksize));
+  rb_hash_aset (rv, rb_str_new2 ("blocks"), ULL2NUM (r->blocks));
+  rb_hash_aset (rv, rb_str_new2 ("atime"), ULL2NUM (r->atime));
+  rb_hash_aset (rv, rb_str_new2 ("mtime"), ULL2NUM (r->mtime));
+  rb_hash_aset (rv, rb_str_new2 ("ctime"), ULL2NUM (r->ctime));
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_lstat (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "lstat");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "lstat");
+
+  struct guestfs_stat *r;
+
+  r = guestfs_lstat (g, path);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_hash_new ();
+  rb_hash_aset (rv, rb_str_new2 ("dev"), ULL2NUM (r->dev));
+  rb_hash_aset (rv, rb_str_new2 ("ino"), ULL2NUM (r->ino));
+  rb_hash_aset (rv, rb_str_new2 ("mode"), ULL2NUM (r->mode));
+  rb_hash_aset (rv, rb_str_new2 ("nlink"), ULL2NUM (r->nlink));
+  rb_hash_aset (rv, rb_str_new2 ("uid"), ULL2NUM (r->uid));
+  rb_hash_aset (rv, rb_str_new2 ("gid"), ULL2NUM (r->gid));
+  rb_hash_aset (rv, rb_str_new2 ("rdev"), ULL2NUM (r->rdev));
+  rb_hash_aset (rv, rb_str_new2 ("size"), ULL2NUM (r->size));
+  rb_hash_aset (rv, rb_str_new2 ("blksize"), ULL2NUM (r->blksize));
+  rb_hash_aset (rv, rb_str_new2 ("blocks"), ULL2NUM (r->blocks));
+  rb_hash_aset (rv, rb_str_new2 ("atime"), ULL2NUM (r->atime));
+  rb_hash_aset (rv, rb_str_new2 ("mtime"), ULL2NUM (r->mtime));
+  rb_hash_aset (rv, rb_str_new2 ("ctime"), ULL2NUM (r->ctime));
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_statvfs (VALUE gv, VALUE pathv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "statvfs");
+
+  const char *path = StringValueCStr (pathv);
+  if (!path)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "path", "statvfs");
+
+  struct guestfs_statvfs *r;
+
+  r = guestfs_statvfs (g, path);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_hash_new ();
+  rb_hash_aset (rv, rb_str_new2 ("bsize"), ULL2NUM (r->bsize));
+  rb_hash_aset (rv, rb_str_new2 ("frsize"), ULL2NUM (r->frsize));
+  rb_hash_aset (rv, rb_str_new2 ("blocks"), ULL2NUM (r->blocks));
+  rb_hash_aset (rv, rb_str_new2 ("bfree"), ULL2NUM (r->bfree));
+  rb_hash_aset (rv, rb_str_new2 ("bavail"), ULL2NUM (r->bavail));
+  rb_hash_aset (rv, rb_str_new2 ("files"), ULL2NUM (r->files));
+  rb_hash_aset (rv, rb_str_new2 ("ffree"), ULL2NUM (r->ffree));
+  rb_hash_aset (rv, rb_str_new2 ("favail"), ULL2NUM (r->favail));
+  rb_hash_aset (rv, rb_str_new2 ("fsid"), ULL2NUM (r->fsid));
+  rb_hash_aset (rv, rb_str_new2 ("flag"), ULL2NUM (r->flag));
+  rb_hash_aset (rv, rb_str_new2 ("namemax"), ULL2NUM (r->namemax));
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_tune2fs_l (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "tune2fs_l");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "tune2fs_l");
+
+  char **r;
+
+  r = guestfs_tune2fs_l (g, device);
+  if (r == NULL)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  VALUE rv = rb_hash_new ();
+  int i;
+  for (i = 0; r[i] != NULL; i+=2) {
+    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));
+    free (r[i]);
+    free (r[i+1]);
+  }
+  free (r);
+  return rv;
+}
+
+static VALUE ruby_guestfs_blockdev_setro (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "blockdev_setro");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "blockdev_setro");
+
+  int r;
+
+  r = guestfs_blockdev_setro (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_blockdev_setrw (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "blockdev_setrw");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "blockdev_setrw");
+
+  int r;
+
+  r = guestfs_blockdev_setrw (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_blockdev_getro (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "blockdev_getro");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "blockdev_getro");
+
+  int r;
+
+  r = guestfs_blockdev_getro (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return INT2NUM (r);
+}
+
+static VALUE ruby_guestfs_blockdev_getss (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "blockdev_getss");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "blockdev_getss");
+
+  int r;
+
+  r = guestfs_blockdev_getss (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return INT2NUM (r);
+}
+
+static VALUE ruby_guestfs_blockdev_getbsz (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "blockdev_getbsz");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "blockdev_getbsz");
+
+  int r;
+
+  r = guestfs_blockdev_getbsz (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return INT2NUM (r);
+}
+
+static VALUE ruby_guestfs_blockdev_setbsz (VALUE gv, VALUE devicev, VALUE blocksizev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "blockdev_setbsz");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "blockdev_setbsz");
+  int blocksize = NUM2INT (blocksizev);
+
+  int r;
+
+  r = guestfs_blockdev_setbsz (g, device, blocksize);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_blockdev_getsz (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "blockdev_getsz");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "blockdev_getsz");
+
+  int64_t r;
+
+  r = guestfs_blockdev_getsz (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return ULL2NUM (r);
+}
+
+static VALUE ruby_guestfs_blockdev_getsize64 (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "blockdev_getsize64");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "blockdev_getsize64");
+
+  int64_t r;
+
+  r = guestfs_blockdev_getsize64 (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return ULL2NUM (r);
+}
+
+static VALUE ruby_guestfs_blockdev_flushbufs (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "blockdev_flushbufs");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "blockdev_flushbufs");
+
+  int r;
+
+  r = guestfs_blockdev_flushbufs (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+static VALUE ruby_guestfs_blockdev_rereadpt (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "blockdev_rereadpt");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "blockdev_rereadpt");
+
+  int r;
+
+  r = guestfs_blockdev_rereadpt (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
+/* Initialize the module. */
+void Init__guestfs ()
+{
+  m_guestfs = rb_define_module ("Guestfs");
+  c_guestfs = rb_define_class_under (m_guestfs, "Guestfs", rb_cObject);
+  e_Error = rb_define_class_under (m_guestfs, "Error", rb_eStandardError);
+
+  rb_define_module_function (m_guestfs, "create", ruby_guestfs_create, 0);
+  rb_define_method (c_guestfs, "close", ruby_guestfs_close, 0);
+
+  rb_define_method (c_guestfs, "launch",
+        ruby_guestfs_launch, 0);
+  rb_define_method (c_guestfs, "wait_ready",
+        ruby_guestfs_wait_ready, 0);
+  rb_define_method (c_guestfs, "kill_subprocess",
+        ruby_guestfs_kill_subprocess, 0);
+  rb_define_method (c_guestfs, "add_drive",
+        ruby_guestfs_add_drive, 1);
+  rb_define_method (c_guestfs, "add_cdrom",
+        ruby_guestfs_add_cdrom, 1);
+  rb_define_method (c_guestfs, "config",
+        ruby_guestfs_config, 2);
+  rb_define_method (c_guestfs, "set_path",
+        ruby_guestfs_set_path, 1);
+  rb_define_method (c_guestfs, "get_path",
+        ruby_guestfs_get_path, 0);
+  rb_define_method (c_guestfs, "set_autosync",
+        ruby_guestfs_set_autosync, 1);
+  rb_define_method (c_guestfs, "get_autosync",
+        ruby_guestfs_get_autosync, 0);
+  rb_define_method (c_guestfs, "set_verbose",
+        ruby_guestfs_set_verbose, 1);
+  rb_define_method (c_guestfs, "get_verbose",
+        ruby_guestfs_get_verbose, 0);
+  rb_define_method (c_guestfs, "mount",
+        ruby_guestfs_mount, 2);
+  rb_define_method (c_guestfs, "sync",
+        ruby_guestfs_sync, 0);
+  rb_define_method (c_guestfs, "touch",
+        ruby_guestfs_touch, 1);
+  rb_define_method (c_guestfs, "cat",
+        ruby_guestfs_cat, 1);
+  rb_define_method (c_guestfs, "ll",
+        ruby_guestfs_ll, 1);
+  rb_define_method (c_guestfs, "ls",
+        ruby_guestfs_ls, 1);
+  rb_define_method (c_guestfs, "list_devices",
+        ruby_guestfs_list_devices, 0);
+  rb_define_method (c_guestfs, "list_partitions",
+        ruby_guestfs_list_partitions, 0);
+  rb_define_method (c_guestfs, "pvs",
+        ruby_guestfs_pvs, 0);
+  rb_define_method (c_guestfs, "vgs",
+        ruby_guestfs_vgs, 0);
+  rb_define_method (c_guestfs, "lvs",
+        ruby_guestfs_lvs, 0);
+  rb_define_method (c_guestfs, "pvs_full",
+        ruby_guestfs_pvs_full, 0);
+  rb_define_method (c_guestfs, "vgs_full",
+        ruby_guestfs_vgs_full, 0);
+  rb_define_method (c_guestfs, "lvs_full",
+        ruby_guestfs_lvs_full, 0);
+  rb_define_method (c_guestfs, "read_lines",
+        ruby_guestfs_read_lines, 1);
+  rb_define_method (c_guestfs, "aug_init",
+        ruby_guestfs_aug_init, 2);
+  rb_define_method (c_guestfs, "aug_close",
+        ruby_guestfs_aug_close, 0);
+  rb_define_method (c_guestfs, "aug_defvar",
+        ruby_guestfs_aug_defvar, 2);
+  rb_define_method (c_guestfs, "aug_defnode",
+        ruby_guestfs_aug_defnode, 3);
+  rb_define_method (c_guestfs, "aug_get",
+        ruby_guestfs_aug_get, 1);
+  rb_define_method (c_guestfs, "aug_set",
+        ruby_guestfs_aug_set, 2);
+  rb_define_method (c_guestfs, "aug_insert",
+        ruby_guestfs_aug_insert, 3);
+  rb_define_method (c_guestfs, "aug_rm",
+        ruby_guestfs_aug_rm, 1);
+  rb_define_method (c_guestfs, "aug_mv",
+        ruby_guestfs_aug_mv, 2);
+  rb_define_method (c_guestfs, "aug_match",
+        ruby_guestfs_aug_match, 1);
+  rb_define_method (c_guestfs, "aug_save",
+        ruby_guestfs_aug_save, 0);
+  rb_define_method (c_guestfs, "aug_load",
+        ruby_guestfs_aug_load, 0);
+  rb_define_method (c_guestfs, "aug_ls",
+        ruby_guestfs_aug_ls, 1);
+  rb_define_method (c_guestfs, "rm",
+        ruby_guestfs_rm, 1);
+  rb_define_method (c_guestfs, "rmdir",
+        ruby_guestfs_rmdir, 1);
+  rb_define_method (c_guestfs, "rm_rf",
+        ruby_guestfs_rm_rf, 1);
+  rb_define_method (c_guestfs, "mkdir",
+        ruby_guestfs_mkdir, 1);
+  rb_define_method (c_guestfs, "mkdir_p",
+        ruby_guestfs_mkdir_p, 1);
+  rb_define_method (c_guestfs, "chmod",
+        ruby_guestfs_chmod, 2);
+  rb_define_method (c_guestfs, "chown",
+        ruby_guestfs_chown, 3);
+  rb_define_method (c_guestfs, "exists",
+        ruby_guestfs_exists, 1);
+  rb_define_method (c_guestfs, "is_file",
+        ruby_guestfs_is_file, 1);
+  rb_define_method (c_guestfs, "is_dir",
+        ruby_guestfs_is_dir, 1);
+  rb_define_method (c_guestfs, "pvcreate",
+        ruby_guestfs_pvcreate, 1);
+  rb_define_method (c_guestfs, "vgcreate",
+        ruby_guestfs_vgcreate, 2);
+  rb_define_method (c_guestfs, "lvcreate",
+        ruby_guestfs_lvcreate, 3);
+  rb_define_method (c_guestfs, "mkfs",
+        ruby_guestfs_mkfs, 2);
+  rb_define_method (c_guestfs, "sfdisk",
+        ruby_guestfs_sfdisk, 5);
+  rb_define_method (c_guestfs, "write_file",
+        ruby_guestfs_write_file, 3);
+  rb_define_method (c_guestfs, "umount",
+        ruby_guestfs_umount, 1);
+  rb_define_method (c_guestfs, "mounts",
+        ruby_guestfs_mounts, 0);
+  rb_define_method (c_guestfs, "umount_all",
+        ruby_guestfs_umount_all, 0);
+  rb_define_method (c_guestfs, "lvm_remove_all",
+        ruby_guestfs_lvm_remove_all, 0);
+  rb_define_method (c_guestfs, "file",
+        ruby_guestfs_file, 1);
+  rb_define_method (c_guestfs, "command",
+        ruby_guestfs_command, 1);
+  rb_define_method (c_guestfs, "command_lines",
+        ruby_guestfs_command_lines, 1);
+  rb_define_method (c_guestfs, "stat",
+        ruby_guestfs_stat, 1);
+  rb_define_method (c_guestfs, "lstat",
+        ruby_guestfs_lstat, 1);
+  rb_define_method (c_guestfs, "statvfs",
+        ruby_guestfs_statvfs, 1);
+  rb_define_method (c_guestfs, "tune2fs_l",
+        ruby_guestfs_tune2fs_l, 1);
+  rb_define_method (c_guestfs, "blockdev_setro",
+        ruby_guestfs_blockdev_setro, 1);
+  rb_define_method (c_guestfs, "blockdev_setrw",
+        ruby_guestfs_blockdev_setrw, 1);
+  rb_define_method (c_guestfs, "blockdev_getro",
+        ruby_guestfs_blockdev_getro, 1);
+  rb_define_method (c_guestfs, "blockdev_getss",
+        ruby_guestfs_blockdev_getss, 1);
+  rb_define_method (c_guestfs, "blockdev_getbsz",
+        ruby_guestfs_blockdev_getbsz, 1);
+  rb_define_method (c_guestfs, "blockdev_setbsz",
+        ruby_guestfs_blockdev_setbsz, 2);
+  rb_define_method (c_guestfs, "blockdev_getsz",
+        ruby_guestfs_blockdev_getsz, 1);
+  rb_define_method (c_guestfs, "blockdev_getsize64",
+        ruby_guestfs_blockdev_getsize64, 1);
+  rb_define_method (c_guestfs, "blockdev_flushbufs",
+        ruby_guestfs_blockdev_flushbufs, 1);
+  rb_define_method (c_guestfs, "blockdev_rereadpt",
+        ruby_guestfs_blockdev_rereadpt, 1);
+}
diff --git a/ruby/ext/guestfs/extconf.rb b/ruby/ext/guestfs/extconf.rb
new file mode 100644 (file)
index 0000000..67389fd
--- /dev/null
@@ -0,0 +1,30 @@
+# libguestfs Ruby bindings -*- ruby -*-
+# @configure_input@
+# 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.
+
+require 'mkmf'
+
+extension_name = '_guestfs'
+
+dir_config(extension_name)
+
+unless have_library("guestfs", "guestfs_create")
+  raise "libguestfs not found"
+end
+
+create_header
+create_makefile(extension_name)
diff --git a/ruby/lib/guestfs.rb b/ruby/lib/guestfs.rb
new file mode 100644 (file)
index 0000000..28c3785
--- /dev/null
@@ -0,0 +1,18 @@
+# libvirt Ruby bindings
+# 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
+
+require '_guestfs'
diff --git a/ruby/run-ruby-tests b/ruby/run-ruby-tests
new file mode 100755 (executable)
index 0000000..9e8908c
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh -
+# libguestfs Ruby 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.
+
+export LD_LIBRARY_PATH=../src/.libs
+export LIBGUESTFS_PATH=$(cd .. && pwd)
+rake test "$@"
+
diff --git a/ruby/tests/tc_010_load.rb b/ruby/tests/tc_010_load.rb
new file mode 100644 (file)
index 0000000..6d882db
--- /dev/null
@@ -0,0 +1,28 @@
+# libguestfs Ruby bindings -*- ruby -*-
+# 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.
+
+require 'test/unit'
+$:.unshift(File::join(File::dirname(__FILE__), "..", "lib"))
+$:.unshift(File::join(File::dirname(__FILE__), "..", "ext", "guestfs"))
+require 'guestfs'
+
+class TestLoad < Test::Unit::TestCase
+  def test_load
+    g = Guestfs::create()
+    assert_not_nil (g)
+  end
+end
diff --git a/ruby/tests/tc_050_lvcreate.rb b/ruby/tests/tc_050_lvcreate.rb
new file mode 100644 (file)
index 0000000..ea87e39
--- /dev/null
@@ -0,0 +1,49 @@
+# libguestfs Ruby bindings -*- ruby -*-
+# 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.
+
+require 'test/unit'
+$:.unshift(File::join(File::dirname(__FILE__), "..", "lib"))
+$:.unshift(File::join(File::dirname(__FILE__), "..", "ext", "guestfs"))
+require 'guestfs'
+
+class TestLoad < Test::Unit::TestCase
+  def test_lvcreate
+    g = Guestfs::create()
+
+    File.open("test.img", "w") {
+      |f| f.seek(500*1024*1024); f.write("\0")
+    }
+
+    g.add_drive("test.img")
+    g.launch()
+    g.wait_ready()
+
+    g.pvcreate("/dev/sda")
+    g.vgcreate("VG", ["/dev/sda"]);
+    g.lvcreate("LV1", "VG", 200);
+    g.lvcreate("LV2", "VG", 200);
+
+    lvs = g.lvs()
+    if lvs != ["/dev/VG/LV1", "/dev/VG/LV2"]
+      raise "incorrect lvs returned"
+    end
+
+    g.sync()
+
+    File.unlink("test.img")
+  end
+end
index 41fc0c8..c0a4740 100755 (executable)
@@ -4863,6 +4863,242 @@ and pod2text ~width name longdesc =
   | Unix.WSIGNALED i | Unix.WSTOPPED i ->
       failwithf "pod2text: process signalled or stopped by signal %d" i
 
+(* Generate ruby bindings. *)
+and generate_ruby_c () =
+  generate_header CStyle LGPLv2;
+
+  pr "\
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <ruby.h>
+
+#include \"guestfs.h\"
+
+#include \"extconf.h\"
+
+static VALUE m_guestfs;                        /* guestfs module */
+static VALUE c_guestfs;                        /* guestfs_h handle */
+static VALUE e_Error;                  /* used for all errors */
+
+static void ruby_guestfs_free (void *p)
+{
+  if (!p) return;
+  guestfs_close ((guestfs_h *) p);
+}
+
+static VALUE ruby_guestfs_create (VALUE m)
+{
+  guestfs_h *g;
+
+  g = guestfs_create ();
+  if (!g)
+    rb_raise (e_Error, \"failed to create guestfs handle\");
+
+  /* Don't print error messages to stderr by default. */
+  guestfs_set_error_handler (g, NULL, NULL);
+
+  /* Wrap it, and make sure the close function is called when the
+   * handle goes away.
+   */
+  return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
+}
+
+static VALUE ruby_guestfs_close (VALUE gv)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+
+  ruby_guestfs_free (g);
+  DATA_PTR (gv) = NULL;
+
+  return Qnil;
+}
+
+";
+
+  List.iter (
+    fun (name, style, _, _, _, _, _) ->
+      pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
+      List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
+      pr ")\n";
+      pr "{\n";
+      pr "  guestfs_h *g;\n";
+      pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
+      pr "  if (!g)\n";
+      pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
+       name;
+      pr "\n";
+
+      List.iter (
+       function
+       | String n ->
+           pr "  const char *%s = StringValueCStr (%sv);\n" n n;
+           pr "  if (!%s)\n" n;
+           pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
+           pr "              \"%s\", \"%s\");\n" n name
+       | OptString n ->
+           pr "  const char *%s = StringValueCStr (%sv);\n" n n
+       | StringList n ->
+           pr "  char **%s;" n;
+           pr "  {\n";
+           pr "    int i, len;\n";
+           pr "    len = RARRAY_LEN (%sv);\n" n;
+           pr "    %s = malloc (sizeof (char *) * (len+1));\n" n;
+           pr "    for (i = 0; i < len; ++i) {\n";
+           pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
+           pr "      %s[i] = StringValueCStr (v);\n" n;
+           pr "    }\n";
+           pr "  }\n";
+       | Bool n
+       | Int n ->
+           pr "  int %s = NUM2INT (%sv);\n" n n
+      ) (snd style);
+      pr "\n";
+
+      let error_code =
+       match fst style with
+       | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
+       | RInt64 _ -> pr "  int64_t r;\n"; "-1"
+       | RConstString _ -> pr "  const char *r;\n"; "NULL"
+       | RString _ -> pr "  char *r;\n"; "NULL"
+       | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
+       | RIntBool _ -> pr "  struct guestfs_int_bool *r;\n"; "NULL"
+       | RPVList n -> pr "  struct guestfs_lvm_pv_list *r;\n"; "NULL"
+       | RVGList n -> pr "  struct guestfs_lvm_vg_list *r;\n"; "NULL"
+       | RLVList n -> pr "  struct guestfs_lvm_lv_list *r;\n"; "NULL"
+       | RStat n -> pr "  struct guestfs_stat *r;\n"; "NULL"
+       | RStatVFS n -> pr "  struct guestfs_statvfs *r;\n"; "NULL" in
+      pr "\n";
+
+      pr "  r = guestfs_%s " name;
+      generate_call_args ~handle:"g" style;
+      pr ";\n";
+
+      List.iter (
+       function
+       | String _ | OptString _ | Bool _ | Int _ -> ()
+       | StringList n ->
+           pr "  free (%s);\n" n
+      ) (snd style);
+
+      pr "  if (r == %s)\n" error_code;
+      pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
+      pr "\n";
+
+      (match fst style with
+       | RErr ->
+          pr "  return Qnil;\n"
+       | RInt _ | RBool _ ->
+          pr "  return INT2NUM (r);\n"
+       | RInt64 _ ->
+          pr "  return ULL2NUM (r);\n"
+       | RConstString _ ->
+          pr "  return rb_str_new2 (r);\n";
+       | RString _ ->
+          pr "  VALUE rv = rb_str_new2 (r);\n";
+          pr "  free (r);\n";
+          pr "  return rv;\n";
+       | RStringList _ ->
+          pr "  int i, len = 0;\n";
+          pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
+          pr "  VALUE rv = rb_ary_new2 (len);\n";
+          pr "  for (i = 0; r[i] != NULL; ++i) {\n";
+          pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
+          pr "    free (r[i]);\n";
+          pr "  }\n";
+          pr "  free (r);\n";
+          pr "  return rv;\n"
+       | RIntBool _ ->
+          pr "  VALUE rv = rb_ary_new2 (2);\n";
+          pr "  rb_ary_push (rv, INT2NUM (r->i));\n";
+          pr "  rb_ary_push (rv, INT2NUM (r->b));\n";
+          pr "  guestfs_free_int_bool (r);\n";
+          pr "  return rv;\n"
+       | RPVList n ->
+          generate_ruby_lvm_code "pv" pv_cols
+       | RVGList n ->
+          generate_ruby_lvm_code "vg" vg_cols
+       | RLVList n ->
+          generate_ruby_lvm_code "lv" lv_cols
+       | RStat n ->
+          pr "  VALUE rv = rb_hash_new ();\n";
+          List.iter (
+            function
+            | name, `Int ->
+                pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
+          ) stat_cols;
+          pr "  free (r);\n";
+          pr "  return rv;\n"
+       | RStatVFS n ->
+          pr "  VALUE rv = rb_hash_new ();\n";
+          List.iter (
+            function
+            | name, `Int ->
+                pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
+          ) statvfs_cols;
+          pr "  free (r);\n";
+          pr "  return rv;\n"
+       | RHashtable _ ->
+          pr "  VALUE rv = rb_hash_new ();\n";
+          pr "  int i;\n";
+          pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
+          pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
+          pr "    free (r[i]);\n";
+          pr "    free (r[i+1]);\n";
+          pr "  }\n";
+          pr "  free (r);\n";
+          pr "  return rv;\n"
+      );
+
+      pr "}\n";
+      pr "\n"
+  ) all_functions;
+
+  pr "\
+/* Initialize the module. */
+void Init__guestfs ()
+{
+  m_guestfs = rb_define_module (\"Guestfs\");
+  c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
+  e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
+
+  rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
+  rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
+
+";
+  (* Define the rest of the methods. *)
+  List.iter (
+    fun (name, style, _, _, _, _, _) ->
+      pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
+      pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
+  ) all_functions;
+
+  pr "}\n"
+
+(* Ruby code to return an LVM struct list. *)
+and generate_ruby_lvm_code typ cols =
+  pr "  VALUE rv = rb_ary_new2 (r->len);\n";
+  pr "  int i;\n";
+  pr "  for (i = 0; i < r->len; ++i) {\n";
+  pr "    VALUE hv = rb_hash_new ();\n";
+  List.iter (
+    function
+    | name, `String ->
+       pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
+    | name, `UUID ->
+       pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
+    | name, `Bytes
+    | name, `Int ->
+       pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
+    | name, `OptPercent ->
+       pr "    rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
+  ) cols;
+  pr "    rb_ary_push (rv, hv);\n";
+  pr "  }\n";
+  pr "  guestfs_free_lvm_%s_list (r);\n" typ;
+  pr "  return rv;\n"
+
 let output_to filename =
   let filename_new = filename ^ ".new" in
   chan := open_out filename_new;
@@ -4962,3 +5198,7 @@ Run it from the top source directory using the command
   let close = output_to "python/guestfs.py" in
   generate_python_py ();
   close ();
+
+  let close = output_to "ruby/ext/guestfs/_guestfs.c" in
+  generate_ruby_c ();
+  close ();