summaryrefslogtreecommitdiffstats
path: root/contrib/macfuse/mount_darwin.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/macfuse/mount_darwin.c')
-rw-r--r--contrib/macfuse/mount_darwin.c355
1 files changed, 355 insertions, 0 deletions
diff --git a/contrib/macfuse/mount_darwin.c b/contrib/macfuse/mount_darwin.c
new file mode 100644
index 00000000000..f7fcc2a70ed
--- /dev/null
+++ b/contrib/macfuse/mount_darwin.c
@@ -0,0 +1,355 @@
+/*
+ * 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.h"
+#include "logging.h"
+#include "common-utils.h"
+
+#define GFFUSE_LOGERR(...) \
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR, ## __VA_ARGS__)
+
+static long
+fuse_os_version_major_np(void)
+{
+ int ret = 0;
+ long major = 0;
+ char *c = NULL;
+ struct utsname u;
+ size_t oldlen;
+
+ oldlen = sizeof(u.release);
+
+ ret = sysctlbyname("kern.osrelease", u.release, &oldlen, NULL, 0);
+ if (ret != 0) {
+ return -1;
+ }
+
+ c = strchr(u.release, '.');
+ if (c == NULL) {
+ return -1;
+ }
+
+ *c = '\0';
+
+ errno = 0;
+ major = strtol(u.release, NULL, 10);
+ if ((errno == EINVAL) || (errno == ERANGE)) {
+ return -1;
+ }
+
+ return major;
+}
+
+static int
+fuse_running_under_rosetta(void)
+{
+ int result = 0;
+ int is_native = 1;
+ size_t sz = sizeof(result);
+
+ int ret = sysctlbyname("sysctl.proc_native", &result, &sz, NULL, (size_t)0);
+ if ((ret == 0) && !result) {
+ is_native = 0;
+ }
+
+ return !is_native;
+}
+
+static int
+loadkmod(void)
+{
+ int result = -1;
+ int pid, terminated_pid;
+ union wait status;
+ long major;
+
+ major = fuse_os_version_major_np();
+
+ if (major < 9) { /* not Mac OS X 10.5+ */
+ return EINVAL;
+ }
+
+ pid = fork();
+
+ if (pid == 0) {
+ execl(MACFUSE_LOAD_PROG, MACFUSE_LOAD_PROG, NULL);
+
+ /* exec failed */
+ exit(ENOENT);
+ }
+
+ require_action(pid != -1, Return, result = errno);
+
+ while ((terminated_pid = wait4(pid, (int *)&status, 0, NULL)) < 0) {
+ /* retry if EINTR, else break out with error */
+ if (errno != EINTR) {
+ break;
+ }
+ }
+
+ if ((terminated_pid == pid) && (WIFEXITED(status))) {
+ result = WEXITSTATUS(status);
+ } else {
+ result = -1;
+ }
+
+Return:
+ check_noerr_string(result, strerror(errno));
+
+ return result;
+}
+
+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;
+
+ /* 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;
+ }
+
+ 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, SIG_IGN);
+
+ 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;
+}
+
+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;
+ }
+ /* XXX does this have any use here? */
+ ret = ioctl(fd, FUSEDEVIOCSETDAEMONDEAD, &fd);
+ if (ret) {
+ return;
+ }
+
+ if (fstat(fd, &sbuf) == -1) {
+ return;
+ }
+
+ devname_r(sbuf.st_rdev, S_IFCHR, dev, 128);
+
+ if (strncmp(dev, MACFUSE_DEVICE_BASENAME,
+ sizeof(MACFUSE_DEVICE_BASENAME) - 1)) {
+ return;
+ }
+
+ strtol(dev + 4, &ep, 10);
+ if (*ep != '\0') {
+ return;
+ }
+
+ rp = realpath(mountpoint, resolved_path);
+ if (rp) {
+ ret = unmount(resolved_path, 0);
+ }
+
+ close(fd);
+
+ return;
+}