13 #include "fuse_misc.h"    15 #include "mount_util.h"    25 #include <sys/socket.h>    28 #include <sys/mount.h>    33 #define MS_RDONLY       MNT_RDONLY    34 #define MS_NOSUID       MNT_NOSUID    35 #define MS_NODEV        MNT_NODEV    36 #define MS_NOEXEC       MNT_NOEXEC    37 #define MS_SYNCHRONOUS  MNT_SYNCHRONOUS    38 #define MS_NOATIME      MNT_NOATIME    40 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)    43 #define FUSERMOUNT_PROG         "fusermount3"    44 #define FUSE_COMMFD_ENV         "_FUSE_COMMFD"    47 #define fork() vfork()    51 #define MS_DIRSYNC 128    73         char *fusermount_opts;
    78 #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }    80 static const struct fuse_opt fuse_mount_opts[] = {
    81         FUSE_MOUNT_OPT(
"allow_other",           allow_other),
    82         FUSE_MOUNT_OPT(
"blkdev",                blkdev),
    83         FUSE_MOUNT_OPT(
"auto_unmount",          auto_unmount),
    84         FUSE_MOUNT_OPT(
"fsname=%s",             fsname),
    85         FUSE_MOUNT_OPT(
"max_read=%u",           max_read),
    86         FUSE_MOUNT_OPT(
"subtype=%s",            subtype),
   117 static void exec_fusermount(
const char *argv[])
   119         execv(FUSERMOUNT_DIR 
"/" FUSERMOUNT_PROG, (
char **) argv);
   120         execvp(FUSERMOUNT_PROG, (
char **) argv);
   123 void fuse_mount_version(
void)
   127                 const char *argv[] = { FUSERMOUNT_PROG, 
"--version", NULL };
   128                 exec_fusermount(argv);
   130         } 
