]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hjfs/9p.c
hjfs: disable shutdown when listening on network connections
[plan9front.git] / sys / src / cmd / hjfs / 9p.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <fcall.h>
5 #include <9p.h>
6 #include "dat.h"
7 #include "fns.h"
8
9 extern Fs *fsmain;
10
11 static void
12 tauth(Req *req)
13 {
14         if((fsmain->flags & FSNOAUTH) != 0)
15                 respond(req, "no authentication required");
16         else
17                 auth9p(req);
18 }
19
20 static void
21 tattach(Req *req)
22 {
23         Chan *ch;
24         int flags;
25         short uid;
26
27         if((fsmain->flags & FSNOAUTH) == 0 && authattach(req) < 0)
28                 return;
29         if(name2uid(fsmain, req->ifcall.uname, &uid) <= 0){
30                 respond(req, "no such user");
31                 return;
32         }
33         if(req->ifcall.aname == nil || *req->ifcall.aname == 0)
34                 flags = 0;
35         else if(strcmp(req->ifcall.aname, "dump") == 0)
36                 flags = CHFDUMP|CHFRO;
37         else{
38                 respond(req, Einval);
39                 return;
40         }
41         ch = chanattach(fsmain, flags);
42         ch->uid = uid;
43         req->fid->aux = ch;
44         req->fid->qid = ch->loc->Qid;
45         req->ofcall.qid = ch->loc->Qid;
46         respond(req, nil);
47 }
48
49 static void
50 tqueue(Req *req)
51 {
52         Chan *ch;
53
54         if((req->fid->qid.type & QTAUTH) != 0){
55                 switch(req->ifcall.type){
56                 case Tread:
57                         authread(req);
58                         return;
59                 case Twrite:
60                         authwrite(req);
61                         return;
62                 default:
63                         respond(req, Einval);
64                         return;
65                 }
66         }
67         ch = req->fid->aux;
68         if(ch == nil){
69                 respond(req, "operation on closed fid");
70                 return;
71         }
72         qlock(&chanqu);
73         req->aux = nil;
74         if(ch->freq == nil)
75                 ch->freq = req;
76         if(ch->lreq != nil)
77                 ((Req *) ch->lreq)->aux = req;
78         ch->lreq = req;
79         if(ch->qnext == nil && (ch->wflags & CHWBUSY) == 0){
80                 ch->qnext = &readych;
81                 ch->qprev = ch->qnext->qprev;
82                 ch->qnext->qprev = ch;
83                 ch->qprev->qnext = ch;
84                 rwakeup(&chanre);
85         }
86         if(req->ifcall.type == Tremove)
87                 req->fid->aux = nil;
88         qunlock(&chanqu);
89 }
90
91 static void
92 tdestroyfid(Fid *fid)
93 {
94         Chan *ch;
95
96         if((fid->qid.type & QTAUTH) != 0){
97                 authdestroy(fid);
98                 return;
99         }
100         qlock(&chanqu);
101         ch = fid->aux;
102         fid->aux = nil;
103         if(ch != nil){
104                 ch->wflags |= CHWCLUNK;
105                 if(ch->qnext == nil && (ch->wflags & CHWBUSY) == 0){
106                         ch->qnext = &readych;
107                         ch->qprev = ch->qnext->qprev;
108                         ch->qnext->qprev = ch;
109                         ch->qprev->qnext = ch;
110                         rwakeup(&chanre);
111                 }
112         }
113         qunlock(&chanqu);
114 }
115
116 static void
117 tend(Srv *)
118 {
119         shutdown();
120 }
121
122 static Srv mysrv = {
123         .auth = tauth,
124         .attach = tattach,
125         .walk = tqueue,
126         .open = tqueue,
127         .create = tqueue,
128         .read = tqueue,
129         .write = tqueue,
130         .stat = tqueue,
131         .wstat = tqueue,
132         .remove = tqueue,
133         .destroyfid = tdestroyfid,
134         .end = tend,
135 };
136
137 void
138 start9p(char *service, char **nets, int stdio)
139 {
140         while(nets && *nets){
141                 mysrv.end = nil;        /* disable shutdown */
142                 threadlistensrv(&mysrv, *nets++);
143         }
144         if(stdio){
145                 mysrv.infd = 1;
146                 mysrv.outfd = 1;
147                 srv(&mysrv);
148         }else
149                 threadpostmountsrv(&mysrv, service, nil, 0);
150 }
151
152 static int
153 twalk(Chan *ch, Fid *fid, Fid *nfid, int n, char **name, Qid *qid)
154 {
155         int i;
156
157         if(nfid != fid){
158                 if(ch->open != 0){
159                         werrstr("trying to clone an open fid");
160                         return -1;
161                 }
162                 ch = chanclone(ch);
163                 if(ch == nil)
164                         return -1;
165                 nfid->aux = ch;
166                 nfid->qid = ch->loc->Qid;
167         }
168         for(i = 0; i < n; i++){
169                 if(chanwalk(ch, name[i]) <= 0)
170                         return i > 0 ? i : -1;
171                 qid[i] = ch->loc->Qid;
172                 nfid->qid = ch->loc->Qid;
173         }
174         return n;
175 }
176
177 static void
178 workerproc(void *)
179 {
180         Chan *ch;
181         Req *req;
182         int rc;
183         Fcall *i, *o;
184
185         qlock(&chanqu);
186         for(;;){
187                 while(readych.qnext == &readych)
188                         rsleep(&chanre);
189                 ch = readych.qnext;
190                 ch->qnext->qprev = ch->qprev;
191                 ch->qprev->qnext = ch->qnext;
192                 ch->qprev = nil;
193                 ch->qnext = nil;
194                 assert((ch->wflags & CHWBUSY) == 0);
195                 ch->wflags |= CHWBUSY;
196                 while(ch != nil && ch->freq != nil){
197                         req = ch->freq;
198                         ch->freq = req->aux;
199                         if(ch->lreq == req)
200                                 ch->lreq = nil;
201                         req->aux = nil;
202                         qunlock(&chanqu);
203                         assert(req->responded == 0);
204                         i = &req->ifcall;
205                         o = &req->ofcall;
206                         switch(req->ifcall.type){
207                         case Twalk:
208                                 rc = twalk(ch, req->fid, req->newfid, i->nwname, i->wname, o->wqid);
209                                 if(rc >= 0)
210                                         o->nwqid = rc;
211                                 break;
212                         case Topen:
213                                 rc = chanopen(ch, i->mode);
214                                 break;
215                         case Tcreate:
216                                 rc = chancreat(ch, i->name, i->perm, i->mode);
217                                 if(rc >= 0){
218                                         o->qid = ch->loc->Qid;
219                                         req->fid->qid = o->qid;
220                                 }
221                                 break;
222                         case Tread:
223                                 rc = o->count = chanread(ch, o->data, i->count, i->offset);
224                                 break;
225                         case Twrite:
226                                 rc = o->count = chanwrite(ch, i->data, i->count, i->offset);
227                                 break;
228                         case Tremove:
229                                 rc = chanremove(ch);
230                                 req->fid->aux = ch = nil;
231                                 break;
232                         case Tstat:
233                                 rc = chanstat(ch, &req->d);
234                                 break;
235                         case Twstat:
236                                 rc = chanwstat(ch, &req->d);
237                                 break;
238                         default:
239                                 werrstr(Einval);
240                                 rc = -1;
241                         }
242                         if(rc < 0)
243                                 responderror(req);
244                         else
245                                 respond(req, nil);
246                         qlock(&chanqu);
247                 }
248                 if(ch != nil){
249                         ch->wflags &= ~CHWBUSY;
250                         if((ch->wflags & CHWCLUNK) != 0)
251                                 chanclunk(ch);
252                 }
253         }
254 }
255
256 QLock chanqu;
257 Chan readych;
258 Rendez chanre;
259
260 void
261 workerinit(void)
262 {
263         int i;
264         
265         readych.qnext = readych.qprev = &readych;
266         chanre.l = &chanqu;
267         for(i = 0; i < NWORKERS; i++)
268                 threadcreate(workerproc, nil, mainstacksize);
269 }