1 /* $OpenBSD: fuse.c,v 1.28 2016/05/24 19:24:46 okan Exp $ */ 2 /* 3 * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/wait.h> 19 #include <sys/types.h> 20 #include <sys/ioctl.h> 21 22 #include <miscfs/fuse/fusefs.h> 23 24 #include <errno.h> 25 #include <signal.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include "fuse_opt.h" 31 #include "fuse_private.h" 32 #include "debug.h" 33 34 static struct fuse_session *sigse; 35 static struct fuse_context *ictx = NULL; 36 static int max_read = FUSEBUFMAXSIZE; 37 38 enum { 39 KEY_HELP, 40 KEY_HELP_WITHOUT_HEADER, 41 KEY_VERSION, 42 KEY_MAXREAD, 43 KEY_STUB 44 }; 45 46 static struct fuse_opt fuse_core_opts[] = { 47 FUSE_OPT_KEY("-h", KEY_HELP), 48 FUSE_OPT_KEY("--help", KEY_HELP), 49 FUSE_OPT_KEY("-ho", KEY_HELP_WITHOUT_HEADER), 50 FUSE_OPT_KEY("-V", KEY_VERSION), 51 FUSE_OPT_KEY("--version", KEY_VERSION), 52 FUSE_OPT_KEY("max_read=", KEY_MAXREAD), 53 FUSE_OPT_KEY("debug", KEY_STUB), 54 FUSE_OPT_KEY("-d", KEY_STUB), 55 FUSE_OPT_KEY("-f", KEY_STUB), 56 FUSE_OPT_KEY("-s", KEY_STUB), 57 FUSE_OPT_KEY("use_ino", KEY_STUB), 58 FUSE_OPT_KEY("big_writes", KEY_STUB), 59 FUSE_OPT_KEY("default_permissions", KEY_STUB), 60 FUSE_OPT_KEY("fsname=", KEY_STUB), 61 FUSE_OPT_END 62 }; 63 64 int 65 fuse_loop(struct fuse *fuse) 66 { 67 struct fusebuf fbuf; 68 struct fuse_context ctx; 69 struct fb_ioctl_xch ioexch; 70 struct kevent ev; 71 ssize_t n; 72 int ret; 73 74 fuse->fc->kq = kqueue(); 75 if (fuse->fc->kq == -1) 76 return (-1); 77 78 EV_SET(&fuse->fc->event, fuse->fc->fd, EVFILT_READ, EV_ADD | 79 EV_ENABLE, 0, 0, 0); 80 81 while (!fuse->fc->dead) { 82 ret = kevent(fuse->fc->kq, &fuse->fc->event, 1, &ev, 1, NULL); 83 if (ret == -1) 84 DPERROR(__func__); 85 else if (ret > 0) { 86 n = read(fuse->fc->fd, &fbuf, sizeof(fbuf)); 87 if (n != sizeof(fbuf)) { 88 fprintf(stderr, "%s: bad fusebuf read\n", 89 __func__); 90 return (-1); 91 } 92 93 /* check if there is data something present */ 94 if (fbuf.fb_len) { 95 fbuf.fb_dat = malloc(fbuf.fb_len); 96 if (fbuf.fb_dat == NULL) 97 return (-1); 98 ioexch.fbxch_uuid = fbuf.fb_uuid; 99 ioexch.fbxch_len = fbuf.fb_len; 100 ioexch.fbxch_data = fbuf.fb_dat; 101 102 if (ioctl(fuse->fc->fd, FIOCGETFBDAT, 103 &ioexch)) { 104 free(fbuf.fb_dat); 105 return (-1); 106 } 107 } 108 109 ctx.fuse = fuse; 110 ctx.uid = fuse->conf.uid; 111 ctx.gid = fuse->conf.gid; 112 ctx.pid = fuse->conf.pid; 113 ctx.umask = fuse->conf.umask; 114 ctx.private_data = fuse->private_data; 115 ictx = &ctx; 116 117 ret = ifuse_exec_opcode(fuse, &fbuf); 118 if (ret) { 119 ictx = NULL; 120 return (-1); 121 } 122 123 n = write(fuse->fc->fd, &fbuf, sizeof(fbuf)); 124 if (fbuf.fb_len) { 125 if (fbuf.fb_dat == NULL) { 126 fprintf(stderr, "%s: fb_dat is Null\n", 127 __func__); 128 return (-1); 129 } 130 ioexch.fbxch_uuid = fbuf.fb_uuid; 131 ioexch.fbxch_len = fbuf.fb_len; 132 ioexch.fbxch_data = fbuf.fb_dat; 133 134 if (ioctl(fuse->fc->fd, FIOCSETFBDAT, &ioexch)) { 135 free(fbuf.fb_dat); 136 return (-1); 137 } 138 free(fbuf.fb_dat); 139 } 140 ictx = NULL; 141 142 if (n != FUSEBUFSIZE) { 143 errno = EINVAL; 144 return (-1); 145 } 146 } 147 } 148 149 return (0); 150 } 151 152 struct fuse_chan * 153 fuse_mount(const char *dir, unused struct fuse_args *args) 154 { 155 struct fusefs_args fargs; 156 struct fuse_chan *fc; 157 const char *errcause; 158 159 fc = calloc(1, sizeof(*fc)); 160 if (fc == NULL) 161 return (NULL); 162 163 fc->dir = realpath(dir, NULL); 164 if (fc->dir == NULL) 165 goto bad; 166 167 if ((fc->fd = open("/dev/fuse0", O_RDWR)) == -1) { 168 perror(__func__); 169 goto bad; 170 } 171 172 fargs.fd = fc->fd; 173 fargs.max_read = max_read; 174 if (mount(MOUNT_FUSEFS, fc->dir, 0, &fargs)) { 175 switch (errno) { 176 case EMFILE: 177 errcause = "mount table full"; 178 break; 179 case EOPNOTSUPP: 180 errcause = "filesystem not supported by kernel"; 181 break; 182 default: 183 errcause = strerror(errno); 184 break; 185 } 186 fprintf(stderr, "%s on %s: %s\n", __func__, dir, errcause); 187 goto bad; 188 } 189 190 return (fc); 191 bad: 192 if (fc->fd != -1) 193 close(fc->fd); 194 free(fc->dir); 195 free(fc); 196 return (NULL); 197 } 198 199 void 200 fuse_unmount(const char *dir, unused struct fuse_chan *ch) 201 { 202 if (ch->dead) 203 return; 204 205 if (unmount(dir, MNT_UPDATE) == -1) 206 DPERROR(__func__); 207 } 208 209 int 210 fuse_is_lib_option(unused const char *opt) 211 { 212 return (fuse_opt_match(fuse_core_opts, opt)); 213 } 214 215 int 216 fuse_chan_fd(struct fuse_chan *ch) 217 { 218 return (ch->fd); 219 } 220 221 struct fuse_session * 222 fuse_get_session(struct fuse *f) 223 { 224 return (&f->se); 225 } 226 227 int 228 fuse_loop_mt(unused struct fuse *fuse) 229 { 230 return (0); 231 } 232 233 struct fuse * 234 fuse_new(struct fuse_chan *fc, unused struct fuse_args *args, 235 const struct fuse_operations *ops, unused size_t size, 236 unused void *userdata) 237 { 238 struct fuse *fuse; 239 struct fuse_vnode *root; 240 241 if ((fuse = calloc(1, sizeof(*fuse))) == NULL) 242 return (NULL); 243 244 /* copy fuse ops to their own structure */ 245 memcpy(&fuse->op, ops, sizeof(fuse->op)); 246 247 fuse->fc = fc; 248 fuse->max_ino = FUSE_ROOT_INO; 249 fuse->se.args = fuse; 250 fuse->private_data = userdata; 251 252 if ((root = alloc_vn(fuse, "/", FUSE_ROOT_INO, 0)) == NULL) { 253 free(fuse); 254 return (NULL); 255 } 256 257 tree_init(&fuse->vnode_tree); 258 tree_init(&fuse->name_tree); 259 if (!set_vn(fuse, root)) { 260 free(fuse); 261 return (NULL); 262 } 263 264 return (fuse); 265 } 266 267 int 268 fuse_daemonize(unused int foreground) 269 { 270 #ifdef DEBUG 271 return (daemon(0,1)); 272 #else 273 return (daemon(0,0)); 274 #endif 275 } 276 277 void 278 fuse_destroy(unused struct fuse *f) 279 { 280 close(f->fc->fd); 281 free(f->fc->dir); 282 free(f->fc); 283 free(f); 284 } 285 286 static void 287 ifuse_get_signal(unused int num) 288 { 289 struct fuse *f; 290 pid_t child; 291 int status; 292 293 if (sigse != NULL) { 294 child = fork(); 295 296 if (child < 0) 297 return ; 298 299 f = sigse->args; 300 if (child == 0) { 301 fuse_unmount(f->fc->dir, f->fc); 302 sigse = NULL; 303 exit(0); 304 } 305 306 fuse_loop(f); 307 wait(&status); 308 } 309 } 310 311 void 312 fuse_remove_signal_handlers(unused struct fuse_session *se) 313 { 314 sigse = NULL; 315 signal(SIGHUP, SIG_DFL); 316 signal(SIGINT, SIG_DFL); 317 signal(SIGTERM, SIG_DFL); 318 signal(SIGPIPE, SIG_DFL); 319 } 320 321 int 322 fuse_set_signal_handlers(unused struct fuse_session *se) 323 { 324 sigse = se; 325 signal(SIGHUP, ifuse_get_signal); 326 signal(SIGINT, ifuse_get_signal); 327 signal(SIGTERM, ifuse_get_signal); 328 signal(SIGPIPE, SIG_IGN); 329 return (0); 330 } 331 332 static void 333 dump_help(void) 334 { 335 fprintf(stderr, "FUSE options:\n" 336 " -d -o debug enable debug output (implies -f)\n" 337 " -V print fuse version\n" 338 "\n"); 339 } 340 341 static void 342 dump_version(void) 343 { 344 fprintf(stderr, "FUSE library version %i\n", FUSE_USE_VERSION); 345 } 346 347 static int 348 ifuse_process_opt(void *data, const char *arg, int key, 349 unused struct fuse_args *args) 350 { 351 struct fuse_core_opt *opt = data; 352 struct stat st; 353 const char *err; 354 int res; 355 356 switch (key) { 357 case KEY_STUB: 358 return (0); 359 case KEY_HELP: 360 case KEY_HELP_WITHOUT_HEADER: 361 dump_help(); 362 return (-1); 363 case KEY_VERSION: 364 dump_version(); 365 return (-1); 366 case KEY_MAXREAD: 367 res = strtonum(arg, 0, FUSEBUFMAXSIZE, &err); 368 if (err) { 369 fprintf(stderr, "fuse: max_read %s\n", err); 370 return (-1); 371 } 372 max_read = res; 373 break; 374 case FUSE_OPT_KEY_NONOPT: 375 if (opt->mp == NULL) { 376 opt->mp = realpath(arg, opt->mp); 377 if (opt->mp == NULL) { 378 fprintf(stderr, "fuse: realpath: " 379 "%s : %s\n", arg, strerror(errno)); 380 return (-1); 381 } 382 383 res = stat(opt->mp, &st); 384 if (res == -1) { 385 fprintf(stderr, "fuse: bad mount point " 386 "%s : %s\n", arg, strerror(errno)); 387 return (-1); 388 } 389 390 if (!S_ISDIR(st.st_mode)) { 391 fprintf(stderr, "fuse: bad mount point " 392 "%s : %s\n", arg, 393 strerror(ENOTDIR)); 394 return (-1); 395 } 396 } else { 397 fprintf(stderr, "fuse: invalid argument %s\n", 398 arg); 399 return (-1); 400 } 401 break; 402 default: 403 fprintf(stderr, "fuse: unknown option %s\n", arg); 404 return (-1); 405 } 406 return (0); 407 } 408 409 int 410 fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, unused int *fg) 411 { 412 struct fuse_core_opt opt; 413 414 #ifdef DEBUG 415 ifuse_debug_init(); 416 #endif 417 bzero(&opt, sizeof(opt)); 418 if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1) 419 return (-1); 420 421 if (opt.mp == NULL) { 422 fprintf(stderr, "fuse: missing mountpoint parameter\n"); 423 return (-1); 424 } 425 426 *mp = strdup(opt.mp); 427 if (*mp == NULL) 428 return (-1); 429 *mt = 0; 430 431 return (0); 432 } 433 434 struct fuse_context * 435 fuse_get_context(void) 436 { 437 return (ictx); 438 } 439 440 int 441 fuse_version(void) 442 { 443 return (FUSE_VERSION); 444 } 445 446 void 447 fuse_teardown(struct fuse *fuse, char *mp) 448 { 449 fuse_unmount(mp, fuse->fc); 450 fuse_destroy(fuse); 451 } 452 453 int 454 fuse_invalidate(unused struct fuse *f, unused const char *path) 455 { 456 return (EINVAL); 457 } 458 459 struct fuse * 460 fuse_setup(int argc, char **argv, const struct fuse_operations *ops, 461 size_t size, char **mp, int *mt, void *data) 462 { 463 struct fuse_args args = FUSE_ARGS_INIT(argc, argv); 464 struct fuse_chan *fc; 465 struct fuse *fuse; 466 int fg; 467 468 if (fuse_parse_cmdline(&args, mp, mt, &fg)) 469 goto err; 470 471 fuse_daemonize(0); 472 473 if ((fc = fuse_mount(*mp, NULL)) == NULL) 474 goto err; 475 476 if ((fuse = fuse_new(fc, NULL, ops, size, data)) == NULL) { 477 free(fc); 478 goto err; 479 } 480 481 return (fuse); 482 err: 483 free(*mp); 484 return (NULL); 485 } 486 487 int 488 fuse_main(int argc, char **argv, const struct fuse_operations *ops, void *data) 489 { 490 struct fuse *fuse; 491 char *mp = NULL; 492 int mt; 493 494 fuse = fuse_setup(argc, argv, ops, sizeof(*ops), &mp, &mt, data); 495 if (!fuse) 496 return (-1); 497 498 return (fuse_loop(fuse)); 499 } 500