Add libguestfs-test-tool.
authorRichard Jones <rjones@trick.home.annexia.org>
Wed, 22 Jul 2009 19:58:39 +0000 (20:58 +0100)
committerRichard Jones <rjones@trick.home.annexia.org>
Wed, 22 Jul 2009 22:00:30 +0000 (23:00 +0100)
This is an end-user testing tool, designed to test basic functionality
of libguestfs/qemu/kernel combination on the end-user's final host
machine.

It does not perform a thorough test, but should be enough to find
most booting issues.

Also this is intended to be used when reporting bugs.

.gitignore
HACKING
Makefile.am
configure.ac
guestfs.pod
po/POTFILES.in
test-tool/Makefile.am [new file with mode: 0644]
test-tool/README [new file with mode: 0644]
test-tool/helper.c [new file with mode: 0644]
test-tool/libguestfs-test-tool.pod [new file with mode: 0644]
test-tool/test-tool.c [new file with mode: 0644]

index b12dda6..d66ed99 100644 (file)
@@ -169,4 +169,7 @@ src/guestfs-structs.h
 src/.pod2text.data
 src/stamp-generator
 stamp-h1
+test-tool/libguestfs-test-tool.1
+test-tool/libguestfs-test-tool
+test-tool/libguestfs-test-tool-helper
 v2v/virt-v2v.1
diff --git a/HACKING b/HACKING
index 6ca33be..42f4f77 100644 (file)
--- a/HACKING
+++ b/HACKING
@@ -91,6 +91,9 @@ src/
        Source code to the C library.
        Also contains the crucial generator program.
 
+test-tool/
+       Interactive qemu/kernel test tool.
+
 v2v/
        Xen to KVM (V2V) conversion tool.
 
index 1f6f62e..f118291 100644 (file)
@@ -18,7 +18,7 @@
 ACLOCAL_AMFLAGS = -I m4
 
 SUBDIRS = src daemon appliance fish po examples images \
-       capitests regressions
+       capitests regressions test-tool
 
 if HAVE_OCAML
 SUBDIRS += ocaml
