Experimental implementation of the supermin appliance (passes most tests).
authorRichard Jones <rjones@trick.home.annexia.org>
Mon, 15 Jun 2009 10:50:35 +0000 (11:50 +0100)
committerRichard Jones <rjones@trick.home.annexia.org>
Mon, 15 Jun 2009 19:38:12 +0000 (20:38 +0100)
.gitignore
appliance/Makefile.am
appliance/guestfs-supermin-helper.in [new file with mode: 0755]
appliance/kmod.whitelist.in [moved from appliance/kmod.whitelist with 100% similarity]
appliance/make.sh.in
appliance/supermin-make.sh.in [new file with mode: 0755]
appliance/supermin-split.sh.in [new file with mode: 0755]
configure.ac
src/guestfs.c

index b64c377..3e5ba21 100644 (file)
@@ -20,8 +20,14 @@ ChangeLog
 Makefile.in
 Makefile
 aclocal.m4
+appliance/guestfs-supermin-helper
 appliance/initramfs.*.img
+appliance/initramfs.*.supermin.hostfiles
+appliance/kmod.whitelist
 appliance/make.sh
+appliance/supermin-make.sh
+appliance/supermin-split.sh
+appliance/supermin.incfiles
 appliance/update.sh
 appliance/vmlinuz.*
 autom4te.cache
index 5dd6521..3362992 100644 (file)
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 EXTRA_DIST = \
-       make.sh update.sh
+       make.sh update.sh supermin-split.sh supermin-make.sh
 
 # Build the root filesystem (appliance).
 # Currently this is arch-dependent, so it seems like putting it in
 # $(libdir) is best.  When we build cross-architecture filesystems we
 # should probably move them to $(datadir).
-
 fsdir = $(libdir)/guestfs
-
+fs_DATA = $(APPLIANCE_FILES)
+
+# These are the resulting output files from the whole process:
+#   VMLINUZ        kernel for the full appliance
+#   INITRAMFSIMG   initramfs (ie. root fs) for the full appliance
+# For details of the supermin appliance, read the README file:
+#   SUPERMINIMG    initramfs (ie. partial root fs) for the supermin appliance
+#   SUPERMINFILES  list of missing files (the ones we will pull out of the
+#                    host filesystem at runtime) in the supermin appliance
+APPLIANCE_FILES = $(INITRAMFSIMG) $(VMLINUZ)
+if SUPERMIN
+APPLIANCE_FILES += $(SUPERMINIMG) $(SUPERMINFILES) kmod.whitelist
+bin_SCRIPTS = guestfs-supermin-helper
+endif
+
+# Don't change these names - they must be the same as in '*.sh' scripts.
 INITRAMFSIMG = initramfs.$(REPO).$(host_cpu).img
 VMLINUZ = vmlinuz.$(REPO).$(host_cpu)
+if SUPERMIN
+SUPERMINIMG = initramfs.$(REPO).$(host_cpu).supermin.img
+SUPERMINFILES = initramfs.$(REPO).$(host_cpu).supermin.hostfiles
+endif
 
-fs_DATA =  $(INITRAMFSIMG) $(VMLINUZ)
-
+# This is for building the normal appliance:
 $(INITRAMFSIMG) $(VMLINUZ): $(top_builddir)/initramfs/fakeroot.log
 
 $(top_builddir)/initramfs/fakeroot.log: make.sh kmod.whitelist
@@ -37,15 +54,49 @@ $(top_builddir)/initramfs/fakeroot.log: make.sh kmod.whitelist
        -mv $(VMLINUZ) $(VMLINUZ).bak
        if ! bash make.sh; then rm -f $@; exit 1; fi
 
-$(INITRAMFSIMG): $(top_builddir)/initramfs/fakeroot.log $(top_builddir)/daemon/guestfsd
+$(INITRAMFSIMG): $(top_builddir)/initramfs/fakeroot.log $(top_builddir)/daemon/guestfsd update.sh
        rm -f $@
        bash update.sh
        touch $@
 
