libfuse: fuse-3.2.4/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(void)
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 (void) quiet;
510 return fuse_mnt_umount(progname, mnt, mnt, lazy);
511 }
512 #endif /* IGNORE_MTAB */
513
514 static void strip_line(char *line)
515 {
516 char *s = strchr(line, '#');
517 if (s != NULL)
518 s[0] = '\0';
519 for (s = line + strlen(line) - 1;
520 s >= line && isspace((unsigned char) *s); s--);
521 s[1] = '\0';
522 for (s = line; isspace((unsigned char) *s); s++);
523 if (s != line)
524 memmove(line, s, strlen(s)+1);
525 }
526
527 static void parse_line(char *line, int linenum)
528 {
529 int tmp;
530 if (strcmp(line, "user_allow_other") == 0)
531 user_allow_other = 1;
532 else if (sscanf(line, "mount_max = %i", &tmp) == 1)
533 mount_max = tmp;
534 else if(line[0])
535 fprintf(stderr,
536 "%s: unknown parameter in %s at line %i: '%s'\n",
537 progname, FUSE_CONF, linenum, line);
538 }
539
540 static void read_conf(void)
541 {
542 FILE *fp = fopen(FUSE_CONF, "r");
543 if (fp != NULL) {
544 int linenum = 1;
545 char line[256];
546 int isnewline = 1;
547 while (fgets(line, sizeof(line), fp) != NULL) {
548 if (isnewline) {
549 if (line[strlen(line)-1] == '\n') {
550 strip_line(line);
551 parse_line(line, linenum);
552 } else {
553 isnewline = 0;
554 }
555 } else if(line[strlen(line)-1] == '\n') {
556 fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
557
558 isnewline = 1;
559 }
560 if (isnewline)
561 linenum ++;
562 }
563 if (!isnewline) {
564 fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
565
566 }
567 fclose(fp);
568 } else if (errno != ENOENT) {
569 fprintf(stderr, "%s: failed to open %s: %s\n",
570 progname, FUSE_CONF, strerror(errno));
571 }
572 }
573
574 static int begins_with(const char *s, const char *beg)
575 {
576 if (strncmp(s, beg, strlen(beg)) == 0)
577 return 1;
578 else
579 return 0;
580 }
581
582 struct mount_flags {
583 const char *opt;
584 unsigned long flag;
585 int on;
586 int safe;
587 };
588
589 static struct mount_flags mount_flags[] = {
590 {"rw", MS_RDONLY, 0, 1},
591 {"ro", MS_RDONLY, 1, 1},
592 {"suid", MS_NOSUID, 0, 0},
593 {"nosuid", MS_NOSUID, 1, 1},
594 {"dev", MS_NODEV, 0, 0},
595 {"nodev", MS_NODEV, 1, 1},
596 {"exec", MS_NOEXEC, 0, 1},
597 {"noexec", MS_NOEXEC, 1, 1},
598 {"async", MS_SYNCHRONOUS, 0, 1},
599 {"sync", MS_SYNCHRONOUS, 1, 1},
600 {"atime", MS_NOATIME, 0, 1},
601 {"noatime", MS_NOATIME, 1, 1},
602 {"dirsync", MS_DIRSYNC, 1, 1},
603 {NULL, 0, 0, 0}
604 };
605
606 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
607 {
608 int i;
609
610 for (i = 0; mount_flags[i].opt != NULL; i++) {
611 const char *opt = mount_flags[i].opt;
612 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
613 *on = mount_flags[i].on;
614 *flag = mount_flags[i].flag;
615 if (!mount_flags[i].safe && getuid() != 0) {
616 *flag = 0;
617 fprintf(stderr,
618 "%s: unsafe option %s ignored\n",
619 progname, opt);
620 }
621 return 1;
622 }
623 }
624 return 0;
625 }
626
627 static int add_option(char **optsp, const char *opt, unsigned expand)
628 {
629 char *newopts;
630 if (*optsp == NULL)
631 newopts = strdup(opt);
632 else {
633 unsigned oldsize = strlen(*optsp);
634 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
635 newopts = (char *) realloc(*optsp, newsize);
636 if (newopts)
637 sprintf(newopts + oldsize, ",%s", opt);
638 }
639 if (newopts == NULL) {
640 fprintf(stderr, "%s: failed to allocate memory\n", progname);
641 return -1;
642 }
643 *optsp = newopts;
644 return 0;
645 }
646
647 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
648 {
649 int i;
650 int l;
651
652 if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
653 return -1;
654
655 for (i = 0; mount_flags[i].opt != NULL; i++) {
656 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
657 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
658 return -1;
659 }
660
661 if (add_option(mnt_optsp, opts, 0) == -1)
662 return -1;
663 /* remove comma from end of opts*/
664 l = strlen(*mnt_optsp);
665 if ((*mnt_optsp)[l-1] == ',')
666 (*mnt_optsp)[l-1] = '\0';
667 if (getuid() != 0) {
668 const char *user = get_user_name();
669 if (user == NULL)
670 return -1;
671
672 if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
673 return -1;
674 strcat(*mnt_optsp, user);
675 }
676 return 0;
677 }
678
679 static int opt_eq(const char *s, unsigned len, const char *opt)
680 {
681 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
682 return 1;
683 else
684 return 0;
685 }
686
687 static int get_string_opt(const char *s, unsigned len, const char *opt,
688 char **val)
689 {
690 int i;
691 unsigned opt_len = strlen(opt);
692 char *d;
693
694 if (*val)
695 free(*val);
696 *val = (char *) malloc(len - opt_len + 1);
697 if (!*val) {
698 fprintf(stderr, "%s: failed to allocate memory\n", progname);
699 return 0;
700 }
701
702 d = *val;
703 s += opt_len;
704 len -= opt_len;
705 for (i = 0; i < len; i++) {
706 if (s[i] == '\\' && i + 1 < len)
707 i++;
708 *d++ = s[i];
709 }
710 *d = '\0';
711 return 1;
712 }
713
714 static int do_mount(const char *mnt, char **typep, mode_t rootmode,
715 int fd, const char *opts, const char *dev, char **sourcep,
716 char **mnt_optsp)
717 {
718 int res;
719 int flags = MS_NOSUID | MS_NODEV;
720 char *optbuf;
721 char *mnt_opts = NULL;
722 const char *s;
723 char *d;
724 char *fsname = NULL;
725 char *subtype = NULL;
726 char *source = NULL;
727 char *type = NULL;
728 int blkdev = 0;
729
730 optbuf = (char *) malloc(strlen(opts) + 128);
731 if (!optbuf) {
732 fprintf(stderr, "%s: failed to allocate memory\n", progname);
733 return -1;
734 }
735
736 for (s = opts, d = optbuf; *s;) {
737 unsigned len;
738 const char *fsname_str = "fsname=";
739 const char *subtype_str = "subtype=";
740 for (len = 0; s[len]; len++) {
741 if (s[len] == '\\' && s[len + 1])
742 len++;
743 else if (s[len] == ',')
744 break;
745 }
746 if (begins_with(s, fsname_str)) {
747 if (!get_string_opt(s, len, fsname_str, &fsname))
748 goto err;
749 } else if (begins_with(s, subtype_str)) {
750 if (!get_string_opt(s, len, subtype_str, &subtype))
751 goto err;
752 } else if (opt_eq(s, len, "blkdev")) {
753 if (getuid() != 0) {
754 fprintf(stderr,
755 "%s: option blkdev is privileged\n",
756 progname);
757 goto err;
758 }
759 blkdev = 1;
760 } else if (opt_eq(s, len, "auto_unmount")) {
761 auto_unmount = 1;
762 } else if (!begins_with(s, "fd=") &&
763 !begins_with(s, "rootmode=") &&
764 !begins_with(s, "user_id=") &&
765 !begins_with(s, "group_id=")) {
766 int on;
767 int flag;
768 int skip_option = 0;
769 if (opt_eq(s, len, "large_read")) {
770 struct utsname utsname;
771 unsigned kmaj, kmin;
772 res = uname(&utsname);
773 if (res == 0 &&
774 sscanf(utsname.release, "%u.%u",
775 &kmaj, &kmin) == 2 &&
776 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
777 fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
778 skip_option = 1;
779 }
780 }
781 if (getuid() != 0 && !user_allow_other &&
782 (opt_eq(s, len, "allow_other") ||
783 opt_eq(s, len, "allow_root"))) {
784 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
785 goto err;
786 }
787 if (!skip_option) {
788 if (find_mount_flag(s, len, &on, &flag)) {
789 if (on)
790 flags |= flag;
791 else
792 flags &= ~flag;
793 } else {
794 memcpy(d, s, len);
795 d += len;
796 *d++ = ',';
797 }
798 }
799 }
800 s += len;
801 if (*s)
802 s++;
803 }
804 *d = '\0';
805 res = get_mnt_opts(flags, optbuf, &mnt_opts);
806 if (res == -1)
807 goto err;
808
809 sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
810 fd, rootmode, getuid(), getgid());
811
812 source = malloc((fsname ? strlen(fsname) : 0) +
813 (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
814
815 type = malloc((subtype ? strlen(subtype) : 0) + 32);
816 if (!type || !source) {
817 fprintf(stderr, "%s: failed to allocate memory\n", progname);
818 goto err;
819 }
820
821 if (subtype)
822 sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
823 else
824 strcpy(type, blkdev ? "fuseblk" : "fuse");
825
826 if (fsname)
827 strcpy(source, fsname);
828 else
829 strcpy(source, subtype ? subtype : dev);
830
831 res = mount(source, mnt, type, flags, optbuf);
832 if (res == -1 && errno == ENODEV && subtype) {
833 /* Probably missing subtype support */
834 strcpy(type, blkdev ? "fuseblk" : "fuse");
835 if (fsname) {
836 if (!blkdev)
837 sprintf(source, "%s#%s", subtype, fsname);
838 } else {
839 strcpy(source, type);
840 }
841
842 res = mount(source, mnt, type, flags, optbuf);
843 }
844 if (res == -1 && errno == EINVAL) {
845 /* It could be an old version not supporting group_id */
846 sprintf(d, "fd=%i,rootmode=%o,user_id=%u",
847 fd, rootmode, getuid());
848 res = mount(source, mnt, type, flags, optbuf);
849 }
850 if (res == -1) {
851 int errno_save = errno;
852 if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
853 fprintf(stderr, "%s: 'fuseblk' support missing\n",
854 progname);
855 else
856 fprintf(stderr, "%s: mount failed: %s\n", progname,
857 strerror(errno_save));
858 goto err;
859 }
860 *sourcep = source;
861 *typep = type;
862 *mnt_optsp = mnt_opts;
863 free(fsname);
864 free(optbuf);
865
866 return 0;
867
868 err:
869 free(fsname);
870 free(subtype);
871 free(source);
872 free(type);
873 free(mnt_opts);
874 free(optbuf);
875 return -1;
876 }
877
878 static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
879 {
880 int res;
881 const char *mnt = *mntp;
882 const char *origmnt = mnt;
883
884 res = lstat(mnt, stbuf);
885 if (res == -1) {
886 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
887 progname, mnt, strerror(errno));
888 return -1;
889 }
890
891 /* No permission checking is done for root */
892 if (getuid() == 0)
893 return 0;
894
895 if (S_ISDIR(stbuf->st_mode)) {
896 res = chdir(mnt);
897 if (res == -1) {
898 fprintf(stderr,
899 "%s: failed to chdir to mountpoint: %s\n",
900 progname, strerror(errno));
901 return -1;
902 }
903 mnt = *mntp = ".";
904 res = lstat(mnt, stbuf);
905 if (res == -1) {
906 fprintf(stderr,
907 "%s: failed to access mountpoint %s: %s\n",
908 progname, origmnt, strerror(errno));
909 return -1;
910 }
911
912 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
913 fprintf(stderr, "%s: mountpoint %s not owned by user\n",
914 progname, origmnt);
915 return -1;
916 }
917
918 res = access(mnt, W_OK);
919 if (res == -1) {
920 fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
921 progname, origmnt);
922 return -1;
923 }
924 } else if (S_ISREG(stbuf->st_mode)) {
925 static char procfile[256];
926 *mountpoint_fd = open(mnt, O_WRONLY);
927 if (*mountpoint_fd == -1) {
928 fprintf(stderr, "%s: failed to open %s: %s\n",
929 progname, mnt, strerror(errno));
930 return -1;
931 }
932 res = fstat(*mountpoint_fd, stbuf);
933 if (res == -1) {
934 fprintf(stderr,
935 "%s: failed to access mountpoint %s: %s\n",
936 progname, mnt, strerror(errno));
937 return -1;
938 }
939 if (!S_ISREG(stbuf->st_mode)) {
940 fprintf(stderr,
941 "%s: mountpoint %s is no longer a regular file\n",
942 progname, mnt);
943 return -1;
944 }
945
946 sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
947 *mntp = procfile;
948 } else {
949 fprintf(stderr,
950 "%s: mountpoint %s is not a directory or a regular file\n",
951 progname, mnt);
952 return -1;
953 }
954
955
956 return 0;
957 }
958
959 static int try_open(const char *dev, char **devp, int silent)
960 {
961 int fd = open(dev, O_RDWR);
962 if (fd != -1) {
963 *devp = strdup(dev);
964 if (*devp == NULL) {
965 fprintf(stderr, "%s: failed to allocate memory\n",
966 progname);
967 close(fd);
968 fd = -1;
969 }
970 } else if (errno == ENODEV ||
971 errno == ENOENT)/* check for ENOENT too, for the udev case */
972 return -2;
973 else if (!silent) {
974 fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
975 strerror(errno));
976 }
977 return fd;
978 }
979
980 static int try_open_fuse_device(char **devp)
981 {
982 int fd;
983
984 drop_privs();
985 fd = try_open(FUSE_DEV, devp, 0);
986 restore_privs();
987 return fd;
988 }
989
990 static int open_fuse_device(char **devp)
991 {
992 int fd = try_open_fuse_device(devp);
993 if (fd >= -1)
994 return fd;
995
996 fprintf(stderr,
997 "%s: fuse device not found, try 'modprobe fuse' first\n",
998 progname);
999
1000 return -1;
1001 }
1002
1003
1004 static int mount_fuse(const char *mnt, const char *opts)
1005 {
1006 int res;
1007 int fd;
1008 char *dev;
1009 struct stat stbuf;
1010 char *type = NULL;
1011 char *source = NULL;
1012 char *mnt_opts = NULL;
1013 const char *real_mnt = mnt;
1014 int mountpoint_fd = -1;
1015
1016 fd = open_fuse_device(&dev);
1017 if (fd == -1)
1018 return -1;
1019
1020 drop_privs();
1021 read_conf();
1022
1023 if (getuid() != 0 && mount_max != -1) {
1024 int mount_count = count_fuse_fs();
1025 if (mount_count >= mount_max) {
1026 fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
1027 goto fail_close_fd;
1028 }
1029 }
1030
1031 res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1032 restore_privs();
1033 if (res != -1)
1034 res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
1035 fd, opts, dev, &source, &mnt_opts);
1036
1037 if (mountpoint_fd != -1)
1038 close(mountpoint_fd);
1039
1040 if (res == -1)
1041 goto fail_close_fd;
1042
1043 res = chdir("/");
1044 if (res == -1) {
1045 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1046 goto fail_close_fd;
1047 }
1048
1049 if (geteuid() == 0) {
1050 res = add_mount(source, mnt, type, mnt_opts);
1051 if (res == -1) {
1052 /* Can't clean up mount in a non-racy way */
1053 goto fail_close_fd;
1054 }
1055 }
1056
1057 out_free:
1058 free(source);
1059 free(type);
1060 free(mnt_opts);
1061 free(dev);
1062
1063 return fd;
1064
1065 fail_close_fd:
1066 close(fd);
1067 fd = -1;
1068 goto out_free;
1069 }
1070
1071 static int send_fd(int sock_fd, int fd)
1072 {
1073 int retval;
1074 struct msghdr msg;
1075 struct cmsghdr *p_cmsg;
1076 struct iovec vec;
1077 size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
1078 int *p_fds;
1079 char sendchar = 0;
1080
1081 msg.msg_control = cmsgbuf;
1082 msg.msg_controllen = sizeof(cmsgbuf);
1083 p_cmsg = CMSG_FIRSTHDR(&msg);
1084 p_cmsg->cmsg_level = SOL_SOCKET;
1085 p_cmsg->cmsg_type = SCM_RIGHTS;
1086 p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1087 p_fds = (int *) CMSG_DATA(p_cmsg);
1088 *p_fds = fd;
1089 msg.msg_controllen = p_cmsg->cmsg_len;
1090 msg.msg_name = NULL;
1091 msg.msg_namelen = 0;
1092 msg.msg_iov = &vec;
1093 msg.msg_iovlen = 1;
1094 msg.msg_flags = 0;
1095 /* "To pass file descriptors or credentials you need to send/read at
1096 * least one byte" (man 7 unix) */
1097 vec.iov_base = &sendchar;
1098 vec.iov_len = sizeof(sendchar);
1099 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1100 if (retval != 1) {
1101 perror("sending file descriptor");
1102 return -1;
1103 }
1104 return 0;
1105 }
1106
1107 static void usage(void)
1108 {
1109 printf("%s: [options] mountpoint\n"
1110 "Options:\n"
1111 " -h print help\n"
1112 " -V print version\n"
1113 " -o opt[,opt...] mount options\n"
1114 " -u unmount\n"
1115 " -q quiet\n"
1116 " -z lazy unmount\n",
1117 progname);
1118 exit(1);
1119 }
1120
1121 static void show_version(void)
1122 {
1123 printf("fusermount3 version: %s\n", PACKAGE_VERSION);
1124 exit(0);
1125 }
1126
1127 int main(int argc, char *argv[])
1128 {
1129 sigset_t sigset;
1130 int ch;
1131 int fd;
1132 int res;
1133 char *origmnt;
1134 char *mnt;
1135 static int unmount = 0;
1136 static int lazy = 0;
1137 static int quiet = 0;
1138 char *commfd;
1139 int cfd;
1140 const char *opts = "";
1141
1142 static const struct option long_opts[] = {
1143 {"unmount", no_argument, NULL, 'u'},
1144 {"lazy", no_argument, NULL, 'z'},
1145 {"quiet", no_argument, NULL, 'q'},
1146 {"help", no_argument, NULL, 'h'},
1147 {"version", no_argument, NULL, 'V'},
1148 {0, 0, 0, 0}};
1149
1150 progname = strdup(argv[0]);
1151 if (progname == NULL) {
1152 fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1153 exit(1);
1154 }
1155
1156 while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
1157 NULL)) != -1) {
1158 switch (ch) {
1159 case 'h':
1160 usage();
1161 break;
1162
1163 case 'V':
1164 show_version();
1165 break;
1166
1167 case 'o':
1168 opts = optarg;
1169 break;
1170
1171 case 'u':
1172 unmount = 1;
1173 break;
1174
1175 case 'z':
1176 lazy = 1;
1177 break;
1178
1179 case 'q':
1180 quiet = 1;
1181 break;
1182
1183 default:
1184 exit(1);
1185 }
1186 }
1187
1188 if (lazy && !unmount) {
1189 fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1190 exit(1);
1191 }
1192
1193 if (optind >= argc) {
1194 fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1195 exit(1);
1196 } else if (argc > optind + 1) {
1197 fprintf(stderr, "%s: extra arguments after the mountpoint\n",
1198 progname);
1199 exit(1);
1200 }
1201
1202 origmnt = argv[optind];
1203
1204 drop_privs();
1205 mnt = fuse_mnt_resolve_path(progname, origmnt);
1206 if (mnt != NULL) {
1207 res = chdir("/");
1208 if (res == -1) {
1209 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1210 goto err_out;
1211 }
1212 }
1213 restore_privs();
1214 if (mnt == NULL)
1215 exit(1);
1216
1217 umask(033);
1218 if (unmount)
1219 goto do_unmount;
1220
1221 commfd = getenv(FUSE_COMMFD_ENV);
1222 if (commfd == NULL) {
1223 fprintf(stderr, "%s: old style mounting not supported\n",
1224 progname);
1225 goto err_out;
1226 }
1227
1228 fd = mount_fuse(mnt, opts);
1229 if (fd == -1)
1230 goto err_out;
1231
1232 cfd = atoi(commfd);
1233 res = send_fd(cfd, fd);
1234 if (res == -1)
1235 goto err_out;
1236 close(fd);
1237
1238 if (!auto_unmount) {
1239 free(mnt);
1240 return 0;
1241 }
1242
1243 /* Become a daemon and wait for the parent to exit or die.
1244 ie For the control socket to get closed.
1245 btw We don't want to use daemon() function here because
1246 it forks and messes with the file descriptors. */
1247 setsid();
1248 res = chdir("/");
1249 if (res == -1) {
1250 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1251 goto err_out;
1252 }
1253
1254 sigfillset(&sigset);
1255 sigprocmask(SIG_BLOCK, &sigset, NULL);
1256
1257 lazy = 1;
1258 quiet = 1;
1259
1260 while (1) {
1261 unsigned char buf[16];
1262 int n = recv(cfd, buf, sizeof(buf), 0);
1263 if (!n)
1264 break;
1265
1266 if (n < 0) {
1267 if (errno == EINTR)
1268 continue;
1269 break;
1270 }
1271 }
1272
1273 do_unmount:
1274 if (geteuid() == 0)
1275 res = unmount_fuse(mnt, quiet, lazy);
1276 else {
1277 res = umount2(mnt, lazy ? UMOUNT_DETACH : 0);
1278 if (res == -1 && !quiet)
1279 fprintf(stderr,
1280 "%s: failed to unmount %s: %s\n",
1281 progname, mnt, strerror(errno));
1282 }
1283 if (res == -1)
1284 goto err_out;
1285 return 0;
1286
1287 err_out:
1288 free(mnt);
1289 exit(1);
1290 }