"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.2.1/lib/mount.c" (14 Nov 2017, 13342 Bytes) of package /linux/misc/fuse-3.2.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mount.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.1.0_vs_3.1.1.

    1 /*
    2   FUSE: Filesystem in Userspace
    3   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
    4 
    5   Architecture specific file system mounting (Linux).
    6 
    7   This program can be distributed under the terms of the GNU LGPLv2.
    8   See the file COPYING.LIB.
    9 */
   10 
   11 #include "config.h"
   12 #include "fuse_i.h"
   13 #include "fuse_misc.h"
   14 #include "fuse_opt.h"
   15 #include "mount_util.h"
   16 
   17 #include <stdio.h>
   18 #include <stdlib.h>
   19 #include <unistd.h>
   20 #include <stddef.h>
   21 #include <string.h>
   22 #include <fcntl.h>
   23 #include <errno.h>
   24 #include <poll.h>
   25 #include <sys/socket.h>
   26 #include <sys/un.h>
   27 #include <sys/wait.h>
   28 #include <sys/mount.h>
   29 
   30 #ifdef __NetBSD__
   31 #include <perfuse.h>
   32 
   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
   39 
   40 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
   41 #endif
   42 
   43 #define FUSERMOUNT_PROG     "fusermount3"
   44 #define FUSE_COMMFD_ENV     "_FUSE_COMMFD"
   45 
   46 #ifndef HAVE_FORK
   47 #define fork() vfork()
   48 #endif
   49 
   50 #ifndef MS_DIRSYNC
   51 #define MS_DIRSYNC 128
   52 #endif
   53 
   54 enum {
   55     KEY_KERN_FLAG,
   56     KEY_KERN_OPT,
   57     KEY_FUSERMOUNT_OPT,
   58     KEY_SUBTYPE_OPT,
   59     KEY_MTAB_OPT,
   60     KEY_ALLOW_OTHER,
   61     KEY_RO,
   62 };
   63 
   64 struct mount_opts {
   65     int allow_other;
   66     int flags;
   67     int auto_unmount;
   68     int blkdev;
   69     char *fsname;
   70     char *subtype;
   71     char *subtype_opt;
   72     char *mtab_opts;
   73     char *fusermount_opts;
   74     char *kernel_opts;
   75     unsigned max_read;
   76 };
   77 
   78 #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
   79 
   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),
   87     FUSE_OPT_KEY("allow_other",     KEY_KERN_OPT),
   88     FUSE_OPT_KEY("auto_unmount",        KEY_FUSERMOUNT_OPT),
   89     FUSE_OPT_KEY("blkdev",          KEY_FUSERMOUNT_OPT),
   90     FUSE_OPT_KEY("fsname=",         KEY_FUSERMOUNT_OPT),
   91     FUSE_OPT_KEY("subtype=",        KEY_SUBTYPE_OPT),
   92     FUSE_OPT_KEY("blksize=",        KEY_KERN_OPT),
   93     FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
   94     FUSE_OPT_KEY("context=",        KEY_KERN_OPT),
   95     FUSE_OPT_KEY("fscontext=",      KEY_KERN_OPT),
   96     FUSE_OPT_KEY("defcontext=",     KEY_KERN_OPT),
   97     FUSE_OPT_KEY("rootcontext=",        KEY_KERN_OPT),
   98     FUSE_OPT_KEY("max_read=",       KEY_KERN_OPT),
   99     FUSE_OPT_KEY("user=",           KEY_MTAB_OPT),
  100     FUSE_OPT_KEY("-r",          KEY_RO),
  101     FUSE_OPT_KEY("ro",          KEY_KERN_FLAG),
  102     FUSE_OPT_KEY("rw",          KEY_KERN_FLAG),
  103     FUSE_OPT_KEY("suid",            KEY_KERN_FLAG),
  104     FUSE_OPT_KEY("nosuid",          KEY_KERN_FLAG),
  105     FUSE_OPT_KEY("dev",         KEY_KERN_FLAG),
  106     FUSE_OPT_KEY("nodev",           KEY_KERN_FLAG),
  107     FUSE_OPT_KEY("exec",            KEY_KERN_FLAG),
  108     FUSE_OPT_KEY("noexec",          KEY_KERN_FLAG),
  109     FUSE_OPT_KEY("async",           KEY_KERN_FLAG),
  110     FUSE_OPT_KEY("sync",            KEY_KERN_FLAG),
  111     FUSE_OPT_KEY("dirsync",         KEY_KERN_FLAG),
  112     FUSE_OPT_KEY("atime",           KEY_KERN_FLAG),
  113     FUSE_OPT_KEY("noatime",         KEY_KERN_FLAG),
  114     FUSE_OPT_END
  115 };
  116 
  117 static void exec_fusermount(const char *argv[])
  118 {
  119     execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
  120     execvp(FUSERMOUNT_PROG, (char **) argv);
  121 }
  122 
  123 void fuse_mount_version(void)
  124 {
  125     int pid = fork();
  126     if (!pid) {
  127         const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
  128         exec_fusermount(argv);
  129         _exit(1);
  130     } else if (pid != -1)
  131         waitpid(pid, NULL, 0);
  132 }
  133 
  134 struct mount_flags {
  135     const char *opt;
  136     unsigned long flag;
  137     int on;
  138 };
  139 
  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},
  153 #ifndef __NetBSD__
  154     {"dirsync", MS_DIRSYNC,     1},
  155 #endif
  156     {NULL,      0,          0}
  157 };
  158 
  159 unsigned get_max_read(struct mount_opts *o)
  160 {
  161     return o->max_read;
  162 }
  163 
  164 static void set_mount_flag(const char *s, int *flags)
  165 {
  166     int i;
  167 
  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;
  173             else
  174                 *flags &= ~mount_flags[i].flag;
  175             return;
  176         }
  177     }
  178     fprintf(stderr, "fuse: internal error, can't find mount flag\n");
  179     abort();
  180 }
  181 
  182 static int fuse_mount_opt_proc(void *data, const char *arg, int key,
  183                    struct fuse_args *outargs)
  184 {
  185     (void) outargs;
  186     struct mount_opts *mo = data;
  187 
  188     switch (key) {
  189     case KEY_RO:
  190         arg = "ro";
  191         /* fall through */
  192     case KEY_KERN_FLAG:
  193         set_mount_flag(arg, &mo->flags);
  194         return 0;
  195 
  196     case KEY_KERN_OPT:
  197         return fuse_opt_add_opt(&mo->kernel_opts, arg);
  198 
  199     case KEY_FUSERMOUNT_OPT:
  200         return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg);
  201 
  202     case KEY_SUBTYPE_OPT:
  203         return fuse_opt_add_opt(&mo->subtype_opt, arg);
  204 
  205     case KEY_MTAB_OPT:
  206         return fuse_opt_add_opt(&mo->mtab_opts, arg);
  207     }
  208 
  209     /* Pass through unknown options */
  210     return 1;
  211 }
  212 
  213 /* return value:
  214  * >= 0  => fd
  215  * -1    => error
  216  */
  217 static int receive_fd(int fd)
  218 {
  219     struct msghdr msg;
  220     struct iovec iov;
  221     char buf[1];
  222     int rv;
  223     size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
  224     struct cmsghdr *cmsg;
  225 
  226     iov.iov_base = buf;
  227     iov.iov_len = 1;
  228 
  229     memset(&msg, 0, sizeof(msg));
  230     msg.msg_name = 0;
  231     msg.msg_namelen = 0;
  232     msg.msg_iov = &iov;
  233     msg.msg_iovlen = 1;
  234     /* old BSD implementations should use msg_accrights instead of
  235      * msg_control; the interface is different. */
  236     msg.msg_control = ccmsg;
  237     msg.msg_controllen = sizeof(ccmsg);
  238 
  239     while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
  240     if (rv == -1) {
  241         perror("recvmsg");
  242         return -1;
  243     }
  244     if(!rv) {
  245         /* EOF */
  246         return -1;
  247     }
  248 
  249     cmsg = CMSG_FIRSTHDR(&msg);
  250     if (cmsg->cmsg_type != SCM_RIGHTS) {
  251         fprintf(stderr, "got control message of unknown type %d\n",
  252             cmsg->cmsg_type);
  253         return -1;
  254     }
  255     return *(int*)CMSG_DATA(cmsg);
  256 }
  257 
  258 void fuse_kern_unmount(const char *mountpoint, int fd)
  259 {
  260     int res;
  261     int pid;
  262 
  263     if (fd != -1) {
  264         struct pollfd pfd;
  265 
  266         pfd.fd = fd;
  267         pfd.events = 0;
  268         res = poll(&pfd, 1, 0);
  269 
  270         /* Need to close file descriptor, otherwise synchronous umount
  271            would recurse into filesystem, and deadlock.
  272 
  273            Caller expects fuse_kern_unmount to close the fd, so close it
  274            anyway. */
  275         close(fd);
  276 
  277         /* If file poll returns POLLERR on the device file descriptor,
  278            then the filesystem is already unmounted or the connection
  279            was severed via /sys/fs/fuse/connections/NNN/abort */
  280         if (res == 1 && (pfd.revents & POLLERR))
  281             return;
  282     }
  283 
  284     if (geteuid() == 0) {
  285         fuse_mnt_umount("fuse", mountpoint, mountpoint,  1);
  286         return;
  287     }
  288 
  289     res = umount2(mountpoint, 2);
  290     if (res == 0)
  291         return;
  292 
  293     pid = fork();
  294     if(pid == -1)
  295         return;
  296 
  297     if(pid == 0) {
  298         const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z",
  299                        "--", mountpoint, NULL };
  300 
  301         exec_fusermount(argv);
  302         _exit(1);
  303     }
  304     waitpid(pid, NULL, 0);
  305 }
  306 
  307 static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
  308         const char *opts, int quiet)
  309 {
  310     int fds[2], pid;
  311     int res;
  312     int rv;
  313 
  314     if (!mountpoint) {
  315         fprintf(stderr, "fuse: missing mountpoint parameter\n");
  316         return -1;
  317     }
  318 
  319     res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
  320     if(res == -1) {
  321         perror("fuse: socketpair() failed");
  322         return -1;
  323     }
  324 
  325     pid = fork();
  326     if(pid == -1) {
  327         perror("fuse: fork() failed");
  328         close(fds[0]);
  329         close(fds[1]);
  330         return -1;
  331     }
  332 
  333     if(pid == 0) {
  334         char env[10];
  335         const char *argv[32];
  336         int a = 0;
  337 
  338         if (quiet) {
  339             int fd = open("/dev/null", O_RDONLY);
  340             if (fd != -1) {
  341                 dup2(fd, 1);
  342                 dup2(fd, 2);
  343             }
  344         }
  345 
  346         argv[a++] = FUSERMOUNT_PROG;
  347         if (opts) {
  348             argv[a++] = "-o";
  349             argv[a++] = opts;
  350         }
  351         argv[a++] = "--";
  352         argv[a++] = mountpoint;
  353         argv[a++] = NULL;
  354 
  355         close(fds[1]);
  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");
  361         _exit(1);
  362     }
  363 
  364     close(fds[0]);
  365     rv = receive_fd(fds[1]);
  366 
  367     if (!mo->auto_unmount) {
  368         /* with auto_unmount option fusermount3 will not exit until
  369            this socket is closed */
  370         close(fds[1]);
  371         waitpid(pid, NULL, 0); /* bury zombie */
  372     }
  373 
  374     if (rv >= 0)
  375         fcntl(rv, F_SETFD, FD_CLOEXEC);
  376 
  377     return rv;
  378 }
  379 
  380 #ifndef O_CLOEXEC
  381 #define O_CLOEXEC 0
  382 #endif
  383 
  384 static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
  385               const char *mnt_opts)
  386 {
  387     char tmp[128];
  388     const char *devname = "/dev/fuse";
  389     char *source = NULL;
  390     char *type = NULL;
  391     struct stat stbuf;
  392     int fd;
  393     int res;
  394 
  395     if (!mnt) {
  396         fprintf(stderr, "fuse: missing mountpoint parameter\n");
  397         return -1;
  398     }
  399 
  400     res = stat(mnt, &stbuf);
  401     if (res == -1) {
  402         fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
  403             mnt, strerror(errno));
  404         return -1;
  405     }
  406 
  407     if (mo->auto_unmount) {
  408         /* Tell the caller to fallback to fusermount3 because
  409            auto-unmount does not work otherwise. */
  410         return -2;
  411     }
  412 
  413     fd = open(devname, O_RDWR | O_CLOEXEC);
  414     if (fd == -1) {
  415         if (errno == ENODEV || errno == ENOENT)
  416             fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n");
  417         else
  418             fprintf(stderr, "fuse: failed to open %s: %s\n",
  419                 devname, strerror(errno));
  420         return -1;
  421     }
  422     if (!O_CLOEXEC)
  423         fcntl(fd, F_SETFD, FD_CLOEXEC);
  424 
  425     snprintf(tmp, sizeof(tmp),  "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
  426          fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
  427 
  428     res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
  429     if (res == -1)
  430         goto out_close;
  431 
  432     source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
  433             (mo->subtype ? strlen(mo->subtype) : 0) +
  434             strlen(devname) + 32);
  435 
  436     type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
  437     if (!type || !source) {
  438         fprintf(stderr, "fuse: failed to allocate memory\n");
  439         goto out_close;
  440     }
  441 
  442     strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
  443     if (mo->subtype) {
  444         strcat(type, ".");
  445         strcat(type, mo->subtype);
  446     }
  447     strcpy(source,
  448            mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
  449 
  450     res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
  451     if (res == -1 && errno == ENODEV && mo->subtype) {
  452         /* Probably missing subtype support */
  453         strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
  454         if (mo->fsname) {
  455             if (!mo->blkdev)
  456                 sprintf(source, "%s#%s", mo->subtype,
  457                     mo->fsname);
  458         } else {
  459             strcpy(source, type);
  460         }
  461         res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
  462     }
  463     if (res == -1) {
  464         /*
  465          * Maybe kernel doesn't support unprivileged mounts, in this
  466          * case try falling back to fusermount3
  467          */
  468         if (errno == EPERM) {
  469             res = -2;
  470         } else {
  471             int errno_save = errno;
  472             if (mo->blkdev && errno == ENODEV &&
  473                 !fuse_mnt_check_fuseblk())
  474                 fprintf(stderr,
  475                     "fuse: 'fuseblk' support missing\n");
  476             else
  477                 fprintf(stderr, "fuse: mount failed: %s\n",
  478                     strerror(errno_save));
  479         }
  480 
  481         goto out_close;
  482     }
  483 
  484 #ifndef IGNORE_MTAB
  485     if (geteuid() == 0) {
  486         char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
  487         res = -1;
  488         if (!newmnt)
  489             goto out_umount;
  490 
  491         res = fuse_mnt_add_mount("fuse", source, newmnt, type,
  492                      mnt_opts);
  493         free(newmnt);
  494         if (res == -1)
  495             goto out_umount;
  496     }
  497 #endif /* IGNORE_MTAB */
  498     free(type);
  499     free(source);
  500 
  501     return fd;
  502 
  503 out_umount:
  504     umount2(mnt, 2); /* lazy umount */
  505 out_close:
  506     free(type);
  507     free(source);
  508     close(fd);
  509     return res;
  510 }
  511 
  512 static int get_mnt_flag_opts(char **mnt_optsp, int flags)
  513 {
  514     int i;
  515 
  516     if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
  517         return -1;
  518 
  519     for (i = 0; mount_flags[i].opt != NULL; i++) {
  520         if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
  521             fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
  522             return -1;
  523     }
  524     return 0;
  525 }
  526 
  527 struct mount_opts *parse_mount_opts(struct fuse_args *args)
  528 {
  529     struct mount_opts *mo;
  530 
  531     mo = (struct mount_opts*) malloc(sizeof(struct mount_opts));
  532     if (mo == NULL)
  533         return NULL;
  534 
  535     memset(mo, 0, sizeof(struct mount_opts));
  536     mo->flags = MS_NOSUID | MS_NODEV;
  537 
  538     if (args &&
  539         fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
  540         goto err_out;
  541 
  542     return mo;
  543 
  544 err_out:
  545     destroy_mount_opts(mo);
  546     return NULL;
  547 }
  548 
  549 void destroy_mount_opts(struct mount_opts *mo)
  550 {
  551     free(mo->fsname);
  552     free(mo->subtype);
  553     free(mo->fusermount_opts);
  554     free(mo->subtype_opt);
  555     free(mo->kernel_opts);
  556     free(mo->mtab_opts);
  557     free(mo);
  558 }
  559 
  560 
  561 int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo)
  562 {
  563     int res = -1;
  564     char *mnt_opts = NULL;
  565 
  566     res = -1;
  567     if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
  568         goto out;
  569     if (mo->kernel_opts && fuse_opt_add_opt(&mnt_opts, mo->kernel_opts) == -1)
  570         goto out;
  571     if (mo->mtab_opts &&  fuse_opt_add_opt(&mnt_opts, mo->mtab_opts) == -1)
  572         goto out;
  573 
  574     res = fuse_mount_sys(mountpoint, mo, mnt_opts);
  575     if (res == -2) {
  576         if (mo->fusermount_opts &&
  577             fuse_opt_add_opt(&mnt_opts, mo->fusermount_opts) == -1)
  578             goto out;
  579 
  580         if (mo->subtype) {
  581             char *tmp_opts = NULL;
  582 
  583             res = -1;
  584             if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
  585                 fuse_opt_add_opt(&tmp_opts, mo->subtype_opt) == -1) {
  586                 free(tmp_opts);
  587                 goto out;
  588             }
  589 
  590             res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
  591             free(tmp_opts);
  592             if (res == -1)
  593                 res = fuse_mount_fusermount(mountpoint, mo,
  594                                 mnt_opts, 0);
  595         } else {
  596             res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
  597         }
  598     }
  599 out:
  600     free(mnt_opts);
  601     return res;
  602 }