]> git.lizzy.rs Git - plan9front.git/blob - sys/src/lib9p/srv.c
merge
[plan9front.git] / sys / src / lib9p / srv.c
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 *srv, Req *r)
167 {
168         if(srv->rref.ref != 2){
169                 respond(r, Ebotch);
170                 return;
171         }
172         if(strncmp(r->ifcall.version, "9P", 2) != 0){
173                 r->ofcall.version = "unknown";
174                 respond(r, nil);
175                 return;
176         }
177         r->ofcall.version = "9P2000";
178         if(r->ifcall.msize < 256){
179                 respond(r, "version: message size too small");
180                 return;
181         }
182         if(r->ifcall.msize < 1024*1024)
183                 r->ofcall.msize = r->ifcall.msize;
184         else
185                 r->ofcall.msize = 1024*1024;
186         respond(r, nil);
187 }
188
189 static void
190 rversion(Req *r, char *error)
191 {
192         if(error == nil)
193                 changemsize(r->srv, r->ofcall.msize);
194 }
195
196 static void
197 sauth(Srv *srv, Req *r)
198 {
199         char e[ERRMAX];
200
201         if((r->afid = allocfid(srv->fpool, r->ifcall.afid)) == nil){
202                 respond(r, Edupfid);
203                 return;
204         }
205         if(srv->auth)
206                 srv->auth(r);
207         else{
208                 snprint(e, sizeof e, "%s: authentication not required", argv0);
209                 respond(r, e);
210         }
211 }
212 static void
213 rauth(Req *r, char *error)
214 {
215         if(error && r->afid)
216                 closefid(removefid(r->srv->fpool, r->afid->fid));
217 }
218
219 static void
220 sattach(Srv *srv, Req *r)
221 {
222         if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){
223                 respond(r, Edupfid);
224                 return;
225         }
226         r->afid = nil;
227         if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){
228                 respond(r, Eunknownfid);
229                 return;
230         }
231         r->fid->uid = estrdup9p(r->ifcall.uname);
232         if(srv->tree){
233                 r->fid->file = srv->tree->root;
234                 incref(r->fid->file);
235                 r->ofcall.qid = r->fid->file->qid;
236                 r->fid->qid = r->ofcall.qid;
237         }
238         if(srv->attach)
239                 srv->attach(r);
240         else
241                 respond(r, nil);
242         return;
243 }
244 static void
245 rattach(Req *r, char *error)
246 {
247         if(error && r->fid)
248                 closefid(removefid(r->srv->fpool, r->fid->fid));
249 }
250
251 static void
252 sflush(Srv *srv, Req *r)
253 {
254         r->oldreq = lookupreq(srv->rpool, r->ifcall.oldtag);
255         if(r->oldreq == nil || r->oldreq == r)
256                 respond(r, nil);
257         else if(srv->flush)
258                 srv->flush(r);
259         else
260                 respond(r, nil);
261 }
262 static int
263 rflush(Req *r, char *error)
264 {
265         Req *or;
266
267         assert(error == nil);
268         or = r->oldreq;
269         if(or){
270                 qlock(&or->lk);
271                 if(or->responded == 0){
272                         or->flush = erealloc9p(or->flush, (or->nflush+1)*sizeof(or->flush[0]));
273                         or->flush[or->nflush++] = r;
274                         qunlock(&or->lk);
275                         return -1;              /* delay response until or is responded */
276                 }
277                 qunlock(&or->lk);
278                 closereq(or);
279         }
280         r->oldreq = nil;
281         return 0;
282 }
283
284 static char*
285 oldwalk1(Fid *fid, char *name, void *arg)
286 {
287         char *e;
288         Qid qid;
289         Srv *srv;
290
291         srv = arg;
292         e = srv->walk1(fid, name, &qid);
293         if(e)
294                 return e;
295         fid->qid = qid;
296         return nil;
297 }
298
299 static char*
300 oldclone(Fid *fid, Fid *newfid, void *arg)
301 {
302         Srv *srv;
303
304         srv = arg;
305         if(srv->clone == nil)
306                 return nil;
307         return srv->clone(fid, newfid);
308 }
309
310 static void
311 swalk(Srv *srv, Req *r)
312 {
313         if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
314                 respond(r, Eunknownfid);
315                 return;
316         }
317         if(r->fid->omode != -1){
318                 respond(r, "cannot clone open fid");
319                 return;
320         }
321         if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){
322                 respond(r, Ewalknodir);
323                 return;
324         }
325         if(r->ifcall.fid != r->ifcall.newfid){
326                 if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){
327                         respond(r, Edupfid);
328                         return;
329                 }
330                 r->newfid->uid = estrdup9p(r->fid->uid);
331         }else{
332                 incref(&r->fid->ref);
333                 r->newfid = r->fid;
334         }
335         if(r->fid->file){
336                 filewalk(r);
337         }else if(srv->walk1)
338                 walkandclone(r, oldwalk1, oldclone, srv);
339         else if(srv->walk)
340                 srv->walk(r);
341         else
342                 sysfatal("no walk function, no file trees");
343 }
344 static void
345 rwalk(Req *r, char *error)
346 {
347         if(error || r->ofcall.nwqid < r->ifcall.nwname){
348                 if(r->ifcall.fid != r->ifcall.newfid && r->newfid)
349                         closefid(removefid(r->srv->fpool, r->newfid->fid));
350                 if (r->ofcall.nwqid==0){
351                         if(error==nil && r->ifcall.nwname!=0)
352                                 r->error = Enotfound;
353                 }else
354                         r->error = nil; // No error on partial walks
355         }else{
356                 if(r->ofcall.nwqid == 0){
357                         /* Just a clone */
358                         r->newfid->qid = r->fid->qid;
359                 }else{
360                         /* if file trees are in use, filewalk took care of the rest */
361                         r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1];
362                 }
363         }
364 }
365
366 static void
367 sopen(Srv *srv, Req *r)
368 {
369         int p;
370
371         if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
372                 respond(r, Eunknownfid);
373                 return;
374         }
375         if(r->fid->omode != -1){
376                 respond(r, Ebotch);
377                 return;
378         }
379         if((r->fid->qid.type&QTDIR) && (r->ifcall.mode&~ORCLOSE) != OREAD){
380                 respond(r, Eisdir);
381                 return;
382         }
383         r->ofcall.qid = r->fid->qid;
384         switch(r->ifcall.mode&3){
385         default:
386                 assert(0);
387         case OREAD:
388                 p = AREAD;      
389                 break;
390         case OWRITE:
391                 p = AWRITE;
392                 break;
393         case ORDWR:
394                 p = AREAD|AWRITE;
395                 break;
396         case OEXEC:
397                 p = AEXEC;      
398                 break;
399         }
400         if(r->ifcall.mode&OTRUNC)
401                 p |= AWRITE;
402         if((r->fid->qid.type&QTDIR) && p!=AREAD){
403                 respond(r, Eperm);
404                 return;
405         }
406         if(r->fid->file){
407                 if(!hasperm(r->fid->file, r->fid->uid, p)){
408                         respond(r, Eperm);
409                         return;
410                 }
411         /* BUG RACE */
412                 if((r->ifcall.mode&ORCLOSE)
413                 && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
414                         respond(r, Eperm);
415                         return;
416                 }
417                 r->ofcall.qid = r->fid->file->qid;
418                 if((r->ofcall.qid.type&QTDIR)
419                 && (r->fid->rdir = opendirfile(r->fid->file)) == nil){
420                         respond(r, "opendirfile failed");
421                         return;
422                 }
423         }
424         if(srv->open)
425                 srv->open(r);
426         else
427                 respond(r, nil);
428 }
429 static void
430 ropen(Req *r, char *error)
431 {
432         char errbuf[ERRMAX];
433         if(error)
434                 return;
435         if(chatty9p){
436                 snprint(errbuf, sizeof errbuf, "fid mode is 0x%ux\n", r->ifcall.mode);
437                 write(2, errbuf, strlen(errbuf));
438         }
439         r->fid->omode = r->ifcall.mode;
440         r->fid->qid = r->ofcall.qid;
441         if(r->ofcall.qid.type&QTDIR)
442                 r->fid->diroffset = 0;
443 }
444
445 static void
446 screate(Srv *srv, Req *r)
447 {
448         if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil)
449                 respond(r, Eunknownfid);
450         else if(r->fid->omode != -1)
451                 respond(r, Ebotch);
452         else if(!(r->fid->qid.type&QTDIR))
453                 respond(r, Ecreatenondir);
454         else if(r->fid->file && !hasperm(r->fid->file, r->fid->uid, AWRITE))
455                 respond(r, Eperm);
456         else if(srv->create)
457                 srv->create(r);
458         else
459                 respond(r, Enocreate);
460 }
461 static void
462 rcreate(Req *r, char *error)
463 {
464         if(error)
465                 return;
466         r->fid->omode = r->ifcall.mode;
467         r->fid->qid = r->ofcall.qid;
468 }
469
470 static void
471 sread(Srv *srv, Req *r)
472 {
473         int o;
474
475         if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
476                 respond(r, Eunknownfid);
477                 return;
478         }
479         if((int)r->ifcall.count < 0){
480                 respond(r, Ebotch);
481                 return;
482         }
483         if(r->ifcall.offset < 0
484         || ((r->fid->qid.type&QTDIR) && r->ifcall.offset != 0 && r->ifcall.offset != r->fid->diroffset)){
485                 respond(r, Ebadoffset);
486                 return;
487         }
488
489         if(r->ifcall.count > srv->msize - IOHDRSZ)
490                 r->ifcall.count = srv->msize - IOHDRSZ;
491         r->rbuf = emalloc9p(r->ifcall.count);
492         r->ofcall.data = r->rbuf;
493         o = r->fid->omode & 3;
494         if(o != OREAD && o != ORDWR && o != OEXEC){
495                 respond(r, Ebotch);
496                 return;
497         }
498         if((r->fid->qid.type&QTDIR) && r->fid->file){
499                 r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count);
500                 respond(r, nil);
501                 return;
502         }
503         if(srv->read)
504                 srv->read(r);
505         else
506                 respond(r, "no srv->read");
507 }
508 static void
509 rread(Req *r, char *error)
510 {
511         if(error==nil && (r->fid->qid.type&QTDIR))
512                 r->fid->diroffset += r->ofcall.count;
513 }
514
515 static void
516 swrite(Srv *srv, Req *r)
517 {
518         int o;
519         char e[ERRMAX];
520
521         if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
522                 respond(r, Eunknownfid);
523                 return;
524         }
525         if((int)r->ifcall.count < 0){
526                 respond(r, Ebotch);
527                 return;
528         }
529         if(r->ifcall.offset < 0){
530                 respond(r, Ebotch);
531                 return;
532         }
533         if(r->ifcall.count > srv->msize - IOHDRSZ)
534                 r->ifcall.count = srv->msize - IOHDRSZ;
535         o = r->fid->omode & 3;
536         if(o != OWRITE && o != ORDWR){
537                 snprint(e, sizeof e, "write on fid with open mode 0x%ux", r->fid->omode);
538                 respond(r, e);
539                 return;
540         }
541         if(srv->write)
542                 srv->write(r);
543         else
544                 respond(r, "no srv->write");
545 }
546 static void
547 rwrite(Req *r, char *error)
548 {
549         if(error)
550                 return;
551         if(r->fid->file)
552                 r->fid->file->qid.vers++;
553 }
554
555 static void
556 sclunk(Srv *srv, Req *r)
557 {
558         if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil)
559                 respond(r, Eunknownfid);
560         else
561                 respond(r, nil);
562 }
563 static void
564 rclunk(Req*, char*)
565 {
566 }
567
568 static void
569 sremove(Srv *srv, Req *r)
570 {
571         if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil){
572                 respond(r, Eunknownfid);
573                 return;
574         }
575         /* BUG RACE */
576         if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
577                 respond(r, Eperm);
578                 return;
579         }
580         if(srv->remove)
581                 srv->remove(r);
582         else
583                 respond(r, r->fid->file ? nil : Enoremove);
584 }
585 static void
586 rremove(Req *r, char *error, char *errbuf)
587 {
588         if(error)
589                 return;
590         if(r->fid->file){
591                 if(removefile(r->fid->file) < 0){
592                         snprint(errbuf, ERRMAX, "remove %s: %r", 
593                                 r->fid->file->name);
594                         r->error = errbuf;
595                 }
596                 r->fid->file = nil;
597         }
598 }
599
600 static void
601 sstat(Srv *srv, Req *r)
602 {
603         if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
604                 respond(r, Eunknownfid);
605                 return;
606         }
607         if(r->fid->file){
608                 /* should we rlock the file? */
609                 r->d = r->fid->file->Dir;
610                 if(r->d.name)
611                         r->d.name = estrdup9p(r->d.name);
612                 if(r->d.uid)
613                         r->d.uid = estrdup9p(r->d.uid);
614                 if(r->d.gid)
615                         r->d.gid = estrdup9p(r->d.gid);
616                 if(r->d.muid)
617                         r->d.muid = estrdup9p(r->d.muid);
618         }
619         if(srv->stat)   
620                 srv->stat(r);   
621         else if(r->fid->file)
622                 respond(r, nil);
623         else
624                 respond(r, Enostat);
625 }
626 static void
627 rstat(Req *r, char *error)
628 {
629         int n;
630         uchar *statbuf;
631         uchar tmp[BIT16SZ];
632
633         if(error)
634                 return;
635         if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){
636                 r->error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ";
637                 return;
638         }
639         n = GBIT16(tmp)+BIT16SZ;
640         statbuf = emalloc9p(n);
641         if(statbuf == nil){
642                 r->error = "out of memory";
643                 return;
644         }
645         r->ofcall.nstat = convD2M(&r->d, statbuf, n);
646         r->ofcall.stat = statbuf;       /* freed in closereq */
647         if(r->ofcall.nstat <= BIT16SZ){
648                 r->error = "convD2M fails";
649                 free(statbuf);
650                 return;
651         }
652 }
653
654 static void
655 swstat(Srv *srv, Req *r)
656 {
657         if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
658                 respond(r, Eunknownfid);
659                 return;
660         }
661         if(srv->wstat == nil){
662                 respond(r, Enowstat);
663                 return;
664         }
665         if(convM2D(r->ifcall.stat, r->ifcall.nstat, &r->d, (char*)r->ifcall.stat) != r->ifcall.nstat){
666                 respond(r, Ebaddir);
667                 return;
668         }
669         if((ushort)~r->d.type){
670                 respond(r, "wstat -- attempt to change type");
671                 return;
672         }
673         if((uint)~r->d.dev){
674                 respond(r, "wstat -- attempt to change dev");
675                 return;
676         }
677         if((uchar)~r->d.qid.type || (ulong)~r->d.qid.vers || (uvlong)~r->d.qid.path){
678                 respond(r, "wstat -- attempt to change qid");
679                 return;
680         }
681         if(r->d.muid && r->d.muid[0]){
682                 respond(r, "wstat -- attempt to change muid");
683                 return;
684         }
685         if((ulong)~r->d.mode && ((r->d.mode&DMDIR)>>24) != (r->fid->qid.type&QTDIR)){
686                 respond(r, "wstat -- attempt to change DMDIR bit");
687                 return;
688         }
689         srv->wstat(r);
690 }
691 static void
692 rwstat(Req*, char*)
693 {
694 }
695
696 static void srvclose(Srv *);
697
698 static void
699 srvwork(void *v)
700 {
701         Srv *srv = v;
702         Req *r;
703
704         incref(&srv->rref);
705         incref(&srv->sref);
706         while(r = getreq(srv)){
707                 incref(&srv->rref);
708                 if(r->error){
709                         respond(r, r->error);
710                         continue;       
711                 }
712                 qlock(&srv->slock);
713                 switch(r->ifcall.type){
714                 default:
715                         respond(r, "unknown message");
716                         break;
717                 case Tversion:  sversion(srv, r);       break;
718                 case Tauth:     sauth(srv, r);  break;
719                 case Tattach:   sattach(srv, r);        break;
720                 case Tflush:    sflush(srv, r); break;
721                 case Twalk:     swalk(srv, r);  break;
722                 case Topen:     sopen(srv, r);  break;
723                 case Tcreate:   screate(srv, r);        break;
724                 case Tread:     sread(srv, r);  break;
725                 case Twrite:    swrite(srv, r); break;
726                 case Tclunk:    sclunk(srv, r); break;
727                 case Tremove:   sremove(srv, r);        break;
728                 case Tstat:     sstat(srv, r);  break;
729                 case Twstat:    swstat(srv, r); break;
730                 }
731                 qunlock(&srv->slock);
732         }
733         decref(&srv->sref);
734         srvclose(srv);
735 }
736
737 static void
738 srvclose(Srv *srv)
739 {
740         if(decref(&srv->rref))
741                 return;
742
743         if(chatty9p)
744                 fprint(2, "srvclose\n");
745
746         free(srv->rbuf);
747         srv->rbuf = nil;
748         free(srv->wbuf);
749         srv->wbuf = nil;
750         srv->msize = 0;
751         freefidpool(srv->fpool);
752         srv->fpool = nil;
753         freereqpool(srv->rpool);
754         srv->rpool = nil;
755
756         if(srv->end)
757                 srv->end(srv);
758 }
759
760 void
761 srvacquire(Srv *srv)
762 {
763         incref(&srv->sref);
764         qlock(&srv->slock);
765 }
766
767 void
768 srvrelease(Srv *srv)
769 {
770         if(decref(&srv->sref) == 0)
771                 _forker(srvwork, srv, 0);
772         qunlock(&srv->slock);
773 }
774
775 void
776 srv(Srv *srv)
777 {
778         fmtinstall('D', dirfmt);
779         fmtinstall('F', fcallfmt);
780
781         srv->sref.ref = 0;
782         srv->rref.ref = 0;
783
784         if(srv->fpool == nil)
785                 srv->fpool = allocfidpool(srv->destroyfid);
786         if(srv->rpool == nil)
787                 srv->rpool = allocreqpool(srv->destroyreq);
788         if(srv->msize == 0)
789                 srv->msize = 8192+IOHDRSZ;
790
791         changemsize(srv, srv->msize);
792
793         srv->fpool->srv = srv;
794         srv->rpool->srv = srv;
795
796         if(srv->start)
797                 srv->start(srv);
798
799         srvwork(srv);
800 }
801
802 void
803 respond(Req *r, char *error)
804 {
805         int i, m, n;
806         char errbuf[ERRMAX];
807         Srv *srv;
808
809         srv = r->srv;
810         assert(srv != nil);
811
812         assert(r->responded == 0);
813         r->error = error;
814
815         switch(r->ifcall.type){
816         /*
817          * Flush is special.  If the handler says so, we return
818          * without further processing.  Respond will be called
819          * again once it is safe.
820          */
821         case Tflush:
822                 if(rflush(r, error)<0)
823                         return;
824                 break;
825         case Tversion:  rversion(r, error);     break;
826         case Tauth:     rauth(r, error);        break;
827         case Tattach:   rattach(r, error);      break;
828         case Twalk:     rwalk(r, error);        break;
829         case Topen:     ropen(r, error);        break;
830         case Tcreate:   rcreate(r, error);      break;
831         case Tread:     rread(r, error);        break;
832         case Twrite:    rwrite(r, error);       break;
833         case Tclunk:    rclunk(r, error);       break;
834         case Tremove:   rremove(r, error, errbuf);      break;
835         case Tstat:     rstat(r, error);        break;
836         case Twstat:    rwstat(r, error);       break;
837         }
838
839         r->ofcall.tag = r->ifcall.tag;
840         r->ofcall.type = r->ifcall.type+1;
841         if(r->error)
842                 setfcallerror(&r->ofcall, r->error);
843
844 if(chatty9p)
845         fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);
846
847         qlock(&srv->wlock);
848         n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
849         if(n <= 0){
850                 fprint(2, "msize = %d n = %d %F\n", srv->msize, n, &r->ofcall);
851                 abort();
852         }
853         assert(n > 2);
854         if(r->pool)     /* not a fake */
855                 closereq(removereq(r->pool, r->ifcall.tag));
856         m = write(srv->outfd, srv->wbuf, n);
857         if(m != n)
858                 fprint(2, "lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
859         qunlock(&srv->wlock);
860
861         qlock(&r->lk);  /* no one will add flushes now */
862         r->responded = 1;
863         qunlock(&r->lk);
864
865         for(i=0; i<r->nflush; i++)
866                 respond(r->flush[i], nil);
867         free(r->flush);
868         r->flush = nil;
869         r->nflush = 0;
870
871         if(r->pool)
872                 closereq(r);
873         else
874                 free(r);
875
876         srvclose(srv);
877 }
878
879 void
880 responderror(Req *r)
881 {
882         char errbuf[ERRMAX];
883         
884         rerrstr(errbuf, sizeof errbuf);
885         respond(r, errbuf);
886 }
887
888 int
889 postfd(char *name, int pfd)
890 {
891         int fd;
892         char buf[80];
893
894         snprint(buf, sizeof buf, "/srv/%s", name);
895         if(chatty9p)
896                 fprint(2, "postfd %s\n", buf);
897         fd = create(buf, OWRITE|ORCLOSE|OCEXEC, 0600);
898         if(fd < 0){
899                 if(chatty9p)
900                         fprint(2, "create fails: %r\n");
901                 return -1;
902         }
903         if(fprint(fd, "%d", pfd) < 0){
904                 if(chatty9p)
905                         fprint(2, "write fails: %r\n");
906                 close(fd);
907                 return -1;
908         }
909         if(chatty9p)
910                 fprint(2, "postfd successful\n");
911         return 0;
912 }
913
914 int
915 sharefd(char *name, char *desc, int pfd)
916 {
917         int fd;
918         char buf[80];
919
920         snprint(buf, sizeof buf, "#σc/%s", name);
921         if((fd = create(buf, OREAD, 0700|DMDIR)) >= 0)
922                 close(fd);
923         snprint(buf, sizeof buf, "#σc/%s/%s", name, desc);
924         if(chatty9p)
925                 fprint(2, "sharefd %s\n", buf);
926         fd = create(buf, OWRITE, 0600);
927         if(fd < 0){
928                 if(chatty9p)
929                         fprint(2, "create fails: %r\n");
930                 return -1;
931         }
932         if(fprint(fd, "%d\n", pfd) < 0){
933                 if(chatty9p)
934                         fprint(2, "write fails: %r\n");
935                 close(fd);
936                 return -1;
937         }
938         close(fd);
939         if(chatty9p)
940                 fprint(2, "sharefd successful\n");
941         return 0;
942 }