[Libguestfs] [PATCH] fuse: Add guestmount-cleanup program to handle unmounting (RHBZ#916780).

Richard W.M. Jones rjones at redhat.com
Mon Mar 4 21:30:30 UTC 2013


From: "Richard W.M. Jones" <rjones at redhat.com>

---
 .gitignore                          |   4 +
 fish/test-mount-local.sh            |   8 +-
 fuse/Makefile.am                    |  55 ++++++-
 fuse/guestmount-cleanup.c           | 297 ++++++++++++++++++++++++++++++++++++
 fuse/guestmount-cleanup.pod         | 103 +++++++++++++
 fuse/guestmount.pod                 |   1 +
 fuse/test-fuse-umount-race.sh       |  11 +-
 fuse/test-fuse.sh                   |  25 +--
 ocaml/t/guestfs_500_mount_local.ml  |  37 +----
 po-docs/ja/Makefile.am              |   1 +
 po-docs/podfiles                    |   1 +
 po-docs/uk/Makefile.am              |   1 +
 po/POTFILES                         |   1 +
 sysprep/Makefile.am                 |   1 +
 sysprep/sysprep_operation_script.ml |  14 +-
 tests/selinux/run-test.pl           |  23 +--
 16 files changed, 486 insertions(+), 97 deletions(-)
 create mode 100644 fuse/guestmount-cleanup.c
 create mode 100644 fuse/guestmount-cleanup.pod

diff --git a/.gitignore b/.gitignore
index 0747430..2f46ba0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -141,7 +141,10 @@ Makefile.in
 /format/virt-format.1
 /fuse/guestmount
 /fuse/guestmount.1
+/fuse/guestmount-cleanup
+/fuse/guestmount-cleanup.1
 /fuse/stamp-guestmount.pod
+/fuse/stamp-guestmount-cleanup.pod
 /generator/.depend
 /generator/files-generated.txt
 /generator/generator
@@ -181,6 +184,7 @@ Makefile.in
 /html/guestfs-testing.1.html
 /html/guestfsd.8.html
 /html/guestmount.1.html
+/html/guestmount-cleanup.1.html
 /html/libguestfs-make-fixed-appliance.1.html
 /html/libguestfs-test-tool.1.html
 /html/virt-alignment-scan.1.html
diff --git a/fish/test-mount-local.sh b/fish/test-mount-local.sh
index ad62a92..ca26088 100755
--- a/fish/test-mount-local.sh
+++ b/fish/test-mount-local.sh
@@ -1,6 +1,6 @@
 #!/bin/bash -
 # libguestfs
-# Copyright (C) 2012 Red Hat Inc.
+# Copyright (C) 2012-2013 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
@@ -51,11 +51,7 @@ if [ $# -gt 0 -a "$1" = "--run-test" ]; then
     echo 'mount-local test successful' > mp/ok
 
     # Unmount the mountpoint.  Might need to retry this.
-    count=10
-    while ! fusermount -u mp && [ $count -gt 0 ]; do
-        sleep 1
-        ((count--))
-    done
+    ../fuse/guestmount-cleanup mp
 
     exit 0
 fi
diff --git a/fuse/Makefile.am b/fuse/Makefile.am
index 12905a3..fc5f54e 100644
--- a/fuse/Makefile.am
+++ b/fuse/Makefile.am
@@ -17,13 +17,21 @@
 
 include $(top_srcdir)/subdir-rules.mk
 
-EXTRA_DIST = guestmount.pod test-fuse.sh test-fuse-umount-race.sh
+EXTRA_DIST = \
+	guestmount.pod \
+	guestmount-cleanup.pod \
+	test-fuse.sh \
+	test-fuse-umount-race.sh
 
-CLEANFILES = stamp-guestmount.pod
+CLEANFILES = \
+	stamp-guestmount.pod \
+	stamp-guestmount-cleanup.pod
 
 if HAVE_FUSE
 
-bin_PROGRAMS = guestmount
+bin_PROGRAMS = \
+	guestmount \
+	guestmount-cleanup
 
 # These source files (all related to option parsing) are shared
 # between guestfish and guestmount.
@@ -35,6 +43,8 @@ SHARED_SOURCE_FILES = \
 	../fish/options.h \
 	../fish/options.c
 
+# guestmount
+
 guestmount_SOURCES = \
 	$(SHARED_SOURCE_FILES) \
 	guestmount.c
@@ -61,10 +71,35 @@ guestmount_LDADD = \
 	$(LIBVIRT_LIBS) \
 	../gnulib/lib/libgnu.la
 
+# guestmount-cleanup
+
+guestmount_cleanup_SOURCES = \
+	guestmount-cleanup.c
+
+guestmount_cleanup_CPPFLAGS = \
+	-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
+	-I$(top_srcdir)/src -I$(top_builddir)/src \
+	-I$(srcdir)/../gnulib/lib -I../gnulib/lib
+
+guestmount_cleanup_CFLAGS = \
+	$(WARN_CFLAGS) $(WERROR_CFLAGS) \
+	$(GPROF_CFLAGS) $(GCOV_CFLAGS)
+
+guestmount_cleanup_LDADD = \
+	$(top_builddir)/src/libutils.la \
+	$(top_builddir)/src/libguestfs.la \
+	$(LIBXML2_LIBS) \
+	$(LIBVIRT_LIBS) \
+	../gnulib/lib/libgnu.la
+
 # Documentation.
 
-man_MANS = guestmount.1
-noinst_DATA = $(top_builddir)/html/guestmount.1.html
+man_MANS = \
+	guestmount.1 \
+	guestmount-cleanup.1
+noinst_DATA = \
+	$(top_builddir)/html/guestmount.1.html \
+	$(top_builddir)/html/guestmount-cleanup.1.html
 
 guestmount.1 $(top_builddir)/html/guestmount.1.html: stamp-guestmount.pod
 
@@ -76,6 +111,16 @@ stamp-guestmount.pod: guestmount.pod
 	  $<
 	touch $@
 
+guestmount-cleanup.1 $(top_builddir)/html/guestmount-cleanup.1.html: stamp-guestmount-cleanup.pod
+
+stamp-guestmount-cleanup.pod: guestmount-cleanup.pod
+	$(PODWRAPPER) \
+	  --man guestmount-cleanup.1 \
+	  --html $(top_builddir)/html/guestmount-cleanup.1.html \
+	  --license GPLv2+ \
+	  $<
+	touch $@
+
 # Tests.
 
 if ENABLE_APPLIANCE
diff --git a/fuse/guestmount-cleanup.c b/fuse/guestmount-cleanup.c
new file mode 100644
index 0000000..06f38d0
--- /dev/null
+++ b/fuse/guestmount-cleanup.c
@@ -0,0 +1,297 @@
+/* guestmount-cleanup
+ * Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <locale.h>
+#include <libintl.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "guestfs.h"
+#include "guestfs-internal-frontend.h"
+
+#include "ignore-value.h"
+#include "progname.h"
+
+static int do_fusermount (const char *mountpoint, char **error_rtn);
+static void do_fuser (const char *mountpoint);
+
+static void __attribute__((noreturn))
+usage (int status)
+{
+  if (status != EXIT_SUCCESS)
+    fprintf (stderr, _("Try `%s --help' for more information.\n"),
+             program_name);
+  else {
+    fprintf (stdout,
+           _("%s: clean up a mounted filesystem\n"
+             "Copyright (C) 2013 Red Hat Inc.\n"
+             "Usage:\n"
+             "  %s [--fd=FD] mountpoint\n"
+             "Options:\n"
+             "  --fd=FD              Pipe file descriptor to monitor\n"
+             "  --help               Display help message and exit\n"
+             "  -v|--verbose         Verbose messages\n"
+             "  -V|--version         Display version and exit\n"
+             ),
+             program_name, program_name);
+  }
+  exit (status);
+}
+
+int
+main (int argc, char *argv[])
+{
+  enum { HELP_OPTION = CHAR_MAX + 1 };
+
+  static const char *options = "v?V";
+  static const struct option long_options[] = {
+    { "fd", 1, 0, 0 },
+    { "help", 0, 0, HELP_OPTION },
+    { "verbose", 0, 0, 'v' },
+    { "version", 0, 0, 'V' },
+    { 0, 0, 0, 0 }
+  };
+
+  int c, fd = -1;
+  int option_index;
+  const char *mountpoint;
+  struct sigaction sa;
+  struct pollfd pollfd;
+  char *error = NULL;
+  size_t i;
+
+  setlocale (LC_ALL, "");
+  bindtextdomain (PACKAGE, LOCALEBASEDIR);
+  textdomain (PACKAGE);
+
+  /* Set global program name that is not polluted with libtool artifacts.  */
+  set_program_name (argv[0]);
+
+  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 (STREQ (long_options[option_index].name, "fd")) {
+        if (sscanf (optarg, "%d", &fd) != 1 || fd < 0) {
+          fprintf (stderr, _("%s: cannot parse fd option '%s'\n"),
+                   program_name, optarg);
+          exit (EXIT_FAILURE);
+        }
+      } else {
+        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
+                 program_name, long_options[option_index].name, option_index);
+        exit (EXIT_FAILURE);
+      }
+      break;
+
+    case 'V':
+      printf ("guestmount-cleanup %s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+      exit (EXIT_SUCCESS);
+
+    case HELP_OPTION:
+      usage (EXIT_SUCCESS);
+
+    default:
+      usage (EXIT_FAILURE);
+    }
+  }
+
+  /* We'd better have a mountpoint. */
+  if (optind+1 != argc) {
+    fprintf (stderr,
+             _("%s: you must specify a mountpoint in the host filesystem\n"),
+             program_name);
+    exit (EXIT_FAILURE);
+  }
+
+  mountpoint = argv[optind];
+
+  /* Monitor the pipe until we get POLLHUP. */
+  if (fd >= 0) {
+    ignore_value (chdir ("/"));
+
+    /* Ignore keyboard signals. */
+    memset (&sa, 0, sizeof sa);
+    sa.sa_handler = SIG_IGN;
+    sa.sa_flags = SA_RESTART;
+    sigaction (SIGINT, &sa, NULL);
+    sigaction (SIGQUIT, &sa, NULL);
+
+    while (1) {
+      pollfd.fd = fd;
+      pollfd.events = POLLIN;
+      pollfd.revents = 0;
+      if (poll (&pollfd, 1, -1) == -1) {
+        if (errno != EAGAIN && errno != EINTR) {
+          perror ("poll");
+          exit (EXIT_FAILURE);
+        }
+      }
+      else {
+        if ((pollfd.revents & POLLHUP) != 0)
+          break;
+      }
+    }
+  }
+
+  /* Unmount the filesystem.  We may have to try a few times. */
+  for (i = 0; i <= 5; ++i) {
+    if (i > 0)
+      sleep (1 << (i-1));
+
+    free (error);
+    error = NULL;
+
+    if (do_fusermount (mountpoint, &error) == 0)
+      goto done;
+  }
+
+  fprintf (stderr, _("%s: failed to unmount %s: %s\n"),
+           program_name, mountpoint, error);
+  free (error);
+
+  do_fuser (mountpoint);
+
+  exit (EXIT_FAILURE);
+
+ done:
+  exit (EXIT_SUCCESS);
+}
+
+static int
+do_fusermount (const char *mountpoint, char **error_rtn)
+{
+  int fd[2];
+  pid_t pid;
+  int r;
+  char *buf = NULL;
+  size_t allocsize = 0, len = 0;
+
+  if (pipe (fd) == -1) {
+    perror ("pipe");
+    exit (EXIT_FAILURE);
+  }
+
+  pid = fork ();
+  if (pid == -1) {
+    perror ("fork");
+    exit (EXIT_FAILURE);
+  }
+
+  if (pid == 0) {               /* Child - run fusermount. */
+    close (fd[0]);
+    dup2 (fd[1], 1);
+    dup2 (fd[1], 2);
+    close (fd[1]);
+
+    execlp ("fusermount", "fusermount", "-u", mountpoint, NULL);
+    perror ("exec");
+    _exit (EXIT_FAILURE);
+  }
+
+  /* Parent - read from the pipe any errors etc. */
+  close (fd[1]);
+
+  while (1) {
+    if (len >= allocsize) {
+      allocsize += 256;
+      buf = realloc (buf, allocsize);
+      if (buf == NULL) {
+        perror ("realloc");
+        exit (EXIT_FAILURE);
+      }
+    }
+
+    /* Leave space in the buffer for a terminating \0 character. */
+    r = read (fd[0], &buf[len], allocsize - len - 1);
+    if (r == -1) {
+      perror ("read");
+      exit (EXIT_FAILURE);
+    }
+
+    if (r == 0)
+      break;
+
+    len += r;
+  }
+
+  if (close (fd[0]) == -1) {
+    perror ("close");
+    exit (EXIT_FAILURE);
+  }
+
+  if (buf) {
+    /* Remove any trailing \n from the error message. */
+    while (len > 0 && buf[len-1] == '\n') {
+      buf[len-1] = '\0';
+      len--;
+    }
+
+    /* Make sure the error message is \0 terminated. */
+    if (len < allocsize)
+      buf[len] = '\0';
+  }
+
+  if (waitpid (pid, &r, 0) == -1) {
+    perror ("waitpid");
+    exit (EXIT_FAILURE);
+  }
+
+  if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) {
+    *error_rtn = buf;
+    return 1;                   /* fusermount or exec failed */
+  }
+
+  free (buf);
+  return 0;                     /* fusermount successful */
+}
+
+/* Try running 'fuser' on the mountpoint.  This is for information
+ * only so don't fail if we can't run it.
+ */
+static void
+do_fuser (const char *mountpoint)
+{
+  pid_t pid;
+
+  pid = fork ();
+  if (pid == -1) {
+    perror ("fork");
+    exit (EXIT_FAILURE);
+  }
+
+  if (pid == 0) {               /* Child - run /sbin/fuser. */
+    execlp ("/sbin/fuser", "fuser", "-v", "-m", mountpoint, NULL);
+    _exit (EXIT_FAILURE);
+  }
+
+  waitpid (pid, NULL, 0);
+}
diff --git a/fuse/guestmount-cleanup.pod b/fuse/guestmount-cleanup.pod
new file mode 100644
index 0000000..988b5f3
--- /dev/null
+++ b/fuse/guestmount-cleanup.pod
@@ -0,0 +1,103 @@
+=encoding utf8
+
+=head1 NAME
+
+guestmount-cleanup - Clean up a mounted filesystem
+
+=head1 SYNOPSIS
+
+ guestmount-cleanup mountpoint
+
+ guestmount-cleanup --fd=<FD> mountpoint
+
+=head1 DESCRIPTION
+
+guestmount-cleanup is a utility to clean up mounted filesystems
+automatically.  This program is used alongside L<guestmount(1)> to
+unmount the filesystem when a program or script using that filesystem
+exits.
+
+There are two ways to use guestmount-cleanup.  When called as:
+
+ guestmount-cleanup mountpoint
+
+it unmounts C<mountpoint> immediately.
+
+When called as:
+
+ guestmount-cleanup --fd=FD mountpoint
+
+it waits until the pipe C<FD> is closed.  This can be used to monitor
+another process and clean up its mountpoint when that process exits,
+as described below.
+
+=head2 FROM PROGRAMS OR SCRIPTING LANGUAGES
+
+In the program, create a pipe (eg. by calling L<pipe(2)>).  Let C<FD>
+be the file descriptor number of the read side of the pipe
+(ie. C<pipefd[0]>).
+
+After mounting the filesystem with L<guestmount(1)> (on
+C<mountpoint>), fork and run guestmount-cleanup like this:
+
+ guestmount-cleanup --fd=FD mountpoint
+
+Close the read side of the pipe in the parent process.
+
+Now, when the write side of the pipe (ie. C<pipefd[1]>) is closed for
+any reason, either explicitly or because the parent process
+exits, guestmount-cleanup notices and unmounts the mountpoint
+(by calling L<fusermount(1)>).
+
+If your operating system supports it, you should set the C<FD_CLOEXEC>
+flag on the write side of the pipe.
+
+=head2 FROM SHELL SCRIPTS
+
+Since bash doesn't provide a way to create an unnamed pipe, use a
+regular trap to call guestmount-cleanup like this:
+
+ trap "guestmount-cleanup mountpoint" INT TERM QUIT EXIT
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--fd=FD>
+
+Specify the pipe file descriptor to monitor, and delay cleanup until
+that pipe is closed.
+
+=item B<--help>
+
+Display brief help and exit.
+
+=item B<-V>
+
+=item B<--version>
+
+Display the program version and exit.
+
+=back
+
+=head1 EXIT STATUS
+
+This program returns 0 if successful, or non-zero if there was an
+error.
+
+=head1 SEE ALSO
+
+L<guestmount(1)>,
+L<fusermount(1)>,
+L<pipe(2)>,
+L<guestfs(3)/MOUNT LOCAL>,
+L<http://libguestfs.org/>,
+L<http://fuse.sf.net/>.
+
+=head1 AUTHORS
+
+Richard W.M. Jones (C<rjones at redhat dot com>)
+
+=head1 COPYRIGHT
+
+Copyright (C) 2013 Red Hat Inc.
diff --git a/fuse/guestmount.pod b/fuse/guestmount.pod
index eb32684..77c97b4 100644
--- a/fuse/guestmount.pod
+++ b/fuse/guestmount.pod
@@ -397,6 +397,7 @@ error.
 
 =head1 SEE ALSO
 
