Richard W.M. Jones
2013-Mar-04 21:30 UTC
[Libguestfs] [PATCH] fuse: Add guestmount-cleanup program to handle unmounting (RHBZ#916780).
* PATCH FOR DISCUSSION ONLY - NOT TO BE APPLIED * Colin suggested something which seems eminently sensible: https://bugzilla.redhat.com/show_bug.cgi?id=916780 I've been through a couple of rounds of trying to implement this. I started with adding the option as suggested to the guestmount program, but it tended to make the guestmount program more complex. More importantly, adding the option only to guestmount means that it cannot be used outside guestmount, specifically by programs that use the mount-local API[1] directly. (For various reasons 'guestfs_umount_local' isn't a usable API in most situations). My second implementation is the patch attached. It adds a new program called guestmount-cleanup which can be used two ways: guestmount-cleanup --fd=<FD> mountpoint where it will monitor the pipe file descriptor <FD>. (I should note that I've never actually tested this code path). Or: guestmount-cleanup mountpoint where it immediately unmounts the mountpoint. In both cases it deals with fusermount retries. The patch is still large and clunky and it doesn't make FUSE that much easier to cope with. I suspect the way to go from here is to reimplement fusermount itself. It would, for example, be much better if we could get some information from fusermount about why it failed. That seems like a good idea until I tell you that fusermount is a setuid program and needs those privs even when dealing with a regular non-root FUSE mount. So we pretty much have to use it, so I'll have to send patches for it. It may also be that we're going about this all wrong and we should use CLONE_NS (which also requires root -- currently) to stop these systemwide daemons from interfering. Rich. [1] http://libguestfs.org/guestfs.3.html#mount-local
Richard W.M. Jones
2013-Mar-04 21:30 UTC
[Libguestfs] [PATCH] fuse: Add guestmount-cleanup program to handle unmounting (RHBZ#916780).
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
Reasonably Related Threads
- [PATCH v2] fuse: Add guestunmount program to handle unmounting (RHBZ#916780)
- [PATCH 0/4] Provide guestmount --pid-file and document possible race when unmounting FUSE filesystems.
- [PATCH v2] New APIs: mount-local and umount-local using FUSE
- [PATCH v3] New APIs: mount-local, mount-local-run and umount-local using FUSE
- [PATCH 0/3] Enable FUSE support in the API via 'mount-local' call.