diff options
Diffstat (limited to 'contrib/macfuse/mount_darwin.c')
| -rw-r--r-- | contrib/macfuse/mount_darwin.c | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/contrib/macfuse/mount_darwin.c b/contrib/macfuse/mount_darwin.c new file mode 100644 index 00000000000..d1d1c34e761 --- /dev/null +++ b/contrib/macfuse/mount_darwin.c @@ -0,0 +1,264 @@ +/* + * Derived from mount_bsd.c from the fuse distribution. + * + * FUSE: Filesystem in Userspace + * Copyright (C) 2005-2006 Csaba Henk <csaba.henk@creo.hu> + * Copyright (C) 2007-2009 Amit Singh <asingh@gmail.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. + */ + +#undef _POSIX_C_SOURCE +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/sysctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <paths.h> + +#include <libproc.h> +#include <sys/utsname.h> + +#include <sys/param.h> +#include <sys/mount.h> +#include <AssertMacros.h> + +#include "fuse_param.h" +#include "fuse_ioctl.h" + +#include "glusterfs/glusterfs.h" +#include "glusterfs/logging.h" +#include "glusterfs/common-utils.h" + +#define GFFUSE_LOGERR(...) \ + gf_log ("glusterfs-fuse", GF_LOG_ERROR, ## __VA_ARGS__) + +int +gf_fuse_mount (const char *mountpoint, char *fsname, char *mnt_param, + pid_t *mnt_pid, int status_fd) /* Not used on OS X */ +{ + int fd = 0; + int pid = 0; + int ret = 0; + char *fdnam = NULL; + char *dev = NULL; + char vstr[4]; + unsigned vval = 0; + int i = 0; + + const char *mountprog = OSXFUSE_MOUNT_PROG; + sig_t chldf = SIG_ERR; + char version[MAXHOSTNAMELEN + 1] = { 0 }; + size_t version_len = MAXHOSTNAMELEN; + size_t version_len_desired = 0; + int r = 0; + char devpath[MAXPATHLEN] = { 0 };; + + if (!mountpoint) { + gf_log ("glustefs-fuse", GF_LOG_ERROR, + "missing or invalid mount point"); + goto err; + } + + /* 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); + + chldf = signal(SIGCHLD, SIG_DFL); /* So that we can wait4() below. */ + + if (chldf == SIG_ERR) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "signal() returned SIG_ERR: %s", + strerror(errno)); + goto err; + } + + /* check for user<->kernel match. */ + ret = sysctlbyname(SYSCTL_OSXFUSE_VERSION_NUMBER, version, + &version_len, NULL, (size_t)0); + if (ret != 0) { + gf_log ("glustefs-fuse", GF_LOG_ERROR, + "sysctlbyname() returned error: %s", + strerror(errno)); + goto err; + } + + /* sysctlbyname() includes the trailing '\0' in version_len */ + version_len_desired = sizeof ("2.x.y"); + + if (version_len != version_len_desired) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "version length mismatch for OSXFUSE %s", + version); + ret = -1; + goto err; + } + + for (i = 0; i < 3; i++) + vstr[i] = version[2*i]; + vstr[3] = '\0'; + + vval = strtoul(vstr, NULL, 10); + if (vval < 264) { + GFFUSE_LOGERR("OSXFUSE version %s is not supported", version); + ret = -1; + goto err; + } + + gf_log("glusterfs-fuse", GF_LOG_INFO, + "OSXFUSE kext version supported %s", version); + + fdnam = getenv("FUSE_DEV_FD"); + if (fdnam) { + fd = strtol(fdnam, NULL, 10); + if (fd < 0) { + GFFUSE_LOGERR("invalid value given in FUSE_DEV_FD"); + ret = -1; + goto err; + } + goto mount; + } + + dev = getenv("FUSE_DEV_NAME"); + if (!dev) { + for (r = 0; r < OSXFUSE_NDEVICES; r++) { + snprintf(devpath, MAXPATHLEN - 1, + _PATH_DEV OSXFUSE_DEVICE_BASENAME "%d", r); + if ((fd = open(devpath, O_RDWR)) < 0) { + GFFUSE_LOGERR("failed to open device %s (%s)", + devpath, + strerror(errno)); + goto err; + } + dev = devpath; + goto mount; + } + } + + fd = open(dev, O_RDWR); + if (fd < 0) { + GFFUSE_LOGERR("failed to open device %s (%s)", dev, + strerror(errno)); + ret = -1; + goto err; + } + +mount: + signal(SIGCHLD, chldf); + + pid = fork(); + if (pid == -1) { + GFFUSE_LOGERR("fork() failed (%s)", strerror(errno)); + ret = -1; + goto err; + } + + if (pid == 0) { + pid = fork(); + if (pid == -1) { + GFFUSE_LOGERR("fork() failed (%s)", strerror(errno)); + ret = -1; + goto err; + } + + if (pid == 0) { + const char *argv[32]; + int a = 0; + char *opts = NULL; + + if (asprintf(&opts, "%s,fssubtype=glusterfs", + mnt_param) == -1) { + GFFUSE_LOGERR("asprintf() error: %s", + strerror(errno)); + ret = -1; + goto err; + } + + 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("OSXFUSE: failed to exec mount" + " program (%s)", strerror(errno)); + _exit(1); + } + _exit(0); + } + ret = fd; +err: + if (ret == -1) { + if (fd > 0) { + close(fd); + } + } + return ret; +} + +void +gf_fuse_unmount(const char *mountpoint, int fd) +{ + int ret; + struct stat sbuf; + char dev[128]; + char resolved_path[PATH_MAX]; + char *ep, *rp = NULL; + + unsigned int hs_complete = 0; + + ret = ioctl(fd, FUSEDEVIOCGETHANDSHAKECOMPLETE, &hs_complete); + if (ret || !hs_complete) { + return; + } + + if (fstat(fd, &sbuf) == -1) { + return; + } + + devname_r(sbuf.st_rdev, S_IFCHR, dev, 128); + + if (strncmp(dev, OSXFUSE_DEVICE_BASENAME, + sizeof(OSXFUSE_DEVICE_BASENAME) - 1)) { + return; + } + + strtol(dev + sizeof(OSXFUSE_DEVICE_BASENAME) - 1, &ep, 10); + if (*ep != '\0') { + return; + } + + rp = realpath(mountpoint, resolved_path); + if (rp) { + ret = unmount(resolved_path, 0); + } + + close(fd); + return; +} |
