1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #define Extern extern
5 #include "exportfs.h"
6
7 char Ebadfid[] = "Bad fid";
8 char Enotdir[] = "Not a directory";
9 char Edupfid[] = "Fid already in use";
10 char Eopen[] = "Fid already opened";
11 char Exmnt[] = "Cannot .. past mount point";
12 char Emip[] = "Mount in progress";
13 char Enopsmt[] = "Out of pseudo mount points";
14 char Enomem[] = "No memory";
15 char Eversion[] = "Bad 9P2000 version";
16
iounit(int x)17 int iounit(int x)
18 {
19 return 8*8192+IOHDRSZ;
20 }
21
22 void*
emallocz(ulong n)23 emallocz(ulong n)
24 {
25 void *v;
26
27 v = mallocz(n, 1);
28 if(v == nil)
29 panic("out of memory");
30 return v;
31 }
32
33
34 void
Xversion(Fsrpc * t)35 Xversion(Fsrpc *t)
36 {
37 Fcall rhdr;
38
39 if(t->work.msize > messagesize)
40 t->work.msize = messagesize;
41 messagesize = t->work.msize;
42 if(strncmp(t->work.version, "9P2000", 6) != 0){
43 reply(&t->work, &rhdr, Eversion);
44 return;
45 }
46 rhdr.version = "9P2000";
47 rhdr.msize = t->work.msize;
48 reply(&t->work, &rhdr, 0);
49 t->busy = 0;
50 }
51
52 void
Xauth(Fsrpc * t)53 Xauth(Fsrpc *t)
54 {
55 Fcall rhdr;
56
57 reply(&t->work, &rhdr, "exportfs: authentication not required");
58 t->busy = 0;
59 }
60
61 void
Xflush(Fsrpc * t)62 Xflush(Fsrpc *t)
63 {
64 Fsrpc *w, *e;
65 Fcall rhdr;
66
67 e = &Workq[Nr_workbufs];
68
69 for(w = Workq; w < e; w++) {
70 if(w->work.tag == t->work.oldtag) {
71 DEBUG(DFD, "\tQ busy %d pid %d can %d\n", w->busy, w->pid, w->canint);
72 if(w->busy && w->pid) {
73 w->flushtag = t->work.tag;
74 DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
75 // if(w->canint)
76 // postnote(PNPROC, w->pid, "flush");
77 t->busy = 0;
78 return;
79 }
80 }
81 }
82
83 reply(&t->work, &rhdr, 0);
84 DEBUG(DFD, "\tflush reply\n");
85 t->busy = 0;
86 }
87
88 void
Xattach(Fsrpc * t)89 Xattach(Fsrpc *t)
90 {
91 Fcall rhdr;
92 Fid *f;
93
94 f = newfid(t->work.fid);
95 if(f == 0) {
96 reply(&t->work, &rhdr, Ebadfid);
97 t->busy = 0;
98 return;
99 }
100
101 if(srvfd >= 0){
102 /*
103 if(psmpt == 0){
104 Nomount:
105 reply(&t->work, &rhdr, Enopsmt);
106 t->busy = 0;
107 freefid(t->work.fid);
108 return;
109 }
110 for(i=0; i<Npsmpt; i++)
111 if(psmap[i] == 0)
112 break;
113 if(i >= Npsmpt)
114 goto Nomount;
115 sprint(buf, "%d", i);
116 f->f = file(psmpt, buf);
117 if(f->f == nil)
118 goto Nomount;
119 sprint(buf, "/mnt/exportfs/%d", i);
120 nfd = dup(srvfd, -1);
121 if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
122 errstr(buf, sizeof buf);
123 reply(&t->work, &rhdr, buf);
124 t->busy = 0;
125 freefid(t->work.fid);
126 close(nfd);
127 return;
128 }
129 psmap[i] = 1;
130 f->mid = i;
131 */
132 }else{
133 f->f = root;
134 f->f->ref++;
135 }
136
137 rhdr.qid = f->f->qid;
138 reply(&t->work, &rhdr, 0);
139 t->busy = 0;
140 }
141
142 Fid*
clonefid(Fid * f,int new)143 clonefid(Fid *f, int new)
144 {
145 Fid *n;
146
147 n = newfid(new);
148 if(n == 0) {
149 n = getfid(new);
150 if(n == 0)
151 fatal("inconsistent fids");
152 if(n->fid >= 0)
153 close(n->fid);
154 freefid(new);
155 n = newfid(new);
156 if(n == 0)
157 fatal("inconsistent fids2");
158 }
159 n->f = f->f;
160 n->f->ref++;
161 return n;
162 }
163
164 void
Xwalk(Fsrpc * t)165 Xwalk(Fsrpc *t)
166 {
167 char err[ERRMAX], *e;
168 Fcall rhdr;
169 Fid *f, *nf;
170 File *wf;
171 int i;
172
173 f = getfid(t->work.fid);
174 if(f == 0) {
175 reply(&t->work, &rhdr, Ebadfid);
176 t->busy = 0;
177 return;
178 }
179
180 nf = nil;
181 if(t->work.newfid != t->work.fid){
182 nf = clonefid(f, t->work.newfid);
183 f = nf;
184 }
185
186 rhdr.nwqid = 0;
187 e = nil;
188 for(i=0; i<t->work.nwname; i++){
189 if(i == MAXWELEM){
190 e = "Too many path elements";
191 break;
192 }
193
194 if(strcmp(t->work.wname[i], "..") == 0) {
195 if(f->f->parent == nil) {
196 e = Exmnt;
197 break;
198 }
199 wf = f->f->parent;
200 wf->ref++;
201 goto Accept;
202 }
203
204 wf = file(f->f, t->work.wname[i]);
205 if(wf == 0){
206 errstr(err, sizeof err);
207 e = err;
208 break;
209 }
210 Accept:
211 freefile(f->f);
212 rhdr.wqid[rhdr.nwqid++] = wf->qid;
213 f->f = wf;
214 continue;
215 }
216
217 if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
218 freefid(t->work.newfid);
219 if(rhdr.nwqid > 0)
220 e = nil;
221 reply(&t->work, &rhdr, e);
222 t->busy = 0;
223 }
224
225 void
Xclunk(Fsrpc * t)226 Xclunk(Fsrpc *t)
227 {
228 Fcall rhdr;
229 Fid *f;
230
231 f = getfid(t->work.fid);
232 if(f == 0) {
233 reply(&t->work, &rhdr, Ebadfid);
234 t->busy = 0;
235 return;
236 }
237
238 if(f->fid >= 0)
239 close(f->fid);
240
241 freefid(t->work.fid);
242 reply(&t->work, &rhdr, 0);
243 t->busy = 0;
244 }
245
246 void
Xstat(Fsrpc * t)247 Xstat(Fsrpc *t)
248 {
249 char err[ERRMAX], *path;
250 Fcall rhdr;
251 Fid *f;
252 Dir *d;
253 int s;
254 uchar *statbuf;
255
256 f = getfid(t->work.fid);
257 if(f == 0) {
258 reply(&t->work, &rhdr, Ebadfid);
259 t->busy = 0;
260 return;
261 }
262 if(f->fid >= 0)
263 d = dirfstat(f->fid);
264 else {
265 path = makepath(f->f, "");
266 d = dirstat(path);
267 free(path);
268 }
269
270 if(d == nil) {
271 errstr(err, sizeof err);
272 reply(&t->work, &rhdr, err);
273 t->busy = 0;
274 return;
275 }
276
277 d->qid.path = f->f->qidt->uniqpath;
278 s = sizeD2M(d);
279 statbuf = emallocz(s);
280 s = convD2M(d, statbuf, s);
281 free(d);
282 rhdr.nstat = s;
283 rhdr.stat = statbuf;
284 reply(&t->work, &rhdr, 0);
285 free(statbuf);
286 t->busy = 0;
287 }
288
289 static int
getiounit(int fd)290 getiounit(int fd)
291 {
292 int n;
293
294 n = iounit(fd);
295 if(n > messagesize-IOHDRSZ)
296 n = messagesize-IOHDRSZ;
297 return n;
298 }
299
300 void
Xcreate(Fsrpc * t)301 Xcreate(Fsrpc *t)
302 {
303 char err[ERRMAX], *path;
304 Fcall rhdr;
305 Fid *f;
306 File *nf;
307
308 f = getfid(t->work.fid);
309 if(f == 0) {
310 reply(&t->work, &rhdr, Ebadfid);
311 t->busy = 0;
312 return;
313 }
314
315
316 path = makepath(f->f, t->work.name);
317 f->fid = create(path, t->work.mode, t->work.perm);
318 free(path);
319 if(f->fid < 0) {
320 errstr(err, sizeof err);
321 reply(&t->work, &rhdr, err);
322 t->busy = 0;
323 return;
324 }
325
326 nf = file(f->f, t->work.name);
327 if(nf == 0) {
328 errstr(err, sizeof err);
329 reply(&t->work, &rhdr, err);
330 t->busy = 0;
331 return;
332 }
333
334 f->mode = t->work.mode;
335 freefile(f->f);
336 f->f = nf;
337 rhdr.qid = f->f->qid;
338 rhdr.iounit = getiounit(f->fid);
339 reply(&t->work, &rhdr, 0);
340 t->busy = 0;
341 }
342
343 void
Xremove(Fsrpc * t)344 Xremove(Fsrpc *t)
345 {
346 char err[ERRMAX], *path;
347 Fcall rhdr;
348 Fid *f;
349
350 f = getfid(t->work.fid);
351 if(f == 0) {
352 reply(&t->work, &rhdr, Ebadfid);
353 t->busy = 0;
354 return;
355 }
356
357 path = makepath(f->f, "");
358 DEBUG(DFD, "\tremove: %s\n", path);
359 if(remove(path) < 0) {
360 free(path);
361 errstr(err, sizeof err);
362 reply(&t->work, &rhdr, err);
363 t->busy = 0;
364 return;
365 }
366 free(path);
367
368 f->f->inval = 1;
369 if(f->fid >= 0)
370 close(f->fid);
371 freefid(t->work.fid);
372
373 reply(&t->work, &rhdr, 0);
374 t->busy = 0;
375 }
376
377 void
Xwstat(Fsrpc * t)378 Xwstat(Fsrpc *t)
379 {
380 char err[ERRMAX], *path;
381 Fcall rhdr;
382 Fid *f;
383 int s;
384 char *strings;
385 Dir d;
386
387 f = getfid(t->work.fid);
388 if(f == 0) {
389 reply(&t->work, &rhdr, Ebadfid);
390 t->busy = 0;
391 return;
392 }
393 strings = emallocz(t->work.nstat); /* ample */
394 if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){
395 rerrstr(err, sizeof err);
396 reply(&t->work, &rhdr, err);
397 t->busy = 0;
398 free(strings);
399 return;
400 }
401
402 if(f->fid >= 0)
403 s = dirfwstat(f->fid, &d);
404 else {
405 path = makepath(f->f, "");
406 s = dirwstat(path, &d);
407 free(path);
408 }
409 if(s < 0) {
410 rerrstr(err, sizeof err);
411 reply(&t->work, &rhdr, err);
412 }
413 else {
414 /* wstat may really be rename */
415 if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
416 free(f->f->name);
417 f->f->name = estrdup(d.name);
418 }
419 reply(&t->work, &rhdr, 0);
420 }
421 free(strings);
422 t->busy = 0;
423 }
424
425 void
slave(Fsrpc * f)426 slave(Fsrpc *f)
427 {
428 Proc *p;
429 int pid;
430 static int nproc;
431
432 for(;;) {
433 for(p = Proclist; p; p = p->next) {
434 if(p->busy == 0) {
435 f->pid = p->pid;
436 p->busy = 1;
437 pid = (uintptr)rendezvous((void*)(uintptr)p->pid, f);
438 if(pid != p->pid)
439 fatal("rendezvous sync fail");
440 return;
441 }
442 }
443
444 if(++nproc > MAXPROC)
445 fatal("too many procs");
446
447 pid = kproc("slave", blockingslave, nil);
448 DEBUG(DFD, "slave pid %d\n", pid);
449 if(pid == -1)
450 fatal("kproc");
451
452 p = malloc(sizeof(Proc));
453 if(p == 0)
454 fatal("out of memory");
455
456 p->busy = 0;
457 p->pid = pid;
458 p->next = Proclist;
459 Proclist = p;
460
461 DEBUG(DFD, "parent %d rendez\n", pid);
462 rendezvous((void*)(uintptr)pid, p);
463 DEBUG(DFD, "parent %d went\n", pid);
464 }
465 }
466
467 void
blockingslave(void * x)468 blockingslave(void *x)
469 {
470 Fsrpc *p;
471 Fcall rhdr;
472 Proc *m;
473 int pid;
474
475 USED(x);
476
477 notify(flushaction);
478
479 pid = getpid();
480
481 DEBUG(DFD, "blockingslave %d rendez\n", pid);
482 m = (Proc*)rendezvous((void*)(uintptr)pid, 0);
483 DEBUG(DFD, "blockingslave %d rendez got %p\n", pid, m);
484
485 for(;;) {
486 p = rendezvous((void*)(uintptr)pid, (void*)(uintptr)pid);
487 if((uintptr)p == ~(uintptr)0) /* Interrupted */
488 continue;
489
490 DEBUG(DFD, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid);
491 if(p->flushtag != NOTAG)
492 goto flushme;
493
494 switch(p->work.type) {
495 case Tread:
496 slaveread(p);
497 break;
498
499 case Twrite:
500 slavewrite(p);
501 break;
502
503 case Topen:
504 slaveopen(p);
505 break;
506
507 default:
508 reply(&p->work, &rhdr, "exportfs: slave type error");
509 }
510 if(p->flushtag != NOTAG) {
511 flushme:
512 p->work.type = Tflush;
513 p->work.tag = p->flushtag;
514 reply(&p->work, &rhdr, 0);
515 }
516 p->busy = 0;
517 m->busy = 0;
518 }
519 }
520
521 int
openmount(int sfd)522 openmount(int sfd)
523 {
524 werrstr("openmount not implemented");
525 return -1;
526 }
527
528 void
slaveopen(Fsrpc * p)529 slaveopen(Fsrpc *p)
530 {
531 char err[ERRMAX], *path;
532 Fcall *work, rhdr;
533 Fid *f;
534 Dir *d;
535
536 work = &p->work;
537
538 f = getfid(work->fid);
539 if(f == 0) {
540 reply(work, &rhdr, Ebadfid);
541 return;
542 }
543 if(f->fid >= 0) {
544 close(f->fid);
545 f->fid = -1;
546 }
547
548 path = makepath(f->f, "");
549 DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
550
551 p->canint = 1;
552 if(p->flushtag != NOTAG){
553 free(path);
554 return;
555 }
556 /* There is a race here I ignore because there are no locks */
557 f->fid = open(path, work->mode);
558 free(path);
559 p->canint = 0;
560 if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
561 Error:
562 errstr(err, sizeof err);
563 reply(work, &rhdr, err);
564 return;
565 }
566 f->f->qid = d->qid;
567 free(d);
568 if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */
569 f->fid = openmount(f->fid);
570 if(f->fid < 0)
571 goto Error;
572 }
573
574 DEBUG(DFD, "\topen: fd %d\n", f->fid);
575 f->mode = work->mode;
576 rhdr.iounit = getiounit(f->fid);
577 rhdr.qid = f->f->qid;
578 reply(work, &rhdr, 0);
579 }
580
581 void
slaveread(Fsrpc * p)582 slaveread(Fsrpc *p)
583 {
584 Fid *f;
585 int n, r;
586 Fcall *work, rhdr;
587 char *data, err[ERRMAX];
588
589 work = &p->work;
590
591 f = getfid(work->fid);
592 if(f == 0) {
593 reply(work, &rhdr, Ebadfid);
594 return;
595 }
596
597 n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
598 p->canint = 1;
599 if(p->flushtag != NOTAG)
600 return;
601 data = malloc(n);
602 if(data == nil)
603 fatal(Enomem);
604
605 /* can't just call pread, since directories must update the offset */
606 r = pread(f->fid, data, n, work->offset);
607 p->canint = 0;
608 if(r < 0) {
609 free(data);
610 errstr(err, sizeof err);
611 reply(work, &rhdr, err);
612 return;
613 }
614
615 DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
616
617 rhdr.data = data;
618 rhdr.count = r;
619 reply(work, &rhdr, 0);
620 free(data);
621 }
622
623 void
slavewrite(Fsrpc * p)624 slavewrite(Fsrpc *p)
625 {
626 char err[ERRMAX];
627 Fcall *work, rhdr;
628 Fid *f;
629 int n;
630
631 work = &p->work;
632
633 f = getfid(work->fid);
634 if(f == 0) {
635 reply(work, &rhdr, Ebadfid);
636 return;
637 }
638
639 n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
640 p->canint = 1;
641 if(p->flushtag != NOTAG)
642 return;
643 n = pwrite(f->fid, work->data, n, work->offset);
644 p->canint = 0;
645 if(n < 0) {
646 errstr(err, sizeof err);
647 reply(work, &rhdr, err);
648 return;
649 }
650
651 DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
652
653 rhdr.count = n;
654 reply(work, &rhdr, 0);
655 }
656
657 void
reopen(Fid * f)658 reopen(Fid *f)
659 {
660 USED(f);
661 fatal("reopen");
662 }
663
664 void
flushaction(void * a,char * cause)665 flushaction(void *a, char *cause)
666 {
667 USED(a);
668 if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
669 fprint(2, "exportsrv: note: %s\n", cause);
670 exits("noted");
671 }
672 if(strncmp(cause, "kill", 4) == 0)
673 noted(NDFLT);
674
675 noted(NCONT);
676 }
677