Make lock argument of fuse_reply_lock const
[fuse.git] / util / fusermount.c
blobb2e87d95fb9be2e61fbe24b3908ef85273e91261
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 <mntent.h>
24 #include <sys/wait.h>
25 #include <sys/stat.h>
26 #include <sys/mount.h>
27 #include <sys/fsuid.h>
28 #include <sys/socket.h>
29 #include <sys/utsname.h>
30 #include <sched.h>
32 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
34 #define FUSE_DEV_OLD "/proc/fs/fuse/dev"
35 #define FUSE_DEV_NEW "/dev/fuse"
36 #define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
37 #define FUSE_CONF "/etc/fuse.conf"
39 #ifndef MS_DIRSYNC
40 #define MS_DIRSYNC 128
41 #endif
42 #ifndef MS_REC
43 #define MS_REC 16384
44 #endif
45 #ifndef MS_PRIVATE
46 #define MS_PRIVATE (1<<18)
47 #endif
49 #ifndef UMOUNT_DETACH
50 #define UMOUNT_DETACH 0x00000002 /* Just detach from the tree */
51 #endif
52 #ifndef UMOUNT_NOFOLLOW
53 #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
54 #endif
55 #ifndef UMOUNT_UNUSED
56 #define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
57 #endif
59 static const char *progname;
61 static int user_allow_other = 0;
62 static int mount_max = 1000;
64 static int auto_unmount = 0;
66 static const char *get_user_name(void)
68 struct passwd *pw = getpwuid(getuid());
69 if (pw != NULL && pw->pw_name != NULL)
70 return pw->pw_name;
71 else {
72 fprintf(stderr, "%s: could not determine username\n", progname);
73 return NULL;
77 static uid_t oldfsuid;
78 static gid_t oldfsgid;
80 static void drop_privs(void)
82 if (getuid() != 0) {
83 oldfsuid = setfsuid(getuid());
84 oldfsgid = setfsgid(getgid());
88 static void restore_privs(void)
90 if (getuid() != 0) {
91 setfsuid(oldfsuid);
92 setfsgid(oldfsgid);
96 #ifndef IGNORE_MTAB
98 * Make sure that /etc/mtab is checked and updated atomically
100 static int lock_umount(void)
102 const char *mtab_lock = _PATH_MOUNTED ".fuselock";
103 int mtablock;
104 int res;
105 struct stat mtab_stat;
107 /* /etc/mtab could be a symlink to /proc/mounts */
108 if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
109 return -1;
111 mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
112 if (mtablock == -1) {
113 fprintf(stderr, "%s: unable to open fuse lock file: %s\n",
114 progname, strerror(errno));
115 return -1;
117 res = lockf(mtablock, F_LOCK, 0);
118 if (res < 0) {
119 fprintf(stderr, "%s: error getting lock: %s\n", progname,
120 strerror(errno));
121 close(mtablock);
122 return -1;
125 return mtablock;
128 static void unlock_umount(int mtablock)
130 if (mtablock >= 0) {
131 int res;
133 res = lockf(mtablock, F_ULOCK, 0);
134 if (res < 0) {
135 fprintf(stderr, "%s: error releasing lock: %s\n",
136 progname, strerror(errno));
138 close(mtablock);
142 static int add_mount(const char *source, const char *mnt, const char *type,
143 const char *opts)
145 return fuse_mnt_add_mount(progname, source, mnt, type, opts);
148 static int may_unmount(const char *mnt, int quiet)
150 struct mntent *entp;
151 FILE *fp;
152 const char *user = NULL;
153 char uidstr[32];
154 unsigned uidlen = 0;
155 int found;
156 const char *mtab = _PATH_MOUNTED;
158 user = get_user_name();
159 if (user == NULL)
160 return -1;
162 fp = setmntent(mtab, "r");
163 if (fp == NULL) {
164 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
165 strerror(errno));
166 return -1;
169 uidlen = sprintf(uidstr, "%u", getuid());
171 found = 0;
172 while ((entp = getmntent(fp)) != NULL) {
173 if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
174 (strcmp(entp->mnt_type, "fuse") == 0 ||
175 strcmp(entp->mnt_type, "fuseblk") == 0 ||
176 strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
177 strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
178 char *p = strstr(entp->mnt_opts, "user=");
179 if (p &&
180 (p == entp->mnt_opts || *(p-1) == ',') &&
181 strcmp(p + 5, user) == 0) {
182 found = 1;
183 break;
185 /* /etc/mtab is a link pointing to
186 /proc/mounts: */
187 else if ((p =
188 strstr(entp->mnt_opts, "user_id=")) &&
189 (p == entp->mnt_opts ||
190 *(p-1) == ',') &&
191 strncmp(p + 8, uidstr, uidlen) == 0 &&
192 (*(p+8+uidlen) == ',' ||
193 *(p+8+uidlen) == '\0')) {
194 found = 1;
195 break;
199 endmntent(fp);
201 if (!found) {
202 if (!quiet)
203 fprintf(stderr,
204 "%s: entry for %s not found in %s\n",
205 progname, mnt, mtab);
206 return -1;
209 return 0;
213 * Check whether the file specified in "fusermount -u" is really a
214 * mountpoint and not a symlink. This is necessary otherwise the user
215 * could move the mountpoint away and replace it with a symlink
216 * pointing to an arbitrary mount, thereby tricking fusermount into
217 * unmounting that (umount(2) will follow symlinks).
219 * This is the child process running in a separate mount namespace, so
220 * we don't mess with the global namespace and if the process is
221 * killed for any reason, mounts are automatically cleaned up.
223 * First make sure nothing is propagated back into the parent
224 * namespace by marking all mounts "private".
226 * Then bind mount parent onto a stable base where the user can't move
227 * it around.
229 * Finally check /proc/mounts for an entry matching the requested
230 * mountpoint. If it's found then we are OK, and the user can't move
231 * it around within the parent directory as rename() will return
232 * EBUSY. Be careful to ignore any mounts that existed before the
233 * bind.
235 static int check_is_mount_child(void *p)
237 const char **a = p;
238 const char *last = a[0];
239 const char *mnt = a[1];
240 int res;
241 const char *procmounts = "/proc/mounts";
242 int found;
243 FILE *fp;
244 struct mntent *entp;
245 int count;
247 res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL);
248 if (res == -1) {
249 fprintf(stderr, "%s: failed to mark mounts private: %s\n",
250 progname, strerror(errno));
251 return 1;
254 fp = setmntent(procmounts, "r");
255 if (fp == NULL) {
256 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
257 procmounts, strerror(errno));
258 return 1;
261 count = 0;
262 while (getmntent(fp) != NULL)
263 count++;
264 endmntent(fp);
266 fp = setmntent(procmounts, "r");
267 if (fp == NULL) {
268 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
269 procmounts, strerror(errno));
270 return 1;
273 res = mount(".", "/", "", MS_BIND | MS_REC, NULL);
274 if (res == -1) {
275 fprintf(stderr, "%s: failed to bind parent to /: %s\n",
276 progname, strerror(errno));
277 return 1;
280 found = 0;
281 while ((entp = getmntent(fp)) != NULL) {
282 if (count > 0) {
283 count--;
284 continue;
286 if (entp->mnt_dir[0] == '/' &&
287 strcmp(entp->mnt_dir + 1, last) == 0) {
288 found = 1;
289 break;
292 endmntent(fp);
294 if (!found) {
295 fprintf(stderr, "%s: %s not mounted\n", progname, mnt);
296 return 1;
299 return 0;
302 static pid_t clone_newns(void *a)
304 char buf[131072];
305 char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15));
307 #ifdef __ia64__
308 extern int __clone2(int (*fn)(void *),
309 void *child_stack_base, size_t stack_size,
310 int flags, void *arg, pid_t *ptid,
311 void *tls, pid_t *ctid);
313 return __clone2(check_is_mount_child, stack, sizeof(buf) / 2,
314 CLONE_NEWNS, a, NULL, NULL, NULL);
315 #else
316 return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
317 #endif
320 static int check_is_mount(const char *last, const char *mnt)
322 pid_t pid, p;
323 int status;
324 const char *a[2] = { last, mnt };
326 pid = clone_newns((void *) a);
327 if (pid == (pid_t) -1) {
328 fprintf(stderr, "%s: failed to clone namespace: %s\n",
329 progname, strerror(errno));
330 return -1;
332 p = waitpid(pid, &status, __WCLONE);
333 if (p == (pid_t) -1) {
334 fprintf(stderr, "%s: waitpid failed: %s\n",
335 progname, strerror(errno));
336 return -1;
338 if (!WIFEXITED(status)) {
339 fprintf(stderr, "%s: child terminated abnormally (status %i)\n",
340 progname, status);
341 return -1;
343 if (WEXITSTATUS(status) != 0)
344 return -1;
346 return 0;
349 static int chdir_to_parent(char *copy, const char **lastp)
351 char *tmp;
352 const char *parent;
353 char buf[65536];
354 int res;
356 tmp = strrchr(copy, '/');
357 if (tmp == NULL || tmp[1] == '\0') {
358 fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n",
359 progname, copy);
360 return -1;
362 if (tmp != copy) {
363 *tmp = '\0';
364 parent = copy;
365 *lastp = tmp + 1;
366 } else if (tmp[1] != '\0') {
367 *lastp = tmp + 1;
368 parent = "/";
369 } else {
370 *lastp = ".";
371 parent = "/";
374 res = chdir(parent);
375 if (res == -1) {
376 fprintf(stderr, "%s: failed to chdir to %s: %s\n",
377 progname, parent, strerror(errno));
378 return -1;
381 if (getcwd(buf, sizeof(buf)) == NULL) {
382 fprintf(stderr, "%s: failed to obtain current directory: %s\n",
383 progname, strerror(errno));
384 return -1;
386 if (strcmp(buf, parent) != 0) {
387 fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname,
388 parent, buf);
389 return -1;
393 return 0;
396 /* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
397 static int umount_nofollow_support(void)
399 int res = umount2("", UMOUNT_UNUSED);
400 if (res != -1 || errno != EINVAL)
401 return 0;
403 res = umount2("", UMOUNT_NOFOLLOW);
404 if (res != -1 || errno != ENOENT)
405 return 0;
407 return 1;
410 static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
412 int res;
413 char *copy;
414 const char *last;
415 int umount_flags = lazy ? UMOUNT_DETACH : 0;
417 if (getuid() != 0) {
418 res = may_unmount(mnt, quiet);
419 if (res == -1)
420 return -1;
423 copy = strdup(mnt);
424 if (copy == NULL) {
425 fprintf(stderr, "%s: failed to allocate memory\n", progname);
426 return -1;
429 res = chdir_to_parent(copy, &last);
430 if (res == -1)
431 goto out;
433 if (umount_nofollow_support()) {
434 umount_flags |= UMOUNT_NOFOLLOW;
435 } else {
436 res = check_is_mount(last, mnt);
437 if (res == -1)
438 goto out;
441 res = umount2(last, umount_flags);
442 if (res == -1 && !quiet) {
443 fprintf(stderr, "%s: failed to unmount %s: %s\n",
444 progname, mnt, strerror(errno));
447 out:
448 if (res == -1)
449 return -1;
451 res = chdir("/");
452 if (res == -1) {
453 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
454 return -1;
457 return fuse_mnt_remove_mount(progname, mnt);
460 static int unmount_fuse(const char *mnt, int quiet, int lazy)
462 int res;
463 int mtablock = lock_umount();
465 res = unmount_fuse_locked(mnt, quiet, lazy);
466 unlock_umount(mtablock);
468 return res;
471 static int count_fuse_fs(void)
473 struct mntent *entp;
474 int count = 0;
475 const char *mtab = _PATH_MOUNTED;
476 FILE *fp = setmntent(mtab, "r");
477 if (fp == NULL) {
478 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
479 strerror(errno));
480 return -1;
482 while ((entp = getmntent(fp)) != NULL) {
483 if (strcmp(entp->mnt_type, "fuse") == 0 ||
484 strncmp(entp->mnt_type, "fuse.", 5) == 0)
485 count ++;
487 endmntent(fp);
488 return count;
492 #else /* IGNORE_MTAB */
493 static int count_fuse_fs()
495 return 0;
498 static int add_mount(const char *source, const char *mnt, const char *type,
499 const char *opts)
501 (void) source;
502 (void) mnt;
503 (void) type;
504 (void) opts;
505 return 0;
508 static int unmount_fuse(const char *mnt, int quiet, int lazy)
510 return fuse_mnt_umount(progname, mnt, mnt, lazy);
512 #endif /* IGNORE_MTAB */
514 static void strip_line(char *line)
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);
527 static void parse_line(char *line, int linenum)
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);
540 static void read_conf(void)
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;
555 } else if(line[strlen(line)-1] == '\n') {
556 fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
558 isnewline = 1;
560 if (isnewline)
561 linenum ++;
563 if (!isnewline) {
564 fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
567 fclose(fp);
568 } else if (errno != ENOENT) {
569 fprintf(stderr, "%s: failed to open %s: %s\n",
570 progname, FUSE_CONF, strerror(errno));
574 static int begins_with(const char *s, const char *beg)
576 if (strncmp(s, beg, strlen(beg)) == 0)
577 return 1;
578 else
579 return 0;
582 struct mount_flags {
583 const char *opt;
584 unsigned long flag;
585 int on;
586 int safe;
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}
606 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
608 int i;
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);
621 return 1;
624 return 0;
627 static int add_option(char **optsp, const char *opt, unsigned expand)
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);
639 if (newopts == NULL) {
640 fprintf(stderr, "%s: failed to allocate memory\n", progname);
641 return -1;
643 *optsp = newopts;
644 return 0;
647 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
649 int i;
650 int l;
652 if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
653 return -1;
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;
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;
672 if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
673 return -1;
674 strcat(*mnt_optsp, user);
676 return 0;
679 static int opt_eq(const char *s, unsigned len, const char *opt)
681 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
682 return 1;
683 else
684 return 0;
687 static int get_string_opt(const char *s, unsigned len, const char *opt,
688 char **val)
690 int i;
691 unsigned opt_len = strlen(opt);
692 char *d;
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;
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];
710 *d = '\0';
711 return 1;
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, off_t rootsize)
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 check_empty = 1;
729 int blkdev = 0;
731 optbuf = (char *) malloc(strlen(opts) + 128);
732 if (!optbuf) {
733 fprintf(stderr, "%s: failed to allocate memory\n", progname);
734 return -1;
737 for (s = opts, d = optbuf; *s;) {
738 unsigned len;
739 const char *fsname_str = "fsname=";
740 const char *subtype_str = "subtype=";
741 for (len = 0; s[len]; len++) {
742 if (s[len] == '\\' && s[len + 1])
743 len++;
744 else if (s[len] == ',')
745 break;
747 if (begins_with(s, fsname_str)) {
748 if (!get_string_opt(s, len, fsname_str, &fsname))
749 goto err;
750 } else if (begins_with(s, subtype_str)) {
751 if (!get_string_opt(s, len, subtype_str, &subtype))
752 goto err;
753 } else if (opt_eq(s, len, "blkdev")) {
754 if (getuid() != 0) {
755 fprintf(stderr,
756 "%s: option blkdev is privileged\n",
757 progname);
758 goto err;
760 blkdev = 1;
761 } else if (opt_eq(s, len, "nonempty")) {
762 check_empty = 0;
763 } else if (opt_eq(s, len, "auto_unmount")) {
764 auto_unmount = 1;
765 } else if (!begins_with(s, "fd=") &&
766 !begins_with(s, "rootmode=") &&
767 !begins_with(s, "user_id=") &&
768 !begins_with(s, "group_id=")) {
769 int on;
770 int flag;
771 int skip_option = 0;
772 if (opt_eq(s, len, "large_read")) {
773 struct utsname utsname;
774 unsigned kmaj, kmin;
775 res = uname(&utsname);
776 if (res == 0 &&
777 sscanf(utsname.release, "%u.%u",
778 &kmaj, &kmin) == 2 &&
779 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
780 fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
781 skip_option = 1;
784 if (getuid() != 0 && !user_allow_other &&
785 (opt_eq(s, len, "allow_other") ||
786 opt_eq(s, len, "allow_root"))) {
787 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
788 goto err;
790 if (!skip_option) {
791 if (find_mount_flag(s, len, &on, &flag)) {
792 if (on)
793 flags |= flag;
794 else
795 flags &= ~flag;
796 } else {
797 memcpy(d, s, len);
798 d += len;
799 *d++ = ',';
803 s += len;
804 if (*s)
805 s++;
807 *d = '\0';
808 res = get_mnt_opts(flags, optbuf, &mnt_opts);
809 if (res == -1)
810 goto err;
812 sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
813 fd, rootmode, getuid(), getgid());
815 if (check_empty &&
816 fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1)
817 goto err;
819 source = malloc((fsname ? strlen(fsname) : 0) +
820 (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
822 type = malloc((subtype ? strlen(subtype) : 0) + 32);
823 if (!type || !source) {
824 fprintf(stderr, "%s: failed to allocate memory\n", progname);
825 goto err;
828 if (subtype)
829 sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
830 else
831 strcpy(type, blkdev ? "fuseblk" : "fuse");
833 if (fsname)
834 strcpy(source, fsname);
835 else
836 strcpy(source, subtype ? subtype : dev);
838 res = mount(source, mnt, type, flags, optbuf);
839 if (res == -1 && errno == ENODEV && subtype) {
840 /* Probably missing subtype support */
841 strcpy(type, blkdev ? "fuseblk" : "fuse");
842 if (fsname) {
843 if (!blkdev)
844 sprintf(source, "%s#%s", subtype, fsname);
845 } else {
846 strcpy(source, type);
849 res = mount(source, mnt, type, flags, optbuf);
851 if (res == -1 && errno == EINVAL) {
852 /* It could be an old version not supporting group_id */
853 sprintf(d, "fd=%i,rootmode=%o,user_id=%i",
854 fd, rootmode, getuid());
855 res = mount(source, mnt, type, flags, optbuf);
857 if (res == -1) {
858 int errno_save = errno;
859 if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
860 fprintf(stderr, "%s: 'fuseblk' support missing\n",
861 progname);
862 else
863 fprintf(stderr, "%s: mount failed: %s\n", progname,
864 strerror(errno_save));
865 goto err;
867 *sourcep = source;
868 *typep = type;
869 *mnt_optsp = mnt_opts;
870 free(fsname);
871 free(optbuf);
873 return 0;
875 err:
876 free(fsname);
877 free(subtype);
878 free(source);
879 free(type);
880 free(mnt_opts);
881 free(optbuf);
882 return -1;
885 static int check_version(const char *dev)
887 int res;
888 int majorver;
889 int minorver;
890 const char *version_file;
891 FILE *vf;
893 if (strcmp(dev, FUSE_DEV_OLD) != 0)
894 return 0;
896 version_file = FUSE_VERSION_FILE_OLD;
897 vf = fopen(version_file, "r");
898 if (vf == NULL) {
899 fprintf(stderr, "%s: kernel interface too old\n", progname);
900 return -1;
902 res = fscanf(vf, "%i.%i", &majorver, &minorver);
903 fclose(vf);
904 if (res != 2) {
905 fprintf(stderr, "%s: error reading %s\n", progname,
906 version_file);
907 return -1;
909 if (majorver < 3) {
910 fprintf(stderr, "%s: kernel interface too old\n", progname);
911 return -1;
913 return 0;
916 static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
918 int res;
919 const char *mnt = *mntp;
920 const char *origmnt = mnt;
922 res = lstat(mnt, stbuf);
923 if (res == -1) {
924 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
925 progname, mnt, strerror(errno));
926 return -1;
929 /* No permission checking is done for root */
930 if (getuid() == 0)
931 return 0;
933 if (S_ISDIR(stbuf->st_mode)) {
934 res = chdir(mnt);
935 if (res == -1) {
936 fprintf(stderr,
937 "%s: failed to chdir to mountpoint: %s\n",
938 progname, strerror(errno));
939 return -1;
941 mnt = *mntp = ".";
942 res = lstat(mnt, stbuf);
943 if (res == -1) {
944 fprintf(stderr,
945 "%s: failed to access mountpoint %s: %s\n",
946 progname, origmnt, strerror(errno));
947 return -1;
950 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
951 fprintf(stderr, "%s: mountpoint %s not owned by user\n",
952 progname, origmnt);
953 return -1;
956 res = access(mnt, W_OK);
957 if (res == -1) {
958 fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
959 progname, origmnt);
960 return -1;
962 } else if (S_ISREG(stbuf->st_mode)) {
963 static char procfile[256];
964 *mountpoint_fd = open(mnt, O_WRONLY);
965 if (*mountpoint_fd == -1) {
966 fprintf(stderr, "%s: failed to open %s: %s\n",
967 progname, mnt, strerror(errno));
968 return -1;
970 res = fstat(*mountpoint_fd, stbuf);
971 if (res == -1) {
972 fprintf(stderr,
973 "%s: failed to access mountpoint %s: %s\n",
974 progname, mnt, strerror(errno));
975 return -1;
977 if (!S_ISREG(stbuf->st_mode)) {
978 fprintf(stderr,
979 "%s: mountpoint %s is no longer a regular file\n",
980 progname, mnt);
981 return -1;
984 sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
985 *mntp = procfile;
986 } else {
987 fprintf(stderr,
988 "%s: mountpoint %s is not a directory or a regular file\n",
989 progname, mnt);
990 return -1;
994 return 0;
997 static int try_open(const char *dev, char **devp, int silent)
999 int fd = open(dev, O_RDWR);
1000 if (fd != -1) {
1001 *devp = strdup(dev);
1002 if (*devp == NULL) {
1003 fprintf(stderr, "%s: failed to allocate memory\n",
1004 progname);
1005 close(fd);
1006 fd = -1;
1008 } else if (errno == ENODEV ||
1009 errno == ENOENT)/* check for ENOENT too, for the udev case */
1010 return -2;
1011 else if (!silent) {
1012 fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
1013 strerror(errno));
1015 return fd;
1018 static int try_open_fuse_device(char **devp)
1020 int fd;
1021 int err;
1023 drop_privs();
1024 fd = try_open(FUSE_DEV_NEW, devp, 0);
1025 restore_privs();
1026 if (fd >= 0)
1027 return fd;
1029 err = fd;
1030 fd = try_open(FUSE_DEV_OLD, devp, 1);
1031 if (fd >= 0)
1032 return fd;
1034 return err;
1037 static int open_fuse_device(char **devp)
1039 int fd = try_open_fuse_device(devp);
1040 if (fd >= -1)
1041 return fd;
1043 fprintf(stderr,
1044 "%s: fuse device not found, try 'modprobe fuse' first\n",
1045 progname);
1047 return -1;
1051 static int mount_fuse(const char *mnt, const char *opts)
1053 int res;
1054 int fd;
1055 char *dev;
1056 struct stat stbuf;
1057 char *type = NULL;
1058 char *source = NULL;
1059 char *mnt_opts = NULL;
1060 const char *real_mnt = mnt;
1061 int mountpoint_fd = -1;
1063 fd = open_fuse_device(&dev);
1064 if (fd == -1)
1065 return -1;
1067 drop_privs();
1068 read_conf();
1070 if (getuid() != 0 && mount_max != -1) {
1071 int mount_count = count_fuse_fs();
1072 if (mount_count >= mount_max) {
1073 fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
1074 goto fail_close_fd;
1078 res = check_version(dev);
1079 if (res != -1) {
1080 res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1081 restore_privs();
1082 if (res != -1)
1083 res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT,
1084 fd, opts, dev, &source, &mnt_opts,
1085 stbuf.st_size);
1086 } else
1087 restore_privs();
1089 if (mountpoint_fd != -1)
1090 close(mountpoint_fd);
1092 if (res == -1)
1093 goto fail_close_fd;
1095 res = chdir("/");
1096 if (res == -1) {
1097 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
1098 goto fail_close_fd;
1101 if (geteuid() == 0) {
1102 res = add_mount(source, mnt, type, mnt_opts);
1103 if (res == -1) {
1104 /* Can't clean up mount in a non-racy way */
1105 goto fail_close_fd;
1109 out_free:
1110 free(source);
1111 free(type);
1112 free(mnt_opts);
1113 free(dev);
1115 return fd;
1117 fail_close_fd:
1118 close(fd);
1119 fd = -1;
1120 goto out_free;
1123 static int send_fd(int sock_fd, int fd)
1125 int retval;
1126 struct msghdr msg;
1127 struct cmsghdr *p_cmsg;
1128 struct iovec vec;
1129 size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
1130 int *p_fds;
1131 char sendchar = 0;
1133 msg.msg_control = cmsgbuf;
1134 msg.msg_controllen = sizeof(cmsgbuf);
1135 p_cmsg = CMSG_FIRSTHDR(&msg);
1136 p_cmsg->cmsg_level = SOL_SOCKET;
1137 p_cmsg->cmsg_type = SCM_RIGHTS;
1138 p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1139 p_fds = (int *) CMSG_DATA(p_cmsg);
1140 *p_fds = fd;
1141 msg.msg_controllen = p_cmsg->cmsg_len;
1142 msg.msg_name = NULL;
1143 msg.msg_namelen = 0;
1144 msg.msg_iov = &vec;
1145 msg.msg_iovlen = 1;
1146 msg.msg_flags = 0;
1147 /* "To pass file descriptors or credentials you need to send/read at
1148 * least one byte" (man 7 unix) */
1149 vec.iov_base = &sendchar;
1150 vec.iov_len = sizeof(sendchar);
1151 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1152 if (retval != 1) {
1153 perror("sending file descriptor");
1154 return -1;
1156 return 0;
1159 static void usage(void)
1161 fprintf(stderr,
1162 "%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;