int gf_fuse_mount (const char *mountpoint, char *fsname, unsigned long mountflags, char *mnt_param, pid_t *mnt_pid, int status_fd) { int fd = -1; pid_t pid = -1; int ret = -1; fd = open ("/dev/fuse", O_RDWR); if (fd == -1) { GFFUSE_LOGERR ("cannot open /dev/fuse (%s)", strerror (errno)); 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); } ret = fuse_mount_sys (mountpoint, fsname, mountflags, mnt_param, fd); if (ret == -1) { gf_log ("glusterfs-fuse", GF_LOG_INFO, "direct mount failed (%s) errno %d, " "retry to mount via fusermount", strerror (errno), errno); ret = fuse_mount_fusermount (mountpoint, fsname, mountflags, mnt_param, fd); } if (ret == -1) GFFUSE_LOGERR ("mount of %s to %s (%s) failed", fsname, mountpoint, mnt_param); 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; }
/* FUSE: to support some changes that were reverted since * then, it was split in two (fuse_mnt_umount() and * exec_umount()); however the actual code is same as here * since 0197ce40 */ int fuse_mnt_umount (const char *progname, const char *abs_mnt, const char *rel_mnt, int lazy) { int res; int status; sigset_t blockmask; sigset_t oldmask; if (!mtab_needs_update (abs_mnt)) { res = umount2 (rel_mnt, lazy ? 2 : 0); if (res == -1) GFFUSE_LOGERR ("%s: failed to unmount %s: %s", progname, abs_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; } 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", rel_mnt, lazy ? "-l" : NULL, NULL); GFFUSE_LOGERR ("%s: failed to execute /bin/umount: %s", progname, strerror (errno)); exit (1); } res = waitpid (res, &status, 0); if (res == -1) GFFUSE_LOGERR ("%s: waitpid: %s", progname, strerror (errno)); if (status != 0) res = -1; out_restore: sigprocmask (SIG_SETMASK, &oldmask, NULL); return res; }
int gf_fuse_mount (const char *mountpoint, char *fsname, char *mnt_param) { int fd, pid; int result; char *fdnam, *dev; const char *mountprog = MACFUSE_MOUNT_PROG; sig_t chldf; /* mount_fusefs should not try to spawn the daemon */ setenv("MOUNT_FUSEFS_SAFE", "1", 1); /* to notify mount_fusefs it's called from lib */ setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); if (!mountpoint) { fprintf(stderr, "missing or invalid mount point\n"); return -1; } if (fuse_running_under_rosetta()) { fprintf(stderr, "MacFUSE does not work under Rosetta\n"); return -1; } chldf = signal(SIGCHLD, SIG_DFL); /* So that we can wait4() below. */ result = loadkmod(); if (result == EINVAL) GFFUSE_LOGERR("OS X >= 10.5 (at least Leopard) required"); else if (result == 0 || result == ENOENT || result == EBUSY) { /* Module loaded, but now need to check for user<->kernel match. */ char version[MAXHOSTNAMELEN + 1] = { 0 }; size_t version_len = MAXHOSTNAMELEN; size_t version_len_desired = 0; result = sysctlbyname(SYSCTL_MACFUSE_VERSION_NUMBER, version, &version_len, NULL, (size_t)0); if (result == 0) { /* sysctlbyname() includes the trailing '\0' in version_len */ version_len_desired = strlen("2.x.y") + 1; if (version_len != version_len_desired) result = -1; } else strcpy(version, "?.?.?"); if (result == 0) { char *ep; char vstr[4]; unsigned vval; int i; for (i = 0; i < 3; i++) vstr[i] = version[2*i]; vstr[3] = '\0'; vval = strtoul(vstr, &ep, 10); if (*ep || vval < 203 || vval > 217) result = -1; else gf_log("glusterfs-fuse", GF_LOG_INFO, "MacFUSE kext version %s", version); } if (result != 0) GFFUSE_LOGERR("MacFUSE version %s is not supported", version); } else GFFUSE_LOGERR("cannot load MacFUSE kext"); if (result != 0) return -1; fdnam = getenv("FUSE_DEV_FD"); if (fdnam) { char *ep; fd = strtol(fdnam, &ep, 10); if (*ep != '\0' || fd < 0) { GFFUSE_LOGERR("invalid value given in FUSE_DEV_FD"); return -1; } goto mount; } dev = getenv("FUSE_DEV_NAME"); if (dev) { if ((fd = open(dev, O_RDWR)) < 0) { GFFUSE_LOGERR("failed to open device (%s)", strerror(errno)); return -1; } } else { int r, devidx = -1; char devpath[MAXPATHLEN]; for (r = 0; r < MACFUSE_NDEVICES; r++) { snprintf(devpath, MAXPATHLEN - 1, _PATH_DEV MACFUSE_DEVICE_BASENAME "%d", r); fd = open(devpath, O_RDWR); if (fd >= 0) { dev = devpath; devidx = r; break; } } if (devidx == -1) { GFFUSE_LOGERR("failed to open device (%s)", strerror(errno)); return -1; } } mount: if (getenv("FUSE_NO_MOUNT") || ! mountpoint) goto out; signal(SIGCHLD, chldf); pid = fork(); if (pid == -1) { GFFUSE_LOGERR("fork() failed (%s)", strerror(errno)); close(fd); return -1; } if (pid == 0) { pid = fork(); if (pid == -1) { GFFUSE_LOGERR("fork() failed (%s)", strerror(errno)); close(fd); exit(1); } if (pid == 0) { const char *argv[32]; int a = 0; char *opts = NULL; if (asprintf(&opts, "%s,fssubtype=glusterfs", mnt_param) == -1) { GFFUSE_LOGERR("Out of memory"); exit(1); } if (! fdnam) asprintf(&fdnam, "%d", fd); argv[a++] = mountprog; if (opts) { argv[a++] = "-o"; argv[a++] = opts; } argv[a++] = fdnam; argv[a++] = mountpoint; argv[a++] = NULL; { char title[MAXPATHLEN + 1] = { 0 }; u_int32_t len = MAXPATHLEN; int ret = proc_pidpath(getpid(), title, len); if (ret) { setenv("MOUNT_FUSEFS_DAEMON_PATH", title, 1); } } execvp(mountprog, (char **) argv); GFFUSE_LOGERR("MacFUSE: failed to exec mount program (%s)", strerror(errno)); exit(1); } _exit(0); } out: return fd; }
static int fuse_mount_sys (const char *mountpoint, char *fsname, unsigned long mountflags, char *mnt_param, int fd) { int ret = -1; unsigned mounted = 0; char *mnt_param_mnt = NULL; char *fstype = "fuse.glusterfs"; char *source = fsname; ret = asprintf (&mnt_param_mnt, "%s,fd=%i,rootmode=%o,user_id=%i,group_id=%i", mnt_param, fd, S_IFDIR, getuid (), getgid ()); if (ret == -1) { GFFUSE_LOGERR ("Out of memory"); goto out; } #ifdef __FreeBSD__ struct iovec *iov = NULL; int iovlen = 0; build_iovec (&iov, &iovlen, "fstype", "fusefs", -1); build_iovec (&iov, &iovlen, "subtype", "glusterfs", -1); build_iovec (&iov, &iovlen, "fspath", mountpoint, -1); build_iovec (&iov, &iovlen, "from", "/dev/fuse", -1); build_iovec (&iov, &iovlen, "volname", source, -1); build_iovec_argf (&iov, &iovlen, "fd", "%d", fd); build_iovec_argf (&iov, &iovlen, "user_id", "%d", getuid()); build_iovec_argf (&iov, &iovlen, "group_id", "%d", getgid()); 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 older kernel ... */ fstype = "fuse"; ret = asprintf (&source, "glusterfs#%s", fsname); if (ret == -1) { GFFUSE_LOGERR ("Out of memory"); goto out; } 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; goto out; } ret = asprintf (&mnt_param_mtab, "%s%s", mountflags & MS_RDONLY ? "ro," : "", mnt_param); 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"); goto out; } } #endif /* GF_LINUX_HOST_OS */ out: if (ret == -1) { GFFUSE_LOGERR("ret = -1\n"); if (mounted) umount2 (mountpoint, 2); /* lazy umount */ } FREE (mnt_param_mnt); if (source != fsname) FREE (source); return ret; }
static int fuse_mount_fusermount (const char *mountpoint, char *fsname, unsigned long mountflags, char *mnt_param, int fd) { 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"); return -1; } ret = asprintf (&fm_mnt_params, "%s%s,fsname=%s,nonempty,subtype=glusterfs", (mountflags & MS_RDONLY) ? "ro," : "", 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)); ret = -1; goto out; } if (pid == 0) { char env[10]; const char *argv[32]; int a = 0; argv[a++] = FUSERMOUNT_PROG; argv[a++] = "-o"; argv[a++] = fm_mnt_params; argv[a++] = "--"; argv[a++] = mountpoint; argv[a++] = NULL; 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); } ret = waitpid (pid, &res, 0); ret = (ret == pid && res == 0) ? 0 : -1; out: FREE (fm_mnt_params); return ret; }
/* FUSE: called add_mount_legacy(); R.I.P. as of cbd3a2a8 */ int fuse_mnt_add_mount (const char *progname, const char *fsname, const char *mnt, const char *type, const char *opts) { 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)); 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; 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 (_PATH_MOUNT, _PATH_MOUNT, "-i", "-f", "-t", type, "-o", opts, fsname, mnt, NULL); GFFUSE_LOGERR ("%s: failed to execute %s: %s", progname, _PATH_MOUNT, strerror (errno)); exit (1); } res = waitpid (res, &status, 0); if (res == -1) GFFUSE_LOGERR ("%s: waitpid: %s", progname, strerror (errno)); res = (res != -1 && status == 0) ? 0 : -1; out_restore: sigprocmask (SIG_SETMASK, &oldmask, NULL); return res; }
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; } copy = strdup (orig); if (copy == NULL) { GFFUSE_LOGERR ("%s: failed to allocate memory", progname); return NULL; } 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'; } 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); } } FREE (copy); if (dst == NULL) GFFUSE_LOGERR ("%s: failed to allocate memory", progname); return dst; }