"Fossies" - the Fresh Open Source Software Archive

Member "ntfs-3g_ntfsprogs-2017.3.23/libfuse-lite/mount.c" (23 Mar 2017, 21209 Bytes) of package /linux/misc/ntfs-3g_ntfsprogs-2017.3.23.tgz:


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 latest Fossies "Diffs" side-by-side code changes report: 3g_ntfsprogs-2016.2.22_vs_3g_ntfsprogs-2017.3.23.

    1 /*
    2     FUSE: Filesystem in Userspace
    3     Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
    4 
    5     This program can be distributed under the terms of the GNU LGPLv2.
    6     See the file COPYING.LIB.
    7 */
    8 
    9 #include "config.h"
   10 #include "fuse_i.h"
   11 #include "fuse_opt.h"
   12 #include "mount_util.h"
   13 
   14 #include <stdio.h>
   15 #include <string.h>
   16 #include <stdlib.h>
   17 #include <unistd.h>
   18 #include <stddef.h>
   19 #include <fcntl.h>
   20 #include <errno.h>
   21 #include <sys/poll.h>
   22 #include <sys/socket.h>
   23 #include <sys/un.h>
   24 #include <sys/wait.h>
   25 #include <sys/mount.h>
   26 
   27 #ifdef __SOLARIS__
   28 
   29 #define FUSERMOUNT_PROG         "fusermount"
   30 #define FUSE_COMMFD_ENV         "_FUSE_COMMFD"
   31 
   32 #ifndef FUSERMOUNT_DIR
   33 #define FUSERMOUNT_DIR "/usr"
   34 #endif /* FUSERMOUNT_DIR */
   35 
   36 #ifndef HAVE_FORK
   37 #define fork() vfork()
   38 #endif
   39 
   40 #endif /* __SOLARIS__ */
   41 
   42 #ifndef MS_DIRSYNC
   43 #define MS_DIRSYNC 128
   44 #endif
   45 
   46 enum {
   47     KEY_KERN_FLAG,
   48     KEY_KERN_OPT,
   49     KEY_FUSERMOUNT_OPT,
   50     KEY_SUBTYPE_OPT,
   51     KEY_MTAB_OPT,
   52     KEY_ALLOW_ROOT,
   53     KEY_RO,
   54     KEY_HELP,
   55     KEY_VERSION,
   56 };
   57 
   58 struct mount_opts {
   59     int allow_other;
   60     int allow_root;
   61     int ishelp;
   62     int flags;
   63 #ifdef __SOLARIS__
   64     int nonempty;
   65     int blkdev;
   66     char *fsname;
   67     char *subtype;
   68     char *subtype_opt;
   69 #else
   70     int blkdev;
   71     char *fsname;
   72 #endif
   73     char *mtab_opts;
   74     char *fusermount_opts;
   75     char *kernel_opts;
   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 #ifdef __SOLARIS__
   82     FUSE_MOUNT_OPT("allow_other",       allow_other),
   83     FUSE_MOUNT_OPT("allow_root",        allow_root),
   84     FUSE_MOUNT_OPT("nonempty",          nonempty),
   85     FUSE_MOUNT_OPT("blkdev",            blkdev),
   86     FUSE_MOUNT_OPT("fsname=%s",         fsname),
   87     FUSE_MOUNT_OPT("subtype=%s",        subtype),
   88     FUSE_OPT_KEY("allow_other",         KEY_KERN_OPT),
   89     FUSE_OPT_KEY("allow_root",          KEY_ALLOW_ROOT),
   90     FUSE_OPT_KEY("nonempty",            KEY_FUSERMOUNT_OPT),
   91     FUSE_OPT_KEY("blkdev",              KEY_FUSERMOUNT_OPT),
   92     FUSE_OPT_KEY("fsname=",             KEY_FUSERMOUNT_OPT),
   93     FUSE_OPT_KEY("subtype=",            KEY_SUBTYPE_OPT),
   94     FUSE_OPT_KEY("large_read",          KEY_KERN_OPT),
   95     FUSE_OPT_KEY("blksize=",            KEY_KERN_OPT),
   96     FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
   97     FUSE_OPT_KEY("max_read=",           KEY_KERN_OPT),
   98     FUSE_OPT_KEY("max_read=",           FUSE_OPT_KEY_KEEP),
   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("-g",                  KEY_KERN_FLAG),
  106     FUSE_OPT_KEY("-m",                  KEY_KERN_FLAG),
  107     FUSE_OPT_KEY("-O",                  KEY_KERN_FLAG),
  108     FUSE_OPT_KEY("setuid",              KEY_KERN_OPT),
  109     FUSE_OPT_KEY("nosetuid",            KEY_KERN_OPT),
  110     FUSE_OPT_KEY("devices",             KEY_KERN_OPT),
  111     FUSE_OPT_KEY("nodevices",           KEY_KERN_OPT),
  112     FUSE_OPT_KEY("exec",                KEY_KERN_OPT),
  113     FUSE_OPT_KEY("noexec",              KEY_KERN_OPT),
  114     FUSE_OPT_KEY("nbmand",              KEY_KERN_OPT),
  115     FUSE_OPT_KEY("nonbmand",            KEY_KERN_OPT),
  116 #else /* __SOLARIS__ */
  117     FUSE_MOUNT_OPT("allow_other",       allow_other),
  118     FUSE_MOUNT_OPT("allow_root",        allow_root),
  119     FUSE_MOUNT_OPT("blkdev",            blkdev),
  120     FUSE_MOUNT_OPT("fsname=%s",         fsname),
  121     FUSE_OPT_KEY("allow_other",         KEY_KERN_OPT),
  122     FUSE_OPT_KEY("allow_root",          KEY_ALLOW_ROOT),
  123     FUSE_OPT_KEY("blkdev",              KEY_FUSERMOUNT_OPT),
  124     FUSE_OPT_KEY("fsname=",             KEY_FUSERMOUNT_OPT),
  125     FUSE_OPT_KEY("large_read",          KEY_KERN_OPT),
  126     FUSE_OPT_KEY("blksize=",            KEY_KERN_OPT),
  127     FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
  128     FUSE_OPT_KEY("context=",            KEY_KERN_OPT),
  129     FUSE_OPT_KEY("max_read=",           KEY_KERN_OPT),
  130     FUSE_OPT_KEY("max_read=",           FUSE_OPT_KEY_KEEP),
  131     FUSE_OPT_KEY("user=",               KEY_MTAB_OPT),
  132     FUSE_OPT_KEY("-r",                  KEY_RO),
  133     FUSE_OPT_KEY("ro",                  KEY_KERN_FLAG),
  134     FUSE_OPT_KEY("rw",                  KEY_KERN_FLAG),
  135     FUSE_OPT_KEY("suid",                KEY_KERN_FLAG),
  136     FUSE_OPT_KEY("nosuid",              KEY_KERN_FLAG),
  137     FUSE_OPT_KEY("dev",                 KEY_KERN_FLAG),
  138     FUSE_OPT_KEY("nodev",               KEY_KERN_FLAG),
  139     FUSE_OPT_KEY("exec",                KEY_KERN_FLAG),
  140     FUSE_OPT_KEY("noexec",              KEY_KERN_FLAG),
  141     FUSE_OPT_KEY("async",               KEY_KERN_FLAG),
  142     FUSE_OPT_KEY("sync",                KEY_KERN_FLAG),
  143     FUSE_OPT_KEY("dirsync",             KEY_KERN_FLAG),
  144     FUSE_OPT_KEY("atime",               KEY_KERN_FLAG),
  145     FUSE_OPT_KEY("noatime",             KEY_KERN_FLAG),
  146 #endif /* __SOLARIS__ */
  147     FUSE_OPT_KEY("-h",                  KEY_HELP),
  148     FUSE_OPT_KEY("--help",              KEY_HELP),
  149     FUSE_OPT_KEY("-V",                  KEY_VERSION),
  150     FUSE_OPT_KEY("--version",           KEY_VERSION),
  151     FUSE_OPT_END
  152 };
  153 
  154 #ifdef __SOLARIS__
  155 
  156 static void mount_help(void)
  157 {
  158     fprintf(stderr,
  159             "    -o allow_other         allow access to other users\n"
  160             "    -o allow_root          allow access to root\n"
  161             "    -o nonempty            allow mounts over non-empty file/dir\n"
  162             "    -o default_permissions enable permission checking by kernel\n"
  163             "    -o fsname=NAME         set filesystem name\n"
  164             "    -o subtype=NAME        set filesystem type\n"
  165             "    -o large_read          issue large read requests (2.4 only)\n"
  166             "    -o max_read=N          set maximum size of read requests\n"
  167             "\n"
  168             );
  169 }
  170 
  171 static void exec_fusermount(const char *argv[])
  172 {
  173     execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
  174     execvp(FUSERMOUNT_PROG, (char **) argv);
  175 }
  176 
  177 static void mount_version(void)
  178 {
  179     int pid = fork();
  180     if (!pid) {
  181         const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
  182         exec_fusermount(argv);
  183         _exit(1);
  184     } else if (pid != -1)
  185         waitpid(pid, NULL, 0);
  186 }
  187 
  188 #endif /* __SOLARIS__ */
  189 
  190 struct mount_flags {
  191     const char *opt;
  192     unsigned long flag;
  193     int on;
  194 };
  195 
  196 static struct mount_flags mount_flags[] = {
  197     {"rw",      MS_RDONLY,      0},
  198     {"ro",      MS_RDONLY,      1},
  199     {"suid",    MS_NOSUID,      0},
  200     {"nosuid",  MS_NOSUID,      1},
  201 #ifndef __SOLARIS__
  202     {"dev",     MS_NODEV,       0},
  203     {"nodev",   MS_NODEV,       1},
  204     {"exec",    MS_NOEXEC,      0},
  205     {"noexec",  MS_NOEXEC,      1},
  206     {"async",   MS_SYNCHRONOUS, 0},
  207     {"sync",    MS_SYNCHRONOUS, 1},
  208     {"atime",   MS_NOATIME,     0},
  209     {"noatime", MS_NOATIME,     1},
  210     {"dirsync", MS_DIRSYNC,     1},
  211 #else /* __SOLARIS__ */
  212     {"-g",      MS_GLOBAL,      1},  /* 1eaf4 */
  213     {"-m",      MS_NOMNTTAB,    1},  /* 1eb00 */
  214     {"-O",      MS_OVERLAY,     1},  /* 1eb0c */
  215 #endif /* __SOLARIS__ */
  216     {NULL,      0,              0}
  217 };
  218 
  219 #ifdef __SOLARIS__
  220 
  221 /*
  222  * See comments in fuse_kern_mount()
  223  */
  224 struct solaris_mount_opts {
  225     int nosuid;
  226     int setuid;
  227     int nosetuid;
  228     int devices;
  229     int nodevices;
  230 };
  231 
  232 #define SOLARIS_MOUNT_OPT(t, p, n) \
  233     { t, offsetof(struct solaris_mount_opts, p), n }
  234 static const struct fuse_opt solaris_mnt_opts[] = {
  235     SOLARIS_MOUNT_OPT("suid",       setuid,         1),
  236     SOLARIS_MOUNT_OPT("suid",       devices,        1),
  237     SOLARIS_MOUNT_OPT("nosuid",     nosuid,         1),
  238     SOLARIS_MOUNT_OPT("setuid",     setuid,         1),
  239     SOLARIS_MOUNT_OPT("nosetuid",   nosetuid,       1),
  240     SOLARIS_MOUNT_OPT("devices",    devices,        1),
  241     SOLARIS_MOUNT_OPT("nodevices",  nodevices,      1),
  242     FUSE_OPT_END
  243 };
  244 
  245 #endif /* __SOLARIS__ */
  246 
  247 static void set_mount_flag(const char *s, int *flags)
  248 {
  249     int i;
  250 
  251     for (i = 0; mount_flags[i].opt != NULL; i++) {
  252         const char *opt = mount_flags[i].opt;
  253         if (strcmp(opt, s) == 0) {
  254             if (mount_flags[i].on)
  255                 *flags |= mount_flags[i].flag;
  256             else
  257                 *flags &= ~mount_flags[i].flag;
  258             return;
  259         }
  260     }
  261     fprintf(stderr, "fuse: internal error, can't find mount flag\n");
  262     abort();
  263 }
  264 
  265 static int fuse_mount_opt_proc(void *data, const char *arg, int key,
  266                                struct fuse_args *outargs)
  267 {
  268     struct mount_opts *mo = data;
  269 
  270     switch (key) {
  271     case KEY_ALLOW_ROOT:
  272         if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
  273             fuse_opt_add_arg(outargs, "-oallow_root") == -1)
  274             return -1;
  275         return 0;
  276 
  277     case KEY_RO:
  278         arg = "ro";
  279         /* fall through */
  280     case KEY_KERN_FLAG:
  281         set_mount_flag(arg, &mo->flags);
  282         return 0;
  283 
  284     case KEY_KERN_OPT:
  285         return fuse_opt_add_opt(&mo->kernel_opts, arg);
  286 
  287     case KEY_FUSERMOUNT_OPT:
  288         return fuse_opt_add_opt(&mo->fusermount_opts, arg);
  289 
  290 #ifdef __SOLARIS__
  291     case KEY_SUBTYPE_OPT:
  292         return fuse_opt_add_opt(&mo->subtype_opt, arg);
  293 #endif /* __SOLARIS__ */
  294 
  295     case KEY_MTAB_OPT:
  296         return fuse_opt_add_opt(&mo->mtab_opts, arg);
  297 
  298     case KEY_HELP:
  299 #ifdef __SOLARIS__
  300         mount_help();
  301 #endif /* __SOLARIS__ */
  302         mo->ishelp = 1;
  303         break;
  304 
  305     case KEY_VERSION:
  306 #ifdef __SOLARIS__
  307         mount_version();
  308 #endif /* __SOLARIS__ */
  309         mo->ishelp = 1;
  310         break;
  311     }
  312     return 1;
  313 }
  314 
  315 #ifdef __SOLARIS__
  316 
  317 /* return value:
  318  * >= 0  => fd
  319  * -1    => error
  320  */
  321 static int receive_fd(int fd)
  322 {
  323     struct msghdr msg;
  324     struct iovec iov;
  325     char buf[1];
  326     int rv;
  327     size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
  328     struct cmsghdr *cmsg;
  329 
  330     iov.iov_base = buf;
  331     iov.iov_len = 1;
  332 
  333     msg.msg_name = 0;
  334     msg.msg_namelen = 0;
  335     msg.msg_iov = &iov;
  336     msg.msg_iovlen = 1;
  337     /* old BSD implementations should use msg_accrights instead of
  338      * msg_control; the interface is different. */
  339     msg.msg_control = ccmsg;
  340     msg.msg_controllen = sizeof(ccmsg);
  341 
  342     while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
  343     if (rv == -1) {
  344         perror("recvmsg");
  345         return -1;
  346     }
  347     if(!rv) {
  348         /* EOF */
  349         return -1;
  350     }
  351 
  352     cmsg = CMSG_FIRSTHDR(&msg);
  353     if (cmsg->cmsg_type != SCM_RIGHTS) {
  354         fprintf(stderr, "got control message of unknown type %d\n",
  355                 cmsg->cmsg_type);
  356         return -1;
  357     }
  358     return *(int*)CMSG_DATA(cmsg);
  359 }
  360 
  361 #endif /* __SOLARIS__ */
  362 
  363 void fuse_kern_unmount(const char *mountpoint, int fd)
  364 {
  365     int res;
  366 #ifdef __SOLARIS__
  367     int pid;
  368 #endif /* __SOLARIS__ */
  369 
  370     if (!mountpoint)
  371         return;
  372 
  373     if (fd != -1) {
  374         struct pollfd pfd;
  375 
  376         pfd.fd = fd;
  377         pfd.events = 0;
  378         res = poll(&pfd, 1, 0);
  379         /* If file poll returns POLLERR on the device file descriptor,
  380            then the filesystem is already unmounted */
  381         if (res == 1 && (pfd.revents & POLLERR))
  382             return;
  383               /*
  384                * Need to close file descriptor, otherwise synchronous umount
  385                * would recurse into filesystem, and deadlock.
  386                */
  387         close(fd);
  388     }
  389 #ifndef __SOLARIS__
  390     fusermount(1, 0, 1, "", mountpoint);
  391 #else /* __SOLARIS__ */
  392     if (geteuid() == 0) {
  393         fuse_mnt_umount("fuse", mountpoint, 1);
  394         return;
  395     }
  396 
  397     res = umount2(mountpoint, 2);
  398     if (res == 0)
  399         return;
  400 
  401     pid = fork();
  402     if(pid == -1)
  403         return;
  404 
  405     if(pid == 0) {
  406         const char *argv[] =
  407             { FUSERMOUNT_PROG, "-u", "-q", "-z", "--", mountpoint, NULL };
  408 
  409         exec_fusermount(argv);
  410         _exit(1);
  411     }
  412     waitpid(pid, NULL, 0);
  413 #endif /* __SOLARIS__ */
  414 }
  415 
  416 #ifdef __SOLARIS__
  417 
  418 static int fuse_mount_fusermount(const char *mountpoint, const char *opts,
  419                                  int quiet)
  420 {
  421     int fds[2], pid;
  422     int res;
  423     int rv;
  424 
  425     if (!mountpoint) {
  426         fprintf(stderr, "fuse: missing mountpoint\n");
  427         return -1;
  428     }
  429 
  430     res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
  431     if(res == -1) {
  432         perror("fuse: socketpair() failed");
  433         return -1;
  434     }
  435 
  436     pid = fork();
  437     if(pid == -1) {
  438         perror("fuse: fork() failed");
  439         close(fds[0]);
  440         close(fds[1]);
  441         return -1;
  442     }
  443 
  444     if(pid == 0) {
  445         char env[10];
  446         const char *argv[32];
  447         int a = 0;
  448 
  449         if (quiet) {
  450             int fd = open("/dev/null", O_RDONLY);
  451             dup2(fd, 1);
  452             dup2(fd, 2);
  453         }
  454 
  455         argv[a++] = FUSERMOUNT_PROG;
  456         if (opts) {
  457             argv[a++] = "-o";
  458             argv[a++] = opts;
  459         }
  460         argv[a++] = "--";
  461         argv[a++] = mountpoint;
  462         argv[a++] = NULL;
  463 
  464         close(fds[1]);
  465         fcntl(fds[0], F_SETFD, 0);
  466         snprintf(env, sizeof(env), "%i", fds[0]);
  467         setenv(FUSE_COMMFD_ENV, env, 1);
  468         exec_fusermount(argv);
  469         perror("fuse: failed to exec fusermount");
  470         _exit(1);
  471     }
  472 
  473     close(fds[0]);
  474     rv = receive_fd(fds[1]);
  475     close(fds[1]);
  476     waitpid(pid, NULL, 0); /* bury zombie */
  477 
  478     return rv;
  479 }
  480 
  481 static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
  482                           const char *mnt_opts)
  483 {
  484     char tmp[128];
  485     const char *devname = "/dev/fuse";
  486     char *source = NULL;
  487     char *type = NULL;
  488     struct stat stbuf;
  489     int fd;
  490     int res;
  491 
  492     if (!mnt) {
  493         fprintf(stderr, "fuse: missing mountpoint\n");
  494         return -1;
  495     }
  496 
  497     res = lstat(mnt, &stbuf);
  498     if (res == -1) {
  499         fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
  500                 mnt, strerror(errno));
  501         return -1;
  502     }
  503 
  504     if (!mo->nonempty) {
  505         res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, stbuf.st_size);
  506         if (res == -1)
  507             return -1;
  508     }
  509 
  510     fd = open(devname, O_RDWR);
  511     if (fd == -1) {
  512         if (errno == ENODEV || errno == ENOENT)
  513             fprintf(stderr,
  514                     "fuse: device not found, try 'modprobe fuse' first\n");
  515         else
  516             fprintf(stderr, "fuse: failed to open %s: %s\n", devname,
  517                     strerror(errno));
  518         return -1;
  519     }
  520 
  521     snprintf(tmp, sizeof(tmp),  "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd,
  522              stbuf.st_mode & S_IFMT, getuid(), getgid());
  523 
  524     res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
  525     if (res == -1)
  526         goto out_close;
  527 
  528     source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
  529                     (mo->subtype ? strlen(mo->subtype) : 0) +
  530                     strlen(devname) + 32);
  531 
  532     type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
  533     if (!type || !source) {
  534         fprintf(stderr, "fuse: failed to allocate memory\n");
  535         goto out_close;
  536     }
  537 
  538     strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
  539     if (mo->subtype) {
  540         strcat(type, ".");
  541         strcat(type, mo->subtype);
  542     }
  543     strcpy(source,
  544            mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
  545 
  546           /* JPA added two final zeroes */
  547     res = mount(source, mnt, MS_OPTIONSTR|mo->flags, type, NULL, 0,
  548         mo->kernel_opts, MAX_MNTOPT_STR, 0, 0);
  549 
  550     if (res == -1 && errno == EINVAL && mo->subtype) {
  551         /* Probably missing subtype support */
  552         strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
  553         if (mo->fsname) {
  554             if (!mo->blkdev)
  555                 sprintf(source, "%s#%s", mo->subtype, mo->fsname);
  556         } else {
  557             strcpy(source, type);
  558         }
  559         /* JPA two null args added */
  560     res = mount(source, mnt, MS_OPTIONSTR|mo->flags, type, NULL, 0,
  561             mo->kernel_opts, MAX_MNTOPT_STR, 0, 0);
  562     }
  563     if (res == -1) {
  564         /*
  565          * Maybe kernel doesn't support unprivileged mounts, in this
  566          * case try falling back to fusermount
  567          */
  568         if (errno == EPERM) {
  569             res = -2;
  570         } else {
  571             int errno_save = errno;
  572             if (mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
  573                 fprintf(stderr, "fuse: 'fuseblk' support missing\n");
  574             else
  575                 fprintf(stderr, "fuse: mount failed: %s\n",
  576                         strerror(errno_save));
  577         }
  578 
  579         goto out_close;
  580     }
  581 
  582     return fd;
  583 
  584  out_umount:
  585     umount2(mnt, 2); /* lazy umount */
  586  out_close:
  587     free(type);
  588     free(source);
  589     close(fd);
  590     return res;
  591 }
  592 
  593 #endif /* __SOLARIS__ */
  594 
  595 static int get_mnt_flag_opts(char **mnt_optsp, int flags)
  596 {
  597     int i;
  598 
  599     if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
  600         return -1;
  601 
  602     for (i = 0; mount_flags[i].opt != NULL; i++) {
  603         if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
  604         fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
  605                 return -1;
  606     }
  607     return 0;
  608 }
  609 
  610 int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
  611 {
  612     struct mount_opts mo;
  613     int res = -1;
  614     char *mnt_opts = NULL;
  615 #ifdef __SOLARIS__
  616     struct solaris_mount_opts smo;
  617     struct fuse_args sa = FUSE_ARGS_INIT(0, NULL);
  618 #endif /* __SOLARIS__ */
  619 
  620     memset(&mo, 0, sizeof(mo));
  621 #ifndef __SOLARIS__
  622     if (getuid())
  623         mo.flags = MS_NOSUID | MS_NODEV;
  624 #else /* __SOLARIS__ */
  625     mo.flags = 0;
  626     memset(&smo, 0, sizeof(smo));
  627     if (args != NULL) {
  628         while (args->argv[sa.argc] != NULL)
  629         fuse_opt_add_arg(&sa, args->argv[sa.argc]);
  630     }
  631 #endif /* __SOLARIS__ */
  632 
  633     if (args &&
  634         fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
  635 #ifndef __SOLARIS__
  636         return -1;
  637 #else /* __SOLARIS__ */
  638         goto out; /* if SOLARIS, clean up 'sa' */
  639 
  640     /*
  641      * In Solaris, nosuid is equivalent to nosetuid + nodevices. We only
  642      * have MS_NOSUID for mount flags (no MS_(NO)SETUID, etc.). But if
  643      * we set that as a default, it restricts specifying just nosetuid
  644      * or nodevices; there is no way for the user to specify setuid +
  645      * nodevices or vice-verse. So we parse the existing options, then
  646      * add restrictive defaults if needed.
  647      */
  648     if (fuse_opt_parse(&sa, &smo, solaris_mnt_opts, NULL) == -1)
  649          goto out;
  650     if (smo.nosuid || (!smo.nodevices && !smo.devices
  651         && !smo.nosetuid && !smo.setuid)) {
  652         mo.flags |= MS_NOSUID;
  653     } else {
  654         /*
  655          * Defaults; if neither nodevices|devices,nosetuid|setuid has
  656          * been specified, add the default negative option string. If
  657          * both have been specified (i.e., -osuid,nosuid), leave them
  658          * alone; the last option will have precedence.
  659          */
  660         if (!smo.nodevices && !smo.devices)
  661              if (fuse_opt_add_opt(&mo.kernel_opts, "nodevices") == -1)
  662                  goto out;
  663         if (!smo.nosetuid && !smo.setuid)
  664             if (fuse_opt_add_opt(&mo.kernel_opts, "nosetuid") == -1)
  665                  goto out;
  666     }
  667 #endif /* __SOLARIS__ */
  668 
  669     if (mo.allow_other && mo.allow_root) {
  670         fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
  671         goto out;
  672     }
  673     res = 0;
  674     if (mo.ishelp)
  675         goto out;
  676 
  677     res = -1;
  678     if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
  679         goto out;
  680 #ifndef __SOLARIS__
  681     if (!(mo.flags & MS_NODEV) && fuse_opt_add_opt(&mnt_opts, "dev") == -1)
  682         goto out;
  683     if (!(mo.flags & MS_NOSUID) && fuse_opt_add_opt(&mnt_opts, "suid") == -1)
  684         goto out;
  685     if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
  686         goto out;
  687     if (mo.mtab_opts &&  fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
  688         goto out;
  689     if (mo.fusermount_opts && fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) < 0)
  690         goto out;
  691     res = fusermount(0, 0, 0, mnt_opts ? mnt_opts : "", mountpoint);
  692 #else /* __SOLARIS__ */
  693     if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
  694         goto out;
  695     if (mo.mtab_opts &&  fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
  696         goto out;
  697     res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
  698     if (res == -2) {
  699         if (mo.fusermount_opts &&
  700             fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
  701             goto out;
  702 
  703         if (mo.subtype) {
  704             char *tmp_opts = NULL;
  705 
  706             res = -1;
  707             if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
  708                 fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
  709                 free(tmp_opts);
  710                 goto out;
  711             }
  712 
  713             res = fuse_mount_fusermount(mountpoint, tmp_opts, 1);
  714             free(tmp_opts);
  715             if (res == -1)
  716                 res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
  717         } else {
  718             res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
  719         }
  720     }
  721 #endif /* __SOLARIS__ */
  722 
  723 out:
  724     free(mnt_opts);
  725 #ifdef __SOLARIS__
  726     fuse_opt_free_args(&sa);
  727     free(mo.subtype);
  728     free(mo.subtype_opt);
  729 #endif /* __SOLARIS__ */
  730     free(mo.fsname);
  731     free(mo.fusermount_opts);
  732     free(mo.kernel_opts);
  733     free(mo.mtab_opts);
  734     return res;
  735 }