blob: 70454f4e3783555e4c713582e6275a53ed238f2f
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 | #ifndef __SOLARIS__ |
385 | close(fd); |
386 | |
387 | fusermount(1, 0, 1, "", mountpoint); |
388 | #else /* __SOLARIS__ */ |
389 | if (geteuid() == 0) { |
390 | fuse_mnt_umount("fuse", mountpoint, 1); |
391 | return; |
392 | } |
393 | |
394 | res = umount2(mountpoint, 2); |
395 | if (res == 0) |
396 | return; |
397 | |
398 | pid = fork(); |
399 | if(pid == -1) |
400 | return; |
401 | |
402 | if(pid == 0) { |
403 | const char *argv[] = |
404 | { FUSERMOUNT_PROG, "-u", "-q", "-z", "--", mountpoint, NULL }; |
405 | |
406 | exec_fusermount(argv); |
407 | _exit(1); |
408 | } |
409 | waitpid(pid, NULL, 0); |
410 | #endif /* __SOLARIS__ */ |
411 | } |
412 | |
413 | #ifdef __SOLARIS__ |
414 | |
415 | static int fuse_mount_fusermount(const char *mountpoint, const char *opts, |
416 | int quiet) |
417 | { |
418 | int fds[2], pid; |
419 | int res; |
420 | int rv; |
421 | |
422 | if (!mountpoint) { |
423 | fprintf(stderr, "fuse: missing mountpoint\n"); |
424 | return -1; |
425 | } |
426 | |
427 | res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); |
428 | if(res == -1) { |
429 | perror("fuse: socketpair() failed"); |
430 | return -1; |
431 | } |
432 | |
433 | pid = fork(); |
434 | if(pid == -1) { |
435 | perror("fuse: fork() failed"); |
436 | close(fds[0]); |
437 | close(fds[1]); |
438 | return -1; |
439 | } |
440 | |
441 | if(pid == 0) { |
442 | char env[10]; |
443 | const char *argv[32]; |
444 | int a = 0; |
445 | |
446 | if (quiet) { |
447 | int fd = open("/dev/null", O_RDONLY); |
448 | dup2(fd, 1); |
449 | dup2(fd, 2); |
450 | } |
451 | |
452 | argv[a++] = FUSERMOUNT_PROG; |
453 | if (opts) { |
454 | argv[a++] = "-o"; |
455 | argv[a++] = opts; |
456 | } |
457 | argv[a++] = "--"; |
458 | argv[a++] = mountpoint; |
459 | argv[a++] = NULL; |
460 | |
461 | close(fds[1]); |
462 | fcntl(fds[0], F_SETFD, 0); |
463 | snprintf(env, sizeof(env), "%i", fds[0]); |
464 | setenv(FUSE_COMMFD_ENV, env, 1); |
465 | exec_fusermount(argv); |
466 | perror("fuse: failed to exec fusermount"); |
467 | _exit(1); |
468 | } |
469 | |
470 | close(fds[0]); |
471 | rv = receive_fd(fds[1]); |
472 | close(fds[1]); |
473 | waitpid(pid, NULL, 0); /* bury zombie */ |
474 | |
475 | return rv; |
476 | } |
477 | |
478 | static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, |
479 | const char *mnt_opts) |
480 | { |
481 | char tmp[128]; |
482 | const char *devname = "/dev/fuse"; |
483 | char *source = NULL; |
484 | char *type = NULL; |
485 | struct stat stbuf; |
486 | int fd; |
487 | int res; |
488 | |
489 | if (!mnt) { |
490 | fprintf(stderr, "fuse: missing mountpoint\n"); |
491 | return -1; |
492 | } |
493 | |
494 | res = lstat(mnt, &stbuf); |
495 | if (res == -1) { |
496 | fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n", |
497 | mnt, strerror(errno)); |
498 | return -1; |
499 | } |
500 | |
501 | if (!mo->nonempty) { |
502 | res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, stbuf.st_size); |
503 | if (res == -1) |
504 | return -1; |
505 | } |
506 | |
507 | fd = open(devname, O_RDWR); |
508 | if (fd == -1) { |
509 | if (errno == ENODEV || errno == ENOENT) |
510 | fprintf(stderr, |
511 | "fuse: device not found, try 'modprobe fuse' first\n"); |
512 | else |
513 | fprintf(stderr, "fuse: failed to open %s: %s\n", devname, |
514 | strerror(errno)); |
515 | return -1; |
516 | } |
517 | |
518 | snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd, |
519 | stbuf.st_mode & S_IFMT, getuid(), getgid()); |
520 | |
521 | res = fuse_opt_add_opt(&mo->kernel_opts, tmp); |
522 | if (res == -1) |
523 | goto out_close; |
524 | |
525 | source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + |
526 | (mo->subtype ? strlen(mo->subtype) : 0) + |
527 | strlen(devname) + 32); |
528 | |
529 | type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); |
530 | if (!type || !source) { |
531 | fprintf(stderr, "fuse: failed to allocate memory\n"); |
532 | goto out_close; |
533 | } |
534 | |
535 | strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); |
536 | if (mo->subtype) { |
537 | strcat(type, "."); |
538 | strcat(type, mo->subtype); |
539 | } |
540 | strcpy(source, |
541 | mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); |
542 | |
543 | /* JPA added two final zeroes */ |
544 | res = mount(source, mnt, MS_OPTIONSTR|mo->flags, type, NULL, 0, |
545 | mo->kernel_opts, MAX_MNTOPT_STR, 0, 0); |
546 | |
547 | if (res == -1 && errno == EINVAL && mo->subtype) { |
548 | /* Probably missing subtype support */ |
549 | strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); |
550 | if (mo->fsname) { |
551 | if (!mo->blkdev) |
552 | sprintf(source, "%s#%s", mo->subtype, mo->fsname); |
553 | } else { |
554 | strcpy(source, type); |
555 | } |
556 | /* JPA two null args added */ |
557 | res = mount(source, mnt, MS_OPTIONSTR|mo->flags, type, NULL, 0, |
558 | mo->kernel_opts, MAX_MNTOPT_STR, 0, 0); |
559 | } |
560 | if (res == -1) { |
561 | /* |
562 | * Maybe kernel doesn't support unprivileged mounts, in this |
563 | * case try falling back to fusermount |
564 | */ |
565 | if (errno == EPERM) { |
566 | res = -2; |
567 | } else { |
568 | int errno_save = errno; |
569 | if (mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) |
570 | fprintf(stderr, "fuse: 'fuseblk' support missing\n"); |
571 | else |
572 | fprintf(stderr, "fuse: mount failed: %s\n", |
573 | strerror(errno_save)); |
574 | } |
575 | |
576 | goto out_close; |
577 | } |
578 | |
579 | return fd; |
580 | |
581 | out_umount: |
582 | umount2(mnt, 2); /* lazy umount */ |
583 | out_close: |
584 | free(type); |
585 | free(source); |
586 | close(fd); |
587 | return res; |
588 | } |
589 | |
590 | #endif /* __SOLARIS__ */ |
591 | |
592 | static int get_mnt_flag_opts(char **mnt_optsp, int flags) |
593 | { |
594 | int i; |
595 | |
596 | if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) |
597 | return -1; |
598 | |
599 | for (i = 0; mount_flags[i].opt != NULL; i++) { |
600 | if (mount_flags[i].on && (flags & mount_flags[i].flag) && |
601 | fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) |
602 | return -1; |
603 | } |
604 | return 0; |
605 | } |
606 | |
607 | int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) |
608 | { |
609 | struct mount_opts mo; |
610 | int res = -1; |
611 | char *mnt_opts = NULL; |
612 | #ifdef __SOLARIS__ |
613 | struct solaris_mount_opts smo; |
614 | struct fuse_args sa = FUSE_ARGS_INIT(0, NULL); |
615 | #endif /* __SOLARIS__ */ |
616 | |
617 | memset(&mo, 0, sizeof(mo)); |
618 | #ifndef __SOLARIS__ |
619 | if (getuid()) |
620 | mo.flags = MS_NOSUID | MS_NODEV; |
621 | #else /* __SOLARIS__ */ |
622 | mo.flags = 0; |
623 | memset(&smo, 0, sizeof(smo)); |
624 | if (args != NULL) { |
625 | while (args->argv[sa.argc] != NULL) |
626 | fuse_opt_add_arg(&sa, args->argv[sa.argc]); |
627 | } |
628 | #endif /* __SOLARIS__ */ |
629 | |
630 | if (args && |
631 | fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) |
632 | #ifndef __SOLARIS__ |
633 | return -1; |
634 | #else /* __SOLARIS__ */ |
635 | goto out; /* if SOLARIS, clean up 'sa' */ |
636 | |
637 | /* |
638 | * In Solaris, nosuid is equivalent to nosetuid + nodevices. We only |
639 | * have MS_NOSUID for mount flags (no MS_(NO)SETUID, etc.). But if |
640 | * we set that as a default, it restricts specifying just nosetuid |
641 | * or nodevices; there is no way for the user to specify setuid + |
642 | * nodevices or vice-verse. So we parse the existing options, then |
643 | * add restrictive defaults if needed. |
644 | */ |
645 | if (fuse_opt_parse(&sa, &smo, solaris_mnt_opts, NULL) == -1) |
646 | goto out; |
647 | if (smo.nosuid || (!smo.nodevices && !smo.devices |
648 | && !smo.nosetuid && !smo.setuid)) { |
649 | mo.flags |= MS_NOSUID; |
650 | } else { |
651 | /* |
652 | * Defaults; if neither nodevices|devices,nosetuid|setuid has |
653 | * been specified, add the default negative option string. If |
654 | * both have been specified (i.e., -osuid,nosuid), leave them |
655 | * alone; the last option will have precedence. |
656 | */ |
657 | if (!smo.nodevices && !smo.devices) |
658 | if (fuse_opt_add_opt(&mo.kernel_opts, "nodevices") == -1) |
659 | goto out; |
660 | if (!smo.nosetuid && !smo.setuid) |
661 | if (fuse_opt_add_opt(&mo.kernel_opts, "nosetuid") == -1) |
662 | goto out; |
663 | } |
664 | #endif /* __SOLARIS__ */ |
665 | |
666 | if (mo.allow_other && mo.allow_root) { |
667 | fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); |
668 | goto out; |
669 | } |
670 | res = 0; |
671 | if (mo.ishelp) |
672 | goto out; |
673 | |
674 | res = -1; |
675 | if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) |
676 | goto out; |
677 | #ifndef __SOLARIS__ |
678 | if (!(mo.flags & MS_NODEV) && fuse_opt_add_opt(&mnt_opts, "dev") == -1) |
679 | goto out; |
680 | if (!(mo.flags & MS_NOSUID) && fuse_opt_add_opt(&mnt_opts, "suid") == -1) |
681 | goto out; |
682 | if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) |
683 | goto out; |
684 | if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) |
685 | goto out; |
686 | if (mo.fusermount_opts && fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) < 0) |
687 | goto out; |
688 | res = fusermount(0, 0, 0, mnt_opts ? mnt_opts : "", mountpoint); |
689 | #else /* __SOLARIS__ */ |
690 | if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) |
691 | goto out; |
692 | if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) |
693 | goto out; |
694 | res = fuse_mount_sys(mountpoint, &mo, mnt_opts); |
695 | if (res == -2) { |
696 | if (mo.fusermount_opts && |
697 | fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1) |
698 | goto out; |
699 | |
700 | if (mo.subtype) { |
701 | char *tmp_opts = NULL; |
702 | |
703 | res = -1; |
704 | if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || |
705 | fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) { |
706 | free(tmp_opts); |
707 | goto out; |
708 | } |
709 | |
710 | res = fuse_mount_fusermount(mountpoint, tmp_opts, 1); |
711 | free(tmp_opts); |
712 | if (res == -1) |
713 | res = fuse_mount_fusermount(mountpoint, mnt_opts, 0); |
714 | } else { |
715 | res = fuse_mount_fusermount(mountpoint, mnt_opts, 0); |
716 | } |
717 | } |
718 | #endif /* __SOLARIS__ */ |
719 | |
720 | out: |
721 | free(mnt_opts); |
722 | #ifdef __SOLARIS__ |
723 | fuse_opt_free_args(&sa); |
724 | free(mo.subtype); |
725 | free(mo.subtype_opt); |
726 | #endif /* __SOLARIS__ */ |
727 | free(mo.fsname); |
728 | free(mo.fusermount_opts); |
729 | free(mo.kernel_opts); |
730 | free(mo.mtab_opts); |
731 | return res; |
732 | } |
733 |