8 extern char *netdir, *local, *remote;
10 char Ebadfid[] = "Bad fid";
11 char Enotdir[] = "Not a directory";
12 char Edupfid[] = "Fid already in use";
13 char Eopen[] = "Fid already opened";
14 char Exmnt[] = "Cannot .. past mount point";
15 char Emip[] = "Mount in progress";
16 char Enopsmt[] = "Out of pseudo mount points";
17 char Enomem[] = "No memory";
18 char Eversion[] = "Bad 9P2000 version";
19 char Ereadonly[] = "File system read only";
29 if(t->work.msize < 256){
30 reply(&t->work, &rhdr, "version: message size too small");
34 if(t->work.msize > messagesize)
35 t->work.msize = messagesize;
36 messagesize = t->work.msize;
37 if(strncmp(t->work.version, "9P2000", 6) != 0){
38 reply(&t->work, &rhdr, Eversion);
42 rhdr.version = "9P2000";
43 rhdr.msize = t->work.msize;
44 reply(&t->work, &rhdr, 0);
53 reply(&t->work, &rhdr, "exportfs: authentication not required");
63 e = &Workq[Nr_workbufs];
65 for(w = Workq; w < e; w++) {
66 if(w->work.tag == t->work.oldtag) {
67 DEBUG(DFD, "\tQ busy %d pid %p can %d\n", w->busy, w->pid, w->canint);
68 if(w->busy && w->pid) {
69 w->flushtag = t->work.tag;
70 DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
72 postnote(PNPROC, w->pid, "flush");
79 reply(&t->work, &rhdr, 0);
80 DEBUG(DFD, "\tflush reply\n");
92 f = newfid(t->work.fid);
94 reply(&t->work, &rhdr, Ebadfid);
102 reply(&t->work, &rhdr, Enopsmt);
104 freefid(t->work.fid);
107 for(i=0; i<Npsmpt; i++)
112 sprint(buf, "%d", i);
113 f->f = file(psmpt, buf);
116 sprint(buf, "/mnt/exportfs/%d", i);
117 nfd = dup(srvfd, -1);
118 if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
119 errstr(buf, sizeof buf);
120 reply(&t->work, &rhdr, buf);
122 freefid(t->work.fid);
133 rhdr.qid = f->f->qid;
134 reply(&t->work, &rhdr, 0);
139 clonefid(Fid *f, int new)
147 fatal("inconsistent fids");
153 fatal("inconsistent fids2");
163 char err[ERRMAX], *e;
169 f = getfid(t->work.fid);
171 reply(&t->work, &rhdr, Ebadfid);
177 if(t->work.newfid != t->work.fid){
178 nf = clonefid(f, t->work.newfid);
184 for(i=0; i<t->work.nwname; i++){
186 e = "Too many path elements";
190 if(strcmp(t->work.wname[i], "..") == 0) {
191 if(f->f->parent == nil) {
200 wf = file(f->f, t->work.wname[i]);
202 errstr(err, sizeof err);
208 rhdr.wqid[rhdr.nwqid++] = wf->qid;
213 if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
214 freefid(t->work.newfid);
217 reply(&t->work, &rhdr, e);
227 f = getfid(t->work.fid);
229 reply(&t->work, &rhdr, Ebadfid);
237 freefid(t->work.fid);
238 reply(&t->work, &rhdr, 0);
245 char err[ERRMAX], *path;
252 f = getfid(t->work.fid);
254 reply(&t->work, &rhdr, Ebadfid);
259 d = dirfstat(f->fid);
261 path = makepath(f->f, "");
267 errstr(err, sizeof err);
268 reply(&t->work, &rhdr, err);
273 d->qid.path = f->f->qidt->uniqpath;
275 statbuf = emallocz(s);
276 s = convD2M(d, statbuf, s);
280 reply(&t->work, &rhdr, 0);
291 if(n > messagesize-IOHDRSZ)
292 n = messagesize-IOHDRSZ;
299 char err[ERRMAX], *path;
305 reply(&t->work, &rhdr, Ereadonly);
309 f = getfid(t->work.fid);
311 reply(&t->work, &rhdr, Ebadfid);
317 path = makepath(f->f, t->work.name);
318 f->fid = create(path, t->work.mode, t->work.perm);
321 errstr(err, sizeof err);
322 reply(&t->work, &rhdr, err);
327 nf = file(f->f, t->work.name);
329 errstr(err, sizeof err);
330 reply(&t->work, &rhdr, err);
335 f->mode = t->work.mode;
338 rhdr.qid = f->f->qid;
339 rhdr.iounit = getiounit(f->fid);
340 reply(&t->work, &rhdr, 0);
347 char err[ERRMAX], *path;
352 reply(&t->work, &rhdr, Ereadonly);
356 f = getfid(t->work.fid);
358 reply(&t->work, &rhdr, Ebadfid);
363 path = makepath(f->f, "");
364 DEBUG(DFD, "\tremove: %s\n", path);
365 if(remove(path) < 0) {
367 errstr(err, sizeof err);
368 reply(&t->work, &rhdr, err);
377 freefid(t->work.fid);
379 reply(&t->work, &rhdr, 0);
386 char err[ERRMAX], *path;
394 reply(&t->work, &rhdr, Ereadonly);
398 f = getfid(t->work.fid);
400 reply(&t->work, &rhdr, Ebadfid);
404 strings = emallocz(t->work.nstat); /* ample */
405 if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){
406 rerrstr(err, sizeof err);
407 reply(&t->work, &rhdr, err);
414 s = dirfwstat(f->fid, &d);
416 path = makepath(f->f, "");
417 s = dirwstat(path, &d);
421 rerrstr(err, sizeof err);
422 reply(&t->work, &rhdr, err);
425 /* wstat may really be rename */
426 if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
428 f->f->name = estrdup(d.name);
430 reply(&t->work, &rhdr, 0);
437 * based on libthread's threadsetname, but drags in less library code.
438 * actually just sets the arguments displayed.
441 procsetname(char *fmt, ...)
449 cmdname = vsmprint(fmt, arg);
453 snprint(buf, sizeof buf, "#p/%d/args", getpid());
454 if((fd = open(buf, OWRITE)) >= 0){
455 write(fd, cmdname, strlen(cmdname)+1);
470 switch(f->work.type){
472 reply(&f->work, &rhdr, Ereadonly);
476 if((f->work.mode&3) == OWRITE || (f->work.mode&OTRUNC)){
477 reply(&f->work, &rhdr, Ereadonly);
484 for(p = Proclist; p; p = p->next) {
488 pid = (uintptr)rendezvous((void*)p->pid, f);
490 fatal("rendezvous sync fail");
495 if(++nproc > MAXPROC)
496 fatal("too many procs");
498 pid = rfork(RFPROC|RFMEM);
504 if (local[0] != '\0')
505 if (netdir[0] != '\0')
506 procsetname("%s: %s -> %s", netdir,
509 procsetname("%s -> %s", local, remote);
514 p = malloc(sizeof(Proc));
516 fatal("out of memory");
523 rendezvous((void*)pid, p);
540 m = rendezvous((void*)pid, 0);
543 p = rendezvous((void*)pid, (void*)pid);
544 if(p == (void*)~0) /* Interrupted */
547 DEBUG(DFD, "\tslave: %p %F b %d p %p\n", pid, &p->work, p->busy, p->pid);
548 if(p->flushtag != NOTAG)
551 switch(p->work.type) {
565 reply(&p->work, &rhdr, "exportfs: slave type error");
567 if(p->flushtag != NOTAG) {
569 p->work.type = Tflush;
570 p->work.tag = p->flushtag;
571 reply(&p->work, &rhdr, 0);
582 char *arg[10], fdbuf[20], mbuf[20];
588 switch(rfork(RFPROC|RFMEM|RFNOWAIT|RFNAMEG|RFFDG|RFREND)){
606 /* close all remaining file descriptors except sfd */
607 if((fd = open("/fd", OREAD)) < 0)
608 _exits("open /fd failed");
609 n = dirreadall(fd, &dir);
611 if(strstr(dir[i].name, "ctl"))
613 fd = atoi(dir[i].name);
614 if(fd > 2 && fd != sfd)
620 snprint(fdbuf, sizeof fdbuf, "-S/fd/%d", sfd);
622 snprint(mbuf, sizeof mbuf, "-m%lud", messagesize-IOHDRSZ);
626 exec("/bin/exportfs", arg);
627 _exits("whoops: exec failed");
634 char err[ERRMAX], *path;
641 f = getfid(work->fid);
643 reply(work, &rhdr, Ebadfid);
651 path = makepath(f->f, "");
652 DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
655 if(p->flushtag != NOTAG){
659 /* There is a race here I ignore because there are no locks */
660 f->fid = open(path, work->mode);
663 if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
665 errstr(err, sizeof err);
666 reply(work, &rhdr, err);
671 if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */
672 f->fid = openmount(f->fid);
677 DEBUG(DFD, "\topen: fd %d\n", f->fid);
678 f->mode = work->mode;
680 rhdr.iounit = getiounit(f->fid);
681 rhdr.qid = f->f->qid;
682 reply(work, &rhdr, 0);
691 char *data, err[ERRMAX];
695 f = getfid(work->fid);
697 reply(work, &rhdr, Ebadfid);
701 n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
703 if(p->flushtag != NOTAG)
709 /* can't just call pread, since directories must update the offset */
710 if(patternfile != nil && (f->f->qid.type&QTDIR))
711 r = preaddir(f, (uchar*)data, n, work->offset);
713 r = pread(f->fid, data, n, work->offset);
717 errstr(err, sizeof err);
718 reply(work, &rhdr, err);
722 DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
726 reply(work, &rhdr, 0);
740 f = getfid(work->fid);
742 reply(work, &rhdr, Ebadfid);
746 n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
748 if(p->flushtag != NOTAG)
750 n = pwrite(f->fid, work->data, n, work->offset);
753 errstr(err, sizeof err);
754 reply(work, &rhdr, err);
758 DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
761 reply(work, &rhdr, 0);
772 flushaction(void *a, char *cause)
775 if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
776 fprint(2, "exportsrv: note: %s\n", cause);
779 if(strncmp(cause, "kill", 4) == 0)