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