aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mount.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mount.c')
-rw-r--r--lib/mount.c222
1 files changed, 125 insertions, 97 deletions
diff --git a/lib/mount.c b/lib/mount.c
index f98a8bb..3fbbe72 100644
--- a/lib/mount.c
+++ b/lib/mount.c
@@ -8,6 +8,9 @@
See the file COPYING.LIB.
*/
+/* For environ */
+#define _GNU_SOURCE
+
#include "fuse_config.h"
#include "fuse_i.h"
#include "fuse_misc.h"
@@ -22,6 +25,7 @@
#include <fcntl.h>
#include <errno.h>
#include <poll.h>
+#include <spawn.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
@@ -44,10 +48,6 @@
#define FUSERMOUNT_PROG "fusermount3"
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
-#ifndef HAVE_FORK
-#define fork() vfork()
-#endif
-
#ifndef MS_DIRSYNC
#define MS_DIRSYNC 128
#endif
@@ -117,21 +117,51 @@ static const struct fuse_opt fuse_mount_opts[] = {
FUSE_OPT_END
};
-static void exec_fusermount(const char *argv[])
+/*
+ * Running fusermount by calling 'posix_spawn'
+ *
+ * @param out_pid might be NULL
+ */
+static int fusermount_posix_spawn(posix_spawn_file_actions_t *action,
+ char const * const argv[], pid_t *out_pid)
{
- execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
- execvp(FUSERMOUNT_PROG, (char **) argv);
+ const char *full_path = FUSERMOUNT_DIR "/" FUSERMOUNT_PROG;
+ pid_t pid;
+
+ /* See man 7 environ for the global environ pointer */
+
+ /* first try the install path */
+ int status = posix_spawn(&pid, full_path, action, NULL,
+ (char * const *) argv, environ);
+ if (status != 0) {
+ /* if that fails, try a system install */
+ status = posix_spawnp(&pid, FUSERMOUNT_PROG, action, NULL,
+ (char * const *) argv, environ);
+ }
+
+ if (status != 0) {
+ fuse_log(FUSE_LOG_ERR,
+ "On calling fusermount posix_spawn failed: %s\n",
+ strerror(status));
+ return -status;
+ }
+
+ if (out_pid)
+ *out_pid = pid;
+ else
+ waitpid(pid, NULL, 0);
+
+ return 0;
}
void fuse_mount_version(void)
{
- int pid = fork();
- if (!pid) {
- const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
- exec_fusermount(argv);
- _exit(1);
- } else if (pid != -1)
- waitpid(pid, NULL, 0);
+ char const *const argv[] = {FUSERMOUNT_PROG, "--version", NULL};
+ int status = fusermount_posix_spawn(NULL, argv, NULL);
+
+ if(status != 0)
+ fuse_log(FUSE_LOG_ERR, "Running '%s --version' failed",
+ FUSERMOUNT_PROG);
}
struct mount_flags {
@@ -249,7 +279,7 @@ static int receive_fd(int fd)
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
if (rv == -1) {
- perror("recvmsg");
+ fuse_log(FUSE_LOG_ERR, "recvmsg failed: %s", strerror(errno));
return -1;
}
if(!rv) {
@@ -269,7 +299,6 @@ static int receive_fd(int fd)
void fuse_kern_unmount(const char *mountpoint, int fd)
{
int res;
- int pid;
if (fd != -1) {
struct pollfd pfd;
@@ -301,23 +330,21 @@ void fuse_kern_unmount(const char *mountpoint, int fd)
if (res == 0)
return;
- pid = fork();
- if(pid == -1)
+ char const * const argv[] =
+ { FUSERMOUNT_PROG, "--unmount", "--quiet", "--lazy",
+ "--", mountpoint, NULL };
+ int status = fusermount_posix_spawn(NULL, argv, NULL);
+ if(status != 0) {
+ fuse_log(FUSE_LOG_ERR, "Spawaning %s to unumount failed",
+ FUSERMOUNT_PROG);
return;
-
- if(pid == 0) {
- const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z",
- "--", mountpoint, NULL };
-
- exec_fusermount(argv);
- _exit(1);
}
- waitpid(pid, NULL, 0);
}
static int setup_auto_unmount(const char *mountpoint, int quiet)
{
- int fds[2], pid;
+ int fds[2];
+ pid_t pid;
int res;
if (!mountpoint) {
@@ -327,59 +354,62 @@ static int setup_auto_unmount(const char *mountpoint, int quiet)
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
if(res == -1) {
- perror("fuse: socketpair() failed");
+ fuse_log(FUSE_LOG_ERR, "Setting up auto-unmountsocketpair() failed",
+ strerror(errno));
return -1;
}
- pid = fork();
- if(pid == -1) {
- perror("fuse: fork() failed");
- close(fds[0]);
- close(fds[1]);
- return -1;
+ char arg_fd_entry[30];
+ snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
+ setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
+
+ char const *const argv[] = {
+ FUSERMOUNT_PROG,
+ "--auto-unmount",
+ "--",
+ mountpoint,
+ NULL,
+ };
+
+ // TODO: add error handling for all manipulations of action.
+ posix_spawn_file_actions_t action;
+ posix_spawn_file_actions_init(&action);
+
+ if (quiet) {
+ posix_spawn_file_actions_addclose(&action, 1);
+ posix_spawn_file_actions_addclose(&action, 2);
}
+ posix_spawn_file_actions_addclose(&action, fds[1]);
- if(pid == 0) {
- char env[10];
- const char *argv[32];
- int a = 0;
-
- if (quiet) {
- int fd = open("/dev/null", O_RDONLY);
- if (fd != -1) {
- dup2(fd, 1);
- dup2(fd, 2);
- }
- }
+ /*
+ * auto-umount runs in the background - it is not waiting for the
+ * process
+ */
+ int status = fusermount_posix_spawn(&action, argv, &pid);
- argv[a++] = FUSERMOUNT_PROG;
- argv[a++] = "--auto-unmount";
- argv[a++] = "--";
- argv[a++] = mountpoint;
- argv[a++] = NULL;
+ posix_spawn_file_actions_destroy(&action);
+ if(status != 0) {
+ close(fds[0]);
close(fds[1]);
- fcntl(fds[0], F_SETFD, 0);
- snprintf(env, sizeof(env), "%i", fds[0]);
- setenv(FUSE_COMMFD_ENV, env, 1);
- exec_fusermount(argv);
- perror("fuse: failed to exec fusermount3");
- _exit(1);
+ fuse_log(FUSE_LOG_ERR, "fuse: Setting up auto-unmount failed");
+ return -1;
}
-
+ // passed to child now, so can close here.
close(fds[0]);
// Now fusermount3 will only exit when fds[1] closes automatically when our
// process exits.
return 0;
+ // Note: fds[1] is leakend and doesn't get FD_CLOEXEC
}
static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
const char *opts, int quiet)
{
- int fds[2], pid;
+ int fds[2];
+ pid_t pid;
int res;
- int rv;
if (!mountpoint) {
fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
@@ -388,51 +418,49 @@ static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
if(res == -1) {
- perror("fuse: socketpair() failed");
+ fuse_log(FUSE_LOG_ERR, "Running %s: socketpair() failed: %s\n",
+ FUSERMOUNT_PROG, strerror(errno));
return -1;
}
- pid = fork();
- if(pid == -1) {
- perror("fuse: fork() failed");
- close(fds[0]);
- close(fds[1]);
- return -1;
- }
+ char arg_fd_entry[30];
+ snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
+ setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
- if(pid == 0) {
- char env[10];
- const char *argv[32];
- int a = 0;
+ char const *const argv[] = {
+ FUSERMOUNT_PROG,
+ "-o", opts ? opts : "",
+ "--",
+ mountpoint,
+ NULL,
+ };
- if (quiet) {
- int fd = open("/dev/null", O_RDONLY);
- if (fd != -1) {
- dup2(fd, 1);
- dup2(fd, 2);
- }
- }
- argv[a++] = FUSERMOUNT_PROG;
- if (opts) {
- argv[a++] = "-o";
- argv[a++] = opts;
- }
- argv[a++] = "--";
- argv[a++] = mountpoint;
- argv[a++] = NULL;
+ posix_spawn_file_actions_t action;
+ posix_spawn_file_actions_init(&action);
+
+ if (quiet) {
+ posix_spawn_file_actions_addclose(&action, 1);
+ posix_spawn_file_actions_addclose(&action, 2);
+ }
+ posix_spawn_file_actions_addclose(&action, fds[1]);
+
+ int status = fusermount_posix_spawn(&action, argv, &pid);
+
+ posix_spawn_file_actions_destroy(&action);
+ if(status != 0) {
+ close(fds[0]);
close(fds[1]);
- fcntl(fds[0], F_SETFD, 0);
- snprintf(env, sizeof(env), "%i", fds[0]);
- setenv(FUSE_COMMFD_ENV, env, 1);
- exec_fusermount(argv);
- perror("fuse: failed to exec fusermount3");
- _exit(1);
+ fuse_log(FUSE_LOG_ERR, "posix_spawnp() for %s failed",
+ FUSERMOUNT_PROG, strerror(errno));
+ return -1;
}
+ // passed to child now, so can close here.
close(fds[0]);
- rv = receive_fd(fds[1]);
+
+ int fd = receive_fd(fds[1]);
if (!mo->auto_unmount) {
/* with auto_unmount option fusermount3 will not exit until
@@ -441,10 +469,10 @@ static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
waitpid(pid, NULL, 0); /* bury zombie */
}
- if (rv >= 0)
- fcntl(rv, F_SETFD, FD_CLOEXEC);
+ if (fd >= 0)
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
- return rv;
+ return fd;
}
#ifndef O_CLOEXEC