libfuse: fuse-3.3.2/util/fusermount.c Source File

libfuse

fusermount.c
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 GPL.
6 See the file COPYING.
7 */
8 /* This program does the mounting and unmounting of FUSE filesystems */
9
10 #define _GNU_SOURCE /* for clone */
11 #include <config.h>
12
13 #include "mount_util.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <unistd.h>
19 #include <getopt.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <pwd.h>
23 #include <paths.h>
24 #include <mntent.h>
25 #include <sys/wait.h>
26 #include <sys/stat.h>
27 #include <sys/mount.h>
28 #include <sys/fsuid.h>
29 #include <sys/socket.h>
30 #include <sys/utsname.h>
31 #include <sched.h>
32
33 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
34
35 #define FUSE_DEV "/dev/fuse"
36 #define FUSE_CONF "/etc/fuse.conf"
37
38 #ifndef MS_DIRSYNC
39 #define MS_DIRSYNC 128
40 #endif
41 #ifndef MS_REC
42 #define MS_REC 16384
43 #endif
44 #ifndef MS_PRIVATE
45 #define MS_PRIVATE (1<<18)
46 #endif
47
48 #ifndef UMOUNT_DETACH
49 #define UMOUNT_DETACH 0x00000002 /* Just detach from the tree */
50 #endif
51 #ifndef UMOUNT_NOFOLLOW
52 #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
53 #endif
54 #ifndef UMOUNT_UNUSED
55 #define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
56 #endif
57
58 static const char *progname;
59
60 static int user_allow_other = 0;
61 static int mount_max = 1000;
62
63 static int auto_unmount = 0;
64
65 static const char *get_user_name(void)
66 {
67 struct passwd *pw = getpwuid(getuid());
68 if (pw != NULL && pw->pw_name != NULL)
69 return pw->pw_name;
70 else {
71 fprintf(stderr, "%s: could not determine username\n", progname);
72 return NULL;
73 }
74 }
75
76 static uid_t oldfsuid;
77 static gid_t oldfsgid;
78
79 static void drop_privs(void)
80 {
81 if (getuid() != 0) {
82 oldfsuid = setfsuid(getuid());
83 oldfsgid = setfsgid(getgid());
84 }
85 }
86
87 static void restore_privs(void)
88 {
89 if (getuid() != 0) {
90 setfsuid(oldfsuid);
91 setfsgid(oldfsgid);
92 }
93 }
94
95 #ifndef IGNORE_MTAB
96 /*
97 * Make sure that /etc/mtab is checked and updated atomically
98 */
99 static int lock_umount(void)
100 {
101 const char *mtab_lock = _PATH_MOUNTED ".fuselock";
102 int mtablock;
103 int res;
104 struct stat mtab_stat;
105
106 /* /etc/mtab could be a symlink to /proc/mounts */
107 if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
108 return -1;
109
110 mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
111 if (mtablock == -1) {
112 fprintf(stderr, "%s: unable to open fuse lock file: %s\n",
113 progname, strerror(errno));
114 return -1;
115 }
116 res = lockf(mtablock, F_LOCK, 0);
117 if (res < 0) {
118 fprintf(stderr, "%s: error getting lock: %s\n", progname,
119 strerror(errno));
120 close(mtablock);
121 return -1;
122 }
123
124 return mtablock;
125 }
126
127 static void unlock_umount(int mtablock)
128 {
129 if (mtablock >= 0) {
130 int res;
131
132 res = lockf(mtablock, F_ULOCK, 0);
133 if (res < 0) {
134 fprintf(stderr, "%s: error releasing lock: %s\n",
135 progname, strerror(errno));
136 }
137 close(mtablock);
138 }
139 }
140
141 static int add_mount(const char *source, const char *mnt, const char *type,
142 const char *opts)
143 {
144 return fuse_mnt_add_mount(progname, source, mnt, type, opts);
145 }
146
147 static int may_unmount(const char *mnt, int quiet)
148 {
149 struct mntent *entp;
150 FILE *fp;
151 const char *user = NULL;
152 char uidstr[32];
153 unsigned uidlen = 0;
154 int found;
155 const char *mtab = _PATH_MOUNTED;
156
157 user = get_user_name();
158 if (user == NULL)
159 return -1;
160
161 fp = setmntent(mtab, "r");
162 if (fp == NULL) {
163 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
164 strerror(errno));
165 return -1;
166 }
167
168 uidlen = sprintf(uidstr, "%u", getuid());
169
170 found = 0;
171 while ((entp = getmntent(fp)) != NULL) {
172 if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
173 (strcmp(entp->mnt_type, "fuse") == 0 ||
174 strcmp(entp->mnt_type, "fuseblk") == 0 ||
175 strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
176 strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
177 char *p = strstr(entp->mnt_opts, "user=");
178 if (p &&
179 (p == entp->mnt_opts || *(p-1) == ',') &&
180 strcmp(p + 5, user) == 0) {
181 found = 1;
182 break;
183 }
184 /* /etc/mtab is a link pointing to
185 /proc/mounts: */
186 else if ((p =
187 strstr(entp->mnt_opts, "user_id=")) &&
188 (p == entp->mnt_opts ||
189 *(p-1) == ',') &&
190 strncmp(p + 8, uidstr, uidlen) == 0 &&
191 (*(p+8+uidlen) == ',' ||
192 *(p+8+uidlen) == '\0')) {
193 found = 1;
194 break;
195 }
196 }
197 }
198 endmntent(fp);
199
200 if (!found) {
201 if (!quiet)
202 fprintf(stderr,
203 "%s: entry for %s not found in %s\n",
204 progname, mnt, mtab);
205 return -1;
206 }
207
208 return 0;
209 }
210
211 /*
212 * Check whether the file specified in "fusermount3 -u" is really a
213 * mountpoint and not a symlink. This is necessary otherwise the user
214 * could move the mountpoint away and replace it with a symlink
215 * pointing to an arbitrary mount, thereby tricking fusermount3 into
216 * unmounting that (umount(2) will follow symlinks).
217 *
218 * This is the child process running in a separate mount namespace, so
219 * we don't mess with the global namespace and if the process is
220 * killed for any reason, mounts are automatically cleaned up.
221 *
222 * First make sure nothing is propagated back into the parent
223 * namespace by marking all mounts "private".
224 *
225 * Then bind mount parent onto a stable base where the user can't move
226 * it around.
227 *
228 * Finally check /proc/mounts for an entry matching the requested
229 * mountpoint. If it's found then we are OK, and the user can't move
230 * it around within the parent directory as rename() will return
231 * EBUSY. Be careful to ignore any mounts that existed before the
232 * bind.
233 */
234 static int check_is_mount_child(void *p)
235 {
236 const char **a = p;
237 const char *last = a[0];
238 const char *mnt = a[1];
239 int res;
240 const char *procmounts = "/proc/mounts";
241 int found;
242 FILE *fp;
243 struct mntent *entp;
244 int count;
245
246 res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL);
247 if (res == -1) {
248 fprintf(stderr, "%s: failed to mark mounts private: %s\n",
249 progname, strerror(errno));
250 return 1;
251 }
252
253 fp = setmntent(procmounts, "r");
254 if (fp == NULL) {
255 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
256 procmounts, strerror(errno));
257 return 1;
258 }
259
260 count = 0;
261 while (getmntent(fp) != NULL)
262 count++;
263 endmntent(fp);
264
265 fp = setmntent(procmounts, "r");
266 if (fp == NULL) {
267 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
268 procmounts, strerror(errno));
269 return 1;
270 }
271
272 res = mount(".", "/", "", MS_BIND | MS_REC, NULL);
273 if (res == -1) {
274 fprintf(stderr, "%s: failed to bind parent to /: %s\n",
275 progname, strerror(errno));
276 return 1;
277 }
278
279 found = 0;
280 while ((entp = getmntent(fp)) != NULL) {
281 if (count > 0) {
282 count--;
283 continue;
284 }
285 if (entp->mnt_dir[0] == '/' &&
286 strcmp(entp->mnt_dir + 1, last) == 0) {
287 found = 1;
288 break;
289 }
290 }
291 endmntent(fp);
292
293 if (!found) {
294 fprintf(stderr, "%s: %s not mounted\n", progname, mnt);
295 return 1;
296 }
297
298 return 0;
299 }
300
301 static pid_t clone_newns(void *a)
302 {
303 char buf[131072];
304 char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15));
305
306 #ifdef __ia64__
307 extern int __clone2(int (*fn)(void *),
308 void *child_stack_base, size_t stack_size,
309 int flags, void *arg, pid_t *ptid,
310 void *tls, pid_t *ctid);
311
312 return __clone2(check_is_mount_child, stack, sizeof(buf) / 2,
313 CLONE_NEWNS, a, NULL, NULL, NULL);
314 #else
315 return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
316 #endif
317 }
318
319 static int check_is_mount(const char *last, const char *mnt)
320 {
321 pid_t pid, p;
322 int status;
323 const char *a[2] = { last, mnt };
324
325 pid = clone_newns((void *) a);
326 if (pid == (pid_t) -1) {
327 fprintf(stderr, "%s: failed to clone namespace: %s\n",
328 progname, strerror(errno));
329 return -1;
330 }
331 p = waitpid(pid, &status, __WCLONE);
332 if (p == (pid_t) -1) {
333 fprintf(stderr, "%s: waitpid failed: %s\n",
334 progname, strerror(errno));
335 return -1;
336 }
337 if (!WIFEXITED(status)) {
338 fprintf(stderr, "%s: child terminated abnormally (status %i)\n",
339 progname, status);
340 return -1;
341 }
342 if (WEXITSTATUS(status) != 0)
343 return -1;
344
345 return 0;
346 }
347
348 static int chdir_to_parent(char *copy, const char **lastp)
349 {
350 char *tmp;
351 const char *parent;
352 char buf[65536];
353 int res;
354
355 tmp = strrchr(copy, '/');
356 if (tmp == NULL || tmp[1] == '\0') {
357 fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n",
358 progname, copy);
359 return -1;
360 }
361 if (tmp != copy) {
362 *tmp = '\0';
363 parent = copy;
364 *lastp = tmp + 1;
365 } else if (tmp[1] != '\0') {
366 *lastp = tmp + 1;
367 parent = "/";
368 } else {
369 *lastp = ".";
370 parent = "/";
371 }
372
373 res = chdir(parent);
374 if (res == -1) {
375 fprintf(stderr, "%s: failed to chdir to %s: %s\n",
376 progname, parent, strerror(errno));
377 return -1;
378 }
379
380 if (getcwd(buf, sizeof(buf)) == NULL) {
381 fprintf(stderr, "%s: failed to obtain current directory: %s\n",
382 progname, strerror(errno));
383 return -1;
384 }
385 if (strcmp(buf, parent) != 0) {
386 fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname,
387 parent, buf);
388 return -1;
389
390 }
391
392 return 0;
393 }
394
395 /* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
396 static int umount_nofollow_support(void)
397 {
398 int res = umount2("", UMOUNT_UNUSED);
399 if (res != -1 || errno != EINVAL)
400 return 0;
401
402 res = umount2("", UMOUNT_NOFOLLOW);
403 if (res != -1 || errno != ENOENT)
404 return 0;
405
406 return 1;
407 }
408
409 static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
410 {
411 int res;
412 char *copy;
413 const char *last;
414 int umount_flags = lazy ? UMOUNT_DETACH : 0;
415
416 if (getuid() != 0) {
417 res = may_unmount(mnt, quiet);
418 if (res == -1)
419 return -1;
420 }
421
422 copy = strdup(mnt);
423 if (copy == NULL) {
424 fprintf(stderr, "%s: failed to allocate memory\n", progname);
425 return -1;
426 }
427
428 res = chdir_to_parent(copy, &last);
429 if (res == -1)
430 goto out;
431
432 if (umount_nofollow_support()) {
433 umount_flags |= UMOUNT_NOFOLLOW;
434 } else {
435 res = check_is_mount(last, mnt);
436 if (res == -1)
437 goto out;
438 }
439
440 res = umount2(last, umount_flags);
441 if (res == -1 && !quiet) {
442 fprintf(stderr, "%s: failed to unmount %s: %s\n",
443 progname, mnt, strerror(errno));
444 }
445
446 out:
447 if (res == -1)
448 return -1;
449
450 res = chdir("/");
451 if (res == -1) {
452 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
453 return -1;
454 }
455
456 return fuse_mnt_remove_mount(progname, mnt);
457 }
458
459 static int unmount_fuse(const char *mnt, int quiet, int lazy)
460 {
461 int res;
462 int mtablock = lock_umount();
463
464 res = unmount_fuse_locked(mnt, quiet, lazy);
465 unlock_umount(mtablock);
466
467 return res;
468 }
469
470 static int count_fuse_fs(void)
471 {
472 struct mntent *entp;
473 int count = 0;
474 const char *mtab = _PATH_MOUNTED;
475 FILE *fp = setmntent(mtab, "r");
476 if (fp == NULL) {
477 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
478 strerror(errno));
479 return -1;
480 }
481 while ((entp = getmntent(fp)) != NULL) {
482 if (strcmp(entp->mnt_type, "fuse") == 0 ||
483 strncmp(entp->mnt_type, "fuse.", 5) == 0)
484 count ++;
485 }
486 endmntent(fp);
487 return count;
488 }
489
490
491 #else /* IGNORE_MTAB */
492 static int count_fuse_fs()
493 {
494 return 0;
495 }
496
497 static int add_mount(const char *source, const char *mnt, const char *type,
498 const char *opts)
499 {
500 (void) source;
501 (void) mnt;
502 (void) type;
503 (void) opts;
504 return 0;
505 }
506
507 static int unmount_fuse(const char *mnt, int quiet, int lazy)
508 {
509 return fuse_mnt_umount(progname, mnt, mnt, lazy);
510 }
511 #endif /* IGNORE_MTAB */
512
513 static void strip_line(char *line)
514 {
515 char *s = strchr(line, '#');
516 if (s != NULL)
517 s[0] = '\0';
518 for (s = line + strlen(line) - 1;
519 s >= line && isspace((unsigned char) *s); s--);
520 s[1] = '\0';
521 for (s = line; isspace((unsigned char) *s); s++);
522 if (s != line)
523 memmove(line, s, strlen(s)+1);
524 }
525
526 static void parse_line(char *line, int linenum)
527 {
528 int tmp;
529 if (strcmp(line, "user_allow_other") == 0)
530 user_allow_other = 1;
531 else if (sscanf(line, "mount_max = %i", &tmp) == 1)
532 mount_max = tmp;
533 else if(line[0])
534 fprintf(stderr,
535 "%s: unknown parameter in %s at line %i: '%s'\n",
536 progname, FUSE_CONF, linenum, line);
537 }
538
539 static void read_conf(void)
540 {
541 FILE *fp = fopen(FUSE_CONF, "r");
542 if (fp != NULL) {
543 int linenum = 1;
544 char line[256];
545 int isnewline = 1;
546 while (fgets(line, sizeof(line), fp) != NULL) {
547 if (isnewline) {
548 if (line[strlen(line)-1] == '\n') {
549 strip_line(line);
550 parse_line(line, linenum);
551 } else {
552 isnewline = 0;
553 }
554 } else if(line[strlen(line)-1] == '\n') {
555 fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
556
557 isnewline = 1;
558 }
559 if (isnewline)
560 linenum ++;
561 }
562 if (!isnewline) {
563 fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
564
565 }
566 fclose(fp);
567 } else if (errno != ENOENT) {
568 fprintf(stderr, "%s: failed to open %s: %s\n",
569 progname, FUSE_CONF, strerror(errno));
570 }
571 }
572
573 static int begins_with(const char *s, const char *beg)
574 {
575 if (strncmp(s, beg, strlen(beg)) == 0)
576 return 1;
577 else
578 return 0;
579 }
580
581 struct mount_flags {
582 const char *opt;
583 unsigned long flag;
584 int on;
585 int safe;
586 };
587
588 static struct mount_flags mount_flags[] = {
589 {"rw", MS_RDONLY, 0, 1},
590 {"ro", MS_RDONLY, 1, 1},
591 {"suid", MS_NOSUID, 0, 0},
592 {"nosuid", MS_NOSUID, 1, 1},
593 {"dev", MS_NODEV, 0, 0},
594 {"nodev", MS_NODEV, 1, 1},
595 {"exec", MS_NOEXEC, 0, 1},
596 {"noexec", MS_NOEXEC, 1, 1},
597 {"async", MS_SYNCHRONOUS, 0, 1},
598 {"sync", MS_SYNCHRONOUS, 1, 1},
599 {"atime", MS_NOATIME, 0, 1},
600 {"noatime", MS_NOATIME, 1, 1},
601 {"dirsync", MS_DIRSYNC, 1, 1},
602 {NULL, 0, 0, 0}
603 };
604
605 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
606 {
607 int i;
608
609 for (i = 0; mount_flags[i].opt != NULL; i++) {
610 const char *opt = mount_flags[i].opt;
611 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
612 *on = mount_flags[i].on;
613 *flag = mount_flags[i].flag;
614 if (!mount_flags[i].safe && getuid() != 0) {
615 *flag = 0;
616 fprintf(stderr,
617 "%s: unsafe option %s ignored\n",
618 progname, opt);
619 }
620 return 1;
621 }
622 }
623 return 0;
624 }
625
626 static int add_option(char **optsp, const char *opt, unsigned expand)
627 {
628 char *newopts;
629 if (*optsp == NULL)
630 newopts = strdup(opt);
631 else {
632 unsigned oldsize = strlen(*optsp);
633 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
634 newopts = (char *) realloc(*optsp, newsize);
635 if (newopts)
636 sprintf(newopts + oldsize, ",%s", opt);
637 }
638 if (newopts == NULL) {
639 fprintf(stderr, "%s: failed to allocate memory\n", progname);
640 return -1;
641 }
642 *optsp = newopts;
643 return 0;
644 }
645
646 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
647 {
648 int i;
649 int l;
650
651 if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
652 return -1;
653
654 for (i = 0; mount_flags[i].opt != NULL; i++) {
655 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
656 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
657 return -1;
658 }
659
660 if (add_option(mnt_optsp, opts, 0) == -1)
661 return -1;
662 /* remove comma from end of opts*/
663 l = strlen(*mnt_optsp);
664 if ((*mnt_optsp)[l-1] == ',')
665 (*mnt_optsp)[l-1] = '\0';
666 if (getuid() != 0) {
667 const char *user = get_user_name();
668 if (user == NULL)
669 return -1;
670
671 if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
672 return -1;
673 strcat(*mnt_optsp, user);
674 }
675 return 0;
676 }
677
678 static int opt_eq(const char *s, unsigned len, const char *opt)
679 {
680 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
681 return 1;
682 else
683 return 0;
684 }
685
686 static int get_string_opt(const char *s, unsigned len, const char *opt,
687 char **val)
688 {
689 int i;
690 unsigned opt_len = strlen(opt);
691 char *d;
692
693 if (*val)
694 free(*val);
695 *val = (char *) malloc(len - opt_len + 1);
696 if (!*val) {
697 fprintf(stderr, "%s: failed to allocate memory\n", progname);
698 return 0;
699 }
700
701 d = *val;
702 s += opt_len;
703 len -= opt_len;
704 for (i = 0; i < len; i++) {
705 if (s[i] == '\\' && i + 1 < len)
706 i++;
707 *d++ = s[i];
708 }
709 *d = '\0';
710 return 1;
711 }
712
713 static int do_mount(const char *mnt, char **typep, mode_t rootmode,
714 int fd, const char *opts, const char *dev, char **sourcep,
715 char **mnt_optsp)
716 {
717 int res;
718 int flags = MS_NOSUID | MS_NODEV;
719 char *optbuf;
720 char *mnt_opts = NULL;
721 const char *s;
722 char *d;
723 char *fsname = NULL;
724 char *subtype = NULL;
725 char *source = NULL;
726 char *type = NULL;
727 int blkdev = 0;
728
729 optbuf = (char *) malloc(strlen(opts) + 128);
730 if (!optbuf) {
731 fprintf(stderr, "%s: failed to allocate memory\n", progname);
732 return -1;
733 }
734
735 for (s = opts, d = optbuf; *s;) {
736 unsigned len;
737 const char *fsname_str = "fsname=";
738 const char *subtype_str = "subtype=";
739 for (len = 0; s[len]; len++) {
740 if (s[len] == '\\' && s[len + 1])
741 len++;
742 else if (s[len] == ',')
743 break;
744 }
745 if (begins_with(s, fsname_str)) {
746 if (!get_string_opt(s, len, fsname_str, &fsname))
747 goto err;
748 } else if (begins_with(s, subtype_str)) {
749 if (!get_string_opt(s, len, subtype_str, &subtype))
750 goto err;
751 } else if (opt_eq(s, len, "blkdev")) {
752 if (getuid() != 0) {
753 fprintf(stderr,
754 "%s: option blkdev is privileged\n",
755 progname);
756 goto err;
757 }
758 blkdev = 1;
759 } else if (opt_eq(s, len, "auto_unmount")) {
760 auto_unmount = 1;
761 } else if (!begins_with(s, "fd=") &&
762 !begins_with(s, "rootmode=") &&
763 !begins_with(s, "user_id=") &&
764 !begins_with(s, "group_id=")) {
765 int on;
766 int flag;
767 int skip_option = 0;
768 if (opt_eq(s, len, "large_read")) {
769 struct utsname utsname;
770 unsigned kmaj, kmin;
771 res = uname(&utsname);
772 if (res == 0 &&
773 sscanf(utsname.release, "%u.%u",
774 &kmaj, &kmin) == 2 &&
775 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
776 fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
777 skip_option = 1;
778 }
779 }
780 if (getuid() != 0 && !user_allow_other &&
781 (opt_eq(s, len, "allow_other") ||
782 opt_eq(s, len, "allow_root"))) {
783 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
784 goto err;
785 }
786 if (!skip_option) {
787 if (find_mount_flag(s, len, &on, &flag)) {
788 if (on)
789 flags |= flag;
790 else
791 flags &= ~flag;
792 } else {
793 memcpy(d, s, len);
794 d += len;
795 *d++ = ',';
796 }
797 }
798 }
799 s += len;
800 if (*s)
801 s++;
802 }
803 *d = '\0';
804 res = get_mnt_opts(flags, optbuf, &mnt_opts);
805 if (res == -1)
806 goto err;
807
808 sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
809 fd, rootmode, getuid(), getgid());
810
811 source = malloc((fsname ? strlen(fsname) : 0) +
812 (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
813
814 type = malloc((subtype ? strlen(subtype) : 0) + 32);
815 if (!type || !source) {
816 fprintf(stderr, "%s: failed to allocate memory\n", progname);
817 goto err;
818 }
819
820 if (subtype)
821 sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
822 else
823 strcpy(type, blkdev ? "fuseblk" : "fuse");
824
825 if (fsname)
826 strcpy(source, fsname);
827 else
828 strcpy(source, subtype ? subtype : dev);
829
830 res = mount(source, mnt, type, flags, optbuf);
831 if (res == -1 && errno == ENODEV && subtype) {
832 /* Probably missing subtype support */
833 strcpy(type, blkdev ? "fuseblk" : "fuse");
834 if (fsname) {
835 if (!blkdev)
836 sprintf(source, "%s#%s", subtype, fsname);
837 } else {
838 strcpy(source, type);
839 }
840
841 res = mount(source, mnt, type, flags, optbuf);
842 }
843 if (res == -1 && errno == EINVAL) {
844 /* It could be an old version not supporting group_id */
845 sprintf(d, "fd=%i,rootmode=%o,user_id=%u",
846 fd, rootmode, getuid());
847 res = mount(source, mnt, type, flags, optbuf);
848 }
849 if (res == -1) {
850 int errno_save = errno;
851 if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
852 fprintf(stderr, "%s: 'fuseblk' support missing\n",
853 progname);
854 else
855 fprintf(stderr, "%s: mount failed: %s\n", progname,
856 strerror(errno_save));
857 goto err;
858 }
859 *sourcep = source;
860 *typep = type;
861 *mnt_optsp = mnt_opts;
862 free(fsname);
863 free(optbuf);
864
865 return 0;
866
867 err:
868 free(fsname);
869 free(subtype);
870 free(source);
871 free(type);
872 free(mnt_opts);
873 free(optbuf);
874 return -1;
875 }
876
877 static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
878 {
879 int res;
880 const char *mnt = *mntp;
881 const char *origmnt = mnt;
882
883 res = lstat(mnt, stbuf);
884 if (res == -1) {
885 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
886 progname, mnt, strerror(errno));
887 return -1;
888 }
889
890 /* No permission checking is done for root */
891 if (getuid() == 0)
892 return 0;
893
894 if (S_ISDIR(stbuf->st_mode)) {
895 res = chdir(mnt);
896 if (res == -1) {
897 fprintf(stderr,
898 "%s: failed to chdir to mountpoint: %s\n",
899 progname, strerror(errno));
900 return -1;
901 }
902 mnt = *mntp = ".";
903 res = lstat(mnt, stbuf);
904 if (res == -1) {
905 fprintf(stderr,
906 "%s: failed to access mountpoint %s: %s\n",
907 progname, origmnt, strerror(errno));
908 return -1;
909 }
910
911 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
912 fprintf(stderr, "%s: mountpoint %s not owned by user\n",
913 progname, origmnt);
914 return -1;
915 }
916
917 res = access(mnt, W_OK);
918 if (res == -1) {
919 fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
920 progname, origmnt);
921 return -1;
922 }
923 } else if (S_ISREG(stbuf->st_mode)) {
924 static char procfile[256];
925 *mountpoint_fd = open(mnt, O_WRONLY);
926 if (*mountpoint_fd == -1) {
927 fprintf(stderr, "%s: failed to open %s: %s\n",
928 progname, mnt, strerror(errno));
929 return -1;
930 }
931 res = fstat(*mountpoint_fd, stbuf);
932 if (res == -1) {
933 fprintf(stderr,
934 "%s: failed to access mountpoint %s: %s\n",
935 progname, mnt, strerror(errno));
936 return -1;
937 }
938 if (!S_ISREG(stbuf->st_mode)) {
939 fprintf(stderr,
940 "%s: mountpoint %s is no longer a regular file\n",
941 progname, mnt);
942 return -1;
943 }
944
945 sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
946 *mntp = procfile;
947 } else {
948 fprintf(stderr,
949 "%s: mountpoint %s is not a directory or a regular file\n",
950 progname, mnt);
951 return -1;
952 }
953
954
955 return 0;
956 }
957
958 static int try_open(const char *dev, char **devp, int silent)
959 {
960 int fd = open(dev, O_RDWR);
961 if (fd != -1) {
962 *devp = strdup(dev);
963 if (*devp == NULL) {
964 fprintf(stderr, "%s: failed to allocate memory\n",
965 progname);
966 close(fd);
967 fd = -1;
968 }
969 } else if (errno == ENODEV ||
970 errno == ENOENT)/* check for ENOENT too, for the udev case */
971 return -2;
972 else if (!silent) {
973 fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
974 strerror(errno));
975 }
976 return fd;
977 }
978
979 static int try_open_fuse_device(char **devp)
980 {
981 int fd;
982
983 drop_privs();
984 fd = try_open(FUSE_DEV, devp, 0);
985 restore_privs();
986 return fd;
987 }
988
989 static int open_fuse_device(char **devp)
990 {
991 int fd = try_open_fuse_device(devp);
992 if (fd >= -1)
993 return fd;
994
995 fprintf(stderr,
996 "%s: fuse device not found, try 'modprobe fuse' first\n",
997 progname);
998
999 return -1;
1000 }
1001
1002
1003 static int mount_fuse(const char *mnt, const char *opts)
1004 {
1005 int res;
1006 int fd;
1007 char *dev;
1008 struct stat stbuf;
1009 char *type = NULL;
1010 char *source = NULL;
1011 char *mnt_opts = NULL;
1012 const char *real_mnt = mnt;
1013 int mountpoint_fd = -1;
1014
1015 fd = open_fuse_device(&dev);
1016 if (fd == -1)
1017 return -1;
1018
1019 drop_privs();
1020 read_conf();
1021
1022 if (getuid() != 0 && mount_max != -1) {
1023 int mount_count = count_fuse_fs();
1024 if (mount_count >= mount_max) {
1025 fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
1026 goto fail_close_fd;
1027 }
1028 }
1029
1030 res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1031 restore_privs();
1032 if (res != -1)
1033 res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
1034 fd, opts, dev, &source, &mnt_opts);
1035
1036 if (mountpoint_fd != -1)
1037 close(mountpoint_fd);
1038
1039 if (res == -1)
1040 goto fail_close_fd;
1041
1042 res = chdir("/");
1043 if (res == -1) {
1044 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1045 goto fail_close_fd;
1046 }
1047
1048 if (geteuid() == 0) {
1049 res = add_mount(source, mnt, type, mnt_opts);
1050 if (res == -1) {
1051 /* Can't clean up mount in a non-racy way */
1052 goto fail_close_fd;
1053 }
1054 }
1055
1056 out_free:
1057 free(source);
1058 free(type);
1059 free(mnt_opts);
1060 free(dev);
1061
1062 return fd;
1063
1064 fail_close_fd:
1065 close(fd);
1066 fd = -1;
1067 goto out_free;
1068 }
1069
1070 static int send_fd(int sock_fd, int fd)
1071 {
1072 int retval;
1073 struct msghdr msg;
1074 struct cmsghdr *p_cmsg;
1075 struct iovec vec;
1076 size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
1077 int *p_fds;
1078 char sendchar = 0;
1079
1080 msg.msg_control = cmsgbuf;
1081 msg.msg_controllen = sizeof(cmsgbuf);
1082 p_cmsg = CMSG_FIRSTHDR(&msg);
1083 p_cmsg->cmsg_level = SOL_SOCKET;
1084 p_cmsg->cmsg_type = SCM_RIGHTS;
1085 p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1086 p_fds = (int *) CMSG_DATA(p_cmsg);
1087 *p_fds = fd;
1088 msg.msg_controllen = p_cmsg->cmsg_len;
1089 msg.msg_name = NULL;
1090 msg.msg_namelen = 0;
1091 msg.msg_iov = &vec;
1092 msg.msg_iovlen = 1;
1093 msg.msg_flags = 0;
1094 /* "To pass file descriptors or credentials you need to send/read at
1095 * least one byte" (man 7 unix) */
1096 vec.iov_base = &sendchar;
1097 vec.iov_len = sizeof(sendchar);
1098 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1099 if (retval != 1) {
1100 perror("sending file descriptor");
1101 return -1;
1102 }
1103 return 0;
1104 }
1105
1106 static void usage(void)
1107 {
1108 printf("%s: [options] mountpoint\n"
1109 "Options:\n"
1110 " -h print help\n"
1111 " -V print version\n"
1112 " -o opt[,opt...] mount options\n"
1113 " -u unmount\n"
1114 " -q quiet\n"
1115 " -z lazy unmount\n",
1116 progname);
1117 exit(1);
1118 }
1119
1120 static void show_version(void)
1121 {
1122 printf("fusermount3 version: %s\n", PACKAGE_VERSION);
1123 exit(0);
1124 }
1125
1126 int main(int argc, char *argv[])
1127 {
1128 sigset_t sigset;
1129 int ch;
1130 int fd;
1131 int res;
1132 char *origmnt;
1133 char *mnt;
1134 static int unmount = 0;
1135 static int lazy = 0;
1136 static int quiet = 0;
1137 char *commfd;
1138 int cfd;
1139 const char *opts = "";
1140
1141 static const struct option long_opts[] = {
1142 {"unmount", no_argument, NULL, 'u'},
1143 {"lazy", no_argument, NULL, 'z'},
1144 {"quiet", no_argument, NULL, 'q'},
1145 {"help", no_argument, NULL, 'h'},
1146 {"version", no_argument, NULL, 'V'},
1147 {0, 0, 0, 0}};
1148
1149 progname = strdup(argv[0]);
1150 if (progname == NULL) {
1151 fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1152 exit(1);
1153 }
1154
1155 while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
1156 NULL)) != -1) {
1157 switch (ch) {
1158 case 'h':
1159 usage();
1160 break;
1161
1162 case 'V':
1163 show_version();
1164 break;
1165
1166 case 'o':
1167 opts = optarg;
1168 break;
1169
1170 case 'u':
1171 unmount = 1;
1172 break;
1173
1174 case 'z':
1175 lazy = 1;
1176 break;
1177
1178 case 'q':
1179 quiet = 1;
1180 break;
1181
1182 default:
1183 exit(1);
1184 }
1185 }
1186
1187 if (lazy && !unmount) {
1188 fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1189 exit(1);
1190 }
1191
1192 if (optind >= argc) {
1193 fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1194 exit(1);
1195 } else if (argc > optind + 1) {
1196 fprintf(stderr, "%s: extra arguments after the mountpoint\n",
1197 progname);
1198 exit(1);
1199 }
1200
1201 origmnt = argv[optind];
1202
1203 drop_privs();
1204 mnt = fuse_mnt_resolve_path(progname, origmnt);
1205 if (mnt != NULL) {
1206 res = chdir("/");
1207 if (res == -1) {
1208 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1209 goto err_out;
1210 }
1211 }
1212 restore_privs();
1213 if (mnt == NULL)
1214 exit(1);
1215
1216 umask(033);
1217 if (unmount)
1218 goto do_unmount;
1219
1220 commfd = getenv(FUSE_COMMFD_ENV);
1221 if (commfd == NULL) {
1222 fprintf(stderr, "%s: old style mounting not supported\n",
1223 progname);
1224 goto err_out;
1225 }
1226
1227 fd = mount_fuse(mnt, opts);
1228 if (fd == -1)
1229 goto err_out;
1230
1231 cfd = atoi(commfd);
1232 res = send_fd(cfd, fd);
1233 if (res == -1)
1234 goto err_out;
1235 close(fd);
1236
1237 if (!auto_unmount) {
1238 free(mnt);
1239 return 0;
1240 }
1241
1242 /* Become a daemon and wait for the parent to exit or die.
1243 ie For the control socket to get closed.
1244 btw We don't want to use daemon() function here because
1245 it forks and messes with the file descriptors. */
1246 setsid();
1247 res = chdir("/");
1248 if (res == -1) {
1249 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1250 goto err_out;
1251 }
1252
1253 sigfillset(&sigset);
1254 sigprocmask(SIG_BLOCK, &sigset, NULL);
1255
1256 lazy = 1;
1257 quiet = 1;
1258
1259 while (1) {
1260 unsigned char buf[16];
1261 int n = recv(cfd, buf, sizeof(buf), 0);
1262 if (!n)
1263 break;
1264
1265 if (n < 0) {
1266 if (errno == EINTR)
1267 continue;
1268 break;
1269 }
1270 }
1271
1272 do_unmount:
1273 if (geteuid() == 0)
1274 res = unmount_fuse(mnt, quiet, lazy);
1275 else {
1276 res = umount2(mnt, lazy ? UMOUNT_DETACH : 0);
1277 if (res == -1 && !quiet)
1278 fprintf(stderr,
1279 "%s: failed to unmount %s: %s\n",
1280 progname, mnt, strerror(errno));
1281 }
1282 if (res == -1)
1283 goto err_out;
1284 return 0;
1285
1286 err_out:
1287 free(mnt);
1288 exit(1);
1289 }