1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include <libsec.h> 6 #include "9p1.h" 7 8 char *user; 9 int newfd; 10 int roldfd; 11 int woldfd; 12 int debug; 13 int dofcall; 14 QLock servelock; 15 QLock fidlock; 16 QLock taglock; 17 int mainpid; 18 int ntag; 19 int nfork; 20 char FLUSHED[] = "FLUSHED"; 21 22 enum{ 23 Maxfdata = 8192 24 }; 25 26 enum{ 27 Command, 28 Network, 29 File, 30 Stdio, 31 }; 32 33 typedef struct Tag Tag; 34 struct Tag 35 { 36 int tag; 37 int flushed; 38 int received; 39 int ref; 40 Tag *next; 41 }; 42 43 typedef struct Message Message; 44 struct Message 45 { 46 char *data; 47 int n; 48 }; 49 50 typedef struct Fid Fid; 51 52 struct Fid 53 { 54 short busy; 55 short allocated; 56 int fid; 57 Qid qid; 58 ulong newoffset; 59 ulong oldoffset; 60 Fid *next; 61 }; 62 63 Fid *fids; 64 Tag *tags; 65 66 char *rflush(Fcall*, Fcall*, char*), 67 *rversion(Fcall*, Fcall*, char*), 68 *rauth(Fcall*, Fcall*, char*), 69 *rattach(Fcall*, Fcall*, char*), 70 *rwalk(Fcall*, Fcall*, char*), 71 *ropen(Fcall*, Fcall*, char*), 72 *rcreate(Fcall*, Fcall*, char*), 73 *rread(Fcall*, Fcall*, char*), 74 *rwrite(Fcall*, Fcall*, char*), 75 *rclunk(Fcall*, Fcall*, char*), 76 *rremove(Fcall*, Fcall*, char*), 77 *rstat(Fcall*, Fcall*, char*), 78 *rwstat(Fcall*, Fcall*, char*); 79 80 char *(*fcalls[])(Fcall*, Fcall*, char*) = { 81 [Tversion] rversion, 82 [Tflush] rflush, 83 [Tauth] rauth, 84 [Tattach] rattach, 85 [Twalk] rwalk, 86 [Topen] ropen, 87 [Tcreate] rcreate, 88 [Tread] rread, 89 [Twrite] rwrite, 90 [Tclunk] rclunk, 91 [Tremove] rremove, 92 [Tstat] rstat, 93 [Twstat] rwstat, 94 }; 95 96 char Etoolong[] = "name too long"; 97 98 void connect(int, char*); 99 void post(int, char*); 100 void serve(void); 101 void demux(void); 102 void* emalloc(ulong); 103 char* transact9p1(Fcall9p1*, Fcall9p1*, char*); 104 Fid* newfid(int); 105 106 struct 107 { 108 char chal[CHALLEN]; /* my challenge */ 109 char rchal[CHALLEN]; /* his challenge */ 110 char authid[NAMEREC]; 111 char authdom[DOMLEN]; 112 int id; 113 } ai; 114 115 void 116 usage(void) 117 { 118 fprint(2, "usage: srvold9p [-abcCd] [-u user] [-s | [-m mountpoint]] [-x 'command' | -n network-addr | -f file] [-F] [-p servicename]\n"); 119 exits("usage"); 120 } 121 122 void 123 main(int argc, char *argv[]) 124 { 125 int method; 126 char *oldstring; 127 char *mountpoint, *postname; 128 int mountflag, mountfd; 129 int p[2]; 130 int i; 131 132 fmtinstall('F', fcallfmt); 133 fmtinstall('G', fcallfmt9p1); 134 fmtinstall('D', dirfmt); 135 136 user = getuser(); 137 mountpoint = nil; 138 mountflag = 0; 139 postname = nil; 140 oldstring = nil; 141 method = -1; 142 mountfd = -1; 143 144 ARGBEGIN{ 145 case 'a': 146 mountflag |= MAFTER; 147 break; 148 case 'b': 149 mountflag |= MBEFORE; 150 break; 151 case 'c': 152 mountflag |= MCREATE; 153 break; 154 case 'C': 155 mountflag |= MCACHE; 156 break; 157 case 'd': 158 debug++; 159 break; 160 case 'f': 161 method = File; 162 oldstring = ARGF(); 163 break; 164 case 'F': 165 dofcall++; 166 break; 167 case 'm': 168 mountpoint = EARGF(usage()); 169 break; 170 case 'n': 171 method = Network; 172 oldstring = ARGF(); 173 break; 174 case 'p': 175 postname = ARGF(); 176 if(postname == nil) 177 usage(); 178 break; 179 case 's': 180 method = Stdio; 181 break; 182 case 'u': 183 user = EARGF(usage()); 184 break; 185 case 'x': 186 method = Command; 187 oldstring = ARGF(); 188 break; 189 default: 190 usage(); 191 }ARGEND; 192 193 if(method == Stdio){ 194 if(mountpoint!=nil || argc!=0) 195 usage(); 196 }else{ 197 if(oldstring == nil || argc != 0 || (mountflag!=0 && mountpoint==nil)) 198 usage(); 199 } 200 201 rfork(RFNOTEG|RFREND); 202 203 connect(method, oldstring); 204 205 if(method == Stdio) 206 newfd = 0; 207 else{ 208 if(pipe(p) < 0) 209 fatal("pipe: %r"); 210 if(postname != nil) 211 post(p[0], postname); 212 mountfd = p[0]; 213 newfd = p[1]; 214 } 215 if(debug) 216 fprint(2, "connected and posted\n"); 217 218 switch(rfork(RFPROC|RFMEM|RFNAMEG|RFFDG)){ 219 case 0: 220 mainpid = getpid(); 221 /* child does all the work */ 222 if(mountfd >= 0) 223 close(mountfd); 224 switch(rfork(RFPROC|RFMEM|RFFDG)){ 225 case 0: 226 for(i = 0; i < 20; i++) 227 if (i != roldfd) close(i); 228 demux(); 229 return; 230 case -1: 231 fatal("fork error: %r"); 232 break; 233 } 234 for(i = 0; i < 20; i++) 235 if (i != newfd && i != woldfd && (debug == 0 || i != 2)) close(i); 236 serve(); 237 break; 238 case -1: 239 fatal("fork error: %r"); 240 break; 241 default: 242 /* parent mounts if required, then exits */ 243 if(mountpoint){ 244 if(mount(mountfd, -1, mountpoint, mountflag, "") < 0) 245 fatal("can't mount: %r"); 246 } 247 break; 248 } 249 exits(nil); 250 } 251 252 void 253 connect(int method, char *oldstring) 254 { 255 char *s; 256 char dir[256]; 257 258 switch(method){ 259 default: 260 roldfd = -1; 261 woldfd = -1; 262 fatal("can't handle method type %d", method); 263 break; 264 case Network: 265 s = netmkaddr(oldstring, 0, "9fs"); 266 roldfd = dial(s, 0, dir, 0); 267 if(roldfd < 0) 268 fatal("dial %s: %r", s); 269 woldfd = roldfd; 270 if(dofcall) 271 roldfd = fcall(woldfd); 272 break; 273 case File: 274 roldfd = open(oldstring, ORDWR); 275 if(roldfd < 0) 276 fatal("can't open %s: %r", oldstring); 277 woldfd = roldfd; 278 if(dofcall) 279 roldfd = fcall(woldfd); 280 break; 281 case Stdio: 282 roldfd = fcall(1); 283 woldfd = 1; 284 break; 285 } 286 } 287 288 void 289 post(int fd, char *srv) 290 { 291 int f; 292 char buf[128]; 293 294 snprint(buf, sizeof buf, "/srv/%s", srv); 295 f = create(buf, OWRITE, 0666); 296 if(f < 0) 297 fatal("can't create %s: %r", buf); 298 sprint(buf, "%d", fd); 299 if(write(f, buf, strlen(buf)) != strlen(buf)) 300 fatal("post write: %r"); 301 close(f); 302 } 303 304 Fid * 305 newfid(int fid) 306 { 307 Fid *f, *ff; 308 309 ff = 0; 310 qlock(&fidlock); 311 for(f = fids; f; f = f->next) 312 if(f->fid == fid){ 313 f->allocated = 1; 314 qunlock(&fidlock); 315 return f; 316 } 317 else if(!ff && !f->allocated) 318 ff = f; 319 if(ff){ 320 ff->fid = fid; 321 ff->allocated = 1; 322 qunlock(&fidlock); 323 return ff; 324 } 325 f = emalloc(sizeof *f); 326 f->fid = fid; 327 f->next = fids; 328 f->allocated = 1; 329 fids = f; 330 qunlock(&fidlock); 331 return f; 332 } 333 334 /* 335 * Reads returning 9P1 messages and demultiplexes them. 336 * BUG: assumes one read per message. 337 */ 338 void 339 demux(void) 340 { 341 int m, n; 342 char *data; 343 Fcall9p1 r; 344 Message *msg; 345 Tag *t; 346 347 for(;;){ 348 data = malloc(IOHDRSZ+Maxfdata); /* no need to clear memory */ 349 if(data == nil) 350 fatal("demux malloc: %r"); 351 m = read(roldfd, data, IOHDRSZ+Maxfdata); 352 if(m <= 0) 353 fatal("read error talking to old system: %r"); 354 n = convM2S9p1(data, &r, m); 355 if(n == 0) 356 fatal("bad conversion receiving from old system"); 357 if(debug) 358 fprint(2, "srvold9p:<=%G\n", &r); 359 qlock(&taglock); 360 for(t=tags; t!=nil; t=t->next) 361 if(t->tag == r.tag){ 362 t->received = 1; 363 break; 364 } 365 qunlock(&taglock); 366 /* 367 * Fcall9p1 tag is used to rendezvous. 368 * Recipient converts message a second time, but that's OK. 369 */ 370 msg = emalloc(sizeof(Message)); 371 msg->data = data; 372 msg->n = n; 373 rendezvous(r.tag, (ulong)msg); 374 } 375 } 376 377 Tag* 378 newtag(int tag) 379 { 380 Tag *t; 381 382 t = emalloc(sizeof(Tag)); 383 t->tag = tag; 384 t->flushed = 0; 385 t->received = 0; 386 t->ref = 1; 387 qlock(&taglock); 388 t->next = tags; 389 tags = t; 390 qunlock(&taglock); 391 return t; 392 } 393 394 void 395 freetag(Tag *tag) /* called with taglock set */ 396 { 397 Tag *t, *prev; 398 399 if(tag->ref-- == 1){ 400 prev = nil; 401 for(t=tags; t!=nil; t=t->next){ 402 if(t == tag){ 403 if(prev == nil) 404 tags = t->next; 405 else 406 prev->next = t->next; 407 break; 408 } 409 prev = t; 410 } 411 if(t == nil) 412 sysfatal("freetag"); 413 free(tag); 414 } 415 } 416 417 void 418 serve(void) 419 { 420 char *err; 421 int n; 422 Fcall thdr; 423 Fcall rhdr; 424 uchar mdata[IOHDRSZ+Maxfdata]; 425 char mdata9p1[IOHDRSZ+Maxfdata]; 426 Tag *tag; 427 428 for(;;){ 429 qlock(&servelock); 430 for(;;){ 431 n = read9pmsg(newfd, mdata, sizeof mdata); 432 433 if(n == 0) 434 continue; 435 if(n < 0) 436 break; 437 if(n > 0 && convM2S(mdata, n, &thdr) > 0) 438 break; 439 } 440 if(n>0 && servelock.head==nil) /* no other processes waiting to read */ 441 switch(rfork(RFPROC|RFMEM)){ 442 case 0: 443 /* child starts serving */ 444 continue; 445 break; 446 case -1: 447 fatal("fork error: %r"); 448 break; 449 default: 450 break; 451 } 452 qunlock(&servelock); 453 454 if(n < 0) 455 fatal(nil); /* exit quietly; remote end has just hung up */ 456 457 if(debug) 458 fprint(2, "srvold9p:<-%F\n", &thdr); 459 460 tag = newtag(thdr.tag); 461 462 if(!fcalls[thdr.type]) 463 err = "bad fcall type"; 464 else 465 err = (*fcalls[thdr.type])(&thdr, &rhdr, mdata9p1); 466 467 qlock(&taglock); 468 if(tag->flushed){ 469 freetag(tag); 470 qunlock(&taglock); 471 continue; 472 } 473 qunlock(&taglock); 474 475 if(err){ 476 rhdr.type = Rerror; 477 rhdr.ename = err; 478 }else{ 479 rhdr.type = thdr.type + 1; 480 rhdr.fid = thdr.fid; 481 } 482 rhdr.tag = thdr.tag; 483 if(debug) 484 fprint(2, "srvold9p:->%F\n", &rhdr);/**/ 485 n = convS2M(&rhdr, mdata, sizeof mdata); 486 if(n == 0) 487 fatal("convS2M error on write"); 488 if(write(newfd, mdata, n) != n) 489 fatal("mount write"); 490 491 qlock(&taglock); 492 freetag(tag); 493 qunlock(&taglock); 494 } 495 } 496 497 void 498 send9p1(Fcall9p1 *t, char *data) 499 { 500 int m, n; 501 502 if(debug) 503 fprint(2, "srvold9p:=>%G\n", t); 504 n = convS2M9p1(t, data); 505 if(n == 0) 506 fatal("bad conversion sending to old system"); 507 m = write(woldfd, data, n); 508 if(m != n) 509 fatal("wrote %d to old system; should be %d", m, n); 510 } 511 512 int 513 recv9p1(Fcall9p1 *r, int tag, char *data) 514 { 515 int n; 516 Message *msg; 517 518 msg = (Message*)rendezvous(tag, 0); 519 if((ulong)msg == ~0UL) 520 fatal("rendezvous: %r"); 521 if(msg == nil){ 522 if(debug) 523 fprint(2, "recv flushed\n"); 524 return -1; 525 } 526 /* copy data to local buffer */ 527 memmove(data, msg->data, msg->n); 528 n = convM2S9p1(data, r, msg->n); 529 if(n == 0) 530 fatal("bad conversion receiving from old system"); 531 free(msg->data); 532 free(msg); 533 return 1; 534 } 535 536 char* 537 transact9p1(Fcall9p1 *t, Fcall9p1 *r, char *mdata9p1) 538 { 539 send9p1(t, mdata9p1); 540 if(recv9p1(r, t->tag, mdata9p1) < 0) 541 return FLUSHED; 542 if(r->type == Rerror9p1) 543 return r->ename; 544 if(r->type != t->type+1) 545 fatal("bad message type; expected %d got %d", t->type+1, r->type); 546 return nil; 547 } 548 549 char* 550 rflush(Fcall *t, Fcall *, char *mdata9p1) 551 { 552 Fcall9p1 t9, r9; 553 Tag *oldt; 554 555 t9.type = Tflush9p1; 556 t9.tag = t->tag; 557 t9.oldtag = t->oldtag; 558 qlock(&taglock); 559 for(oldt=tags; oldt!=nil; oldt=oldt->next) 560 if(oldt->tag == t->oldtag){ 561 oldt->flushed = 1; 562 oldt->ref++; 563 break; 564 } 565 qunlock(&taglock); 566 567 if(oldt == nil){ /* nothing to flush */ 568 if(debug) 569 fprint(2, "no such tag to flush\n"); 570 return 0; 571 } 572 573 transact9p1(&t9, &r9, mdata9p1); /* can't error */ 574 575 qlock(&taglock); 576 if(oldt->received == 0){ /* wake up receiver */ 577 if(debug) 578 fprint(2, "wake up receiver\n"); 579 oldt->received = 1; 580 rendezvous(t->oldtag, 0); 581 } 582 freetag(oldt); 583 qunlock(&taglock); 584 return 0; 585 } 586 587 char* 588 rversion(Fcall *t, Fcall *r, char*) 589 { 590 Fid *f; 591 592 /* just ack; this one doesn't go to old service */ 593 if(t->msize > IOHDRSZ+Maxfdata) 594 r->msize = IOHDRSZ+Maxfdata; 595 else 596 r->msize = t->msize; 597 if(strncmp(t->version, "9P2000", 6) != 0) 598 return "unknown 9P version"; 599 r->version = "9P2000"; 600 601 qlock(&fidlock); 602 for(f = fids; f; f = f->next){ 603 f->busy = 0; 604 f->allocated = 0; 605 } 606 qunlock(&fidlock); 607 608 return 0; 609 } 610 611 char* 612 rauth(Fcall *, Fcall *, char *) 613 { 614 return "srvold9p: authentication not supported"; 615 } 616 617 #ifdef asdf 618 619 void 620 memrandom(void *p, int n) 621 { 622 ulong *lp; 623 uchar *cp; 624 625 for(lp = p; n >= sizeof(ulong); n -= sizeof(ulong)) 626 *lp++ = fastrand(); 627 for(cp = (uchar*)lp; n > 0; n--) 628 *cp++ = fastrand(); 629 } 630 631 char* 632 rsession(Fcall *t, Fcall *r, char *mdata9p1) 633 { 634 char *err; 635 Fcall9p1 t9, r9; 636 Fid *f; 637 638 t9.type = Tsession9p1; 639 t9.tag = t->tag; 640 if(doauth) 641 memrandom(t9.chal, sizeof t9.chal); 642 else 643 memset(t9.chal, 0, sizeof t9.chal); 644 err = transact9p1(&t9, &r9, mdata9p1); 645 if(err) 646 return err; 647 648 qlock(&fidlock); 649 for(f = fids; f; f = f->next){ 650 f->busy = 0; 651 f->allocated = 0; 652 } 653 qunlock(&fidlock); 654 655 if(doauth){ 656 memmove(ai.authid, r9.authid, sizeof ai.authid); 657 memmove(ai.authdom, r9.authdom, sizeof ai.authid); 658 memmove(ai.rchal, r9.chal, sizeof ai.rchal); 659 memmove(ai.chal, t9.chal, sizeof ai.chal); 660 r->authid = ai.authid; 661 r->authdom = ai.authdom; 662 r->chal = (uchar*)ai.rchal; 663 r->nchal = CHALLEN; 664 } else { 665 r->authid = ""; 666 r->authdom = ""; 667 r->nchal = 0; 668 r->chal = nil; 669 } 670 return 0; 671 } 672 #endif 673 674 char* 675 rattach(Fcall *t, Fcall *r, char *mdata9p1) 676 { 677 char *err; 678 Fcall9p1 t9, r9; 679 Fid *f; 680 681 f = newfid(t->fid); 682 if(f->busy) 683 return "attach: fid in use"; 684 /* no authentication! */ 685 t9.type = Tattach9p1; 686 t9.tag = t->tag; 687 t9.fid = t->fid; 688 strncpy(t9.uname, t->uname, NAMEREC); 689 if(strcmp(user, "none") == 0) 690 strncpy(t9.uname, user, NAMEREC); 691 strncpy(t9.aname, t->aname, NAMEREC); 692 memset(t9.ticket, 0, sizeof t9.ticket); 693 memset(t9.auth, 0, sizeof t9.auth); 694 err = transact9p1(&t9, &r9, mdata9p1); 695 if(err) 696 return err; 697 698 r->qid.path = r9.qid.path & ~0x80000000; 699 r->qid.vers = r9.qid.version; 700 r->qid.type = QTDIR; 701 f->busy = 1; 702 f->qid = r->qid; 703 return 0; 704 } 705 706 char* 707 rwalk(Fcall *t, Fcall *r, char *mdata9p1) 708 { 709 char *err; 710 Fcall9p1 t9, r9; 711 int i, fid; 712 Qid *q; 713 Fid *f, *nf; 714 715 f = newfid(t->fid); 716 if(!f->busy) 717 return "walk: bad fid"; 718 719 fid = t->fid; 720 nf = nil; 721 if(t->fid != t->newfid){ 722 nf = newfid(t->newfid); 723 if(nf->busy) 724 return "walk: newfid in use"; 725 t9.type = Tclone9p1; 726 t9.tag = t->tag; 727 t9.fid = t->fid; 728 t9.newfid = t->newfid; 729 err = transact9p1(&t9, &r9, mdata9p1); 730 if(err){ 731 nf->busy = 0; 732 nf->allocated = 0; 733 return err; 734 } 735 fid = t->newfid; 736 nf->busy = 1; 737 } 738 739 err = nil; 740 r->nwqid = 0; 741 for(i=0; i<t->nwname && err==nil; i++){ 742 if(i > MAXWELEM) 743 break; 744 t9.type = Twalk9p1; 745 t9.tag = t->tag; 746 t9.fid = fid; 747 strncpy(t9.name, t->wname[i], NAMEREC); 748 err = transact9p1(&t9, &r9, mdata9p1); 749 if(err == FLUSHED){ 750 i = -1; /* guarantee cleanup */ 751 break; 752 } 753 if(err == nil){ 754 q = &r->wqid[r->nwqid++]; 755 q->type = QTFILE; 756 if(r9.qid.path & 0x80000000) 757 q->type = QTDIR; 758 q->vers = r9.qid.version; 759 q->path = r9.qid.path & ~0x80000000; 760 } 761 } 762 763 if(nf!=nil && (err!=nil || i<t->nwname)){ 764 /* clunk the new fid */ 765 t9.type = Tclunk9p1; 766 t9.tag = t->tag; 767 t9.fid = t->newfid; 768 transact9p1(&t9, &r9, mdata9p1); 769 /* ignore more errors */ 770 nf->busy = 0; 771 nf->allocated = 0; 772 } 773 774 if(i>0 && i==t->nwname && err==nil) 775 f->qid = r->wqid[r->nwqid-1]; 776 if(i > 0) 777 return 0; 778 return err; 779 } 780 781 char* 782 ropen(Fcall *t, Fcall *r, char *mdata9p1) 783 { 784 char *err; 785 Fcall9p1 t9, r9; 786 Fid *f; 787 788 f = newfid(t->fid); 789 if(!f->busy) 790 return "open: bad fid"; 791 792 t9.type = Topen9p1; 793 t9.tag = t->tag; 794 t9.fid = t->fid; 795 t9.mode = t->mode; 796 err = transact9p1(&t9, &r9, mdata9p1); 797 if(err) 798 return err; 799 800 r->qid.path = r9.qid.path & ~0x80000000; 801 r->qid.vers = r9.qid.version; 802 r->qid.type = QTFILE; 803 if(r9.qid.path & 0x80000000) 804 r->qid.type = QTDIR; 805 f->qid = r->qid; 806 f->newoffset = 0; 807 f->oldoffset = 0; 808 r->iounit = 0; 809 return 0; 810 } 811 812 char* 813 rcreate(Fcall *t, Fcall *r, char *mdata9p1) 814 { 815 char *err; 816 Fcall9p1 t9, r9; 817 Fid *f; 818 819 f = newfid(t->fid); 820 if(!f->busy) 821 return "create: bad fid"; 822 823 t9.type = Tcreate9p1; 824 t9.tag = t->tag; 825 t9.fid = t->fid; 826 if(strlen(t->name)+1 >= NAMEREC) 827 return "file name element too long"; 828 strncpy(t9.name, t->name, NAMEREC); 829 t9.perm = t->perm; 830 t9.mode = t->mode; 831 err = transact9p1(&t9, &r9, mdata9p1); 832 if(err) 833 return err; 834 835 r->qid.path = r9.qid.path & ~0x80000000; 836 r->qid.vers = r9.qid.version; 837 r->qid.type = QTFILE; 838 if(r9.qid.path & 0x80000000) 839 r->qid.type = QTDIR; 840 if(r9.qid.path & 0x40000000) 841 r->qid.type |= QTAPPEND; 842 if(r9.qid.path & 0x20000000) 843 r->qid.type |= QTEXCL; 844 f->qid = r->qid; 845 r->iounit = 0; 846 return 0; 847 } 848 849 char* 850 dirrread(Fcall *t, Fcall *r, char *mdata9p1) 851 { 852 char *err; 853 Fcall9p1 t9, r9; 854 Fid *f; 855 int i, ndir, n, count; 856 Dir d; 857 uchar buf[Maxfdata]; 858 char *old; 859 860 f = newfid(t->fid); 861 if(!f->busy) 862 return "dirread: bad fid"; 863 864 if(f->newoffset != t->offset) 865 return "seek in directory disallowed"; 866 867 t9.type = Tread9p1; 868 t9.tag = t->tag; 869 t9.fid = t->fid; 870 t9.offset = f->oldoffset; 871 t9.count = t->count; /* new directories tend to be smaller, so this may overshoot */ 872 err = transact9p1(&t9, &r9, mdata9p1); 873 if(err) 874 return err; 875 876 ndir = r9.count/DIRREC; 877 old = r9.data; 878 count = 0; 879 for(i=0; i<ndir; i++){ 880 if(convM2D9p1(old, &d) != DIRREC) 881 return "bad dir conversion in read"; 882 n = convD2M(&d, buf+count, sizeof buf-count); 883 if(n<=BIT16SZ || count+n>t->count) 884 break; 885 old += DIRREC; 886 f->oldoffset += DIRREC; 887 f->newoffset += n; 888 count += n; 889 } 890 memmove(r9.data, buf, count); /* put it back in stable storage */ 891 r->data = r9.data; 892 r->count = count; 893 return 0; 894 } 895 896 char* 897 rread(Fcall *t, Fcall *r, char *mdata9p1) 898 { 899 char *err; 900 Fcall9p1 t9, r9; 901 Fid *f; 902 903 f = newfid(t->fid); 904 if(!f->busy) 905 return "read: bad fid"; 906 907 if(f->qid.type & QTDIR) 908 return dirrread(t, r, mdata9p1); 909 910 t9.type = Tread9p1; 911 t9.tag = t->tag; 912 t9.fid = t->fid; 913 t9.offset = t->offset; 914 t9.count = t->count; 915 err = transact9p1(&t9, &r9, mdata9p1); 916 if(err) 917 return err; 918 919 r->count = r9.count; 920 r->data = r9.data; /* points to stable storage */ 921 return 0; 922 } 923 924 char* 925 rwrite(Fcall *t, Fcall *r, char *mdata9p1) 926 { 927 char *err; 928 Fcall9p1 t9, r9; 929 Fid *f; 930 931 f = newfid(t->fid); 932 if(!f->busy) 933 return "write: bad fid"; 934 935 t9.type = Twrite9p1; 936 t9.tag = t->tag; 937 t9.fid = t->fid; 938 t9.offset = t->offset; 939 t9.count = t->count; 940 t9.data = t->data; 941 err = transact9p1(&t9, &r9, mdata9p1); 942 if(err) 943 return err; 944 945 r->count = r9.count; 946 return 0; 947 } 948 949 char* 950 rclunk(Fcall *t, Fcall *, char *mdata9p1) 951 { 952 Fcall9p1 t9, r9; 953 Fid *f; 954 955 f = newfid(t->fid); 956 if(!f->busy) 957 return "clunk: bad fid"; 958 t9.type = Tclunk9p1; 959 t9.tag = t->tag; 960 t9.fid = t->fid; 961 transact9p1(&t9, &r9, mdata9p1); 962 f->busy = 0; 963 f->allocated = 0; 964 /* disregard error */ 965 return 0; 966 } 967 968 char* 969 rremove(Fcall *t, Fcall*, char *mdata9p1) 970 { 971 char *err; 972 Fcall9p1 t9, r9; 973 Fid *f; 974 975 f = newfid(t->fid); 976 if(!f->busy) 977 return "remove: bad fid"; 978 t9.type = Tremove9p1; 979 t9.tag = t->tag; 980 t9.fid = t->fid; 981 err = transact9p1(&t9, &r9, mdata9p1); 982 f->busy = 0; 983 f->allocated = 0; 984 return err; 985 } 986 987 char* 988 rstat(Fcall *t, Fcall *r, char *mdata9p1) 989 { 990 Fcall9p1 t9, r9; 991 char *err; 992 Fid *f; 993 Dir d; 994 uchar buf[256]; /* big enough; there's no long names */ 995 996 f = newfid(t->fid); 997 if(!f->busy) 998 return "stat: bad fid"; 999 1000 t9.type = Tstat9p1; 1001 t9.tag = t->tag; 1002 t9.fid = t->fid; 1003 err = transact9p1(&t9, &r9, mdata9p1); 1004 if(err) 1005 return err; 1006 1007 if(convM2D9p1(r9.stat, &d) != DIRREC) 1008 return "bad conversion in stat"; 1009 r->stat = buf; 1010 r->nstat = convD2M(&d, buf, sizeof buf); 1011 return 0; 1012 } 1013 1014 int 1015 anydefault(Dir *d) 1016 { 1017 if(d->name[0] == '\0') 1018 return 1; 1019 if(d->uid[0] == '\0') 1020 return 1; 1021 if(d->gid[0] == '\0') 1022 return 1; 1023 if(d->mode == ~0) 1024 return 1; 1025 if(d->mtime == ~0) 1026 return 1; 1027 return 0; 1028 } 1029 1030 char* 1031 rwstat(Fcall *t, Fcall *, char *mdata9p1) 1032 { 1033 Fcall9p1 t9, r9; 1034 char strs[DIRREC]; 1035 char *err; 1036 Fid *f; 1037 Dir d, cd; 1038 1039 f = newfid(t->fid); 1040 if(!f->busy) 1041 return "wstat: bad fid"; 1042 1043 convM2D(t->stat, t->nstat, &d, strs); 1044 cd = d; 1045 if(anydefault(&d)){ 1046 /* must first stat file so we can copy current values */ 1047 t9.type = Tstat9p1; 1048 t9.tag = t->tag; 1049 t9.fid = t->fid; 1050 err = transact9p1(&t9, &r9, mdata9p1); 1051 if(err) 1052 return err; 1053 if(convM2D9p1(r9.stat, &cd) != DIRREC) 1054 return "bad in conversion in wstat"; 1055 1056 /* fill in default values */ 1057 if(d.name[0] != '\0'){ 1058 if(strlen(d.name) >= NAMEREC) 1059 return Etoolong; 1060 cd.name = d.name; 1061 } 1062 if(d.uid[0] != '\0'){ 1063 if(strlen(d.uid) >= NAMEREC) 1064 return Etoolong; 1065 cd.uid = d.uid; 1066 } 1067 if(d.gid[0] != '\0'){ 1068 if(strlen(d.gid) >= NAMEREC) 1069 return Etoolong; 1070 cd.gid = d.gid; 1071 } 1072 if(d.mode != ~0) 1073 cd.mode = d.mode; 1074 if(d.mtime != ~0) 1075 cd.mtime = d.mtime; 1076 if(d.length != ~0LL) 1077 cd.length = d.length; 1078 } 1079 1080 if(convD2M9p1(&cd, t9.stat) != DIRREC) 1081 return "bad out conversion in wstat"; 1082 1083 t9.type = Twstat9p1; 1084 t9.tag = t->tag; 1085 t9.fid = t->fid; 1086 err = transact9p1(&t9, &r9, mdata9p1); 1087 if(err) 1088 return err; 1089 return 0; 1090 } 1091 1092 void * 1093 emalloc(ulong n) 1094 { 1095 void *p; 1096 1097 p = malloc(n); 1098 if(!p) 1099 fatal("out of memory: %r"); 1100 memset(p, 0, n); 1101 return p; 1102 } 1103 1104 void 1105 fatal(char *fmt, ...) 1106 { 1107 char buf[1024]; 1108 va_list arg; 1109 1110 if(fmt){ 1111 va_start(arg, fmt); 1112 vseprint(buf, buf+sizeof(buf), fmt, arg); 1113 va_end(arg); 1114 fprint(2, "%s: (pid %d) %s\n", argv0, getpid(), buf); 1115 }else 1116 buf[0] = '\0'; 1117 if(mainpid){ 1118 /* two hits are sometimes needed */ 1119 postnote(PNGROUP, mainpid, "die1 - from srvold9p"); 1120 postnote(PNGROUP, mainpid, "die2 - from srvold9p"); 1121 } 1122 exits(buf); 1123 } 1124