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