aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--configure.in7
-rw-r--r--lib/mount_util.c49
-rw-r--r--lib/mount_util.h1
-rw-r--r--util/fusermount.c156
5 files changed, 215 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index b6bcda3..5ce455c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,17 @@
* Open /dev/null for write instead of read for redirecting stdout
and stderr
+ * If umount(8) supports --fake and --no-canonicalize (util-linux-ng
+ version 2.18 or later), and umount(2) supports the
+ UMOUNT_NOFOLLOW flag (linux kernel version 2.6.35 or later) then,
+ "fusermount -u" will call the umount(2) system call and use
+ "umount --fake ..." to update /etc/mtab
+
+ * Added --disable-legacy-umount option to configure. This
+ disables the runtime checking of umount(8) version. When built
+ with this option then "fusermount -u" will fail if umount(8)
+ doesn't support the --fake and --no-canonicalize options.
+
2010-10-14 Miklos Szeredi <miklos@szeredi.hu>
* Use LTLIBICONV when linking libfuse. This fixes building against
diff --git a/configure.in b/configure.in
index 3b64511..846868a 100644
--- a/configure.in
+++ b/configure.in
@@ -33,6 +33,8 @@ AC_ARG_ENABLE(example,
[ --enable-example Compile with examples ])
AC_ARG_ENABLE(mtab,
[ --disable-mtab Disable and ignore usage of /etc/mtab ])
+AC_ARG_ENABLE(legacy-umount,
+ [ --disable-legacy-umount If umount(8) is util-linux-ng >= 2.18 ])
AC_ARG_WITH(pkgconfigdir,
[ --with-pkgconfigdir=DIR pkgconfig file in DIR @<:@LIBDIR/pkgconfig@:>@],
@@ -54,6 +56,11 @@ fi
if test "$enable_mtab" = "no"; then
AC_DEFINE(IGNORE_MTAB, 1, [Don't update /etc/mtab])
fi
+
+if test "$enable_legacy_umount" != "no"; then
+ AC_DEFINE(LEGACY_UMOUNT, 1, [Enable legacy umount support])
+fi
+
AC_CHECK_FUNCS([fork setxattr fdatasync])
AC_CHECK_MEMBERS([struct stat.st_atim])
AC_CHECK_MEMBERS([struct stat.st_atimespec])
diff --git a/lib/mount_util.c b/lib/mount_util.c
index 25b7e43..edbba12 100644
--- a/lib/mount_util.c
+++ b/lib/mount_util.c
@@ -262,6 +262,55 @@ int fuse_mnt_umount(const char *progname, const char *abs_mnt,
return exec_umount(progname, rel_mnt, lazy);
}
+static int remove_mount(const char *progname, const char *mnt)
+{
+ int res;
+ int status;
+ sigset_t blockmask;
+ sigset_t oldmask;
+
+ sigemptyset(&blockmask);
+ sigaddset(&blockmask, SIGCHLD);
+ res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
+ if (res == -1) {
+ fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
+ return -1;
+ }
+
+ res = fork();
+ if (res == -1) {
+ fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
+ goto out_restore;
+ }
+ if (res == 0) {
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ setuid(geteuid());
+ execl("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
+ "--fake", mnt, NULL);
+ fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
+ progname, strerror(errno));
+ exit(1);
+ }
+ res = waitpid(res, &status, 0);
+ if (res == -1)
+ fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
+
+ if (status != 0)
+ res = -1;
+
+ out_restore:
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ return res;
+}
+
+int fuse_mnt_remove_mount(const char *progname, const char *mnt)
+{
+ if (!mtab_needs_update(mnt))
+ return 0;
+
+ return remove_mount(progname, mnt);
+}
+
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
{
char buf[PATH_MAX];
diff --git a/lib/mount_util.h b/lib/mount_util.h
index f392f99..dc5c916 100644
--- a/lib/mount_util.h
+++ b/lib/mount_util.h
@@ -10,6 +10,7 @@
int fuse_mnt_add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts);
+int fuse_mnt_remove_mount(const char *progname, const char *mnt);
int fuse_mnt_umount(const char *progname, const char *abs_mnt,
const char *rel_mnt, int lazy);
char *fuse_mnt_resolve_path(const char *progname, const char *orig);
diff --git a/util/fusermount.c b/util/fusermount.c
index 39da9b6..3b4125e 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -45,6 +45,16 @@
#define MS_PRIVATE (1<<18)
#endif
+#ifndef UMOUNT_DETACH
+#define UMOUNT_DETACH 0x00000002 /* Just detach from the tree */
+#endif
+#ifndef UMOUNT_NOFOLLOW
+#define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
+#endif
+#ifndef UMOUNT_UNUSED
+#define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
+#endif
+
static const char *progname;
static int user_allow_other = 0;
@@ -380,19 +390,13 @@ static int chdir_to_parent(char *copy, const char **lastp, int *currdir_fd)
return 0;
}
-static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
+static int unmount_fuse_legacy(const char *mnt, int lazy)
{
int currdir_fd = -1;
char *copy;
const char *last;
int res;
- if (getuid() != 0) {
- res = may_unmount(mnt, quiet);
- if (res == -1)
- return -1;
- }
-
copy = strdup(mnt);
if (copy == NULL) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
@@ -419,6 +423,140 @@ out:
return res;
}
+static int unmount_fuse_nofollow(const char *mnt, int quiet, int lazy)
+{
+ int res;
+ int umount_flags = UMOUNT_NOFOLLOW;
+
+ if (lazy)
+ umount_flags |= UMOUNT_DETACH;
+
+ res = umount2(mnt, umount_flags);
+ if (res == -1) {
+ if (!quiet) {
+ fprintf(stderr, "%s: failed to unmount %s: %s\n",
+ progname, mnt, strerror(errno));
+ }
+ return -1;
+ }
+
+ return fuse_mnt_remove_mount(progname, mnt);
+}
+
+/* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
+static int umount_nofollow_support(void)
+{
+ int res = umount2("", UMOUNT_UNUSED);
+ if (res != -1 || errno != EINVAL)
+ return 0;
+
+ res = umount2("", UMOUNT_NOFOLLOW);
+ if (res != -1 || errno != ENOENT)
+ return 0;
+
+ return 1;
+}
+
+#ifdef LEGACY_UMOUNT
+/* Check if umount(8) supports "--fake" and "--no-canonicalize" options */
+static int umount_fake_support(void)
+{
+ int res;
+ int status;
+ sigset_t blockmask;
+ sigset_t oldmask;
+ int pip[2];
+ char buf[1024];
+ char *s;
+ unsigned majver;
+ unsigned minver;
+ int supported = 0;
+ int pid;
+
+ res = pipe(pip);
+ if (res == -1)
+ return 0;
+
+ sigemptyset(&blockmask);
+ sigaddset(&blockmask, SIGCHLD);
+ res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
+ if (res == -1)
+ goto out_close;
+
+ pid = fork();
+ if (pid == -1)
+ goto out_restore;
+
+ if (pid == 0) {
+ int nullfd;
+
+ close(pip[0]);
+ dup2(pip[1], 1);
+ if (pip[1] != 1)
+ close(pip[1]);
+ nullfd = open("/dev/null", O_WRONLY);
+ dup2(nullfd, 2);
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ setuid(getuid());
+ execl("/bin/umount", "/bin/umount", "--version", NULL);
+ exit(1);
+ }
+ res = read(pip[0], buf, sizeof(buf));
+ if (res == -1 || res == sizeof(buf))
+ buf[0] = '\0';
+ else
+ buf[res] = '\0';
+
+ res = waitpid(pid, &status, 0);
+ if (res == -1 || status != 0)
+ goto out_restore;
+
+ s = strstr(buf, "util-linux-ng ");
+ if (s == NULL)
+ goto out_restore;
+
+ s += 14;
+ if (sscanf(s, "%u.%u", &majver, &minver) < 2)
+ goto out_restore;
+
+ if (majver < 2 || (majver == 2 && minver < 18))
+ goto out_restore;
+
+ supported = 1;
+
+out_restore:
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+out_close:
+ close(pip[0]);
+ close(pip[1]);
+
+ return supported;
+}
+#else
+static int umount_fake_support(void)
+{
+ return 1;
+}
+#endif
+
+static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
+{
+ int res;
+
+ if (getuid() != 0) {
+ res = may_unmount(mnt, quiet);
+ if (res == -1)
+ return -1;
+ }
+
+ if (umount_nofollow_support() && umount_fake_support())
+ res = unmount_fuse_nofollow(mnt, quiet, lazy);
+ else
+ res = unmount_fuse_legacy(mnt, lazy);
+
+ return res;
+}
+
static int unmount_fuse(const char *mnt, int quiet, int lazy)
{
int res;
@@ -1073,7 +1211,7 @@ static int mount_fuse(const char *mnt, const char *opts)
if (geteuid() == 0) {
res = add_mount(source, mnt, type, mnt_opts);
if (res == -1) {
- umount2(mnt, 2); /* lazy umount */
+ umount2(mnt, UMOUNT_DETACH); /* lazy umount */
close(fd);
return -1;
}
@@ -1231,7 +1369,7 @@ int main(int argc, char *argv[])
if (geteuid() == 0)
res = unmount_fuse(mnt, quiet, lazy);
else {
- res = umount2(mnt, lazy ? 2 : 0);
+ res = umount2(mnt, lazy ? UMOUNT_DETACH : 0);
if (res == -1 && !quiet)
fprintf(stderr,
"%s: failed to unmount %s: %s\n",