fuse.c (25106B)
1 #include "a.h" 2 3 int fusefd; 4 int fuseeof; 5 int fusebufsize; 6 int fusemaxwrite; 7 FuseMsg *fusemsglist; 8 Lock fusemsglock; 9 10 int mountfuse(char *mtpt); 11 void unmountfuse(char *mtpt); 12 13 FuseMsg* 14 allocfusemsg(void) 15 { 16 FuseMsg *m; 17 void *vbuf; 18 19 lock(&fusemsglock); 20 if((m = fusemsglist) != nil){ 21 fusemsglist = m->next; 22 unlock(&fusemsglock); 23 return m; 24 } 25 unlock(&fusemsglock); 26 m = emalloc(sizeof(*m) + fusebufsize); 27 vbuf = m+1; 28 m->buf = vbuf; 29 m->nbuf = 0; 30 m->hdr = vbuf; 31 m->tx = m->hdr+1; 32 return m; 33 } 34 35 void 36 freefusemsg(FuseMsg *m) 37 { 38 lock(&fusemsglock); 39 m->next = fusemsglist; 40 fusemsglist = m; 41 unlock(&fusemsglock); 42 } 43 44 FuseMsg* 45 readfusemsg(void) 46 { 47 FuseMsg *m; 48 int n, nn; 49 50 m = allocfusemsg(); 51 /* 52 * The FUSE kernel device apparently guarantees 53 * that this read will return exactly one message. 54 * You get an error return if you ask for just the 55 * length (first 4 bytes). 56 * FUSE returns an ENODEV error, not EOF, 57 * when the connection is unmounted. 58 */ 59 do{ 60 errno = 0; 61 n = read(fusefd, m->buf, fusebufsize); 62 }while(n < 0 && errno == EINTR); 63 if(n < 0){ 64 if(errno != ENODEV) 65 sysfatal("readfusemsg: %r"); 66 } 67 if(n <= 0){ 68 fuseeof = 1; 69 freefusemsg(m); 70 return nil; 71 } 72 m->nbuf = n; 73 74 /* 75 * FreeBSD FUSE sends a short length in the header 76 * for FUSE_INIT even though the actual read length 77 * is correct. 78 */ 79 if(n == sizeof(*m->hdr)+sizeof(struct fuse_init_in) 80 && m->hdr->opcode == FUSE_INIT && m->hdr->len < n) 81 m->hdr->len = n; 82 83 if(m->hdr->len != n) 84 sysfatal("readfusemsg: got %d wanted %d", 85 n, m->hdr->len); 86 m->hdr->len -= sizeof(*m->hdr); 87 88 /* 89 * Paranoia. 90 * Make sure lengths are long enough. 91 * Make sure string arguments are NUL terminated. 92 * (I don't trust the kernel module.) 93 */ 94 switch(m->hdr->opcode){ 95 default: 96 /* 97 * Could sysfatal here, but can also let message go 98 * and assume higher-level code will return an 99 * "I don't know what you mean" error and recover. 100 */ 101 break; 102 case FUSE_LOOKUP: 103 case FUSE_UNLINK: 104 case FUSE_RMDIR: 105 case FUSE_REMOVEXATTR: 106 /* just a string */ 107 if(((char*)m->tx)[m->hdr->len-1] != 0) 108 bad: 109 sysfatal("readfusemsg: bad message"); 110 break; 111 case FUSE_FORGET: 112 if(m->hdr->len < sizeof(struct fuse_forget_in)) 113 goto bad; 114 break; 115 case FUSE_GETATTR: 116 break; 117 case FUSE_SETATTR: 118 if(m->hdr->len < sizeof(struct fuse_setattr_in)) 119 goto bad; 120 break; 121 case FUSE_READLINK: 122 break; 123 case FUSE_SYMLINK: 124 /* two strings */ 125 if(((char*)m->tx)[m->hdr->len-1] != 0 126 || memchr(m->tx, 0, m->hdr->len-1) == 0) 127 goto bad; 128 break; 129 case FUSE_MKNOD: 130 if(m->hdr->len <= sizeof(struct fuse_mknod_in) 131 || ((char*)m->tx)[m->hdr->len-1] != 0) 132 goto bad; 133 break; 134 case FUSE_MKDIR: 135 if(m->hdr->len <= sizeof(struct fuse_mkdir_in) 136 || ((char*)m->tx)[m->hdr->len-1] != 0) 137 goto bad; 138 break; 139 case FUSE_RENAME: 140 /* a struct and two strings */ 141 if(m->hdr->len <= sizeof(struct fuse_rename_in) 142 || ((char*)m->tx)[m->hdr->len-1] != 0 143 || memchr((uchar*)m->tx+sizeof(struct fuse_rename_in), 0, m->hdr->len-sizeof(struct fuse_rename_in)-1) == 0) 144 goto bad; 145 break; 146 case FUSE_LINK: 147 if(m->hdr->len <= sizeof(struct fuse_link_in) 148 || ((char*)m->tx)[m->hdr->len-1] != 0) 149 goto bad; 150 break; 151 case FUSE_OPEN: 152 case FUSE_OPENDIR: 153 if(m->hdr->len < sizeof(struct fuse_open_in)) 154 goto bad; 155 break; 156 case FUSE_READ: 157 case FUSE_READDIR: 158 if(m->hdr->len < sizeof(struct fuse_read_in)) 159 goto bad; 160 break; 161 case FUSE_WRITE: 162 /* no strings, but check that write length is sane */ 163 if(m->hdr->len < sizeof(struct fuse_write_in)+((struct fuse_write_in*)m->tx)->size) 164 goto bad; 165 break; 166 case FUSE_STATFS: 167 break; 168 case FUSE_RELEASE: 169 case FUSE_RELEASEDIR: 170 if(m->hdr->len < sizeof(struct fuse_release_in)) 171 goto bad; 172 break; 173 case FUSE_FSYNC: 174 case FUSE_FSYNCDIR: 175 if(m->hdr->len < sizeof(struct fuse_fsync_in)) 176 goto bad; 177 break; 178 case FUSE_SETXATTR: 179 /* struct, one string, and one binary blob */ 180 if(m->hdr->len <= sizeof(struct fuse_setxattr_in)) 181 goto bad; 182 nn = ((struct fuse_setxattr_in*)m->tx)->size; 183 if(m->hdr->len < sizeof(struct fuse_setxattr_in)+nn+1) 184 goto bad; 185 if(((char*)m->tx)[m->hdr->len-nn-1] != 0) 186 goto bad; 187 break; 188 case FUSE_GETXATTR: 189 /* struct and one string */ 190 if(m->hdr->len <= sizeof(struct fuse_getxattr_in) 191 || ((char*)m->tx)[m->hdr->len-1] != 0) 192 goto bad; 193 break; 194 case FUSE_LISTXATTR: 195 if(m->hdr->len < sizeof(struct fuse_getxattr_in)) 196 goto bad; 197 break; 198 case FUSE_FLUSH: 199 if(m->hdr->len < sizeof(struct fuse_flush_in)) 200 goto bad; 201 break; 202 case FUSE_INIT: 203 if(m->hdr->len < sizeof(struct fuse_init_in)) 204 goto bad; 205 break; 206 case FUSE_ACCESS: 207 if(m->hdr->len < sizeof(struct fuse_access_in)) 208 goto bad; 209 break; 210 case FUSE_CREATE: 211 if(m->hdr->len <= sizeof(struct fuse_open_in) 212 || ((char*)m->tx)[m->hdr->len-1] != 0) 213 goto bad; 214 break; 215 } 216 if(debug) 217 fprint(2, "FUSE -> %G\n", m->hdr, m->tx); 218 return m; 219 } 220 221 /* 222 * Reply to FUSE request m using additonal 223 * argument buffer arg of size narg bytes. 224 * Perhaps should free the FuseMsg here? 225 */ 226 void 227 replyfuse(FuseMsg *m, void *arg, int narg) 228 { 229 struct iovec vec[2]; 230 struct fuse_out_header hdr; 231 int nvec; 232 233 hdr.len = sizeof hdr + narg; 234 hdr.error = 0; 235 hdr.unique = m->hdr->unique; 236 if(debug) 237 fprint(2, "FUSE <- %#G\n", m->hdr, &hdr, arg); 238 239 vec[0].iov_base = &hdr; 240 vec[0].iov_len = sizeof hdr; 241 nvec = 1; 242 if(arg && narg){ 243 vec[1].iov_base = arg; 244 vec[1].iov_len = narg; 245 nvec++; 246 } 247 writev(fusefd, vec, nvec); 248 freefusemsg(m); 249 } 250 251 /* 252 * Reply to FUSE request m with errno e. 253 */ 254 void 255 replyfuseerrno(FuseMsg *m, int e) 256 { 257 struct fuse_out_header hdr; 258 259 hdr.len = sizeof hdr; 260 hdr.error = -e; /* FUSE sends negative errnos. */ 261 hdr.unique = m->hdr->unique; 262 if(debug) 263 fprint(2, "FUSE <- %#G\n", m->hdr, &hdr, 0); 264 write(fusefd, &hdr, sizeof hdr); 265 freefusemsg(m); 266 } 267 268 void 269 replyfuseerrstr(FuseMsg *m) 270 { 271 replyfuseerrno(m, errstr2errno()); 272 } 273 274 char *fusemtpt; 275 void 276 unmountatexit(void) 277 { 278 if(fusemtpt) 279 unmountfuse(fusemtpt); 280 } 281 282 void 283 initfuse(char *mtpt) 284 { 285 FuseMsg *m; 286 struct fuse_init_in *tx; 287 struct fuse_init_out rx; 288 289 fusemtpt = mtpt; 290 291 /* 292 * The 4096 is for the message headers. 293 * It's a lot, but it's what the FUSE libraries ask for. 294 */ 295 fusemaxwrite = getpagesize(); 296 fusebufsize = 4096 + fusemaxwrite; 297 298 if((fusefd = mountfuse(mtpt)) < 0) 299 sysfatal("mountfuse: %r"); 300 301 if((m = readfusemsg()) == nil) 302 sysfatal("readfusemsg: %r"); 303 if(m->hdr->opcode != FUSE_INIT) 304 sysfatal("fuse: expected FUSE_INIT (26) got %d", m->hdr->opcode); 305 tx = m->tx; 306 307 /* 308 * Complain if the kernel is too new. 309 * We could forge ahead, but at least the one time I tried, 310 * the kernel rejected the newer version by making the 311 * writev fail in replyfuse, which is a much more confusing 312 * error message. In the future, might be nice to try to 313 * support older versions that differ only slightly. 314 */ 315 if(tx->major < FUSE_KERNEL_VERSION 316 || (tx->major == FUSE_KERNEL_VERSION && tx->minor < FUSE_KERNEL_MINOR_VERSION)) 317 sysfatal("fuse: too kernel version %d.%d older than program version %d.%d", 318 tx->major, tx->minor, FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); 319 320 memset(&rx, 0, sizeof rx); 321 rx.major = FUSE_KERNEL_VERSION; 322 rx.minor = FUSE_KERNEL_MINOR_VERSION; 323 rx.max_write = fusemaxwrite; 324 replyfuse(m, &rx, sizeof rx); 325 } 326 327 /* 328 * Print FUSE messages. Assuming it is installed as %G, 329 * use %G with hdr, arg arguments to format a request, 330 * and %#G with reqhdr, hdr, arg arguments to format a response. 331 * The reqhdr is necessary in the %#G form because the 332 * response does not contain an opcode tag. 333 */ 334 int 335 fusefmt(Fmt *fmt) 336 { 337 struct fuse_in_header *hdr = va_arg(fmt->args, void*); 338 if((fmt->flags&FmtSharp) == 0){ /* "%G", hdr, arg */ 339 void *a = va_arg(fmt->args, void*); 340 fmtprint(fmt, "len %d unique %#llux uid %d gid %d pid %d ", 341 hdr->len, hdr->unique, hdr->uid, hdr->gid, hdr->pid); 342 343 switch(hdr->opcode){ 344 default: { 345 fmtprint(fmt, "??? opcode %d", hdr->opcode); 346 break; 347 } 348 case FUSE_LOOKUP: { 349 fmtprint(fmt, "Lookup nodeid %#llux name %#q", 350 hdr->nodeid, a); 351 break; 352 } 353 case FUSE_FORGET: { 354 struct fuse_forget_in *tx = a; 355 /* nlookup (a ref count) is a vlong! */ 356 fmtprint(fmt, "Forget nodeid %#llux nlookup %lld", 357 hdr->nodeid, tx->nlookup); 358 break; 359 } 360 case FUSE_GETATTR: { 361 fmtprint(fmt, "Getattr nodeid %#llux", hdr->nodeid); 362 break; 363 } 364 case FUSE_SETATTR: { 365 struct fuse_setattr_in *tx = a; 366 fmtprint(fmt, "Setattr nodeid %#llux", hdr->nodeid); 367 if(tx->valid&FATTR_FH) 368 fmtprint(fmt, " fh %#llux", tx->fh); 369 if(tx->valid&FATTR_SIZE) 370 fmtprint(fmt, " size %lld", tx->size); 371 if(tx->valid&FATTR_ATIME) 372 fmtprint(fmt, " atime %.20g", tx->atime+tx->atimensec*1e-9); 373 if(tx->valid&FATTR_MTIME) 374 fmtprint(fmt, " mtime %.20g", tx->mtime+tx->mtimensec*1e-9); 375 if(tx->valid&FATTR_MODE) 376 fmtprint(fmt, " mode %#uo", tx->mode); 377 if(tx->valid&FATTR_UID) 378 fmtprint(fmt, " uid %d", tx->uid); 379 if(tx->valid&FATTR_GID) 380 fmtprint(fmt, " gid %d", tx->gid); 381 break; 382 } 383 case FUSE_READLINK: { 384 fmtprint(fmt, "Readlink nodeid %#llux", hdr->nodeid); 385 break; 386 } 387 case FUSE_SYMLINK: { 388 char *old, *new; 389 390 old = a; 391 new = a + strlen(a) + 1; 392 fmtprint(fmt, "Symlink nodeid %#llux old %#q new %#q", 393 hdr->nodeid, old, new); 394 break; 395 } 396 case FUSE_MKNOD: { 397 struct fuse_mknod_in *tx = a; 398 fmtprint(fmt, "Mknod nodeid %#llux mode %#uo rdev %#ux name %#q", 399 hdr->nodeid, tx->mode, tx->rdev, tx+1); 400 break; 401 } 402 case FUSE_MKDIR: { 403 struct fuse_mkdir_in *tx = a; 404 fmtprint(fmt, "Mkdir nodeid %#llux mode %#uo name %#q", 405 hdr->nodeid, tx->mode, tx+1); 406 break; 407 } 408 case FUSE_UNLINK: { 409 fmtprint(fmt, "Unlink nodeid %#llux name %#q", 410 hdr->nodeid, a); 411 break; 412 } 413 case FUSE_RMDIR: { 414 fmtprint(fmt, "Rmdir nodeid %#llux name %#q", 415 hdr->nodeid, a); 416 break; 417 } 418 case FUSE_RENAME: { 419 struct fuse_rename_in *tx = a; 420 char *old = (char*)(tx+1); 421 char *new = old + strlen(old) + 1; 422 fmtprint(fmt, "Rename nodeid %#llux old %#q newdir %#llux new %#q", 423 hdr->nodeid, old, tx->newdir, new); 424 break; 425 } 426 case FUSE_LINK: { 427 struct fuse_link_in *tx = a; 428 fmtprint(fmt, "Link oldnodeid %#llux nodeid %#llux name %#q", 429 tx->oldnodeid, hdr->nodeid, tx+1); 430 break; 431 } 432 case FUSE_OPEN: { 433 struct fuse_open_in *tx = a; 434 /* Should one or both of flags and mode be octal? */ 435 fmtprint(fmt, "Open nodeid %#llux flags %#ux mode %#ux", 436 hdr->nodeid, tx->flags, tx->mode); 437 break; 438 } 439 case FUSE_READ: { 440 struct fuse_read_in *tx = a; 441 fmtprint(fmt, "Read nodeid %#llux fh %#llux offset %lld size %ud", 442 hdr->nodeid, tx->fh, tx->offset, tx->size); 443 break; 444 } 445 case FUSE_WRITE: { 446 struct fuse_write_in *tx = a; 447 fmtprint(fmt, "Write nodeid %#llux fh %#llux offset %lld size %ud flags %#ux", 448 hdr->nodeid, tx->fh, tx->offset, tx->size, tx->write_flags); 449 break; 450 } 451 case FUSE_STATFS: { 452 fmtprint(fmt, "Statfs"); 453 break; 454 } 455 case FUSE_RELEASE: { 456 struct fuse_release_in *tx = a; 457 fmtprint(fmt, "Release nodeid %#llux fh %#llux flags %#ux", 458 hdr->nodeid, tx->fh, tx->flags); 459 break; 460 } 461 case FUSE_FSYNC: { 462 struct fuse_fsync_in *tx = a; 463 fmtprint(fmt, "Fsync nodeid %#llux fh %#llux flags %#ux", 464 hdr->nodeid, tx->fh, tx->fsync_flags); 465 break; 466 } 467 case FUSE_SETXATTR: { 468 struct fuse_setxattr_in *tx = a; 469 char *name = (char*)(tx+1); 470 char *value = name + strlen(name) + 1; 471 fmtprint(fmt, "Setxattr nodeid %#llux size %d flags %#ux name %#q value %#q", 472 hdr->nodeid, tx->size, tx->flags, name, value); 473 break; 474 } 475 case FUSE_GETXATTR: { 476 struct fuse_getxattr_in *tx = a; 477 fmtprint(fmt, "Getxattr nodeid %#llux size %d name %#q", 478 hdr->nodeid, tx->size, tx+1); 479 break; 480 } 481 case FUSE_LISTXATTR: { 482 struct fuse_getxattr_in *tx = a; 483 fmtprint(fmt, "Listxattr nodeid %#llux size %d", 484 hdr->nodeid, tx->size); 485 break; 486 } 487 case FUSE_REMOVEXATTR: { 488 fmtprint(fmt, "Removexattr nodeid %#llux name %#q", 489 hdr->nodeid, a); 490 break; 491 } 492 case FUSE_FLUSH: { 493 struct fuse_flush_in *tx = a; 494 fmtprint(fmt, "Flush nodeid %#llux fh %#llux flags %#ux", 495 hdr->nodeid, tx->fh, tx->flush_flags); 496 break; 497 } 498 case FUSE_INIT: { 499 struct fuse_init_in *tx = a; 500 fmtprint(fmt, "Init major %d minor %d", 501 tx->major, tx->minor); 502 break; 503 } 504 case FUSE_OPENDIR: { 505 struct fuse_open_in *tx = a; 506 fmtprint(fmt, "Opendir nodeid %#llux flags %#ux mode %#ux", 507 hdr->nodeid, tx->flags, tx->mode); 508 break; 509 } 510 case FUSE_READDIR: { 511 struct fuse_read_in *tx = a; 512 fmtprint(fmt, "Readdir nodeid %#llux fh %#llux offset %lld size %ud", 513 hdr->nodeid, tx->fh, tx->offset, tx->size); 514 break; 515 } 516 case FUSE_RELEASEDIR: { 517 struct fuse_release_in *tx = a; 518 fmtprint(fmt, "Releasedir nodeid %#llux fh %#llux flags %#ux", 519 hdr->nodeid, tx->fh, tx->flags); 520 break; 521 } 522 case FUSE_FSYNCDIR: { 523 struct fuse_fsync_in *tx = a; 524 fmtprint(fmt, "Fsyncdir nodeid %#llux fh %#llux flags %#ux", 525 hdr->nodeid, tx->fh, tx->fsync_flags); 526 break; 527 } 528 case FUSE_ACCESS: { 529 struct fuse_access_in *tx = a; 530 fmtprint(fmt, "Access nodeid %#llux mask %#ux", 531 hdr->nodeid, tx->mask); 532 break; 533 } 534 case FUSE_CREATE: { 535 struct fuse_open_in *tx = a; 536 fmtprint(fmt, "Create nodeid %#llx flags %#ux mode %#ux name %#q", 537 hdr->nodeid, tx->flags, tx->mode, tx+1); 538 break; 539 } 540 } 541 }else{ /* "%#G", reqhdr, hdr, arg - use reqhdr only for type */ 542 struct fuse_out_header *ohdr = va_arg(fmt->args, void*); 543 void *a = va_arg(fmt->args, void*); 544 int len = ohdr->len - sizeof *ohdr; 545 fmtprint(fmt, "unique %#llux ", ohdr->unique); 546 if(ohdr->error){ 547 fmtprint(fmt, "error %d %s", ohdr->error, strerror(-ohdr->error)); 548 }else 549 switch(hdr->opcode){ 550 default: { 551 fmtprint(fmt, "??? opcode %d", hdr->opcode); 552 break; 553 } 554 case FUSE_LOOKUP: { 555 /* 556 * For a negative entry, can send back ENOENT 557 * or rx->ino == 0. 558 * In protocol version 7.4 and before, can only use 559 * the ENOENT method. 560 * Presumably the benefit of sending rx->ino == 0 561 * is that you can specify the length of time to cache 562 * the negative result. 563 */ 564 struct fuse_entry_out *rx; 565 fmtprint(fmt, "(Lookup) "); 566 fmt_entry_out: 567 rx = a; 568 fmtprint(fmt, "nodeid %#llux gen %#llux entry_valid %.20g attr_valid %.20g ", 569 rx->nodeid, rx->generation, 570 rx->entry_valid+rx->entry_valid_nsec*1e-9, 571 rx->attr_valid+rx->attr_valid_nsec*1e-9); 572 fmtprint(fmt, " ino %#llux size %lld blocks %lld atime %.20g mtime %.20g ctime %.20g mode %#uo nlink %d uid %d gid %d rdev %#ux", 573 rx->attr.ino, rx->attr.size, rx->attr.blocks, 574 rx->attr.atime+rx->attr.atimensec*1e-9, 575 rx->attr.mtime+rx->attr.mtimensec*1e-9, 576 rx->attr.ctime+rx->attr.ctimensec*1e-9, 577 rx->attr.mode, rx->attr.nlink, rx->attr.uid, 578 rx->attr.gid, rx->attr.rdev); 579 break; 580 } 581 case FUSE_FORGET: { 582 /* Can't happen! No reply. */ 583 fmtprint(fmt, "(Forget) can't happen"); 584 break; 585 } 586 case FUSE_GETATTR: { 587 struct fuse_attr_out *rx; 588 fmtprint(fmt, "(Getattr) "); 589 fmt_attr_out: 590 rx = a; 591 fmtprint(fmt, "attr_valid %.20g", 592 rx->attr_valid+rx->attr_valid_nsec*1e-9); 593 fmtprint(fmt, " ino %#llux size %lld blocks %lld atime %.20g mtime %.20g ctime %.20g mode %#uo nlink %d uid %d gid %d rdev %#ux", 594 rx->attr.ino, rx->attr.size, rx->attr.blocks, 595 rx->attr.atime+rx->attr.atimensec*1e-9, 596 rx->attr.mtime+rx->attr.mtimensec*1e-9, 597 rx->attr.ctime+rx->attr.ctimensec*1e-9, 598 rx->attr.mode, rx->attr.nlink, rx->attr.uid, 599 rx->attr.gid, rx->attr.rdev); 600 break; 601 } 602 case FUSE_SETATTR: { 603 fmtprint(fmt, "(Setattr) "); 604 goto fmt_attr_out; 605 break; 606 } 607 case FUSE_READLINK: { 608 fmtprint(fmt, "(Readlink) %#.*q", 609 utfnlen(a, len), a); 610 break; 611 } 612 case FUSE_SYMLINK: { 613 fmtprint(fmt, "(Symlink) "); 614 goto fmt_entry_out; 615 break; 616 } 617 case FUSE_MKNOD: { 618 fmtprint(fmt, "(Mknod) "); 619 goto fmt_entry_out; 620 break; 621 } 622 case FUSE_MKDIR: { 623 fmtprint(fmt, "(Mkdir) "); 624 goto fmt_entry_out; 625 break; 626 } 627 case FUSE_UNLINK: { 628 fmtprint(fmt, "(Unlink)"); 629 break; 630 } 631 case FUSE_RMDIR: { 632 fmtprint(fmt, "(Rmdir)"); 633 break; 634 } 635 case FUSE_RENAME: { 636 fmtprint(fmt, "(Rename)"); 637 break; 638 } 639 case FUSE_LINK: { 640 fmtprint(fmt, "(Link) "); 641 goto fmt_entry_out; 642 break; 643 } 644 case FUSE_OPEN: { 645 struct fuse_open_out *rx; 646 fmtprint(fmt, "(Open) "); 647 fmt_open_out: 648 rx = a; 649 fmtprint(fmt, "fh %#llux flags %#ux", rx->fh, rx->open_flags); 650 break; 651 } 652 case FUSE_READ: { 653 fmtprint(fmt, "(Read) size %d", len); 654 break; 655 } 656 case FUSE_WRITE: { 657 struct fuse_write_out *rx = a; 658 fmtprint(fmt, "(Write) size %d", rx->size); 659 break; 660 } 661 case FUSE_STATFS: { 662 /* 663 * Before protocol version 7.4, only first 48 bytes are used. 664 */ 665 struct fuse_statfs_out *rx = a; 666 fmtprint(fmt, "(Statfs) blocks %lld bfree %lld bavail %lld files %lld ffree %lld bsize %ud namelen %ud frsize %ud", 667 rx->st.blocks, rx->st.bfree, rx->st.bavail, 668 rx->st.files, rx->st.ffree, rx->st.bsize, 669 rx->st.namelen, rx->st.frsize); 670 break; 671 } 672 case FUSE_RELEASE: { 673 fmtprint(fmt, "(Release)"); 674 break; 675 } 676 case FUSE_FSYNC: { 677 fmtprint(fmt, "(Fsync)"); 678 break; 679 } 680 case FUSE_SETXATTR: { 681 fmtprint(fmt, "(Setxattr)"); 682 break; 683 } 684 case FUSE_GETXATTR: { 685 fmtprint(fmt, "(Getxattr) size %d", len); 686 break; 687 } 688 case FUSE_LISTXATTR: { 689 fmtprint(fmt, "(Lisrxattr) size %d", len); 690 break; 691 } 692 case FUSE_REMOVEXATTR: { 693 fmtprint(fmt, "(Removexattr)"); 694 break; 695 } 696 case FUSE_FLUSH: { 697 fmtprint(fmt, "(Flush)"); 698 break; 699 } 700 case FUSE_INIT: { 701 struct fuse_init_out *rx = a; 702 fmtprint(fmt, "(Init) major %d minor %d max_write %d", 703 rx->major, rx->minor, rx->max_write); 704 break; 705 } 706 case FUSE_OPENDIR: { 707 fmtprint(fmt, "(Opendir) "); 708 goto fmt_open_out; 709 break; 710 } 711 case FUSE_READDIR: { 712 fmtprint(fmt, "(Readdir) size %d", len); 713 break; 714 } 715 case FUSE_RELEASEDIR: { 716 fmtprint(fmt, "(Releasedir)"); 717 break; 718 } 719 case FUSE_FSYNCDIR: { 720 fmtprint(fmt, "(Fsyncdir)"); 721 break; 722 } 723 case FUSE_ACCESS: { 724 fmtprint(fmt, "(Access)"); 725 break; 726 } 727 case FUSE_CREATE: { 728 struct fuse_create_out *rx = a; 729 fmtprint(fmt, "(Create) "); 730 fmtprint(fmt, "nodeid %#llux gen %#llux entry_valid %.20g attr_valid %.20g ", 731 rx->e.nodeid, rx->e.generation, 732 rx->e.entry_valid+rx->e.entry_valid_nsec*1e-9, 733 rx->e.attr_valid+rx->e.attr_valid_nsec*1e-9); 734 fmtprint(fmt, " ino %#llux size %lld blocks %lld atime %.20g mtime %.20g ctime %.20g mode %#uo nlink %d uid %d gid %d rdev %#ux", 735 rx->e.attr.ino, rx->e.attr.size, rx->e.attr.blocks, 736 rx->e.attr.atime+rx->e.attr.atimensec*1e-9, 737 rx->e.attr.mtime+rx->e.attr.mtimensec*1e-9, 738 rx->e.attr.ctime+rx->e.attr.ctimensec*1e-9, 739 rx->e.attr.mode, rx->e.attr.nlink, rx->e.attr.uid, 740 rx->e.attr.gid, rx->e.attr.rdev); 741 fmtprint(fmt, " fh %#llux flags %#ux", rx->o.fh, rx->o.open_flags); 742 break; 743 } 744 } 745 } 746 return 0; 747 } 748 749 #if defined(__APPLE__) 750 #include <sys/param.h> 751 #include <sys/mount.h> 752 #endif 753 754 /* 755 * Mounts a fuse file system on mtpt and returns 756 * a file descriptor for the corresponding fuse 757 * message conversation. 758 */ 759 int 760 mountfuse(char *mtpt) 761 { 762 #if defined(__linux__) 763 int p[2], pid, fd; 764 char buf[20]; 765 766 if(socketpair(AF_UNIX, SOCK_STREAM, 0, p) < 0) 767 return -1; 768 pid = fork(); 769 if(pid < 0) 770 return -1; 771 if(pid == 0){ 772 close(p[1]); 773 snprint(buf, sizeof buf, "%d", p[0]); 774 putenv("_FUSE_COMMFD", buf); 775 execlp("fusermount", "fusermount", "--", mtpt, nil); 776 fprint(2, "exec fusermount: %r\n"); 777 _exit(1); 778 } 779 close(p[0]); 780 fd = recvfd(p[1]); 781 close(p[1]); 782 return fd; 783 #elif defined(__FreeBSD__) && !defined(__APPLE__) 784 int pid, fd; 785 char buf[20]; 786 787 if((fd = open("/dev/fuse", ORDWR)) < 0) 788 return -1; 789 snprint(buf, sizeof buf, "%d", fd); 790 791 pid = fork(); 792 if(pid < 0) 793 return -1; 794 if(pid == 0){ 795 execlp("mount_fusefs", "mount_fusefs", buf, mtpt, nil); 796 fprint(2, "exec mount_fusefs: %r\n"); 797 _exit(1); 798 } 799 return fd; 800 #elif defined(__APPLE__) 801 int i, pid, fd, r, p[2]; 802 char buf[20]; 803 struct vfsconf vfs; 804 char *f, *v; 805 806 if(getvfsbyname(v="osxfusefs", &vfs) < 0 && 807 getvfsbyname(v="macfuse", &vfs) < 0 && 808 getvfsbyname(v="osxfuse", &vfs) < 0 && 809 getvfsbyname(v="fusefs", &vfs) < 0){ 810 if(access((v="osxfusefs", f="/Library/Filesystems/osxfusefs.fs" 811 "/Support/load_osxfusefs"), 0) < 0 && 812 access((v="macfuse", f="/Library/Filesystems/macfuse.fs" 813 "/Contents/Resources/load_macfuse"), 0) < 0 && 814 access((v="osxfuse", f="/Library/Filesystems/osxfuse.fs" 815 "/Contents/Resources/load_osxfuse"), 0) < 0 && 816 access((v="osxfuse", f="/opt/local/Library/Filesystems/osxfuse.fs" 817 "/Contents/Resources/load_osxfuse"), 0) < 0 && 818 access((v="fusefs", f="/System/Library/Extensions/fusefs.kext" 819 "/Contents/Resources/load_fusefs"), 0) < 0 && 820 access(f="/Library/Extensions/fusefs.kext" 821 "/Contents/Resources/load_fusefs", 0) < 0 && 822 access(f="/Library/Filesystems" 823 "/fusefs.fs/Support/load_fusefs", 0) < 0 && 824 access(f="/System/Library/Filesystems" 825 "/fusefs.fs/Support/load_fusefs", 0) < 0){ 826 werrstr("cannot find load_fusefs"); 827 return -1; 828 } 829 if((r=system(f)) < 0){ 830 werrstr("%s: %r", f); 831 return -1; 832 } 833 if(r != 0){ 834 werrstr("load_fusefs failed: exit %d", r); 835 return -1; 836 } 837 if(getvfsbyname(v, &vfs) < 0){ 838 werrstr("getvfsbyname %s: %r", v); 839 return -1; 840 } 841 } 842 843 /* MacFUSE >=4 dropped support for passing fd */ 844 if (strcmp(v, "macfuse") == 0) { 845 if(socketpair(AF_UNIX, SOCK_STREAM, 0, p) < 0) 846 return -1; 847 pid = fork(); 848 if(pid < 0) 849 return -1; 850 if(pid == 0){ 851 close(p[1]); 852 snprint(buf, sizeof buf, "%d", p[0]); 853 putenv("_FUSE_COMMFD", buf); 854 putenv("_FUSE_COMMVERS", "2"); 855 putenv("_FUSE_CALL_BY_LIB", "1"); 856 putenv("_FUSE_DAEMON_PATH", 857 "/Library/Filesystems/macfuse.fs/Contents/Resources/mount_macfus"); 858 execl("/Library/Filesystems/macfuse.fs/Contents/Resources/mount_macfuse", 859 "mount_macfuse", mtpt, nil); 860 fprint(2, "exec mount_macfuse: %r\n"); 861 _exit(1); 862 } 863 close(p[0]); 864 fd = recvfd(p[1]); 865 close(p[1]); 866 return fd; 867 } 868 869 /* Look for available FUSE device. */ 870 /* 871 * We need to truncate `fs` from the end of the vfs name if 872 * it's present 873 */ 874 int len; 875 if (strcmp(v, "osxfuse") == 0) { 876 len = strlen(v); 877 } else { 878 len = strlen(v)-2; 879 } 880 for(i=0;; i++){ 881 snprint(buf, sizeof buf, "/dev/%.*s%d", len, v, i); 882 if(access(buf, 0) < 0){ 883 werrstr("no available fuse devices"); 884 return -1; 885 } 886 if((fd = open(buf, ORDWR)) >= 0) 887 break; 888 } 889 890 pid = fork(); 891 if(pid < 0) 892 return -1; 893 if(pid == 0){ 894 snprint(buf, sizeof buf, "%d", fd); 895 /* OSXFUSE >=3.3 changed the name of the environment variable, set both */ 896 putenv("MOUNT_FUSEFS_CALL_BY_LIB", ""); 897 putenv("MOUNT_OSXFUSE_CALL_BY_LIB", ""); 898 /* 899 * Different versions of OSXFUSE and MacFUSE put the 900 * mount_fusefs binary in different places. Try all. 901 */ 902 /* OSXFUSE >=3.3 greater location */ 903 putenv("MOUNT_OSXFUSE_DAEMON_PATH", 904 "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse"); 905 execl("/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse", 906 "mount_osxfuse", buf, mtpt, nil); 907 908 /* OSXFUSE >=3.3 from macports */ 909 putenv("MOUNT_OSXFUSE_DAEMON_PATH", 910 "/opt/local/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse"); 911 execl("/opt/local/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse", 912 "mount_osxfuse", buf, mtpt, nil); 913 914 /* Lion OSXFUSE location */ 915 putenv("MOUNT_FUSEFS_DAEMON_PATH", 916 "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"); 917 execl("/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs", 918 "mount_osxfusefs", buf, mtpt, nil); 919 920 /* Leopard location */ 921 putenv("MOUNT_FUSEFS_DAEMON_PATH", 922 "/Library/Filesystems/fusefs.fs/Support/mount_fusefs"); 923 execl("/Library/Filesystems/fusefs.fs/Support/mount_fusefs", 924 "mount_fusefs", buf, mtpt, nil); 925 926 /* possible Tiger locations */ 927 execl("/System/Library/Filesystems/fusefs.fs/mount_fusefs", 928 "mount_fusefs", buf, mtpt, nil); 929 execl("/System/Library/Filesystems/fusefs.fs/Support/mount_fusefs", 930 "mount_fusefs", buf, mtpt, nil); 931 fprint(2, "exec mount_fusefs: %r\n"); 932 _exit(1); 933 } 934 return fd; 935 936 #else 937 werrstr("cannot mount fuse on this system"); 938 return -1; 939 #endif 940 } 941 942 void 943 waitfuse(void) 944 { 945 waitpid(); 946 } 947 948 void 949 unmountfuse(char *mtpt) 950 { 951 int pid; 952 953 pid = fork(); 954 if(pid < 0) 955 return; 956 if(pid == 0){ 957 #if defined(__linux__) 958 execlp("fusermount", "fusermount", "-u", "-z", "--", mtpt, nil); 959 fprint(2, "exec fusermount -u: %r\n"); 960 #else 961 execlp("umount", "umount", mtpt, nil); 962 fprint(2, "exec umount: %r\n"); 963 #endif 964 _exit(1); 965 } 966 waitpid(); 967 }