13 #include "fuse_misc.h" 
   15 #include "mount_util.h" 
   25 #include <sys/socket.h> 
   28 #include <sys/mount.h> 
   33 #define MS_RDONLY       MNT_RDONLY 
   34 #define MS_NOSUID       MNT_NOSUID 
   35 #define MS_NODEV        MNT_NODEV 
   36 #define MS_NOEXEC       MNT_NOEXEC 
   37 #define MS_SYNCHRONOUS  MNT_SYNCHRONOUS 
   38 #define MS_NOATIME      MNT_NOATIME 
   40 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0) 
   43 #define FUSERMOUNT_PROG         "fusermount3" 
   44 #define FUSE_COMMFD_ENV         "_FUSE_COMMFD" 
   47 #define fork() vfork() 
   51 #define MS_DIRSYNC 128 
   73         char *fusermount_opts;
 
   78 #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } 
   80 static const struct fuse_opt fuse_mount_opts[] = {
 
   81         FUSE_MOUNT_OPT(
"allow_other",           allow_other),
 
   82         FUSE_MOUNT_OPT(
"blkdev",                blkdev),
 
   83         FUSE_MOUNT_OPT(
"auto_unmount",          auto_unmount),
 
   84         FUSE_MOUNT_OPT(
"fsname=%s",             fsname),
 
   85         FUSE_MOUNT_OPT(
"max_read=%u",           max_read),
 
   86         FUSE_MOUNT_OPT(
"subtype=%s",            subtype),
 
  117 static void exec_fusermount(
const char *argv[])
 
  119         execv(FUSERMOUNT_DIR 
"/" FUSERMOUNT_PROG, (
char **) argv);
 
  120         execvp(FUSERMOUNT_PROG, (
char **) argv);
 
  123 void fuse_mount_version(
void)
 
  127                 const char *argv[] = { FUSERMOUNT_PROG, 
"--version", NULL };
 
  128                 exec_fusermount(argv);
 
  130         } 
