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";
20 char Enoprocs[] = "Out of processes";
30 if(t->work.msize < 256){
31 reply(&t->work, &rhdr, "version: message size too small");
35 if(t->work.msize > messagesize)
36 t->work.msize = messagesize;
37 messagesize = t->work.msize;
38 if(strncmp(t->work.version, "9P2000", 6) != 0){
39 reply(&t->work, &rhdr, Eversion);
43 rhdr.version = "9P2000";
44 rhdr.msize = t->work.msize;
45 reply(&t->work, &rhdr, 0);
54 reply(&t->work, &rhdr, "exportfs: authentication not required");
65 for(m = Proclist; m != nil; m = m->next){
67 if(w == nil || w->work.tag != t->work.oldtag)
72 if(w != nil && w->work.tag == t->work.oldtag) {
73 w->flushtag = t->work.tag;
74 DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
75 postnote(PNPROC, m->pid, "flush");
83 reply(&t->work, &rhdr, 0);
84 DEBUG(DFD, "\tflush reply\n");
96 f = newfid(t->work.fid);
98 reply(&t->work, &rhdr, Ebadfid);
106 reply(&t->work, &rhdr, Enopsmt);
107 freefid(t->work.fid);
111 for(i=0; i<Npsmpt; i++)
116 sprint(buf, "%d", i);
117 f->f = file(psmpt, buf);
120 sprint(buf, "/mnt/exportfs/%d", i);
121 nfd = dup(srvfd, -1);
122 if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
123 errstr(buf, sizeof buf);
124 reply(&t->work, &rhdr, buf);
125 freefid(t->work.fid);
137 rhdr.qid = f->f->qid;
138 reply(&t->work, &rhdr, 0);
143 clonefid(Fid *f, int new)
151 fatal("inconsistent fids");
157 fatal("inconsistent fids2");
167 char err[ERRMAX], *e;
173 f = getfid(t->work.fid);
175 reply(&t->work, &rhdr, Ebadfid);
181 if(t->work.newfid != t->work.fid){
182 nf = clonefid(f, t->work.newfid);
188 for(i=0; i<t->work.nwname; i++){
190 e = "Too many path elements";
194 if(strcmp(t->work.wname[i], "..") == 0) {
195 if(f->f->parent == nil) {
204 wf = file(f->f, t->work.wname[i]);
206 errstr(err, sizeof err);
212 rhdr.wqid[rhdr.nwqid++] = wf->qid;
217 if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
218 freefid(t->work.newfid);
221 reply(&t->work, &rhdr, e);
231 f = getfid(t->work.fid);
233 reply(&t->work, &rhdr, Ebadfid);
241 freefid(t->work.fid);
242 reply(&t->work, &rhdr, 0);
249 char err[ERRMAX], *path;
256 f = getfid(t->work.fid);
258 reply(&t->work, &rhdr, Ebadfid);
263 d = dirfstat(f->fid);
265 path = makepath(f->f, "");
271 errstr(err, sizeof err);
272 reply(&t->work, &rhdr, err);
277 d->qid.path = f->f->qidt->uniqpath;
279 statbuf = emallocz(s);
280 s = convD2M(d, statbuf, s);
284 reply(&t->work, &rhdr, 0);
295 if(n > messagesize-IOHDRSZ)
296 n = messagesize-IOHDRSZ;
303 char err[ERRMAX], *path;
309 reply(&t->work, &rhdr, Ereadonly);
313 f = getfid(t->work.fid);
315 reply(&t->work, &rhdr, Ebadfid);
321 path = makepath(f->f, t->work.name);
322 f->fid = create(path, t->work.mode, t->work.perm);
325 errstr(err, sizeof err);
326 reply(&t->work, &rhdr, err);
331 nf = file(f->f, t->work.name);
333 errstr(err, sizeof err);
334 reply(&t->work, &rhdr, err);
339 f->mode = t->work.mode;
342 rhdr.qid = f->f->qid;
343 rhdr.iounit = getiounit(f->fid);
344 reply(&t->work, &rhdr, 0);
351 char err[ERRMAX], *path;
356 reply(&t->work, &rhdr, Ereadonly);
360 f = getfid(t->work.fid);
362 reply(&t->work, &rhdr, Ebadfid);
367 path = makepath(f->f, "");
368 DEBUG(DFD, "\tremove: %s\n", path);
369 if(remove(path) < 0) {
371 errstr(err, sizeof err);
372 reply(&t->work, &rhdr, err);
381 freefid(t->work.fid);
383 reply(&t->work, &rhdr, 0);
390 char err[ERRMAX], *path;
398 reply(&t->work, &rhdr, Ereadonly);
402 f = getfid(t->work.fid);
404 reply(&t->work, &rhdr, Ebadfid);
408 strings = emallocz(t->work.nstat); /* ample */
409 if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){
410 rerrstr(err, sizeof err);
411 reply(&t->work, &rhdr, err);
418 s = dirfwstat(f->fid, &d);
420 path = makepath(f->f, "");
421 s = dirwstat(path, &d);
425 rerrstr(err, sizeof err);
426 reply(&t->work, &rhdr, err);
429 /* wstat may really be rename */
430 if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
432 f->f->name = estrdup(d.name);
434 reply(&t->work, &rhdr, 0);
441 * based on libthread's threadsetname, but drags in less library code.
442 * actually just sets the arguments displayed.
445 procsetname(char *fmt, ...)
453 cmdname = vsmprint(fmt, arg);
457 snprint(buf, sizeof buf, "#p/%d/args", getpid());
458 if((fd = open(buf, OWRITE)) >= 0){
459 write(fd, cmdname, strlen(cmdname)+1);
474 switch(f->work.type){
476 reply(&f->work, &rhdr, Ereadonly);
480 if((f->work.mode&3) == OWRITE || (f->work.mode&(OTRUNC|ORCLOSE))){
481 reply(&f->work, &rhdr, Ereadonly);
488 for(l = &Proclist; (m = *l) != nil; l = &m->next) {
493 while(rendezvous(m, f) == (void*)~0)
496 /* swept a slave proc */
506 * as long as the number of slave procs
507 * is small, dont bother sweeping.
515 m = emallocz(sizeof(Proc));
516 pid = rfork(RFPROC|RFMEM|RFNOWAIT);
519 reply(&f->work, &rhdr, Enoprocs);
525 if (local[0] != '\0')
526 if (netdir[0] != '\0')
527 procsetname("%s: %s -> %s", netdir,
530 procsetname("%s -> %s", local, remote);
544 blockingslave(Proc *m)
552 p = rendezvous(m, nil);
553 if(p == (void*)~0) /* Interrupted */
555 if(p == nil) /* Swept */
558 DEBUG(DFD, "\tslave: %d %F\n", m->pid, &p->work);
559 if(p->flushtag != NOTAG)
562 switch(p->work.type) {
576 reply(&p->work, &rhdr, "exportfs: slave type error");
583 /* no more flushes can come in now */
584 if(p->flushtag != NOTAG) {
585 p->work.type = Tflush;
586 p->work.tag = p->flushtag;
587 reply(&p->work, &rhdr, 0);
597 char *arg[10], fdbuf[20], mbuf[20];
603 switch(rfork(RFPROC|RFMEM|RFNOWAIT|RFNAMEG|RFFDG|RFREND)){
621 /* close all remaining file descriptors except sfd */
622 if((fd = open("/fd", OREAD)) < 0)
623 _exits("open /fd failed");
624 n = dirreadall(fd, &dir);
626 if(strstr(dir[i].name, "ctl"))
628 fd = atoi(dir[i].name);
629 if(fd > 2 && fd != sfd)
634 arg[0] = argv0; /* "/bin/exportfs" */
635 snprint(fdbuf, sizeof fdbuf, "-S/fd/%d", sfd);
637 snprint(mbuf, sizeof mbuf, "-m%lud", messagesize-IOHDRSZ);
642 arg[0] = "/bin/exportfs";
644 _exits("whoops: exec failed");
651 char err[ERRMAX], *path;
658 f = getfid(work->fid);
660 reply(work, &rhdr, Ebadfid);
668 path = makepath(f->f, "");
669 DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
670 f->fid = open(path, work->mode);
672 if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
674 errstr(err, sizeof err);
675 reply(work, &rhdr, err);
680 if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */
681 f->fid = openmount(f->fid);
686 DEBUG(DFD, "\topen: fd %d\n", f->fid);
687 f->mode = work->mode;
689 rhdr.iounit = getiounit(f->fid);
690 rhdr.qid = f->f->qid;
691 reply(work, &rhdr, 0);
700 char *data, err[ERRMAX];
704 f = getfid(work->fid);
706 reply(work, &rhdr, Ebadfid);
710 n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
713 reply(work, &rhdr, Enomem);
717 /* can't just call pread, since directories must update the offset */
718 if(patternfile != nil && (f->f->qid.type&QTDIR))
719 r = preaddir(f, (uchar*)data, n, work->offset);
721 r = pread(f->fid, data, n, work->offset);
724 errstr(err, sizeof err);
725 reply(work, &rhdr, err);
728 DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
732 reply(work, &rhdr, 0);
746 f = getfid(work->fid);
748 reply(work, &rhdr, Ebadfid);
752 n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
753 n = pwrite(f->fid, work->data, n, work->offset);
755 errstr(err, sizeof err);
756 reply(work, &rhdr, err);
760 DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
763 reply(work, &rhdr, 0);
774 flushaction(void *a, char *cause)
777 if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
778 fprint(2, "exportsrv: note: %s\n", cause);
781 if(strncmp(cause, "kill", 4) == 0)