1 #include "dat.h"
2 #include "fns.h"
3 #include "error.h"
4
5 typedef struct Srv Srv;
6 struct Srv
7 {
8 Ref;
9 int fd; /* fd for opened /srv or /srv/X, or -1 */
10 int sfd; /* fd for created /srv entry or -1 */
11 uvlong path;
12 Srv *next;
13 };
14
15 static QLock srv9lk;
16 static Srv *srv9;
17 static Srv *srvroot;
18
19 static char*
srvname(Chan * c)20 srvname(Chan *c)
21 {
22 char *p;
23
24 p = strrchr(c->name->s, '/');
25 if(p == nil)
26 return "";
27 return p+1;
28 }
29
30 static Srv*
srvget(uvlong path)31 srvget(uvlong path)
32 {
33 Srv *sv;
34
35 qlock(&srv9lk);
36 for(sv = srv9; sv != nil; sv = sv->next)
37 if(sv->path == path){
38 incref(sv);
39 qunlock(&srv9lk);
40 return sv;
41 }
42 sv = smalloc(sizeof(*sv));
43 sv->path = path;
44 sv->fd = -1;
45 sv->sfd = -1;
46 sv->ref = 1;
47 sv->next = srv9;
48 srv9 = sv;
49 qunlock(&srv9lk);
50 return sv;
51 }
52
53 static void
srvput(Srv * sv)54 srvput(Srv *sv)
55 {
56 Srv **l;
57 int fd, sfd;
58
59 if(sv != nil && decref(sv) == 0){
60 qlock(&srv9lk);
61 for(l = &srv9; *l != nil; l = &(*l)->next)
62 if(*l == sv){
63 *l = sv->next;
64 break;
65 }
66 qunlock(&srv9lk);
67 fd = sv->fd;
68 sfd = sv->sfd;
69 free(sv);
70 if(sfd >= 0){
71 osenter();
72 close(sfd);
73 osleave();
74 }
75 if(fd >= 0){
76 osenter();
77 close(fd);
78 osleave();
79 }
80 }
81 }
82
83 static void
srv9init(void)84 srv9init(void)
85 {
86 Srv *sv;
87
88 sv = mallocz(sizeof(*srvroot), 1);
89 sv->path = 0;
90 sv->fd = -1;
91 sv->ref = 1; /* subsequently never reaches zero */
92 srvroot = srv9 = sv;
93 }
94
95 static Chan*
srv9attach(char * spec)96 srv9attach(char *spec)
97 {
98 Chan *c;
99
100 if(*spec)
101 error(Ebadspec);
102 c = devattach(L'₪', spec);
103 if(c != nil){
104 incref(srvroot);
105 c->aux = srvroot;
106 }
107 return c;
108 }
109
110 static Walkqid*
srv9walk(Chan * c,Chan * nc,char ** name,int nname)111 srv9walk(Chan *c, Chan *nc, char **name, int nname)
112 {
113 int j, alloc;
114 Walkqid *wq;
115 char *n;
116 Dir *d;
117
118 if(nname > 0)
119 isdir(c);
120
121 alloc = 0;
122 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
123 if(waserror()){
124 if(alloc)
125 cclose(wq->clone);
126 free(wq);
127 return nil;
128 }
129 if(nc == nil){
130 nc = devclone(c);
131 nc->type = 0; /* device doesn't know about this channel yet */
132 alloc = 1;
133 }
134 wq->clone = nc;
135
136 for(j=0; j<nname; j++){
137 if(!(nc->qid.type&QTDIR)){
138 if(j==0)
139 error(Enotdir);
140 break;
141 }
142 n = name[j];
143 if(strcmp(n, ".") != 0 && strcmp(n, "..") != 0){
144 snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", n);
145 d = dirstat(up->genbuf);
146 if(d == nil){
147 if(j == 0)
148 error(Enonexist);
149 kstrcpy(up->env->errstr, Enonexist, ERRMAX);
150 break;
151 }
152 nc->qid = d->qid;
153 free(d);
154 }
155 wq->qid[wq->nqid++] = nc->qid;
156 }
157 poperror();
158 if(wq->nqid < nname){
159 if(alloc)
160 cclose(wq->clone);
161 wq->clone = nil;
162 }else{
163 /* attach cloned channel to device */
164 wq->clone->type = c->type;
165 if(wq->clone != c)
166 nc->aux = srvget(nc->qid.path);
167 }
168 return wq;
169 }
170
171 static int
srv9stat(Chan * c,uchar * db,int n)172 srv9stat(Chan *c, uchar *db, int n)
173 {
174 Srv *sv;
175 Dir d;
176
177 if(c->qid.type & QTDIR){
178 devdir(c, c->qid, "#₪", 0, eve, 0775, &d);
179 n = convD2M(&d, db, n);
180 if(n == 0)
181 error(Eshortstat);
182 return n;
183 }
184 sv = c->aux;
185 if(sv->fd >= 0){
186 osenter();
187 n = fstat(sv->fd, db, n);
188 osleave();
189 }else{
190 osenter();
191 n = stat(srvname(c), db, n);
192 osleave();
193 }
194 return n;
195 }
196
197 static Chan*
srv9open(Chan * c,int omode)198 srv9open(Chan *c, int omode)
199 {
200 Srv *sv;
201 char *args[10];
202 int fd[2], i, ifd, is9p;
203 Dir *d;
204
205 sv = c->aux;
206 if(c->qid.type == QTDIR){
207 osenter();
208 sv->fd = open("/srv", omode);
209 osleave();
210 if(sv->fd < 0)
211 oserror();
212 c->mode = omode;
213 c->flag |= COPEN;
214 c->offset = 0;
215 return c;
216 }
217
218 if(omode&OTRUNC || openmode(omode) != ORDWR)
219 error(Eperm);
220 if(sv->fd < 0){
221 snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", srvname(c));
222
223 /* check permission */
224 osenter();
225 ifd = open(up->genbuf, omode);
226 osleave();
227 if(ifd < 0)
228 oserror();
229 osenter();
230 d = dirfstat(ifd);
231 is9p = d != nil && d->qid.type & QTMOUNT;
232 free(d);
233 osleave();
234
235 if(is9p){
236 close(ifd);
237
238 /* spawn exportfs */
239 args[0] = "exportfs";
240 args[1] = "-S";
241 args[2] = up->genbuf;
242 args[3] = nil;
243 if(pipe(fd) < 0)
244 oserror();
245 /* TO DO: without RFMEM there's a copy made of each page touched by any kproc until the exec */
246 switch(rfork(RFPROC|RFNOWAIT|RFREND|RFFDG|RFNAMEG|RFENVG)){ /* no sharing except NOTEG */
247 case -1:
248 oserrstr(up->genbuf, sizeof(up->genbuf));
249 close(fd[0]);
250 close(fd[1]);
251 error(up->genbuf);
252 case 0:
253 for(i=3; i<MAXNFD; i++)
254 if(i != fd[1])
255 close(i);
256 dup(fd[1], 0);
257 if(fd[0] != 0)
258 close(fd[0]);
259 dup(0, 1);
260 exec("/bin/exportfs", args);
261 exits("exportfs failed");
262 default:
263 sv->fd = fd[0];
264 close(fd[1]);
265 break;
266 }
267 }else
268 sv->fd = ifd;
269 }
270
271 c->mode = ORDWR;
272 c->offset = 0;
273 c->flag |= COPEN;
274 return c;
275 }
276
277 static void
srv9close(Chan * c)278 srv9close(Chan *c)
279 {
280 srvput(c->aux);
281 }
282
283 static long
srv9read(Chan * c,void * va,long n,vlong off)284 srv9read(Chan *c, void *va, long n, vlong off)
285 {
286 Srv *sv;
287
288 sv = c->aux;
289 osenter();
290 n = pread(sv->fd, va, n, off);
291 osleave();
292 if(n < 0)
293 oserror();
294 return n;
295 }
296
297 static long
srv9write(Chan * c,void * va,long n,vlong off)298 srv9write(Chan *c, void *va, long n, vlong off)
299 {
300 Srv *sv;
301
302 sv = c->aux;
303 osenter();
304 n = pwrite(sv->fd, va, n, off);
305 osleave();
306 if(n == 0)
307 error(Ehungup);
308 if(n < 0)
309 oserror();
310 return n;
311 }
312
313 static void
srv9create(Chan * c,char * name,int omode,ulong perm)314 srv9create(Chan *c, char *name, int omode, ulong perm)
315 {
316 Srv *sv;
317 int sfd, fd[2];
318 vlong path;
319 Dir *d;
320
321 if(openmode(omode) != ORDWR)
322 error(Eperm);
323
324 if(pipe(fd) < 0)
325 oserror();
326 if(waserror()){
327 close(fd[0]);
328 close(fd[1]);
329 nexterror();
330 }
331
332 snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", name);
333 osenter();
334 sfd = create(up->genbuf, OWRITE|ORCLOSE, perm);
335 osleave();
336 if(sfd < 0)
337 oserror();
338 if(waserror()){
339 close(sfd);
340 nexterror();
341 }
342 osenter();
343 if(fprint(sfd, "%d", fd[1]) < 0){
344 osleave();
345 oserror();
346 }
347 d = dirfstat(sfd);
348 osleave();
349 if(d != nil){
350 path = d->qid.path;
351 free(d);
352 }else
353 oserror();
354
355 poperror();
356 poperror();
357 close(fd[1]);
358
359 if(waserror()){
360 close(sfd);
361 close(fd[0]);
362 nexterror();
363 }
364 sv = srvget(path);
365 sv->fd = fd[0];
366 sv->sfd = sfd;
367 poperror();
368
369 srvput((Srv*)c->aux);
370 c->qid.type = QTFILE;
371 c->qid.path = path;
372 c->aux = sv;
373 c->flag |= COPEN;
374 c->mode = ORDWR;
375 c->offset = 0;
376 }
377
378 Dev srv9devtab = {
379 L'₪',
380 "srv9",
381
382 srv9init,
383 srv9attach,
384 srv9walk,
385 srv9stat,
386 srv9open,
387 srv9create, /* TO DO */
388 srv9close,
389 srv9read,
390 devbread,
391 srv9write,
392 devbwrite,
393 devremove, /* TO DO */
394 devwstat, /* TO DO */
395 };
396