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>
45 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
47 #define FUSE_DEV_OLD "/proc/fs/fuse/dev"
48 #define FUSE_DEV_NEW "/dev/fuse"
49 #define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
50 #define FUSE_CONF "/etc/fuse.conf"
52 static const char *progname;
54 static int user_allow_other = 0;
55 static int mount_max = 1000;
57 static const char *get_user_name(void)
59 struct passwd *pw = getpwuid(getuid());
60 if (pw != NULL && pw->pw_name != NULL)
63 fprintf(stderr, "%s: could not determine username\n", progname);
68 static uid_t oldfsuid;
69 static gid_t oldfsgid;
71 static void drop_privs(void)
74 oldfsuid = setfsuid(getuid());
75 oldfsgid = setfsgid(getgid());
79 static void restore_privs(void)
87 static int do_unmount(const char *mnt, int quiet, int lazy)
89 int res = umount2(mnt, lazy ? 2 : 0);
92 fprintf(stderr, "%s: failed to unmount %s: %s\n",
93 progname, mnt, strerror(errno));
99 /* use a lock file so that multiple fusermount processes don't try and
100 modify the mtab file at once! */
101 static int lock_mtab(void)
103 const char *mtab_lock = _PATH_MOUNTED ".fuselock";
107 mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
109 res = lockf(mtablock, F_LOCK, 0);
111 fprintf(stderr, "%s: error getting lock", progname);
113 fprintf(stderr, "%s: unable to open fuse lock file\n", progname);
118 static void unlock_mtab(int mtablock)
121 lockf(mtablock, F_ULOCK, 0);
126 /* Glibc addmntent() doesn't encode '\n', misencodes '\t' as '\n'
127 (version 2.3.2), and encodes '\\' differently as mount(8). So
128 let's not allow those characters, they are not all that usual in
130 static int check_name(const char *name)
133 for (s = "\n\t\\"; *s; s++) {
134 if (strchr(name, *s)) {
135 fprintf(stderr, "%s: illegal character 0x%02x in mount entry\n",
143 static int add_mount(const char *fsname, const char *mnt, const char *type,
147 const char *mtab = _PATH_MOUNTED;
151 if (check_name(fsname) == -1 || check_name(mnt) == -1 ||
152 check_name(type) == -1 || check_name(opts) == -1)
155 fp = setmntent(mtab, "a");
157 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
162 ent.mnt_fsname = (char *) fsname;
163 ent.mnt_dir = (char *) mnt;
164 ent.mnt_type = (char *) type;
165 ent.mnt_opts = (char *) opts;
168 res = addmntent(fp, &ent);
170 fprintf(stderr, "%s: failed to add entry to %s: %s\n", progname,
171 mtab, strerror(errno));
179 static int remove_mount(const char *mnt, int quiet, const char *mtab,
180 const char *mtab_new)
186 const char *user = NULL;
191 fp = setmntent(mtab, "r");
193 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
198 newfp = setmntent(mtab_new, "w");
200 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab_new,
206 user = get_user_name();
210 uidlen = sprintf(uidstr, "%u", getuid());
214 while ((entp = getmntent(fp)) != NULL) {
216 if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
217 strcmp(entp->mnt_type, "fuse") == 0) {
221 char *p = strstr(entp->mnt_opts, "user=");
222 if (p && (p == entp->mnt_opts || *(p-1) == ',') &&
223 strcmp(p + 5, user) == 0)
225 /* /etc/mtab is a link pointing to /proc/mounts: */
226 else if ((p = strstr(entp->mnt_opts, "user_id=")) &&
227 (p == entp->mnt_opts || *(p-1) == ',') &&
228 strncmp(p + 8, uidstr, uidlen) == 0 &&
229 (*(p+8+uidlen) == ',' || *(p+8+uidlen) == '\0'))
236 res = addmntent(newfp, entp);
238 fprintf(stderr, "%s: failed to add entry to %s: %s\n",
239 progname, mtab_new, strerror(errno));
249 fprintf(stderr, "%s: entry for %s not found in %s\n", progname,
258 static int count_fuse_fs(void)
262 const char *mtab = _PATH_MOUNTED;
263 FILE *fp = setmntent(mtab, "r");
265 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
269 while ((entp = getmntent(fp)) != NULL) {
270 if (strcmp(entp->mnt_type, "fuse") == 0)
277 static int unmount_rename(const char *mnt, int quiet, int lazy,
278 const char *mtab, const char *mtab_new)
284 res = do_unmount(mnt, quiet, lazy);
289 if (stat(mtab, &sbuf) == 0)
290 chown(mtab_new, sbuf.st_uid, sbuf.st_gid);
292 res = rename(mtab_new, mtab);
294 fprintf(stderr, "%s: failed to rename %s to %s: %s\n", progname,
295 mtab_new, mtab, strerror(errno));
301 static int unmount_fuse(const char *mnt, int quiet, int lazy)
304 const char *mtab = _PATH_MOUNTED;
305 const char *mtab_new = _PATH_MOUNTED "~fuse~";
307 res = remove_mount(mnt, quiet, mtab, mtab_new);
311 res = unmount_rename(mnt, quiet, lazy, mtab, mtab_new);
318 #else /* IGNORE_MTAB */
319 static int lock_mtab()
324 static void unlock_mtab(int mtablock)
329 static int count_fuse_fs()
334 static int add_mount(const char *fsname, const char *mnt, const char *type,
344 static int unmount_fuse(const char *mnt, int quiet, int lazy)
346 return do_unmount(mnt, quiet, lazy);
348 #endif /* IGNORE_MTAB */
350 static void strip_line(char *line)
352 char *s = strchr(line, '#');
355 for (s = line + strlen(line) - 1; s >= line && isspace((unsigned char) *s); s--);
357 for (s = line; isspace((unsigned char) *s); s++);
359 memmove(line, s, strlen(s)+1);
362 static void parse_line(char *line, int linenum)
365 if (strcmp(line, "user_allow_other") == 0)
366 user_allow_other = 1;
367 else if (sscanf(line, "mount_max = %i", &tmp) == 1)
370 fprintf(stderr, "%s: unknown parameter in %s at line %i: '%s'\n",
371 progname, FUSE_CONF, linenum, line);
374 static void read_conf(void)
376 FILE *fp = fopen(FUSE_CONF, "r");
381 while (fgets(line, sizeof(line), fp) != NULL) {
383 if (line[strlen(line)-1] == '\n') {
385 parse_line(line, linenum);
387 fprintf(stderr, "%s: reading %s: line %i too long\n",
388 progname, FUSE_CONF, linenum);
391 } else if(line[strlen(line)-1] == '\n')
397 } else if (errno != ENOENT) {
398 fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF,
403 static int begins_with(const char *s, const char *beg)
405 if (strncmp(s, beg, strlen(beg)) == 0)
418 static struct mount_flags mount_flags[] = {
419 {"rw", MS_RDONLY, 0, 1},
420 {"ro", MS_RDONLY, 1, 1},
421 {"suid", MS_NOSUID, 0, 0},
422 {"nosuid", MS_NOSUID, 1, 1},
423 {"dev", MS_NODEV, 0, 0},
424 {"nodev", MS_NODEV, 1, 1},
425 {"exec", MS_NOEXEC, 0, 1},
426 {"noexec", MS_NOEXEC, 1, 1},
427 {"async", MS_SYNCHRONOUS, 0, 1},
428 {"sync", MS_SYNCHRONOUS, 1, 1},
429 {"atime", MS_NOATIME, 0, 1},
430 {"noatime", MS_NOATIME, 1, 1},
434 static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
438 for (i = 0; mount_flags[i].opt != NULL; i++) {
439 const char *opt = mount_flags[i].opt;
440 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
441 *on = mount_flags[i].on;
442 *flag = mount_flags[i].flag;
443 if (!mount_flags[i].safe && getuid() != 0) {
445 fprintf(stderr, "%s: unsafe option %s ignored\n",
454 static int add_option(char **optsp, const char *opt, unsigned expand)
458 newopts = strdup(opt);
460 unsigned oldsize = strlen(*optsp);
461 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
462 newopts = (char *) realloc(*optsp, newsize);
464 sprintf(newopts + oldsize, ",%s", opt);
466 if (newopts == NULL) {
467 fprintf(stderr, "%s: failed to allocate memory\n", progname);
474 static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
479 if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
482 for (i = 0; mount_flags[i].opt != NULL; i++) {
483 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
484 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
488 if (add_option(mnt_optsp, opts, 0) == -1)
490 /* remove comma from end of opts*/
491 l = strlen(*mnt_optsp);
492 if ((*mnt_optsp)[l-1] == ',')
493 (*mnt_optsp)[l-1] = '\0';
495 const char *user = get_user_name();
499 if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
501 strcat(*mnt_optsp, user);
506 static int opt_eq(const char *s, unsigned len, const char *opt)
508 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
514 static int check_mountpoint_empty(const char *mnt, mode_t rootmode,
519 if (S_ISDIR(rootmode)) {
521 DIR *dp = opendir(mnt);
523 fprintf(stderr, "%s: failed to mountpoint for reading: %s\n",
524 progname, strerror(errno));
527 while ((ent = readdir(dp)) != NULL) {
528 if (strcmp(ent->d_name, ".") != 0 &&
529 strcmp(ent->d_name, "..") != 0) {
539 fprintf(stderr, "%s: mountpoint is not empty\n", progname);
540 fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
546 static int do_mount(const char *mnt, const char *type, mode_t rootmode,
547 int fd, const char *opts, const char *dev, char **fsnamep,
548 char **mnt_optsp, off_t rootsize)
551 int flags = MS_NOSUID | MS_NODEV;
553 char *mnt_opts = NULL;
559 optbuf = (char *) malloc(strlen(opts) + 128);
561 fprintf(stderr, "%s: failed to allocate memory\n", progname);
565 for (s = opts, d = optbuf; *s;) {
567 const char *fsname_str = "fsname=";
568 for (len = 0; s[len] && s[len] != ','; len++);
569 if (begins_with(s, fsname_str)) {
570 unsigned fsname_str_len = strlen(fsname_str);
573 fsname = (char *) malloc(len - fsname_str_len + 1);
575 fprintf(stderr, "%s: failed to allocate memory\n", progname);
578 memcpy(fsname, s + fsname_str_len, len - fsname_str_len);
579 fsname[len - fsname_str_len] = '\0';
580 } else if (opt_eq(s, len, "nonempty")) {
582 } else if (!begins_with(s, "fd=") &&
583 !begins_with(s, "rootmode=") &&
584 !begins_with(s, "user_id=") &&
585 !begins_with(s, "group_id=")) {
589 if (opt_eq(s, len, "large_read")) {
590 struct utsname utsname;
592 res = uname(&utsname);
594 sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 &&
595 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
596 fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
600 if (getuid() != 0 && !user_allow_other &&
601 (opt_eq(s, len, "allow_other") ||
602 opt_eq(s, len, "allow_root"))) {
603 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
607 if (find_mount_flag(s, len, &on, &flag)) {
624 res = get_mnt_opts(flags, optbuf, &mnt_opts);
628 sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
629 fd, rootmode, getuid(), getgid());
630 if (fsname == NULL) {
631 fsname = strdup(dev);
633 fprintf(stderr, "%s: failed to allocate memory\n", progname);
638 if (check_empty && check_mountpoint_empty(mnt, rootmode, rootsize) == -1)
641 res = mount(fsname, mnt, type, flags, optbuf);
642 if (res == -1 && errno == EINVAL) {
643 /* It could be an old version not supporting group_id */
644 sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid());
645 res = mount(fsname, mnt, type, flags, optbuf);
648 fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno));
652 *mnt_optsp = mnt_opts;
665 static int check_version(const char *dev)
670 const char *version_file;
673 if (strcmp(dev, FUSE_DEV_OLD) != 0)
676 version_file = FUSE_VERSION_FILE_OLD;
677 vf = fopen(version_file, "r");
679 fprintf(stderr, "%s: kernel interface too old\n", progname);
682 res = fscanf(vf, "%i.%i", &majorver, &minorver);
685 fprintf(stderr, "%s: error reading %s\n", progname, version_file);
689 fprintf(stderr, "%s: kernel interface too old\n", progname);
695 static int check_perm(const char **mntp, struct stat *stbuf, int *currdir_fd,
699 const char *mnt = *mntp;
700 const char *origmnt = mnt;
702 res = lstat(mnt, stbuf);
704 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
705 progname, mnt, strerror(errno));
709 /* No permission checking is done for root */
713 if (S_ISDIR(stbuf->st_mode)) {
714 *currdir_fd = open(".", O_RDONLY);
715 if (*currdir_fd == -1) {
716 fprintf(stderr, "%s: failed to open current directory: %s\n",
717 progname, strerror(errno));
722 fprintf(stderr, "%s: failed to chdir to mountpoint: %s\n",
723 progname, strerror(errno));
727 res = lstat(mnt, stbuf);
729 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
730 progname, origmnt, strerror(errno));
734 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
735 fprintf(stderr, "%s: mountpoint %s not owned by user\n",
740 res = access(mnt, W_OK);
742 fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
746 } else if (S_ISREG(stbuf->st_mode)) {
747 static char procfile[256];
748 *mountpoint_fd = open(mnt, O_WRONLY);
749 if (*mountpoint_fd == -1) {
750 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mnt,
754 res = fstat(*mountpoint_fd, stbuf);
756 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
757 progname, mnt, strerror(errno));
760 if (!S_ISREG(stbuf->st_mode)) {
761 fprintf(stderr, "%s: mountpoint %s is no longer a regular file\n",
766 sprintf(procfile, "/proc/self/fd/%i", *mountpoint_fd);
770 "%s: mountpoint %s is not a directory or a regular file\n",
779 static int try_open(const char *dev, char **devp, int silent)
781 int fd = open(dev, O_RDWR);
785 fprintf(stderr, "%s: failed to allocate memory\n", progname);
789 } else if (errno == ENODEV)
792 fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev,
798 static int try_open_fuse_device(char **devp)
804 fd = try_open(FUSE_DEV_NEW, devp, 0);
810 fd = try_open(FUSE_DEV_OLD, devp, 1);
817 static int open_fuse_device(char **devp)
819 int fd = try_open_fuse_device(devp);
825 "%s: fuse device not found, try 'modprobe fuse' first\n",
831 static int mount_fuse(const char *mnt, const char *opts)
836 const char *type = "fuse";
839 char *mnt_opts = NULL;
840 const char *real_mnt = mnt;
842 int mountpoint_fd = -1;
845 fd = open_fuse_device(&dev);
849 if (geteuid() == 0) {
850 mtablock = lock_mtab();
860 if (getuid() != 0 && mount_max != -1) {
861 int mount_count = count_fuse_fs();
862 if (mount_count >= mount_max) {
863 fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname);
865 unlock_mtab(mtablock);
870 res = check_version(dev);
872 res = check_perm(&real_mnt, &stbuf, &currdir_fd, &mountpoint_fd);
875 res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT, fd, opts,
876 dev, &fsname, &mnt_opts, stbuf.st_size);
880 if (currdir_fd != -1) {
884 if (mountpoint_fd != -1)
885 close(mountpoint_fd);
889 unlock_mtab(mtablock);
893 if (geteuid() == 0) {
894 res = add_mount(fsname, mnt, type, mnt_opts);
895 unlock_mtab(mtablock);
897 umount2(mnt, 2); /* lazy umount */
910 static char *resolve_path(const char *orig)
917 const char *toresolv;
920 fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
926 fprintf(stderr, "%s: failed to allocate memory\n", progname);
932 for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
936 tmp = strrchr(copy, '/');
945 if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
952 if (realpath(toresolv, buf) == NULL) {
953 fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
958 if (lastcomp == NULL)
961 dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
963 unsigned buflen = strlen(buf);
964 if (buflen && buf[buflen-1] == '/')
965 sprintf(dst, "%s%s", buf, lastcomp);
967 sprintf(dst, "%s/%s", buf, lastcomp);
972 fprintf(stderr, "%s: failed to allocate memory\n", progname);
976 static int send_fd(int sock_fd, int fd)
980 struct cmsghdr *p_cmsg;
982 char cmsgbuf[CMSG_SPACE(sizeof(fd))];
986 msg.msg_control = cmsgbuf;
987 msg.msg_controllen = sizeof(cmsgbuf);
988 p_cmsg = CMSG_FIRSTHDR(&msg);
989 p_cmsg->cmsg_level = SOL_SOCKET;
990 p_cmsg->cmsg_type = SCM_RIGHTS;
991 p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
992 p_fds = (int *) CMSG_DATA(p_cmsg);
994 msg.msg_controllen = p_cmsg->cmsg_len;
1000 /* "To pass file descriptors or credentials you need to send/read at
1001 * least one byte" (man 7 unix) */
1002 vec.iov_base = &sendchar;
1003 vec.iov_len = sizeof(sendchar);
1004 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1006 perror("sending file descriptor");
1012 static void usage(void)
1015 "%s: [options] mountpoint\n"
1018 " -v print version\n"
1019 " -o opt[,opt...] mount options\n"
1022 " -z lazy unmount\n",
1027 static void show_version(void)
1029 printf("%s\n", PACKAGE_STRING);
1033 int main(int argc, char *argv[])
1040 static int unmount = 0;
1041 static int lazy = 0;
1042 static int quiet = 0;
1045 const char *opts = "";
1047 static const struct option long_opts[] = {
1048 {"unmount", no_argument, NULL, 'u'},
1049 {"lazy", no_argument, NULL, 'z'},
1050 {"quiet", no_argument, NULL, 'q'},
1051 {"help", no_argument, NULL, 'h'},
1052 {"version", no_argument, NULL, 'v'},
1056 captive_standalone_init();
1058 progname = strdup(argv[0]);
1059 if (progname == NULL) {
1060 fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
1064 while ((ch = getopt_long(argc, argv, "hvo:uzq", long_opts, NULL)) != -1) {
1095 if (lazy && !unmount) {
1096 fprintf(stderr, "%s: -z can only be used with -u\n", progname);
1100 if (optind >= argc) {
1101 fprintf(stderr, "%s: missing mountpoint argument\n", progname);
1105 origmnt = argv[optind];
1108 mnt = resolve_path(origmnt);
1115 if (geteuid() == 0) {
1116 int mtablock = lock_mtab();
1117 res = unmount_fuse(mnt, quiet, lazy);
1118 unlock_mtab(mtablock);
1120 res = do_unmount(mnt, quiet, lazy);
1126 commfd = getenv(FUSE_COMMFD_ENV);
1127 if (commfd == NULL) {
1128 fprintf(stderr, "%s: old style mounting not supported\n", progname);
1132 fd = mount_fuse(mnt, opts);
1137 res = send_fd(cfd, fd);