diff options
| author | Csaba Henk <csaba@gluster.com> | 2010-02-20 18:53:38 +0000 | 
|---|---|---|
| committer | Anand V. Avati <avati@dev.gluster.com> | 2010-02-21 00:17:42 -0800 | 
| commit | 94d31fdaf967f0d224a2bfa7b275b0344e0f5700 (patch) | |
| tree | c1b5134d26aa145d36da5c1b732f3a10ea56422c /contrib/fuse-util | |
| parent | f9269f4776141ae78fb10d1bf5ae63da7595a369 (diff) | |
fuse: bring over recent mounting code changes from libfuse upstream
Following commits were ported (commit ids as of
http://git.gluster.com/?p=users/csaba/fuse.git
repo):
commit 06fe3eb9c864b69bea98600c0a7eab7b63834735
Author: mszeredi <mszeredi>
Date:   Thu Feb 18 11:05:12 2010 +0000
    * Fix stack alignment for clone()
 ChangeLog               |    4 ++++
 include/fuse_lowlevel.h |    1 +
 util/fusermount.c       |    9 ++++-----
 3 files changed, 9 insertions(+), 5 deletions(-)
commit dfe1aab6520d70d72d36edf0508fef9a865daa5f
Author: mszeredi <mszeredi>
Date:   Tue Jan 26 18:20:12 2010 +0000
    * Fix race if two "fusermount -u" instances are run in parallel.
    Reported by Dan Rosenberg
    * Make sure that the path to be unmounted doesn't refer to a
    symlink
 ChangeLog         |    8 +
 lib/mount.c       |    2 +-
 lib/mount_util.c  |   31 +++--
 lib/mount_util.h  |    3 +-
 util/fusermount.c |  380 +++++++++++++++++++++++++++++++++++++++++++++--------
 5 files changed, 351 insertions(+), 73 deletions(-)
