libfuse: refcount fuse_chan objects
[fuse.git] / util / fusermount.c
blobb226fbddb815b0eb0f2972db24d40aedb1b43328
1 /*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
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 */
10 #define _GNU_SOURCE /* for clone */
11 #include <config.h>
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>
33 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
35 #define FUSE_DEV_OLD "/proc/fs/fuse/dev"
36 #define FUSE_DEV_NEW "/dev/fuse"
37 #define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
38 #define FUSE_CONF "/etc/fuse.conf"
40 #ifndef MS_DIRSYNC
41 #define MS_DIRSYNC 128
42 #endif
43 #ifndef MS_REC
44 #define MS_REC 16384
45 #endif
46 #ifndef MS_PRIVATE
47 #define MS_PRIVATE (1<<18)
48 #endif
50 #ifndef UMOUNT_DETACH
51 #define UMOUNT_DETACH 0x00000002 /* Just detach from the tree */
52 #endif
53 #ifndef UMOUNT_NOFOLLOW
54 #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
55 #endif
56 #ifndef UMOUNT_UNUSED
57 #define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
58 #endif
60 static const char *progname;
62 static int user_allow_other = 0;
63 static int mount_max = 1000;
65 static int auto_unmount = 0;
67 static const char *get_user_name(void)
69 struct passwd *pw = getpwuid(getuid());
70 if (pw != NULL && pw->pw_name != NULL)
71 return pw->pw_name;
72 else {
73 fprintf(stderr, "%s: could not determine username\n", progname);
74 return NULL;
78 static uid_t oldfsuid;
79 static gid_t oldfsgid;
81 static void drop_privs(void)
83 if (getuid() != 0) {
84 oldfsuid = setfsuid(getuid());
85 oldfsgid = setfsgid(getgid());
89 static void restore_privs(void)
91 if (getuid() != 0) {
92 setfsuid(oldfsuid);
93 setfsgid(oldfsgid);
97 #ifndef IGNORE_MTAB
99 * Make sure that /etc/mtab is checked and updated atomically
101 static int lock_umount(void)
103 const char *mtab_lock = _PATH_MOUNTED ".fuselock";
104 int mtablock;
105 int res;
106 struct stat mtab_stat;
108 /* /etc/mtab could be a symlink to /proc/mounts */
109 if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
110 return -1;
112 mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
113 if (mtablock == -1) {
114 fprintf(stderr, "%s: unable to open fuse lock file: %s\n",
115 progname, strerror(errno));
116 return -1;
118 res = lockf(mtablock, F_LOCK, 0);
119 if (res < 0) {
120 fprintf(stderr, "%s: error getting lock: %s\n", progname,
121 strerror(errno));
122 close(mtablock);
123 return -1;
126 return mtablock;
129 static void unlock_umount(int mtablock)
131 if (mtablock >= 0) {
132 int res;
134 res = lockf(mtablock, F_ULOCK, 0);
135 if (res < 0) {
136 fprintf(stderr, "%s: error releasing lock: %s\n",
137 progname, strerror(errno));
139 close(mtablock);
143 static int add_mount(const char *source, const char *mnt, const char *type,
144 const char *opts)
146 return fuse_mnt_add_mount(progname, source, mnt, type, opts);
149 static int may_unmount(const char *mnt, int quiet)
151 struct mntent *entp;
152 FILE *fp;
153 const char *user = NULL;
154 char uidstr[32];
155 unsigned uidlen = 0;
156 int found;
157 const char *mtab = _PATH_MOUNTED;
159 user = get_user_name();
160 if (user == NULL)
161 return -1;
163 fp = setmntent(mtab, "r");
164 if (fp == NULL) {
165 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
166 strerror(errno));
167 return -1;
170 uidlen = sprintf(uidstr, "%u", getuid());
172 found = 0;
173 while ((entp = getmntent(fp)) != NULL) {
174 if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
175 (strcmp(entp->mnt_type, "fuse") == 0 ||
176 strcmp(entp->mnt_type, "fuseblk") == 0 ||
177 strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
178 strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
179 char *p = strstr(entp->mnt_opts, "user=");
180 if (p &&
181 (p == entp->mnt_opts || *(p-1) == ',') &&
182 strcmp(p + 5, user) == 0) {
183 found = 1;
184 break;
186 /* /etc/mtab is a link pointing to
187 /proc/mounts: */
188 else if ((p =
189 strstr(entp->mnt_opts, "user_id=")) &&
190 (p == entp->mnt_opts ||
191 *(p-1) == ',') &&
192 strncmp(p + 8, uidstr, uidlen) == 0 &&
193 (*(p+8+uidlen) == ',' ||
194 *(p+8+uidlen) == '\0')) {
195 found = 1;
196 break;
200 endmntent(fp);
202 if (!found) {
203 if (!quiet)
204 fprintf(stderr,
205 "%s: entry for %s not found in %s\n",
206 progname, mnt, mtab);
207 return -1;
210 return 0;
214 * Check whether the file specified in "fusermount -u" is really a
215 * mountpoint and not a symlink. This is necessary otherwise the user
216 * could move the mountpoint away and replace it with a symlink
217 * pointing to an arbitrary mount, thereby tricking fusermount into
218 * unmounting that (umount(2) will follow symlinks).
220 * This is the child process running in a separate mount namespace, so
221 * we don't mess with the global namespace and if the process is
222 * killed for any reason, mounts are automatically cleaned up.
224 * First make sure nothing is propagated back into the parent
225 * namespace by marking all mounts "private".
227 * Then bind mount parent onto a stable base where the user can't move
228 * it around.
230 * Finally check /proc/mounts for an entry matching the requested
231 * mountpoint. If it's found then we are OK, and the user can't move
232 * it around within the parent directory as rename() will return
233 * EBUSY. Be careful to ignore any mounts that existed before the
234 * bind.
236 static int check_is_mount_child(void *p)
238 const char **a = p;
239 const char *last = a[0];
240 const char *mnt = a[1];
241 int res;
242 const char *procmounts = "/proc/mounts";
243 int found;
244 FILE *fp;
245 struct mntent *entp;
246 int count;
248 res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL);
249 if (res == -1) {
250 fprintf(stderr, "%s: failed to mark mounts private: %s\n",
251 progname, strerror(errno));
252 return 1;
255 fp = setmntent(procmounts, "r");
256 if (fp == NULL) {
257 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
258 procmounts, strerror(errno));
259 return 1;
262 count = 0;
263 while (getmntent(fp) != NULL)
264 count++;
265 endmntent(fp);
267 fp = setmntent(procmounts, "r");
268 if (fp == NULL) {
269 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
270 procmounts, strerror(errno));
271 return 1;
274 res = mount(".", "/", "", MS_BIND | MS_REC, NULL);
275 if (res == -1) {
276 fprintf(stderr, "%s: failed to bind parent to /: %s\n",
277 progname, strerror(errno));
278 return 1;
281 found = 0;
282 while ((entp = getmntent(fp)) != NULL) {
283 if (count > 0) {
284 count--;
285 continue;
287 if (entp->mnt_dir[0] == '/' &&
288 strcmp(entp->mnt_dir + 1, last) == 0) {
289 found = 1;
290 break;
293 endmntent(fp);
295 if (!found) {
296 fprintf(stderr, "%s: %s not mounted\n", progname, mnt);
297 return 1;
300 return 0;
303 static pid_t clone_newns(void *a)
305 char buf[131072];
306 char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15));
308 #ifdef __ia64__
309 extern int __clone2(int (*fn)(void *),
310 void *child_stack_base, size_t stack_size,
311 int flags, void *arg, pid_t *ptid,
312 void *tls, pid_t *ctid);
314 return __clone2(check_is_mount_child, stack, sizeof(buf) / 2,
315 CLONE_NEWNS, a, NULL, NULL, NULL);
316 #else
317 return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
318 #endif
321 static int check_is_mount(const char *last, const char *mnt)
323 pid_t pid, p;
324 int status;
325 const char *a[2] = { last, mnt };
327 pid = clone_newns((void *) a);
328 if (pid == (pid_t) -1) {
329 fprintf(stderr, "%s: failed to clone namespace: %s\n",
330 progname, strerror(errno));
331 return -1;
333 p = waitpid(pid, &status, __WCLONE);
334 if (p == (pid_t) -1) {
335 fprintf(stderr, "%s: waitpid failed: %s\n",
336 progname, strerror(errno));
337 return -1;
339 if (!WIFEXITED(status)) {
340 fprintf(stderr, "%s: child terminated abnormally (status %i)\n",
341 progname, status);
342 return -1;
344 if (WEXITSTATUS(status) != 0)
345 return -1;
347 return 0;
350 static int chdir_to_parent(char *copy, const char **lastp)
352 char *tmp;
353 const char *parent;
354 char buf[65536];
355 int res;
357 tmp = strrchr(copy, '/');
358 if (tmp == NULL || tmp[1] == '\0') {
359 fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n",
360 progname, copy);
361 return -1;
363 if (tmp != copy) {
364 *tmp = '\0';
365 parent = copy;
366 *lastp = tmp + 1;
367 } else if (tmp[1] != '\0') {
368 *lastp = tmp + 1;
369 parent = "/";
370 } else {
371 *lastp = ".";
372 parent = "/";
375 res = chdir(parent);
376 if (res == -1) {
377 fprintf(stderr, "%s: failed to chdir to %s: %s\n",
378 progname, parent, strerror(errno));
379 return -1;
382 if (getcwd(buf, sizeof(buf)) == NULL) {
383 fprintf(stderr, "%s: failed to obtain current directory: %s\n",
384 progname, strerror(errno));
385 return -1;
387 if (strcmp(buf, parent) != 0) {
388 fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname,
389 parent, buf);
390 return -1;
394 return 0;
397 /* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
398 static int umount_nofollow_support(void)
400 int res = umount2("", UMOUNT_UNUSED);
401 if (res != -1 || errno != EINVAL)
402 return 0;
404 res = umount2("", UMOUNT_NOFOLLOW);
405 if (res != -1 || errno != ENOENT)
406 return 0;
408 return 1;
411 static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
413 int res;
414 char *copy;
415 const char *last;
416 int umount_flags = lazy ? UMOUNT_DETACH : 0;
418 if (getuid() != 0) {
419 res = may_unmount(mnt, quiet);
420 if (res == -1)
421 return -1;
424 copy = strdup(mnt);
425 if (copy == NULL) {
426 fprintf(stderr, "%s: failed to allocate memory\n", progname);
427 return -1;
430 res = chdir_to_parent(copy, &last);
431 if (res == -1)
432 goto out;
434 if (umount_nofollow_support()) {
435 umount_flags |= UMOUNT_NOFOLLOW;
436 } else {
437 res = check_is_mount(last, mnt);
438 if (res == -1)
439 goto out;
442 res = umount2(last, umount_flags);
443 if (res == -1 && !quiet) {
444 fprintf(stderr, "%s: failed to unmount %s: %s\n",
445 progname, mnt, strerror(errno));
448 out:
449 if (res == -1)
450 return -1;
452 res = chdir("/");
453 if (res == -1) {
454 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
455 return -1;
458 return fuse_mnt_remove_mount(progname, mnt);
461 static int unmount_fuse(const char *mnt, int quiet, int lazy)
463 int res;
464 int mtablock = lock_umount();
466 res = unmount_fuse_locked(mnt, quiet, lazy);
467 unlock_umount(mtablock);
469 return res;
472 static int count_fuse_fs(void)
474 struct mntent *entp;
475 int count = 0;
476 const char *mtab = _PATH_MOUNTED;
477 FILE *fp = setmntent(mtab, "r");
478 if (fp == NULL) {
479 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
480 strerror(errno));
481 return -1;
483 while ((entp = getmntent(fp)) != NULL) {
484 if (strcmp(entp->mnt_type, "fuse") == 0 ||
485 strncmp(entp->mnt_type, "fuse.", 5) == 0)
486 count ++;
488 endmntent(fp);
489 return count;
493 #else /* IGNORE_MTAB */
494 static int count_fuse_fs()
496 return 0;
499 static int add_mount(const char *source, const char *mnt, const char *type,
500 const char *opts)
502 (void) source;
503 (void) mnt;
504 (void) type;
505 (void) opts;
506 return 0;
509 static int unmount_fuse(const char *mnt, int quiet, int lazy)
511 return fuse_mnt_umount(progname, mnt, mnt, lazy);
513 #endif /* IGNORE_MTAB */
515 static void strip_line(char *line)
517 char *s = strchr(line, '#');
518 if (s != NULL)
519 s[0] = '\0';
520 for (s = line + strlen(line) - 1;
521 s >= line && isspace((unsigned char) *s); s--);
522 s[1] = '\0';
523 for (s = line; isspace((unsigned char) *s); s++);
524 if (s != line)
525 memmove(line, s, strlen(s)+1);
528 static void parse_line(char *line, int linenum)
530 int tmp;
531 if (strcmp(line, "user_allow_other") == 0)
532 user_allow_other = 1;
533 else if (sscanf(line, "mount_max = %i", &tmp) == 1)
534 mount_max = tmp;
535 else if(line[0])
536 fprintf(stderr,
537 "%s: unknown parameter in %s at line %i: '%s'\n",
538 progname, FUSE_CONF, linenum, line);
541 static void read_conf(void)
543 FILE *fp = fopen(FUSE_CONF, "r");
544 if (fp != NULL) {
545 int linenum = 1;
546 char line[256];
547 int isnewline = 1;
548 while (fgets(line, sizeof(line), fp) != NULL) {
549 if (isnewline) {
550 if (line[strlen(line)-1] == '\n') {
551 strip_line(line);
552 parse_line(line, linenum);
553 } else {
554 isnewline = 0;
556 } else if(line[strlen(line)-1] == '\n') {
557 fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
559 isnewline = 1;
561 if (isnewline)
562 linenum ++;
564 if (!isnewline) {
565 fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
568 fclose(fp);
569 } else if (errno != ENOENT) {
570 fprintf(stderr, "%s: failed to open %s: %s\n",
571 progname, FUSE_CONF, strerror(errno));
575 static int begins_with(const char *s, const char *beg)
577 if (strncmp(s, beg, strlen(beg)) == 0)
578 return 1;
579 else
580 return 0;
583 struct mount_flags {
584 const char *opt;
585 unsigned long flag;
586 int on;
587 int safe;
590 static struct mount_flags mount_flags[] = {
591 {"rw", MS_RDONLY, 0, 1},
592 {"ro", MS_RDONLY, 1, 1},
593 {"suid", MS_NOSUID, 0, 0},
594 {"nosuid", MS_NOSUID, 1, 1},
595 {"dev", MS_NODEV, 0, 0},
596 {"nodev", MS_NODEV, 1, 1},
597 {"exec", MS_NOEXEC, 0, 1},
598 {"noexec", MS_NOEXEC, 1, 1},
599 {"async", MS_SYNCHRONOUS, 0, 1},
600 {"sync", MS_SYNCHRONOUS, 1, 1},
601 {"atime", MS_NOATIME, 0, 1},
602 {"noatime", MS_NOATIME, 1, 1},
603 {"dirsync", MS_DIRSYNC, 1, 1},
604 {NULL, 0, 0, 0}
607 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
609 int i;
611 for (i = 0; mount_flags[i].opt != NULL; i++) {
612 const char *opt = mount_flags[i].opt;
613 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
614 *on = mount_flags[i].on;
615 *flag = mount_flags[i].flag;
616 if (!mount_flags[i].safe && getuid() != 0) {
617 *flag = 0;
618 fprintf(stderr,
619 "%s: unsafe option %s ignored\n",
620 progname, opt);
622 return 1;
625 return 0;
628 static int add_option(char **optsp, const char *opt, unsigned expand)
630 char *newopts;
631 if (*optsp == NULL)
632 newopts = strdup(opt);
633 else {
634 unsigned oldsize = strlen(*optsp);
635 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
636 newopts = (char *) realloc(*optsp, newsize);
637 if (newopts)
638 sprintf(newopts + oldsize, ",%s", opt);
640 if (newopts == NULL) {
641 fprintf(stderr, "%s: failed to allocate memory\n", progname);
642 return -1;
644 *optsp = newopts;
645 return 0;
648 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
650 int i;
651 int l;
653 if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
654 return -1;
656 for (i = 0; mount_flags[i].opt != NULL; i++) {
657 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
658 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
659 return -1;
662 if (add_option(mnt_optsp, opts, 0) == -1)
663 return -1;
664 /* remove comma from end of opts*/
665 l = strlen(*mnt_optsp);
666 if ((*mnt_optsp)[l-1] == ',')
667 (*mnt_optsp)[l-1] = '\0';
668 if (getuid() != 0) {
669 const char *user = get_user_name();
670 if (user == NULL)
671 return -1;
673 if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
674 return -1;
675 strcat(*mnt_optsp, user);
677 return 0;
680 static int opt_eq(const char *s, unsigned len, const char *opt)
682 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
683 return 1;
684 else
685 return 0;
688 static int get_string_opt(const char *s, unsigned len, const char *opt,
689 char **val)
691 int i;
692 unsigned opt_len = strlen(opt);
693 char *d;
695 if (*val)
696 free(*val);
697 *val = (char *) malloc(len - opt_len + 1);
698 if (!*val) {
699 fprintf(stderr, "%s: failed to allocate memory\n", progname);
700 return 0;
703 d = *val;
704 s += opt_len;
705 len -= opt_len;
706 for (i = 0; i < len; i++) {
707 if (s[i] == '\\' && i + 1 < len)
708 i++;
709 *d++ = s[i];
711 *d = '\0';
712 return 1;
715 static int do_mount(const char *mnt, char **typep, mode_t rootmode,
716 int fd, const char *opts, const char *dev, char **sourcep,
717 char **mnt_optsp, off_t rootsize)
719 int res;
720 int flags = MS_NOSUID | MS_NODEV;
721 char *optbuf;
722 char *mnt_opts = NULL;
723 const char *s;
724 char *d;
725 char *fsname = NULL;
726 char *subtype = NULL;
727 char *source = NULL;
728 char *type = NULL;
729 int check_empty = 1;
730 int blkdev = 0;
732 optbuf = (char *) malloc(strlen(opts) + 128);
733 if (!optbuf) {
734 fprintf(stderr, "%s: failed to allocate memory\n", progname);
735 return -1;
738 for (s = opts, d = optbuf; *s;) {
739 unsigned len;
740 const char *fsname_str = "fsname=";
741 const char *subtype_str = "subtype=";
742 for (len = 0; s[len]; len++) {
743 if (s[len] == '\\' && s[len + 1])
744 len++;
745 else if (s[len] == ',')
746 break;
748 if (begins_with(s, fsname_str)) {
749 if (!get_string_opt(s, len, fsname_str, &fsname))
750 goto err;
751 } else if (begins_with(s, subtype_str)) {
752 if (!get_string_opt(s, len, subtype_str, &subtype))
753 goto err;
754 } else if (opt_eq(s, len, "blkdev")) {
755 if (getuid() != 0) {
756 fprintf(stderr,
757 "%s: option blkdev is privileged\n",
758 progname);
759 goto err;
761 blkdev = 1;
762 } else if (opt_eq(s, len, "nonempty")) {
763 check_empty = 0;
764 } else if (opt_eq(s, len, "auto_unmount")) {
765 auto_unmount = 1;
766 } else if (!begins_with(s, "fd=") &&
767 !begins_with(s, "rootmode=") &&
768 !begins_with(s, "user_id=") &&
769 !begins_with(s, "group_id=")) {
770 int on;
771 int flag;
772 int skip_option = 0;
773 if (opt_eq(s, len, "large_read")) {
774 struct utsname utsname;
775 unsigned kmaj, kmin;
776 res = uname(&utsname);
777 if (res == 0 &&
778 sscanf(utsname.release, "%u.%u",
779 &kmaj, &kmin) == 2 &&
780 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
781 fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
782 skip_option = 1;
785 if (getuid() != 0 && !user_allow_other &&
786 (opt_eq(s, len, "allow_other") ||
787 opt_eq(s, len, "allow_root"))) {
788 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
789 goto err;
791 if (!skip_option) {
792 if (find_mount_flag(s, len, &on, &flag)) {
793 if (on)
794 flags |= flag;
795 else
796 flags &= ~flag;
797 } else {
798 memcpy(d, s, len);
799 d += len;
800 *d++ = ',';
804 s += len;
805 if (*s)
806 s++;
808 *d = '\0';
809 res = get_mnt_opts(flags, optbuf, &mnt_opts);
810 if (res == -1)
811 goto err;
813 sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
814 fd, rootmode, getuid(), getgid());
816 if (check_empty &&
817 fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1)
818 goto err;
820 source = malloc((fsname ? strlen(fsname) : 0) +
821 (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
823 type = malloc((subtype ? strlen(subtype) : 0) + 32);
824 if (!type || !source) {
825 fprintf(stderr, "%s: failed to allocate memory\n", progname);
826 goto err;
829 if (subtype)
830 sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
831 else
832 strcpy(type, blkdev ? "fuseblk" : "fuse");
834 if (fsname)
835 strcpy(source, fsname);
836 else
837 strcpy(source, subtype ? subtype : dev);
839 res = mount(source, mnt, type, flags, optbuf);
840 if (res == -1 && errno == ENODEV && subtype) {
841 /* Probably missing subtype support */
842 strcpy(type, blkdev ? "fuseblk" : "fuse");
843 if (fsname) {
844 if (!blkdev)
845 sprintf(source, "%s#%s", subtype, fsname);
846 } else {
847 strcpy(source, type);
850 res = mount(source, mnt, type, flags, optbuf);
852 if (res == -1 && errno == EINVAL) {
853 /* It could be an old version not supporting group_id */
854 sprintf(d, "fd=%i,rootmode=%o,user_id=%u",
855 fd, rootmode, getuid());
856 res = mount(source, mnt, type, flags, optbuf);
858 if (res == -1) {
859 int errno_save = errno;
860 if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
861 fprintf(stderr, "%s: 'fuseblk' support missing\n",
862 progname);
863 else
864 fprintf(stderr, "%s: mount failed: %s\n", progname,
865 strerror(errno_save));
866 goto err;
868 *sourcep = source;
869 *typep = type;
870 *mnt_optsp = mnt_opts;
871 free(fsname);
872 free(optbuf);
874 return 0;
876 err:
877 free(fsname);
878 free(subtype);
879 free(source);
880 free(type);
881 free(mnt_opts);
882 free(optbuf);
883 return -1;
886 static int check_version(const char *dev)
888 int res;
889 int majorver;
890 int minorver;
891 const char *version_file;
892 FILE *vf;
894 if (strcmp(dev, FUSE_DEV_OLD) != 0)
895 return 0;
897 version_file = FUSE_VERSION_FILE_OLD;
898 vf = fopen(version_file, "r");
899 if (vf == NULL) {
900 fprintf(stderr, "%s: kernel interface too old\n", progname);
901 return -1;
903 res = fscanf(vf, "%i.%i", &majorver, &minorver);
904 fclose(vf);
905 if (res != 2) {
906 fprintf(stderr, "%s: error reading %s\n", progname,
907 version_file);
908 return -1;
910 if (majorver < 3) {
911 fprintf(stderr, "%s: kernel interface too old\n", progname);
912 return -1;
914 return 0;
917 static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
919 int res;
920 const char *mnt = *mntp;
921 const char *origmnt = mnt;
923 res = lstat(mnt, stbuf);
924 if (res == -1) {
925 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
926 progname, mnt, strerror(errno));
927 return -1;
930 /* No permission checking is done for root */
931 if (getuid() == 0)
932 return 0;
934 if (S_ISDIR(stbuf->st_mode)) {
935 res = chdir(mnt);
936 if (res == -1) {
937 fprintf(stderr,
938 "%s: failed to chdir to mountpoint: %s\n",
939 progname, strerror(errno));
940 return -1;
942 mnt = *mntp = ".";
943 res = lstat(mnt, stbuf);
944 if (res == -1) {
945 fprintf(stderr,
946 "%s: failed to access mountpoint %s: %s\n",
947 progname, origmnt, strerror(errno));
948 return -1;
951 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
952 fprintf(stderr, "%s: mountpoint %s not owned by user\n",
953 progname, origmnt);
954 return -1;
957 res = access(mnt, W_OK);
958 if (res == -1) {
959 fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
960 progname, origmnt);
961 return -1;
963 } else if (S_ISREG(stbuf->st_mode)) {
964 static char procfile[256];
965 *mountpoint_fd = open(mnt, O_WRONLY);
966 if (*mountpoint_fd == -1) {
967 fprintf(stderr, "%s: failed to open %s: %s\n",
968 progname, mnt, strerror(errno));
969 return -1;
971 res = fstat(*mountpoint_fd, stbuf);
972 if (res == -1) {
973 fprintf(stderr,
974 "%s: failed to access mountpoint %s: %s\n",
975 progname, mnt, strerror(errno));
976 return -1;
978 if (!S_ISREG(stbuf->st_mode)) {
979 fprintf(stderr,
980 "%s: mountpoint %s is no longer a regular file\n",
981 progname, mnt);
982 return -1;
985 sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
986 *mntp = procfile;
987 } else {
988 fprintf(stderr,
989 "%s: mountpoint %s is not a directory or a regular file\n",
990 progname, mnt);
991 return -1;
995 return 0;
998 static int try_open(const char *dev, char **devp, int silent)
1000 int fd = open(dev, O_RDWR);
1001 if (fd != -1) {
1002 *devp = strdup(dev);
1003 if (*devp == NULL) {
1004 fprintf(stderr, "%s: failed to allocate memory\n",
1005 progname);
1006 close(fd);
1007 fd = -1;
1009 } else if (errno == ENODEV ||
1010 errno == ENOENT)/* check for ENOENT too, for the udev case */
1011 return -2;
1012 else if (!silent) {
1013 fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
1014 strerror(errno));
1016 return fd;
1019 static int try_open_fuse_device(char **devp)
1021 int fd;
1022 int err;
1024 drop_privs();
1025 fd = try_open(FUSE_DEV_NEW, devp, 0);
1026 restore_privs();
1027 if (fd >= 0)
1028 return fd;
1030 err = fd;
1031 fd = try_open(FUSE_DEV_OLD, devp, 1);
1032 if (fd >= 0)
1033 return fd;
1035 return err;
1038 static int open_fuse_device(char **devp)
1040 int fd = try_open_fuse_device(devp);
1041 if (fd >= -1)
1042 return fd;
1044 fprintf(stderr,
1045 "%s: fuse device not found, try 'modprobe fuse' first\n",
1046 progname);
1048 return -1;
1052 static int mount_fuse(const char *mnt, const char *opts)
1054 int res;
1055 int fd;
1056 char *dev;
1057 struct stat stbuf;
1058 char *type = NULL;
1059 char *source = NULL;
1060 char *mnt_opts = NULL;
1061 const char *real_mnt = mnt;
1062 int mountpoint_fd = -1;
1064 fd = open_fuse_device(&dev);
1065 if (fd == -1)
1066 return -1;
1068 drop_privs();
1069 read_conf();
1071 if (getuid() != 0 && mount_max != -1) {
1072 int mount_count = count_fuse_fs();
1073 if (mount_count >= mount_max) {
1074 fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
1075 goto fail_close_fd;
1079 res = check_version(dev);
1080 if (res != -1) {
1081 res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1082 restore_privs();
1083 if (res != -1)
1084 res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
1085 fd, opts, dev, &source, &mnt_opts,
1086 stbuf.st_size);
1087 } else
1088 restore_privs();
1090 if (mountpoint_fd != -1)
1091 close(mountpoint_fd);
1093 if (res == -1)
1094 goto fail_close_fd;
1096 res = chdir("/");
1097 if (res == -1) {
1098 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1099 goto fail_close_fd;
1102 if (geteuid() == 0) {
1103 res = add_mount(source, mnt, type, mnt_opts);
1104 if (res == -1) {
1105 /* Can't clean up mount in a non-racy way */
1106 goto fail_close_fd;
1110 out_free:
1111 free(source);
1112 free(type);
1113 free(mnt_opts);
1114 free(dev);
1116 return fd;
1118 fail_close_fd:
1119 close(fd);
1120 fd = -1;
1121 goto out_free;
1124 static int send_fd(int sock_fd, int fd)
1126 int retval;
1127 struct msghdr msg;
1128 struct cmsghdr *p_cmsg;
1129 struct iovec vec;
1130 size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
1131 int *p_fds;
1132 char sendchar = 0;
1134 msg.msg_control = cmsgbuf;
1135 msg.msg_controllen = sizeof(cmsgbuf);
1136 p_cmsg = CMSG_FIRSTHDR(&msg);
1137 p_cmsg->cmsg_level = SOL_SOCKET;
1138 p_cmsg->cmsg_type = SCM_RIGHTS;
1139 p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1140 p_fds = (int *) CMSG_DATA(p_cmsg);
1141 *p_fds = fd;
1142 msg.msg_controllen = p_cmsg->cmsg_len;
1143 msg.msg_name = NULL;
1144 msg.msg_namelen = 0;
1145 msg.msg_iov = &vec;
1146 msg.msg_iovlen = 1;
1147 msg.msg_flags = 0;
1148 /* "To pass file descriptors or credentials you need to send/read at
1149 * least one byte" (man 7 unix) */
1150 vec.iov_base = &sendchar;
1151 vec.iov_len = sizeof(sendchar);
1152 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1153 if (retval != 1) {
1154 perror("sending file descriptor");
1155 return -1;
1157 return 0;
1160 static void usage(void)
1162 printf("%s: [options] mountpoint\n"
1163 "Options:\n"
1164 " -h print help\n"
1165 " -V print version\n"
1166 " -o opt[,opt...] mount options\n"
1167 " -u unmount\n"
1168 " -q quiet\n"
1169 " -z lazy unmount\n",
1170 progname);
1171 exit(1);
1174 static void show_version(void)
1176 printf("fusermount version: %s\n", PACKAGE_VERSION);
1177 exit(0);
1180 int main(int argc, char *argv[])
1182 sigset_t sigset;
1183 int ch;
1184 int fd;
1185 int res;
1186 char *origmnt;
1187 char *mnt;
1188 static int unmount = 0;
1189 static int lazy = 0;
1190 static int quiet = 0;
1191 char *commfd;
1192 int cfd;
1193 const char *opts = "";
1195 static const struct option long_opts[] = {
1196 {"unmount", no_argument, NULL, 'u'},
1197 {"lazy", no_argument, NULL, 'z'},
1198 {"quiet", no_argument, NULL, 'q'},
1199 {"help", no_argument, NULL, 'h'},
1200 {"version", no_argument, NULL, 'V'},
1201 {0, 0, 0, 0}};
1203 progname = strdup(argv[0]);
1204 if (progname == NULL) {
1205 fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1206 exit(1);
1209 while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
1210 NULL)) != -1) {
1211 switch (ch) {
1212 case 'h':
1213 usage();
1214 break;
1216 case 'V':
1217 show_version();
1218 break;
1220 case 'o':
1221 opts = optarg;
1222 break;
1224 case 'u':
1225 unmount = 1;
1226 break;
1228 case 'z':
1229 lazy = 1;
1230 break;
1232 case 'q':
1233 quiet = 1;
1234 break;
1236 default:
1237 exit(1);
1241 if (lazy && !unmount) {
1242 fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1243 exit(1);
1246 if (optind >= argc) {
1247 fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1248 exit(1);
1249 } else if (argc > optind + 1) {
1250 fprintf(stderr, "%s: extra arguments after the mountpoint\n",
1251 progname);
1252 exit(1);
1255 origmnt = argv[optind];
1257 drop_privs();
1258 mnt = fuse_mnt_resolve_path(progname, origmnt);
1259 if (mnt != NULL) {
1260 res = chdir("/");
1261 if (res == -1) {
1262 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1263 exit(1);
1266 restore_privs();
1267 if (mnt == NULL)
1268 exit(1);
1270 umask(033);
1271 if (unmount)
1272 goto do_unmount;
1274 commfd = getenv(FUSE_COMMFD_ENV);
1275 if (commfd == NULL) {
1276 fprintf(stderr, "%s: old style mounting not supported\n",
1277 progname);
1278 exit(1);
1281 fd = mount_fuse(mnt, opts);
1282 if (fd == -1)
1283 exit(1);
1285 cfd = atoi(commfd);
1286 res = send_fd(cfd, fd);
1287 if (res == -1)
1288 exit(1);
1289 close(fd);
1291 if (!auto_unmount)
1292 return 0;
1294 /* Become a daemon and wait for the parent to exit or die.
1295 ie For the control socket to get closed.
1296 btw We don't want to use daemon() function here because
1297 it forks and messes with the file descriptors. */
1298 setsid();
1299 res = chdir("/");
1300 if (res == -1) {
1301 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1302 exit(1);
1305 sigfillset(&sigset);
1306 sigprocmask(SIG_BLOCK, &sigset, NULL);
1308 lazy = 1;
1309 quiet = 1;
1311 while (1) {
1312 unsigned char buf[16];
1313 int n = recv(cfd, buf, sizeof(buf), 0);
1314 if (!n)
1315 break;
1317 if (n < 0) {
1318 if (errno == EINTR)
1319 continue;
1320 break;
1324 do_unmount:
1325 if (geteuid() == 0)
1326 res = unmount_fuse(mnt, quiet, lazy);
1327 else {
1328 res = umount2(mnt, lazy ? UMOUNT_DETACH : 0);
1329 if (res == -1 && !quiet)
1330 fprintf(stderr,
1331 "%s: failed to unmount %s: %s\n",
1332 progname, mnt, strerror(errno));
1334 if (res == -1)
1335 exit(1);
1336 return 0;