2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU GPL.
8 /* This program does the mounting and unmounting of FUSE filesystems */
11 * NOTE: This program should be part of (or be called from) /bin/mount
13 * Unless that is done, operations on /etc/mtab are not under lock, and so
14 * data in this file may be lost. (I will _not_ reimplement that locking,
15 * and anyway that should be done in libc, if possible. But probably it
32 #include <sys/param.h>
35 #include <sys/mount.h>
36 #include <sys/fsuid.h>
37 #include <sys/socket.h>
39 #include <sys/utsname.h>
40 #include <sys/sysmacros.h>
43 #include <captive/client.h>
44 #include <linux/kdev_t.h>
45 #include <linux/major.h>
48 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
50 #define FUSE_DEV_OLD "/proc/fs/fuse/dev"
51 #define FUSE_DEV_NEW "/dev/fuse"
52 #define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
53 #define FUSE_CONF "/etc/fuse.conf"
55 static const char *progname;
57 static int user_allow_other = 0;
58 static int mount_max = 1000;
60 static const char *get_user_name(void)
62 struct passwd *pw = getpwuid(getuid());
63 if (pw != NULL && pw->pw_name != NULL)
66 fprintf(stderr, "%s: could not determine username\n", progname);
71 static uid_t oldfsuid;
72 static gid_t oldfsgid;
74 static void drop_privs(void)
77 oldfsuid = setfsuid(getuid());
78 oldfsgid = setfsgid(getgid());
82 static void restore_privs(void)
90 static int do_unmount(const char *mnt, int quiet, int lazy)
92 int res = umount2(mnt, lazy ? 2 : 0);
95 fprintf(stderr, "%s: failed to unmount %s: %s\n",
96 progname, mnt, strerror(errno));
102 /* use a lock file so that multiple fusermount processes don't try and
103 modify the mtab file at once! */
104 static int lock_mtab(void)
106 const char *mtab_lock = _PATH_MOUNTED ".fuselock";
110 mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
112 res = lockf(mtablock, F_LOCK, 0);
114 fprintf(stderr, "%s: error getting lock", progname);
116 fprintf(stderr, "%s: unable to open fuse lock file\n", progname);
121 static void unlock_mtab(int mtablock)
124 int trash0=lockf(mtablock, F_ULOCK, 0);
129 /* Glibc addmntent() doesn't encode '\n', misencodes '\t' as '\n'
130 (version 2.3.2), and encodes '\\' differently as mount(8). So
131 let's not allow those characters, they are not all that usual in
133 static int check_name(const char *name)
136 for (s = "\n\t\\"; *s; s++) {
137 if (strchr(name, *s)) {
138 fprintf(stderr, "%s: illegal character 0x%02x in mount entry\n",
146 static int add_mount(const char *fsname, const char *mnt, const char *type,
150 const char *mtab = _PATH_MOUNTED;
154 if (check_name(fsname) == -1 || check_name(mnt) == -1 ||
155 check_name(type) == -1 || check_name(opts) == -1)
158 fp = setmntent(mtab, "a");
160 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
165 ent.mnt_fsname = (char *) fsname;
166 ent.mnt_dir = (char *) mnt;
167 ent.mnt_type = (char *) type;
168 ent.mnt_opts = (char *) opts;
171 res = addmntent(fp, &ent);
173 fprintf(stderr, "%s: failed to add entry to %s: %s\n", progname,
174 mtab, strerror(errno));
182 static int remove_mount(const char *mnt, int quiet, const char *mtab,
183 const char *mtab_new)
189 const char *user = NULL;
194 fp = setmntent(mtab, "r");
196 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
201 newfp = setmntent(mtab_new, "w");
203 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab_new,
209 user = get_user_name();
213 uidlen = sprintf(uidstr, "%u", getuid());
217 while ((entp = getmntent(fp)) != NULL) {
219 if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
220 strcmp(entp->mnt_type, "fuse") == 0) {
224 char *p = strstr(entp->mnt_opts, "user=");
225 if (p && (p == entp->mnt_opts || *(p-1) == ',') &&
226 strcmp(p + 5, user) == 0)
228 /* /etc/mtab is a link pointing to /proc/mounts: */
229 else if ((p = strstr(entp->mnt_opts, "user_id=")) &&
230 (p == entp->mnt_opts || *(p-1) == ',') &&
231 strncmp(p + 8, uidstr, uidlen) == 0 &&
232 (*(p+8+uidlen) == ',' || *(p+8+uidlen) == '\0'))
239 res = addmntent(newfp, entp);
241 fprintf(stderr, "%s: failed to add entry to %s: %s\n",
242 progname, mtab_new, strerror(errno));
252 fprintf(stderr, "%s: entry for %s not found in %s\n", progname,
261 static int count_fuse_fs(void)
265 const char *mtab = _PATH_MOUNTED;
266 FILE *fp = setmntent(mtab, "r");
268 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
272 while ((entp = getmntent(fp)) != NULL) {
273 if (strcmp(entp->mnt_type, "fuse") == 0)
280 static int unmount_rename(const char *mnt, int quiet, int lazy,
281 const char *mtab, const char *mtab_new)
287 res = do_unmount(mnt, quiet, lazy);
292 if (stat(mtab, &sbuf) == 0) {
293 int trash0=chown(mtab_new, sbuf.st_uid, sbuf.st_gid);
296 res = rename(mtab_new, mtab);
298 fprintf(stderr, "%s: failed to rename %s to %s: %s\n", progname,
299 mtab_new, mtab, strerror(errno));
305 static int unmount_fuse(const char *mnt, int quiet, int lazy)
308 const char *mtab = _PATH_MOUNTED;
309 const char *mtab_new = _PATH_MOUNTED "~fuse~";
311 res = remove_mount(mnt, quiet, mtab, mtab_new);
315 res = unmount_rename(mnt, quiet, lazy, mtab, mtab_new);
322 #else /* IGNORE_MTAB */
323 static int lock_mtab()
328 static void unlock_mtab(int mtablock)
333 static int count_fuse_fs()
338 static int add_mount(const char *fsname, const char *mnt, const char *type,
348 static int unmount_fuse(const char *mnt, int quiet, int lazy)
350 return do_unmount(mnt, quiet, lazy);
352 #endif /* IGNORE_MTAB */
354 static void strip_line(char *line)
356 char *s = strchr(line, '#');
359 for (s = line + strlen(line) - 1; s >= line && isspace((unsigned char) *s); s--);
361 for (s = line; isspace((unsigned char) *s); s++);
363 memmove(line, s, strlen(s)+1);
366 static void parse_line(char *line, int linenum)
369 if (strcmp(line, "user_allow_other") == 0)
370 user_allow_other = 1;
371 else if (sscanf(line, "mount_max = %i", &tmp) == 1)
374 fprintf(stderr, "%s: unknown parameter in %s at line %i: '%s'\n",
375 progname, FUSE_CONF, linenum, line);
378 static void read_conf(void)
380 FILE *fp = fopen(FUSE_CONF, "r");
385 while (fgets(line, sizeof(line), fp) != NULL) {
387 if (line[strlen(line)-1] == '\n') {
389 parse_line(line, linenum);
391 fprintf(stderr, "%s: reading %s: line %i too long\n",
392 progname, FUSE_CONF, linenum);
395 } else if(line[strlen(line)-1] == '\n')
401 } else if (errno != ENOENT) {
402 fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF,
407 static int begins_with(const char *s, const char *beg)
409 if (strncmp(s, beg, strlen(beg)) == 0)
422 static struct mount_flags mount_flags[] = {
423 {"rw", MS_RDONLY, 0, 1},
424 {"ro", MS_RDONLY, 1, 1},
425 {"suid", MS_NOSUID, 0, 0},
426 {"nosuid", MS_NOSUID, 1, 1},
427 {"dev", MS_NODEV, 0, 0},
428 {"nodev", MS_NODEV, 1, 1},
429 {"exec", MS_NOEXEC, 0, 1},
430 {"noexec", MS_NOEXEC, 1, 1},
431 {"async", MS_SYNCHRONOUS, 0, 1},
432 {"sync", MS_SYNCHRONOUS, 1, 1},
433 {"atime", MS_NOATIME, 0, 1},
434 {"noatime", MS_NOATIME, 1, 1},
438 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
442 for (i = 0; mount_flags[i].opt != NULL; i++) {
443 const char *opt = mount_flags[i].opt;
444 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
445 *on = mount_flags[i].on;
446 *flag = mount_flags[i].flag;
447 if (!mount_flags[i].safe && getuid() != 0) {
449 fprintf(stderr, "%s: unsafe option %s ignored\n",
458 static int add_option(char **optsp, const char *opt, unsigned expand)
462 newopts = strdup(opt);
464 unsigned oldsize = strlen(*optsp);
465 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
466 newopts = (char *) realloc(*optsp, newsize);
468 sprintf(newopts + oldsize, ",%s", opt);
470 if (newopts == NULL) {
471 fprintf(stderr, "%s: failed to allocate memory\n", progname);
478 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
483 if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
486 for (i = 0; mount_flags[i].opt != NULL; i++) {
487 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
488 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
492 if (add_option(mnt_optsp, opts, 0) == -1)
494 /* remove comma from end of opts*/
495 l = strlen(*mnt_optsp);
496 if ((*mnt_optsp)[l-1] == ',')
497 (*mnt_optsp)[l-1] = '\0';
499 const char *user = get_user_name();
503 if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
505 strcat(*mnt_optsp, user);
510 static int opt_eq(const char *s, unsigned len, const char *opt)
512 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
518 static int check_mountpoint_empty(const char *mnt, mode_t rootmode,
523 if (S_ISDIR(rootmode)) {
525 DIR *dp = opendir(mnt);
527 fprintf(stderr, "%s: failed to mountpoint for reading: %s\n",
528 progname, strerror(errno));
531 while ((ent = readdir(dp)) != NULL) {
532 if (strcmp(ent->d_name, ".") != 0 &&
533 strcmp(ent->d_name, "..") != 0) {
543 fprintf(stderr, "%s: mountpoint is not empty\n", progname);
544 fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
550 static int do_mount(const char *mnt, const char *type, mode_t rootmode,
551 int fd, const char *opts, const char *dev, char **fsnamep,
552 char **mnt_optsp, off_t rootsize)
555 int flags = MS_NOSUID | MS_NODEV;
557 char *mnt_opts = NULL;
563 optbuf = (char *) malloc(strlen(opts) + 128);
565 fprintf(stderr, "%s: failed to allocate memory\n", progname);
569 for (s = opts, d = optbuf; *s;) {
571 const char *fsname_str = "fsname=";
572 for (len = 0; s[len] && s[len] != ','; len++);
573 if (begins_with(s, fsname_str)) {
574 unsigned fsname_str_len = strlen(fsname_str);
577 fsname = (char *) malloc(len - fsname_str_len + 1);
579 fprintf(stderr, "%s: failed to allocate memory\n", progname);
582 memcpy(fsname, s + fsname_str_len, len - fsname_str_len);
583 fsname[len - fsname_str_len] = '\0';
584 } else if (opt_eq(s, len, "nonempty")) {
586 } else if (!begins_with(s, "fd=") &&
587 !begins_with(s, "rootmode=") &&
588 !begins_with(s, "user_id=") &&
589 !begins_with(s, "group_id=")) {
593 if (opt_eq(s, len, "large_read")) {
594 struct utsname utsname;
596 res = uname(&utsname);
598 sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 &&
599 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
600 fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
604 if (getuid() != 0 && !user_allow_other &&
605 (opt_eq(s, len, "allow_other") ||
606 opt_eq(s, len, "allow_root"))) {
607 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
611 if (find_mount_flag(s, len, &on, &flag)) {
628 res = get_mnt_opts(flags, optbuf, &mnt_opts);
632 sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
633 fd, rootmode, getuid(), getgid());
634 if (fsname == NULL) {
635 fsname = strdup(dev);
637 fprintf(stderr, "%s: failed to allocate memory\n", progname);
642 if (check_empty && check_mountpoint_empty(mnt, rootmode, rootsize) == -1)
645 res = mount(fsname, mnt, type, flags, optbuf);
646 if (res == -1 && errno == EINVAL) {
647 /* It could be an old version not supporting group_id */
648 sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid());
649 res = mount(fsname, mnt, type, flags, optbuf);
652 fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno));
656 *mnt_optsp = mnt_opts;
669 static int check_version(const char *dev)
674 const char *version_file;
677 if (strcmp(dev, FUSE_DEV_OLD) != 0)
680 version_file = FUSE_VERSION_FILE_OLD;
681 vf = fopen(version_file, "r");
683 fprintf(stderr, "%s: kernel interface too old\n", progname);
686 res = fscanf(vf, "%i.%i", &majorver, &minorver);
689 fprintf(stderr, "%s: error reading %s\n", progname, version_file);
693 fprintf(stderr, "%s: kernel interface too old\n", progname);
699 static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd,
703 const char *mnt = *mntp;
704 const char *origmnt = mnt;
706 res = lstat(mnt, stbuf);
708 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
709 progname, mnt, strerror(errno));
713 /* No permission checking is done for root */
717 if (S_ISDIR(stbuf->st_mode)) {
718 *currdir_fd = open(".", O_RDONLY);
719 if (*currdir_fd == -1) {
720 fprintf(stderr, "%s: failed to open current directory: %s\n",
721 progname, strerror(errno));
726 fprintf(stderr, "%s: failed to chdir to mountpoint: %s\n",
727 progname, strerror(errno));
731 res = lstat(mnt, stbuf);
733 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
734 progname, origmnt, strerror(errno));
738 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
739 fprintf(stderr, "%s: mountpoint %s not owned by user\n",
744 res = access(mnt, W_OK);
746 fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
750 } else if (S_ISREG(stbuf->st_mode)) {
751 static char procfile[256];
752 *mountpoint_fd = open(mnt, O_WRONLY);
753 if (*mountpoint_fd == -1) {
754 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mnt,
758 res = fstat(*mountpoint_fd, stbuf);
760 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
761 progname, mnt, strerror(errno));
764 if (!S_ISREG(stbuf->st_mode)) {
765 fprintf(stderr, "%s: mountpoint %s is no longer a regular file\n",
770 sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
774 "%s: mountpoint %s is not a directory or a regular file\n",
783 static int try_open(const char *dev, char **devp, int silent)
785 int fd = open(dev, O_RDWR);
787 if (fd == -1 && errno == ENOENT && !strcmp(dev, FUSE_DEV_NEW)
788 && !mknod(dev, 0660 | S_IFCHR, MKDEV(MISC_MAJOR, 229))) {
791 fprintf(stderr, "%s: Notice: Created FUSE device: %s\n", progname, dev);
792 if ((group = getgrnam("fuse")) && !chown(dev, 0, group->gr_gid))
793 fd = open(dev, O_RDWR);
798 fprintf(stderr, "%s: failed to allocate memory\n", progname);
802 } else if (errno == ENODEV)
805 fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
811 static int try_open_fuse_device(char **devp)
817 fd = try_open(FUSE_DEV_NEW, devp, 0);
823 fd = try_open(FUSE_DEV_OLD, devp, 1);
830 static int open_fuse_device(char **devp)
832 int fd = try_open_fuse_device(devp);
838 "%s: fuse device not found, try 'modprobe fuse' first\n",
844 static int mount_fuse(const char *mnt, const char *opts)
849 const char *type = "fuse";
852 char *mnt_opts = NULL;
853 const char *real_mnt = mnt;
855 int mountpoint_fd = -1;
858 fd = open_fuse_device(&dev);
862 if (geteuid() == 0) {
863 mtablock = lock_mtab();
873 if (getuid() != 0 && mount_max != -1) {
874 int mount_count = count_fuse_fs();
875 if (mount_count >= mount_max) {
876 fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
878 unlock_mtab(mtablock);
883 res = check_version(dev);
885 res = check_perm(&real_mnt, &stbuf, &currdir_fd, &mountpoint_fd);
888 res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT, fd, opts,
889 dev, &fsname, &mnt_opts, stbuf.st_size);
893 if (currdir_fd != -1) {
894 int trash0=fchdir(currdir_fd);
897 if (mountpoint_fd != -1)
898 close(mountpoint_fd);
902 unlock_mtab(mtablock);
906 if (geteuid() == 0) {
907 res = add_mount(fsname, mnt, type, mnt_opts);
908 unlock_mtab(mtablock);
910 umount2(mnt, 2); /* lazy umount */
923 static char *resolve_path(const char *orig)
930 const char *toresolv;
933 fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
939 fprintf(stderr, "%s: failed to allocate memory\n", progname);
945 for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
949 tmp = strrchr(copy, '/');
958 if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
965 if (realpath(toresolv, buf) == NULL) {
966 fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
971 if (lastcomp == NULL)
974 dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
976 unsigned buflen = strlen(buf);
977 if (buflen && buf[buflen-1] == '/')
978 sprintf(dst, "%s%s", buf, lastcomp);
980 sprintf(dst, "%s/%s", buf, lastcomp);
985 fprintf(stderr, "%s: failed to allocate memory\n", progname);
989 static int send_fd(int sock_fd, int fd)
993 struct cmsghdr *p_cmsg;
995 char cmsgbuf[CMSG_SPACE(sizeof(fd))];
999 msg.msg_control = cmsgbuf;
1000 msg.msg_controllen = sizeof(cmsgbuf);
1001 p_cmsg = CMSG_FIRSTHDR(&msg);
1002 p_cmsg->cmsg_level = SOL_SOCKET;
1003 p_cmsg->cmsg_type = SCM_RIGHTS;
1004 p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1005 p_fds = (int *) CMSG_DATA(p_cmsg);
1007 msg.msg_controllen = p_cmsg->cmsg_len;
1008 msg.msg_name = NULL;
1009 msg.msg_namelen = 0;
1013 /* "To pass file descriptors or credentials you need to send/read at
1014 * least one byte" (man 7 unix) */
1015 vec.iov_base = &sendchar;
1016 vec.iov_len = sizeof(sendchar);
1017 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1019 perror("sending file descriptor");
1025 static void usage(void)
1028 "%s: [options] mountpoint\n"
1031 " -v print version\n"
1032 " -o opt[,opt...] mount options\n"
1035 " -z lazy unmount\n",
1040 static void show_version(void)
1042 printf("%s\n", PACKAGE_STRING);
1046 int main(int argc, char *argv[])
1053 static int unmount = 0;
1054 static int lazy = 0;
1055 static int quiet = 0;
1058 const char *opts = "";
1060 static const struct option long_opts[] = {
1061 {"unmount", no_argument, NULL, 'u'},
1062 {"lazy", no_argument, NULL, 'z'},
1063 {"quiet", no_argument, NULL, 'q'},
1064 {"help", no_argument, NULL, 'h'},
1065 {"version", no_argument, NULL, 'v'},
1069 captive_standalone_init();
1071 progname = strdup(argv[0]);
1072 if (progname == NULL) {
1073 fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1077 while ((ch = getopt_long(argc, argv, "hvo:uzq", long_opts, NULL)) != -1) {
1108 if (lazy && !unmount) {
1109 fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1113 if (optind >= argc) {
1114 fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1118 origmnt = argv[optind];
1121 mnt = resolve_path(origmnt);
1128 if (geteuid() == 0) {
1129 int mtablock = lock_mtab();
1130 res = unmount_fuse(mnt, quiet, lazy);
1131 unlock_mtab(mtablock);
1133 res = do_unmount(mnt, quiet, lazy);
1139 commfd = getenv(FUSE_COMMFD_ENV);
1140 if (commfd == NULL) {
1141 fprintf(stderr, "%s: old style mounting not supported\n", progname);
1145 fd = mount_fuse(mnt, opts);
1150 res = send_fd(cfd, fd);