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#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
41#define FUSE_DEV "/dev/fuse"
43static const char *progname;
45static int user_allow_other = 0;
46static int mount_max = 1000;
48static int auto_unmount = 0;
50#ifdef GETMNTENT_NEEDS_UNESCAPING
55static void unescape(
char *buf) {
59 char *next_src = strchrnul(src,
'\\');
60 int offset = next_src - src;
61 memmove(dest, src, offset);
71 if(
'0' <= src[0] && src[0] <
'2' &&
72 '0' <= src[1] && src[1] <
'8' &&
73 '0' <= src[2] && src[2] <
'8') {
74 *dest++ = (src[0] -
'0') << 6
76 | (src[2] -
'0') << 0;
78 }
else if (src[0] ==
'\\') {
87static struct mntent *GETMNTENT(FILE *stream)
89 struct mntent *entp = getmntent(stream);
91 unescape(entp->mnt_fsname);
92 unescape(entp->mnt_dir);
93 unescape(entp->mnt_type);
94 unescape(entp->mnt_opts);
99#define GETMNTENT getmntent
105static int extract_x_options(
const char *original,
char **non_x_opts,
109 const char *opt, *opt_end;
111 orig_len = strlen(original) + 1;
113 *non_x_opts = calloc(1, orig_len);
114 *x_opts = calloc(1, orig_len);
116 size_t non_x_opts_len = orig_len;
117 size_t x_opts_len = orig_len;
119 if (*non_x_opts == NULL || *x_opts == NULL) {
120 fprintf(stderr,
"%s: Failed to allocate %zuB.\n",
125 for (opt = original; opt < original + orig_len; opt = opt_end + 1) {
128 opt_end = strchr(opt,
',');
130 opt_end = original + orig_len;
132 size_t opt_len = opt_end - opt;
133 size_t opt_len_left = orig_len - (opt - original);
137 if (strncmp(opt,
"x-", MIN(2, opt_len_left)) == 0) {
138 buf_len = x_opts_len;
142 buf_len = non_x_opts_len;
144 opt_buf = *non_x_opts;
147 if (buf_len < orig_len) {
148 strncat(opt_buf,
",", 2);
153 if ((ssize_t)(buf_len - opt_len) < 0) {
155 fprintf(stderr,
"%s: no buf space left in copy, orig='%s'\n",
160 strncat(opt_buf, opt, opt_end - opt);
164 x_opts_len = buf_len;
166 non_x_opts_len = buf_len;
172static const char *get_user_name(
void)
174 struct passwd *pw = getpwuid(getuid());
175 if (pw != NULL && pw->pw_name != NULL)
178 fprintf(stderr,
"%s: could not determine username\n", progname);
183static uid_t oldfsuid;
184static gid_t oldfsgid;
186static void drop_privs(
void)
189 oldfsuid = setfsuid(getuid());
190 oldfsgid = setfsgid(getgid());
194static void restore_privs(
void)
206static int lock_umount(
void)
208 const char *mtab_lock = _PATH_MOUNTED
".fuselock";
211 struct stat mtab_stat;
214 if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
217 mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
218 if (mtablock == -1) {
219 fprintf(stderr,
"%s: unable to open fuse lock file: %s\n",
220 progname, strerror(errno));
223 res = lockf(mtablock, F_LOCK, 0);
225 fprintf(stderr,
"%s: error getting lock: %s\n", progname,
234static void unlock_umount(
int mtablock)
239 res = lockf(mtablock, F_ULOCK, 0);
241 fprintf(stderr,
"%s: error releasing lock: %s\n",
242 progname, strerror(errno));
248static int add_mount(
const char *source,
const char *mnt,
const char *type,
251 return fuse_mnt_add_mount(progname, source, mnt, type, opts);
254static int may_unmount(
const char *mnt,
int quiet)
258 const char *user = NULL;
262 const char *mtab = _PATH_MOUNTED;
264 user = get_user_name();
268 fp = setmntent(mtab,
"r");
270 fprintf(stderr,
"%s: failed to open %s: %s\n", progname, mtab,
275 uidlen = sprintf(uidstr,
"%u", getuid());
278 while ((entp = GETMNTENT(fp)) != NULL) {
279 if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
280 (strcmp(entp->mnt_type,
"fuse") == 0 ||
281 strcmp(entp->mnt_type,
"fuseblk") == 0 ||
282 strncmp(entp->mnt_type,
"fuse.", 5) == 0 ||
283 strncmp(entp->mnt_type,
"fuseblk.", 8) == 0)) {
284 char *p = strstr(entp->mnt_opts,
"user=");
286 (p == entp->mnt_opts || *(p-1) ==
',') &&
287 strcmp(p + 5, user) == 0) {
294 strstr(entp->mnt_opts,
"user_id=")) &&
295 (p == entp->mnt_opts ||
297 strncmp(p + 8, uidstr, uidlen) == 0 &&
298 (*(p+8+uidlen) ==
',' ||
299 *(p+8+uidlen) ==
'\0')) {
310 "%s: entry for %s not found in %s\n",
311 progname, mnt, mtab);
342static int check_is_mount_child(
void *p)
345 const char *last = a[0];
346 const char *mnt = a[1];
347 const char *type = a[2];
349 const char *procmounts =
"/proc/mounts";
355 res = mount(
"",
"/",
"", MS_PRIVATE | MS_REC, NULL);
357 fprintf(stderr,
"%s: failed to mark mounts private: %s\n",
358 progname, strerror(errno));
362 fp = setmntent(procmounts,
"r");
364 fprintf(stderr,
"%s: failed to open %s: %s\n", progname,
365 procmounts, strerror(errno));
370 while (GETMNTENT(fp) != NULL)
374 fp = setmntent(procmounts,
"r");
376 fprintf(stderr,
"%s: failed to open %s: %s\n", progname,
377 procmounts, strerror(errno));
381 res = mount(
".",
"/",
"", MS_BIND | MS_REC, NULL);
383 fprintf(stderr,
"%s: failed to bind parent to /: %s\n",
384 progname, strerror(errno));
389 while ((entp = GETMNTENT(fp)) != NULL) {
394 if (entp->mnt_dir[0] ==
'/' &&
395 strcmp(entp->mnt_dir + 1, last) == 0 &&
396 (!type || strcmp(entp->mnt_type, type) == 0)) {
404 fprintf(stderr,
"%s: %s not mounted\n", progname, mnt);
411static pid_t clone_newns(
void *a)
414 char *stack = buf + (
sizeof(buf) / 2 - ((
size_t) buf & 15));
417 extern int __clone2(
int (*fn)(
void *),
418 void *child_stack_base,
size_t stack_size,
419 int flags,
void *arg, pid_t *ptid,
420 void *tls, pid_t *ctid);
422 return __clone2(check_is_mount_child, stack,
sizeof(buf) / 2,
423 CLONE_NEWNS, a, NULL, NULL, NULL);
425 return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
429static int check_is_mount(
const char *last,
const char *mnt,
const char *type)
433 const char *a[3] = { last, mnt, type };
435 pid = clone_newns((
void *) a);
436 if (pid == (pid_t) -1) {
437 fprintf(stderr,
"%s: failed to clone namespace: %s\n",
438 progname, strerror(errno));
441 p = waitpid(pid, &status, __WCLONE);
442 if (p == (pid_t) -1) {
443 fprintf(stderr,
"%s: waitpid failed: %s\n",
444 progname, strerror(errno));
447 if (!WIFEXITED(status)) {
448 fprintf(stderr,
"%s: child terminated abnormally (status %i)\n",
452 if (WEXITSTATUS(status) != 0)
458static int chdir_to_parent(
char *copy,
const char **lastp)
465 tmp = strrchr(copy,
'/');
466 if (tmp == NULL || tmp[1] ==
'\0') {
467 fprintf(stderr,
"%s: internal error: invalid abs path: <%s>\n",
475 }
else if (tmp[1] !=
'\0') {
485 fprintf(stderr,
"%s: failed to chdir to %s: %s\n",
486 progname, parent, strerror(errno));
490 if (getcwd(buf,
sizeof(buf)) == NULL) {
491 fprintf(stderr,
"%s: failed to obtain current directory: %s\n",
492 progname, strerror(errno));
495 if (strcmp(buf, parent) != 0) {
496 fprintf(stderr,
"%s: mountpoint moved (%s -> %s)\n", progname,
506static int unmount_fuse_locked(
const char *mnt,
int quiet,
int lazy)
511 int umount_flags = (lazy ? UMOUNT_DETACH : 0) | UMOUNT_NOFOLLOW;
514 res = may_unmount(mnt, quiet);
521 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
526 res = chdir_to_parent(copy, &last);
532 res = umount2(last, umount_flags);
534 if (res == -1 && !quiet) {
535 fprintf(stderr,
"%s: failed to unmount %s: %s\n",
536 progname, mnt, strerror(errno));
546 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
550 return fuse_mnt_remove_mount(progname, mnt);
553static int unmount_fuse(
const char *mnt,
int quiet,
int lazy)
556 int mtablock = lock_umount();
558 res = unmount_fuse_locked(mnt, quiet, lazy);
559 unlock_umount(mtablock);
564static int count_fuse_fs(
void)
568 const char *mtab = _PATH_MOUNTED;
569 FILE *fp = setmntent(mtab,
"r");
571 fprintf(stderr,
"%s: failed to open %s: %s\n", progname, mtab,
575 while ((entp = GETMNTENT(fp)) != NULL) {
576 if (strcmp(entp->mnt_type,
"fuse") == 0 ||
577 strncmp(entp->mnt_type,
"fuse.", 5) == 0)
586static int count_fuse_fs(
void)
591static int add_mount(
const char *source,
const char *mnt,
const char *type,
601static int unmount_fuse(
const char *mnt,
int quiet,
int lazy)
604 return fuse_mnt_umount(progname, mnt, mnt, lazy);
608static void strip_line(
char *line)
610 char *s = strchr(line,
'#');
613 for (s = line + strlen(line) - 1;
614 s >= line && isspace((
unsigned char) *s); s--);
616 for (s = line; isspace((
unsigned char) *s); s++);
618 memmove(line, s, strlen(s)+1);
621static void parse_line(
char *line,
int linenum)
624 if (strcmp(line,
"user_allow_other") == 0)
625 user_allow_other = 1;
626 else if (sscanf(line,
"mount_max = %i", &tmp) == 1)
630 "%s: unknown parameter in %s at line %i: '%s'\n",
631 progname, FUSE_CONF, linenum, line);
634static void read_conf(
void)
636 FILE *fp = fopen(FUSE_CONF,
"r");
641 while (fgets(line,
sizeof(line), fp) != NULL) {
643 if (line[strlen(line)-1] ==
'\n') {
645 parse_line(line, linenum);
649 }
else if(line[strlen(line)-1] ==
'\n') {
650 fprintf(stderr,
"%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
658 fprintf(stderr,
"%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
662 fprintf(stderr,
"%s: reading %s: read failed\n", progname, FUSE_CONF);
666 }
else if (errno != ENOENT) {
667 bool fatal = (errno != EACCES && errno != ELOOP &&
668 errno != ENAMETOOLONG && errno != ENOTDIR &&
670 fprintf(stderr,
"%s: failed to open %s: %s\n",
671 progname, FUSE_CONF, strerror(errno));
677static int begins_with(
const char *s,
const char *beg)
679 if (strncmp(s, beg, strlen(beg)) == 0)
692static struct mount_flags mount_flags[] = {
693 {
"rw", MS_RDONLY, 0, 1},
694 {
"ro", MS_RDONLY, 1, 1},
695 {
"suid", MS_NOSUID, 0, 0},
696 {
"nosuid", MS_NOSUID, 1, 1},
697 {
"dev", MS_NODEV, 0, 0},
698 {
"nodev", MS_NODEV, 1, 1},
699 {
"exec", MS_NOEXEC, 0, 1},
700 {
"noexec", MS_NOEXEC, 1, 1},
701 {
"async", MS_SYNCHRONOUS, 0, 1},
702 {
"sync", MS_SYNCHRONOUS, 1, 1},
703 {
"atime", MS_NOATIME, 0, 1},
704 {
"noatime", MS_NOATIME, 1, 1},
705 {
"diratime", MS_NODIRATIME, 0, 1},
706 {
"nodiratime", MS_NODIRATIME, 1, 1},
707 {
"lazytime", MS_LAZYTIME, 1, 1},
708 {
"nolazytime", MS_LAZYTIME, 0, 1},
709 {
"relatime", MS_RELATIME, 1, 1},
710 {
"norelatime", MS_RELATIME, 0, 1},
711 {
"strictatime", MS_STRICTATIME, 1, 1},
712 {
"nostrictatime", MS_STRICTATIME, 0, 1},
713 {
"dirsync", MS_DIRSYNC, 1, 1},
714 {
"symfollow", MS_NOSYMFOLLOW, 0, 1},
715 {
"nosymfollow", MS_NOSYMFOLLOW, 1, 1},
719static int find_mount_flag(
const char *s,
unsigned len,
int *on,
int *flag)
723 for (i = 0; mount_flags[i].opt != NULL; i++) {
724 const char *opt = mount_flags[i].opt;
725 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
726 *on = mount_flags[i].on;
727 *flag = mount_flags[i].flag;
728 if (!mount_flags[i].safe && getuid() != 0) {
731 "%s: unsafe option %s ignored\n",
740static int add_option(
char **optsp,
const char *opt,
unsigned expand)
744 newopts = strdup(opt);
746 unsigned oldsize = strlen(*optsp);
747 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
748 newopts = (
char *) realloc(*optsp, newsize);
750 sprintf(newopts + oldsize,
",%s", opt);
752 if (newopts == NULL) {
753 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
760static int get_mnt_opts(
int flags,
char *opts,
char **mnt_optsp)
765 if (!(flags & MS_RDONLY) && add_option(mnt_optsp,
"rw", 0) == -1)
768 for (i = 0; mount_flags[i].opt != NULL; i++) {
769 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
770 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
774 if (add_option(mnt_optsp, opts, 0) == -1)
777 l = strlen(*mnt_optsp);
778 if ((*mnt_optsp)[l-1] ==
',')
779 (*mnt_optsp)[l-1] =
'\0';
781 const char *user = get_user_name();
785 if (add_option(mnt_optsp,
"user=", strlen(user)) == -1)
787 strcat(*mnt_optsp, user);
792static int opt_eq(
const char *s,
unsigned len,
const char *opt)
794 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
800static int get_string_opt(
const char *s,
unsigned len,
const char *opt,
804 unsigned opt_len = strlen(opt);
809 *val = (
char *) malloc(len - opt_len + 1);
811 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
818 for (i = 0; i < len; i++) {
819 if (s[i] ==
'\\' && i + 1 < len)
832static int mount_notrunc(
const char *source,
const char *target,
833 const char *filesystemtype,
unsigned long mountflags,
835 if (strlen(data) > sysconf(_SC_PAGESIZE) - 1) {
836 fprintf(stderr,
"%s: mount options too long\n", progname);
840 return mount(source, target, filesystemtype, mountflags, data);
844static int do_mount(
const char *mnt,
const char **typep, mode_t rootmode,
845 int fd,
const char *opts,
const char *dev,
char **sourcep,
849 int flags = MS_NOSUID | MS_NODEV;
851 char *mnt_opts = NULL;
855 char *subtype = NULL;
860 optbuf = (
char *) malloc(strlen(opts) + 128);
862 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
866 for (s = opts, d = optbuf; *s;) {
868 const char *fsname_str =
"fsname=";
869 const char *subtype_str =
"subtype=";
870 bool escape_ok = begins_with(s, fsname_str) ||
871 begins_with(s, subtype_str);
872 for (len = 0; s[len]; len++) {
873 if (escape_ok && s[len] ==
'\\' && s[len + 1])
875 else if (s[len] ==
',')
878 if (begins_with(s, fsname_str)) {
879 if (!get_string_opt(s, len, fsname_str, &fsname))
881 }
else if (begins_with(s, subtype_str)) {
882 if (!get_string_opt(s, len, subtype_str, &subtype))
884 }
else if (opt_eq(s, len,
"blkdev")) {
887 "%s: option blkdev is privileged\n",
892 }
else if (opt_eq(s, len,
"auto_unmount")) {
894 }
else if (!opt_eq(s, len,
"nonempty") &&
895 !begins_with(s,
"fd=") &&
896 !begins_with(s,
"rootmode=") &&
897 !begins_with(s,
"user_id=") &&
898 !begins_with(s,
"group_id=")) {
902 if (opt_eq(s, len,
"large_read")) {
903 struct utsname utsname;
905 res = uname(&utsname);
907 sscanf(utsname.release,
"%u.%u",
908 &kmaj, &kmin) == 2 &&
909 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
910 fprintf(stderr,
"%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
914 if (getuid() != 0 && !user_allow_other &&
915 (opt_eq(s, len,
"allow_other") ||
916 opt_eq(s, len,
"allow_root"))) {
917 fprintf(stderr,
"%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
921 if (find_mount_flag(s, len, &on, &flag)) {
926 }
else if (opt_eq(s, len,
"default_permissions") ||
927 opt_eq(s, len,
"allow_other") ||
928 begins_with(s,
"max_read=") ||
929 begins_with(s,
"blksize=")) {
934 fprintf(stderr,
"%s: unknown option '%.*s'\n", progname, len, s);
944 res = get_mnt_opts(flags, optbuf, &mnt_opts);
948 sprintf(d,
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
949 fd, rootmode, getuid(), getgid());
951 source = malloc((fsname ? strlen(fsname) : 0) +
952 (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
954 type = malloc((subtype ? strlen(subtype) : 0) + 32);
955 if (!type || !source) {
956 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
961 sprintf(type,
"%s.%s", blkdev ?
"fuseblk" :
"fuse", subtype);
963 strcpy(type, blkdev ?
"fuseblk" :
"fuse");
966 strcpy(source, fsname);
968 strcpy(source, subtype ? subtype : dev);
970 res = mount_notrunc(source, mnt, type, flags, optbuf);
971 if (res == -1 && errno == ENODEV && subtype) {
973 strcpy(type, blkdev ?
"fuseblk" :
"fuse");
976 sprintf(source,
"%s#%s", subtype, fsname);
978 strcpy(source, type);
981 res = mount_notrunc(source, mnt, type, flags, optbuf);
983 if (res == -1 && errno == EINVAL) {
985 sprintf(d,
"fd=%i,rootmode=%o,user_id=%u",
986 fd, rootmode, getuid());
987 res = mount_notrunc(source, mnt, type, flags, optbuf);
990 int errno_save = errno;
991 if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
992 fprintf(stderr,
"%s: 'fuseblk' support missing\n",
995 fprintf(stderr,
"%s: mount failed: %s\n", progname,
996 strerror(errno_save));
1001 *mnt_optsp = mnt_opts;
1017static int check_perm(
const char **mntp,
struct stat *stbuf,
int *mountpoint_fd)
1020 const char *mnt = *mntp;
1021 const char *origmnt = mnt;
1022 struct statfs fs_buf;
1025 res = lstat(mnt, stbuf);
1027 fprintf(stderr,
"%s: failed to access mountpoint %s: %s\n",
1028 progname, mnt, strerror(errno));
1036 if (S_ISDIR(stbuf->st_mode)) {
1040 "%s: failed to chdir to mountpoint: %s\n",
1041 progname, strerror(errno));
1045 res = lstat(mnt, stbuf);
1048 "%s: failed to access mountpoint %s: %s\n",
1049 progname, origmnt, strerror(errno));
1053 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
1054 fprintf(stderr,
"%s: mountpoint %s not owned by user\n",
1059 res = access(mnt, W_OK);
1061 fprintf(stderr,
"%s: user has no write access to mountpoint %s\n",
1065 }
else if (S_ISREG(stbuf->st_mode)) {
1066 static char procfile[256];
1067 *mountpoint_fd = open(mnt, O_WRONLY);
1068 if (*mountpoint_fd == -1) {
1069 fprintf(stderr,
"%s: failed to open %s: %s\n",
1070 progname, mnt, strerror(errno));
1073 res = fstat(*mountpoint_fd, stbuf);
1076 "%s: failed to access mountpoint %s: %s\n",
1077 progname, mnt, strerror(errno));
1080 if (!S_ISREG(stbuf->st_mode)) {
1082 "%s: mountpoint %s is no longer a regular file\n",
1087 sprintf(procfile,
"/proc/self/fd/%i", *mountpoint_fd);
1091 "%s: mountpoint %s is not a directory or a regular file\n",
1102 if (statfs(*mntp, &fs_buf)) {
1103 fprintf(stderr,
"%s: failed to access mountpoint %s: %s\n",
1104 progname, mnt, strerror(errno));
1113 typeof(fs_buf.f_type) f_type_whitelist[] = {
1144 0x736675005346544e ,
1149 for (i = 0; i <
sizeof(f_type_whitelist)/
sizeof(f_type_whitelist[0]); i++) {
1150 if (f_type_whitelist[i] == fs_buf.f_type)
1154 fprintf(stderr,
"%s: mounting over filesystem type %#010lx is forbidden\n",
1155 progname, (
unsigned long)fs_buf.f_type);
1159static int try_open(
const char *dev,
char **devp,
int silent)
1161 int fd = open(dev, O_RDWR);
1163 *devp = strdup(dev);
1164 if (*devp == NULL) {
1165 fprintf(stderr,
"%s: failed to allocate memory\n",
1170 }
else if (errno == ENODEV ||
1174 fprintf(stderr,
"%s: failed to open %s: %s\n", progname, dev,
1180static int try_open_fuse_device(
char **devp)
1185 fd = try_open(FUSE_DEV, devp, 0);
1190static int open_fuse_device(
char **devp)
1192 int fd = try_open_fuse_device(devp);
1197 "%s: fuse device not found, try 'modprobe fuse' first\n",
1204static int mount_fuse(
const char *mnt,
const char *opts,
const char **type)
1210 char *source = NULL;
1211 char *mnt_opts = NULL;
1212 const char *real_mnt = mnt;
1213 int mountpoint_fd = -1;
1214 char *do_mount_opts = NULL;
1215 char *x_opts = NULL;
1217 fd = open_fuse_device(&dev);
1224 if (getuid() != 0 && mount_max != -1) {
1225 int mount_count = count_fuse_fs();
1226 if (mount_count >= mount_max) {
1227 fprintf(stderr,
"%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
1233 res= extract_x_options(opts, &do_mount_opts, &x_opts);
1237 res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
1240 res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT,
1241 fd, do_mount_opts, dev, &source, &mnt_opts);
1243 if (mountpoint_fd != -1)
1244 close(mountpoint_fd);
1251 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
1255 if (geteuid() == 0) {
1256 if (x_opts && strlen(x_opts) > 0) {
1261 size_t mnt_opts_len = strlen(mnt_opts);
1262 size_t x_mnt_opts_len = mnt_opts_len+
1264 char *x_mnt_opts = calloc(1, x_mnt_opts_len);
1267 strcpy(x_mnt_opts, mnt_opts);
1268 strncat(x_mnt_opts,
",", 2);
1271 strncat(x_mnt_opts, x_opts,
1272 x_mnt_opts_len - mnt_opts_len - 2);
1275 mnt_opts = x_mnt_opts;
1278 res = add_mount(source, mnt, *type, mnt_opts);
1290 free(do_mount_opts);
1300static int send_fd(
int sock_fd,
int fd)
1304 struct cmsghdr *p_cmsg;
1306 size_t cmsgbuf[CMSG_SPACE(
sizeof(fd)) /
sizeof(size_t)];
1310 msg.msg_control = cmsgbuf;
1311 msg.msg_controllen =
sizeof(cmsgbuf);
1312 p_cmsg = CMSG_FIRSTHDR(&msg);
1313 p_cmsg->cmsg_level = SOL_SOCKET;
1314 p_cmsg->cmsg_type = SCM_RIGHTS;
1315 p_cmsg->cmsg_len = CMSG_LEN(
sizeof(fd));
1316 p_fds = (
int *) CMSG_DATA(p_cmsg);
1318 msg.msg_controllen = p_cmsg->cmsg_len;
1319 msg.msg_name = NULL;
1320 msg.msg_namelen = 0;
1326 vec.iov_base = &sendchar;
1327 vec.iov_len =
sizeof(sendchar);
1328 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
1330 perror(
"sending file descriptor");
1342static int recheck_ENOTCONN_as_owner(
const char *mnt)
1346 perror(
"fuse: recheck_ENOTCONN_as_owner can't fork");
1347 _exit(EXIT_FAILURE);
1348 }
else if(pid == 0) {
1349 uid_t uid = getuid();
1350 gid_t gid = getgid();
1351 if(setresgid(gid, gid, gid) == -1) {
1352 perror(
"fuse: can't set resgid");
1353 _exit(EXIT_FAILURE);
1355 if(setresuid(uid, uid, uid) == -1) {
1356 perror(
"fuse: can't set resuid");
1357 _exit(EXIT_FAILURE);
1360 int fd = open(mnt, O_RDONLY);
1361 if(fd == -1 && errno == ENOTCONN)
1362 _exit(EXIT_SUCCESS);
1364 _exit(EXIT_FAILURE);
1367 int res = waitpid(pid, &status, 0);
1369 perror(
"fuse: waiting for child failed");
1370 _exit(EXIT_FAILURE);
1372 return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS;
1392static int should_auto_unmount(
const char *mnt,
const char *type)
1401 fprintf(stderr,
"%s: failed to allocate memory\n", progname);
1405 if (chdir_to_parent(copy, &last) == -1)
1407 if (check_is_mount(last, mnt, type) == -1)
1410 fd = open(mnt, O_RDONLY);
1420 result = recheck_ENOTCONN_as_owner(mnt);
1432static void usage(
void)
1434 printf(
"%s: [options] mountpoint\n"
1437 " -V print version\n"
1438 " -o opt[,opt...] mount options\n"
1441 " -z lazy unmount\n",
1446static void show_version(
void)
1448 printf(
"fusermount3 version: %s\n", PACKAGE_VERSION);
1457static void close_inherited_fds(
int cfd)
1459 int max_fd = sysconf(_SC_OPEN_MAX);
1462#ifdef CLOSE_RANGE_CLOEXEC
1464 rc = close_range(cfd + 1, ~0U, 0);
1466 fprintf(stderr,
"Failed to close high range of FDs: %s",
1471 rc = close_range(0, cfd - 1, 0);
1473 fprintf(stderr,
"Failed to close low range of FDs: %s",
1486 for (
int fd = 0; fd <= max_fd; fd++) {
1492int main(
int argc,
char *argv[])
1500 static int unmount = 0;
1501 static int lazy = 0;
1502 static int quiet = 0;
1503 char *commfd = NULL;
1505 const char *opts =
"";
1506 const char *type = NULL;
1507 int setup_auto_unmount_only = 0;
1509 static const struct option long_opts[] = {
1510 {
"unmount", no_argument, NULL,
'u'},
1511 {
"lazy", no_argument, NULL,
'z'},
1512 {
"quiet", no_argument, NULL,
'q'},
1513 {
"help", no_argument, NULL,
'h'},
1514 {
"version", no_argument, NULL,
'V'},
1515 {
"options", required_argument, NULL,
'o'},
1518 {
"auto-unmount", no_argument, NULL,
'U'},
1519 {
"comm-fd", required_argument, NULL,
'c'},
1522 progname = strdup(argc > 0 ? argv[0] :
"fusermount");
1523 if (progname == NULL) {
1524 fprintf(stderr,
"%s: failed to allocate memory\n", argv[0]);
1528 while ((ch = getopt_long(argc, argv,
"hVo:uzq", long_opts,
1549 setup_auto_unmount_only = 1;
1567 if (lazy && !unmount) {
1568 fprintf(stderr,
"%s: -z can only be used with -u\n", progname);
1572 if (optind >= argc) {
1573 fprintf(stderr,
"%s: missing mountpoint argument\n", progname);
1575 }
else if (argc > optind + 1) {
1576 fprintf(stderr,
"%s: extra arguments after the mountpoint\n",
1581 origmnt = argv[optind];
1584 mnt = fuse_mnt_resolve_path(progname, origmnt);
1588 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
1597 if (!setup_auto_unmount_only && unmount)
1601 commfd = getenv(FUSE_COMMFD_ENV);
1602 if (commfd == NULL) {
1603 fprintf(stderr,
"%s: old style mounting not supported\n",
1608 res = libfuse_strtol(commfd, &cfd);
1611 "%s: invalid _FUSE_COMMFD: %s\n",
1617 struct stat statbuf;
1618 fstat(cfd, &statbuf);
1619 if(!S_ISSOCK(statbuf.st_mode)) {
1621 "%s: file descriptor %li is not a socket, can't send fuse fd\n",
1627 if (setup_auto_unmount_only)
1628 goto wait_for_auto_unmount;
1630 fd = mount_fuse(mnt, opts, &type);
1634 res = send_fd(cfd, fd);
1636 umount2(mnt, MNT_DETACH);
1641 if (!auto_unmount) {
1647wait_for_auto_unmount:
1653 close_inherited_fds(cfd);
1658 fprintf(stderr,
"%s: failed to chdir to '/'\n", progname);
1662 sigfillset(&sigset);
1663 sigprocmask(SIG_BLOCK, &sigset, NULL);
1669 unsigned char buf[16];
1670 int n = recv(cfd, buf,
sizeof(buf), 0);
1681 if (!should_auto_unmount(mnt, type)) {
1687 res = unmount_fuse(mnt, quiet, lazy);
1689 res = umount2(mnt, lazy ? UMOUNT_DETACH : 0);
1690 if (res == -1 && !quiet)
1692 "%s: failed to unmount %s: %s\n",
1693 progname, mnt, strerror(errno));