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 = -1;
674 if (mo.ishelp)
675 goto out;
676
677 if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
678 goto out;
679 #ifndef __SOLARIS__
680 if (!(mo.flags & MS_NODEV) && fuse_opt_add_opt(&mnt_opts, "dev") == -1)
681 goto out;
682 if (!(mo.flags & MS_NOSUID) && fuse_opt_add_opt(&mnt_opts, "suid") == -1)
683 goto out;
684 if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
685 goto out;
686 if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
687 goto out;
688 if (mo.fusermount_opts && fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) < 0)
689 goto out;
690 res = fusermount(0, 0, 0, mnt_opts ? mnt_opts : "", mountpoint);
691 #else /* __SOLARIS__ */
692 if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
693 goto out;
694 if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
695 goto out;
696 res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
697 if (res == -2) {
698 if (mo.fusermount_opts &&
699 fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
700 goto out;
701
702 if (mo.subtype) {
703 char *tmp_opts = NULL;
704
705 res = -1;
706 if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
707 fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
708 free(tmp_opts);
709 goto out;
710 }
711
712 res = fuse_mount_fusermount(mountpoint, tmp_opts, 1);
713 free(tmp_opts);
714 if (res == -1)
715 res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
716 } else {
717 res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
718 }
719 }
720 #endif /* __SOLARIS__ */
721
722 out:
723 free(mnt_opts);
724 #ifdef __SOLARIS__
725 fuse_opt_free_args(&sa);
726 free(mo.subtype);
727 free(mo.subtype_opt);
728 #endif /* __SOLARIS__ */
729 free(mo.fsname);
730 free(mo.fusermount_opts);
731 free(mo.kernel_opts);
732 free(mo.mtab_opts);
733 return res;
734 }
735