else if (pid != -1)
 
  131                 waitpid(pid, NULL, 0);
 
  140 static const struct mount_flags mount_flags[] = {
 
  141         {
"rw",      MS_RDONLY,      0},
 
  142         {
"ro",      MS_RDONLY,      1},
 
  143         {
"suid",    MS_NOSUID,      0},
 
  144         {
"nosuid",  MS_NOSUID,      1},
 
  145         {
"dev",     MS_NODEV,       0},
 
  146         {
"nodev",   MS_NODEV,       1},
 
  147         {
"exec",    MS_NOEXEC,      0},
 
  148         {
"noexec",  MS_NOEXEC,      1},
 
  149         {
"async",   MS_SYNCHRONOUS, 0},
 
  150         {
"sync",    MS_SYNCHRONOUS, 1},
 
  151         {
"atime",   MS_NOATIME,     0},
 
  152         {
"noatime", MS_NOATIME,     1},
 
  154         {
"dirsync", MS_DIRSYNC,     1},
 
  159 unsigned get_max_read(
struct mount_opts *o)
 
  164 static void set_mount_flag(
const char *s, 
int *flags)
 
  168         for (i = 0; mount_flags[i].opt != NULL; i++) {
 
  169                 const char *opt = mount_flags[i].opt;
 
  170                 if (strcmp(opt, s) == 0) {
 
  171                         if (mount_flags[i].on)
 
  172                                 *flags |= mount_flags[i].flag;
 
  174                                 *flags &= ~mount_flags[i].flag;
 
  178         fuse_log(FUSE_LOG_ERR, 
"fuse: internal error, can't find mount flag\n");
 
  182 static int fuse_mount_opt_proc(
void *data, 
const char *arg, 
int key,
 
  186         struct mount_opts *mo = data;
 
  193                 set_mount_flag(arg, &mo->flags);
 
  199         case KEY_FUSERMOUNT_OPT:
 
  202         case KEY_SUBTYPE_OPT:
 
  217 static int receive_fd(
int fd)
 
  223         size_t ccmsg[CMSG_SPACE(
sizeof(
int)) / 
sizeof(size_t)];
 
  224         struct cmsghdr *cmsg;
 
  229         memset(&msg, 0, 
sizeof(msg));
 
  236         msg.msg_control = ccmsg;
 
  237         msg.msg_controllen = 
sizeof(ccmsg);
 
  239         while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
 
  249         cmsg = CMSG_FIRSTHDR(&msg);
 
  250         if (cmsg->cmsg_type != SCM_RIGHTS) {
 
  251                 fuse_log(FUSE_LOG_ERR, 
"got control message of unknown type %d\n",
 
  255         return *(
int*)CMSG_DATA(cmsg);
 
  258 void fuse_kern_unmount(
const char *mountpoint, 
int fd)
 
  268                 res = poll(&pfd, 1, 0);
 
  280                 if (res == 1 && (pfd.revents & POLLERR))
 
  284         if (geteuid() == 0) {
 
  285                 fuse_mnt_umount(
"fuse", mountpoint, mountpoint,  1);
 
  289         res = umount2(mountpoint, 2);
 
  298                 const char *argv[] = { FUSERMOUNT_PROG, 
"-u", 
"-q", 
"-z",
 
  299                                        "--", mountpoint, NULL };
 
  301                 exec_fusermount(argv);
 
  304         waitpid(pid, NULL, 0);
 
  307 static int fuse_mount_fusermount(
const char *mountpoint, 
struct mount_opts *mo,
 
  308                 const char *opts, 
int quiet)
 
  315                 fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  319         res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
 
  321                 perror(
"fuse: socketpair() failed");
 
  327                 perror(
"fuse: fork() failed");
 
  335                 const char *argv[32];
 
  339                         int fd = open(
"/dev/null", O_RDONLY);
 
  346                 argv[a++] = FUSERMOUNT_PROG;
 
  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");
 
  365         rv = receive_fd(fds[1]);
 
  367         if (!mo->auto_unmount) {
 
  371                 waitpid(pid, NULL, 0); 
 
  375                 fcntl(rv, F_SETFD, FD_CLOEXEC);
 
  384 static int fuse_mount_sys(
const char *mnt, 
struct mount_opts *mo,
 
  385                           const char *mnt_opts)
 
  388         const char *devname = 
"/dev/fuse";
 
  396                 fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  400         res = stat(mnt, &stbuf);
 
  402                 fuse_log(FUSE_LOG_ERR, 
"fuse: failed to access mountpoint %s: %s\n",
 
  403                         mnt, strerror(errno));
 
  407         if (mo->auto_unmount) {
 
  413         fd = open(devname, O_RDWR | O_CLOEXEC);
 
  415                 if (errno == ENODEV || errno == ENOENT)
 
  416                         fuse_log(FUSE_LOG_ERR, 
"fuse: device not found, try 'modprobe fuse' first\n");
 
  418                         fuse_log(FUSE_LOG_ERR, 
"fuse: failed to open %s: %s\n",
 
  419                                 devname, strerror(errno));
 
  423                 fcntl(fd, F_SETFD, FD_CLOEXEC);
 
  425         snprintf(tmp, 
sizeof(tmp),  
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
 
  426                  fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
 
  432         source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
 
  433                         (mo->subtype ? strlen(mo->subtype) : 0) +
 
  434                         strlen(devname) + 32);
 
  436         type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
 
  437         if (!type || !source) {
 
  438                 fuse_log(FUSE_LOG_ERR, 
"fuse: failed to allocate memory\n");
 
  442         strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
 
  445                 strcat(type, mo->subtype);
 
  448                mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
 
  450         res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
 
  451         if (res == -1 && errno == ENODEV && mo->subtype) {
 
  453                 strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
 
  456                                 sprintf(source, 
"%s#%s", mo->subtype,
 
  459                         strcpy(source, type);
 
  461                 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
 
  468                 if (errno == EPERM) {
 
  471                         int errno_save = errno;
 
  472                         if (mo->blkdev && errno == ENODEV &&
 
  473                             !fuse_mnt_check_fuseblk())
 
  475                                         "fuse: 'fuseblk' support missing\n");
 
  477                                 fuse_log(FUSE_LOG_ERR, 
"fuse: mount failed: %s\n",
 
  478                                         strerror(errno_save));
 
  485         if (geteuid() == 0) {
 
  486                 char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
 
  491                 res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
 
  512 static int get_mnt_flag_opts(
char **mnt_optsp, 
int flags)
 
  519         for (i = 0; mount_flags[i].opt != NULL; i++) {
 
  520                 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
 
  527 struct mount_opts *parse_mount_opts(
struct fuse_args *args)
 
  529         struct mount_opts *mo;
 
  531         mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
 
  535         memset(mo, 0, 
sizeof(
struct mount_opts));
 
  536         mo->flags = MS_NOSUID | MS_NODEV;
 
  539             fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
 
  545         destroy_mount_opts(mo);
 
  549 void destroy_mount_opts(
struct mount_opts *mo)
 
  553         free(mo->fusermount_opts);
 
  554         free(mo->subtype_opt);
 
  555         free(mo->kernel_opts);
 
  561 int fuse_kern_mount(
const char *mountpoint, 
struct mount_opts *mo)
 
  564         char *mnt_opts = NULL;
 
  567         if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
 
  574         res = fuse_mount_sys(mountpoint, mo, mnt_opts);
 
  576                 if (mo->fusermount_opts &&
 
  581                         char *tmp_opts = NULL;
 
  590                         res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
 
  593                                 res = fuse_mount_fusermount(mountpoint, mo,
 
  596                         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)