Signed-off-by: Csaba Henk <csaba@gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 657 (Metabug for tracking fuse upstream)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=657
Diffstat (limited to 'contrib/fuse-util')
| -rw-r--r-- | contrib/fuse-util/fusermount.c | 379 | ||||
| -rw-r--r-- | contrib/fuse-util/mount_util.h | 3 | 
2 files changed, 324 insertions, 58 deletions
diff --git a/contrib/fuse-util/fusermount.c b/contrib/fuse-util/fusermount.c index c3ecc86cc..6123c66e3 100644 --- a/contrib/fuse-util/fusermount.c +++ b/contrib/fuse-util/fusermount.c @@ -26,6 +26,7 @@  #include <sys/fsuid.h>  #include <sys/socket.h>  #include <sys/utsname.h> +#include <sched.h>  #define FUSE_COMMFD_ENV		"_FUSE_COMMFD" @@ -37,6 +38,12 @@  #ifndef MS_DIRSYNC  #define MS_DIRSYNC 128  #endif +#ifndef MS_REC +#define MS_REC 16384 +#endif +#ifndef MS_SLAVE +#define MS_SLAVE (1<<19) +#endif  static const char *progname; @@ -74,77 +81,335 @@ static void restore_privs(void)  }  #ifndef IGNORE_MTAB +/* + * Make sure that /etc/mtab is checked and updated atomically + */ +static int lock_umount(void) +{ +	const char *mtab_lock = _PATH_MOUNTED ".fuselock"; +	int mtablock; +	int res; +	struct stat mtab_stat; + +	/* /etc/mtab could be a symlink to /proc/mounts */ +	if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode)) +		return -1; + +	mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600); +	if (mtablock == -1) { +		fprintf(stderr, "%s: unable to open fuse lock file: %s\n", +			progname, strerror(errno)); +		return -1; +	} +	res = lockf(mtablock, F_LOCK, 0); +	if (res < 0) { +		fprintf(stderr, "%s: error getting lock: %s\n", progname, +			strerror(errno)); +		close(mtablock); +		return -1; +	} + +	return mtablock; +} + +static void unlock_umount(int mtablock) +{ +	lockf(mtablock, F_ULOCK, 0); +	close(mtablock); +} +  static int add_mount(const char *source, const char *mnt, const char *type,  		     const char *opts)  {  	return fuse_mnt_add_mount(progname, source, mnt, type, opts);  } -static int unmount_fuse(const char *mnt, int quiet, int lazy) +static int may_unmount(const char *mnt, int quiet)  { -	if (getuid() != 0) { -		struct mntent *entp; -		FILE *fp; -		const char *user = NULL; -		char uidstr[32]; -		unsigned uidlen = 0; -		int found; -		const char *mtab = _PATH_MOUNTED; - -		user = get_user_name(); -		if (user == NULL) -			return -1; +	struct mntent *entp; +	FILE *fp; +	const char *user = NULL; +	char uidstr[32]; +	unsigned uidlen = 0; +	int found; +	const char *mtab = _PATH_MOUNTED; -		fp = setmntent(mtab, "r"); -		if (fp == NULL) { -			fprintf(stderr, -				"%s: failed to open %s: %s\n", progname, mtab, -				strerror(errno)); -			return -1; -		} +	user = get_user_name(); +	if (user == NULL) +		return -1; -		uidlen = sprintf(uidstr, "%u", getuid()); - -		found = 0; -		while ((entp = getmntent(fp)) != NULL) { -			if (!found && strcmp(entp->mnt_dir, mnt) == 0 && -			    (strcmp(entp->mnt_type, "fuse") == 0 || -			     strcmp(entp->mnt_type, "fuseblk") == 0 || -			     strncmp(entp->mnt_type, "fuse.", 5) == 0 || -			     strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) { -				char *p = strstr(entp->mnt_opts, "user="); -				if (p && -				    (p == entp->mnt_opts || *(p-1) == ',') && -				    strcmp(p + 5, user) == 0) { -					found = 1; -					break; -				} -				/* /etc/mtab is a link pointing to -				   /proc/mounts: */ -				else if ((p = -					  strstr(entp->mnt_opts, "user_id=")) && -					 (p == entp->mnt_opts || -					  *(p-1) == ',') && -					 strncmp(p + 8, uidstr, uidlen) == 0 && -					 (*(p+8+uidlen) == ',' || -					  *(p+8+uidlen) == '\0')) { -					found = 1; -					break; -				} +	fp = setmntent(mtab, "r"); +	if (fp == NULL) { +		fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, +			strerror(errno)); +		return -1; +	} + +	uidlen = sprintf(uidstr, "%u", getuid()); + +	found = 0; +	while ((entp = getmntent(fp)) != NULL) { +		if (!found && strcmp(entp->mnt_dir, mnt) == 0 && +		    (strcmp(entp->mnt_type, "fuse") == 0 || +		     strcmp(entp->mnt_type, "fuseblk") == 0 || +		     strncmp(entp->mnt_type, "fuse.", 5) == 0 || +		     strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) { +			char *p = strstr(entp->mnt_opts, "user="); +			if (p && +			    (p == entp->mnt_opts || *(p-1) == ',') && +			    strcmp(p + 5, user) == 0) { +				found = 1; +				break; +			} +			/* /etc/mtab is a link pointing to +			   /proc/mounts: */ +			else if ((p = +				  strstr(entp->mnt_opts, "user_id=")) && +				 (p == entp->mnt_opts || +				  *(p-1) == ',') && +				 strncmp(p + 8, uidstr, uidlen) == 0 && +				 (*(p+8+uidlen) == ',' || +				  *(p+8+uidlen) == '\0')) { +				found = 1; +				break;  			}  		} -		endmntent(fp); +	} +	endmntent(fp); -		if (!found) { -			if (!quiet) -				fprintf(stderr, -					"%s: entry for %s not found in %s\n", -					progname, mnt, mtab); -			return -1; +	if (!found) { +		if (!quiet) +			fprintf(stderr, +				"%s: entry for %s not found in %s\n", +				progname, mnt, mtab); +		return -1; +	} + +	return 0; +} + +/* + * Check whether the file specified in "fusermount -u" is really a + * mountpoint and not a symlink.  This is necessary otherwise the user + * could move the mountpoint away and replace it with a symlink + * pointing to an arbitrary mount, thereby tricking fusermount into + * unmounting that (umount(2) will follow symlinks). + * + * This is the child process running in a separate mount namespace, so + * we don't mess with the global namespace and if the process is + * killed for any reason, mounts are automatically cleaned up. + * + * First make sure nothing is propagated back into the parent + * namespace by marking all mounts "slave". + * + * Then bind mount parent onto a stable base where the user can't move + * it around.  Use "/tmp", since it will almost certainly exist, but + * anything similar would do as well. + * + * Finally check /proc/mounts for an entry matching the requested + * mountpoint.  If it's found then we are OK, and the user can't move + * it around within the parent directory as rename() will return EBUSY. + */ +static int check_is_mount_child(void *p) +{ +	const char **a = p; +	const char *last = a[0]; +	const char *mnt = a[1]; +	int res; +	const char *procmounts = "/proc/mounts"; +	int found; +	FILE *fp; +	struct mntent *entp; + +	res = mount("", "/", "", MS_SLAVE | MS_REC, NULL); +	if (res == -1) { +		fprintf(stderr, "%s: failed to mark mounts slave: %s\n", +			progname, strerror(errno)); +		return 1; +	} + +	res = mount(".", "/tmp", "", MS_BIND | MS_REC, NULL); +	if (res == -1) { +		fprintf(stderr, "%s: failed to bind parent to /tmp: %s\n", +			progname, strerror(errno)); +		return 1; +	} + +	fp = setmntent(procmounts, "r"); +	if (fp == NULL) { +		fprintf(stderr, "%s: failed to open %s: %s\n", progname, +			procmounts, strerror(errno)); +		return 1; +	} + +	found = 0; +	while ((entp = getmntent(fp)) != NULL) { +		if (strncmp(entp->mnt_dir, "/tmp/", 5) == 0 && +		    strcmp(entp->mnt_dir + 5, last) == 0) { +			found = 1; +			break;  		}  	} +	endmntent(fp); + +	if (!found) { +		fprintf(stderr, "%s: %s not mounted\n", progname, mnt); +		return 1; +	} + +	return 0; +} + +static pid_t clone_newns(void *a) +{ +	char buf[131072]; +	char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15)); + +#ifdef __ia64__ +	extern int __clone2(int (*fn)(void *), +			    void *child_stack_base, size_t stack_size, +			    int flags, void *arg, pid_t *ptid, +			    void *tls, pid_t *ctid); + +	return __clone2(check_is_mount_child, stack, sizeof(buf) / 2, +			CLONE_NEWNS, a, NULL, NULL, NULL); +#else +	return clone(check_is_mount_child, stack, CLONE_NEWNS, a); +#endif +} + +static int check_is_mount(const char *last, const char *mnt) +{ +	pid_t pid, p; +	int status; +	const char *a[2] = { last, mnt }; + +	pid = clone_newns((void *) a); +	if (pid == (pid_t) -1) { +		fprintf(stderr, "%s: failed to clone namespace: %s\n", +			progname, strerror(errno)); +		return -1; +	} +	p = waitpid(pid, &status, __WCLONE); +	if (p == (pid_t) -1) { +		fprintf(stderr, "%s: waitpid failed: %s\n", +			progname, strerror(errno)); +		return -1; +	} +	if (!WIFEXITED(status)) { +		fprintf(stderr, "%s: child terminated abnormally (status %i)\n", +			progname, status); +		return -1; +	} +	if (WEXITSTATUS(status) != 0) +		return -1; + +	return 0; +} + +static int chdir_to_parent(char *copy, const char **lastp, int *currdir_fd) +{ +	char *tmp; +	const char *parent; +	char buf[65536]; +	int res; + +	tmp = strrchr(copy, '/'); +	if (tmp == NULL || tmp[1] == '\0') { +		fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n", +			progname, copy); +		return -1; +	} +	if (tmp != copy) { +		*tmp = '\0'; +		parent = copy; +		*lastp = tmp + 1; +	} else if (tmp[1] != '\0') { +		*lastp = tmp + 1; +		parent = "/"; +	} else { +		*lastp = "."; +		parent = "/"; +	} + +	*currdir_fd = open(".", O_RDONLY); +	if (*currdir_fd == -1) { +		fprintf(stderr, +			"%s: failed to open current directory: %s\n", +			progname, strerror(errno)); +		return -1; +	} + +	res = chdir(parent); +	if (res == -1) { +		fprintf(stderr, "%s: failed to chdir to %s: %s\n", +			progname, parent, strerror(errno)); +		return -1; +	} + +	if (getcwd(buf, sizeof(buf)) == NULL) { +		fprintf(stderr, "%s: failed to obtain current directory: %s\n", +			progname, strerror(errno)); +		return -1; +	} +	if (strcmp(buf, parent) != 0) { +		fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname, +			parent, buf); +		return -1; -	return fuse_mnt_umount(progname, mnt, lazy); +	} + +	return 0; +} + +static int unmount_fuse_locked(const char *mnt, int quiet, 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); +		return -1; +	} + +	res = chdir_to_parent(copy, &last, &currdir_fd); +	if (res == -1) +		goto out; + +	res = check_is_mount(last, mnt); +	if (res == -1) +		goto out; + +	res = fuse_mnt_umount(progname, mnt, last, lazy); + +out: +	free(copy); +	if (currdir_fd != -1) { +		fchdir(currdir_fd); +		close(currdir_fd); +	} + +	return res; +} + +static int unmount_fuse(const char *mnt, int quiet, int lazy) +{ +	int res; +	int mtablock = lock_umount(); + +	res = unmount_fuse_locked(mnt, quiet, lazy); +	unlock_umount(mtablock); + +	return res;  }  static int count_fuse_fs(void) @@ -186,7 +451,7 @@ static int add_mount(const char *source, const char *mnt, const char *type,  static int unmount_fuse(const char *mnt, int quiet, int lazy)  { -	return fuse_mnt_umount(progname, mnt, lazy); +	return fuse_mnt_umount(progname, mnt, mnt, lazy);  }  #endif /* IGNORE_MTAB */ diff --git a/contrib/fuse-util/mount_util.h b/contrib/fuse-util/mount_util.h index cf54d9d0d..f392f99f1 100644 --- a/contrib/fuse-util/mount_util.h +++ b/contrib/fuse-util/mount_util.h @@ -10,7 +10,8 @@  int fuse_mnt_add_mount(const char *progname, const char *fsname,  		       const char *mnt, const char *type, const char *opts); -int fuse_mnt_umount(const char *progname, const char *mnt, int lazy); +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);  int fuse_mnt_check_empty(const char *progname, const char *mnt,  			 mode_t rootmode, off_t rootsize);  | 
