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
setfcallerror(Fcall * f,char * err)31 setfcallerror(Fcall *f, char *err)
32 {
33 f->ename = err;
34 f->type = Rerror;
35 }
36
37 static void
changemsize(Srv * srv,int msize)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*
getreq(Srv * s)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
filewalk(Req * r)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
walkandclone(Req * r,char * (* walk1)(Fid *,char *,void *),char * (* clone)(Fid *,Fid *,void *),void * arg)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
sversion(Srv *,Req * r)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
rversion(Req * r,char * error)179 rversion(Req *r, char *error)
180 {
181 assert(error == nil);
182 changemsize(r->srv, r->ofcall.msize);
183 }
184
185 static void
sauth(Srv * srv,Req * r)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
rauth(Req * r,char * error)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
sattach(Srv * srv,Req * r)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
rattach(Req * r,char * error)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
sflush(Srv * srv,Req * r)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
rflush(Req * r,char * error)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*
oldwalk1(Fid * fid,char * name,void * arg)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*
oldclone(Fid * fid,Fid * newfid,void * arg)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
swalk(Srv * srv,Req * r)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
rwalk(Req * r,char * error)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
sopen(Srv * srv,Req * r)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
ropen(Req * r,char * error)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
screate(Srv * srv,Req * r)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
rcreate(Req * r,char * error)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
sread(Srv * srv,Req * r)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
rread(Req * r,char * error)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
swrite(Srv * srv,Req * r)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
rwrite(Req * r,char * error)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
sclunk(Srv * srv,Req * r)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
rclunk(Req *,char *)553 rclunk(Req*, char*)
554 {
555 }
556
557 static void
sremove(Srv * srv,Req * r)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
rremove(Req * r,char * error,char * errbuf)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
sstat(Srv * srv,Req * r)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
rstat(Req * r,char * error)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
swstat(Srv * srv,Req * r)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
rwstat(Req *,char *)681 rwstat(Req*, char*)
682 {
683 }
684
685 void
srv(Srv * srv)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
respond(Req * r,char * error)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
responderror(Req * r)822 responderror(Req *r)
823 {
824 char errbuf[ERRMAX];
825
826 rerrstr(errbuf, sizeof errbuf);
827 respond(r, errbuf);
828 }
829
830 int
postfd(char * name,int pfd)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