11 #include "fuse_config.h" 
   13 #include "fuse_misc.h" 
   15 #include "mount_util.h" 
   25 #include <sys/socket.h> 
   29 #include "fuse_mount_compat.h" 
   34 #define MS_RDONLY       MNT_RDONLY 
   35 #define MS_NOSUID       MNT_NOSUID 
   36 #define MS_NODEV        MNT_NODEV 
   37 #define MS_NOEXEC       MNT_NOEXEC 
   38 #define MS_SYNCHRONOUS  MNT_SYNCHRONOUS 
   39 #define MS_NOATIME      MNT_NOATIME 
   41 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0) 
   44 #define FUSERMOUNT_PROG         "fusermount3" 
   45 #define FUSE_COMMFD_ENV         "_FUSE_COMMFD" 
   48 #define fork() vfork() 
   52 #define MS_DIRSYNC 128 
   74         char *fusermount_opts;
 
   79 #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } 
   81 static const struct fuse_opt fuse_mount_opts[] = {
 
   82         FUSE_MOUNT_OPT(
"allow_other",           allow_other),
 
   83         FUSE_MOUNT_OPT(
"blkdev",                blkdev),
 
   84         FUSE_MOUNT_OPT(
"auto_unmount",          auto_unmount),
 
   85         FUSE_MOUNT_OPT(
"fsname=%s",             fsname),
 
   86         FUSE_MOUNT_OPT(
"max_read=%u",           max_read),
 
   87         FUSE_MOUNT_OPT(
"subtype=%s",            subtype),
 
  120 static void exec_fusermount(
const char *argv[])
 
  122         execv(FUSERMOUNT_DIR 
"/" FUSERMOUNT_PROG, (
char **) argv);
 
  123         execvp(FUSERMOUNT_PROG, (
char **) argv);
 
  126 void fuse_mount_version(
void)
 
  130                 const char *argv[] = { FUSERMOUNT_PROG, 
"--version", NULL };
 
  131                 exec_fusermount(argv);
 
  133         } 
