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),
 
  118 static void exec_fusermount(
const char *argv[])
 
  120         execv(FUSERMOUNT_DIR 
"/" FUSERMOUNT_PROG, (
char **) argv);
 
  121         execvp(FUSERMOUNT_PROG, (
char **) argv);
 
  124 void fuse_mount_version(
void)
 
  128                 const char *argv[] = { FUSERMOUNT_PROG, 
"--version", NULL };
 
  129                 exec_fusermount(argv);
 
  131         } 
else if (pid != -1)
 
  132                 waitpid(pid, NULL, 0);
 
  141 static const struct mount_flags mount_flags[] = {
 
  142         {
"rw",      MS_RDONLY,      0},
 
  143         {
"ro",      MS_RDONLY,      1},
 
  144         {
"suid",    MS_NOSUID,      0},
 
  145         {
"nosuid",  MS_NOSUID,      1},
 
  146         {
"dev",     MS_NODEV,       0},
 
  147         {
"nodev",   MS_NODEV,       1},
 
  148         {
"exec",    MS_NOEXEC,      0},
 
  149         {
"noexec",  MS_NOEXEC,      1},
 
  150         {
"async",   MS_SYNCHRONOUS, 0},
 
  151         {
"sync",    MS_SYNCHRONOUS, 1},
 
  152         {
"atime",   MS_NOATIME,     0},
 
  153         {
"noatime", MS_NOATIME,     1},
 
  155         {
"dirsync", MS_DIRSYNC,     1},
 
  160 unsigned get_max_read(
struct mount_opts *o)
 
  165 static void set_mount_flag(
const char *s, 
int *flags)
 
  169         for (i = 0; mount_flags[i].opt != NULL; i++) {
 
  170                 const char *opt = mount_flags[i].opt;
 
  171                 if (strcmp(opt, s) == 0) {
 
  172                         if (mount_flags[i].on)
 
  173                                 *flags |= mount_flags[i].flag;
 
  175                                 *flags &= ~mount_flags[i].flag;
 
  179         fuse_log(FUSE_LOG_ERR, 
"fuse: internal error, can't find mount flag\n");
 
  183 static int fuse_mount_opt_proc(
void *data, 
const char *arg, 
int key,
 
  187         struct mount_opts *mo = data;
 
  194                 set_mount_flag(arg, &mo->flags);
 
  200         case KEY_FUSERMOUNT_OPT:
 
  203         case KEY_SUBTYPE_OPT:
 
  218 static int receive_fd(
int fd)
 
  224         size_t ccmsg[CMSG_SPACE(
sizeof(
int)) / 
sizeof(size_t)];
 
  225         struct cmsghdr *cmsg;
 
  230         memset(&msg, 0, 
sizeof(msg));
 
  237         msg.msg_control = ccmsg;
 
  238         msg.msg_controllen = 
sizeof(ccmsg);
 
  240         while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
 
  250         cmsg = CMSG_FIRSTHDR(&msg);
 
  251         if (cmsg->cmsg_type != SCM_RIGHTS) {
 
  252                 fuse_log(FUSE_LOG_ERR, 
"got control message of unknown type %d\n",
 
  256         return *(
int*)CMSG_DATA(cmsg);
 
  259 void fuse_kern_unmount(
const char *mountpoint, 
int fd)
 
  269                 res = poll(&pfd, 1, 0);
 
  281                 if (res == 1 && (pfd.revents & POLLERR))
 
  285         if (geteuid() == 0) {
 
  286                 fuse_mnt_umount(
"fuse", mountpoint, mountpoint,  1);
 
  290         res = umount2(mountpoint, 2);
 
  299                 const char *argv[] = { FUSERMOUNT_PROG, 
"-u", 
"-q", 
"-z",
 
  300                                        "--", mountpoint, NULL };
 
  302                 exec_fusermount(argv);
 
  305         waitpid(pid, NULL, 0);
 
  308 static int fuse_mount_fusermount(
const char *mountpoint, 
struct mount_opts *mo,
 
  309                 const char *opts, 
int quiet)
 
  316                 fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  320         res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
 
  322                 perror(
"fuse: socketpair() failed");
 
  328                 perror(
"fuse: fork() failed");
 
  336                 const char *argv[32];
 
  340                         int fd = open(
"/dev/null", O_RDONLY);
 
  347                 argv[a++] = FUSERMOUNT_PROG;
 
  353                 argv[a++] = mountpoint;
 
  357                 fcntl(fds[0], F_SETFD, 0);
 
  358                 snprintf(env, 
sizeof(env), 
"%i", fds[0]);
 
  359                 setenv(FUSE_COMMFD_ENV, env, 1);
 
  360                 exec_fusermount(argv);
 
  361                 perror(
"fuse: failed to exec fusermount3");
 
  366         rv = receive_fd(fds[1]);
 
  368         if (!mo->auto_unmount) {
 
  372                 waitpid(pid, NULL, 0); 
 
  376                 fcntl(rv, F_SETFD, FD_CLOEXEC);
 
  385 static int fuse_mount_sys(
const char *mnt, 
struct mount_opts *mo,
 
  386                           const char *mnt_opts)
 
  389         const char *devname = 
"/dev/fuse";
 
  397                 fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  401         res = stat(mnt, &stbuf);
 
  403                 fuse_log(FUSE_LOG_ERR, 
"fuse: failed to access mountpoint %s: %s\n",
 
  404                         mnt, strerror(errno));
 
  408         if (mo->auto_unmount) {
 
  414         fd = open(devname, O_RDWR | O_CLOEXEC);
 
  416                 if (errno == ENODEV || errno == ENOENT)
 
  417                         fuse_log(FUSE_LOG_ERR, 
"fuse: device not found, try 'modprobe fuse' first\n");
 
  419                         fuse_log(FUSE_LOG_ERR, 
"fuse: failed to open %s: %s\n",
 
  420                                 devname, strerror(errno));
 
  424                 fcntl(fd, F_SETFD, FD_CLOEXEC);
 
  426         snprintf(tmp, 
sizeof(tmp),  
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
 
  427                  fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
 
  433         source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
 
  434                         (mo->subtype ? strlen(mo->subtype) : 0) +
 
  435                         strlen(devname) + 32);
 
  437         type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
 
  438         if (!type || !source) {
 
  439                 fuse_log(FUSE_LOG_ERR, 
"fuse: failed to allocate memory\n");
 
  443         strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
 
  446                 strcat(type, mo->subtype);
 
  449                mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
 
  451         res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
 
  452         if (res == -1 && errno == ENODEV && mo->subtype) {
 
  454                 strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
 
  457                                 sprintf(source, 
"%s#%s", mo->subtype,
 
  460                         strcpy(source, type);
 
  462                 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
 
  469                 if (errno == EPERM) {
 
  472                         int errno_save = errno;
 
  473                         if (mo->blkdev && errno == ENODEV &&
 
  474                             !fuse_mnt_check_fuseblk())
 
  476                                         "fuse: 'fuseblk' support missing\n");
 
  478                                 fuse_log(FUSE_LOG_ERR, 
"fuse: mount failed: %s\n",
 
  479                                         strerror(errno_save));
 
  486         if (geteuid() == 0) {
 
  487                 char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
 
  492                 res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
 
  513 static int get_mnt_flag_opts(
char **mnt_optsp, 
int flags)
 
  520         for (i = 0; mount_flags[i].opt != NULL; i++) {
 
  521                 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
 
  528 struct mount_opts *parse_mount_opts(
struct fuse_args *args)
 
  530         struct mount_opts *mo;
 
  532         mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
 
  536         memset(mo, 0, 
sizeof(
struct mount_opts));
 
  537         mo->flags = MS_NOSUID | MS_NODEV;
 
  540             fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
 
  546         destroy_mount_opts(mo);
 
  550 void destroy_mount_opts(
struct mount_opts *mo)
 
  554         free(mo->fusermount_opts);
 
  555         free(mo->subtype_opt);
 
  556         free(mo->kernel_opts);
 
  562 int fuse_kern_mount(
const char *mountpoint, 
struct mount_opts *mo)
 
  565         char *mnt_opts = NULL;
 
  568         if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
 
  575         res = fuse_mount_sys(mountpoint, mo, mnt_opts);
 
  577                 if (mo->fusermount_opts &&
 
  582                         char *tmp_opts = NULL;
 
  591                         res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
 
  594                                 res = fuse_mount_fusermount(mountpoint, mo,
 
  597                         res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
 
void fuse_log(enum fuse_log_level level, const char *fmt,...)
#define FUSE_OPT_KEY(templ, key)
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
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(char **opts, const char *opt)