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,
'#');
698 while (len > 0 && isspace((
unsigned char) line[len - 1]))
701 for (s = line; isspace((
unsigned char) *s); s++);
703 memmove(line, s, strlen(s)+1);
706static void parse_line(
char *line,
int linenum)
709 if (strcmp(line,
"user_allow_other") == 0)
710 user_allow_other = 1;
711 else if (sscanf(line,
"mount_max = %i", &tmp) == 1) {
714 "%s: invalid mount_max = %i in %s at line %i\n",
715 progname, tmp, FUSE_CONF, linenum);
721 "%s: unknown parameter in %s at line %i: '%s'\n",
722 progname, FUSE_CONF, linenum, line);
725static void read_conf(
void)
727 FILE *fp = fopen(FUSE_CONF,
"r");
732 while (fgets(line,
sizeof(line), fp) != NULL) {
734 if (line[strlen(line)-1] ==
'\n') {
736 parse_line(line, linenum);
740 }
else if(line[strlen(line)-1] ==
'\n') {
741 fprintf(stderr,
"%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
749 fprintf(stderr,
"%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
753 fprintf(stderr,
"%s: reading %s: read failed\n", progname, FUSE_CONF);
757 }
else if (errno != ENOENT) {
758 bool fatal = (errno != EACCES && errno != ELOOP &&
759 errno != ENAMETOOLONG && errno != ENOTDIR &&
761 fprintf(stderr,
"%s: failed to open %s: %s\n",
762 progname, FUSE_CONF, strerror(errno));
768static int begins_with(
const char *s,
const char *beg)
770 if (strncmp(s, beg, strlen(beg)) == 0)
783static struct mount_flags mount_flags[] = {
784 {
"rw", MS_RDONLY, 0, 1},
785 {
"ro", MS_RDONLY, 1, 1},
786 {
"suid", MS_NOSUID, 0, 0},
787 {
"nosuid", MS_NOSUID, 1, 1},
788 {
"dev", MS_NODEV, 0, 0},
789 {
"nodev", MS_NODEV, 1, 1},
790 {
"exec", MS_NOEXEC, 0, 1},
791 {
"noexec", MS_NOEXEC, 1, 1},
792 {
"async", MS_SYNCHRONOUS, 0, 1},
793 {
"sync", MS_SYNCHRONOUS, 1, 1},
794 {
"atime", MS_NOATIME, 0, 1},
795 {
"noatime", MS_NOATIME, 1, 1},
796 {
"diratime", MS_NODIRATIME, 0, 1},
797 {
"nodiratime", MS_NODIRATIME, 1, 1},
798 {
"lazytime", MS_LAZYTIME, 1, 1},
799 {
"nolazytime", MS_LAZYTIME, 0, 1},
800 {
"relatime", MS_RELATIME, 1, 1},
801 {
"norelatime", MS_RELATIME, 0, 1},
802 {
"strictatime", MS_STRICTATIME, 1, 1},
803 {
"nostrictatime", MS_STRICTATIME, 0, 1},
804 {
"dirsync", MS_DIRSYNC, 1, 1},
805 {
"symfollow", MS_NOSYMFOLLOW, 0, 1},
806 {
"nosymfollow", MS_NOSYMFOLLOW, 1, 1},
810static int find_mount_flag(
const char *s,
unsigned len,
int *on,
int *flag)
814 for (i = 0; mount_flags[i].opt != NULL; i++) {
815 const char *opt = mount_flags[i].opt;
816 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
817 *on = mount_flags[i].on;
818 *flag = mount_flags[i].flag;
819 if (!mount_flags[i].safe && getuid() != 0) {
822 "%s: unsafe option %s ignored\n",
831static int add_option(
char **optsp,
const char *opt,
unsigned expand)
835 newopts = strdup(opt);
837 unsigned oldsize = strlen(*optsp);
838 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
839 newopts = (
char *) realloc(*optsp, newsize);
841 sprintf(newopts + oldsize,
",%s", opt);
843 if (newopts == NULL) {
844 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
851static int get_mnt_opts(
int flags,
char *opts,
char **mnt_optsp)
856 if (!(flags & MS_RDONLY) && add_option(mnt_optsp,
"rw", 0) == -1)
859 for (i = 0; mount_flags[i].opt != NULL; i++) {
860 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
861 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
865 if (add_option(mnt_optsp, opts, 0) == -1)
868 l = strlen(*mnt_optsp);
869 if (l > 0 && (*mnt_optsp)[l-1] ==
',')
870 (*mnt_optsp)[l-1] =
'\0';
872 const char *user = get_user_name();
876 if (add_option(mnt_optsp,
"user=", strlen(user)) == -1)
878 strcat(*mnt_optsp, user);
883static int opt_eq(
const char *s,
unsigned len,
const char *opt)
885 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
891static int get_string_opt(
const char *s,
unsigned len,
const char *opt,
895 unsigned opt_len = strlen(opt);
900 *val = (
char *) malloc(len - opt_len + 1);
902 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
909 for (i = 0; i < len; i++) {
910 if (s[i] ==
'\\' && i + 1 < len)
923static int mount_notrunc(
const char *source,
const char *target,
924 const char *filesystemtype,
unsigned long mountflags,
926 if (strlen(data) > sysconf(_SC_PAGESIZE) - 1) {
927 fprintf(stderr,
"%s: mount options too long\n", progname);
931 return mount(source, target, filesystemtype, mountflags, data);
935static int do_mount(
const char *mnt,
const char **typep, mode_t rootmode,
936 int fd,
const char *opts,
const char *dev,
char **sourcep,
940 int flags = MS_NOSUID | MS_NODEV;
942 char *mnt_opts = NULL;
946 char *subtype = NULL;
951 optbuf = (
char *) malloc(strlen(opts) + 128);
953 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
957 for (s = opts, d = optbuf; *s;) {
959 const char *fsname_str =
"fsname=";
960 const char *subtype_str =
"subtype=";
961 bool escape_ok = begins_with(s, fsname_str) ||
962 begins_with(s, subtype_str);
963 for (len = 0; s[len]; len++) {
964 if (escape_ok && s[len] ==
'\\' && s[len + 1])
966 else if (s[len] ==
',')
969 if (begins_with(s, fsname_str)) {
970 if (!get_string_opt(s, len, fsname_str, &fsname))
972 }
else if (begins_with(s, subtype_str)) {
973 if (!get_string_opt(s, len, subtype_str, &subtype))
975 }
else if (opt_eq(s, len,
"blkdev")) {
978 "%s: option blkdev is privileged\n",
983 }
else if (opt_eq(s, len,
"auto_unmount")) {
985 }
else if (!opt_eq(s, len,
"nonempty") &&
986 !begins_with(s,
"fd=") &&
987 !begins_with(s,
"rootmode=") &&
988 !begins_with(s,
"user_id=") &&
989 !begins_with(s,
"group_id=")) {
993 if (opt_eq(s, len,
"large_read")) {
994 struct utsname utsname;
996 res = uname(&utsname);
998 sscanf(utsname.release,
"%u.%u",
999 &kmaj, &kmin) == 2 &&
1000 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
1001 fprintf(stderr,
"%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
1005 if (getuid() != 0 && !user_allow_other &&
1006 (opt_eq(s, len,
"allow_other") ||
1007 opt_eq(s, len,
"allow_root"))) {
1008 fprintf(stderr,
"%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
1012 if (find_mount_flag(s, len, &on, &flag)) {
1017 }
else if (opt_eq(s, len,
"default_permissions") ||
1018 opt_eq(s, len,
"allow_other") ||
1019 begins_with(s,
"max_read=") ||
1020 begins_with(s,
"blksize=")) {
1025 fprintf(stderr,
"%s: unknown option '%.*s'\n", progname, len, s);
1035 res = get_mnt_opts(flags, optbuf, &mnt_opts);
1039 sprintf(d,
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
1040 fd, rootmode, getuid(), getgid());
1042 source = malloc((fsname ? strlen(fsname) : 0) +
1043 (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
1045 type = malloc((subtype ? strlen(subtype) : 0) + 32);
1046 if (!type || !source) {
1047 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
1052 sprintf(type,
"%s.%s", blkdev ?
"fuseblk" :
"fuse", subtype);
1054 strcpy(type, blkdev ?
"fuseblk" :
"fuse");
1057 strcpy(source, fsname);
1059 strcpy(source, subtype ? subtype : dev);
1061 res = mount_notrunc(source, mnt, type, flags, optbuf);
1062 if (res == -1 && errno == ENODEV && subtype) {
1064 strcpy(type, blkdev ?
"fuseblk" :
"fuse");
1067 sprintf(source,
"%s#%s", subtype, fsname);
1069 strcpy(source, type);
1072 res = mount_notrunc(source, mnt, type, flags, optbuf);
1074 if (res == -1 && errno == EINVAL) {
1076 sprintf(d,
"fd=%i,rootmode=%o,user_id=%u",
1077 fd, rootmode, getuid());
1078 res = mount_notrunc(source, mnt, type, flags, optbuf);
1081 int errno_save = errno;
1082 if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
1083 fprintf(stderr,
"%s: 'fuseblk' support missing\n",
1086 fprintf(stderr,
"%s: mount failed: %s\n", progname,
1087 strerror(errno_save));
1092 *mnt_optsp = mnt_opts;
1113static int pin_mountpoint(
const char *mnt,
bool is_root,
struct stat *stbuf)
1115 int open_flags = O_PATH | O_CLOEXEC;
1119 open_flags |= O_NOFOLLOW;
1121 fd = open(mnt, open_flags);
1123 fprintf(stderr,
"%s: failed to access mountpoint %s: %s\n",
1124 progname, mnt, strerror(errno));
1128 if (fstat(fd, stbuf) == -1) {
1129 fprintf(stderr,
"%s: failed to access mountpoint %s: %s\n",
1130 progname, mnt, strerror(errno));
1138static int check_perm(
const char **mntp,
struct stat *stbuf,
int *mountpoint_fd)
1142 const char *mnt = *mntp;
1143 const bool is_root = getuid() == 0;
1144 struct statfs fs_buf;
1147 fd = pin_mountpoint(mnt, is_root, stbuf);
1153 *mountpoint_fd = fd;
1157 if (S_ISDIR(stbuf->st_mode)) {
1161 "%s: failed to chdir to mountpoint: %s\n",
1162 progname, strerror(errno));
1171 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
1172 fprintf(stderr,
"%s: mountpoint %s not owned by user\n",
1178 res = access(*mntp, W_OK);
1180 fprintf(stderr,
"%s: user has no write access to mountpoint %s\n",
1184 }
else if (S_ISREG(stbuf->st_mode)) {
1185 static char procfile[256];
1188 snprintf(procfile,
sizeof(procfile),
"/proc/self/fd/%i", fd);
1195 wfd = open(procfile, O_WRONLY);
1197 fprintf(stderr,
"%s: failed to open %s: %s\n",
1198 progname, mnt, strerror(errno));
1205 snprintf(procfile,
sizeof(procfile),
"/proc/self/fd/%i", fd);
1209 "%s: mountpoint %s is not a directory or a regular file\n",
1221 if (statfs(*mntp, &fs_buf)) {
1222 fprintf(stderr,
"%s: failed to access mountpoint %s: %s\n",
1223 progname, mnt, strerror(errno));
1233 typeof(fs_buf.f_type) f_type_whitelist[] = {
1266#if __SIZEOF_LONG__ > 4
1267 0x736675005346544e ,
1273 for (i = 0; i <
sizeof(f_type_whitelist)/
sizeof(f_type_whitelist[0]); i++) {
1274 if (f_type_whitelist[i] == fs_buf.f_type) {
1275 *mountpoint_fd = fd;
1280 fprintf(stderr,
"%s: mounting over filesystem type %#010lx is forbidden\n",
1281 progname, (
unsigned long)fs_buf.f_type);
1289static int open_fuse_device(
const char *dev)
1294 fd = open(dev, O_RDWR);
1296 if (errno == ENODEV || errno == ENOENT)
1298 "%s: fuse device %s not found. Kernel module not loaded?\n",
1302 "%s: failed to open %s: %s\n", progname, dev, strerror(errno));
1308static int mount_fuse(
const char *mnt,
const char *opts,
const char **type)
1312 const char *dev = getenv(FUSE_KERN_DEVICE_ENV) ?: FUSE_DEV;
1314 char *source = NULL;
1315 char *mnt_opts = NULL;
1316 const char *real_mnt = mnt;
1317 int mountpoint_fd = -1;
1318 char *do_mount_opts = NULL;
1319 char *x_opts = NULL;
1321 fd = open_fuse_device(dev);
1328 if (getuid() != 0 && mount_max != -1) {
1329 int mount_count = count_fuse_fs();
1330 if (mount_count >= mount_max) {
1331 fprintf(stderr,
"%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
1337 res= extract_x_options(opts, &do_mount_opts, &x_opts);
1341 res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1344 res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT,
1345 fd, do_mount_opts, dev, &source, &mnt_opts);
1347 if (mountpoint_fd != -1)
1348 close(mountpoint_fd);
1355 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
1359 if (geteuid() == 0) {
1360 if (x_opts && strlen(x_opts) > 0) {
1365 size_t mnt_opts_len = strlen(mnt_opts);
1366 size_t x_mnt_opts_len = mnt_opts_len+
1368 char *x_mnt_opts = calloc(1, x_mnt_opts_len);
1371 strcpy(x_mnt_opts, mnt_opts);
1372 strncat(x_mnt_opts,
",", 2);
1375 strncat(x_mnt_opts, x_opts,
1376 x_mnt_opts_len - mnt_opts_len - 2);
1379 mnt_opts = x_mnt_opts;
1382 res = add_mount(source, mnt, *type, mnt_opts);
1393 free(do_mount_opts);
1403static int send_fd(
int sock_fd,
int fd)
1407 struct cmsghdr *p_cmsg;
1409 size_t cmsgbuf[CMSG_SPACE(
sizeof(fd)) /
sizeof(size_t)];
1413 msg.msg_control = cmsgbuf;
1414 msg.msg_controllen =
sizeof(cmsgbuf);
1415 p_cmsg = CMSG_FIRSTHDR(&msg);
1416 p_cmsg->cmsg_level = SOL_SOCKET;
1417 p_cmsg->cmsg_type = SCM_RIGHTS;
1418 p_cmsg->cmsg_len = CMSG_LEN(
sizeof(fd));
1419 p_fds = (
int *) CMSG_DATA(p_cmsg);
1421 msg.msg_controllen = p_cmsg->cmsg_len;
1422 msg.msg_name = NULL;
1423 msg.msg_namelen = 0;
1429 vec.iov_base = &sendchar;
1430 vec.iov_len =
sizeof(sendchar);
1431 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1433 perror(
"sending file descriptor");
1443static int check_ENOTCONN_as_owner(
const char *mnt)
1447 perror(
"fuse: recheck_ENOTCONN_as_owner can't fork");
1448 _exit(EXIT_FAILURE);
1449 }
else if(pid == 0) {
1450 uid_t uid = getuid();
1451 gid_t gid = getgid();
1452 if(setresgid(gid, gid, gid) == -1) {
1453 perror(
"fuse: can't set resgid");
1454 _exit(EXIT_FAILURE);
1456 if(setresuid(uid, uid, uid) == -1) {
1457 perror(
"fuse: can't set resuid");
1458 _exit(EXIT_FAILURE);
1461 int fd = open(mnt, O_RDONLY);
1462 if (fd == -1 && (errno == ENOTCONN || errno == ECONNABORTED))
1463 _exit(EXIT_SUCCESS);
1465 _exit(EXIT_FAILURE);
1468 int res = waitpid(pid, &status, 0);
1470 perror(
"fuse: waiting for child failed");
1471 _exit(EXIT_FAILURE);
1473 return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS;
1493static int should_auto_unmount(
const char *mnt,
const char *type)
1501 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
1505 if (chdir_to_parent(copy, &last) == -1)
1507 if (check_is_mount(last, mnt, type) == -1)
1510 result = check_ENOTCONN_as_owner(mnt);
1516static void usage(
void)
1518 printf(
"%s: [options] mountpoint\n"
1521 " -V print version\n"
1522 " -o opt[,opt...] mount options\n"
1525 " -z lazy unmount\n",
1530static void show_version(
void)
1532 printf(
"fusermount3 version: %s\n", PACKAGE_VERSION);
1536static void close_range_loop(
int min_fd,
int max_fd,
int cfd)
1538 for (
int fd = min_fd; fd <= max_fd; fd++)
1548static int close_inherited_fds(
int cfd)
1554 if (cfd <= STDERR_FILENO)
1557#ifdef HAVE_CLOSE_RANGE
1558 if (cfd < STDERR_FILENO + 2) {
1559 close_range_loop(STDERR_FILENO + 1, cfd - 1, cfd);
1561 rc = close_range(STDERR_FILENO + 1, cfd - 1, 0);
1567 rc = close_range(cfd + 1, ~0U, 0);
1574 int max_fd = sysconf(_SC_OPEN_MAX) - 1;
1576 close_range_loop(STDERR_FILENO + 1, max_fd, cfd);
1579 nullfd = open(
"/dev/null", O_RDWR);
1581 perror(
"fusermount: cannot open /dev/null");
1586 dup2(nullfd, STDIN_FILENO);
1587 dup2(nullfd, STDOUT_FILENO);
1588 dup2(nullfd, STDERR_FILENO);
1589 if (nullfd > STDERR_FILENO)
1595int main(
int argc,
char *argv[])
1603 static int unmount = 0;
1604 static int lazy = 0;
1605 static int quiet = 0;
1606 char *commfd = NULL;
1608 const char *opts =
"";
1609 const char *type = NULL;
1610 int setup_auto_unmount_only = 0;
1612 static const struct option long_opts[] = {
1613 {
"unmount", no_argument, NULL,
'u'},
1614 {
"lazy", no_argument, NULL,
'z'},
1615 {
"quiet", no_argument, NULL,
'q'},
1616 {
"help", no_argument, NULL,
'h'},
1617 {
"version", no_argument, NULL,
'V'},
1618 {
"options", required_argument, NULL,
'o'},
1621 {
"auto-unmount", no_argument, NULL,
'U'},
1622 {
"comm-fd", required_argument, NULL,
'c'},
1625 progname = strdup(argc > 0 ? argv[0] :
"fusermount");
1626 if (progname == NULL) {
1627 fprintf(stderr,
"%s: failed to allocate memory\n", argv[0]);
1631 while ((ch = getopt_long(argc, argv,
"hVo:uzq", long_opts,
1652 setup_auto_unmount_only = 1;
1670 if (lazy && !unmount) {
1671 fprintf(stderr,
"%s: -z can only be used with -u\n", progname);
1675 if (optind >= argc) {
1676 fprintf(stderr,
"%s: missing mountpoint argument\n", progname);
1678 }
else if (argc > optind + 1) {
1679 fprintf(stderr,
"%s: extra arguments after the mountpoint\n",
1684 origmnt = argv[optind];
1687 mnt = fuse_mnt_resolve_path(progname, origmnt);
1691 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
1700 if (!setup_auto_unmount_only && unmount)
1704 commfd = getenv(FUSE_COMMFD_ENV);
1705 if (commfd == NULL) {
1706 fprintf(stderr,
"%s: old style mounting not supported\n",
1711 res = libfuse_strtol(commfd, &cfd);
1714 "%s: invalid _FUSE_COMMFD: %s\n",
1721 struct stat statbuf;
1722 if (fstat(cfd, &statbuf) == -1) {
1724 "%s: fstat of comm fd %li failed: %s\n",
1725 progname, cfd, strerror(errno));
1728 if(!S_ISSOCK(statbuf.st_mode)) {
1730 "%s: file descriptor %li is not a socket, can't send fuse fd\n",
1736 if (setup_auto_unmount_only)
1737 goto wait_for_auto_unmount;
1739 fd = mount_fuse(mnt, opts, &type);
1743 res = send_fd(cfd, fd);
1745 unmount_fuse(mnt, 1, 1);
1750 if (!auto_unmount) {
1756wait_for_auto_unmount:
1762 res = close_inherited_fds(cfd);
1769 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
1773 sigfillset(&sigset);
1774 sigprocmask(SIG_BLOCK, &sigset, NULL);
1780 unsigned char buf[16];
1781 int n = recv(cfd, buf,
sizeof(buf), 0);
1792 if (!should_auto_unmount(mnt, type)) {
1798 res = unmount_fuse(mnt, quiet, lazy);
1800 res = umount2(mnt, (lazy ? UMOUNT_DETACH : 0) | UMOUNT_NOFOLLOW);
1801 if (res == -1 && !quiet)
1803 "%s: failed to unmount %s: %s\n",
1804 progname, mnt, strerror(errno));