1 /*- 2 * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org> 3 * Copyright (c) 2019 The DragonFly Project 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <vfs/fuse/fuse_mount.h> 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <stdbool.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include <getopt.h> 38 #include <mntopts.h> 39 #include <err.h> 40 41 #define MOPT_FUSE_LINUX_OPTS \ 42 { "default_permissions", 0, FUSE_MOUNT_DEFAULT_PERMISSIONS, 1 }, \ 43 { "allow_other", 0, FUSE_MOUNT_ALLOW_OTHER, 1 }, \ 44 { "max_read=", 0, FUSE_MOUNT_MAX_READ, 1 }, \ 45 { "subtype=", 0, FUSE_MOUNT_SUBTYPE, 1 } 46 47 /* XXX */ 48 #define MOPT_FUSE_LINUX_IGNORE_OPTS \ 49 { "fsname=", 0, 0, 1 }, \ 50 { "fd=", 0, 0, 1 }, \ 51 { "rootmode=", 0, 0, 1 }, \ 52 { "user_id=", 0, 0, 1 }, \ 53 { "group_id=", 0, 0, 1 }, \ 54 \ 55 { "auto_unmount", 0, 0, 1 }, \ 56 { "blkdev", 0, 0, 1 }, \ 57 { "blksize=", 0, 0, 1 }, \ 58 { "context=", 0, 0, 1 }, \ 59 { "fscontext=", 0, 0, 1 }, \ 60 { "defcontext=", 0, 0, 1 }, \ 61 { "rootcontext=", 0, 0, 1 }, \ 62 { "user=", 0, 0, 1 }, \ 63 { "-r", 0, 0, 1 }, \ 64 { "ro", 0, 0, 1 }, \ 65 { "rw", 0, 0, 1 }, \ 66 { "suid", 0, 0, 1 }, \ 67 { "nosuid", 0, 0, 1 }, \ 68 { "dev", 0, 0, 1 }, \ 69 { "nodev", 0, 0, 1 }, \ 70 { "exec", 0, 0, 1 }, \ 71 { "noexec", 0, 0, 1 }, \ 72 { "async", 0, 0, 1 }, \ 73 { "sync", 0, 0, 1 }, \ 74 { "dirsync", 0, 0, 1 }, \ 75 { "atime", 0, 0, 1 }, \ 76 { "noatime", 0, 0, 1 } 77 78 static struct mntopt mopts[] = { 79 MOPT_FUSE_LINUX_OPTS, 80 MOPT_FUSE_LINUX_IGNORE_OPTS, 81 MOPT_STDOPTS, 82 MOPT_NULL 83 }; 84 85 static void 86 usage(void) 87 { 88 fprintf(stderr, "usage: mount_fusefs [-o options] fd mountpoint\n"); 89 exit(1); 90 } 91 92 static char* 93 get_optval(const char *ptr) 94 { 95 char *ret = strdup(ptr); 96 const char *end = strstr(ptr, ","); 97 98 if (!end) 99 return ret; 100 101 ret[(int)(end - ptr)] = '\0'; 102 return ret; 103 } 104 105 /* 106 * e.g. 107 * argv[0] = "mount_fusefs" 108 * argv[1] = "-o" 109 * argv[2] = "max_read=...,subtype=hello" 110 * argv[3] = "3" 111 * argv[4] = "/mnt/fuse" 112 * argv[5] = "(null)" 113 */ 114 int 115 main(int argc, char **argv) 116 { 117 struct fuse_mount_info args; 118 struct vfsconf vfc; 119 struct stat st; 120 const char *fdstr, *mntpt; 121 char *ep, mntpath[MAXPATHLEN], fusedev[64]; 122 int error, c, fd, mntflags; 123 124 mntflags = 0; 125 memset(&args, 0, sizeof(args)); 126 127 while ((c = getopt_long(argc, argv, "ho:", NULL, NULL)) != -1) { 128 switch(c) { 129 case 'o': 130 getmntopts(optarg, mopts, &mntflags, &args.flags); 131 if (args.flags & FUSE_MOUNT_MAX_READ) { 132 char *p = strstr(optarg, "max_read="); 133 if (p) { 134 p = get_optval(p + 9); 135 args.max_read = strtol(p, NULL, 0); 136 free(p); 137 } 138 } 139 if (args.flags & FUSE_MOUNT_SUBTYPE) { 140 char *p = strstr(optarg, "subtype="); 141 if (p) { 142 p = get_optval(p + 8); 143 args.subtype = strdup(p); 144 free(p); 145 } 146 } 147 break; 148 case 'h': 149 default: 150 usage(); /* exit */ 151 } 152 } 153 argc -= optind; 154 argv += optind; 155 156 if (argc < 2) 157 usage(); 158 159 fdstr = argv[0]; 160 mntpt = argv[1]; 161 checkpath(mntpt, mntpath); 162 163 fd = strtol(fdstr, &ep, 10); 164 if (fd <= 0 || *ep != '\0') 165 err(1, "Invalid FUSE fd %s", fdstr); 166 167 if (fstat(fd, &st) == -1) 168 err(1, "Failed to stat FUSE fd %d", fd); 169 strcpy(fusedev, "/dev/"); 170 devname_r(st.st_rdev, S_IFCHR, fusedev + strlen(fusedev), 171 sizeof(fusedev) - strlen(fusedev)); 172 if (stat(fusedev, &st) == -1) 173 err(1, "Failed to stat FUSE device %s", fusedev); 174 if (strncmp(fusedev, "/dev/fuse", 9)) 175 err(1, "Invalid FUSE device %s", fusedev); 176 args.fd = fd; 177 args.from = strdup(fusedev); 178 179 error = getvfsbyname("fuse", &vfc); 180 if (error && vfsisloadable("fuse")) { 181 if(vfsload("fuse")) 182 err(1, "vfsload(%s)", "fuse"); 183 endvfsent(); 184 error = getvfsbyname("fuse", &vfc); 185 } 186 if (error) 187 errx(1, "%s filesystem not available", "fuse"); 188 189 if (mount(vfc.vfc_name, mntpath, mntflags, &args) == -1) 190 err(1, "mount"); 191 192 return 0; 193 } 194