+L<guestmount-cleanup(1)>,
 L<guestfish(1)>,
 L<virt-inspector(1)>,
 L<virt-cat(1)>,
diff --git a/fuse/test-fuse-umount-race.sh b/fuse/test-fuse-umount-race.sh
index 59186ab..8a7b1a4 100755
--- a/fuse/test-fuse-umount-race.sh
+++ b/fuse/test-fuse-umount-race.sh
@@ -48,15 +48,8 @@ pid="$(cat test.pid)"
 
 timeout=10
 
-count=$timeout
-while ! fusermount -u mp && [ $count -gt 0 ]; do
-    sleep 1
-    ((count--))
-done
-if [ $count -eq 0 ]; then
-    echo "$0: fusermount failed after $timeout seconds"
-    exit 1
-fi
+# Unmount the mountpoint.
+./guestmount-cleanup mp
 
 # Wait for guestmount to exit.
 count=$timeout
diff --git a/fuse/test-fuse.sh b/fuse/test-fuse.sh
index bd0c096..e2fe71a 100755
--- a/fuse/test-fuse.sh
+++ b/fuse/test-fuse.sh
@@ -49,18 +49,24 @@ top_builddir=$(cd "$top_builddir" > /dev/null; pwd)
 # Paths to the other programs and files.  NB: Must be absolute paths.
 guestfish="$top_builddir/fish/guestfish"
 guestmount="$top_builddir/fuse/guestmount"
