diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2010-11-08 16:00:16 +0100 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2010-11-08 16:00:16 +0100 |
commit | eba226948b44d5a303a10908d440e808eaf0bae6 (patch) | |
tree | d4159cf06f50b52cd3bfdfc6e6ec58d4969523e2 /util | |
parent | 9b2ab7ebed39ab680e0d9a489e213cb8c4f49970 (diff) | |
download | android_external_fuse-eba226948b44d5a303a10908d440e808eaf0bae6.tar.gz android_external_fuse-eba226948b44d5a303a10908d440e808eaf0bae6.tar.bz2 android_external_fuse-eba226948b44d5a303a10908d440e808eaf0bae6.zip |
update umount procedure
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.
Diffstat (limited to 'util')
-rw-r--r-- | util/fusermount.c | 156 |
1 files changed, 147 insertions, 9 deletions
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", |