else if (pid != -1)
 
  134                 waitpid(pid, NULL, 0);
 
  143 static const struct mount_flags mount_flags[] = {
 
  144         {
"rw",      MS_RDONLY,      0},
 
  145         {
"ro",      MS_RDONLY,      1},
 
  146         {
"suid",    MS_NOSUID,      0},
 
  147         {
"nosuid",  MS_NOSUID,      1},
 
  148         {
"dev",     MS_NODEV,       0},
 
  149         {
"nodev",   MS_NODEV,       1},
 
  150         {
"exec",    MS_NOEXEC,      0},
 
  151         {
"noexec",  MS_NOEXEC,      1},
 
  152         {
"async",   MS_SYNCHRONOUS, 0},
 
  153         {
"sync",    MS_SYNCHRONOUS, 1},
 
  154         {
"noatime", MS_NOATIME,     1},
 
  155         {
"nodiratime",      MS_NODIRATIME,      1},
 
  156         {
"norelatime",      MS_RELATIME,        0},
 
  157         {
"nostrictatime",   MS_STRICTATIME,     0},
 
  159         {
"dirsync", MS_DIRSYNC,     1},
 
  164 unsigned get_max_read(
struct mount_opts *o)
 
  169 static void set_mount_flag(
const char *s, 
int *flags)
 
  173         for (i = 0; mount_flags[i].opt != NULL; i++) {
 
  174                 const char *opt = mount_flags[i].opt;
 
  175                 if (strcmp(opt, s) == 0) {
 
  176                         if (mount_flags[i].on)
 
  177                                 *flags |= mount_flags[i].flag;
 
  179                                 *flags &= ~mount_flags[i].flag;
 
  183         fuse_log(FUSE_LOG_ERR, 
"fuse: internal error, can't find mount flag\n");
 
  187 static int fuse_mount_opt_proc(
void *data, 
const char *arg, 
int key,
 
  191         struct mount_opts *mo = data;
 
  198                 set_mount_flag(arg, &mo->flags);
 
  204         case KEY_FUSERMOUNT_OPT:
 
  207         case KEY_SUBTYPE_OPT:
 
  222 static int receive_fd(
int fd)
 
  228         size_t ccmsg[CMSG_SPACE(
sizeof(
int)) / 
sizeof(size_t)];
 
  229         struct cmsghdr *cmsg;
 
  234         memset(&msg, 0, 
sizeof(msg));
 
  241         msg.msg_control = ccmsg;
 
  242         msg.msg_controllen = 
sizeof(ccmsg);
 
  244         while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
 
  254         cmsg = CMSG_FIRSTHDR(&msg);
 
  255         if (cmsg->cmsg_type != SCM_RIGHTS) {
 
  256                 fuse_log(FUSE_LOG_ERR, 
"got control message of unknown type %d\n",
 
  260         return *(
int*)CMSG_DATA(cmsg);
 
  263 void fuse_kern_unmount(
const char *mountpoint, 
int fd)
 
  273                 res = poll(&pfd, 1, 0);
 
  285                 if (res == 1 && (pfd.revents & POLLERR))
 
  289         if (geteuid() == 0) {
 
  290                 fuse_mnt_umount(
"fuse", mountpoint, mountpoint,  1);
 
  294         res = umount2(mountpoint, 2);
 
  303                 const char *argv[] = { FUSERMOUNT_PROG, 
"-u", 
"-q", 
"-z",
 
  304                                        "--", mountpoint, NULL };
 
  306                 exec_fusermount(argv);
 
  309         waitpid(pid, NULL, 0);
 
  312 static int setup_auto_unmount(
const char *mountpoint, 
int quiet)
 
  318                 fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  322         res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
 
  324                 perror(
"fuse: socketpair() failed");
 
  330                 perror(
"fuse: fork() failed");
 
  338                 const char *argv[32];
 
  342                         int fd = open(
"/dev/null", O_RDONLY);
 
  349                 argv[a++] = FUSERMOUNT_PROG;
 
  350                 argv[a++] = 
"--auto-unmount";
 
  352                 argv[a++] = mountpoint;
 
  356                 fcntl(fds[0], F_SETFD, 0);
 
  357                 snprintf(env, 
sizeof(env), 
"%i", fds[0]);
 
  358                 setenv(FUSE_COMMFD_ENV, env, 1);
 
  359                 exec_fusermount(argv);
 
  360                 perror(
"fuse: failed to exec fusermount3");
 
  371 static int fuse_mount_fusermount(
const char *mountpoint, 
struct mount_opts *mo,
 
  372                 const char *opts, 
int quiet)
 
  379                 fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  383         res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
 
  385                 perror(
"fuse: socketpair() failed");
 
  391                 perror(
"fuse: fork() failed");
 
  399                 const char *argv[32];
 
  403                         int fd = open(
"/dev/null", O_RDONLY);
 
  410                 argv[a++] = FUSERMOUNT_PROG;
 
  416                 argv[a++] = mountpoint;
 
  420                 fcntl(fds[0], F_SETFD, 0);
 
  421                 snprintf(env, 
sizeof(env), 
"%i", fds[0]);
 
  422                 setenv(FUSE_COMMFD_ENV, env, 1);
 
  423                 exec_fusermount(argv);
 
  424                 perror(
"fuse: failed to exec fusermount3");
 
  429         rv = receive_fd(fds[1]);
 
  431         if (!mo->auto_unmount) {
 
  435                 waitpid(pid, NULL, 0); 
 
  439                 fcntl(rv, F_SETFD, FD_CLOEXEC);
 
  448 static int fuse_mount_sys(
const char *mnt, 
struct mount_opts *mo,
 
  449                           const char *mnt_opts)
 
  452         const char *devname = 
"/dev/fuse";
 
  460                 fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  464         res = stat(mnt, &stbuf);
 
  466                 fuse_log(FUSE_LOG_ERR, 
"fuse: failed to access mountpoint %s: %s\n",
 
  467                         mnt, strerror(errno));
 
  471         fd = open(devname, O_RDWR | O_CLOEXEC);
 
  473                 if (errno == ENODEV || errno == ENOENT)
 
  474                         fuse_log(FUSE_LOG_ERR, 
"fuse: device not found, try 'modprobe fuse' first\n");
 
  476                         fuse_log(FUSE_LOG_ERR, 
"fuse: failed to open %s: %s\n",
 
  477                                 devname, strerror(errno));
 
  481                 fcntl(fd, F_SETFD, FD_CLOEXEC);
 
  483         snprintf(tmp, 
sizeof(tmp),  
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
 
  484                  fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
 
  490         source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
 
  491                         (mo->subtype ? strlen(mo->subtype) : 0) +
 
  492                         strlen(devname) + 32);
 
  494         type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
 
  495         if (!type || !source) {
 
  496                 fuse_log(FUSE_LOG_ERR, 
"fuse: failed to allocate memory\n");
 
  500         strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
 
  503                 strcat(type, mo->subtype);
 
  506                mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
 
  508         res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
 
  509         if (res == -1 && errno == ENODEV && mo->subtype) {
 
  511                 strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
 
  514                                 sprintf(source, 
"%s#%s", mo->subtype,
 
  517                         strcpy(source, type);
 
  519                 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
 
  526                 if (errno == EPERM) {
 
  529                         int errno_save = errno;
 
  530                         if (mo->blkdev && errno == ENODEV &&
 
  531                             !fuse_mnt_check_fuseblk())
 
  533                                         "fuse: 'fuseblk' support missing\n");
 
  535                                 fuse_log(FUSE_LOG_ERR, 
"fuse: mount failed: %s\n",
 
  536                                         strerror(errno_save));
 
  543         if (geteuid() == 0) {
 
  544                 char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
 
  549                 res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
 
  570 static int get_mnt_flag_opts(
char **mnt_optsp, 
int flags)
 
  577         for (i = 0; mount_flags[i].opt != NULL; i++) {
 
  578                 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
 
  585 struct mount_opts *parse_mount_opts(
struct fuse_args *args)
 
  587         struct mount_opts *mo;
 
  589         mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
 
  593         memset(mo, 0, 
sizeof(
struct mount_opts));
 
  594         mo->flags = MS_NOSUID | MS_NODEV;
 
  597             fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
 
  603         destroy_mount_opts(mo);
 
  607 void destroy_mount_opts(
struct mount_opts *mo)
 
  611         free(mo->fusermount_opts);
 
  612         free(mo->subtype_opt);
 
  613         free(mo->kernel_opts);
 
  619 int fuse_kern_mount(
const char *mountpoint, 
struct mount_opts *mo)
 
  622         char *mnt_opts = NULL;
 
  625         if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
 
  632         res = fuse_mount_sys(mountpoint, mo, mnt_opts);
 
  633         if (res >= 0 && mo->auto_unmount) {
 
  634                 if(0 > setup_auto_unmount(mountpoint, 0)) {
 
  636                         umount2(mountpoint, MNT_DETACH); 
 
  639         } 
else if (res == -2) {
 
  640                 if (mo->fusermount_opts &&
 
  645                         char *tmp_opts = NULL;
 
  654                         res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
 
  657                                 res = fuse_mount_fusermount(mountpoint, mo,
 
  660                         res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
 
void fuse_log(enum fuse_log_level level, const char *fmt,...)
#define FUSE_OPT_KEY(templ, key)
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
int fuse_opt_add_opt(char **opts, const char *opt)