1 /* $OpenBSD: fuse.c,v 1.31 2017/10/25 09:29:46 mpi 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 while (waitpid(child, &status, 0) == -1) { 308 if (errno != EINTR) 309 break; 310 } 311 } 312 } 313 314 void 315 fuse_remove_signal_handlers(unused struct fuse_session *se) 316 { 317 sigse = NULL; 318 signal(SIGHUP, SIG_DFL); 319 signal(SIGINT, SIG_DFL); 320 signal(SIGTERM, SIG_DFL); 321 signal(SIGPIPE, SIG_DFL); 322 } 323 324 int 325 fuse_set_signal_handlers(unused struct fuse_session *se) 326 { 327 sigse = se; 328 signal(SIGHUP, ifuse_get_signal); 329 signal(SIGINT, ifuse_get_signal); 330 signal(SIGTERM, ifuse_get_signal); 331 signal(SIGPIPE, SIG_IGN); 332 return (0); 333 } 334 335 static void 336 dump_help(void) 337 { 338 fprintf(stderr, "FUSE options:\n" 339 " -d -o debug enable debug output (implies -f)\n" 340 " -V print fuse version\n" 341 "\n"); 342 } 343 344 static void 345 dump_version(void) 346 { 347 fprintf(stderr, "FUSE library version %i\n", FUSE_USE_VERSION); 348 } 349 350 static int 351 ifuse_process_opt(void *data, const char *arg, int key, 352 unused struct fuse_args *args) 353 { 354 struct fuse_core_opt *opt = data; 355 struct stat st; 356 const char *err; 357 int res; 358 359 switch (key) { 360 case KEY_STUB: 361 return (0); 362 case KEY_HELP: 363 case KEY_HELP_WITHOUT_HEADER: 364 dump_help(); 365 return (-1); 366 case KEY_VERSION: 367 dump_version(); 368 return (-1); 369 case KEY_MAXREAD: 370 res = strtonum(arg, 0, FUSEBUFMAXSIZE, &err); 371 if (err) { 372 fprintf(stderr, "fuse: max_read %s\n", err); 373 return (-1); 374 } 375 max_read = res; 376 break; 377 case FUSE_OPT_KEY_NONOPT: 378 if (opt->mp == NULL) { 379 opt->mp = realpath(arg, opt->mp); 380 if (opt->mp == NULL) { 381 fprintf(stderr, "fuse: realpath: " 382 "%s : %s\n", arg, strerror(errno)); 383 return (-1); 384 } 385 386 res = stat(opt->mp, &st); 387 if (res == -1) { 388 fprintf(stderr, "fuse: bad mount point " 389 "%s : %s\n", arg, strerror(errno)); 390 return (-1); 391 } 392 393 if (!S_ISDIR(st.st_mode)) { 394 fprintf(stderr, "fuse: bad mount point " 395 "%s : %s\n", arg, 396 strerror(ENOTDIR)); 397 return (-1); 398 } 399 } else { 400 fprintf(stderr, "fuse: invalid argument %s\n", 401 arg); 402 return (-1); 403 } 404 break; 405 default: 406 fprintf(stderr, "fuse: unknown option %s\n", arg); 407 return (-1); 408 } 409 return (0); 410 } 411 412 int 413 fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, unused int *fg) 414 { 415 struct fuse_core_opt opt; 416 417 #ifdef DEBUG 418 ifuse_debug_init(); 419 #endif 420 bzero(&opt, sizeof(opt)); 421 if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1) 422 return (-1); 423 424 if (opt.mp == NULL) { 425 fprintf(stderr, "fuse: missing mountpoint parameter\n"); 426 return (-1); 427 } 428 429 if (mp != NULL) { 430 *mp = strdup(opt.mp); 431 if (*mp == NULL) 432 return (-1); 433 } 434 435 if (mt != NULL) 436 *mt = 0; 437 438 return (0); 439 } 440 441 struct fuse_context * 442 fuse_get_context(void) 443 { 444 return (ictx); 445 } 446 447 int 448 fuse_version(void) 449 { 450 return (FUSE_VERSION); 451 } 452 453 void 454 fuse_teardown(struct fuse *fuse, char *mp) 455 { 456 fuse_unmount(mp, fuse->fc); 457 fuse_destroy(fuse); 458 } 459 460 int 461 fuse_invalidate(unused struct fuse *f, unused const char *path) 462 { 463 return (EINVAL); 464 } 465 466 struct fuse * 467 fuse_setup(int argc, char **argv, const struct fuse_operations *ops, 468 size_t size, char **mp, int *mt, void *data) 469 { 470 struct fuse_args args = FUSE_ARGS_INIT(argc, argv); 471 struct fuse_chan *fc; 472 struct fuse *fuse; 473 char *dir; 474 int fg; 475 476 dir = NULL; 477 if (fuse_parse_cmdline(&args, &dir, mt, &fg)) 478 goto err; 479 480 fuse_daemonize(0); 481 482 if ((fc = fuse_mount(dir, NULL)) == NULL) 483 goto err; 484 485 if ((fuse = fuse_new(fc, NULL, ops, size, data)) == NULL) { 486 free(fc); 487 goto err; 488 } 489 490 if (mp != NULL) 491 *mp = dir; 492 493 return (fuse); 494 err: 495 free(dir); 496 return (NULL); 497 } 498 499 int 500 fuse_main(int argc, char **argv, const struct fuse_operations *ops, void *data) 501 { 502 struct fuse *fuse; 503 char *mp = NULL; 504 int mt; 505 506 fuse = fuse_setup(argc, argv, ops, sizeof(*ops), &mp, &mt, data); 507 if (!fuse) 508 return (-1); 509 510 return (fuse_loop(fuse)); 511 } 512