index 1bc1109..bc60608 100644 (file)
@@ -574,6 +574,7 @@ AC_CONFIG_FILES([Makefile
                 images/Makefile
                 capitests/Makefile
                 regressions/Makefile
+                test-tool/Makefile
                 ocaml/Makefile ocaml/examples/Makefile
                 perl/Makefile
                 python/Makefile
index 4235454..6bdc941 100644 (file)
@@ -982,6 +982,11 @@ That you are testing a recent version.
 
 Describe the bug accurately, and give a way to reproduce it.
 
+=item *
+
+Run libguestfs-test-tool and paste the B<complete, unedited>
+output into the bug report.
+
 =back
 
 =head1 AUTHORS
index 7ad1e12..ca01b3d 100644 (file)
@@ -74,4 +74,6 @@ ruby/ext/guestfs/_guestfs.c
 src/guestfs-actions.c
 src/guestfs-bindtests.c
 src/guestfs.c
+test-tool/helper.c
+test-tool/test-tool.c
 v2v/virt-v2v.pl
diff --git a/test-tool/Makefile.am b/test-tool/Makefile.am
new file mode 100644 (file)
index 0000000..510a42f
--- /dev/null
@@ -0,0 +1,44 @@
+# libguestfs
+# 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 = libguestfs-test-tool.pod
+
+CLEANFILES =
+
+bin_PROGRAMS = libguestfs-test-tool
+libexec_PROGRAMS = libguestfs-test-tool-helper
+man_MANS = libguestfs-test-tool.1
+
+AM_CPPFLAGS = \
+       -DDEFAULT_HELPER='"$(libexecdir)/libguestfs-test-tool-helper"'
+
+libguestfs_test_tool_SOURCES = test-tool.c
+libguestfs_test_tool_CFLAGS = \
+       -I$(top_srcdir)/src -I$(top_builddir)/src \
+       -Wall
+libguestfs_test_tool_LDADD = \
+       $(top_builddir)/src/libguestfs.la
+
+libguestfs_test_tool_helper_SOURCES = helper.c
+libguestfs_test_tool_helper_LDFLAGS = -all-static
+
+libguestfs-test-tool.1: libguestfs-test-tool.pod
+       $(POD2MAN) \
+         --section 1 \
+         -c "Virtualization Support" \
+         --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \
+         $< > $@
diff --git a/test-tool/README b/test-tool/README
new file mode 100644 (file)
index 0000000..a98a02d
--- /dev/null
@@ -0,0 +1,9 @@
+This is a test tool, not a comprehensive test, but a "does it
+basically function" test, which can be packaged and given to end
+users.
+
+It also collects and prints a lot of internal debug information, which
+is useful in bug reports to track down appliance / qemu boot problems.
+
+For more information, please read the man page
+libguestfs-test-tool(1).
diff --git a/test-tool/helper.c b/test-tool/helper.c
new file mode 100644 (file)
index 0000000..3395f21
--- /dev/null
@@ -0,0 +1,73 @@
+/* libguestfs-test-tool-helper
+ * 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.
+ */
+
+/* NB. This program is intended to run inside the appliance. */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+char buffer[10 * 1024];
+
+int
+main (void)
+{
+  int fd;
+
+  fprintf (stderr, "This is the libguestfs-test-tool helper program.\n");
+
+  /* This should fail immediately if we're not in the appliance. */
+  if (mkdir ("/tmp", 0700) == -1) {
+    perror ("mkdir");
+    fprintf (stderr, "This program should not be run directly.  Use libguestfs-test-tool instead.\n");
+    exit (1);
+  }
+
+  if (geteuid () != 0) {
+    fprintf (stderr, "helper: This program doesn't appear to be running as root.\n");
+    exit (1);
+  }
+
+  if (mkdir ("/tmp/helper", 0700) == -1) {
+    perror ("/tmp/helper");
+    exit (1);
+  }
+
+  fd = open ("/tmp/helper/a", O_CREAT|O_EXCL|O_WRONLY, 0600);
+  if (fd == -1) {
+    perror ("create /tmp/helper/a");
+    exit (1);
+  }
+  if (write (fd, buffer, sizeof buffer) != sizeof buffer) {
+    perror ("write");
+    exit (1);
+  }
+  if (close (fd) == -1) {
+    perror ("close");
+    exit (1);
+  }
+
+  exit (0);
+}
diff --git a/test-tool/libguestfs-test-tool.pod b/test-tool/libguestfs-test-tool.pod
new file mode 100644 (file)
index 0000000..df8c77b
--- /dev/null
@@ -0,0 +1,136 @@
+=encoding utf8
+
+=head1 NAME
+
+libguestfs-test-tool - End user tests for libguestfs
+
+=head1 SYNOPSIS
+
+ libguestfs-test-tool [--options]
+
+=head1 DESCRIPTION
+
+libguestfs-test-tool is a test program shipped with libguestfs to end
+users and developers, to allow them to check basic libguestfs
+functionality is working.  This is needed because libguestfs
+occasionally breaks for reasons beyond our control: usually because of
+changes in the underlying qemu or kernel packages, or the host
+environment.
+
+If you suspect a problem in libguestfs, then just run:
+
+ libguestfs-test-tool
+
+It will print lots of diagnostic messages.
+
+If it runs to completion successfully, you will see this near the end:
+
+ ===== TEST FINISHED OK =====
+
+and the test tool will exit with code 0.
+
+If it fails (and/or exits with non-zero error code), please paste the
+B<complete, unedited> output of the test tool into a bug report.  More
+information about reporting bugs can be found on the
+L<http://libguestfs.org/> website.
+
+=head1 OPTIONS
+
+=over 4
+
+=item I<--help>
+
+Display short usage information and exit.
+
+=item I<--helper /path/to/libguestfs-test-tool-helper>
+
+Pass an alternate name for the helper program.  libguestfs-test-tool
+will normally look in the C<$libexec> directory that was configured
+when the tool was built.
+
+=item I<--qemu qemu_binary>
+
+If you have downloaded another qemu binary, point this option at the
+full path of the binary to try it.
+
+=item I<--qemudir qemu_source_dir>
+
+If you have compiled qemu from source, point this option at the source
+directory to try it.
+
+=item I<--timeout N>
+
+Set the launch timeout to C<N> seconds.  The default is 120 seconds
+which does not usually need to be adjusted unless your machine is very
+slow.
+
+=back
+
+=head1 TRYING OUT A DIFFERENT VERSION OF QEMU
+
+If you have compiled another version of qemu from source and would
+like to try that, then you can use the I<--qemudir> option to point to
+the qemu source directory.
+
+If you have downloaded a qemu binary from somewhere, use the I<--qemu>
+option to point to the binary.
+
+When using an alternate qemu with libguestfs, usually you would need
+to write a qemu wrapper script (see section I<QEMU WRAPPERS> in
+L<guestfs(3)>).  libguestfs-test-tool writes a temporary qemu wrapper
+script when you use either of the I<--qemudir> or I<--qemu> options.
+
+=head1 EXIT CODE
+
+libguestfs-test-tool returns I<0> if the tests completed without
+error, or I<1> if there was an error.
+
+=head1 FILES
+
+=over 4
+
+=item /usr/libexec/libguestfs-test-tool-helper
+
+This helper program is run inside the appliance and provides
+additional tests.
+
+=item /usr/bin/mkisofs
+
+The C<mkisofs> command is required in order to construct a CD-ROM ISO
+file which is used as part of the tests.
+
+=back
+
+=head1 ENVIRONMENT VARIABLES
+
+For the full list of environment variables which may affect
+libguestfs, please see the L<guestfs(3)> manual page.
+
+=head1 SEE ALSO
+
+L<guestfs(3)>,
+L<http://libguestfs.org/>,
+L<http://qemu.org/>.
+
+=head1 AUTHORS
+
+Richard W.M. Jones (C<rjones at redhat dot com>)
+
+=head1 COPYRIGHT
+
+Copyright (C) 2009 Red Hat Inc.
+L<http://libguestfs.org/>
+
+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.
diff --git a/test-tool/test-tool.c b/test-tool/test-tool.c
new file mode 100644 (file)
index 0000000..9617073
--- /dev/null
@@ -0,0 +1,437 @@
+/* libguestfs-test-tool
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <guestfs.h>
+
+#ifdef HAVE_GETTEXT
+#include "gettext.h"
+#define _(str) dgettext(PACKAGE, (str))
+#define N_(str) dgettext(PACKAGE, (str))
+#else
+#define _(str) str
+#define N_(str) str
+#endif
+
+#define DEFAULT_TIMEOUT 120
+
+static const char *helper = DEFAULT_HELPER;
+static int timeout = DEFAULT_TIMEOUT;
+static char tmpf[] = "/tmp/libguestfs-test-tool-sda-XXXXXX";
+static char isof[] = "/tmp/libguestfs-test-tool-iso-XXXXXX";
+static guestfs_h *g;
+
+static void preruncheck (void);
+static void make_files (void);
+static void set_qemu (const char *path, int use_wrapper);
+
+static void
+usage (void)
+{
+  printf (_("libguestfs-test-tool: interactive test tool\n"
+           "Copyright (C) 2009 Red Hat Inc.\n"
+           "Usage:\n"
+           "  libguestfs-test-tool [--options]\n"
+           "Options:\n"
+           "  --help         Display usage\n"
+           "  --helper libguestfs-test-tool-helper\n"
+           "                 Helper program (default: %s)\n"
+           "  --qemudir dir  Specify QEMU source directory\n"
+           "  --qemu qemu    Specify QEMU binary\n"
+           "  --timeout n\n"
+           "  -t n           Set launch timeout (default: %d seconds)\n"
+           ),
+         DEFAULT_HELPER, DEFAULT_TIMEOUT);
+}
+
+int
+main (int argc, char *argv[])
+{
+  static const char *options = "?";
+  static struct option long_options[] = {
+    { "help", 0, 0, '?' },
+    { "helper", 1, 0, 0 },
+    { "qemu", 1, 0, 0 },
+    { "qemudir", 1, 0, 0 },
+    { "timeout", 1, 0, 't' },
+    { 0, 0, 0, 0 }
+  };
+  int c;
+  int option_index;
+  extern char **environ;
+  int i;
+  struct guestfs_version *vers;
+  char *sfdisk_lines[] = { ",", NULL };
+  char *str;
+  /* XXX This is wrong if the user renames the helper. */
+  char *helper_args[] = { "/iso/libguestfs-test-tool-helper", NULL };
+
+  for (;;) {
+    c = getopt_long (argc, argv, options, long_options, &option_index);
+    if (c == -1) break;
+
+    switch (c) {
+    case 0:                    /* options which are long only */
+      if (strcmp (long_options[option_index].name, "helper") == 0)
+       helper = optarg;
+      else if (strcmp (long_options[option_index].name, "qemu") == 0)
+       set_qemu (optarg, 0);
+      else if (strcmp (long_options[option_index].name, "qemudir") == 0)
+       set_qemu (optarg, 1);
+      else {
+       fprintf (stderr,
+                _("libguestfs-test-tool: unknown long option: %s (%d)\n"),
+                long_options[option_index].name, option_index);
+       exit (1);
+      }
+      break;
+
+    case 't':
+      if (sscanf (optarg, "%d", &timeout) != 1 || timeout < 0) {
+       fprintf (stderr,
+                _("libguestfs-test-tool: invalid timeout: %s\n"),
+                optarg);
+       exit (1);
+      }
+      break;
+
+    case '?':
+      usage ();
+      exit (0);
+
+    default:
+      fprintf (stderr,
+              _("libguestfs-test-tool: unexpected command line option 0x%x\n"),
+              c);
+      exit (1);
+    }
+  }
+
+  preruncheck ();
+  make_files ();
+
+  printf ("===== Test starts here =====\n");
+
+  /* Must set LIBGUESTFS_DEBUG=1 */
+  setenv ("LIBGUESTFS_DEBUG", "1", 1);
+
+  /* Print out any environment variables which may relate to this test. */
+  for (i = 0; environ[i] != NULL; ++i)
+    if (strncmp (environ[i], "LIBGUESTFS_", 11) == 0)
+      printf ("%s\n", environ[i]);
+
+  /* Create the handle and configure it. */
+  g = guestfs_create ();
+  if (g == NULL) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: failed to create libguestfs handle\n"));
+    exit (1);
+  }
+  if (guestfs_add_drive (g, tmpf) == -1) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: failed to add drive '%s'\n"),
+            tmpf);
+    exit (1);
+  }
+  if (guestfs_add_drive (g, isof) == -1) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: failed to add drive '%s'\n"),
+            isof);
+    exit (1);
+  }
+
+  /* Print any version info etc. */
+  vers = guestfs_version (g);
+  if (vers == NULL) {
+    fprintf (stderr, _("libguestfs-test-tool: guestfs_version failed\n"));
+    exit (1);
+  }
+  printf ("library version: %"PRIi64".%"PRIi64".%"PRIi64"%s\n",
+         vers->major, vers->minor, vers->release, vers->extra);
+  guestfs_free_version (vers);
+
+  printf ("guestfs_get_append: %s\n", guestfs_get_append (g) ? : "(null)");
+  printf ("guestfs_get_autosync: %d\n", guestfs_get_autosync (g));
+  printf ("guestfs_get_memsize: %d\n", guestfs_get_memsize (g));
+  printf ("guestfs_get_path: %s\n", guestfs_get_path (g));
+  printf ("guestfs_get_qemu: %s\n", guestfs_get_qemu (g));
+  printf ("guestfs_get_verbose: %d\n", guestfs_get_verbose (g));
+
+  /* Launch the guest handle. */
+  if (guestfs_launch (g) == -1) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: failed to launch appliance\n"));
+    exit (1);
+  }
+
+  printf ("Launching appliance, timeout set to %d seconds.\n", timeout);
+  fflush (stdout);
+
+  alarm (timeout);
+
+  if (guestfs_wait_ready (g) == -1) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: failed or timed out in 'wait_ready'\n"));
+    exit (1);
+  }
+
+  alarm (0);
+
+  printf ("Guest launched OK.\n");
+  fflush (stdout);
+
+  /* Create the filesystem and mount everything. */
+  if (guestfs_sfdiskM (g, "/dev/sda", sfdisk_lines) == -1) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: failed to run sfdisk\n"));
+    exit (1);
+  }
+
+  if (guestfs_mkfs (g, "ext2", "/dev/sda1") == -1) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: failed to mkfs.ext2\n"));
+    exit (1);
+  }
+
+  if (guestfs_mount (g, "/dev/sda1", "/") == -1) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: failed to mount /dev/sda1 on /\n"));
+    exit (1);
+  }
+
+  if (guestfs_mkdir (g, "/iso") == -1) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: failed to mkdir /iso\n"));
+    exit (1);
+  }
+
+  if (guestfs_mount (g, "/dev/sdb", "/iso") == -1) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: failed to mount /dev/sdb on /iso\n"));
+    exit (1);
+  }
+
+  /* Let's now run some simple tests using the helper program. */
+  str = guestfs_command (g, helper_args);
+  if (str == NULL) {
+    fprintf (stderr,
+            _("libguestfs-test-tool: could not run helper program, or helper failed\n"));
+    exit (1);
+  }
+  free (str);
+
+  printf ("===== TEST FINISHED OK =====\n");
+  exit (0);
+}
+
+static char qemuwrapper[] = "/tmp/libguestfs-test-tool-wrapper-XXXXXX";
+
+static void
+cleanup_wrapper (void)
+{
+  unlink (qemuwrapper);
+}
+
+/* Handle the --qemu and --qemudir parameters.  use_wrapper is true
+ * in the --qemudir (source directory) case, where we have to create
+ * a wrapper shell script.
+ */
+static void
+set_qemu (const char *path, int use_wrapper)
+{
+  char buffer[PATH_MAX];
+  struct stat statbuf;
+  int fd;
+  FILE *fp;
+
+  if (getenv ("LIBGUESTFS_QEMU")) {
+    fprintf (stderr,
+    _("LIBGUESTFS_QEMU environment variable is already set, so\n"
+      "--qemu/--qemudir options cannot be used.\n"));
+    exit (1);
+  }
+
+  if (!use_wrapper) {
+    if (access (path, X_OK) == -1) {
+      fprintf (stderr,
+              _("Binary '%s' does not exist or is not executable\n"),
+              path);
+      exit (1);
+    }
+
+    setenv ("LIBGUESTFS_QEMU", path, 1);
+    return;
+  }
+
+  /* This should be a source directory, so check it. */
+  snprintf (buffer, sizeof buffer, "%s/pc-bios", path);
+  if (stat (buffer, &statbuf) == -1 ||
+      !S_ISDIR (statbuf.st_mode)) {
+    fprintf (stderr,
+            _("%s: does not look like a qemu source directory\n"),
+            path);
+    exit (1);
+  }
+
+  /* Make a wrapper script. */
+  fd = mkstemp (qemuwrapper);
+  if (fd == -1) {
+    perror (qemuwrapper);
+    exit (1);
+  }
+
+  fchmod (fd, 0700);
+
+  fp = fdopen (fd, "w");
+  fprintf (fp,
+          "#!/bin/sh -\n"
+          "qemudir='%s'\n"
+          "\"$qemudir\"/",
+          path);
+
+  /* Select the right qemu binary for the wrapper script. */
+#ifdef __i386__
+  fprintf (fp, "i386-softmmu/qemu");
+#else
+  fprintf (fp, host_cpu "-softmmu/qemu-system-" host_cpu);
+#endif
+
+  fprintf (fp, " -L \"$qemudir\"/pc-bios \"$@\"\n");
+
+  fclose (fp);
+
+  setenv ("LIBGUESTFS_QEMU", qemuwrapper, 1);
+  atexit (cleanup_wrapper);
+}
+
+/* After getting the command line args, but before running
+ * anything, we check everything is in place to do the tests.
+ */
+static void
+preruncheck (void)
+{
+  int r;
+  FILE *fp;
+  char cmd[256];
+  char buffer[1024];
+
+  if (access (helper, R_OK) == -1) {
+    fprintf (stderr,
+    _("Test tool helper program 'libguestfs-test-tool-helper' is not\n"
+      "available.  Expected to find it in '%s'\n"
+      "\n"
+      "Use the --helper option to specify the location of this program.\n"),
+            helper);
+    exit (1);
+  }
+
+  snprintf (cmd, sizeof cmd, "file '%s'", helper);
+  fp = popen (cmd, "r");
+  if (fp == NULL) {
+    perror (cmd);
+    exit (1);
+  }
+  r = fread (buffer, 1, sizeof buffer - 1, fp);
+  if (r == 0) {
+    fprintf (stderr, _("command failed: %s"), cmd);
+    exit (1);
+  }
+  pclose (fp);
+  buffer[r] = '\0';
+
+  if (strstr (buffer, "statically linked") == NULL) {
+    fprintf (stderr,
+    _("Test tool helper program %s\n"
+      "is not statically linked.  This is a build error when this test tool\n"
+      "was built.\n"),
+            helper);
+    exit (1);
+  }
+}
+
+static void
+cleanup_tmpfiles (void)
+{
+  unlink (tmpf);
+  unlink (isof);
+}
+
+static void
+make_files (void)
+{
+  int fd, r;
+  char cmd[256];
+
+  /* Make the ISO which will contain the helper program. */
+  fd = mkstemp (isof);
+  if (fd == -1) {
+    perror (isof);
+    exit (1);
+  }
+  close (fd);
+
+  snprintf (cmd, sizeof cmd, "mkisofs -quiet -rJT -o '%s' '%s'",
+           isof, helper);
+  r = system (cmd);
+  if (r == -1 || WEXITSTATUS(r) != 0) {
+    fprintf (stderr,
+            _("mkisofs command failed: %s\n"), cmd);
+    exit (1);
+  }
+
+  /* Allocate the sparse file for /dev/sda. */
+  fd = mkstemp (tmpf);
+  if (fd == -1) {
+    perror (tmpf);
+    unlink (isof);
+    exit (1);
+  }
+
+  if (lseek (fd, 100 * 1024 * 1024 - 1, SEEK_SET) == -1) {
+    perror ("lseek");
+    close (fd);
+    unlink (tmpf);
+    unlink (isof);
+    exit (1);
+  }
+
+  if (write (fd, "\0", 1) == -1) {
+    perror ("write");
+    close (fd);
+    unlink (tmpf);
+    unlink (isof);
+    exit (1);
+  }
+
+  close (fd);
+
+  atexit (cleanup_tmpfiles);   /* Removes tmpf and isof. */
+}