-make.sh: make.sh.in
+kmod.whitelist: kmod.whitelist.in
+       grep -v '^[[:space:]]*$$' < $< | grep -v '^#' > $@
+
+# This is for building the supermin appliance.  It has to be enabled
+# specifically with './configure --enable-supermin'.  You really need
+# to read the README file.
+
+if SUPERMIN
+
+# First we need to decide which files go in and out of the supermin
+# appliance.  This decision is made by 'supermin-split.sh'.
+$(SUPERMINFILES): supermin.incfiles
+supermin.incfiles: $(top_builddir)/initramfs/fakeroot.log supermin-split.sh
+       rm -f supermin.incfiles $(SUPERMINFILES)
+       bash supermin-split.sh
+
+# Second we need to create a supermin appliance with just the included
+# files (leaving out the host files, which we'll add back at runtime).
+$(SUPERMINIMG): supermin.incfiles supermin-make.sh
+       rm -f $@
+       bash supermin-make.sh
+
+endif
+
+# This should rebuild the scripts if the input files change, although
+# it doesn't always seem to work.
+%.sh: %.sh.in
        cd .. && ./config.status appliance/$@
+       chmod +x $@
+
+guestfs-supermin-helper: guestfs-supermin-helper.in
+       cd .. && ./config.status appliance/$@
+       chmod +x $@
+
+#----------------------------------------------------------------------
+# Extra rules for testing the appliance.
 
-# Test-boot the image.
+# Test-boot the appliance.
 
 test-boot: emptydisk
        qemu-system-$(host_cpu) \
@@ -75,7 +126,7 @@ test-boot-realistic: emptydisk
 
 # Make clean.
 
-CLEANFILES = $(fs_DATA)
+CLEANFILES = $(APPLIANCE_FILES)
 
 clean-local:
        rm -rf $(top_builddir)/initramfs
diff --git a/appliance/guestfs-supermin-helper.in b/appliance/guestfs-supermin-helper.in
new file mode 100755 (executable)
index 0000000..1384ef6
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/bash -
+# @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.
+
+# Helper script which constructs the supermin appliance at runtime.
+
+unset CDPATH
+
+set -e
+
+# Source directory containing the supermin input files.
+sourcedir=$(cd "$1" > /dev/null; pwd)
+
+# Output files.
+kernel="$2"
+initrd="$3"
+
+# Look for the kernel first.  This is very unsophisticated: We
+# just look for any kernel named vmlinuz-*.$host_cpu which has a
+# corresponding /lib/modules/*.$host_cpu directory.
+
+for f in /boot/vmlinuz-*.@host_cpu@; do
+    b=$(basename "$f")
+    b=$(echo "$b" | sed 's,vmlinuz-,,')
+    modpath="/lib/modules/$b"
+    if [ -d "$modpath" ]; then
+       ln -sf "$f" "$kernel"
+       break
+    fi
+    modpath=
+done
+
+if [ -z "$modpath" ]; then
+    echo "$0: failed to find a suitable kernel" >&2
+    exit 1
+fi
+
+# The initrd consists of these components:
+# (1) The base skeleton appliance that we constructed at build time.
+#     name = initramfs.@REPO@.@host_cpu@.supermin.img
+#     format = compressed cpio
+# (2) The modules from modpath which are on the module whitelist.
+#     format = plain cpio
+# (3) The host files which match wildcards in *.supermin.hostfiles.
+#     format = plain cpio
+
+cp "$sourcedir"/initramfs.@REPO@.@host_cpu@.supermin.img "$initrd"
+
+# Kernel modules (2).
+exec 5<"$sourcedir"/kmod.whitelist
+whitelist=
+while read kmod 0<&5; do
+    whitelist="$whitelist -a -not -name $kmod"
+done
+exec 5<&-
+
+find "$modpath" -not -name '*.ko' -o \( -name '*.ko' $whitelist \) -a -print0 |
+  cpio --quiet -o -0 -H newc >> "$initrd"
+
+# Host files (3).
+
+(cd / && \
+  ls -1df $(
+      cat "$sourcedir"/initramfs.@REPO@.@host_cpu@.supermin.hostfiles
+    ) 2>/dev/null |
+  cpio --quiet -o -H newc ) >> "$initrd"
index 8f3b212..9d77bea 100755 (executable)
@@ -80,18 +80,22 @@ rm -f $koutput
 # Don't need any keyboard maps.
 @FEBOOTSTRAP_RUN@ initramfs -- rm -rf /lib/kbd
 
