2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 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 */
10 #define _GNU_SOURCE /* for clone */
13 #include "mount_util.h"
27 #include <sys/mount.h>
28 #include <sys/fsuid.h>
29 #include <sys/socket.h>
30 #include <sys/utsname.h>
33 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
35 #define FUSE_DEV_OLD "/proc/fs/fuse/dev"
36 #define FUSE_DEV_NEW "/dev/fuse"
37 #define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
38 #define FUSE_CONF "/etc/fuse.conf"
41 #define MS_DIRSYNC 128
47 #define MS_PRIVATE (1<<18)
51 #define UMOUNT_DETACH 0x00000002 /* Just detach from the tree */
53 #ifndef UMOUNT_NOFOLLOW
54 #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
57 #define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
60 static const char *progname
;
62 static int user_allow_other
= 0;
63 static int mount_max
= 1000;
65 static int auto_unmount
= 0;
67 static const char *get_user_name(void)
69 struct passwd
*pw
= getpwuid(getuid());
70 if (pw
!= NULL
&& pw
->pw_name
!= NULL
)
73 fprintf(stderr
, "%s: could not determine username\n", progname
);
78 static uid_t oldfsuid
;
79 static gid_t oldfsgid
;
81 static void drop_privs(void)
84 oldfsuid
= setfsuid(getuid());
85 oldfsgid
= setfsgid(getgid());
89 static void restore_privs(void)
99 * Make sure that /etc/mtab is checked and updated atomically
101 static int lock_umount(void)
103 const char *mtab_lock
= _PATH_MOUNTED
".fuselock";
106 struct stat mtab_stat
;
108 /* /etc/mtab could be a symlink to /proc/mounts */
109 if (lstat(_PATH_MOUNTED
, &mtab_stat
) == 0 && S_ISLNK(mtab_stat
.st_mode
))
112 mtablock
= open(mtab_lock
, O_RDWR
| O_CREAT
, 0600);
113 if (mtablock
== -1) {
114 fprintf(stderr
, "%s: unable to open fuse lock file: %s\n",
115 progname
, strerror(errno
));
118 res
= lockf(mtablock
, F_LOCK
, 0);
120 fprintf(stderr
, "%s: error getting lock: %s\n", progname
,
129 static void unlock_umount(int mtablock
)
134 res
= lockf(mtablock
, F_ULOCK
, 0);
136 fprintf(stderr
, "%s: error releasing lock: %s\n",
137 progname
, strerror(errno
));
143 static int add_mount(const char *source
, const char *mnt
, const char *type
,
146 return fuse_mnt_add_mount(progname
, source
, mnt
, type
, opts
);
149 static int may_unmount(const char *mnt
, int quiet
)
153 const char *user
= NULL
;
157 const char *mtab
= _PATH_MOUNTED
;
159 user
= get_user_name();
163 fp
= setmntent(mtab
, "r");
165 fprintf(stderr
, "%s: failed to open %s: %s\n", progname
, mtab
,
170 uidlen
= sprintf(uidstr
, "%u", getuid());
173 while ((entp
= getmntent(fp
)) != NULL
) {
174 if (!found
&& strcmp(entp
->mnt_dir
, mnt
) == 0 &&
175 (strcmp(entp
->mnt_type
, "fuse") == 0 ||
176 strcmp(entp
->mnt_type
, "fuseblk") == 0 ||
177 strncmp(entp
->mnt_type
, "fuse.", 5) == 0 ||
178 strncmp(entp
->mnt_type
, "fuseblk.", 8) == 0)) {
179 char *p
= strstr(entp
->mnt_opts
, "user=");
181 (p
== entp
->mnt_opts
|| *(p
-1) == ',') &&
182 strcmp(p
+ 5, user
) == 0) {
186 /* /etc/mtab is a link pointing to
189 strstr(entp
->mnt_opts
, "user_id=")) &&
190 (p
== entp
->mnt_opts
||
192 strncmp(p
+ 8, uidstr
, uidlen
) == 0 &&
193 (*(p
+8+uidlen
) == ',' ||
194 *(p
+8+uidlen
) == '\0')) {
205 "%s: entry for %s not found in %s\n",
206 progname
, mnt
, mtab
);
214 * Check whether the file specified in "fusermount -u" is really a
215 * mountpoint and not a symlink. This is necessary otherwise the user
216 * could move the mountpoint away and replace it with a symlink
217 * pointing to an arbitrary mount, thereby tricking fusermount into
218 * unmounting that (umount(2) will follow symlinks).
220 * This is the child process running in a separate mount namespace, so
221 * we don't mess with the global namespace and if the process is
222 * killed for any reason, mounts are automatically cleaned up.
224 * First make sure nothing is propagated back into the parent
225 * namespace by marking all mounts "private".
227 * Then bind mount parent onto a stable base where the user can't move
230 * Finally check /proc/mounts for an entry matching the requested
231 * mountpoint. If it's found then we are OK, and the user can't move
232 * it around within the parent directory as rename() will return
233 * EBUSY. Be careful to ignore any mounts that existed before the
236 static int check_is_mount_child(void *p
)
239 const char *last
= a
[0];
240 const char *mnt
= a
[1];
242 const char *procmounts
= "/proc/mounts";
248 res
= mount("", "/", "", MS_PRIVATE
| MS_REC
, NULL
);
250 fprintf(stderr
, "%s: failed to mark mounts private: %s\n",
251 progname
, strerror(errno
));
255 fp
= setmntent(procmounts
, "r");
257 fprintf(stderr
, "%s: failed to open %s: %s\n", progname
,
258 procmounts
, strerror(errno
));
263 while (getmntent(fp
) != NULL
)
267 fp
= setmntent(procmounts
, "r");
269 fprintf(stderr
, "%s: failed to open %s: %s\n", progname
,
270 procmounts
, strerror(errno
));
274 res
= mount(".", "/", "", MS_BIND
| MS_REC
, NULL
);
276 fprintf(stderr
, "%s: failed to bind parent to /: %s\n",
277 progname
, strerror(errno
));
282 while ((entp
= getmntent(fp
)) != NULL
) {
287 if (entp
->mnt_dir
[0] == '/' &&
288 strcmp(entp
->mnt_dir
+ 1, last
) == 0) {
296 fprintf(stderr
, "%s: %s not mounted\n", progname
, mnt
);
303 static pid_t
clone_newns(void *a
)
306 char *stack
= buf
+ (sizeof(buf
) / 2 - ((size_t) buf
& 15));
309 extern int __clone2(int (*fn
)(void *),
310 void *child_stack_base
, size_t stack_size
,
311 int flags
, void *arg
, pid_t
*ptid
,
312 void *tls
, pid_t
*ctid
);
314 return __clone2(check_is_mount_child
, stack
, sizeof(buf
) / 2,
315 CLONE_NEWNS
, a
, NULL
, NULL
, NULL
);
317 return clone(check_is_mount_child
, stack
, CLONE_NEWNS
, a
);
321 static int check_is_mount(const char *last
, const char *mnt
)
325 const char *a
[2] = { last
, mnt
};
327 pid
= clone_newns((void *) a
);
328 if (pid
== (pid_t
) -1) {
329 fprintf(stderr
, "%s: failed to clone namespace: %s\n",
330 progname
, strerror(errno
));
333 p
= waitpid(pid
, &status
, __WCLONE
);
334 if (p
== (pid_t
) -1) {
335 fprintf(stderr
, "%s: waitpid failed: %s\n",
336 progname
, strerror(errno
));
339 if (!WIFEXITED(status
)) {
340 fprintf(stderr
, "%s: child terminated abnormally (status %i)\n",
344 if (WEXITSTATUS(status
) != 0)
350 static int chdir_to_parent(char *copy
, const char **lastp
)
357 tmp
= strrchr(copy
, '/');
358 if (tmp
== NULL
|| tmp
[1] == '\0') {
359 fprintf(stderr
, "%s: internal error: invalid abs path: <%s>\n",
367 } else if (tmp
[1] != '\0') {
377 fprintf(stderr
, "%s: failed to chdir to %s: %s\n",
378 progname
, parent
, strerror(errno
));
382 if (getcwd(buf
, sizeof(buf
)) == NULL
) {
383 fprintf(stderr
, "%s: failed to obtain current directory: %s\n",
384 progname
, strerror(errno
));
387 if (strcmp(buf
, parent
) != 0) {
388 fprintf(stderr
, "%s: mountpoint moved (%s -> %s)\n", progname
,
397 /* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
398 static int umount_nofollow_support(void)
400 int res
= umount2("", UMOUNT_UNUSED
);
401 if (res
!= -1 || errno
!= EINVAL
)
404 res
= umount2("", UMOUNT_NOFOLLOW
);
405 if (res
!= -1 || errno
!= ENOENT
)
411 static int unmount_fuse_locked(const char *mnt
, int quiet
, int lazy
)
416 int umount_flags
= lazy
? UMOUNT_DETACH
: 0;
419 res
= may_unmount(mnt
, quiet
);
426 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
430 res
= chdir_to_parent(copy
, &last
);
434 if (umount_nofollow_support()) {
435 umount_flags
|= UMOUNT_NOFOLLOW
;
437 res
= check_is_mount(last
, mnt
);
442 res
= umount2(last
, umount_flags
);
443 if (res
== -1 && !quiet
) {
444 fprintf(stderr
, "%s: failed to unmount %s: %s\n",
445 progname
, mnt
, strerror(errno
));
454 fprintf(stderr
, "%s: failed to chdir to '/'\n", progname
);
458 return fuse_mnt_remove_mount(progname
, mnt
);
461 static int unmount_fuse(const char *mnt
, int quiet
, int lazy
)
464 int mtablock
= lock_umount();
466 res
= unmount_fuse_locked(mnt
, quiet
, lazy
);
467 unlock_umount(mtablock
);
472 static int count_fuse_fs(void)
476 const char *mtab
= _PATH_MOUNTED
;
477 FILE *fp
= setmntent(mtab
, "r");
479 fprintf(stderr
, "%s: failed to open %s: %s\n", progname
, mtab
,
483 while ((entp
= getmntent(fp
)) != NULL
) {
484 if (strcmp(entp
->mnt_type
, "fuse") == 0 ||
485 strncmp(entp
->mnt_type
, "fuse.", 5) == 0)
493 #else /* IGNORE_MTAB */
494 static int count_fuse_fs()
499 static int add_mount(const char *source
, const char *mnt
, const char *type
,
509 static int unmount_fuse(const char *mnt
, int quiet
, int lazy
)
511 return fuse_mnt_umount(progname
, mnt
, mnt
, lazy
);
513 #endif /* IGNORE_MTAB */
515 static void strip_line(char *line
)
517 char *s
= strchr(line
, '#');
520 for (s
= line
+ strlen(line
) - 1;
521 s
>= line
&& isspace((unsigned char) *s
); s
--);
523 for (s
= line
; isspace((unsigned char) *s
); s
++);
525 memmove(line
, s
, strlen(s
)+1);
528 static void parse_line(char *line
, int linenum
)
531 if (strcmp(line
, "user_allow_other") == 0)
532 user_allow_other
= 1;
533 else if (sscanf(line
, "mount_max = %i", &tmp
) == 1)
537 "%s: unknown parameter in %s at line %i: '%s'\n",
538 progname
, FUSE_CONF
, linenum
, line
);
541 static void read_conf(void)
543 FILE *fp
= fopen(FUSE_CONF
, "r");
548 while (fgets(line
, sizeof(line
), fp
) != NULL
) {
550 if (line
[strlen(line
)-1] == '\n') {
552 parse_line(line
, linenum
);
556 } else if(line
[strlen(line
)-1] == '\n') {
557 fprintf(stderr
, "%s: reading %s: line %i too long\n", progname
, FUSE_CONF
, linenum
);
565 fprintf(stderr
, "%s: reading %s: missing newline at end of file\n", progname
, FUSE_CONF
);
569 } else if (errno
!= ENOENT
) {
570 fprintf(stderr
, "%s: failed to open %s: %s\n",
571 progname
, FUSE_CONF
, strerror(errno
));
575 static int begins_with(const char *s
, const char *beg
)
577 if (strncmp(s
, beg
, strlen(beg
)) == 0)
590 static struct mount_flags mount_flags
[] = {
591 {"rw", MS_RDONLY
, 0, 1},
592 {"ro", MS_RDONLY
, 1, 1},
593 {"suid", MS_NOSUID
, 0, 0},
594 {"nosuid", MS_NOSUID
, 1, 1},
595 {"dev", MS_NODEV
, 0, 0},
596 {"nodev", MS_NODEV
, 1, 1},
597 {"exec", MS_NOEXEC
, 0, 1},
598 {"noexec", MS_NOEXEC
, 1, 1},
599 {"async", MS_SYNCHRONOUS
, 0, 1},
600 {"sync", MS_SYNCHRONOUS
, 1, 1},
601 {"atime", MS_NOATIME
, 0, 1},
602 {"noatime", MS_NOATIME
, 1, 1},
603 {"dirsync", MS_DIRSYNC
, 1, 1},
607 static int find_mount_flag(const char *s
, unsigned len
, int *on
, int *flag
)
611 for (i
= 0; mount_flags
[i
].opt
!= NULL
; i
++) {
612 const char *opt
= mount_flags
[i
].opt
;
613 if (strlen(opt
) == len
&& strncmp(opt
, s
, len
) == 0) {
614 *on
= mount_flags
[i
].on
;
615 *flag
= mount_flags
[i
].flag
;
616 if (!mount_flags
[i
].safe
&& getuid() != 0) {
619 "%s: unsafe option %s ignored\n",
628 static int add_option(char **optsp
, const char *opt
, unsigned expand
)
632 newopts
= strdup(opt
);
634 unsigned oldsize
= strlen(*optsp
);
635 unsigned newsize
= oldsize
+ 1 + strlen(opt
) + expand
+ 1;
636 newopts
= (char *) realloc(*optsp
, newsize
);
638 sprintf(newopts
+ oldsize
, ",%s", opt
);
640 if (newopts
== NULL
) {
641 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
648 static int get_mnt_opts(int flags
, char *opts
, char **mnt_optsp
)
653 if (!(flags
& MS_RDONLY
) && add_option(mnt_optsp
, "rw", 0) == -1)
656 for (i
= 0; mount_flags
[i
].opt
!= NULL
; i
++) {
657 if (mount_flags
[i
].on
&& (flags
& mount_flags
[i
].flag
) &&
658 add_option(mnt_optsp
, mount_flags
[i
].opt
, 0) == -1)
662 if (add_option(mnt_optsp
, opts
, 0) == -1)
664 /* remove comma from end of opts*/
665 l
= strlen(*mnt_optsp
);
666 if ((*mnt_optsp
)[l
-1] == ',')
667 (*mnt_optsp
)[l
-1] = '\0';
669 const char *user
= get_user_name();
673 if (add_option(mnt_optsp
, "user=", strlen(user
)) == -1)
675 strcat(*mnt_optsp
, user
);
680 static int opt_eq(const char *s
, unsigned len
, const char *opt
)
682 if(strlen(opt
) == len
&& strncmp(s
, opt
, len
) == 0)
688 static int get_string_opt(const char *s
, unsigned len
, const char *opt
,
692 unsigned opt_len
= strlen(opt
);
697 *val
= (char *) malloc(len
- opt_len
+ 1);
699 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
706 for (i
= 0; i
< len
; i
++) {
707 if (s
[i
] == '\\' && i
+ 1 < len
)
715 static int do_mount(const char *mnt
, char **typep
, mode_t rootmode
,
716 int fd
, const char *opts
, const char *dev
, char **sourcep
,
717 char **mnt_optsp
, off_t rootsize
)
720 int flags
= MS_NOSUID
| MS_NODEV
;
722 char *mnt_opts
= NULL
;
726 char *subtype
= NULL
;
732 optbuf
= (char *) malloc(strlen(opts
) + 128);
734 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
738 for (s
= opts
, d
= optbuf
; *s
;) {
740 const char *fsname_str
= "fsname=";
741 const char *subtype_str
= "subtype=";
742 for (len
= 0; s
[len
]; len
++) {
743 if (s
[len
] == '\\' && s
[len
+ 1])
745 else if (s
[len
] == ',')
748 if (begins_with(s
, fsname_str
)) {
749 if (!get_string_opt(s
, len
, fsname_str
, &fsname
))
751 } else if (begins_with(s
, subtype_str
)) {
752 if (!get_string_opt(s
, len
, subtype_str
, &subtype
))
754 } else if (opt_eq(s
, len
, "blkdev")) {
757 "%s: option blkdev is privileged\n",
762 } else if (opt_eq(s
, len
, "nonempty")) {
764 } else if (opt_eq(s
, len
, "auto_unmount")) {
766 } else if (!begins_with(s
, "fd=") &&
767 !begins_with(s
, "rootmode=") &&
768 !begins_with(s
, "user_id=") &&
769 !begins_with(s
, "group_id=")) {
773 if (opt_eq(s
, len
, "large_read")) {
774 struct utsname utsname
;
776 res
= uname(&utsname
);
778 sscanf(utsname
.release
, "%u.%u",
779 &kmaj
, &kmin
) == 2 &&
780 (kmaj
> 2 || (kmaj
== 2 && kmin
> 4))) {
781 fprintf(stderr
, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname
, kmaj
, kmin
);
785 if (getuid() != 0 && !user_allow_other
&&
786 (opt_eq(s
, len
, "allow_other") ||
787 opt_eq(s
, len
, "allow_root"))) {
788 fprintf(stderr
, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname
, len
, s
);
792 if (find_mount_flag(s
, len
, &on
, &flag
)) {
809 res
= get_mnt_opts(flags
, optbuf
, &mnt_opts
);
813 sprintf(d
, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
814 fd
, rootmode
, getuid(), getgid());
817 fuse_mnt_check_empty(progname
, mnt
, rootmode
, rootsize
) == -1)
820 source
= malloc((fsname
? strlen(fsname
) : 0) +
821 (subtype
? strlen(subtype
) : 0) + strlen(dev
) + 32);
823 type
= malloc((subtype
? strlen(subtype
) : 0) + 32);
824 if (!type
|| !source
) {
825 fprintf(stderr
, "%s: failed to allocate memory\n", progname
);
830 sprintf(type
, "%s.%s", blkdev
? "fuseblk" : "fuse", subtype
);
832 strcpy(type
, blkdev
? "fuseblk" : "fuse");
835 strcpy(source
, fsname
);
837 strcpy(source
, subtype
? subtype
: dev
);
839 res
= mount(source
, mnt
, type
, flags
, optbuf
);
840 if (res
== -1 && errno
== ENODEV
&& subtype
) {
841 /* Probably missing subtype support */
842 strcpy(type
, blkdev
? "fuseblk" : "fuse");
845 sprintf(source
, "%s#%s", subtype
, fsname
);
847 strcpy(source
, type
);
850 res
= mount(source
, mnt
, type
, flags
, optbuf
);
852 if (res
== -1 && errno
== EINVAL
) {
853 /* It could be an old version not supporting group_id */
854 sprintf(d
, "fd=%i,rootmode=%o,user_id=%u",
855 fd
, rootmode
, getuid());
856 res
= mount(source
, mnt
, type
, flags
, optbuf
);
859 int errno_save
= errno
;
860 if (blkdev
&& errno
== ENODEV
&& !fuse_mnt_check_fuseblk())
861 fprintf(stderr
, "%s: 'fuseblk' support missing\n",
864 fprintf(stderr
, "%s: mount failed: %s\n", progname
,
865 strerror(errno_save
));
870 *mnt_optsp
= mnt_opts
;
886 static int check_version(const char *dev
)
891 const char *version_file
;
894 if (strcmp(dev
, FUSE_DEV_OLD
) != 0)
897 version_file
= FUSE_VERSION_FILE_OLD
;
898 vf
= fopen(version_file
, "r");
900 fprintf(stderr
, "%s: kernel interface too old\n", progname
);
903 res
= fscanf(vf
, "%i.%i", &majorver
, &minorver
);
906 fprintf(stderr
, "%s: error reading %s\n", progname
,
911 fprintf(stderr
, "%s: kernel interface too old\n", progname
);
917 static int check_perm(const char **mntp
, struct stat
*stbuf
, int *mountpoint_fd
)
920 const char *mnt
= *mntp
;
921 const char *origmnt
= mnt
;
923 res
= lstat(mnt
, stbuf
);
925 fprintf(stderr
, "%s: failed to access mountpoint %s: %s\n",
926 progname
, mnt
, strerror(errno
));
930 /* No permission checking is done for root */
934 if (S_ISDIR(stbuf
->st_mode
)) {
938 "%s: failed to chdir to mountpoint: %s\n",
939 progname
, strerror(errno
));
943 res
= lstat(mnt
, stbuf
);
946 "%s: failed to access mountpoint %s: %s\n",
947 progname
, origmnt
, strerror(errno
));
951 if ((stbuf
->st_mode
& S_ISVTX
) && stbuf
->st_uid
!= getuid()) {
952 fprintf(stderr
, "%s: mountpoint %s not owned by user\n",
957 res
= access(mnt
, W_OK
);
959 fprintf(stderr
, "%s: user has no write access to mountpoint %s\n",
963 } else if (S_ISREG(stbuf
->st_mode
)) {
964 static char procfile
[256];
965 *mountpoint_fd
= open(mnt
, O_WRONLY
);
966 if (*mountpoint_fd
== -1) {
967 fprintf(stderr
, "%s: failed to open %s: %s\n",
968 progname
, mnt
, strerror(errno
));
971 res
= fstat(*mountpoint_fd
, stbuf
);
974 "%s: failed to access mountpoint %s: %s\n",
975 progname
, mnt
, strerror(errno
));
978 if (!S_ISREG(stbuf
->st_mode
)) {
980 "%s: mountpoint %s is no longer a regular file\n",
985 sprintf(procfile
, "/proc/self/fd/%i", *mountpoint_fd
);
989 "%s: mountpoint %s is not a directory or a regular file\n",
998 static int try_open(const char *dev
, char **devp
, int silent
)
1000 int fd
= open(dev
, O_RDWR
);
1002 *devp
= strdup(dev
);
1003 if (*devp
== NULL
) {
1004 fprintf(stderr
, "%s: failed to allocate memory\n",
1009 } else if (errno
== ENODEV
||
1010 errno
== ENOENT
)/* check for ENOENT too, for the udev case */
1013 fprintf(stderr
, "%s: failed to open %s: %s\n", progname
, dev
,
1019 static int try_open_fuse_device(char **devp
)
1025 fd
= try_open(FUSE_DEV_NEW
, devp
, 0);
1031 fd
= try_open(FUSE_DEV_OLD
, devp
, 1);
1038 static int open_fuse_device(char **devp
)
1040 int fd
= try_open_fuse_device(devp
);
1045 "%s: fuse device not found, try 'modprobe fuse' first\n",
1052 static int mount_fuse(const char *mnt
, const char *opts
)
1059 char *source
= NULL
;
1060 char *mnt_opts
= NULL
;
1061 const char *real_mnt
= mnt
;
1062 int mountpoint_fd
= -1;
1064 fd
= open_fuse_device(&dev
);
1071 if (getuid() != 0 && mount_max
!= -1) {
1072 int mount_count
= count_fuse_fs();
1073 if (mount_count
>= mount_max
) {
1074 fprintf(stderr
, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname
);
1079 res
= check_version(dev
);
1081 res
= check_perm(&real_mnt
, &stbuf
, &mountpoint_fd
);
1084 res
= do_mount(real_mnt
, &type
, stbuf
.st_mode
& S_IFMT
,
1085 fd
, opts
, dev
, &source
, &mnt_opts
,
1090 if (mountpoint_fd
!= -1)
1091 close(mountpoint_fd
);
1098 fprintf(stderr
, "%s: failed to chdir to '/'\n", progname
);
1102 if (geteuid() == 0) {
1103 res
= add_mount(source
, mnt
, type
, mnt_opts
);
1105 /* Can't clean up mount in a non-racy way */
1124 static int send_fd(int sock_fd
, int fd
)
1128 struct cmsghdr
*p_cmsg
;
1130 size_t cmsgbuf
[CMSG_SPACE(sizeof(fd
)) / sizeof(size_t)];
1134 msg
.msg_control
= cmsgbuf
;
1135 msg
.msg_controllen
= sizeof(cmsgbuf
);
1136 p_cmsg
= CMSG_FIRSTHDR(&msg
);
1137 p_cmsg
->cmsg_level
= SOL_SOCKET
;
1138 p_cmsg
->cmsg_type
= SCM_RIGHTS
;
1139 p_cmsg
->cmsg_len
= CMSG_LEN(sizeof(fd
));
1140 p_fds
= (int *) CMSG_DATA(p_cmsg
);
1142 msg
.msg_controllen
= p_cmsg
->cmsg_len
;
1143 msg
.msg_name
= NULL
;
1144 msg
.msg_namelen
= 0;
1148 /* "To pass file descriptors or credentials you need to send/read at
1149 * least one byte" (man 7 unix) */
1150 vec
.iov_base
= &sendchar
;
1151 vec
.iov_len
= sizeof(sendchar
);
1152 while ((retval
= sendmsg(sock_fd
, &msg
, 0)) == -1 && errno
== EINTR
);
1154 perror("sending file descriptor");
1160 static void usage(void)
1162 printf("%s: [options] mountpoint\n"
1165 " -V print version\n"
1166 " -o opt[,opt...] mount options\n"
1169 " -z lazy unmount\n",
1174 static void show_version(void)
1176 printf("fusermount version: %s\n", PACKAGE_VERSION
);
1180 int main(int argc
, char *argv
[])
1188 static int unmount
= 0;
1189 static int lazy
= 0;
1190 static int quiet
= 0;
1193 const char *opts
= "";
1195 static const struct option long_opts
[] = {
1196 {"unmount", no_argument
, NULL
, 'u'},
1197 {"lazy", no_argument
, NULL
, 'z'},
1198 {"quiet", no_argument
, NULL
, 'q'},
1199 {"help", no_argument
, NULL
, 'h'},
1200 {"version", no_argument
, NULL
, 'V'},
1203 progname
= strdup(argv
[0]);
1204 if (progname
== NULL
) {
1205 fprintf(stderr
, "%s: failed to allocate memory\n", argv
[0]);
1209 while ((ch
= getopt_long(argc
, argv
, "hVo:uzq", long_opts
,
1241 if (lazy
&& !unmount
) {
1242 fprintf(stderr
, "%s: -z can only be used with -u\n", progname
);
1246 if (optind
>= argc
) {
1247 fprintf(stderr
, "%s: missing mountpoint argument\n", progname
);
1249 } else if (argc
> optind
+ 1) {
1250 fprintf(stderr
, "%s: extra arguments after the mountpoint\n",
1255 origmnt
= argv
[optind
];
1258 mnt
= fuse_mnt_resolve_path(progname
, origmnt
);
1262 fprintf(stderr
, "%s: failed to chdir to '/'\n", progname
);
1274 commfd
= getenv(FUSE_COMMFD_ENV
);
1275 if (commfd
== NULL
) {
1276 fprintf(stderr
, "%s: old style mounting not supported\n",
1281 fd
= mount_fuse(mnt
, opts
);
1286 res
= send_fd(cfd
, fd
);
1294 /* Become a daemon and wait for the parent to exit or die.
1295 ie For the control socket to get closed.
1296 btw We don't want to use daemon() function here because
1297 it forks and messes with the file descriptors. */
1301 fprintf(stderr
, "%s: failed to chdir to '/'\n", progname
);
1305 sigfillset(&sigset
);
1306 sigprocmask(SIG_BLOCK
, &sigset
, NULL
);
1312 unsigned char buf
[16];
1313 int n
= recv(cfd
, buf
, sizeof(buf
), 0);
1326 res
= unmount_fuse(mnt
, quiet
, lazy
);
1328 res
= umount2(mnt
, lazy
? UMOUNT_DETACH
: 0);
1329 if (res
== -1 && !quiet
)
1331 "%s: failed to unmount %s: %s\n",
1332 progname
, mnt
, strerror(errno
));