diff options
Diffstat (limited to 'contrib/fuse-lib/mount.c')
| -rw-r--r-- | contrib/fuse-lib/mount.c | 829 |
1 files changed, 362 insertions, 467 deletions
diff --git a/contrib/fuse-lib/mount.c b/contrib/fuse-lib/mount.c index cf8dc5b4afb..06ff191f542 100644 --- a/contrib/fuse-lib/mount.c +++ b/contrib/fuse-lib/mount.c @@ -1,317 +1,203 @@ /* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB. */ -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <stddef.h> -#include <limits.h> -#include <fcntl.h> -#include <errno.h> -#include <dirent.h> -#include <mntent.h> -#include <sys/stat.h> -#include <sys/poll.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/wait.h> -#include <sys/mount.h> - -#ifdef FUSE_UTIL -#define MALLOC(size) malloc (size) -#define FREE(ptr) free (ptr) -#define GFFUSE_LOGERR(...) fprintf (stderr, ## __VA_ARGS__) -#else /* FUSE_UTIL */ -#include "glusterfs.h" -#include "logging.h" -#include "common-utils.h" +#include "mount_util.h" +#include "mount-gluster-compat.h" #ifdef GF_FUSERMOUNT #define FUSERMOUNT_PROG FUSERMOUNT_DIR "/fusermount-glusterfs" #else #define FUSERMOUNT_PROG "fusermount" #endif -#define FUSE_COMMFD_ENV "_FUSE_COMMFD" - -#define GFFUSE_LOGERR(...) \ - gf_log ("glusterfs-fuse", GF_LOG_ERROR, ## __VA_ARGS__) -#endif /* !FUSE_UTIL */ +#define FUSE_DEVFD_ENV "_FUSE_DEVFD" -/* - * Functions below, until following note, were taken from libfuse - * (http://git.gluster.com/?p=users/csaba/fuse.git;a=commit;h=b988bbf9) - * almost verbatim. What has been changed: - * - style adopted to that of glusterfs - * - s/fprintf/gf_log/ - * - s/free/FREE/, s/malloc/MALLOC/ - * - there are some other minor things - */ +#ifdef __FreeBSD__ +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> +#endif /* __FreeBSD__ */ -static int -mtab_needs_update (const char *mnt) +/* FUSE: function is called fuse_kern_unmount() */ +void +gf_fuse_unmount (const char *mountpoint, int fd) { int res; - struct stat stbuf; - - /* If mtab is within new mount, don't touch it */ - if (strncmp (mnt, _PATH_MOUNTED, strlen (mnt)) == 0 && - _PATH_MOUNTED[strlen (mnt)] == '/') - return 0; - - /* - * Skip mtab update if /etc/mtab: - * - * - doesn't exist, - * - is a symlink, - * - is on a read-only filesystem. - */ - res = lstat (_PATH_MOUNTED, &stbuf); - if (res == -1) { - if (errno == ENOENT) - return 0; - } else { - if (S_ISLNK (stbuf.st_mode)) - return 0; + int pid; + + if (!mountpoint) + return; + + if (fd != -1) { + struct pollfd pfd; + + pfd.fd = fd; + pfd.events = 0; + res = poll (&pfd, 1, 0); + /* If file poll returns POLLERR on the device file descriptor, + then the filesystem is already unmounted */ + if (res == 1 && (pfd.revents & POLLERR)) + return; - res = access (_PATH_MOUNTED, W_OK); - if (res == -1 && errno == EROFS) - return 0; + /* Need to close file descriptor, otherwise synchronous umount + would recurse into filesystem, and deadlock */ + close (fd); + } + + if (geteuid () == 0) { + fuse_mnt_umount ("fuse", mountpoint, mountpoint, 1); + return; + } else { + GFFUSE_LOGERR ("fuse: Effective-uid: %d", geteuid()); } - return 1; + res = umount2 (mountpoint, 2); + if (res == 0) + return; + + GFFUSE_LOGERR ("fuse: failed to unmount %s: %s", + mountpoint, strerror (errno)); + pid = fork (); + if (pid == -1) + return; + + if (pid == 0) { + const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z", + "--", mountpoint, NULL }; + + execvp (FUSERMOUNT_PROG, (char **)argv); + GFFUSE_LOGERR ("fuse: failed to execute fuserumount: %s", + strerror (errno)); + _exit (1); + } + waitpid (pid, NULL, 0); } -#ifndef FUSE_UTIL -static -#endif + +/* gluster-specific routines */ + +/* Unmounting in a daemon that lurks 'till main process exits */ int -fuse_mnt_add_mount (const char *progname, const char *fsname, - const char *mnt, const char *type, const char *opts) +gf_fuse_unmount_daemon (const char *mountpoint, int fd) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - if (!mtab_needs_update (mnt)) - return 0; - - sigemptyset (&blockmask); - sigaddset (&blockmask, SIGCHLD); - res = sigprocmask (SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - GFFUSE_LOGERR ("%s: sigprocmask: %s", - progname, strerror (errno)); + int ret = -1; + pid_t pid = -1; + + if (fd == -1) return -1; - } - res = fork (); - if (res == -1) { - GFFUSE_LOGERR ("%s: fork: %s", progname, strerror (errno)); - goto out_restore; - } - if (res == 0) { - char templ[] = "/tmp/fusermountXXXXXX"; - char *tmp; - - /* mtab update done async, just log if fails */ - res = fork (); - if (res) - exit (res == -1 ? 1 : 0); - res = fork (); - if (res) { - if (res != -1) - res = waitpid (res, &status, 0); - if (res == -1) - GFFUSE_LOGERR ("%s: /etc/mtab update failed", - progname); - - exit (0); - } + int ump[2] = {0,}; - sigprocmask (SIG_SETMASK, &oldmask, NULL); - setuid (geteuid ()); - - /* - * hide in a directory, where mount isn't able to resolve - * fsname as a valid path - */ - tmp = mkdtemp (templ); - if (!tmp) { - GFFUSE_LOGERR ("%s: failed to create temporary directory", - progname); - exit (1); - } - if (chdir (tmp)) { - GFFUSE_LOGERR ("%s: failed to chdir to %s: %s", - progname, tmp, strerror (errno)); - exit (1); - } - rmdir (tmp); - execl ("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, - "-o", opts, fsname, mnt, NULL); - GFFUSE_LOGERR ("%s: failed to execute /bin/mount: %s", - progname, strerror (errno)); - exit (1); + ret = pipe(ump); + if (ret == -1) { + close (fd); + return -1; } - res = waitpid (res, &status, 0); - if (res == -1) - GFFUSE_LOGERR ("%s: waitpid: %s", progname, strerror (errno)); - if (status != 0) - res = -1; + pid = fork (); + switch (pid) { + case 0: + { + char c = 0; + sigset_t sigset; - out_restore: - sigprocmask (SIG_SETMASK, &oldmask, NULL); - return res; -} + close_fds_except (ump, 1); -#ifndef FUSE_UTIL -static -#endif -char -*fuse_mnt_resolve_path (const char *progname, const char *orig) -{ - char buf[PATH_MAX]; - char *copy; - char *dst; - char *end; - char *lastcomp; - const char *toresolv; - - if (!orig[0]) { - GFFUSE_LOGERR ("%s: invalid mountpoint '%s'", progname, orig); - return NULL; - } + setsid(); + (void)chdir("/"); + sigfillset(&sigset); + sigprocmask(SIG_BLOCK, &sigset, NULL); - copy = strdup (orig); - if (copy == NULL) { - GFFUSE_LOGERR ("%s: failed to allocate memory", progname); - return NULL; - } + read (ump[0], &c, 1); - toresolv = copy; - lastcomp = NULL; - for (end = copy + strlen (copy) - 1; end > copy && *end == '/'; end --); - if (end[0] != '/') { - char *tmp; - end[1] = '\0'; - tmp = strrchr (copy, '/'); - if (tmp == NULL) { - lastcomp = copy; - toresolv = "."; - } else { - lastcomp = tmp + 1; - if (tmp == copy) - toresolv = "/"; - } - if (strcmp (lastcomp, ".") == 0 || strcmp (lastcomp, "..") == 0) { - lastcomp = NULL; - toresolv = copy; - } - else if (tmp) - tmp[0] = '\0'; + gf_fuse_unmount (mountpoint, fd); + exit (0); } - if (realpath (toresolv, buf) == NULL) { - GFFUSE_LOGERR ("%s: bad mount point %s: %s", progname, orig, - strerror (errno)); - FREE (copy); - return NULL; - } - if (lastcomp == NULL) - dst = strdup (buf); - else { - dst = (char *) MALLOC (strlen (buf) + 1 + strlen (lastcomp) + 1); - if (dst) { - unsigned buflen = strlen (buf); - if (buflen && buf[buflen-1] == '/') - sprintf (dst, "%s%s", buf, lastcomp); - else - sprintf (dst, "%s/%s", buf, lastcomp); - } + case -1: + close (fd); + fd = -1; + ret = -1; + close (ump[1]); } - FREE (copy); - if (dst == NULL) - GFFUSE_LOGERR ("%s: failed to allocate memory", progname); - return dst; + close (ump[0]); + + return ret; } -#ifndef FUSE_UTIL -/* return value: - * >= 0 => fd - * -1 => error - */ -static int -receive_fd (int fd) +static char * +escape (char *s) { - struct msghdr msg; - struct iovec iov; - char buf[1]; - int rv; - size_t ccmsg[CMSG_SPACE (sizeof (int)) / sizeof (size_t)]; - struct cmsghdr *cmsg; - - iov.iov_base = buf; - iov.iov_len = 1; - - msg.msg_name = 0; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - /* old BSD implementations should use msg_accrights instead of - * msg_control; the interface is different. */ - msg.msg_control = ccmsg; - msg.msg_controllen = sizeof (ccmsg); - - while (((rv = recvmsg (fd, &msg, 0)) == -1) && errno == EINTR); - if (rv == -1) { - GFFUSE_LOGERR ("recvmsg failed: %s", strerror (errno)); - return -1; - } - if (!rv) { - /* EOF */ - return -1; + size_t len = 0; + char *p = NULL; + char *q = NULL; + char *e = NULL; + + for (p = s; *p; p++) { + if (*p == ',') + len++; + len++; } - cmsg = CMSG_FIRSTHDR (&msg); - if (!cmsg->cmsg_type == SCM_RIGHTS) { - GFFUSE_LOGERR ("got control message of unknown type %d", - cmsg->cmsg_type); - return -1; + e = CALLOC (1, len + 1); + if (!e) + return NULL; + + for (p = s, q = e; *p; p++, q++) { + if (*p == ',') { + *q = '\\'; + q++; + } + *q = *p; } - return *(int*)CMSG_DATA (cmsg); + + return e; } static int -fuse_mount_fusermount (const char *mountpoint, const char *opts) +fuse_mount_fusermount (const char *mountpoint, char *fsname, + char *mnt_param, int fd) { - int fds[2], pid; - int res; - int rv; + int pid = -1; + int res = 0; + int ret = -1; + char *fm_mnt_params = NULL; + char *efsname = NULL; + +#ifndef GF_FUSERMOUNT + GFFUSE_LOGERR ("Mounting via helper utility " + "(unprivileged mounting) is supported " + "only if glusterfs is compiled with " + "--enable-fusermount"); + return -1; +#endif + + efsname = escape (fsname); + if (!efsname) { + GFFUSE_LOGERR ("Out of memory"); - res = socketpair (PF_UNIX, SOCK_STREAM, 0, fds); - if (res == -1) { - GFFUSE_LOGERR ("socketpair() failed: %s", strerror (errno)); return -1; } + ret = asprintf (&fm_mnt_params, + "%s,fsname=%s,nonempty,subtype=glusterfs", + mnt_param, efsname); + FREE (efsname); + if (ret == -1) { + GFFUSE_LOGERR ("Out of memory"); + goto out; + } + + /* fork to exec fusermount */ pid = fork (); if (pid == -1) { GFFUSE_LOGERR ("fork() failed: %s", strerror (errno)); - close (fds[0]); - close (fds[1]); - return -1; + ret = -1; + goto out; } if (pid == 0) { @@ -320,223 +206,197 @@ fuse_mount_fusermount (const char *mountpoint, const char *opts) int a = 0; argv[a++] = FUSERMOUNT_PROG; - if (opts) { - argv[a++] = "-o"; - argv[a++] = opts; - } + argv[a++] = "-o"; + argv[a++] = fm_mnt_params; argv[a++] = "--"; argv[a++] = mountpoint; argv[a++] = NULL; - close (fds[1]); - fcntl (fds[0], F_SETFD, 0); - snprintf (env, sizeof (env), "%i", fds[0]); - setenv (FUSE_COMMFD_ENV, env, 1); + snprintf (env, sizeof (env), "%i", fd); + setenv (FUSE_DEVFD_ENV, env, 1); execvp (FUSERMOUNT_PROG, (char **)argv); GFFUSE_LOGERR ("failed to exec fusermount: %s", strerror (errno)); _exit (1); } - close (fds[0]); - rv = receive_fd (fds[1]); - close (fds[1]); - waitpid (pid, NULL, 0); /* bury zombie */ - - return rv; + ret = waitpid (pid, &res, 0); + ret = (ret == pid && res == 0) ? 0 : -1; + out: + FREE (fm_mnt_params); + return ret; } -#endif -#ifndef FUSE_UTIL -static -#endif -int -fuse_mnt_umount (const char *progname, const char *mnt, int lazy) +#if defined(__FreeBSD__) +void +build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val, + size_t len) { - int res; - int status; - sigset_t blockmask; - sigset_t oldmask; - - if (!mtab_needs_update (mnt)) { - res = umount2 (mnt, lazy ? 2 : 0); - if (res == -1) - GFFUSE_LOGERR ("%s: failed to unmount %s: %s", - progname, mnt, strerror (errno)); - return res; - } - - sigemptyset (&blockmask); - sigaddset (&blockmask, SIGCHLD); - res = sigprocmask (SIG_BLOCK, &blockmask, &oldmask); - if (res == -1) { - GFFUSE_LOGERR ("%s: sigprocmask: %s", progname, - strerror (errno)); - return -1; - } + int i; + if (*iovlen < 0) + return; + i = *iovlen; - res = fork (); - if (res == -1) { - GFFUSE_LOGERR ("%s: fork: %s", progname, strerror (errno)); - goto out_restore; - } - if (res == 0) { - sigprocmask (SIG_SETMASK, &oldmask, NULL); - setuid (geteuid ()); - execl ("/bin/umount", "/bin/umount", "-i", mnt, - lazy ? "-l" : NULL, NULL); - GFFUSE_LOGERR ("%s: failed to execute /bin/umount: %s", - progname, strerror (errno)); - exit (1); + *iov = realloc(*iov, sizeof **iov * (i + 2)); + if (*iov == NULL) { + *iovlen = -1; + return; } - res = waitpid (res, &status, 0); - if (res == -1) - GFFUSE_LOGERR ("%s: waitpid: %s", progname, strerror (errno)); - if (status != 0) - res = -1; + (*iov)[i].iov_base = strdup(name); + (*iov)[i].iov_len = strlen(name) + 1; - out_restore: - sigprocmask (SIG_SETMASK, &oldmask, NULL); - return res; -} - -#ifdef FUSE_UTIL -int -fuse_mnt_check_empty (const char *progname, const char *mnt, - mode_t rootmode, off_t rootsize) -{ - int isempty = 1; - - if (S_ISDIR (rootmode)) { - struct dirent *ent; - DIR *dp = opendir (mnt); - if (dp == NULL) { - fprintf (stderr, - "%s: failed to open mountpoint for reading: %s\n", - progname, strerror (errno)); - return -1; - } - while ((ent = readdir (dp)) != NULL) { - if (strcmp (ent->d_name, ".") != 0 && - strcmp (ent->d_name, "..") != 0) { - isempty = 0; - break; - } - } - closedir (dp); - } else if (rootsize) - isempty = 0; - - if (!isempty) { - fprintf (stderr, "%s: mountpoint is not empty\n", progname); - fprintf (stderr, "%s: if you are sure this is safe, " - "use the 'nonempty' mount option\n", progname); - return -1; + i++; + (*iov)[i].iov_base = val; + if (len == (size_t) -1) { + if (val != NULL) + len = strlen(val) + 1; + else + len = 0; } - return 0; + (*iov)[i].iov_len = (int)len; + *iovlen = ++i; } -int -fuse_mnt_check_fuseblk (void) +/* + * This function is needed for compatibility with parameters + * which used to use the mount_argf() command for the old mount() syscall. + */ +void +build_iovec_argf(struct iovec **iov, int *iovlen, const char *name, + const char *fmt, ...) { - char buf[256]; - FILE *f = fopen ("/proc/filesystems", "r"); - if (!f) - return 1; - - while (fgets (buf, sizeof (buf), f)) - if (strstr (buf, "fuseblk\n")) { - fclose (f); - return 1; - } + va_list ap; + char val[255] = { 0 }; - fclose (f); - return 0; + va_start(ap, fmt); + vsnprintf(val, sizeof(val), fmt, ap); + va_end(ap); + build_iovec(iov, iovlen, name, strdup(val), (size_t)-1); } +#endif /* __FreeBSD__ */ + +struct mount_flags { + const char *opt; + mount_flag_t flag; + int on; +} mount_flags[] = { + /* We provide best effort cross platform support for mount flags by + * defining the ones which are commonly used in Unix-like OS-es. + */ + {"ro", MS_RDONLY, 1}, + {"nosuid", MS_NOSUID, 1}, + {"nodev", MS_NODEV, 1}, + {"noatime", MS_NOATIME, 1}, + {"noexec", MS_NOEXEC, 1}, +#ifdef GF_LINUX_HOST_OS + {"rw", MS_RDONLY, 0}, + {"suid", MS_NOSUID, 0}, + {"dev", MS_NODEV, 0}, + {"exec", MS_NOEXEC, 0}, + {"async", MS_SYNCHRONOUS, 0}, + {"sync", MS_SYNCHRONOUS, 1}, + {"atime", MS_NOATIME, 0}, + {"dirsync", MS_DIRSYNC, 1}, #endif + {NULL, 0, 0} +}; -#ifndef FUSE_UTIL -void -gf_fuse_unmount (const char *mountpoint, int fd) +static int +mount_param_to_flag (char *mnt_param, mount_flag_t *mntflags, + char **mnt_param_new) { - int res; - int pid; - - if (!mountpoint) - return; - - if (fd != -1) { - struct pollfd pfd; - - pfd.fd = fd; - pfd.events = 0; - res = poll (&pfd, 1, 0); - /* If file poll returns POLLERR on the device file descriptor, - then the filesystem is already unmounted */ - if (res == 1 && (pfd.revents & POLLERR)) - return; + gf_boolean_t found = _gf_false; + struct mount_flags *flag = NULL; + char *param_tok = NULL; + token_iter_t tit = {0,}; + gf_boolean_t iter_end = _gf_false; + + /* Allocate a buffer that will hold the mount parameters remaining + * after the ones corresponding to mount flags are processed and + * removed.The length of the original params are a good upper bound + * of the size needed. + */ + *mnt_param_new = strdup (mnt_param); + if (!*mnt_param_new) + return -1; - /* Need to close file descriptor, otherwise synchronous umount - would recurse into filesystem, and deadlock */ - close (fd); - } + for (param_tok = token_iter_init (*mnt_param_new, ',', &tit) ;;) { + iter_end = next_token (¶m_tok, &tit); + + found = _gf_false; + for (flag = mount_flags; flag->opt; flag++) { + /* Compare the mount flag name to the param + * name at hand. + */ + if (strcmp (flag->opt, param_tok) == 0) { + /* If there is a match, adjust mntflags + * accordingly and break. + */ + if (flag->on) { + *mntflags |= flag->flag; + } else { + *mntflags &= ~flag->flag; + } + found = _gf_true; + break; + } + } + /* Exclude flag names from new parameter list. */ + if (found) + drop_token (param_tok, &tit); - if (geteuid () == 0) { - fuse_mnt_umount ("fuse", mountpoint, 1); - return; + if (iter_end) + break; } - res = umount2 (mountpoint, 2); - if (res == 0) - return; - - pid = fork (); - if (pid == -1) - return; - - if (pid == 0) { - const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z", - "--", mountpoint, NULL }; - - execvp (FUSERMOUNT_PROG, (char **)argv); - _exit (1); - } - waitpid (pid, NULL, 0); + return 0; } -#endif -/* - * Functions below are loosely modelled after similar functions of libfuse - */ - -#ifndef FUSE_UTIL static int -fuse_mount_sys (const char *mountpoint, char *fsname, char *mnt_param) +fuse_mount_sys (const char *mountpoint, char *fsname, + char *mnt_param, int fd) { - int fd = -1, ret = -1; + int ret = -1; unsigned mounted = 0; char *mnt_param_mnt = NULL; char *fstype = "fuse.glusterfs"; char *source = fsname; - - fd = open ("/dev/fuse", O_RDWR); - if (fd == -1) { - GFFUSE_LOGERR ("cannot open /dev/fuse (%s)", strerror (errno)); - - return -1; - } - - ret = asprintf (&mnt_param_mnt, - "%s,fd=%i,rootmode=%o,user_id=%i,group_id=%i", - mnt_param, fd, S_IFDIR, getuid (), getgid ()); + mount_flag_t mountflags = 0; + char *mnt_param_new = NULL; + + ret = mount_param_to_flag (mnt_param, &mountflags, &mnt_param_new); + if (ret == 0) + ret = asprintf (&mnt_param_mnt, + "%s,fd=%i,rootmode=%o,user_id=%i,group_id=%i", + mnt_param_new, fd, S_IFDIR, getuid (), + getgid ()); if (ret == -1) { GFFUSE_LOGERR ("Out of memory"); goto out; } - ret = mount (source, mountpoint, fstype, 0, + +#ifdef __FreeBSD__ + struct iovec *iov = NULL; + int iovlen = 0; + char fdstr[15]; + sprintf (fdstr, "%d", fd); + + build_iovec (&iov, &iovlen, "fstype", "fusefs", -1); + build_iovec (&iov, &iovlen, "subtype", "glusterfs", -1); + build_iovec (&iov, &iovlen, "fspath", __DECONST(void *, mountpoint), + -1); + build_iovec (&iov, &iovlen, "from", "/dev/fuse", -1); + build_iovec (&iov, &iovlen, "volname", source, -1); + build_iovec (&iov, &iovlen, "fd", fdstr, -1); + build_iovec (&iov, &iovlen, "allow_other", NULL, -1); + ret = nmount (iov, iovlen, mountflags); +#else + ret = mount (source, mountpoint, fstype, mountflags, mnt_param_mnt); +#endif /* __FreeBSD__ */ +#ifdef GF_LINUX_HOST_OS if (ret == -1 && errno == ENODEV) { /* fs subtype support was added by 79c0b2df aka v2.6.21-3159-g79c0b2d. Probably we have an @@ -548,16 +408,19 @@ fuse_mount_sys (const char *mountpoint, char *fsname, char *mnt_param) goto out; } - ret = mount (source, mountpoint, fstype, 0, + ret = mount (source, mountpoint, fstype, mountflags, mnt_param_mnt); } +#endif /* GF_LINUX_HOST_OS */ if (ret == -1) goto out; else mounted = 1; +#ifdef GF_LINUX_HOST_OS if (geteuid () == 0) { char *newmnt = fuse_mnt_resolve_path ("fuse", mountpoint); + char *mnt_param_mtab = NULL; if (!newmnt) { ret = -1; @@ -565,8 +428,17 @@ fuse_mount_sys (const char *mountpoint, char *fsname, char *mnt_param) goto out; } - ret = fuse_mnt_add_mount ("fuse", source, newmnt, fstype, - mnt_param); + ret = asprintf (&mnt_param_mtab, "%s%s", + mountflags & MS_RDONLY ? "ro," : "", + mnt_param_new); + if (ret == -1) + GFFUSE_LOGERR ("Out of memory"); + else { + ret = fuse_mnt_add_mount ("fuse", source, newmnt, + fstype, mnt_param_mtab); + FREE (mnt_param_mtab); + } + FREE (newmnt); if (ret == -1) { GFFUSE_LOGERR ("failed to add mtab entry"); @@ -574,58 +446,81 @@ fuse_mount_sys (const char *mountpoint, char *fsname, char *mnt_param) goto out; } } +#endif /* GF_LINUX_HOST_OS */ - out: +out: if (ret == -1) { + GFFUSE_LOGERR("ret = -1\n"); if (mounted) umount2 (mountpoint, 2); /* lazy umount */ - close (fd); - fd = -1; } FREE (mnt_param_mnt); + FREE (mnt_param_new); if (source != fsname) FREE (source); - return fd; + + return ret; } int -gf_fuse_mount (const char *mountpoint, char *fsname, char *mnt_param) +gf_fuse_mount (const char *mountpoint, char *fsname, + char *mnt_param, pid_t *mnt_pid, int status_fd) { - int fd = -1, rv = -1; - char *fm_mnt_params = NULL, *p = NULL; + int fd = -1; + pid_t pid = -1; + int ret = -1; - fd = fuse_mount_sys (mountpoint, fsname, mnt_param); + fd = open ("/dev/fuse", O_RDWR); if (fd == -1) { - gf_log ("glusterfs-fuse", GF_LOG_NORMAL, - "direct mount failed (%s), " - "retry to mount via fusermount", - strerror (errno)); - - rv = asprintf (&fm_mnt_params, - "%s,fsname=%s,nonempty,subtype=glusterfs", - mnt_param, fsname); - - if (rv == -1) { - GFFUSE_LOGERR ("Out of memory"); + GFFUSE_LOGERR ("cannot open /dev/fuse (%s)", + strerror (errno)); + return -1; + } - return -1; + /* start mount agent */ + pid = fork(); + switch (pid) { + case 0: + /* hello it's mount agent */ + if (!mnt_pid) { + /* daemonize mount agent, caller is + * not interested in waiting for it + */ + pid = fork (); + if (pid) + exit (pid == -1 ? 1 : 0); } - fd = fuse_mount_fusermount (mountpoint, fm_mnt_params); - if (fd == -1) { - p = fm_mnt_params + strlen (fm_mnt_params); - while (*--p != ','); - *p = '\0'; + ret = fuse_mount_sys (mountpoint, fsname, mnt_param, fd); + if (ret == -1) { + gf_log ("glusterfs-fuse", GF_LOG_INFO, + "direct mount failed (%s) errno %d", + strerror (errno), errno); - fd = fuse_mount_fusermount (mountpoint, fm_mnt_params); + if (errno == EPERM) { + gf_log ("glusterfs-fuse", GF_LOG_INFO, + "retry to mount via fusermount"); + + ret = fuse_mount_fusermount (mountpoint, fsname, + mnt_param, fd); + } } - FREE (fm_mnt_params); + if (ret == -1) + GFFUSE_LOGERR ("mount of %s to %s (%s) failed", + fsname, mountpoint, mnt_param); - if (fd == -1) - GFFUSE_LOGERR ("mount failed"); + if (status_fd >= 0) + (void)write (status_fd, &ret, sizeof (ret)); + exit (!!ret); + /* bye mount agent */ + case -1: + close (fd); + fd = -1; } + if (mnt_pid) + *mnt_pid = pid; + return fd; } -#endif |
