11#include "fuse_config.h"
12#include "mount_util.h"
30#include "fuse_mount_compat.h"
33#include <sys/socket.h>
34#include <sys/utsname.h>
39#if defined HAVE_CLOSE_RANGE && defined linux
40#include <linux/close_range.h>
43#if defined HAVE_LISTMOUNT
44#include <linux/mount.h>
49#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
50#define FUSE_KERN_DEVICE_ENV "FUSE_KERN_DEVICE"
52#define FUSE_DEV "/dev/fuse"
54static const char *progname;
56static int user_allow_other = 0;
57static int mount_max = 1000;
59static int auto_unmount = 0;
61#ifdef GETMNTENT_NEEDS_UNESCAPING
66static void unescape(
char *buf) {
70 char *next_src = strchrnul(src,
'\\');
71 int offset = next_src - src;
72 memmove(dest, src, offset);
82 if(
'0' <= src[0] && src[0] <
'2' &&
83 '0' <= src[1] && src[1] <
'8' &&
84 '0' <= src[2] && src[2] <
'8') {
85 *dest++ = (src[0] -
'0') << 6
87 | (src[2] -
'0') << 0;
89 }
else if (src[0] ==
'\\') {
98static struct mntent *GETMNTENT(FILE *stream)
100 struct mntent *entp = getmntent(stream);
102 unescape(entp->mnt_fsname);
103 unescape(entp->mnt_dir);
104 unescape(entp->mnt_type);
105 unescape(entp->mnt_opts);
110#define GETMNTENT getmntent
116static int extract_x_options(
const char *original,
char **non_x_opts,
120 const char *opt, *opt_end;
122 orig_len = strlen(original) + 1;
124 *non_x_opts = calloc(1, orig_len);
125 *x_opts = calloc(1, orig_len);
127 size_t non_x_opts_len = orig_len;
128 size_t x_opts_len = orig_len;
130 if (*non_x_opts == NULL || *x_opts == NULL) {
131 fprintf(stderr,
"%s: Failed to allocate %zuB.\n",
136 for (opt = original; opt < original + orig_len; opt = opt_end + 1) {
139 opt_end = strchr(opt,
',');
141 opt_end = original + orig_len;
143 size_t opt_len = opt_end - opt;
144 size_t opt_len_left = orig_len - (opt - original);
148 if (strncmp(opt,
"x-", MIN(2, opt_len_left)) == 0) {
149 buf_len = x_opts_len;
153 buf_len = non_x_opts_len;
155 opt_buf = *non_x_opts;
158 if (buf_len < orig_len) {
159 strncat(opt_buf,
",", 2);
164 if ((ssize_t)(buf_len - opt_len) < 0) {
166 fprintf(stderr,
"%s: no buf space left in copy, orig='%s'\n",
171 strncat(opt_buf, opt, opt_end - opt);
175 x_opts_len = buf_len;
177 non_x_opts_len = buf_len;
183static const char *get_user_name(
void)
185 struct passwd *pw = getpwuid(getuid());
186 if (pw != NULL && pw->pw_name != NULL)
189 fprintf(stderr,
"%s: could not determine username\n", progname);
194static uid_t oldfsuid;
195static gid_t oldfsgid;
197static void drop_privs(
void)
200 oldfsuid = setfsuid(getuid());
201 oldfsgid = setfsgid(getgid());
205static void restore_privs(
void)
217static int lock_umount(
void)
219 const char *mtab_lock = _PATH_MOUNTED
".fuselock";
222 struct stat mtab_stat;
225 if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
228 mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
229 if (mtablock == -1) {
230 fprintf(stderr,
"%s: unable to open fuse lock file: %s\n",
231 progname, strerror(errno));
234 res = lockf(mtablock, F_LOCK, 0);
236 fprintf(stderr,
"%s: error getting lock: %s\n", progname,
245static void unlock_umount(
int mtablock)
250 res = lockf(mtablock, F_ULOCK, 0);
252 fprintf(stderr,
"%s: error releasing lock: %s\n",
253 progname, strerror(errno));
259static int add_mount(
const char *source,
const char *mnt,
const char *type,
262 return fuse_mnt_add_mount(progname, source, mnt, type, opts);
265static int may_unmount(
const char *mnt,
int quiet)
269 const char *user = NULL;
273 const char *mtab = _PATH_MOUNTED;
275 user = get_user_name();
279 fp = setmntent(mtab,
"r");
281 fprintf(stderr,
"%s: failed to open %s: %s\n", progname, mtab,
286 uidlen = sprintf(uidstr,
"%u", getuid());
289 while ((entp = GETMNTENT(fp)) != NULL) {
290 if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
291 (strcmp(entp->mnt_type,
"fuse") == 0 ||
292 strcmp(entp->mnt_type,
"fuseblk") == 0 ||
293 strncmp(entp->mnt_type,
"fuse.", 5) == 0 ||
294 strncmp(entp->mnt_type,
"fuseblk.", 8) == 0)) {
295 char *p = strstr(entp->mnt_opts,
"user=");
297 (p == entp->mnt_opts || *(p-1) ==
',') &&
298 strcmp(p + 5, user) == 0) {
305 strstr(entp->mnt_opts,
"user_id=")) &&
306 (p == entp->mnt_opts ||
308 strncmp(p + 8, uidstr, uidlen) == 0 &&
309 (*(p+8+uidlen) ==
',' ||
310 *(p+8+uidlen) ==
'\0')) {
321 "%s: entry for %s not found in %s\n",
322 progname, mnt, mtab);
353static int check_is_mount_child(
void *p)
356 const char *last = a[0];
357 const char *mnt = a[1];
358 const char *type = a[2];
360 const char *procmounts =
"/proc/mounts";
366 res = mount(
"",
"/",
"", MS_PRIVATE | MS_REC, NULL);
368 fprintf(stderr,
"%s: failed to mark mounts private: %s\n",
369 progname, strerror(errno));
373 fp = setmntent(procmounts,
"r");
375 fprintf(stderr,
"%s: failed to open %s: %s\n", progname,
376 procmounts, strerror(errno));
381 while (GETMNTENT(fp) != NULL)
385 fp = setmntent(procmounts,
"r");
387 fprintf(stderr,
"%s: failed to open %s: %s\n", progname,
388 procmounts, strerror(errno));
392 res = mount(
".",
"/",
"", MS_BIND | MS_REC, NULL);
394 fprintf(stderr,
"%s: failed to bind parent to /: %s\n",
395 progname, strerror(errno));
400 while ((entp = GETMNTENT(fp)) != NULL) {
405 if (entp->mnt_dir[0] ==
'/' &&
406 strcmp(entp->mnt_dir + 1, last) == 0 &&
407 (!type || strcmp(entp->mnt_type, type) == 0)) {
415 fprintf(stderr,
"%s: %s not mounted\n", progname, mnt);
422static pid_t clone_newns(
void *a)
425 char *stack = buf + (
sizeof(buf) / 2 - ((
size_t) buf & 15));
428 extern int __clone2(
int (*fn)(
void *),
429 void *child_stack_base,
size_t stack_size,
430 int flags,
void *arg, pid_t *ptid,
431 void *tls, pid_t *ctid);
433 return __clone2(check_is_mount_child, stack,
sizeof(buf) / 2,
434 CLONE_NEWNS, a, NULL, NULL, NULL);
436 return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
440static int check_is_mount(
const char *last,
const char *mnt,
const char *type)
444 const char *a[3] = { last, mnt, type };
446 pid = clone_newns((
void *) a);
447 if (pid == (pid_t) -1) {
448 fprintf(stderr,
"%s: failed to clone namespace: %s\n",
449 progname, strerror(errno));
452 p = waitpid(pid, &status, __WCLONE);
453 if (p == (pid_t) -1) {
454 fprintf(stderr,
"%s: waitpid failed: %s\n",
455 progname, strerror(errno));
458 if (!WIFEXITED(status)) {
459 fprintf(stderr,
"%s: child terminated abnormally (status %i)\n",
463 if (WEXITSTATUS(status) != 0)
469static int chdir_to_parent(
char *copy,
const char **lastp)
476 tmp = strrchr(copy,
'/');
477 if (tmp == NULL || tmp[1] ==
'\0') {
478 fprintf(stderr,
"%s: internal error: invalid abs path: <%s>\n",
486 }
else if (tmp[1] !=
'\0') {
496 fprintf(stderr,
"%s: failed to chdir to %s: %s\n",
497 progname, parent, strerror(errno));
501 if (getcwd(buf,
sizeof(buf)) == NULL) {
502 fprintf(stderr,
"%s: failed to obtain current directory: %s\n",
503 progname, strerror(errno));
506 if (strcmp(buf, parent) != 0) {
507 fprintf(stderr,
"%s: mountpoint moved (%s -> %s)\n", progname,
517static int unmount_fuse_locked(
const char *mnt,
int quiet,
int lazy)
522 int umount_flags = (lazy ? UMOUNT_DETACH : 0) | UMOUNT_NOFOLLOW;
525 res = may_unmount(mnt, quiet);
532 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
537 res = chdir_to_parent(copy, &last);
543 res = umount2(last, umount_flags);
545 if (res == -1 && !quiet) {
546 fprintf(stderr,
"%s: failed to unmount %s: %s\n",
547 progname, mnt, strerror(errno));
557 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
561 return fuse_mnt_remove_mount(progname, mnt);
564static int unmount_fuse(
const char *mnt,
int quiet,
int lazy)
567 int mtablock = lock_umount();
569 res = unmount_fuse_locked(mnt, quiet, lazy);
570 unlock_umount(mtablock);
575static int count_fuse_fs_mtab(
void)
579 const char *mtab = _PATH_MOUNTED;
580 FILE *fp = setmntent(mtab,
"r");
582 fprintf(stderr,
"%s: failed to open %s: %s\n", progname, mtab,
586 while ((entp = GETMNTENT(fp)) != NULL) {
587 if (strcmp(entp->mnt_type,
"fuse") == 0 ||
588 strncmp(entp->mnt_type,
"fuse.", 5) == 0)
596static int count_fuse_fs_ls_mnt(
void)
598 #define SMBUF_SIZE 1024
599 #define MNT_ID_LEN 128
604 uint64_t mnt_ids[MNT_ID_LEN];
605 unsigned char smbuf[SMBUF_SIZE];
606 struct mnt_id_req req = {
607 .size =
sizeof(
struct mnt_id_req),
609 struct statmount *sm;
612 req.mnt_id = LSMT_ROOT;
614 n_mounts = syscall(SYS_listmount, &req, &mnt_ids, MNT_ID_LEN, 0);
615 if (n_mounts == -1) {
616 if (errno != ENOSYS) {
617 fprintf(stderr,
"%s: failed to list mounts: %s\n", progname,
623 for (
int i = 0; i < n_mounts; i++) {
624 req.mnt_id = mnt_ids[i];
625 req.param = STATMOUNT_FS_TYPE;
626 ret = syscall(SYS_statmount, &req, &smbuf, SMBUF_SIZE, 0);
631 fprintf(stderr,
"%s: failed to stat mount %lld: %s\n", progname,
632 req.mnt_id, strerror(errno));
636 sm = (
struct statmount *)smbuf;
637 if (sm->mask & STATMOUNT_FS_TYPE &&
638 strcmp(&sm->str[sm->fs_type],
"fuse") == 0)
642 if (n_mounts < MNT_ID_LEN)
644 req.param = mnt_ids[MNT_ID_LEN - 1];
649static int count_fuse_fs(
void)
651 int count = count_fuse_fs_ls_mnt();
653 return count >= 0 ? count : count_fuse_fs_mtab();
656static int count_fuse_fs(
void)
658 return count_fuse_fs_mtab();
663static int count_fuse_fs(
void)
668static int add_mount(
const char *source,
const char *mnt,
const char *type,
678static int unmount_fuse(
const char *mnt,
int quiet,
int lazy)
681 return fuse_mnt_umount(progname, mnt, mnt, lazy);
685static void strip_line(
char *line)
687 char *s = strchr(line,
'#');
690 for (s = line + strlen(line) - 1;
691 s >= line && isspace((
unsigned char) *s); s--);
693 for (s = line; isspace((
unsigned char) *s); s++);
695 memmove(line, s, strlen(s)+1);
698static void parse_line(
char *line,
int linenum)
701 if (strcmp(line,
"user_allow_other") == 0)
702 user_allow_other = 1;
703 else if (sscanf(line,
"mount_max = %i", &tmp) == 1)
707 "%s: unknown parameter in %s at line %i: '%s'\n",
708 progname, FUSE_CONF, linenum, line);
711static void read_conf(
void)
713 FILE *fp = fopen(FUSE_CONF,
"r");
718 while (fgets(line,
sizeof(line), fp) != NULL) {
720 if (line[strlen(line)-1] ==
'\n') {
722 parse_line(line, linenum);
726 }
else if(line[strlen(line)-1] ==
'\n') {
727 fprintf(stderr,
"%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
735 fprintf(stderr,
"%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
739 fprintf(stderr,
"%s: reading %s: read failed\n", progname, FUSE_CONF);
743 }
else if (errno != ENOENT) {
744 bool fatal = (errno != EACCES && errno != ELOOP &&
745 errno != ENAMETOOLONG && errno != ENOTDIR &&
747 fprintf(stderr,
"%s: failed to open %s: %s\n",
748 progname, FUSE_CONF, strerror(errno));
754static int begins_with(
const char *s,
const char *beg)
756 if (strncmp(s, beg, strlen(beg)) == 0)
769static struct mount_flags mount_flags[] = {
770 {
"rw", MS_RDONLY, 0, 1},
771 {
"ro", MS_RDONLY, 1, 1},
772 {
"suid", MS_NOSUID, 0, 0},
773 {
"nosuid", MS_NOSUID, 1, 1},
774 {
"dev", MS_NODEV, 0, 0},
775 {
"nodev", MS_NODEV, 1, 1},
776 {
"exec", MS_NOEXEC, 0, 1},
777 {
"noexec", MS_NOEXEC, 1, 1},
778 {
"async", MS_SYNCHRONOUS, 0, 1},
779 {
"sync", MS_SYNCHRONOUS, 1, 1},
780 {
"atime", MS_NOATIME, 0, 1},
781 {
"noatime", MS_NOATIME, 1, 1},
782 {
"diratime", MS_NODIRATIME, 0, 1},
783 {
"nodiratime", MS_NODIRATIME, 1, 1},
784 {
"lazytime", MS_LAZYTIME, 1, 1},
785 {
"nolazytime", MS_LAZYTIME, 0, 1},
786 {
"relatime", MS_RELATIME, 1, 1},
787 {
"norelatime", MS_RELATIME, 0, 1},
788 {
"strictatime", MS_STRICTATIME, 1, 1},
789 {
"nostrictatime", MS_STRICTATIME, 0, 1},
790 {
"dirsync", MS_DIRSYNC, 1, 1},
791 {
"symfollow", MS_NOSYMFOLLOW, 0, 1},
792 {
"nosymfollow", MS_NOSYMFOLLOW, 1, 1},
796static int find_mount_flag(
const char *s,
unsigned len,
int *on,
int *flag)
800 for (i = 0; mount_flags[i].opt != NULL; i++) {
801 const char *opt = mount_flags[i].opt;
802 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
803 *on = mount_flags[i].on;
804 *flag = mount_flags[i].flag;
805 if (!mount_flags[i].safe && getuid() != 0) {
808 "%s: unsafe option %s ignored\n",
817static int add_option(
char **optsp,
const char *opt,
unsigned expand)
821 newopts = strdup(opt);
823 unsigned oldsize = strlen(*optsp);
824 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
825 newopts = (
char *) realloc(*optsp, newsize);
827 sprintf(newopts + oldsize,
",%s", opt);
829 if (newopts == NULL) {
830 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
837static int get_mnt_opts(
int flags,
char *opts,
char **mnt_optsp)
842 if (!(flags & MS_RDONLY) && add_option(mnt_optsp,
"rw", 0) == -1)
845 for (i = 0; mount_flags[i].opt != NULL; i++) {
846 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
847 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
851 if (add_option(mnt_optsp, opts, 0) == -1)
854 l = strlen(*mnt_optsp);
855 if ((*mnt_optsp)[l-1] ==
',')
856 (*mnt_optsp)[l-1] =
'\0';
858 const char *user = get_user_name();
862 if (add_option(mnt_optsp,
"user=", strlen(user)) == -1)
864 strcat(*mnt_optsp, user);
869static int opt_eq(
const char *s,
unsigned len,
const char *opt)
871 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
877static int get_string_opt(
const char *s,
unsigned len,
const char *opt,
881 unsigned opt_len = strlen(opt);
886 *val = (
char *) malloc(len - opt_len + 1);
888 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
895 for (i = 0; i < len; i++) {
896 if (s[i] ==
'\\' && i + 1 < len)
909static int mount_notrunc(
const char *source,
const char *target,
910 const char *filesystemtype,
unsigned long mountflags,
912 if (strlen(data) > sysconf(_SC_PAGESIZE) - 1) {
913 fprintf(stderr,
"%s: mount options too long\n", progname);
917 return mount(source, target, filesystemtype, mountflags, data);
921static int do_mount(
const char *mnt,
const char **typep, mode_t rootmode,
922 int fd,
const char *opts,
const char *dev,
char **sourcep,
926 int flags = MS_NOSUID | MS_NODEV;
928 char *mnt_opts = NULL;
932 char *subtype = NULL;
937 optbuf = (
char *) malloc(strlen(opts) + 128);
939 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
943 for (s = opts, d = optbuf; *s;) {
945 const char *fsname_str =
"fsname=";
946 const char *subtype_str =
"subtype=";
947 bool escape_ok = begins_with(s, fsname_str) ||
948 begins_with(s, subtype_str);
949 for (len = 0; s[len]; len++) {
950 if (escape_ok && s[len] ==
'\\' && s[len + 1])
952 else if (s[len] ==
',')
955 if (begins_with(s, fsname_str)) {
956 if (!get_string_opt(s, len, fsname_str, &fsname))
958 }
else if (begins_with(s, subtype_str)) {
959 if (!get_string_opt(s, len, subtype_str, &subtype))
961 }
else if (opt_eq(s, len,
"blkdev")) {
964 "%s: option blkdev is privileged\n",
969 }
else if (opt_eq(s, len,
"auto_unmount")) {
971 }
else if (!opt_eq(s, len,
"nonempty") &&
972 !begins_with(s,
"fd=") &&
973 !begins_with(s,
"rootmode=") &&
974 !begins_with(s,
"user_id=") &&
975 !begins_with(s,
"group_id=")) {
979 if (opt_eq(s, len,
"large_read")) {
980 struct utsname utsname;
982 res = uname(&utsname);
984 sscanf(utsname.release,
"%u.%u",
985 &kmaj, &kmin) == 2 &&
986 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
987 fprintf(stderr,
"%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
991 if (getuid() != 0 && !user_allow_other &&
992 (opt_eq(s, len,
"allow_other") ||
993 opt_eq(s, len,
"allow_root"))) {
994 fprintf(stderr,
"%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
998 if (find_mount_flag(s, len, &on, &flag)) {
1003 }
else if (opt_eq(s, len,
"default_permissions") ||
1004 opt_eq(s, len,
"allow_other") ||
1005 begins_with(s,
"max_read=") ||
1006 begins_with(s,
"blksize=")) {
1011 fprintf(stderr,
"%s: unknown option '%.*s'\n", progname, len, s);
1021 res = get_mnt_opts(flags, optbuf, &mnt_opts);
1025 sprintf(d,
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
1026 fd, rootmode, getuid(), getgid());
1028 source = malloc((fsname ? strlen(fsname) : 0) +
1029 (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
1031 type = malloc((subtype ? strlen(subtype) : 0) + 32);
1032 if (!type || !source) {
1033 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
1038 sprintf(type,
"%s.%s", blkdev ?
"fuseblk" :
"fuse", subtype);
1040 strcpy(type, blkdev ?
"fuseblk" :
"fuse");
1043 strcpy(source, fsname);
1045 strcpy(source, subtype ? subtype : dev);
1047 res = mount_notrunc(source, mnt, type, flags, optbuf);
1048 if (res == -1 && errno == ENODEV && subtype) {
1050 strcpy(type, blkdev ?
"fuseblk" :
"fuse");
1053 sprintf(source,
"%s#%s", subtype, fsname);
1055 strcpy(source, type);
1058 res = mount_notrunc(source, mnt, type, flags, optbuf);
1060 if (res == -1 && errno == EINVAL) {
1062 sprintf(d,
"fd=%i,rootmode=%o,user_id=%u",
1063 fd, rootmode, getuid());
1064 res = mount_notrunc(source, mnt, type, flags, optbuf);
1067 int errno_save = errno;
1068 if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
1069 fprintf(stderr,
"%s: 'fuseblk' support missing\n",
1072 fprintf(stderr,
"%s: mount failed: %s\n", progname,
1073 strerror(errno_save));
1078 *mnt_optsp = mnt_opts;
1094static int check_perm(
const char **mntp,
struct stat *stbuf,
int *mountpoint_fd)
1097 const char *mnt = *mntp;
1098 const char *origmnt = mnt;
1099 struct statfs fs_buf;
1102 res = lstat(mnt, stbuf);
1104 fprintf(stderr,
"%s: failed to access mountpoint %s: %s\n",
1105 progname, mnt, strerror(errno));
1113 if (S_ISDIR(stbuf->st_mode)) {
1117 "%s: failed to chdir to mountpoint: %s\n",
1118 progname, strerror(errno));
1122 res = lstat(mnt, stbuf);
1125 "%s: failed to access mountpoint %s: %s\n",
1126 progname, origmnt, strerror(errno));
1130 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
1131 fprintf(stderr,
"%s: mountpoint %s not owned by user\n",
1136 res = access(mnt, W_OK);
1138 fprintf(stderr,
"%s: user has no write access to mountpoint %s\n",
1142 }
else if (S_ISREG(stbuf->st_mode)) {
1143 static char procfile[256];
1144 *mountpoint_fd = open(mnt, O_WRONLY);
1145 if (*mountpoint_fd == -1) {
1146 fprintf(stderr,
"%s: failed to open %s: %s\n",
1147 progname, mnt, strerror(errno));
1150 res = fstat(*mountpoint_fd, stbuf);
1153 "%s: failed to access mountpoint %s: %s\n",
1154 progname, mnt, strerror(errno));
1157 if (!S_ISREG(stbuf->st_mode)) {
1159 "%s: mountpoint %s is no longer a regular file\n",
1164 sprintf(procfile,
"/proc/self/fd/%i", *mountpoint_fd);
1168 "%s: mountpoint %s is not a directory or a regular file\n",
1179 if (statfs(*mntp, &fs_buf)) {
1180 fprintf(stderr,
"%s: failed to access mountpoint %s: %s\n",
1181 progname, mnt, strerror(errno));
1190 typeof(fs_buf.f_type) f_type_whitelist[] = {
1223#if __SIZEOF_LONG__ > 4
1224 0x736675005346544e ,
1230 for (i = 0; i <
sizeof(f_type_whitelist)/
sizeof(f_type_whitelist[0]); i++) {
1231 if (f_type_whitelist[i] == fs_buf.f_type)
1235 fprintf(stderr,
"%s: mounting over filesystem type %#010lx is forbidden\n",
1236 progname, (
unsigned long)fs_buf.f_type);
1240static int open_fuse_device(
const char *dev)
1245 fd = open(dev, O_RDWR);
1247 if (errno == ENODEV || errno == ENOENT)
1249 "%s: fuse device %s not found. Kernel module not loaded?\n",
1253 "%s: failed to open %s: %s\n", progname, dev, strerror(errno));
1259static int mount_fuse(
const char *mnt,
const char *opts,
const char **type)
1263 const char *dev = getenv(FUSE_KERN_DEVICE_ENV) ?: FUSE_DEV;
1265 char *source = NULL;
1266 char *mnt_opts = NULL;
1267 const char *real_mnt = mnt;
1268 int mountpoint_fd = -1;
1269 char *do_mount_opts = NULL;
1270 char *x_opts = NULL;
1272 fd = open_fuse_device(dev);
1279 if (getuid() != 0 && mount_max != -1) {
1280 int mount_count = count_fuse_fs();
1281 if (mount_count >= mount_max) {
1282 fprintf(stderr,
"%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
1288 res= extract_x_options(opts, &do_mount_opts, &x_opts);
1292 res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1295 res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT,
1296 fd, do_mount_opts, dev, &source, &mnt_opts);
1298 if (mountpoint_fd != -1)
1299 close(mountpoint_fd);
1306 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
1310 if (geteuid() == 0) {
1311 if (x_opts && strlen(x_opts) > 0) {
1316 size_t mnt_opts_len = strlen(mnt_opts);
1317 size_t x_mnt_opts_len = mnt_opts_len+
1319 char *x_mnt_opts = calloc(1, x_mnt_opts_len);
1322 strcpy(x_mnt_opts, mnt_opts);
1323 strncat(x_mnt_opts,
",", 2);
1326 strncat(x_mnt_opts, x_opts,
1327 x_mnt_opts_len - mnt_opts_len - 2);
1330 mnt_opts = x_mnt_opts;
1333 res = add_mount(source, mnt, *type, mnt_opts);
1344 free(do_mount_opts);
1354static int send_fd(
int sock_fd,
int fd)
1358 struct cmsghdr *p_cmsg;
1360 size_t cmsgbuf[CMSG_SPACE(
sizeof(fd)) /
sizeof(size_t)];
1364 msg.msg_control = cmsgbuf;
1365 msg.msg_controllen =
sizeof(cmsgbuf);
1366 p_cmsg = CMSG_FIRSTHDR(&msg);
1367 p_cmsg->cmsg_level = SOL_SOCKET;
1368 p_cmsg->cmsg_type = SCM_RIGHTS;
1369 p_cmsg->cmsg_len = CMSG_LEN(
sizeof(fd));
1370 p_fds = (
int *) CMSG_DATA(p_cmsg);
1372 msg.msg_controllen = p_cmsg->cmsg_len;
1373 msg.msg_name = NULL;
1374 msg.msg_namelen = 0;
1380 vec.iov_base = &sendchar;
1381 vec.iov_len =
sizeof(sendchar);
1382 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1384 perror(
"sending file descriptor");
1396static int recheck_ENOTCONN_as_owner(
const char *mnt)
1400 perror(
"fuse: recheck_ENOTCONN_as_owner can't fork");
1401 _exit(EXIT_FAILURE);
1402 }
else if(pid == 0) {
1403 uid_t uid = getuid();
1404 gid_t gid = getgid();
1405 if(setresgid(gid, gid, gid) == -1) {
1406 perror(
"fuse: can't set resgid");
1407 _exit(EXIT_FAILURE);
1409 if(setresuid(uid, uid, uid) == -1) {
1410 perror(
"fuse: can't set resuid");
1411 _exit(EXIT_FAILURE);
1414 int fd = open(mnt, O_RDONLY);
1415 if(fd == -1 && errno == ENOTCONN)
1416 _exit(EXIT_SUCCESS);
1418 _exit(EXIT_FAILURE);
1421 int res = waitpid(pid, &status, 0);
1423 perror(
"fuse: waiting for child failed");
1424 _exit(EXIT_FAILURE);
1426 return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS;
1446static int should_auto_unmount(
const char *mnt,
const char *type)
1455 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
1459 if (chdir_to_parent(copy, &last) == -1)
1461 if (check_is_mount(last, mnt, type) == -1)
1464 fd = open(mnt, O_RDONLY);
1474 result = recheck_ENOTCONN_as_owner(mnt);
1486static void usage(
void)
1488 printf(
"%s: [options] mountpoint\n"
1491 " -V print version\n"
1492 " -o opt[,opt...] mount options\n"
1495 " -z lazy unmount\n",
1500static void show_version(
void)
1502 printf(
"fusermount3 version: %s\n", PACKAGE_VERSION);
1506static void close_range_loop(
int min_fd,
int max_fd,
int cfd)
1508 for (
int fd = min_fd; fd <= max_fd; fd++)
1518static int close_inherited_fds(
int cfd)
1524 if (cfd <= STDERR_FILENO)
1527#ifdef HAVE_CLOSE_RANGE
1528 if (cfd < STDERR_FILENO + 2) {
1529 close_range_loop(STDERR_FILENO + 1, cfd - 1, cfd);
1531 rc = close_range(STDERR_FILENO + 1, cfd - 1, 0);
1537 rc = close_range(cfd + 1, ~0U, 0);
1544 int max_fd = sysconf(_SC_OPEN_MAX) - 1;
1546 close_range_loop(STDERR_FILENO + 1, max_fd, cfd);
1549 nullfd = open(
"/dev/null", O_RDWR);
1551 perror(
"fusermount: cannot open /dev/null");
1556 dup2(nullfd, STDIN_FILENO);
1557 dup2(nullfd, STDOUT_FILENO);
1558 dup2(nullfd, STDERR_FILENO);
1559 if (nullfd > STDERR_FILENO)
1565int main(
int argc,
char *argv[])
1573 static int unmount = 0;
1574 static int lazy = 0;
1575 static int quiet = 0;
1576 char *commfd = NULL;
1578 const char *opts =
"";
1579 const char *type = NULL;
1580 int setup_auto_unmount_only = 0;
1582 static const struct option long_opts[] = {
1583 {
"unmount", no_argument, NULL,
'u'},
1584 {
"lazy", no_argument, NULL,
'z'},
1585 {
"quiet", no_argument, NULL,
'q'},
1586 {
"help", no_argument, NULL,
'h'},
1587 {
"version", no_argument, NULL,
'V'},
1588 {
"options", required_argument, NULL,
'o'},
1591 {
"auto-unmount", no_argument, NULL,
'U'},
1592 {
"comm-fd", required_argument, NULL,
'c'},
1595 progname = strdup(argc > 0 ? argv[0] :
"fusermount");
1596 if (progname == NULL) {
1597 fprintf(stderr,
"%s: failed to allocate memory\n", argv[0]);
1601 while ((ch = getopt_long(argc, argv,
"hVo:uzq", long_opts,
1622 setup_auto_unmount_only = 1;
1640 if (lazy && !unmount) {
1641 fprintf(stderr,
"%s: -z can only be used with -u\n", progname);
1645 if (optind >= argc) {
1646 fprintf(stderr,
"%s: missing mountpoint argument\n", progname);
1648 }
else if (argc > optind + 1) {
1649 fprintf(stderr,
"%s: extra arguments after the mountpoint\n",
1654 origmnt = argv[optind];
1657 mnt = fuse_mnt_resolve_path(progname, origmnt);
1661 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
1670 if (!setup_auto_unmount_only && unmount)
1674 commfd = getenv(FUSE_COMMFD_ENV);
1675 if (commfd == NULL) {
1676 fprintf(stderr,
"%s: old style mounting not supported\n",
1681 res = libfuse_strtol(commfd, &cfd);
1684 "%s: invalid _FUSE_COMMFD: %s\n",
1691 struct stat statbuf;
1692 fstat(cfd, &statbuf);
1693 if(!S_ISSOCK(statbuf.st_mode)) {
1695 "%s: file descriptor %li is not a socket, can't send fuse fd\n",
1701 if (setup_auto_unmount_only)
1702 goto wait_for_auto_unmount;
1704 fd = mount_fuse(mnt, opts, &type);
1708 res = send_fd(cfd, fd);
1710 umount2(mnt, MNT_DETACH);
1715 if (!auto_unmount) {
1721wait_for_auto_unmount:
1727 res = close_inherited_fds(cfd);
1734 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
1738 sigfillset(&sigset);
1739 sigprocmask(SIG_BLOCK, &sigset, NULL);
1745 unsigned char buf[16];
1746 int n = recv(cfd, buf,
sizeof(buf), 0);
1757 if (!should_auto_unmount(mnt, type)) {
1763 res = unmount_fuse(mnt, quiet, lazy);
1765 res = umount2(mnt, lazy ? UMOUNT_DETACH : 0);
1766 if (res == -1 && !quiet)
1768 "%s: failed to unmount %s: %s\n",
1769 progname, mnt, strerror(errno));