else if (pid != -1)
   131                 waitpid(pid, NULL, 0);
   140 static const struct mount_flags mount_flags[] = {
   141         {
"rw",      MS_RDONLY,      0},
   142         {
"ro",      MS_RDONLY,      1},
   143         {
"suid",    MS_NOSUID,      0},
   144         {
"nosuid",  MS_NOSUID,      1},
   145         {
"dev",     MS_NODEV,       0},
   146         {
"nodev",   MS_NODEV,       1},
   147         {
"exec",    MS_NOEXEC,      0},
   148         {
"noexec",  MS_NOEXEC,      1},
   149         {
"async",   MS_SYNCHRONOUS, 0},
   150         {
"sync",    MS_SYNCHRONOUS, 1},
   151         {
"atime",   MS_NOATIME,     0},
   152         {
"noatime", MS_NOATIME,     1},
   154         {
"dirsync", MS_DIRSYNC,     1},
   159 unsigned get_max_read(
struct mount_opts *o)
   164 static void set_mount_flag(
const char *s, 
int *flags)
   168         for (i = 0; mount_flags[i].opt != NULL; i++) {
   169                 const char *opt = mount_flags[i].opt;
   170                 if (strcmp(opt, s) == 0) {
   171                         if (mount_flags[i].on)
   172                                 *flags |= mount_flags[i].flag;
   174                                 *flags &= ~mount_flags[i].flag;
   178         fuse_log(FUSE_LOG_ERR, 
"fuse: internal error, can't find mount flag\n");
   182 static int fuse_mount_opt_proc(
void *data, 
const char *arg, 
int key,
   186         struct mount_opts *mo = data;
   193                 set_mount_flag(arg, &mo->flags);
   199         case KEY_FUSERMOUNT_OPT:
   202         case KEY_SUBTYPE_OPT:
   217 static int receive_fd(
int fd)
   223         size_t ccmsg[CMSG_SPACE(
sizeof(
int)) / 
sizeof(size_t)];
   224         struct cmsghdr *cmsg;
   229         memset(&msg, 0, 
sizeof(msg));
   236         msg.msg_control = ccmsg;
   237         msg.msg_controllen = 
sizeof(ccmsg);
   239         while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
   249         cmsg = CMSG_FIRSTHDR(&msg);
   250         if (cmsg->cmsg_type != SCM_RIGHTS) {
   251                 fuse_log(FUSE_LOG_ERR, 
"got control message of unknown type %d\n",
   255         return *(
int*)CMSG_DATA(cmsg);
   258 void fuse_kern_unmount(
const char *mountpoint, 
int fd)
   268                 res = poll(&pfd, 1, 0);
   280                 if (res == 1 && (pfd.revents & POLLERR))
   284         if (geteuid() == 0) {
   285                 fuse_mnt_umount(
"fuse", mountpoint, mountpoint,  1);
   289         res = umount2(mountpoint, 2);
   298                 const char *argv[] = { FUSERMOUNT_PROG, 
"-u", 
"-q", 
"-z",
   299                                        "--", mountpoint, NULL };
   301                 exec_fusermount(argv);
   304         waitpid(pid, NULL, 0);
   307 static int fuse_mount_fusermount(
const char *mountpoint, 
struct mount_opts *mo,
   308                 const char *opts, 
int quiet)
   315                 fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
   319         res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
   321                 perror(
"fuse: socketpair() failed");
   327                 perror(
"fuse: fork() failed");
   335                 const char *argv[32];
   339                         int fd = open(
"/dev/null", O_RDONLY);
   346                 argv[a++] = FUSERMOUNT_PROG;
   352                 argv[a++] = mountpoint;
   356                 fcntl(fds[0], F_SETFD, 0);
   357                 snprintf(env, 
sizeof(env), 
"%i", fds[0]);
   358                 setenv(FUSE_COMMFD_ENV, env, 1);
   359                 exec_fusermount(argv);
   360                 perror(
"fuse: failed to exec fusermount3");
   365         rv = receive_fd(fds[1]);
   367         if (!mo->auto_unmount) {
   371                 waitpid(pid, NULL, 0); 
   375                 fcntl(rv, F_SETFD, FD_CLOEXEC);
   384 static int fuse_mount_sys(
const char *mnt, 
struct mount_opts *mo,
   385                           const char *mnt_opts)
   388         const char *devname = 
"/dev/fuse";
   396                 fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
   400         res = stat(mnt, &stbuf);
   402                 fuse_log(FUSE_LOG_ERR, 
"fuse: failed to access mountpoint %s: %s\n",
   403                         mnt, strerror(errno));
   407         if (mo->auto_unmount) {
   413         fd = open(devname, O_RDWR | O_CLOEXEC);
   415                 if (errno == ENODEV || errno == ENOENT)
   416                         fuse_log(FUSE_LOG_ERR, 
"fuse: device not found, try 'modprobe fuse' first\n");
   418                         fuse_log(FUSE_LOG_ERR, 
"fuse: failed to open %s: %s\n",
   419                                 devname, strerror(errno));
   423                 fcntl(fd, F_SETFD, FD_CLOEXEC);
   425         snprintf(tmp, 
sizeof(tmp),  
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
   426                  fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
   432         source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
   433                         (mo->subtype ? strlen(mo->subtype) : 0) +
   434                         strlen(devname) + 32);
   436         type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
   437         if (!type || !source) {
   438                 fuse_log(FUSE_LOG_ERR, 
"fuse: failed to allocate memory\n");
   442         strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
   445                 strcat(type, mo->subtype);
   448                mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
   450         res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
   451         if (res == -1 && errno == ENODEV && mo->subtype) {
   453                 strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
   456                                 sprintf(source, 
"%s#%s", mo->subtype,
   459                         strcpy(source, type);
   461                 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
   468                 if (errno == EPERM) {
   471                         int errno_save = errno;
   472                         if (mo->blkdev && errno == ENODEV &&
   473                             !fuse_mnt_check_fuseblk())
   475                                         "fuse: 'fuseblk' support missing\n");
   477                                 fuse_log(FUSE_LOG_ERR, 
"fuse: mount failed: %s\n",
   478                                         strerror(errno_save));
   485         if (geteuid() == 0) {
   486                 char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
   491                 res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
   512 static int get_mnt_flag_opts(
char **mnt_optsp, 
int flags)
   519         for (i = 0; mount_flags[i].opt != NULL; i++) {
   520                 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
   527 struct mount_opts *parse_mount_opts(
struct fuse_args *args)
   529         struct mount_opts *mo;
   531         mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
   535         memset(mo, 0, 
sizeof(
struct mount_opts));
   536         mo->flags = MS_NOSUID | MS_NODEV;
   539             fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
   545         destroy_mount_opts(mo);
   549 void destroy_mount_opts(
struct mount_opts *mo)
   553         free(mo->fusermount_opts);
   554         free(mo->subtype_opt);
   555         free(mo->kernel_opts);
   561 int fuse_kern_mount(
const char *mountpoint, 
struct mount_opts *mo)
   564         char *mnt_opts = NULL;
   567         if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
   574         res = fuse_mount_sys(mountpoint, mo, mnt_opts);
   576                 if (mo->fusermount_opts &&
   581                         char *tmp_opts = NULL;
   590                         res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
   593                                 res = fuse_mount_fusermount(mountpoint, mo,
   596                         res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
 #define FUSE_OPT_KEY(templ, key)
int fuse_opt_add_opt(char **opts, const char *opt)
void fuse_log(enum fuse_log_level level, const char *fmt,...)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
int fuse_opt_add_opt_escaped(char **opts, const char *opt)