aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am1
-rw-r--r--lib/fuse.c54
-rw-r--r--lib/fuse_i.h1
-rw-r--r--lib/fuse_mt.c9
-rw-r--r--lib/helper.c143
-rw-r--r--lib/mount.c136
6 files changed, 202 insertions, 142 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 5ecee0b..cf1de09 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -6,4 +6,5 @@ libfuse_a_SOURCES = \
fuse.c \
fuse_mt.c \
helper.c \
+ mount.c
fuse_i.h
diff --git a/lib/fuse.c b/lib/fuse.c
index 42ab52a..1a11ae6 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -355,8 +355,8 @@ static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
size_t outsize;
struct fuse_out_header *out;
- if(error > 0) {
- fprintf(stderr, "fuse: positive error code: %i\n", error);
+ if(error <= -512 || error > 0) {
+ fprintf(stderr, "fuse: bad error value: %i\n", error);
error = -ERANGE;
}
@@ -366,6 +366,7 @@ static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
outsize = sizeof(struct fuse_out_header) + argsize;
outbuf = (char *) malloc(outsize);
out = (struct fuse_out_header *) outbuf;
+ memset(out, 0, sizeof(struct fuse_out_header));
out->unique = in->unique;
out->error = error;
if(argsize != 0)
@@ -395,7 +396,9 @@ static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
res = f->op.getattr(path, &buf);
free(path);
}
+
if(res == 0) {
+ memset(&arg, 0, sizeof(struct fuse_lookup_out));
convert_stat(&buf, &arg.attr);
arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
if(f->flags & FUSE_DEBUG) {
@@ -431,8 +434,11 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in)
res = f->op.getattr(path, &buf);
free(path);
}
- if(res == 0)
+
+ if(res == 0) {
+ memset(&arg, 0, sizeof(struct fuse_getattr_out));
convert_stat(&buf, &arg.attr);
+ }
send_reply(f, in, res, &arg, sizeof(arg));
}
@@ -513,8 +519,10 @@ static void do_setattr(struct fuse *f, struct fuse_in_header *in,
if(!res) {
struct stat buf;
res = f->op.getattr(path, &buf);
- if(!res)
+ if(!res) {
+ memset(&outarg, 0, sizeof(struct fuse_setattr_out));
convert_stat(&buf, &outarg.attr);
+ }
}
}
free(path);
@@ -559,6 +567,8 @@ static void do_getdir(struct fuse *f, struct fuse_in_header *in)
free(path);
}
fflush(dh.fp);
+
+ memset(&arg, 0, sizeof(struct fuse_getdir_out));
arg.fd = fileno(dh.fp);
send_reply(f, in, res, &arg, sizeof(arg));
fclose(dh.fp);
@@ -584,6 +594,7 @@ static void do_mknod(struct fuse *f, struct fuse_in_header *in,
free(path);
}
if(res == 0) {
+ memset(&outarg, 0, sizeof(struct fuse_mknod_out));
convert_stat(&buf, &outarg.attr);
outarg.ino = find_node(f, in->ino, PARAM(inarg), &outarg.attr,
in->unique);
@@ -751,6 +762,7 @@ static void do_read(struct fuse *f, struct fuse_in_header *in,
fflush(stdout);
}
}
+ memset(out, 0, sizeof(struct fuse_out_header));
out->unique = in->unique;
out->error = res;
outsize = sizeof(struct fuse_out_header) + size;
@@ -798,8 +810,10 @@ static void do_statfs(struct fuse *f, struct fuse_in_header *in)
struct fuse_statfs_out arg;
res = -ENOSYS;
- if(f->op.statfs)
+ if(f->op.statfs) {
+ memset(&arg, 0, sizeof(struct fuse_statfs_out));
res = f->op.statfs((struct fuse_statfs *) &arg.st);
+ }
send_reply(f, in, res, &arg, sizeof(arg));
}
@@ -916,18 +930,24 @@ struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
do {
res = read(f->fd, cmd->buf, FUSE_MAX_IN);
if(res == -1) {
+ free_cmd(cmd);
+ if(errno == EINTR)
+ return NULL;
+
/* ENODEV means we got unmounted, so we silenty return failure */
if(errno != ENODEV) {
- perror("fuse: reading device");
/* BAD... This will happen again */
+ perror("fuse: reading device");
}
- free_cmd(cmd);
+
+ fuse_exit(f);
return NULL;
}
if((size_t) res < sizeof(struct fuse_in_header)) {
- fprintf(stderr, "short read on fuse device\n");
- /* Cannot happen */
free_cmd(cmd);
+ /* Cannot happen */
+ fprintf(stderr, "short read on fuse device\n");
+ fuse_exit(f);
return NULL;
}
cmd->buflen = res;
@@ -941,18 +961,27 @@ struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
return cmd;
}
-
void fuse_loop(struct fuse *f)
{
while(1) {
- struct fuse_cmd *cmd = __fuse_read_cmd(f);
+ struct fuse_cmd *cmd;
+
+ if(f->exited)
+ return;
+
+ cmd = __fuse_read_cmd(f);
if(cmd == NULL)
- exit(1);
+ continue;
__fuse_process_cmd(f, cmd);
}
}
+void fuse_exit(struct fuse *f)
+{
+ f->exited = 1;
+}
+
struct fuse_context *fuse_get_context(struct fuse *f)
{
if(f->getcontext)
@@ -985,6 +1014,7 @@ struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op)
f->getcontext = NULL;
f->context.uid = 0;
f->context.gid = 0;
+ f->exited = 0;
root = (struct node *) calloc(1, sizeof(struct node));
root->mode = 0;
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index 02b28ec..52f1fdc 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -38,6 +38,7 @@ struct fuse {
struct fuse_context *(*getcontext)(struct fuse *);
struct fuse_context context;
pthread_key_t context_key;
+ volatile int exited;
};
struct fuse_dirhandle {
diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c
index 42d4bad..f1a2e5c 100644
--- a/lib/fuse_mt.c
+++ b/lib/fuse_mt.c
@@ -32,9 +32,14 @@ static void *do_work(void *data)
struct fuse *f = w->f;
while(1) {
- struct fuse_cmd *cmd = __fuse_read_cmd(w->f);
+ struct fuse_cmd *cmd;
+
+ if(f->exited)
+ break;
+
+ cmd = __fuse_read_cmd(w->f);
if(cmd == NULL)
- pthread_exit(NULL);
+ continue;
if(f->numavail == 0 && f->numworker < FUSE_MAX_WORKERS) {
pthread_mutex_lock(&f->lock);
diff --git a/lib/helper.c b/lib/helper.c
index 522b377..d3b8b1c 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -10,21 +10,15 @@
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
+#include <string.h>
#include <limits.h>
#include <signal.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <fcntl.h>
-#include <sys/wait.h>
#define FUSE_MOUNTED_ENV "_FUSE_MOUNTED"
#define FUSE_UMOUNT_CMD_ENV "_FUSE_UNMOUNT_CMD"
-#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
-#define FUSERMOUNT_PROG "fusermount"
+static struct fuse *fuse;
static void usage(char *progname)
{
@@ -38,125 +32,10 @@ static void usage(char *progname)
exit(1);
}
-static char umount_cmd[1024];
-static int fuse_fd;
-
-static void fuse_unmount()
-{
- close(fuse_fd);
- if(umount_cmd[0] != '\0')
- system(umount_cmd);
-}
-
-/* return value:
- * >= 0 => fd
- * -1 => error
- */
-static int receive_fd(int fd)
-{
- struct msghdr msg;
- struct iovec iov;
- char buf[1];
- int rv;
- int connfd = -1;
- char ccmsg[CMSG_SPACE(sizeof(connfd))];
- 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) {
- perror("recvmsg");
- return -1;
- }
- if(!rv) {
- /* EOF */
- fprintf(stderr, "got EOF\n");
- return -1;
- }
-
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg->cmsg_type == SCM_RIGHTS) {
- fprintf(stderr, "got control message of unknown type %d\n",
- cmsg->cmsg_type);
- return -1;
- }
- return *(int*)CMSG_DATA(cmsg);
-}
-
-int fuse_mount(const char *mountpoint, const char *args[])
-{
- const char *mountprog = FUSERMOUNT_PROG;
- int fds[2], pid;
- int res;
- int rv;
-
- snprintf(umount_cmd, sizeof(umount_cmd) - 1, "%s -u %s", mountprog,
- mountpoint);
-
- res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
- if(res == -1) {
- perror("fuse: socketpair() failed");
- return -1;
- }
-
- pid = fork();
- if(pid == -1) {
- perror("fuse: fork() failed");
- close(fds[0]);
- close(fds[1]);
- return -1;
- }
-
- if(pid == 0) {
- char env[10];
- char **newargv;
- int numargs = 0;
- int actr;
- int i;
-
- if(args != NULL)
- while(args[numargs] != NULL)
- numargs ++;
-
- newargv = (char **) malloc((1 + numargs + 2) * sizeof(char *));
- actr = 0;
- newargv[actr++] = strdup(mountprog);
- for(i = 0; i < numargs; i++)
- newargv[actr++] = strdup(args[i]);
- newargv[actr++] = strdup(mountpoint);
- newargv[actr++] = NULL;
-
- close(fds[1]);
- fcntl(fds[0], F_SETFD, 0);
- snprintf(env, sizeof(env), "%i", fds[0]);
- setenv(FUSE_COMMFD_ENV, env, 1);
- execvp(mountprog, newargv);
- perror("fuse: failed to exec fusermount");
- exit(1);
- }
-
- close(fds[0]);
- rv = receive_fd(fds[1]);
- close(fds[1]);
- waitpid(pid, NULL, 0); /* bury zombie */
-
- return rv;
-}
-
static void exit_handler()
{
- exit(0);
+ if(fuse != NULL)
+ fuse_exit(fuse);
}
static void set_signal_handlers()
@@ -188,14 +67,17 @@ void fuse_main(int argc, char *argv[], const struct fuse_operations *op)
int argctr = 1;
int flags;
int multithreaded;
- struct fuse *fuse;
char *isreexec = getenv(FUSE_MOUNTED_ENV);
+ int fuse_fd;
+ char *fuse_mountpoint = NULL;
+ char umount_cmd[1024] = "";
if(isreexec == NULL) {
if(argc < 2 || argv[1][0] == '-')
usage(argv[0]);
- fuse_fd = fuse_mount(argv[1], NULL);
+ fuse_mountpoint = strdup(argv[1]);
+ fuse_fd = fuse_mount(fuse_mountpoint, NULL);
if(fuse_fd == -1)
exit(1);
@@ -217,7 +99,6 @@ void fuse_main(int argc, char *argv[], const struct fuse_operations *op)
strncpy(umount_cmd, tmpstr, sizeof(umount_cmd) - 1);
}
- atexit(fuse_unmount);
set_signal_handlers();
flags = 0;
@@ -252,5 +133,11 @@ void fuse_main(int argc, char *argv[], const struct fuse_operations *op)
fuse_loop_mt(fuse);
else
fuse_loop(fuse);
+
+ close(fuse_fd);
+ if(fuse_mountpoint != NULL)
+ fuse_unmount(fuse_mountpoint);
+ else if(umount_cmd[0] != '\0')
+ system(umount_cmd);
}
diff --git a/lib/mount.c b/lib/mount.c
new file mode 100644
index 0000000..1224afa
--- /dev/null
+++ b/lib/mount.c
@@ -0,0 +1,136 @@
+/*
+ FUSE: Filesystem in Userspace
+ Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
+
+ This program can be distributed under the terms of the GNU LGPL.
+ See the file COPYING.LIB.
+*/
+
+#include "fuse.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#define FUSERMOUNT_PROG "fusermount"
+#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
+
+
+/* return value:
+ * >= 0 => fd
+ * -1 => error
+ */
+static int receive_fd(int fd)
+{
+ struct msghdr msg;
+ struct iovec iov;
+ char buf[1];
+ int rv;
+ int connfd = -1;
+ char ccmsg[CMSG_SPACE(sizeof(connfd))];
+ 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) {
+ perror("recvmsg");
+ return -1;
+ }
+ if(!rv) {
+ /* EOF */
+ return -1;
+ }
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg->cmsg_type == SCM_RIGHTS) {
+ fprintf(stderr, "got control message of unknown type %d\n",
+ cmsg->cmsg_type);
+ return -1;
+ }
+ return *(int*)CMSG_DATA(cmsg);
+}
+
+void fuse_unmount(const char *mountpoint)
+{
+ const char *mountprog = FUSERMOUNT_PROG;
+ char umount_cmd[1024];
+
+ snprintf(umount_cmd, sizeof(umount_cmd) - 1, "%s -u %s", mountprog,
+ mountpoint);
+
+ umount_cmd[sizeof(umount_cmd) - 1] = '\0';
+ system(umount_cmd);
+}
+
+int fuse_mount(const char *mountpoint, const char *args[])
+{
+ const char *mountprog = FUSERMOUNT_PROG;
+ int fds[2], pid;
+ int res;
+ int rv;
+
+ res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
+ if(res == -1) {
+ perror("fuse: socketpair() failed");
+ return -1;
+ }
+
+ pid = fork();
+ if(pid == -1) {
+ perror("fuse: fork() failed");
+ close(fds[0]);
+ close(fds[1]);
+ return -1;
+ }
+
+ if(pid == 0) {
+ char env[10];
+ char **newargv;
+ int numargs = 0;
+ int actr;
+ int i;
+
+ if(args != NULL)
+ while(args[numargs] != NULL)
+ numargs ++;
+
+ newargv = (char **) malloc((1 + numargs + 2) * sizeof(char *));
+ actr = 0;
+ newargv[actr++] = strdup(mountprog);
+ for(i = 0; i < numargs; i++)
+ newargv[actr++] = strdup(args[i]);
+ newargv[actr++] = strdup(mountpoint);
+ newargv[actr++] = NULL;
+
+ close(fds[1]);
+ fcntl(fds[0], F_SETFD, 0);
+ snprintf(env, sizeof(env), "%i", fds[0]);
+ setenv(FUSE_COMMFD_ENV, env, 1);
+ execvp(mountprog, newargv);
+ perror("fuse: failed to exec fusermount");
+ exit(1);
+ }
+
+ close(fds[0]);
+ rv = receive_fd(fds[1]);
+ close(fds[1]);
+ waitpid(pid, NULL, 0); /* bury zombie */
+
+ return rv;
+}