1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #define Extern extern 6 #include "exportfs.h" 7 8 char *e[] = 9 { 10 [Ebadfid] "Bad fid", 11 [Enotdir] "Not a directory", 12 [Edupfid] "Fid already in use", 13 [Eopen] "Fid already opened", 14 [Exmnt] "Cannot .. past mount point", 15 [Enoauth] "Authentication failed", 16 [Emip] "Mount in progress", 17 [Enopsmt] "Out of pseudo mount points", 18 }; 19 20 void 21 Xnop(Fsrpc *r) 22 { 23 Fcall thdr; 24 25 reply(&r->work, &thdr, 0); 26 r->busy = 0; 27 } 28 29 void 30 Xsession(Fsrpc *r) 31 { 32 Fcall thdr; 33 34 memset(thdr.authid, 0, sizeof(thdr.authid)); 35 memset(thdr.authdom, 0, sizeof(thdr.authdom)); 36 memset(thdr.chal, 0, sizeof(thdr.chal)); 37 reply(&r->work, &thdr, 0); 38 r->busy = 0; 39 } 40 41 void 42 Xflush(Fsrpc *r) 43 { 44 Fsrpc *t, *e; 45 Fcall thdr; 46 47 e = &Workq[Nr_workbufs]; 48 49 for(t = Workq; t < e; t++) { 50 if(t->work.tag == r->work.oldtag) { 51 DEBUG(2, "\tQ busy %d pid %d can %d\n", t->busy, t->pid, t->canint); 52 if(t->busy && t->pid) { 53 t->flushtag = r->work.tag; 54 DEBUG(2, "\tset flushtag %d\n", r->work.tag); 55 if(t->canint) 56 postnote(PNPROC, t->pid, "flush"); 57 r->busy = 0; 58 return; 59 } 60 } 61 } 62 63 reply(&r->work, &thdr, 0); 64 DEBUG(2, "\tflush reply\n"); 65 r->busy = 0; 66 } 67 68 void 69 Xattach(Fsrpc *r) 70 { 71 Fcall thdr; 72 Fid *f; 73 74 f = newfid(r->work.fid); 75 if(f == 0) { 76 reply(&r->work, &thdr, e[Ebadfid]); 77 r->busy = 0; 78 return; 79 } 80 81 f->f = root; 82 thdr.qid = f->f->qid; 83 reply(&r->work, &thdr, 0); 84 r->busy = 0; 85 } 86 87 void 88 Xclone(Fsrpc *r) 89 { 90 Fcall thdr; 91 Fid *f, *n; 92 93 f = getfid(r->work.fid); 94 if(f == 0) { 95 reply(&r->work, &thdr, e[Ebadfid]); 96 r->busy = 0; 97 return; 98 } 99 n = newfid(r->work.newfid); 100 if(n == 0) { 101 n = getfid(r->work.newfid); 102 if(n == 0) 103 fatal("inconsistent fids"); 104 if(n->fid >= 0) 105 close(n->fid); 106 freefid(r->work.newfid); 107 n = newfid(r->work.newfid); 108 if(n == 0) 109 fatal("inconsistent fids2"); 110 } 111 n->f = f->f; 112 reply(&r->work, &thdr, 0); 113 r->busy = 0; 114 } 115 116 void 117 Xwalk(Fsrpc *r) 118 { 119 char err[ERRLEN]; 120 Fcall thdr; 121 Fid *f; 122 File *nf; 123 124 f = getfid(r->work.fid); 125 if(f == 0) { 126 reply(&r->work, &thdr, e[Ebadfid]); 127 r->busy = 0; 128 return; 129 } 130 131 if(strcmp(r->work.name, "..") == 0) { 132 if(f->f->parent == 0) { 133 reply(&r->work, &thdr, e[Exmnt]); 134 r->busy = 0; 135 return; 136 } 137 f->f = f->f->parent; 138 thdr.qid = f->f->qid; 139 reply(&r->work, &thdr, 0); 140 r->busy = 0; 141 return; 142 } 143 144 nf = file(f->f, r->work.name); 145 if(nf == 0) { 146 errstr(err); 147 reply(&r->work, &thdr, err); 148 r->busy = 0; 149 return; 150 } 151 152 f->f = nf; 153 thdr.qid = nf->qid; 154 reply(&r->work, &thdr, 0); 155 r->busy = 0; 156 } 157 158 void 159 Xclunk(Fsrpc *r) 160 { 161 Fcall thdr; 162 Fid *f; 163 164 f = getfid(r->work.fid); 165 if(f == 0) { 166 reply(&r->work, &thdr, e[Ebadfid]); 167 r->busy = 0; 168 return; 169 } 170 171 if(f->fid >= 0) 172 close(f->fid); 173 174 freefid(r->work.fid); 175 reply(&r->work, &thdr, 0); 176 r->busy = 0; 177 } 178 179 void 180 Xstat(Fsrpc *r) 181 { 182 char err[ERRLEN], path[128]; 183 Fcall thdr; 184 Fid *f; 185 int s; 186 187 f = getfid(r->work.fid); 188 if(f == 0) { 189 reply(&r->work, &thdr, e[Ebadfid]); 190 r->busy = 0; 191 return; 192 } 193 if(f->fid >= 0) 194 s = fstat(f->fid, thdr.stat); 195 else { 196 makepath(path, f->f, ""); 197 s = stat(path, thdr.stat); 198 } 199 200 if(s < 0) { 201 errstr(err); 202 reply(&r->work, &thdr, err); 203 r->busy = 0; 204 return; 205 } 206 reply(&r->work, &thdr, 0); 207 r->busy = 0; 208 } 209 210 void 211 Xcreate(Fsrpc *r) 212 { 213 char err[ERRLEN], path[128]; 214 Fcall thdr; 215 Fid *f; 216 File *nf; 217 218 f = getfid(r->work.fid); 219 if(f == 0) { 220 reply(&r->work, &thdr, e[Ebadfid]); 221 r->busy = 0; 222 return; 223 } 224 225 226 makepath(path, f->f, r->work.name); 227 f->fid = create(path, r->work.mode, r->work.perm); 228 if(f->fid < 0) { 229 errstr(err); 230 reply(&r->work, &thdr, err); 231 r->busy = 0; 232 return; 233 } 234 235 nf = file(f->f, r->work.name); 236 if(nf == 0) { 237 errstr(err); 238 reply(&r->work, &thdr, err); 239 r->busy = 0; 240 return; 241 } 242 243 f->mode = r->work.mode; 244 f->f = nf; 245 f->offset = 0; 246 thdr.qid = f->f->qid; 247 reply(&r->work, &thdr, 0); 248 r->busy = 0; 249 } 250 251 252 void 253 Xremove(Fsrpc *r) 254 { 255 char err[ERRLEN], path[128]; 256 Fcall thdr; 257 Fid *f; 258 259 f = getfid(r->work.fid); 260 if(f == 0) { 261 reply(&r->work, &thdr, e[Ebadfid]); 262 r->busy = 0; 263 return; 264 } 265 266 makepath(path, f->f, ""); 267 DEBUG(2, "\tremove: %s\n", path); 268 if(remove(path) < 0) { 269 errstr(err); 270 reply(&r->work, &thdr, err); 271 r->busy = 0; 272 return; 273 } 274 275 if(f->fid >= 0) 276 close(f->fid); 277 freefid(r->work.fid); 278 279 reply(&r->work, &thdr, 0); 280 r->busy = 0; 281 } 282 283 void 284 Xwstat(Fsrpc *r) 285 { 286 char err[ERRLEN], path[128]; 287 Fcall thdr; 288 Fid *f; 289 int s; 290 291 f = getfid(r->work.fid); 292 if(f == 0) { 293 reply(&r->work, &thdr, e[Ebadfid]); 294 r->busy = 0; 295 return; 296 } 297 if(f->fid >= 0) 298 s = fwstat(f->fid, r->work.stat); 299 else { 300 makepath(path, f->f, ""); 301 s = wstat(path, r->work.stat); 302 } 303 if(s < 0) { 304 errstr(err); 305 reply(&r->work, &thdr, err); 306 } 307 else { 308 /* wstat may really be rename */ 309 strncpy(f->f->name, r->work.stat, NAMELEN); 310 reply(&r->work, &thdr, 0); 311 } 312 313 r->busy = 0; 314 } 315 316 void 317 Xclwalk(Fsrpc *r) 318 { 319 Fcall thdr; 320 Fid *f, *n; 321 322 f = getfid(r->work.fid); 323 if(f == 0) { 324 reply(&r->work, &thdr, e[Ebadfid]); 325 r->busy = 0; 326 return; 327 } 328 n = newfid(r->work.newfid); 329 if(n == 0) { 330 reply(&r->work, &thdr, e[Edupfid]); 331 r->busy = 0; 332 return; 333 } 334 n->f = f->f; 335 r->work.fid = r->work.newfid; 336 Xwalk(r); 337 } 338 339 int 340 wrmount(Fsrpc *p) 341 { 342 Dir d; 343 Fid *f; 344 Fcall thdr, *work; 345 346 work = &p->work; 347 348 f = getfid(work->fid); 349 if(f == 0) 350 return 0; 351 if(f->fid < 0) 352 return 0; 353 if(dirfstat(f->fid, &d) < 0) 354 return 0; 355 if((d.mode&CHMOUNT) == 0) 356 return 0; 357 358 /* This may need to be a list matched by tag */ 359 if(f->mpend) { 360 reply(work, &thdr, e[Emip]); 361 p->busy = 0; 362 return 1; 363 } 364 365 f->mpend = p; 366 367 thdr.count = work->count; 368 reply(work, &thdr, 0); 369 return 1; 370 } 371 372 void 373 slave(Fsrpc *f) 374 { 375 Proc *p; 376 int pid, n; 377 Fcall mcall; 378 static int nproc; 379 380 /* 381 * Look for a write to a message channel from the mount 382 * driver and attempt to multiplex to a local mount 383 */ 384 if(f->work.type == Twrite && f->work.data[0] == Tattach) { 385 n = convM2S(f->work.data, &mcall, f->work.count); 386 if(n != 0 && wrmount(f)) 387 return; 388 } 389 390 for(;;) { 391 for(p = Proclist; p; p = p->next) { 392 if(p->busy == 0) { 393 f->pid = p->pid; 394 p->busy = 1; 395 pid = rendezvous(p->pid, (ulong)f); 396 if(pid != p->pid) 397 fatal("rendezvous sync fail"); 398 return; 399 } 400 } 401 402 if(++nproc > MAXPROC) 403 fatal("too many procs"); 404 405 pid = rfork(RFPROC|RFMEM); 406 switch(pid) { 407 case -1: 408 fatal("rfork"); 409 410 case 0: 411 blockingslave(); 412 fatal("slave"); 413 414 default: 415 p = malloc(sizeof(Proc)); 416 if(p == 0) 417 fatal("out of memory"); 418 419 p->busy = 0; 420 p->pid = pid; 421 p->next = Proclist; 422 Proclist = p; 423 424 rendezvous(pid, (ulong)p); 425 } 426 } 427 } 428 429 void 430 blockingslave(void) 431 { 432 Fsrpc *p; 433 Fcall thdr; 434 Proc *m; 435 int pid; 436 437 notify(flushaction); 438 439 pid = getpid(); 440 441 m = (Proc*)rendezvous(pid, 0); 442 443 for(;;) { 444 p = (Fsrpc*)rendezvous(pid, pid); 445 if((int)p == ~0) /* Interrupted */ 446 continue; 447 448 DEBUG(2, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid); 449 if(p->flushtag != NOTAG) 450 goto flushme; 451 452 switch(p->work.type) { 453 case Tread: 454 slaveread(p); 455 break; 456 457 case Twrite: 458 slavewrite(p); 459 break; 460 461 case Topen: 462 slaveopen(p); 463 break; 464 465 default: 466 reply(&p->work, &thdr, "exportfs: slave type error"); 467 } 468 if(p->flushtag != NOTAG) { 469 flushme: 470 p->work.type = Tflush; 471 p->work.tag = p->flushtag; 472 reply(&p->work, &thdr, 0); 473 } 474 p->busy = 0; 475 m->busy = 0; 476 } 477 } 478 479 File* 480 mkmpt(char *buf, Fid *f) 481 { 482 int i; 483 File *fl; 484 char nr[10]; 485 486 if(psmpt == 0) 487 return 0; 488 489 for(i = 1; i < Npsmpt; i++) 490 if(psmap[i] == 0) 491 break; 492 493 if(i >= Npsmpt-1) 494 return 0; 495 496 sprint(nr, "%d", i); 497 fl = file(psmpt, nr); 498 if(fl == 0) 499 return 0; 500 501 sprint(buf, "/mnt/exportfs/%d", i); 502 psmap[i] = 1; 503 f->mid = i; 504 505 return fl; 506 } 507 508 void 509 rdmount(Fid *f, Fsrpc *p) 510 { 511 File *nf; 512 int n, fd; 513 Fid *mfid; 514 Fsrpc *mp; 515 char mpath[256]; 516 Fcall thdr, *work, mcall; 517 518 work = &p->work; 519 520 mp = f->mpend; 521 convM2S(mp->work.data, &mcall, mp->work.count); 522 523 mfid = newfid(mcall.fid); 524 if(mfid == 0) { 525 mcall.type = Rerror; 526 strcpy(mcall.ename, e[Ebadfid]); 527 goto repl; 528 } 529 530 nf = mkmpt(mpath, mfid); 531 if(nf == 0) { 532 mcall.type = Rerror; 533 strcpy(mcall.ename, e[Enopsmt]); 534 goto repl; 535 } 536 537 fd = dup(f->fid, -1); 538 p->canint = 1; 539 n = amount(fd, mpath, MREPL, mcall.aname); 540 p->canint = 0; 541 if(n < 0) { 542 close(fd); 543 freefid(mcall.fid); 544 mcall.type = Rerror; 545 mcall.ename[0] = 0; 546 errstr(mcall.ename); 547 } 548 else { 549 mfid->f = nf; 550 mcall.type = Rattach; 551 mcall.qid = nf->qid; 552 mcall.qid.path &= ~CHDIR; 553 } 554 repl: 555 thdr.count = convS2M(&mcall, mp->buf); 556 thdr.data = mp->buf; 557 reply(work, &thdr, 0); 558 mp->busy = 0; 559 f->mpend = 0; 560 } 561 562 void 563 slaveopen(Fsrpc *p) 564 { 565 char err[ERRLEN], path[128]; 566 Fcall *work, thdr; 567 Fid *f; 568 569 work = &p->work; 570 571 f = getfid(work->fid); 572 if(f == 0) { 573 reply(work, &thdr, e[Ebadfid]); 574 return; 575 } 576 if(f->fid >= 0) { 577 close(f->fid); 578 f->fid = -1; 579 } 580 581 makepath(path, f->f, ""); 582 DEBUG(2, "\topen: %s %d\n", path, work->mode); 583 584 p->canint = 1; 585 if(p->flushtag != NOTAG) 586 return; 587 /* There is a race here I ignore because there are no locks */ 588 f->fid = open(path, work->mode); 589 p->canint = 0; 590 if(f->fid < 0) { 591 errstr(err); 592 reply(work, &thdr, err); 593 return; 594 } 595 596 DEBUG(2, "\topen: fd %d\n", f->fid); 597 f->mode = work->mode; 598 f->offset = 0; 599 thdr.qid = f->f->qid; 600 reply(work, &thdr, 0); 601 } 602 603 void 604 slaveread(Fsrpc *p) 605 { 606 Fid *f; 607 int n, r; 608 Fcall *work, thdr; 609 char data[MAXFDATA], err[ERRLEN]; 610 611 work = &p->work; 612 613 f = getfid(work->fid); 614 if(f == 0) { 615 reply(work, &thdr, e[Ebadfid]); 616 return; 617 } 618 619 /* Do the work half of a split transaction mount */ 620 if(f->mpend) { 621 rdmount(f, p); 622 return; 623 } 624 625 if(work->offset != f->offset) 626 fileseek(f, work->offset); 627 628 n = (work->count > MAXFDATA) ? MAXFDATA : work->count; 629 p->canint = 1; 630 if(p->flushtag != NOTAG) 631 return; 632 r = read(f->fid, data, n); 633 p->canint = 0; 634 if(r < 0) { 635 errstr(err); 636 reply(work, &thdr, err); 637 return; 638 } 639 640 DEBUG(2, "\tread: fd=%d %d bytes\n", f->fid, r); 641 642 f->offset += r; 643 thdr.data = data; 644 thdr.count = r; 645 reply(work, &thdr, 0); 646 } 647 648 void 649 slavewrite(Fsrpc *p) 650 { 651 char err[ERRLEN]; 652 Fcall *work, thdr; 653 Fid *f; 654 int n; 655 656 work = &p->work; 657 658 f = getfid(work->fid); 659 if(f == 0) { 660 reply(work, &thdr, e[Ebadfid]); 661 return; 662 } 663 664 if(work->offset != f->offset) 665 fileseek(f, work->offset); 666 667 n = (work->count > MAXFDATA) ? MAXFDATA : work->count; 668 p->canint = 1; 669 if(p->flushtag != NOTAG) 670 return; 671 n = write(f->fid, work->data, n); 672 p->canint = 0; 673 if(n < 0) { 674 errstr(err); 675 reply(work, &thdr, err); 676 return; 677 } 678 679 DEBUG(2, "\twrite: %d bytes fd=%d\n", n, f->fid); 680 681 f->offset += n; 682 thdr.count = n; 683 reply(work, &thdr, 0); 684 } 685 686 void 687 fileseek(Fid *f, ulong offset) 688 { 689 char chunk[DIRCHUNK]; 690 int n, nbytes, r; 691 692 if(f->f->qid.path&CHDIR) { 693 if(offset < f->offset) 694 reopen(f); 695 696 for(nbytes = offset - f->offset; nbytes; nbytes -= r) { 697 n = (nbytes > DIRCHUNK) ? DIRCHUNK : nbytes; 698 r = read(f->fid, chunk, n); 699 if(r <= 0) { 700 DEBUG(2,"\tdir seek error\n"); 701 return; 702 } 703 f->offset += r; 704 } 705 } 706 else 707 f->offset = seek(f->fid, offset, 0); 708 } 709 710 void 711 reopen(Fid *f) 712 { 713 USED(f); 714 fatal("reopen"); 715 } 716 717 void 718 flushaction(void *a, char *cause) 719 { 720 USED(a); 721 if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) { 722 fprint(2, "exportsrv: note: %s\n", cause); 723 exits("noted"); 724 } 725 if(strncmp(cause, "kill", 4) == 0) 726 noted(NDFLT); 727 728 noted(NCONT); 729 } 730