1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include <thread.h> 6 #include <9p.h> 7 8 void (*_forker)(void(*)(void*), void*, int); 9 10 static char Ebadattach[] = "unknown specifier in attach"; 11 static char Ebadoffset[] = "bad offset"; 12 static char Ebadcount[] = "bad count"; 13 static char Ebotch[] = "9P protocol botch"; 14 static char Ecreatenondir[] = "create in non-directory"; 15 static char Edupfid[] = "duplicate fid"; 16 static char Eduptag[] = "duplicate tag"; 17 static char Eisdir[] = "is a directory"; 18 static char Enocreate[] = "create prohibited"; 19 static char Enomem[] = "out of memory"; 20 static char Enoremove[] = "remove prohibited"; 21 static char Enostat[] = "stat prohibited"; 22 static char Enotfound[] = "file not found"; 23 static char Enowrite[] = "write prohibited"; 24 static char Enowstat[] = "wstat prohibited"; 25 static char Eperm[] = "permission denied"; 26 static char Eunknownfid[] = "unknown fid"; 27 static char Ebaddir[] = "bad directory in wstat"; 28 static char Ewalknodir[] = "walk in non-directory"; 29 30 static void 31 setfcallerror(Fcall *f, char *err) 32 { 33 f->ename = err; 34 f->type = Rerror; 35 } 36 37 static void 38 changemsize(Srv *srv, int msize) 39 { 40 if(srv->rbuf && srv->wbuf && srv->msize == msize) 41 return; 42 qlock(&srv->rlock); 43 qlock(&srv->wlock); 44 srv->msize = msize; 45 free(srv->rbuf); 46 free(srv->wbuf); 47 srv->rbuf = emalloc9p(msize); 48 srv->wbuf = emalloc9p(msize); 49 qunlock(&srv->rlock); 50 qunlock(&srv->wlock); 51 } 52 53 static Req* 54 getreq(Srv *s) 55 { 56 long n; 57 uchar *buf; 58 Fcall f; 59 Req *r; 60 61 qlock(&s->rlock); 62 if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){ 63 qunlock(&s->rlock); 64 return nil; 65 } 66 67 buf = emalloc9p(n); 68 memmove(buf, s->rbuf, n); 69 qunlock(&s->rlock); 70 71 if(convM2S(buf, n, &f) != n){ 72 free(buf); 73 return nil; 74 } 75 76 if((r=allocreq(s->rpool, f.tag)) == nil){ /* duplicate tag: cons up a fake Req */ 77 r = emalloc9p(sizeof *r); 78 incref(&r->ref); 79 r->tag = f.tag; 80 r->ifcall = f; 81 r->error = Eduptag; 82 r->buf = buf; 83 r->responded = 0; 84 r->type = 0; 85 r->srv = s; 86 r->pool = nil; 87 if(chatty9p) 88 fprint(2, "<-%d- %F: dup tag\n", s->infd, &f); 89 return r; 90 } 91 92 r->srv = s; 93 r->responded = 0; 94 r->buf = buf; 95 r->ifcall = f; 96 memset(&r->ofcall, 0, sizeof r->ofcall); 97 r->type = r->ifcall.type; 98 99 if(chatty9p) 100 if(r->error) 101 fprint(2, "<-%d- %F: %s\n", s->infd, &r->ifcall, r->error); 102 else 103 fprint(2, "<-%d- %F\n", s->infd, &r->ifcall); 104 105 return r; 106 } 107 108 static void 109 filewalk(Req *r) 110 { 111 int i; 112 File *f; 113 114 f = r->fid->file; 115 assert(f != nil); 116 117 incref(f); 118 for(i=0; i<r->ifcall.nwname; i++) 119 if(f = walkfile(f, r->ifcall.wname[i])) 120 r->ofcall.wqid[i] = f->qid; 121 else 122 break; 123 124 r->ofcall.nwqid = i; 125 if(f){ 126 r->newfid->file = f; 127 r->newfid->qid = r->newfid->file->qid; 128 } 129 respond(r, nil); 130 } 131 132 void 133 walkandclone(Req *r, char *(*walk1)(Fid*, char*, void*), char *(*clone)(Fid*, Fid*, void*), void *arg) 134 { 135 int i; 136 char *e; 137 138 if(r->fid == r->newfid && r->ifcall.nwname > 1){ 139 respond(r, "lib9p: unused documented feature not implemented"); 140 return; 141 } 142 143 if(r->fid != r->newfid){ 144 r->newfid->qid = r->fid->qid; 145 if(clone && (e = clone(r->fid, r->newfid, arg))){ 146 respond(r, e); 147 return; 148 } 149 } 150 151 e = nil; 152 for(i=0; i<r->ifcall.nwname; i++){ 153 if(e = walk1(r->newfid, r->ifcall.wname[i], arg)) 154 break; 155 r->ofcall.wqid[i] = r->newfid->qid; 156 } 157 158 r->ofcall.nwqid = i; 159 if(e && i==0) 160 respond(r, e); 161 else 162 respond(r, nil); 163 } 164 165 static void 166 sversion(Srv*, Req *r) 167 { 168 if(strncmp(r->ifcall.version, "9P", 2) != 0){ 169 r->ofcall.version = "unknown"; 170 respond(r, nil); 171 return; 172 } 173 174 r->ofcall.version = "9P2000"; 175 r->ofcall.msize = r->ifcall.msize; 176 respond(r, nil); 177 } 178 static void 179 rversion(Req *r, char *error) 180 { 181 assert(error == nil); 182 changemsize(r->srv, r->ofcall.msize); 183 } 184 185 static void 186 sauth(Srv *srv, Req *r) 187 { 188 char e[ERRMAX]; 189 190 if((r->afid = allocfid(srv->fpool, r->ifcall.afid)) == nil){ 191 respond(r, Edupfid); 192 return; 193 } 194 if(srv->auth) 195 srv->auth(r); 196 else{ 197 snprint(e, sizeof e, "%s: authentication not required", argv0); 198 respond(r, e); 199 } 200 } 201 static void 202 rauth(Req *r, char *error) 203 { 204 if(error && r->afid) 205 closefid(removefid(r->srv->fpool, r->afid->fid)); 206 } 207 208 static void 209 sattach(Srv *srv, Req *r) 210 { 211 if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){ 212 respond(r, Edupfid); 213 return; 214 } 215 r->afid = nil; 216 if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){ 217 respond(r, Eunknownfid); 218 return; 219 } 220 r->fid->uid = estrdup9p(r->ifcall.uname); 221 if(srv->tree){ 222 r->fid->file = srv->tree->root; 223 incref(r->fid->file); 224 r->ofcall.qid = r->fid->file->qid; 225 r->fid->qid = r->ofcall.qid; 226 } 227 if(srv->attach) 228 srv->attach(r); 229 else 230 respond(r, nil); 231 return; 232 } 233 static void 234 rattach(Req *r, char *error) 235 { 236 if(error && r->fid) 237 closefid(removefid(r->srv->fpool, r->fid->fid)); 238 } 239 240 static void 241 sflush(Srv *srv, Req *r) 242 { 243 r->oldreq = lookupreq(srv->rpool, r->ifcall.oldtag); 244 if(r->oldreq == nil || r->oldreq == r) 245 respond(r, nil); 246 else if(srv->flush) 247 srv->flush(r); 248 else 249 respond(r, nil); 250 } 251 static int 252 rflush(Req *r, char *error) 253 { 254 Req *or; 255 256 assert(error == nil); 257 or = r->oldreq; 258 if(or){ 259 qlock(&or->lk); 260 if(or->responded == 0){ 261 or->flush = erealloc9p(or->flush, (or->nflush+1)*sizeof(or->flush[0])); 262 or->flush[or->nflush++] = r; 263 qunlock(&or->lk); 264 return -1; /* delay response until or is responded */ 265 } 266 qunlock(&or->lk); 267 closereq(or); 268 } 269 r->oldreq = nil; 270 return 0; 271 } 272 273 static char* 274 oldwalk1(Fid *fid, char *name, void *arg) 275 { 276 char *e; 277 Qid qid; 278 Srv *srv; 279 280 srv = arg; 281 e = srv->walk1(fid, name, &qid); 282 if(e) 283 return e; 284 fid->qid = qid; 285 return nil; 286 } 287 288 static char* 289 oldclone(Fid *fid, Fid *newfid, void *arg) 290 { 291 Srv *srv; 292 293 srv = arg; 294 if(srv->clone == nil) 295 return nil; 296 return srv->clone(fid, newfid); 297 } 298 299 static void 300 swalk(Srv *srv, Req *r) 301 { 302 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 303 respond(r, Eunknownfid); 304 return; 305 } 306 if(r->fid->omode != -1){ 307 respond(r, "cannot clone open fid"); 308 return; 309 } 310 if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){ 311 respond(r, Ewalknodir); 312 return; 313 } 314 if(r->ifcall.fid != r->ifcall.newfid){ 315 if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){ 316 respond(r, Edupfid); 317 return; 318 } 319 r->newfid->uid = estrdup9p(r->fid->uid); 320 }else{ 321 incref(&r->fid->ref); 322 r->newfid = r->fid; 323 } 324 if(r->fid->file){ 325 filewalk(r); 326 }else if(srv->walk1) 327 walkandclone(r, oldwalk1, oldclone, srv); 328 else if(srv->walk) 329 srv->walk(r); 330 else 331 sysfatal("no walk function, no file trees"); 332 } 333 static void 334 rwalk(Req *r, char *error) 335 { 336 if(error || r->ofcall.nwqid < r->ifcall.nwname){ 337 if(r->ifcall.fid != r->ifcall.newfid && r->newfid) 338 closefid(removefid(r->srv->fpool, r->newfid->fid)); 339 if (r->ofcall.nwqid==0){ 340 if(error==nil && r->ifcall.nwname!=0) 341 r->error = Enotfound; 342 }else 343 r->error = nil; // No error on partial walks 344 }else{ 345 if(r->ofcall.nwqid == 0){ 346 /* Just a clone */ 347 r->newfid->qid = r->fid->qid; 348 }else{ 349 /* if file trees are in use, filewalk took care of the rest */ 350 r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1]; 351 } 352 } 353 } 354 355 static void 356 sopen(Srv *srv, Req *r) 357 { 358 int p; 359 360 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 361 respond(r, Eunknownfid); 362 return; 363 } 364 if(r->fid->omode != -1){ 365 respond(r, Ebotch); 366 return; 367 } 368 if((r->fid->qid.type&QTDIR) && (r->ifcall.mode&~ORCLOSE) != OREAD){ 369 respond(r, Eisdir); 370 return; 371 } 372 r->ofcall.qid = r->fid->qid; 373 switch(r->ifcall.mode&3){ 374 default: 375 assert(0); 376 case OREAD: 377 p = AREAD; 378 break; 379 case OWRITE: 380 p = AWRITE; 381 break; 382 case ORDWR: 383 p = AREAD|AWRITE; 384 break; 385 case OEXEC: 386 p = AEXEC; 387 break; 388 } 389 if(r->ifcall.mode&OTRUNC) 390 p |= AWRITE; 391 if((r->fid->qid.type&QTDIR) && p!=AREAD){ 392 respond(r, Eperm); 393 return; 394 } 395 if(r->fid->file){ 396 if(!hasperm(r->fid->file, r->fid->uid, p)){ 397 respond(r, Eperm); 398 return; 399 } 400 /* BUG RACE */ 401 if((r->ifcall.mode&ORCLOSE) 402 && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){ 403 respond(r, Eperm); 404 return; 405 } 406 r->ofcall.qid = r->fid->file->qid; 407 if((r->ofcall.qid.type&QTDIR) 408 && (r->fid->rdir = opendirfile(r->fid->file)) == nil){ 409 respond(r, "opendirfile failed"); 410 return; 411 } 412 } 413 if(srv->open) 414 srv->open(r); 415 else 416 respond(r, nil); 417 } 418 static void 419 ropen(Req *r, char *error) 420 { 421 char errbuf[ERRMAX]; 422 if(error) 423 return; 424 if(chatty9p){ 425 snprint(errbuf, sizeof errbuf, "fid mode is 0x%ux\n", r->ifcall.mode); 426 write(2, errbuf, strlen(errbuf)); 427 } 428 r->fid->omode = r->ifcall.mode; 429 r->fid->qid = r->ofcall.qid; 430 if(r->ofcall.qid.type&QTDIR) 431 r->fid->diroffset = 0; 432 } 433 434 static void 435 screate(Srv *srv, Req *r) 436 { 437 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil) 438 respond(r, Eunknownfid); 439 else if(r->fid->omode != -1) 440 respond(r, Ebotch); 441 else if(!(r->fid->qid.type&QTDIR)) 442 respond(r, Ecreatenondir); 443 else if(r->fid->file && !hasperm(r->fid->file, r->fid->uid, AWRITE)) 444 respond(r, Eperm); 445 else if(srv->create) 446 srv->create(r); 447 else 448 respond(r, Enocreate); 449 } 450 static void 451 rcreate(Req *r, char *error) 452 { 453 if(error) 454 return; 455 r->fid->omode = r->ifcall.mode; 456 r->fid->qid = r->ofcall.qid; 457 } 458 459 static void 460 sread(Srv *srv, Req *r) 461 { 462 int o; 463 464 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 465 respond(r, Eunknownfid); 466 return; 467 } 468 if((int)r->ifcall.count < 0){ 469 respond(r, Ebotch); 470 return; 471 } 472 if(r->ifcall.offset < 0 473 || ((r->fid->qid.type&QTDIR) && r->ifcall.offset != 0 && r->ifcall.offset != r->fid->diroffset)){ 474 respond(r, Ebadoffset); 475 return; 476 } 477 478 if(r->ifcall.count > srv->msize - IOHDRSZ) 479 r->ifcall.count = srv->msize - IOHDRSZ; 480 r->rbuf = emalloc9p(r->ifcall.count); 481 r->ofcall.data = r->rbuf; 482 o = r->fid->omode & 3; 483 if(o != OREAD && o != ORDWR && o != OEXEC){ 484 respond(r, Ebotch); 485 return; 486 } 487 if((r->fid->qid.type&QTDIR) && r->fid->file){ 488 r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count); 489 respond(r, nil); 490 return; 491 } 492 if(srv->read) 493 srv->read(r); 494 else 495 respond(r, "no srv->read"); 496 } 497 static void 498 rread(Req *r, char *error) 499 { 500 if(error==nil && (r->fid->qid.type&QTDIR)) 501 r->fid->diroffset += r->ofcall.count; 502 } 503 504 static void 505 swrite(Srv *srv, Req *r) 506 { 507 int o; 508 char e[ERRMAX]; 509 510 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 511 respond(r, Eunknownfid); 512 return; 513 } 514 if((int)r->ifcall.count < 0){ 515 respond(r, Ebotch); 516 return; 517 } 518 if(r->ifcall.offset < 0){ 519 respond(r, Ebotch); 520 return; 521 } 522 if(r->ifcall.count > srv->msize - IOHDRSZ) 523 r->ifcall.count = srv->msize - IOHDRSZ; 524 o = r->fid->omode & 3; 525 if(o != OWRITE && o != ORDWR){ 526 snprint(e, sizeof e, "write on fid with open mode 0x%ux", r->fid->omode); 527 respond(r, e); 528 return; 529 } 530 if(srv->write) 531 srv->write(r); 532 else 533 respond(r, "no srv->write"); 534 } 535 static void 536 rwrite(Req *r, char *error) 537 { 538 if(error) 539 return; 540 if(r->fid->file) 541 r->fid->file->qid.vers++; 542 } 543 544 static void 545 sclunk(Srv *srv, Req *r) 546 { 547 if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil) 548 respond(r, Eunknownfid); 549 else 550 respond(r, nil); 551 } 552 static void 553 rclunk(Req*, char*) 554 { 555 } 556 557 static void 558 sremove(Srv *srv, Req *r) 559 { 560 if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil){ 561 respond(r, Eunknownfid); 562 return; 563 } 564 /* BUG RACE */ 565 if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){ 566 respond(r, Eperm); 567 return; 568 } 569 if(srv->remove) 570 srv->remove(r); 571 else 572 respond(r, r->fid->file ? nil : Enoremove); 573 } 574 static void 575 rremove(Req *r, char *error, char *errbuf) 576 { 577 if(error) 578 return; 579 if(r->fid->file){ 580 if(removefile(r->fid->file) < 0){ 581 snprint(errbuf, ERRMAX, "remove %s: %r", 582 r->fid->file->name); 583 r->error = errbuf; 584 } 585 r->fid->file = nil; 586 } 587 } 588 589 static void 590 sstat(Srv *srv, Req *r) 591 { 592 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 593 respond(r, Eunknownfid); 594 return; 595 } 596 if(r->fid->file){ 597 /* should we rlock the file? */ 598 r->d = r->fid->file->Dir; 599 if(r->d.name) 600 r->d.name = estrdup9p(r->d.name); 601 if(r->d.uid) 602 r->d.uid = estrdup9p(r->d.uid); 603 if(r->d.gid) 604 r->d.gid = estrdup9p(r->d.gid); 605 if(r->d.muid) 606 r->d.muid = estrdup9p(r->d.muid); 607 } 608 if(srv->stat) 609 srv->stat(r); 610 else if(r->fid->file) 611 respond(r, nil); 612 else 613 respond(r, Enostat); 614 } 615 static void 616 rstat(Req *r, char *error) 617 { 618 int n; 619 uchar *statbuf; 620 uchar tmp[BIT16SZ]; 621 622 if(error) 623 return; 624 if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){ 625 r->error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ"; 626 return; 627 } 628 n = GBIT16(tmp)+BIT16SZ; 629 statbuf = emalloc9p(n); 630 if(statbuf == nil){ 631 r->error = "out of memory"; 632 return; 633 } 634 r->ofcall.nstat = convD2M(&r->d, statbuf, n); 635 r->ofcall.stat = statbuf; /* freed in closereq */ 636 if(r->ofcall.nstat <= BIT16SZ){ 637 r->error = "convD2M fails"; 638 free(statbuf); 639 return; 640 } 641 } 642 643 static void 644 swstat(Srv *srv, Req *r) 645 { 646 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 647 respond(r, Eunknownfid); 648 return; 649 } 650 if(srv->wstat == nil){ 651 respond(r, Enowstat); 652 return; 653 } 654 if(convM2D(r->ifcall.stat, r->ifcall.nstat, &r->d, (char*)r->ifcall.stat) != r->ifcall.nstat){ 655 respond(r, Ebaddir); 656 return; 657 } 658 if((ushort)~r->d.type){ 659 respond(r, "wstat -- attempt to change type"); 660 return; 661 } 662 if((uint)~r->d.dev){ 663 respond(r, "wstat -- attempt to change dev"); 664 return; 665 } 666 if((uchar)~r->d.qid.type || (ulong)~r->d.qid.vers || (uvlong)~r->d.qid.path){ 667 respond(r, "wstat -- attempt to change qid"); 668 return; 669 } 670 if(r->d.muid && r->d.muid[0]){ 671 respond(r, "wstat -- attempt to change muid"); 672 return; 673 } 674 if((ulong)~r->d.mode && ((r->d.mode&DMDIR)>>24) != (r->fid->qid.type&QTDIR)){ 675 respond(r, "wstat -- attempt to change DMDIR bit"); 676 return; 677 } 678 srv->wstat(r); 679 } 680 static void 681 rwstat(Req*, char*) 682 { 683 } 684 685 void 686 srv(Srv *srv) 687 { 688 Req *r; 689 690 fmtinstall('D', dirfmt); 691 fmtinstall('F', fcallfmt); 692 693 if(srv->fpool == nil) 694 srv->fpool = allocfidpool(srv->destroyfid); 695 if(srv->rpool == nil) 696 srv->rpool = allocreqpool(srv->destroyreq); 697 if(srv->msize == 0) 698 srv->msize = 8192+IOHDRSZ; 699 700 changemsize(srv, srv->msize); 701 702 srv->fpool->srv = srv; 703 srv->rpool->srv = srv; 704 705 while(r = getreq(srv)){ 706 if(r->error){ 707 respond(r, r->error); 708 continue; 709 } 710 switch(r->ifcall.type){ 711 default: 712 respond(r, "unknown message"); 713 break; 714 case Tversion: sversion(srv, r); break; 715 case Tauth: sauth(srv, r); break; 716 case Tattach: sattach(srv, r); break; 717 case Tflush: sflush(srv, r); break; 718 case Twalk: swalk(srv, r); break; 719 case Topen: sopen(srv, r); break; 720 case Tcreate: screate(srv, r); break; 721 case Tread: sread(srv, r); break; 722 case Twrite: swrite(srv, r); break; 723 case Tclunk: sclunk(srv, r); break; 724 case Tremove: sremove(srv, r); break; 725 case Tstat: sstat(srv, r); break; 726 case Twstat: swstat(srv, r); break; 727 } 728 } 729 730 free(srv->rbuf); 731 srv->rbuf = nil; 732 free(srv->wbuf); 733 srv->wbuf = nil; 734 srv->msize = 0; 735 freefidpool(srv->fpool); 736 srv->fpool = nil; 737 freereqpool(srv->rpool); 738 srv->rpool = nil; 739 740 if(srv->end) 741 srv->end(srv); 742 } 743 744 void 745 respond(Req *r, char *error) 746 { 747 int i, m, n; 748 char errbuf[ERRMAX]; 749 Srv *srv; 750 751 srv = r->srv; 752 assert(srv != nil); 753 754 assert(r->responded == 0); 755 r->error = error; 756 757 switch(r->ifcall.type){ 758 default: 759 assert(0); 760 /* 761 * Flush is special. If the handler says so, we return 762 * without further processing. Respond will be called 763 * again once it is safe. 764 */ 765 case Tflush: 766 if(rflush(r, error)<0) 767 return; 768 break; 769 case Tversion: rversion(r, error); break; 770 case Tauth: rauth(r, error); break; 771 case Tattach: rattach(r, error); break; 772 case Twalk: rwalk(r, error); break; 773 case Topen: ropen(r, error); break; 774 case Tcreate: rcreate(r, error); break; 775 case Tread: rread(r, error); break; 776 case Twrite: rwrite(r, error); break; 777 case Tclunk: rclunk(r, error); break; 778 case Tremove: rremove(r, error, errbuf); break; 779 case Tstat: rstat(r, error); break; 780 case Twstat: rwstat(r, error); break; 781 } 782 783 r->ofcall.tag = r->ifcall.tag; 784 r->ofcall.type = r->ifcall.type+1; 785 if(r->error) 786 setfcallerror(&r->ofcall, r->error); 787 788 if(chatty9p) 789 fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall); 790 791 qlock(&srv->wlock); 792 n = convS2M(&r->ofcall, srv->wbuf, srv->msize); 793 if(n <= 0){ 794 fprint(2, "n = %d %F\n", n, &r->ofcall); 795 abort(); 796 } 797 assert(n > 2); 798 if(r->pool) /* not a fake */ 799 closereq(removereq(r->pool, r->ifcall.tag)); 800 m = write(srv->outfd, srv->wbuf, n); 801 if(m != n) 802 sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd); 803 qunlock(&srv->wlock); 804 805 qlock(&r->lk); /* no one will add flushes now */ 806 r->responded = 1; 807 qunlock(&r->lk); 808 809 for(i=0; i<r->nflush; i++) 810 respond(r->flush[i], nil); 811 free(r->flush); 812 r->flush = nil; 813 r->nflush = 0; 814 815 if(r->pool) 816 closereq(r); 817 else 818 free(r); 819 } 820 821 void 822 responderror(Req *r) 823 { 824 char errbuf[ERRMAX]; 825 826 rerrstr(errbuf, sizeof errbuf); 827 respond(r, errbuf); 828 } 829 830 int 831 postfd(char *name, int pfd) 832 { 833 int fd; 834 char buf[80]; 835 836 snprint(buf, sizeof buf, "/srv/%s", name); 837 if(chatty9p) 838 fprint(2, "postfd %s\n", buf); 839 fd = create(buf, OWRITE|ORCLOSE|OCEXEC, 0600); 840 if(fd < 0){ 841 if(chatty9p) 842 fprint(2, "create fails: %r\n"); 843 return -1; 844 } 845 if(fprint(fd, "%d", pfd) < 0){ 846 if(chatty9p) 847 fprint(2, "write fails: %r\n"); 848 close(fd); 849 return -1; 850 } 851 if(chatty9p) 852 fprint(2, "postfd successful\n"); 853 return 0; 854 } 855 856