]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hjfs/9p.c
renamed statw to df
[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, int stdio)
139 {
140         if(stdio){
141                 mysrv.infd = 1;
142                 mysrv.outfd = 1;
143                 srv(&mysrv);
144         }else
145                 threadpostmountsrv(&mysrv, service, nil, 0);
146 }
147
148 static int
149 twalk(Chan *ch, Fid *fid, Fid *nfid, int n, char **name, Qid *qid)
150 {
151         int i;
152
153         if(nfid != fid){
154                 if(ch->open != 0){
155                         werrstr("trying to clone an open fid");
156                         return -1;
157                 }
158                 ch = chanclone(ch);
159                 if(ch == nil)
160                         return -1;
161                 nfid->aux = ch;
162                 nfid->qid = ch->loc->Qid;
163         }
164         for(i = 0; i < n; i++){
165                 if(chanwalk(ch, name[i]) <= 0)
166                         return i > 0 ? i : -1;
167                 qid[i] = ch->loc->Qid;
168                 nfid->qid = ch->loc->Qid;
169         }
170         return n;
171 }
172
173 static void
174 workerproc(void *)
175 {
176         Chan *ch;
177         Req *req;
178         int rc;
179         Fcall *i, *o;
180
181         qlock(&chanqu);
182         for(;;){
183                 while(readych.qnext == &readych)
184                         rsleep(&chanre);
185                 ch = readych.qnext;
186                 ch->qnext->qprev = ch->qprev;
187                 ch->qprev->qnext = ch->qnext;
188                 ch->qprev = nil;
189                 ch->qnext = nil;
190                 assert((ch->wflags & CHWBUSY) == 0);
191                 ch->wflags |= CHWBUSY;
192                 while(ch != nil && ch->freq != nil){
193                         req = ch->freq;
194                         ch->freq = req->aux;
195                         if(ch->lreq == req)
196                                 ch->lreq = nil;
197                         req->aux = nil;
198                         qunlock(&chanqu);
199                         assert(req->responded == 0);
200                         i = &req->ifcall;
201                         o = &req->ofcall;
202                         switch(req->ifcall.type){
203                         case Twalk:
204                                 rc = twalk(ch, req->fid, req->newfid, i->nwname, i->wname, o->wqid);
205                                 if(rc >= 0)
206                                         o->nwqid = rc;
207                                 break;
208                         case Topen:
209                                 rc = chanopen(ch, i->mode);
210                                 break;
211                         case Tcreate:
212                                 rc = chancreat(ch, i->name, i->perm, i->mode);
213                                 if(rc >= 0){
214                                         o->qid = ch->loc->Qid;
215                                         req->fid->qid = o->qid;
216                                 }
217                                 break;
218                         case Tread:
219                                 rc = o->count = chanread(ch, o->data, i->count, i->offset);
220                                 break;
221                         case Twrite:
222                                 rc = o->count = chanwrite(ch, i->data, i->count, i->offset);
223                                 break;
224                         case Tremove:
225                                 rc = chanremove(ch);
226                                 req->fid->aux = ch = nil;
227                                 break;
228                         case Tstat:
229                                 rc = chanstat(ch, &req->d);
230                                 break;
231                         case Twstat:
232                                 rc = chanwstat(ch, &req->d);
233                                 break;
234                         default:
235                                 werrstr(Einval);
236                                 rc = -1;
237                         }
238                         if(rc < 0)
239                                 responderror(req);
240                         else
241                                 respond(req, nil);
242                         qlock(&chanqu);
243                 }
244                 if(ch != nil){
245                         ch->wflags &= ~CHWBUSY;
246                         if((ch->wflags & CHWCLUNK) != 0)
247                                 chanclunk(ch);
248                 }
249         }
250 }
251
252 QLock chanqu;
253 Chan readych;
254 Rendez chanre;
255
256 void
257 workerinit(void)
258 {
259         int i;
260         
261         readych.qnext = readych.qprev = &readych;
262         chanre.l = &chanqu;
263         for(i = 0; i < NWORKERS; i++)
264                 threadcreate(workerproc, nil, mainstacksize);
265 }