+guestmount_cleanup="$top_builddir/fuse/guestmount-cleanup"
 image="$top_builddir/fuse/test.img"
 mp="$top_builddir/fuse/test-mp"
 
-if [ ! -x "$guestfish" -o ! -x "$guestmount" ]; then
-    echo "$0: error: guestfish or guestmount are not available"
+if [ ! -x "$guestfish" -o ! -x "$guestmount" -o ! -x "$guestmount_cleanup" ]
+then
+    echo "$0: error: guestfish, guestmount or guestmount-cleanup are not available"
     exit 1
 fi
 
-# Ensure everything is cleaned up on exit.
+# Ensure the mountpoint directory exists and is not being used.
 rm -f "$image"
 mkdir -p "$mp"
 fusermount -u "$mp" >/dev/null 2>&1 ||:
+
+# Ensure everything is cleaned up on exit.
+mounted=
+
 function cleanup ()
 {
     status=$?
@@ -75,15 +81,9 @@ function cleanup ()
     # Who's using this?  Should be no one, but see below.
     if [ -x /sbin/fuser ]; then /sbin/fuser "$mp"; fi
 
-    # If you run this and you have GNOME running at the same time,
-    # then randomly /usr/libexec/gvfs-gdu-volume-monitor will decide
-    # to do whatever it does in the mountpoint directory, preventing
-    # you from unmounting it!  Hence the need for this loop.
-    count=10
-    while ! fusermount -u "$mp" && [ $count -gt 0 ]; do
-        sleep 1
-        ((count--))
-    done
+    if [ -n "$mounted" ]; then
+        $guestmount_cleanup "$mp"
+    fi
 
     rm -f "$image"
     rm -rf "$mp"
@@ -121,6 +121,7 @@ $guestmount \
     -o uid="$(id -u)" -o gid="$(id -g)" "$mp"
 # To debug guestmount, add this to the end of the preceding command:
 # -v -x & sleep 60
+mounted=yes
 
 stage Changing into mounted directory
 cd "$mp"
diff --git a/ocaml/t/guestfs_500_mount_local.ml b/ocaml/t/guestfs_500_mount_local.ml
index 3047544..c1d7bdd 100644
--- a/ocaml/t/guestfs_500_mount_local.ml
+++ b/ocaml/t/guestfs_500_mount_local.ml
@@ -142,40 +142,9 @@ and test_mountpoint mp =
   done;
 
   if debug then eprintf "%s > unmounting filesystem\n%!" mp;
-
-  unmount mp
-
-(* We may need to retry this a few times because of processes which
- * run in the background jumping into mountpoints.  Only display
- * errors if it still fails after many retries.
- *)
-and unmount mp =
-  let logfile = sprintf "%s.fusermount.log" mp in
-  let unlink_logfile () =
-    try unlink logfile with Unix_error _ -> ()
-  in
-  unlink_logfile ();
-
-  let run_command () =
-    Sys.command (sprintf "fusermount -u %s >> %s 2>&1"
-                   (Filename.quote mp) (Filename.quote logfile)) = 0
-  in
-
-  let rec loop tries =
-    if tries <= 5 then (
-      if not (run_command ()) then (
-        sleep 1;
-        loop (tries+1)
-      )
-    ) else (
-      ignore (Sys.command (sprintf "cat %s" (Filename.quote logfile)));
-      eprintf "fusermount: %s: failed, see earlier error messages\n" mp;
-      exit 1
-    )
-  in
-  loop 0;
-
-  unlink_logfile ()
+  ignore (
+    Sys.command (sprintf "../fuse/guestmount-cleanup %s" (Filename.quote mp))
+  )
 
 let () =
   match Array.to_list Sys.argv with
diff --git a/po-docs/ja/Makefile.am b/po-docs/ja/Makefile.am
index d3413ec..b18189b 100644
--- a/po-docs/ja/Makefile.am
+++ b/po-docs/ja/Makefile.am
@@ -41,6 +41,7 @@ MANPAGES = \
 	guestfs-testing.1 \
 	guestfsd.8 \
 	guestmount.1 \
+	guestmount-cleanup.1 \
 	libguestfs-make-fixed-appliance.1 \
 	libguestfs-test-tool.1 \
 	virt-alignment-scan.1 \
diff --git a/po-docs/podfiles b/po-docs/podfiles
index 74f722d..47f5e78 100644
--- a/po-docs/podfiles
+++ b/po-docs/podfiles
@@ -20,6 +20,7 @@
 ../fish/virt-tar-in.pod
 ../fish/virt-tar-out.pod
 ../format/virt-format.pod
+../fuse/guestmount-cleanup.pod
 ../fuse/guestmount.pod
 ../guestfs-release-notes.pod
 ../inspector/virt-inspector.pod
diff --git a/po-docs/uk/Makefile.am b/po-docs/uk/Makefile.am
index d3413ec..b18189b 100644
--- a/po-docs/uk/Makefile.am
+++ b/po-docs/uk/Makefile.am
@@ -41,6 +41,7 @@ MANPAGES = \
 	guestfs-testing.1 \
 	guestfsd.8 \
 	guestmount.1 \
+	guestmount-cleanup.1 \
 	libguestfs-make-fixed-appliance.1 \
 	libguestfs-test-tool.1 \
 	virt-alignment-scan.1 \
diff --git a/po/POTFILES b/po/POTFILES
index d746354..0fde83d 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -143,6 +143,7 @@ fish/supported.c
 fish/tilde.c
 fish/time.c
 format/format.c
+fuse/guestmount-cleanup.c
 fuse/guestmount.c
 gobject/src/optargs-add_domain.c
 gobject/src/optargs-add_drive.c
diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am
index e16a19d..de49d86 100644
--- a/sysprep/Makefile.am
+++ b/sysprep/Makefile.am
@@ -155,6 +155,7 @@ sysprep-operations.pod: virt-sysprep
 TESTS_ENVIRONMENT = \
 	abs_builddir=$(abs_builddir) \
 	abs_srcdir=$(abs_srcdir) \
+	PATH=$(abs_top_builddir)/fuse:$(PATH) \
 	$(top_builddir)/run --test
 
 if ENABLE_APPLIANCE
diff --git a/sysprep/sysprep_operation_script.ml b/sysprep/sysprep_operation_script.ml
index a49bc3c..c11103d 100644
--- a/sysprep/sysprep_operation_script.ml
+++ b/sysprep/sysprep_operation_script.ml
@@ -77,7 +77,7 @@ let rec script_perform (g : Guestfs.guestfs) root =
   []
 
 (* Run the scripts in the background and make sure they call
- * fusermount afterwards.
+ * guestmount-cleanup afterwards.
  *)
 and run_scripts mp scripts =
   let sh = "/bin/bash" in
@@ -89,19 +89,11 @@ cleanup ()
 {
   status=$?
   cd /
-  count=10
-  while ! fusermount -u %s >/dev/null 2>&1 && [ $count -gt 0 ]; do
-    sleep 1
-    ((count--))
-  done
-  if [ $count -eq 0 ]; then
-    echo \"fusermount: failed to unmount directory\" %s >&2
-    exit 1
-  fi
+  guestmount-cleanup %s ||:
   exit $status
 }
 trap cleanup INT TERM QUIT EXIT ERR\n"
-      (Filename.quote mp) (Filename.quote mp) ^
+      (Filename.quote mp) ^
       String.concat "\n" scripts in
   let args = [| sh; "-c"; cmd |] in
 
diff --git a/tests/selinux/run-test.pl b/tests/selinux/run-test.pl
index 5258bb1..1cdeb05 100755
--- a/tests/selinux/run-test.pl
+++ b/tests/selinux/run-test.pl
@@ -175,28 +175,11 @@ sub run_fuse_tests
     }
 
     # Unmount the test directory.
-    unmount ($mpdir);
-
-    exit ($errors == 0 ? 0 : 1);
-}
-
-# Unmount the FUSE directory.  We may need to retry this a few times.
-sub unmount
-{
-    my $mpdir = shift;
-    my $retries = 5;
-
-    while ($retries > 0) {
-        if (system ("fusermount", "-u", $mpdir) == 0) {
-            last;
-        }
-        sleep 1;
-        $retries--;
-    }
-
-    if ($retries == 0) {
+    if (system ("../../fuse/guestmount-cleanup", $mpdir) != 0) {
         die "failed to unmount FUSE directory\n";
     }
+
+    exit ($errors == 0 ? 0 : 1);
 }
 
 # Test extended attributes, using the libguestfs API directly.
-- 
1.8.1.2




More information about the Libguestfs mailing list