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 
mount_help(void)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 
exec_fusermount(const char * argv[])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 
mount_version(void)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 
set_mount_flag(const char * s,int * flags)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 
fuse_mount_opt_proc(void * data,const char * arg,int key,struct fuse_args * outargs)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  */
receive_fd(int fd)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 
fuse_kern_unmount(const char * mountpoint,int fd)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 
fuse_mount_fusermount(const char * mountpoint,const char * opts,int quiet)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 
fuse_mount_sys(const char * mnt,struct mount_opts * mo,const char * mnt_opts)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 
get_mnt_flag_opts(char ** mnt_optsp,int flags)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 
fuse_kern_mount(const char * mountpoint,struct fuse_args * args)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 }
736