2001-11-21 18:03:39 +08:00
|
|
|
/*
|
|
|
|
FUSE: Filesystem in Userspace
|
|
|
|
Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
|
|
|
|
|
|
|
|
This program can be distributed under the terms of the GNU GPL.
|
|
|
|
See the file COPYING.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "fuse.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <errno.h>
|
2002-04-18 22:41:48 +08:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/wait.h>
|
2001-11-21 18:03:39 +08:00
|
|
|
|
2002-10-25 19:40:14 +08:00
|
|
|
#define FUSE_MOUNTED_ENV "_FUSE_MOUNTED"
|
|
|
|
#define FUSE_UMOUNT_CMD_ENV "_FUSE_UNMOUNT_CMD"
|
|
|
|
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
|
|
|
|
|
|
|
|
#define FUSERMOUNT_PROG "fusermount"
|
2001-11-21 18:03:39 +08:00
|
|
|
|
|
|
|
static void usage(char *progname)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"usage: %s mountpoint [options] \n"
|
|
|
|
"Options:\n"
|
|
|
|
" -d enable debug output\n"
|
|
|
|
" -s disable multithreaded operation\n"
|
|
|
|
" -h print help\n",
|
|
|
|
progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2002-10-25 19:40:14 +08:00
|
|
|
static char umount_cmd[1024];
|
|
|
|
static int fuse_fd;
|
2001-11-21 18:03:39 +08:00
|
|
|
|
2002-10-25 19:40:14 +08:00
|
|
|
static void fuse_unmount()
|
2001-11-21 18:03:39 +08:00
|
|
|
{
|
2002-10-25 19:40:14 +08:00
|
|
|
close(fuse_fd);
|
|
|
|
if(umount_cmd[0] != '\0')
|
|
|
|
system(umount_cmd);
|
2001-11-21 18:03:39 +08:00
|
|
|
}
|
|
|
|
|
2002-06-26 21:47:21 +08:00
|
|
|
/* return value:
|
|
|
|
* >= 0 => fd
|
|
|
|
* -1 => error
|
|
|
|
*/
|
2002-10-25 19:40:14 +08:00
|
|
|
static int receive_fd(int fd)
|
|
|
|
{
|
2002-04-18 22:41:48 +08:00
|
|
|
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);
|
|
|
|
|
2002-06-26 21:47:21 +08:00
|
|
|
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
|
2002-04-18 22:41:48 +08:00
|
|
|
if (rv == -1) {
|
|
|
|
perror("recvmsg");
|
|
|
|
return -1;
|
|
|
|
}
|
2002-06-26 21:47:21 +08:00
|
|
|
if(!rv) {
|
|
|
|
/* EOF */
|
|
|
|
fprintf(stderr, "got EOF\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2002-04-18 22:41:48 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2002-10-25 19:40:14 +08:00
|
|
|
int fuse_mount(const char *mountpoint, const char *args[])
|
2002-04-19 23:57:02 +08:00
|
|
|
{
|
2002-10-25 19:40:14 +08:00
|
|
|
const char *mountprog = FUSERMOUNT_PROG;
|
2002-04-18 22:41:48 +08:00
|
|
|
int fds[2], pid;
|
2002-10-25 19:40:14 +08:00
|
|
|
int res;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
snprintf(umount_cmd, sizeof(umount_cmd) - 1, "%s -u %s", mountprog,
|
|
|
|
mountpoint);
|
2002-04-19 23:57:02 +08:00
|
|
|
|
2002-10-25 19:40:14 +08:00
|
|
|
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
|
|
|
|
if(res == -1) {
|
|
|
|
perror("fuse: socketpair() failed");
|
2002-04-18 22:41:48 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2002-10-25 19:40:14 +08:00
|
|
|
|
2002-04-18 22:41:48 +08:00
|
|
|
pid = fork();
|
2002-10-25 19:40:14 +08:00
|
|
|
if(pid == -1) {
|
|
|
|
perror("fuse: fork() failed");
|
2002-04-18 22:41:48 +08:00
|
|
|
close(fds[0]);
|
|
|
|
close(fds[1]);
|
|
|
|
return -1;
|
|
|
|
}
|
2002-10-25 19:40:14 +08:00
|
|
|
|
2002-04-19 23:57:02 +08:00
|
|
|
if(pid == 0) {
|
2002-10-25 19:40:14 +08:00
|
|
|
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;
|
|
|
|
|
2002-04-19 23:57:02 +08:00
|
|
|
close(fds[1]);
|
2002-10-25 19:40:14 +08:00
|
|
|
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");
|
2002-04-19 23:57:02 +08:00
|
|
|
exit(1);
|
2002-04-18 22:41:48 +08:00
|
|
|
}
|
2002-04-19 23:57:02 +08:00
|
|
|
|
|
|
|
close(fds[0]);
|
2002-10-25 19:40:14 +08:00
|
|
|
rv = receive_fd(fds[1]);
|
|
|
|
close(fds[1]);
|
|
|
|
waitpid(pid, NULL, 0); /* bury zombie */
|
|
|
|
|
2002-04-19 23:57:02 +08:00
|
|
|
return rv;
|
2002-04-18 22:41:48 +08:00
|
|
|
}
|
2001-11-21 18:03:39 +08:00
|
|
|
|
|
|
|
static void exit_handler()
|
|
|
|
{
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_signal_handlers()
|
|
|
|
{
|
|
|
|
struct sigaction sa;
|
|
|
|
|
|
|
|
sa.sa_handler = exit_handler;
|
|
|
|
sigemptyset(&(sa.sa_mask));
|
|
|
|
sa.sa_flags = 0;
|
|
|
|
|
|
|
|
if (sigaction(SIGHUP, &sa, NULL) == -1 ||
|
|
|
|
sigaction(SIGINT, &sa, NULL) == -1 ||
|
|
|
|
sigaction(SIGTERM, &sa, NULL) == -1) {
|
|
|
|
|
|
|
|
perror("Cannot set exit signal handlers");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
sa.sa_handler = SIG_IGN;
|
|
|
|
|
|
|
|
if(sigaction(SIGPIPE, &sa, NULL) == -1) {
|
|
|
|
perror("Cannot set ignored signals");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void fuse_main(int argc, char *argv[], const struct fuse_operations *op)
|
|
|
|
{
|
2002-10-25 19:40:14 +08:00
|
|
|
int argctr = 1;
|
2001-11-21 18:03:39 +08:00
|
|
|
int flags;
|
|
|
|
int multithreaded;
|
|
|
|
struct fuse *fuse;
|
2002-10-25 19:40:14 +08:00
|
|
|
char *isreexec = getenv(FUSE_MOUNTED_ENV);
|
2001-11-21 18:03:39 +08:00
|
|
|
|
2002-10-25 19:40:14 +08:00
|
|
|
if(isreexec == NULL) {
|
|
|
|
if(argc < 2 || argv[1][0] == '-')
|
|
|
|
usage(argv[0]);
|
|
|
|
|
|
|
|
fuse_fd = fuse_mount(argv[1], NULL);
|
|
|
|
if(fuse_fd == -1)
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
argctr++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
char *tmpstr;
|
|
|
|
|
|
|
|
/* Old (obsolescent) way of doing the mount:
|
|
|
|
|
|
|
|
fusermount [options] mountpoint [program [args ...]]
|
|
|
|
|
|
|
|
fusermount execs this program and passes the control file
|
|
|
|
descriptor dup()-ed to stdin */
|
|
|
|
fuse_fd = 0;
|
|
|
|
|
|
|
|
tmpstr = getenv(FUSE_UMOUNT_CMD_ENV);
|
|
|
|
if(tmpstr != NULL)
|
|
|
|
strncpy(umount_cmd, tmpstr, sizeof(umount_cmd) - 1);
|
|
|
|
}
|
2001-11-21 18:03:39 +08:00
|
|
|
|
|
|
|
atexit(fuse_unmount);
|
|
|
|
set_signal_handlers();
|
|
|
|
|
|
|
|
flags = 0;
|
|
|
|
multithreaded = 1;
|
|
|
|
for(; argctr < argc && argv[argctr][0] == '-'; argctr ++) {
|
|
|
|
switch(argv[argctr][1]) {
|
|
|
|
case 'd':
|
|
|
|
flags |= FUSE_DEBUG;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 's':
|
|
|
|
multithreaded = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
usage(argv[0]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "invalid option: %s\n", argv[argctr]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(argctr != argc) {
|
|
|
|
fprintf(stderr, "missing or surplus argument\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2002-10-25 19:40:14 +08:00
|
|
|
fuse = fuse_new(fuse_fd, flags, op);
|
2001-11-21 18:03:39 +08:00
|
|
|
|
|
|
|
if(multithreaded)
|
|
|
|
fuse_loop_mt(fuse);
|
|
|
|
else
|
|
|
|
fuse_loop(fuse);
|
|
|
|
}
|
|
|
|
|