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 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 chown(mtab_new, sbuf.st_uid, sbuf.st_gid);
295 res = rename(mtab_new, mtab);
297 fprintf(stderr, "%s: failed to rename %s to %s: %s\n", progname,
298 mtab_new, mtab, strerror(errno));
304 static int unmount_fuse(const char *mnt, int quiet, int lazy)
307 const char *mtab = _PATH_MOUNTED;
308 const char *mtab_new = _PATH_MOUNTED "~fuse~";
310 res = remove_mount(mnt, quiet, mtab, mtab_new);
314 res = unmount_rename(mnt, quiet, lazy, mtab, mtab_new);
321 #else /* IGNORE_MTAB */
322 static int lock_mtab()
327 static void unlock_mtab(int mtablock)
332 static int count_fuse_fs()
337 static int add_mount(const char *fsname, const char *mnt, const char *type,
347 static int unmount_fuse(const char *mnt, int quiet, int lazy)
349 return do_unmount(mnt, quiet, lazy);
351 #endif /* IGNORE_MTAB */
353 static void strip_line(char *line)
355 char *s = strchr(line, '#');
358 for (s = line + strlen(line) - 1; s >= line && isspace((unsigned char) *s); s--);
360 for (s = line; isspace((unsigned char) *s); s++);
362 memmove(line, s, strlen(s)+1);
365 static void parse_line(char *line, int linenum)
368 if (strcmp(line, "user_allow_other") == 0)
369 user_allow_other = 1;
370 else if (sscanf(line, "mount_max = %i", &tmp) == 1)
373 fprintf(stderr, "%s: unknown parameter in %s at line %i: '%s'\n",
374 progname, FUSE_CONF, linenum, line);
377 static void read_conf(void)
379 FILE *fp = fopen(FUSE_CONF, "r");
384 while (fgets(line, sizeof(line), fp) != NULL) {
386 if (line[strlen(line)-1] == '\n') {
388 parse_line(line, linenum);
390 fprintf(stderr, "%s: reading %s: line %i too long\n",
391 progname, FUSE_CONF, linenum);
394 } else if(line[strlen(line)-1] == '\n')
400 } else if (errno != ENOENT) {
401 fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF,
406 static int begins_with(const char *s, const char *beg)
408 if (strncmp(s, beg, strlen(beg)) == 0)
421 static struct mount_flags mount_flags[] = {
422 {"rw", MS_RDONLY, 0, 1},
423 {"ro", MS_RDONLY, 1, 1},
424 {"suid", MS_NOSUID, 0, 0},
425 {"nosuid", MS_NOSUID, 1, 1},
426 {"dev", MS_NODEV, 0, 0},
427 {"nodev", MS_NODEV, 1, 1},
428 {"exec", MS_NOEXEC, 0, 1},
429 {"noexec", MS_NOEXEC, 1, 1},
430 {"async", MS_SYNCHRONOUS, 0, 1},
431 {"sync", MS_SYNCHRONOUS, 1, 1},
432 {"atime", MS_NOATIME, 0, 1},
433 {"noatime", MS_NOATIME, 1, 1},
437 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
441 for (i = 0; mount_flags[i].opt != NULL; i++) {
442 const char *opt = mount_flags[i].opt;
443 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
444 *on = mount_flags[i].on;
445 *flag = mount_flags[i].flag;
446 if (!mount_flags[i].safe && getuid() != 0) {
448 fprintf(stderr, "%s: unsafe option %s ignored\n",
457 static int add_option(char **optsp, const char *opt, unsigned expand)
461 newopts = strdup(opt);
463 unsigned oldsize = strlen(*optsp);
464 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
465 newopts = (char *) realloc(*optsp, newsize);
467 sprintf(newopts + oldsize, ",%s", opt);
469 if (newopts == NULL) {
470 fprintf(stderr, "%s: failed to allocate memory\n", progname);
477 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
482 if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
485 for (i = 0; mount_flags[i].opt != NULL; i++) {
486 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
487 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
491 if (add_option(mnt_optsp, opts, 0) == -1)
493 /* remove comma from end of opts*/
494 l = strlen(*mnt_optsp);
495 if ((*mnt_optsp)[l-1] == ',')
496 (*mnt_optsp)[l-1] = '\0';
498 const char *user = get_user_name();
502 if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
504 strcat(*mnt_optsp, user);
509 static int opt_eq(const char *s, unsigned len, const char *opt)
511 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
517 static int check_mountpoint_empty(const char *mnt, mode_t rootmode,
522 if (S_ISDIR(rootmode)) {
524 DIR *dp = opendir(mnt);
526 fprintf(stderr, "%s: failed to mountpoint for reading: %s\n",
527 progname, strerror(errno));
530 while ((ent = readdir(dp)) != NULL) {
531 if (strcmp(ent->d_name, ".") != 0 &&
532 strcmp(ent->d_name, "..") != 0) {
542 fprintf(stderr, "%s: mountpoint is not empty\n", progname);
543 fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
549 static int do_mount(const char *mnt, const char *type, mode_t rootmode,
550 int fd, const char *opts, const char *dev, char **fsnamep,
551 char **mnt_optsp, off_t rootsize)
554 int flags = MS_NOSUID | MS_NODEV;
556 char *mnt_opts = NULL;
562 optbuf = (char *) malloc(strlen(opts) + 128);
564 fprintf(stderr, "%s: failed to allocate memory\n", progname);
568 for (s = opts, d = optbuf; *s;) {
570 const char *fsname_str = "fsname=";
571 for (len = 0; s[len] && s[len] != ','; len++);
572 if (begins_with(s, fsname_str)) {
573 unsigned fsname_str_len = strlen(fsname_str);
576 fsname = (char *) malloc(len - fsname_str_len + 1);
578 fprintf(stderr, "%s: failed to allocate memory\n", progname);
581 memcpy(fsname, s + fsname_str_len, len - fsname_str_len);
582 fsname[len - fsname_str_len] = '\0';
583 } else if (opt_eq(s, len, "nonempty")) {
585 } else if (!begins_with(s, "fd=") &&
586 !begins_with(s, "rootmode=") &&
587 !begins_with(s, "user_id=") &&
588 !begins_with(s, "group_id=")) {
592 if (opt_eq(s, len, "large_read")) {
593 struct utsname utsname;
595 res = uname(&utsname);
597 sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 &&
598 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
599 fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
603 if (getuid() != 0 && !user_allow_other &&
604 (opt_eq(s, len, "allow_other") ||
605 opt_eq(s, len, "allow_root"))) {
606 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
610 if (find_mount_flag(s, len, &on, &flag)) {
627 res = get_mnt_opts(flags, optbuf, &mnt_opts);
631 sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
632 fd, rootmode, getuid(), getgid());
633 if (fsname == NULL) {
634 fsname = strdup(dev);
636 fprintf(stderr, "%s: failed to allocate memory\n", progname);
641 if (check_empty && check_mountpoint_empty(mnt, rootmode, rootsize) == -1)
644 res = mount(fsname, mnt, type, flags, optbuf);
645 if (res == -1 && errno == EINVAL) {
646 /* It could be an old version not supporting group_id */
647 sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid());
648 res = mount(fsname, mnt, type, flags, optbuf);
651 fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno));
655 *mnt_optsp = mnt_opts;
668 static int check_version(const char *dev)
673 const char *version_file;
676 if (strcmp(dev, FUSE_DEV_OLD) != 0)
679 version_file = FUSE_VERSION_FILE_OLD;
680 vf = fopen(version_file, "r");
682 fprintf(stderr, "%s: kernel interface too old\n", progname);
685 res = fscanf(vf, "%i.%i", &majorver, &minorver);
688 fprintf(stderr, "%s: error reading %s\n", progname, version_file);
692 fprintf(stderr, "%s: kernel interface too old\n", progname);
698 static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd,
702 const char *mnt = *mntp;
703 const char *origmnt = mnt;
705 res = lstat(mnt, stbuf);
707 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
708 progname, mnt, strerror(errno));
712 /* No permission checking is done for root */
716 if (S_ISDIR(stbuf->st_mode)) {
717 *currdir_fd = open(".", O_RDONLY);
718 if (*currdir_fd == -1) {
719 fprintf(stderr, "%s: failed to open current directory: %s\n",
720 progname, strerror(errno));
725 fprintf(stderr, "%s: failed to chdir to mountpoint: %s\n",
726 progname, strerror(errno));
730 res = lstat(mnt, stbuf);
732 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
733 progname, origmnt, strerror(errno));
737 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
738 fprintf(stderr, "%s: mountpoint %s not owned by user\n",
743 res = access(mnt, W_OK);
745 fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
749 } else if (S_ISREG(stbuf->st_mode)) {
750 static char procfile[256];
751 *mountpoint_fd = open(mnt, O_WRONLY);
752 if (*mountpoint_fd == -1) {
753 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mnt,
757 res = fstat(*mountpoint_fd, stbuf);
759 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
760 progname, mnt, strerror(errno));
763 if (!S_ISREG(stbuf->st_mode)) {
764 fprintf(stderr, "%s: mountpoint %s is no longer a regular file\n",
769 sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
773 "%s: mountpoint %s is not a directory or a regular file\n",
782 static int try_open(const char *dev, char **devp, int silent)
784 int fd = open(dev, O_RDWR);
786 if (fd == -1 && errno == ENOENT && !strcmp(dev, FUSE_DEV_NEW)
787 && !mknod(dev, 0660 | S_IFCHR, MKDEV(MISC_MAJOR, 229))) {
790 fprintf(stderr, "%s: Notice: Created FUSE device: %s\n", progname, dev);
791 if ((group = getgrnam("fuse")) && !chown(dev, 0, group->gr_gid))
792 fd = open(dev, O_RDWR);
797 fprintf(stderr, "%s: failed to allocate memory\n", progname);
801 } else if (errno == ENODEV)
804 fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
810 static int try_open_fuse_device(char **devp)
816 fd = try_open(FUSE_DEV_NEW, devp, 0);
822 fd = try_open(FUSE_DEV_OLD, devp, 1);
829 static int open_fuse_device(char **devp)
831 int fd = try_open_fuse_device(devp);
837 "%s: fuse device not found, try 'modprobe fuse' first\n",
843 static int mount_fuse(const char *mnt, const char *opts)
848 const char *type = "fuse";
851 char *mnt_opts = NULL;
852 const char *real_mnt = mnt;
854 int mountpoint_fd = -1;
857 fd = open_fuse_device(&dev);
861 if (geteuid() == 0) {
862 mtablock = lock_mtab();
872 if (getuid() != 0 && mount_max != -1) {
873 int mount_count = count_fuse_fs();
874 if (mount_count >= mount_max) {
875 fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
877 unlock_mtab(mtablock);
882 res = check_version(dev);
884 res = check_perm(&real_mnt, &stbuf, &currdir_fd, &mountpoint_fd);
887 res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT, fd, opts,
888 dev, &fsname, &mnt_opts, stbuf.st_size);
892 if (currdir_fd != -1) {
896 if (mountpoint_fd != -1)
897 close(mountpoint_fd);
901 unlock_mtab(mtablock);
905 if (geteuid() == 0) {
906 res = add_mount(fsname, mnt, type, mnt_opts);
907 unlock_mtab(mtablock);
909 umount2(mnt, 2); /* lazy umount */
922 static char *resolve_path(const char *orig)
929 const char *toresolv;
932 fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
938 fprintf(stderr, "%s: failed to allocate memory\n", progname);
944 for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
948 tmp = strrchr(copy, '/');
957 if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
964 if (realpath(toresolv, buf) == NULL) {
965 fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
970 if (lastcomp == NULL)
973 dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
975 unsigned buflen = strlen(buf);
976 if (buflen && buf[buflen-1] == '/')
977 sprintf(dst, "%s%s", buf, lastcomp);
979 sprintf(dst, "%s/%s", buf, lastcomp);
984 fprintf(stderr, "%s: failed to allocate memory\n", progname);
988 static int send_fd(int sock_fd, int fd)
992 struct cmsghdr *p_cmsg;
994 char cmsgbuf[CMSG_SPACE(sizeof(fd))];
998 msg.msg_control = cmsgbuf;
999 msg.msg_controllen = sizeof(cmsgbuf);
1000 p_cmsg = CMSG_FIRSTHDR(&msg);
1001 p_cmsg->cmsg_level = SOL_SOCKET;
1002 p_cmsg->cmsg_type = SCM_RIGHTS;
1003 p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1004 p_fds = (int *) CMSG_DATA(p_cmsg);
1006 msg.msg_controllen = p_cmsg->cmsg_len;
1007 msg.msg_name = NULL;
1008 msg.msg_namelen = 0;
1012 /* "To pass file descriptors or credentials you need to send/read at
1013 * least one byte" (man 7 unix) */
1014 vec.iov_base = &sendchar;
1015 vec.iov_len = sizeof(sendchar);
1016 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1018 perror("sending file descriptor");
1024 static void usage(void)
1027 "%s: [options] mountpoint\n"
1030 " -v print version\n"
1031 " -o opt[,opt...] mount options\n"
1034 " -z lazy unmount\n",
1039 static void show_version(void)
1041 printf("%s\n", PACKAGE_STRING);
1045 int main(int argc, char *argv[])
1052 static int unmount = 0;
1053 static int lazy = 0;
1054 static int quiet = 0;
1057 const char *opts = "";
1059 static const struct option long_opts[] = {
1060 {"unmount", no_argument, NULL, 'u'},
1061 {"lazy", no_argument, NULL, 'z'},
1062 {"quiet", no_argument, NULL, 'q'},
1063 {"help", no_argument, NULL, 'h'},
1064 {"version", no_argument, NULL, 'v'},
1068 captive_standalone_init();
1070 progname = strdup(argv[0]);
1071 if (progname == NULL) {
1072 fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1076 while ((ch = getopt_long(argc, argv, "hvo:uzq", long_opts, NULL)) != -1) {
1107 if (lazy && !unmount) {
1108 fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1112 if (optind >= argc) {
1113 fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1117 origmnt = argv[optind];
1120 mnt = resolve_path(origmnt);
1127 if (geteuid() == 0) {
1128 int mtablock = lock_mtab();
1129 res = unmount_fuse(mnt, quiet, lazy);
1130 unlock_mtab(mtablock);
1132 res = do_unmount(mnt, quiet, lazy);
1138 commfd = getenv(FUSE_COMMFD_ENV);
1139 if (commfd == NULL) {
1140 fprintf(stderr, "%s: old style mounting not supported\n", progname);
1144 fd = mount_fuse(mnt, opts);
1149 res = send_fd(cfd, fd);