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