+# Remove anything in home directory.  Because this is potentially
+# liable to monstrous fuck-ups, we don't put a slash before 'home'.
+(cd initramfs && echo home/*) |
+  xargs @FEBOOTSTRAP_RUN@ initramfs -- rm -rf
+
+# Remove /var/lib/yum stuff.
+@FEBOOTSTRAP_RUN@ initramfs -- rm -rf /var/lib/yum
+
 # Kernel modules take up nearly half of the image.  Only include ones
 # which are on the whitelist.
-grep -v '^[[:space:]]*$' < appliance/kmod.whitelist |
-  grep -v '^#' > kmod.whitelist.tmp
-exec 5<kmod.whitelist.tmp
+exec 5<appliance/kmod.whitelist
 whitelist=
 while read kmod 0<&5; do
     whitelist="$whitelist -a -not -name $kmod"
 done
 exec 5<&-
-rm kmod.whitelist.tmp
-#echo whitelist=$whitelist
 
 (cd initramfs && \
   find lib/modules/*/kernel -name '*.ko' $whitelist -a -print0 ) |
diff --git a/appliance/supermin-make.sh.in b/appliance/supermin-make.sh.in
new file mode 100755 (executable)
index 0000000..b993833
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash -
+# @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.
+
+# Build the supermin appliance.
+# Read the README file!
+
+unset CDPATH
+
+set -e
+
+cd @top_builddir@
+
+output=appliance/initramfs.@REPO@.@host_cpu@.supermin.img
+
+# Generate final image.
+@FEBOOTSTRAP_TO_INITRAMFS@ --files=$(pwd)/appliance/supermin.incfiles initramfs > $output-t
+mv $output-t $output
+ls -lh $output
diff --git a/appliance/supermin-split.sh.in b/appliance/supermin-split.sh.in
new file mode 100755 (executable)
index 0000000..fe4ab6e
--- /dev/null
@@ -0,0 +1,93 @@
+#!/bin/bash -
+# @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.
+
+# Decide which files will stay in the supermin appliance and which
+# files will be pulled out of the host at runtime.
+#
+# Read the README file!
+#
+# The basic idea is that we create two output files, one containing
+# the files that will stay, and the other listing the files that
+# will be pulled from the host (ie. not go into the appliance now).
+#
+# The list of files that stay ('supermin.incfiles') is just a straight
+# list of files and directories.
+#
+# The list of files that come from the host ('*.supermin.hostfiles')
+# can include wildcards, to allow libraries to be upgraded on the
+# host.
+
+unset CDPATH
+
+set -e
+
+cd @top_builddir@/initramfs
+
+incfiles=../appliance/supermin.incfiles
+hostfiles=../appliance/initramfs.@REPO@.@host_cpu@.supermin.hostfiles
+
+exec 5>$incfiles
+exec 6>$hostfiles
+
+# Note currently the initramfs contains ~2500 files, and none have
+# "funny characters" in the names.  So this is reasonable just to
+# simplify the script.
+for path in $(find -not -name fakeroot.log); do
+    dir=$(dirname "$path")
+    file=$(basename "$path")
+
+    # All we're going to keep are the special files /init, the daemon,
+    # configuration files (/etc), devices and modifiable stuff (/var).
+    if [ "$path" = "./init" -o "$file" = "guestfsd" ]; then
+       echo "$path" >&5
+
+    elif [[ "$path" =~ '^\./etc' || "$path" =~ '^./dev' || "$path" =~ '^\./var' ]]; then
+       echo "$path" >&5
+
+    # Kernel modules are always copied in from the host, including all
+    # the dependency files.
+    elif [[ "$path" =~ '^\./lib/modules/' ]]; then
+       :
+
+    elif [ -d "$path" ]; then
+       # Always write directory names to both output files.
+       echo "$path" >&5
+       echo "$path" >&6
+
+    # Some libraries need fixed version numbers replaced by wildcards.
+
+    elif [[ "$file" =~ '^ld-[.0-9]+\.so$' ]]; then
+       echo "$dir/ld-*.so" >&6
+
+    # libfoo-1.2.3.so
+    elif [[ "$file" =~ '^lib(.*)-[-.0-9]+\.so$' ]]; then
+       echo "$dir/lib${BASH_REMATCH[1]}-*.so" >&6
+
+    # libfoo-1.2.3.so.1.2.3 (but NOT '*.so.N')
+    elif [[ "$file" =~ '^lib(.*)-[-.0-9]+\.so\.([0-9]+)\.' ]]; then
+       echo "$dir/lib${BASH_REMATCH[1]}-*.so.${BASH_REMATCH[2]}.*" >&6
+
+    # libfoo.so.1.2.3 (but NOT '*.so.N')
+    elif [[ "$file" =~ '^lib(.*)\.so\.([0-9]+)\.' ]]; then
+       echo "$dir/lib${BASH_REMATCH[1]}.so.${BASH_REMATCH[2]}.*" >&6
+
+    else
+       # Anything else comes from the host directly.
+       echo "$path" >&6
+    fi
+done
index e73799a..be1ed6b 100644 (file)
@@ -480,6 +480,8 @@ AC_CONFIG_FILES([Makefile
                 src/Makefile fish/Makefile po/Makefile.in examples/Makefile
                 appliance/Makefile
                 appliance/make.sh appliance/update.sh
+                appliance/supermin-split.sh appliance/supermin-make.sh
+                appliance/guestfs-supermin-helper
                 images/Makefile
                 capitests/Makefile
                 regressions/Makefile
@@ -495,7 +497,7 @@ AC_CONFIG_FILES([Makefile
 AC_OUTPUT
 
 dnl WTF?
-chmod +x appliance/make.sh appliance/update.sh
+chmod +x appliance/*.sh appliance/guestfs-supermin-helper
 
 dnl Produce summary.
 echo
index fea8107..8f06d3b 100644 (file)
@@ -31,6 +31,7 @@
 #include <time.h>
 #include <sys/stat.h>
 #include <sys/select.h>
+#include <dirent.h>
 
 #include <rpc/types.h>
 #include <rpc/xdr.h>
@@ -309,6 +310,12 @@ guestfs_close (guestfs_h *g)
     snprintf (filename, sizeof filename, "%s/sock", g->tmpdir);
     unlink (filename);
 
+    snprintf (filename, sizeof filename, "%s/initrd", g->tmpdir);
+    unlink (filename);
+
+    snprintf (filename, sizeof filename, "%s/kernel", g->tmpdir);
+    unlink (filename);
+
     rmdir (g->tmpdir);
 
     free (g->tmpdir);
@@ -706,6 +713,46 @@ guestfs_add_cdrom (guestfs_h *g, const char *filename)
   return guestfs_config (g, "-cdrom", filename);
 }
 
+/* Returns true iff file is contained in dir. */
+static int
+dir_contains_file (const char *dir, const char *file)
+{
+  int dirlen = strlen (dir);
+  int filelen = strlen (file);
+  int len = dirlen+filelen+2;
+  char path[len];
+
+  snprintf (path, len, "%s/%s", dir, file);
+  return access (path, F_OK) == 0;
+}
+
+/* Returns true iff every listed file is contained in 'dir'. */
+static int
+dir_contains_files (const char *dir, ...)
+{
+  va_list args;
+  const char *file;
+
+  va_start (args, dir);
+  while ((file = va_arg (args, const char *)) != NULL) {
+    if (!dir_contains_file (dir, file)) {
+      va_end (args);
+      return 0;
+    }
+  }
+  va_end (args);
+  return 1;
+}
+
+static int build_supermin_appliance (guestfs_h *g, const char *path, char **kernel, char **initrd);
+
+static const char *kernel_name = "vmlinuz." REPO "." host_cpu;
+static const char *initrd_name = "initramfs." REPO "." host_cpu ".img";
+static const char *supermin_name =
+  "initramfs." REPO "." host_cpu ".supermin.img";
+static const char *supermin_hostfiles_name =
+  "initramfs." REPO "." host_cpu ".supermin.hostfiles";
+
 int
 guestfs_launch (guestfs_h *g)
 {
@@ -714,8 +761,6 @@ guestfs_launch (guestfs_h *g)
   size_t len;
   int wfd[2], rfd[2];
   int tries;
-  const char *kernel_name = "vmlinuz." REPO "." host_cpu;
-  const char *initrd_name = "initramfs." REPO "." host_cpu ".img";
   char *path, *pelem, *pend;
   char *kernel = NULL, *initrd = NULL;
   char unixsock[256];
@@ -732,7 +777,20 @@ guestfs_launch (guestfs_h *g)
     return -1;
   }
 
-  /* Search g->path for the kernel and initrd. */
+  /* Make the temporary directory. */
+  if (!g->tmpdir) {
+    g->tmpdir = safe_strdup (g, dir_template);
+    if (mkdtemp (g->tmpdir) == NULL) {
+      perrorf (g, _("%s: cannot create temporary directory"), dir_template);
+      goto cleanup0;
+    }
+  }
+
+  /* First search g->path for the supermin appliance, and try to
+   * synthesize a kernel and initrd from that.  If it fails, we
+   * try the path search again looking for a backup ordinary
+   * appliance.
+   */
   pelem = path = safe_strdup (g, g->path);
   do {
     pend = strchrnul (pelem, ':');
@@ -740,32 +798,31 @@ guestfs_launch (guestfs_h *g)
     *pend = '\0';
     len = pend - pelem;
 
-    /* Empty element or "." means cwd. */
+    /* Empty element of "." means cwd. */
     if (len == 0 || (len == 1 && *pelem == '.')) {
       if (g->verbose)
        fprintf (stderr,
-                "looking for kernel and initrd in current directory\n");
-      if (access (kernel_name, F_OK) == 0 && access (initrd_name, F_OK) == 0) {
-       kernel = safe_strdup (g, kernel_name);
-       initrd = safe_strdup (g, initrd_name);
+                "looking for supermin appliance in current directory\n");
+      if (dir_contains_files (".",
+                             supermin_name, supermin_hostfiles_name,
+                             "kmod.whitelist", NULL)) {
+       if (build_supermin_appliance (g, ".", &kernel, &initrd) == -1)
+         return -1;
        break;
       }
     }
-    /* Look at <path>/kernel etc. */
+    /* Look at <path>/supermin* etc. */
     else {
-      kernel = safe_malloc (g, len + strlen (kernel_name) + 2);
-      initrd = safe_malloc (g, len + strlen (initrd_name) + 2);
-      sprintf (kernel, "%s/%s", pelem, kernel_name);
-      sprintf (initrd, "%s/%s", pelem, initrd_name);
-
       if (g->verbose)
-       fprintf (stderr, "looking for %s and %s\n", kernel, initrd);
+       fprintf (stderr, "looking for supermin appliance in %s\n", pelem);
 
-      if (access (kernel, F_OK) == 0 && access (initrd, F_OK) == 0)
+      if (dir_contains_files (pelem,
+                             supermin_name, supermin_hostfiles_name,
+                             "kmod.whitelist", NULL)) {
+       if (build_supermin_appliance (g, pelem, &kernel, &initrd) == -1)
+         return -1;
        break;
-      free (kernel);
-      free (initrd);
-      kernel = initrd = NULL;
+      }
     }
 
     pelem = pend + 1;
@@ -774,6 +831,46 @@ guestfs_launch (guestfs_h *g)
   free (path);
 
   if (kernel == NULL || initrd == NULL) {
+    /* Search g->path for the kernel and initrd. */
+    pelem = path = safe_strdup (g, g->path);
+    do {
+      pend = strchrnul (pelem, ':');
+      pmore = *pend == ':';
+      *pend = '\0';
+      len = pend - pelem;
+
+      /* Empty element or "." means cwd. */
+      if (len == 0 || (len == 1 && *pelem == '.')) {
+       if (g->verbose)
+         fprintf (stderr,
+                  "looking for appliance in current directory\n");
+       if (dir_contains_files (".", kernel_name, initrd_name, NULL)) {
+         kernel = safe_strdup (g, kernel_name);
+         initrd = safe_strdup (g, initrd_name);
+         break;
+       }
+      }
+      /* Look at <path>/kernel etc. */
+      else {
+       if (g->verbose)
+         fprintf (stderr, "looking for appliance in %s\n", pelem);
+
+       if (dir_contains_files (pelem, kernel_name, initrd_name, NULL)) {
+         kernel = safe_malloc (g, len + strlen (kernel_name) + 2);
+         initrd = safe_malloc (g, len + strlen (initrd_name) + 2);
+         sprintf (kernel, "%s/%s", pelem, kernel_name);
+         sprintf (initrd, "%s/%s", pelem, initrd_name);
+         break;
+       }
+      }
+
+      pelem = pend + 1;
+    } while (pmore);
+
+    free (path);
+  }
+
+  if (kernel == NULL || initrd == NULL) {
     error (g, _("cannot find %s or %s on LIBGUESTFS_PATH (current path = %s)"),
           kernel_name, initrd_name, g->path);
     goto cleanup0;
@@ -788,15 +885,7 @@ guestfs_launch (guestfs_h *g)
    */
   memsize = 384;
 
-  /* Make the temporary directory containing the socket. */
-  if (!g->tmpdir) {
-    g->tmpdir = safe_strdup (g, dir_template);
-    if (mkdtemp (g->tmpdir) == NULL) {
-      perrorf (g, _("%s: cannot create temporary directory"), dir_template);
-      goto cleanup0;
-    }
-  }
-
+  /* Make the vmchannel socket. */
   snprintf (unixsock, sizeof unixsock, "%s/sock", g->tmpdir);
   unlink (unixsock);
 
@@ -1048,6 +1137,34 @@ guestfs_launch (guestfs_h *g)
   return -1;
 }
 
+/* This function does the hard work of building the supermin appliance
+ * on the fly.  'path' is the directory containing the control files.
+ * 'kernel' and 'initrd' are where we will return the names of the
+ * kernel and initrd (only initrd is built).  The work is done by
+ * an external script.  We just tell it where to put the result.
+ */
+static int
+build_supermin_appliance (guestfs_h *g, const char *path,
+                         char **kernel, char **initrd)
+{
+  char cmd[4096];
+  int r;
+
+  snprintf (cmd, sizeof cmd,
+           "PATH='%s':$PATH "
+           "guestfs-supermin-helper '%s' %s/kernel %s/initrd",
+           path,
+           path, g->tmpdir, g->tmpdir);
+
+  r = system (cmd);
+  if (r == -1 || WEXITSTATUS(r) != 0) {
+    error (g, _("external command failed: %s"), cmd);
+    return -1;
+  }
+
+  return 0;
+}
+
 static void
 finish_wait_ready (guestfs_h *g, void *vp)
 {