History

add exportfs to help modify the system limits (butters, procs, etc.)

John (EBo) David committed 15 years ago

Commit bf4c1ea1 parent 64d3cde7 files · +2025 −2Browse files

Unified · Split

7 files
  1. sys/src/cmd/exportfs/exportfs.c +937 −0
  2. sys/src/cmd/exportfs/exportfs.h +144 −0
  3. sys/src/cmd/exportfs/exportsrv.c +764 −0
  4. sys/src/cmd/exportfs/mkfile +18 −0
  5. sys/src/cmd/exportfs/pattern.c +154 −0
  6. sys/src/cmd/uem/tests/bg_256.rc +5 −1
  7. sys/src/cmd/uem/tests/pbg_4.rc +3 −1
sys/src/cmd/exportfs/exportfs.c+937−0
@@ -0,0 +1,937 @@
1+/*
2+ * exportfs - Export a plan 9 name space across a network
3+ */
4+#include <u.h>
5+#include <libc.h>
6+#include <auth.h>
7+#include <fcall.h>
8+#include <libsec.h>
9+#define Extern
10+#include "exportfs.h"
11+
12+#define QIDPATH ((1LL<<48)-1)
13+vlong newqid = 0;
14+
15+enum {
16+ Encnone,
17+ Encssl,
18+ Enctls,
19+};
20+
21+void (*fcalls[])(Fsrpc*) =
22+{
23+ [Tversion] Xversion,
24+ [Tauth] Xauth,
25+ [Tflush] Xflush,
26+ [Tattach] Xattach,
27+ [Twalk] Xwalk,
28+ [Topen] slave,
29+ [Tcreate] Xcreate,
30+ [Tclunk] Xclunk,
31+ [Tread] slave,
32+ [Twrite] slave,
33+ [Tremove] Xremove,
34+ [Tstat] Xstat,
35+ [Twstat] Xwstat,
36+};
37+
38+/* accounting and debugging counters */
39+int filecnt;
40+int freecnt;
41+int qidcnt;
42+int qfreecnt;
43+int ncollision;
44+
45+int netfd; /* initially stdin */
46+int srvfd = -1;
47+int nonone = 1;
48+char *filterp;
49+char *ealgs = "rc4_256 sha1";
50+char *aanfilter = "/bin/aan";
51+int encproto = Encnone;
52+int readonly;
53+
54+static void mksecret(char *, uchar *);
55+static int localread9pmsg(int, void *, uint, ulong *);
56+static char *anstring = "tcp!*!0";
57+
58+char *netdir = "", *local = "", *remote = "";
59+
60+int filter(int, char *);
61+
62+void
63+usage(void)
64+{
65+ fprint(2, "usage: %s [-adnsR] [-f dbgfile] [-m msize] [-r root] "
66+ "[-S srvfile] [-e 'crypt hash'] [-P exclusion-file] "
67+ "[-A announce-string] [-B address]\n", argv0);
68+ fatal("usage");
69+}
70+
71+static void
72+noteconn(int fd)
73+{
74+ NetConnInfo *nci;
75+
76+ nci = getnetconninfo(nil, fd);
77+ if (nci == nil)
78+ return;
79+ netdir = strdup(nci->dir);
80+ local = strdup(nci->lsys);
81+ remote = strdup(nci->rsys);
82+ freenetconninfo(nci);
83+}
84+
85+void
86+main(int argc, char **argv)
87+{
88+ char buf[ERRMAX], ebuf[ERRMAX], *srvfdfile;
89+ Fsrpc *r;
90+ int doauth, n, fd;
91+ char *dbfile, *srv, *na, *nsfile, *keyspec;
92+ AuthInfo *ai;
93+ ulong initial;
94+
95+ dbfile = "/tmp/exportdb";
96+ srv = nil;
97+ srvfd = -1;
98+ srvfdfile = nil;
99+ na = nil;
100+ nsfile = nil;
101+ keyspec = "";
102+ doauth = 0;
103+
104+ ai = nil;
105+ ARGBEGIN{
106+ case 'a':
107+ doauth = 1;
108+ break;
109+
110+ case 'd':
111+ dbg++;
112+ break;
113+
114+ case 'e':
115+ ealgs = EARGF(usage());
116+ if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
117+ ealgs = nil;
118+ break;
119+
120+ case 'f':
121+ dbfile = EARGF(usage());
122+ break;
123+
124+ case 'k':
125+ keyspec = EARGF(usage());
126+ break;
127+
128+ case 'm':
129+ messagesize = strtoul(EARGF(usage()), nil, 0);
130+ break;
131+
132+ case 'n':
133+ nonone = 0;
134+ break;
135+
136+ case 'r':
137+ srv = EARGF(usage());
138+ break;
139+
140+ case 's':
141+ srv = "/";
142+ break;
143+
144+ case 'A':
145+ anstring = EARGF(usage());
146+ break;
147+
148+ case 'B':
149+ na = EARGF(usage());
150+ break;
151+
152+ case 'F':
153+ /* accepted but ignored, for backwards compatibility */
154+ break;
155+
156+ case 'N':
157+ nsfile = EARGF(usage());
158+ break;
159+
160+ case 'P':
161+ patternfile = EARGF(usage());
162+ break;
163+
164+ case 'R':
165+ readonly = 1;
166+ break;
167+
168+ case 'S':
169+ if(srvfdfile)
170+ usage();
171+ srvfdfile = EARGF(usage());
172+ break;
173+
174+ default:
175+ usage();
176+ }ARGEND
177+ USED(argc, argv);
178+
179+ if(doauth){
180+ /*
181+ * We use p9any so we don't have to visit this code again, with the
182+ * cost that this code is incompatible with the old world, which
183+ * requires p9sk2. (The two differ in who talks first, so compatibility
184+ * is awkward.)
185+ */
186+ ai = auth_proxy(0, auth_getkey, "proto=p9any role=server %s", keyspec);
187+ if(ai == nil)
188+ fatal("auth_proxy: %r");
189+ if(nonone && strcmp(ai->cuid, "none") == 0)
190+ fatal("exportfs by none disallowed");
191+ if(auth_chuid(ai, nsfile) < 0)
192+ fatal("auth_chuid: %r");
193+ putenv("service", "exportfs");
194+ }
195+
196+ if(srvfdfile){
197+ if((srvfd = open(srvfdfile, ORDWR)) < 0)
198+ sysfatal("open '%s': %r", srvfdfile);
199+ }
200+
201+ if(na){
202+ if(srv == nil)
203+ sysfatal("-B requires -s");
204+
205+ local = "me";
206+ remote = na;
207+ if((fd = dial(netmkaddr(na, 0, "importfs"), 0, 0, 0)) < 0)
208+ sysfatal("can't dial %s: %r", na);
209+
210+ ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec);
211+ if(ai == nil)
212+ sysfatal("%r: %s", na);
213+
214+ dup(fd, 0);
215+ dup(fd, 1);
216+ close(fd);
217+ }
218+
219+ exclusions();
220+
221+ if(dbg) {
222+ n = create(dbfile, OWRITE|OTRUNC, 0666);
223+ dup(n, DFD);
224+ close(n);
225+ }
226+
227+ if(srvfd >= 0 && srv){
228+ fprint(2, "exportfs: -S cannot be used with -r or -s\n");
229+ usage();
230+ }
231+
232+ DEBUG(DFD, "exportfs: started\n");
233+
234+ rfork(RFNOTEG);
235+
236+ if(messagesize == 0){
237+ messagesize = iounit(netfd);
238+ if(messagesize == 0)
239+ messagesize = 8192+IOHDRSZ;
240+ }
241+
242+ Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs);
243+// for(i=0; i<Nr_workbufs; i++)
244+// Workq[i].buf = emallocz(messagesize);
245+ fhash = emallocz(sizeof(Fid*)*FHASHSIZE);
246+
247+ fmtinstall('F', fcallfmt);
248+
249+ /*
250+ * Get tree to serve from network connection,
251+ * check we can get there and ack the connection
252+ */
253+ if(srvfd != -1) {
254+ /* do nothing */
255+ }
256+ else if(srv) {
257+ chdir(srv);
258+ DEBUG(DFD, "invoked as server for %s", srv);
259+ strncpy(buf, srv, sizeof buf);
260+ }
261+ else {
262+ noteconn(netfd);
263+ buf[0] = 0;
264+ n = read(0, buf, sizeof(buf)-1);
265+ if(n < 0) {
266+ errstr(buf, sizeof buf);
267+ fprint(0, "read(0): %s", buf);
268+ DEBUG(DFD, "read(0): %s", buf);
269+ exits(buf);
270+ }
271+ buf[n] = 0;
272+ if(chdir(buf) < 0) {
273+ errstr(ebuf, sizeof ebuf);
274+ fprint(0, "chdir(%d:\"%s\"): %s", n, buf, ebuf);
275+ DEBUG(DFD, "chdir(%d:\"%s\"): %s", n, buf, ebuf);
276+ exits(ebuf);
277+ }
278+ }
279+
280+ DEBUG(DFD, "\niniting root\n");
281+ initroot();
282+
283+ DEBUG(DFD, "exportfs: %s\n", buf);
284+
285+ if(srv == nil && srvfd == -1 && write(0, "OK", 2) != 2)
286+ fatal("open ack write");
287+
288+ if (readn(netfd, &initial, sizeof(ulong)) < sizeof(ulong))
289+ fatal("can't read initial string: %r\n");
290+
291+ if (strncmp((char *)&initial, "impo", sizeof(ulong)) == 0) {
292+ char buf[128], *p, *args[3];
293+
294+ /* New import. Read import's parameters... */
295+ initial = 0;
296+
297+ p = buf;
298+ while (p - buf < sizeof buf) {
299+ if ((n = read(netfd, p, 1)) < 0)
300+ fatal("can't read impo arguments: %r\n");
301+
302+ if (n == 0)
303+ fatal("connection closed while reading arguments\n");
304+
305+ if (*p == '\n')
306+ *p = '\0';
307+ if (*p++ == '\0')
308+ break;
309+ }
310+
311+ if (tokenize(buf, args, nelem(args)) != 2)
312+ fatal("impo arguments invalid: impo%s...\n", buf);
313+
314+ if (strcmp(args[0], "aan") == 0)
315+ filterp = aanfilter;
316+ else if (strcmp(args[0], "nofilter") != 0)
317+ fatal("import filter argument unsupported: %s\n", args[0]);
318+
319+ if (strcmp(args[1], "ssl") == 0)
320+ encproto = Encssl;
321+ else if (strcmp(args[1], "tls") == 0)
322+ encproto = Enctls;
323+ else if (strcmp(args[1], "clear") != 0)
324+ fatal("import encryption proto unsupported: %s\n", args[1]);
325+
326+ if (encproto == Enctls)
327+ sysfatal("%s: tls has not yet been implemented", argv[0]);
328+ }
329+
330+ if (encproto != Encnone && ealgs && ai) {
331+ uchar key[16];
332+ uchar digest[SHA1dlen];
333+ char fromclientsecret[21];
334+ char fromserversecret[21];
335+ int i;
336+
337+ memmove(key+4, ai->secret, ai->nsecret);
338+
339+ /* exchange random numbers */
340+ srand(truerand());
341+ for(i = 0; i < 4; i++)
342+ key[i+12] = rand();
343+
344+ if (initial)
345+ fatal("Protocol botch: old import\n");
346+ if(readn(netfd, key, 4) != 4)
347+ fatal("can't read key part; %r\n");
348+
349+ if(write(netfd, key+12, 4) != 4)
350+ fatal("can't write key part; %r\n");
351+
352+ /* scramble into two secrets */
353+ sha1(key, sizeof(key), digest, nil);
354+ mksecret(fromclientsecret, digest);
355+ mksecret(fromserversecret, digest+10);
356+
357+ if (filterp)
358+ netfd = filter(netfd, filterp);
359+
360+ switch (encproto) {
361+ case Encssl:
362+ netfd = pushssl(netfd, ealgs, fromserversecret,
363+ fromclientsecret, nil);
364+ break;
365+ case Enctls:
366+ default:
367+ fatal("Unsupported encryption protocol\n");
368+ }
369+
370+ if(netfd < 0)
371+ fatal("can't establish ssl connection: %r");
372+ }
373+ else if (filterp) {
374+ if (initial)
375+ fatal("Protocol botch: don't know how to deal with this\n");
376+ netfd = filter(netfd, filterp);
377+ }
378+
379+ /*
380+ * Start serving file requests from the network
381+ */
382+ for(;;) {
383+ r = getsbuf();
384+ if(r == 0)
385+ fatal("Out of service buffers");
386+
387+ n = localread9pmsg(netfd, r->buf, messagesize, &initial);
388+ if(n <= 0)
389+ fatal(nil);
390+
391+ if(convM2S(r->buf, n, &r->work) == 0)
392+ fatal("convM2S format error");
393+
394+ DEBUG(DFD, "%F\n", &r->work);
395+ (fcalls[r->work.type])(r);
396+ }
397+}
398+
399+/*
400+ * WARNING: Replace this with the original version as soon as all
401+ * _old_ imports have been replaced with negotiating imports. Also
402+ * cpu relies on this (which needs to be fixed!) -- pb.
403+ */
404+static int
405+localread9pmsg(int fd, void *abuf, uint n, ulong *initial)
406+{
407+ int m, len;
408+ uchar *buf;
409+
410+ buf = abuf;
411+
412+ /* read count */
413+ assert(BIT32SZ == sizeof(ulong));
414+ if (*initial) {
415+ memcpy(buf, initial, BIT32SZ);
416+ *initial = 0;
417+ }
418+ else {
419+ m = readn(fd, buf, BIT32SZ);
420+ if(m != BIT32SZ){
421+ if(m < 0)
422+ return -1;
423+ return 0;
424+ }
425+ }
426+
427+ len = GBIT32(buf);
428+ if(len <= BIT32SZ || len > n){
429+ werrstr("bad length in 9P2000 message header");
430+ return -1;
431+ }
432+ len -= BIT32SZ;
433+ m = readn(fd, buf+BIT32SZ, len);
434+ if(m < len)
435+ return 0;
436+ return BIT32SZ+m;
437+}
438+void
439+reply(Fcall *r, Fcall *t, char *err)
440+{
441+ uchar *data;
442+ int n;
443+
444+ t->tag = r->tag;
445+ t->fid = r->fid;
446+ if(err) {
447+ t->type = Rerror;
448+ t->ename = err;
449+ }
450+ else
451+ t->type = r->type + 1;
452+
453+ DEBUG(DFD, "\t%F\n", t);
454+
455+ data = malloc(messagesize); /* not mallocz; no need to clear */
456+ if(data == nil)
457+ fatal(Enomem);
458+ n = convS2M(t, data, messagesize);
459+ if(write(netfd, data, n)!=n)
460+{syslog(0, "exportfs", "short write: %r");
461+ fatal("mount write");
462+}
463+ free(data);
464+}
465+
466+Fid *
467+getfid(int nr)
468+{
469+ Fid *f;
470+
471+ for(f = fidhash(nr); f; f = f->next)
472+ if(f->nr == nr)
473+ return f;
474+
475+ return 0;
476+}
477+
478+int
479+freefid(int nr)
480+{
481+ Fid *f, **l;
482+ char buf[128];
483+
484+ l = &fidhash(nr);
485+ for(f = *l; f; f = f->next) {
486+ if(f->nr == nr) {
487+ if(f->mid) {
488+ sprint(buf, "/mnt/exportfs/%d", f->mid);
489+ unmount(0, buf);
490+ psmap[f->mid] = 0;
491+ }
492+ if(f->f) {
493+ freefile(f->f);
494+ f->f = nil;
495+ }
496+ if(f->dir){
497+ free(f->dir);
498+ f->dir = nil;
499+ }
500+ *l = f->next;
501+ f->next = fidfree;
502+ fidfree = f;
503+ return 1;
504+ }
505+ l = &f->next;
506+ }
507+
508+ return 0;
509+}
510+
511+Fid *
512+newfid(int nr)
513+{
514+ Fid *new, **l;
515+ int i;
516+
517+ l = &fidhash(nr);
518+ for(new = *l; new; new = new->next)
519+ if(new->nr == nr)
520+ return 0;
521+
522+ if(fidfree == 0) {
523+ fidfree = emallocz(sizeof(Fid) * Fidchunk);
524+
525+ for(i = 0; i < Fidchunk-1; i++)
526+ fidfree[i].next = &fidfree[i+1];
527+
528+ fidfree[Fidchunk-1].next = 0;
529+ }
530+
531+ new = fidfree;
532+ fidfree = new->next;
533+
534+ memset(new, 0, sizeof(Fid));
535+ new->next = *l;
536+ *l = new;
537+ new->nr = nr;
538+ new->fid = -1;
539+ new->mid = 0;
540+
541+ return new;
542+}
543+
544+Fsrpc *
545+getsbuf(void)
546+{
547+ static int ap;
548+ int look, rounds;
549+ Fsrpc *wb;
550+ int small_instead_of_fast = 1;
551+
552+ if(small_instead_of_fast)
553+ ap = 0; /* so we always start looking at the beginning and reuse buffers */
554+
555+ for(rounds = 0; rounds < 10; rounds++) {
556+ for(look = 0; look < Nr_workbufs; look++) {
557+ if(++ap == Nr_workbufs)
558+ ap = 0;
559+ if(Workq[ap].busy == 0)
560+ break;
561+ }
562+
563+ if(look == Nr_workbufs){
564+ sleep(10 * rounds);
565+ continue;
566+ }
567+
568+ wb = &Workq[ap];
569+ wb->pid = 0;
570+ wb->canint = 0;
571+ wb->flushtag = NOTAG;
572+ wb->busy = 1;
573+ if(wb->buf == nil) /* allocate buffers dynamically to keep size down */
574+ wb->buf = emallocz(messagesize);
575+ return wb;
576+ }
577+ fatal("No more work buffers");
578+ return nil;
579+}
580+
581+void
582+freefile(File *f)
583+{
584+ File *parent, *child;
585+
586+Loop:
587+ f->ref--;
588+ if(f->ref > 0)
589+ return;
590+ freecnt++;
591+ if(f->ref < 0) abort();
592+ DEBUG(DFD, "free %s\n", f->name);
593+ /* delete from parent */
594+ parent = f->parent;
595+ if(parent->child == f)
596+ parent->child = f->childlist;
597+ else{
598+ for(child=parent->child; child->childlist!=f; child=child->childlist)
599+ if(child->childlist == nil)
600+ fatal("bad child list");
601+ child->childlist = f->childlist;
602+ }
603+ freeqid(f->qidt);
604+ free(f->name);
605+ f->name = nil;
606+ free(f);
607+ f = parent;
608+ if(f != nil)
609+ goto Loop;
610+}
611+
612+File *
613+file(File *parent, char *name)
614+{
615+ Dir *dir;
616+ char *path;
617+ File *f;
618+
619+ DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
620+
621+ path = makepath(parent, name);
622+ if(patternfile != nil && excludefile(path)){
623+ free(path);
624+ return nil;
625+ }
626+ dir = dirstat(path);
627+ free(path);
628+ if(dir == nil)
629+ return nil;
630+
631+ for(f = parent->child; f; f = f->childlist)
632+ if(strcmp(name, f->name) == 0)
633+ break;
634+
635+ if(f == nil){
636+ f = emallocz(sizeof(File));
637+ f->name = estrdup(name);
638+
639+ f->parent = parent;
640+ f->childlist = parent->child;
641+ parent->child = f;
642+ parent->ref++;
643+ f->ref = 0;
644+ filecnt++;
645+ }
646+ f->ref++;
647+ f->qid.type = dir->qid.type;
648+ f->qid.vers = dir->qid.vers;
649+ f->qidt = uniqueqid(dir);
650+ f->qid.path = f->qidt->uniqpath;
651+
652+ f->inval = 0;
653+
654+ free(dir);
655+
656+ return f;
657+}
658+
659+void
660+initroot(void)
661+{
662+ Dir *dir;
663+
664+ root = emallocz(sizeof(File));
665+ root->name = estrdup(".");
666+
667+ dir = dirstat(root->name);
668+ if(dir == nil)
669+ fatal("root stat");
670+
671+ root->ref = 1;
672+ root->qid.vers = dir->qid.vers;
673+ root->qidt = uniqueqid(dir);
674+ root->qid.path = root->qidt->uniqpath;
675+ root->qid.type = QTDIR;
676+ free(dir);
677+
678+ psmpt = emallocz(sizeof(File));
679+ psmpt->name = estrdup("/");
680+
681+ dir = dirstat(psmpt->name);
682+ if(dir == nil)
683+ return;
684+
685+ psmpt->ref = 1;
686+ psmpt->qid.vers = dir->qid.vers;
687+ psmpt->qidt = uniqueqid(dir);
688+ psmpt->qid.path = psmpt->qidt->uniqpath;
689+ free(dir);
690+
691+ psmpt = file(psmpt, "mnt");
692+ if(psmpt == 0)
693+ return;
694+ psmpt = file(psmpt, "exportfs");
695+}
696+
697+char*
698+makepath(File *p, char *name)
699+{
700+ int i, n;
701+ char *c, *s, *path, *seg[256];
702+
703+ seg[0] = name;
704+ n = strlen(name)+2;
705+ for(i = 1; i < 256 && p; i++, p = p->parent){
706+ seg[i] = p->name;
707+ n += strlen(p->name)+1;
708+ }
709+ path = malloc(n);
710+ if(path == nil)
711+ fatal("out of memory");
712+ s = path;
713+
714+ while(i--) {
715+ for(c = seg[i]; *c; c++)
716+ *s++ = *c;
717+ *s++ = '/';
718+ }
719+ while(s[-1] == '/')
720+ s--;
721+ *s = '\0';
722+
723+ return path;
724+}
725+
726+int
727+qidhash(vlong path)
728+{
729+ int h, n;
730+
731+ h = 0;
732+ for(n=0; n<64; n+=Nqidbits){
733+ h ^= path;
734+ path >>= Nqidbits;
735+ }
736+ return h & (Nqidtab-1);
737+}
738+
739+void
740+freeqid(Qidtab *q)
741+{
742+ ulong h;
743+ Qidtab *l;
744+
745+ q->ref--;
746+ if(q->ref > 0)
747+ return;
748+ qfreecnt++;
749+ h = qidhash(q->path);
750+ if(qidtab[h] == q)
751+ qidtab[h] = q->next;
752+ else{
753+ for(l=qidtab[h]; l->next!=q; l=l->next)
754+ if(l->next == nil)
755+ fatal("bad qid list");
756+ l->next = q->next;
757+ }
758+ free(q);
759+}
760+
761+Qidtab*
762+qidlookup(Dir *d)
763+{
764+ ulong h;
765+ Qidtab *q;
766+
767+ h = qidhash(d->qid.path);
768+ for(q=qidtab[h]; q!=nil; q=q->next)
769+ if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path)
770+ return q;
771+ return nil;
772+}
773+
774+int
775+qidexists(vlong path)
776+{
777+ int h;
778+ Qidtab *q;
779+
780+ for(h=0; h<Nqidtab; h++)
781+ for(q=qidtab[h]; q!=nil; q=q->next)
782+ if(q->uniqpath == path)
783+ return 1;
784+ return 0;
785+}
786+
787+Qidtab*
788+uniqueqid(Dir *d)
789+{
790+ ulong h;
791+ vlong path;
792+ Qidtab *q;
793+
794+ q = qidlookup(d);
795+ if(q != nil){
796+ q->ref++;
797+ return q;
798+ }
799+ path = d->qid.path;
800+ while(qidexists(path)){
801+ DEBUG(DFD, "collision on %s\n", d->name);
802+ /* collision: find a new one */
803+ ncollision++;
804+ path &= QIDPATH;
805+ ++newqid;
806+ if(newqid >= (1<<16)){
807+ DEBUG(DFD, "collision wraparound\n");
808+ newqid = 1;
809+ }
810+ path |= newqid<<48;
811+ DEBUG(DFD, "assign qid %.16llux\n", path);
812+ }
813+ q = mallocz(sizeof(Qidtab), 1);
814+ if(q == nil)
815+ fatal("no memory for qid table");
816+ qidcnt++;
817+ q->ref = 1;
818+ q->type = d->type;
819+ q->dev = d->dev;
820+ q->path = d->qid.path;
821+ q->uniqpath = path;
822+ h = qidhash(d->qid.path);
823+ q->next = qidtab[h];
824+ qidtab[h] = q;
825+ return q;
826+}
827+
828+void
829+fatal(char *s, ...)
830+{
831+ char buf[ERRMAX];
832+ va_list arg;
833+ Proc *m;
834+
835+ if (s) {
836+ va_start(arg, s);
837+ vsnprint(buf, ERRMAX, s, arg);
838+ va_end(arg);
839+ }
840+
841+ /* Clear away the slave children */
842+ for(m = Proclist; m; m = m->next)
843+ postnote(PNPROC, m->pid, "kill");
844+
845+ DEBUG(DFD, "%s\n", buf);
846+ if (s)
847+ sysfatal("%s", buf); /* caution: buf could contain '%' */
848+ else
849+ exits(nil);
850+}
851+
852+void*
853+emallocz(uint n)
854+{
855+ void *p;
856+
857+ p = mallocz(n, 1);
858+ if(p == nil)
859+ fatal(Enomem);
860+ return p;
861+}
862+
863+char*
864+estrdup(char *s)
865+{
866+ char *t;
867+
868+ t = strdup(s);
869+ if(t == nil)
870+ fatal(Enomem);
871+ return t;
872+}
873+
874+/* Network on fd1, mount driver on fd0 */
875+int
876+filter(int fd, char *cmd)
877+{
878+ int p[2], lfd, len, nb, argc;
879+ char newport[128], buf[128], devdir[40], *s, *file, *argv[16];
880+
881+ /* Get a free port and post it to the client. */
882+ if (announce(anstring, devdir) < 0)
883+ sysfatal("filter: Cannot announce %s: %r", anstring);
884+
885+ snprint(buf, sizeof(buf), "%s/local", devdir);
886+ buf[sizeof buf - 1] = '\0';
887+ if ((lfd = open(buf, OREAD)) < 0)
888+ sysfatal("filter: Cannot open %s: %r", buf);
889+ if ((len = read(lfd, newport, sizeof newport - 1)) < 0)
890+ sysfatal("filter: Cannot read %s: %r", buf);
891+ close(lfd);
892+ newport[len] = '\0';
893+
894+ if ((s = strchr(newport, '\n')) != nil)
895+ *s = '\0';
896+
897+ if ((nb = write(fd, newport, len)) < 0)
898+ sysfatal("getport; cannot write port; %r");
899+ assert(nb == len);
900+
901+ argc = tokenize(cmd, argv, nelem(argv)-2);
902+ if (argc == 0)
903+ sysfatal("filter: empty command");
904+ argv[argc++] = buf;
905+ argv[argc] = nil;
906+ file = argv[0];
907+ if (s = strrchr(argv[0], '/'))
908+ argv[0] = s+1;
909+
910+ if(pipe(p) < 0)
911+ fatal("pipe");
912+
913+ switch(rfork(RFNOWAIT|RFPROC|RFFDG)) {
914+ case -1:
915+ fatal("rfork record module");
916+ case 0:
917+ if (dup(p[0], 1) < 0)
918+ fatal("filter: Cannot dup to 1; %r\n");
919+ if (dup(p[0], 0) < 0)
920+ fatal("filter: Cannot dup to 0; %r\n");
921+ close(p[0]);
922+ close(p[1]);
923+ exec(file, argv);
924+ fatal("exec record module");
925+ default:
926+ close(fd);
927+ close(p[0]);
928+ }
929+ return p[1];
930+}
931+
932+static void
933+mksecret(char *t, uchar *f)
934+{
935+ sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
936+ f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
937+}
sys/src/cmd/exportfs/exportfs.h+144−0
@@ -0,0 +1,144 @@
1+/*
2+ * exportfs.h - definitions for exporting file server
3+ */
4+
5+#define DEBUG if(!dbg){}else fprint
6+#define DFD 9
7+#define fidhash(s) fhash[s%FHASHSIZE]
8+
9+typedef struct Fsrpc Fsrpc;
10+typedef struct Fid Fid;
11+typedef struct File File;
12+typedef struct Proc Proc;
13+typedef struct Qidtab Qidtab;
14+
15+struct Fsrpc
16+{
17+ int busy; /* Work buffer has pending rpc to service */
18+ uintptr pid; /* Pid of slave process executing the rpc */
19+ int canint; /* Interrupt gate */
20+ int flushtag; /* Tag on which to reply to flush */
21+ Fcall work; /* Plan 9 incoming Fcall */
22+ uchar *buf; /* Data buffer */
23+};
24+
25+struct Fid
26+{
27+ int fid; /* system fd for i/o */
28+ File *f; /* File attached to this fid */
29+ int mode;
30+ int nr; /* fid number */
31+ int mid; /* Mount id */
32+ Fid *next; /* hash link */
33+
34+ /* for preaddir -- ARRGH! */
35+ Dir *dir; /* buffer for reading directories */
36+ int ndir; /* number of entries in dir */
37+ int cdir; /* number of consumed entries in dir */
38+ int gdir; /* glue index */
39+ vlong offset; /* offset in virtual directory */
40+};
41+
42+struct File
43+{
44+ char *name;
45+ int ref;
46+ Qid qid;
47+ Qidtab *qidt;
48+ int inval;
49+ File *parent;
50+ File *child;
51+ File *childlist;
52+};
53+
54+struct Proc
55+{
56+ uintptr pid;
57+ int busy;
58+ Proc *next;
59+};
60+
61+struct Qidtab
62+{
63+ int ref;
64+ int type;
65+ int dev;
66+ vlong path;
67+ vlong uniqpath;
68+ Qidtab *next;
69+};
70+
71+enum
72+{
73+ MAXPROC = 50,
74+ FHASHSIZE = 64,
75+ Nr_workbufs = 50,
76+ Fidchunk = 1000,
77+ Npsmpt = 32,
78+ Nqidbits = 5,
79+ Nqidtab = (1<<Nqidbits),
80+};
81+
82+char Ebadfid[];
83+char Enotdir[];
84+char Edupfid[];
85+char Eopen[];
86+char Exmnt[];
87+char Enomem[];
88+char Emip[];
89+char Enopsmt[];
90+
91+Extern Fsrpc *Workq;
92+Extern int dbg;
93+Extern File *root;
94+Extern File *psmpt;
95+Extern Fid **fhash;
96+Extern Fid *fidfree;
97+Extern Proc *Proclist;
98+Extern char psmap[Npsmpt];
99+Extern Qidtab *qidtab[Nqidtab];
100+Extern ulong messagesize;
101+Extern char Enomem[];
102+Extern int srvfd;
103+Extern char* patternfile;
104+
105+/* File system protocol service procedures */
106+void Xattach(Fsrpc*);
107+void Xauth(Fsrpc*);
108+void Xclunk(Fsrpc*);
109+void Xcreate(Fsrpc*);
110+void Xflush(Fsrpc*);
111+void Xnop(Fsrpc*);
112+void Xremove(Fsrpc*);
113+void Xstat(Fsrpc*);
114+void Xversion(Fsrpc*);
115+void Xwalk(Fsrpc*);
116+void Xwstat(Fsrpc*);
117+void slave(Fsrpc*);
118+
119+void reply(Fcall*, Fcall*, char*);
120+Fid *getfid(int);
121+int freefid(int);
122+Fid *newfid(int);
123+Fsrpc *getsbuf(void);
124+void initroot(void);
125+void fatal(char*, ...);
126+char* makepath(File*, char*);
127+File *file(File*, char*);
128+void freefile(File*);
129+void slaveopen(Fsrpc*);
130+void slaveread(Fsrpc*);
131+void slavewrite(Fsrpc*);
132+void blockingslave(void);
133+void reopen(Fid *f);
134+void noteproc(int, char*);
135+void flushaction(void*, char*);
136+void pushfcall(char*);
137+Qidtab* uniqueqid(Dir*);
138+void freeqid(Qidtab*);
139+char* estrdup(char*);
140+void* emallocz(uint);
141+int readmessage(int, char*, int);
142+void exclusions(void);
143+int excludefile(char*);
144+int preaddir(Fid*, uchar*, int, vlong);
sys/src/cmd/exportfs/exportsrv.c+764−0
@@ -0,0 +1,764 @@
1+#include <u.h>
2+#include <libc.h>
3+#include <auth.h>
4+#include <fcall.h>
5+#define Extern extern
6+#include "exportfs.h"
7+
8+extern char *netdir, *local, *remote;
9+
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+
21+ulong messagesize;
22+int readonly;
23+
24+void
25+Xversion(Fsrpc *t)
26+{
27+ Fcall rhdr;
28+
29+ if(t->work.msize > messagesize)
30+ t->work.msize = messagesize;
31+ messagesize = t->work.msize;
32+ if(strncmp(t->work.version, "9P2000", 6) != 0){
33+ reply(&t->work, &rhdr, Eversion);
34+ return;
35+ }
36+ rhdr.version = "9P2000";
37+ rhdr.msize = t->work.msize;
38+ reply(&t->work, &rhdr, 0);
39+ t->busy = 0;
40+}
41+
42+void
43+Xauth(Fsrpc *t)
44+{
45+ Fcall rhdr;
46+
47+ reply(&t->work, &rhdr, "exportfs: authentication not required");
48+ t->busy = 0;
49+}
50+
51+void
52+Xflush(Fsrpc *t)
53+{
54+ Fsrpc *w, *e;
55+ Fcall rhdr;
56+
57+ e = &Workq[Nr_workbufs];
58+
59+ for(w = Workq; w < e; w++) {
60+ if(w->work.tag == t->work.oldtag) {
61+ DEBUG(DFD, "\tQ busy %d pid %p can %d\n", w->busy, w->pid, w->canint);
62+ if(w->busy && w->pid) {
63+ w->flushtag = t->work.tag;
64+ DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
65+ if(w->canint)
66+ postnote(PNPROC, w->pid, "flush");
67+ t->busy = 0;
68+ return;
69+ }
70+ }
71+ }
72+
73+ reply(&t->work, &rhdr, 0);
74+ DEBUG(DFD, "\tflush reply\n");
75+ t->busy = 0;
76+}
77+
78+void
79+Xattach(Fsrpc *t)
80+{
81+ int i, nfd;
82+ Fcall rhdr;
83+ Fid *f;
84+ char buf[128];
85+
86+ f = newfid(t->work.fid);
87+ if(f == 0) {
88+ reply(&t->work, &rhdr, Ebadfid);
89+ t->busy = 0;
90+ return;
91+ }
92+
93+ if(srvfd >= 0){
94+ if(psmpt == 0){
95+ Nomount:
96+ reply(&t->work, &rhdr, Enopsmt);
97+ t->busy = 0;
98+ freefid(t->work.fid);
99+ return;
100+ }
101+ for(i=0; i<Npsmpt; i++)
102+ if(psmap[i] == 0)
103+ break;
104+ if(i >= Npsmpt)
105+ goto Nomount;
106+ sprint(buf, "%d", i);
107+ f->f = file(psmpt, buf);
108+ if(f->f == nil)
109+ goto Nomount;
110+ sprint(buf, "/mnt/exportfs/%d", i);
111+ nfd = dup(srvfd, -1);
112+ if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
113+ errstr(buf, sizeof buf);
114+ reply(&t->work, &rhdr, buf);
115+ t->busy = 0;
116+ freefid(t->work.fid);
117+ close(nfd);
118+ return;
119+ }
120+ psmap[i] = 1;
121+ f->mid = i;
122+ }else{
123+ f->f = root;
124+ f->f->ref++;
125+ }
126+
127+ rhdr.qid = f->f->qid;
128+ reply(&t->work, &rhdr, 0);
129+ t->busy = 0;
130+}
131+
132+Fid*
133+clonefid(Fid *f, int new)
134+{
135+ Fid *n;
136+
137+ n = newfid(new);
138+ if(n == 0) {
139+ n = getfid(new);
140+ if(n == 0)
141+ fatal("inconsistent fids");
142+ if(n->fid >= 0)
143+ close(n->fid);
144+ freefid(new);
145+ n = newfid(new);
146+ if(n == 0)
147+ fatal("inconsistent fids2");
148+ }
149+ n->f = f->f;
150+ n->f->ref++;
151+ return n;
152+}
153+
154+void
155+Xwalk(Fsrpc *t)
156+{
157+ char err[ERRMAX], *e;
158+ Fcall rhdr;
159+ Fid *f, *nf;
160+ File *wf;
161+ int i;
162+
163+ f = getfid(t->work.fid);
164+ if(f == 0) {
165+ reply(&t->work, &rhdr, Ebadfid);
166+ t->busy = 0;
167+ return;
168+ }
169+
170+ nf = nil;
171+ if(t->work.newfid != t->work.fid){
172+ nf = clonefid(f, t->work.newfid);
173+ f = nf;
174+ }
175+
176+ rhdr.nwqid = 0;
177+ e = nil;
178+ for(i=0; i<t->work.nwname; i++){
179+ if(i == MAXWELEM){
180+ e = "Too many path elements";
181+ break;
182+ }
183+
184+ if(strcmp(t->work.wname[i], "..") == 0) {
185+ if(f->f->parent == nil) {
186+ e = Exmnt;
187+ break;
188+ }
189+ wf = f->f->parent;
190+ wf->ref++;
191+ goto Accept;
192+ }
193+
194+ wf = file(f->f, t->work.wname[i]);
195+ if(wf == 0){
196+ errstr(err, sizeof err);
197+ e = err;
198+ break;
199+ }
200+ Accept:
201+ freefile(f->f);
202+ rhdr.wqid[rhdr.nwqid++] = wf->qid;
203+ f->f = wf;
204+ continue;
205+ }
206+
207+ if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
208+ freefid(t->work.newfid);
209+ if(rhdr.nwqid > 0)
210+ e = nil;
211+ reply(&t->work, &rhdr, e);
212+ t->busy = 0;
213+}
214+
215+void
216+Xclunk(Fsrpc *t)
217+{
218+ Fcall rhdr;
219+ Fid *f;
220+
221+ f = getfid(t->work.fid);
222+ if(f == 0) {
223+ reply(&t->work, &rhdr, Ebadfid);
224+ t->busy = 0;
225+ return;
226+ }
227+
228+ if(f->fid >= 0)
229+ close(f->fid);
230+
231+ freefid(t->work.fid);
232+ reply(&t->work, &rhdr, 0);
233+ t->busy = 0;
234+}
235+
236+void
237+Xstat(Fsrpc *t)
238+{
239+ char err[ERRMAX], *path;
240+ Fcall rhdr;
241+ Fid *f;
242+ Dir *d;
243+ int s;
244+ uchar *statbuf;
245+
246+ f = getfid(t->work.fid);
247+ if(f == 0) {
248+ reply(&t->work, &rhdr, Ebadfid);
249+ t->busy = 0;
250+ return;
251+ }
252+ if(f->fid >= 0)
253+ d = dirfstat(f->fid);
254+ else {
255+ path = makepath(f->f, "");
256+ d = dirstat(path);
257+ free(path);
258+ }
259+
260+ if(d == nil) {
261+ errstr(err, sizeof err);
262+ reply(&t->work, &rhdr, err);
263+ t->busy = 0;
264+ return;
265+ }
266+
267+ d->qid.path = f->f->qidt->uniqpath;
268+ s = sizeD2M(d);
269+ statbuf = emallocz(s);
270+ s = convD2M(d, statbuf, s);
271+ free(d);
272+ rhdr.nstat = s;
273+ rhdr.stat = statbuf;
274+ reply(&t->work, &rhdr, 0);
275+ free(statbuf);
276+ t->busy = 0;
277+}
278+
279+static int
280+getiounit(int fd)
281+{
282+ int n;
283+
284+ n = iounit(fd);
285+ if(n > messagesize-IOHDRSZ)
286+ n = messagesize-IOHDRSZ;
287+ return n;
288+}
289+
290+void
291+Xcreate(Fsrpc *t)
292+{
293+ char err[ERRMAX], *path;
294+ Fcall rhdr;
295+ Fid *f;
296+ File *nf;
297+
298+ if(readonly) {
299+ reply(&t->work, &rhdr, Ereadonly);
300+ t->busy = 0;
301+ return;
302+ }
303+ f = getfid(t->work.fid);
304+ if(f == 0) {
305+ reply(&t->work, &rhdr, Ebadfid);
306+ t->busy = 0;
307+ return;
308+ }
309+
310+
311+ path = makepath(f->f, t->work.name);
312+ f->fid = create(path, t->work.mode, t->work.perm);
313+ free(path);
314+ if(f->fid < 0) {
315+ errstr(err, sizeof err);
316+ reply(&t->work, &rhdr, err);
317+ t->busy = 0;
318+ return;
319+ }
320+
321+ nf = file(f->f, t->work.name);
322+ if(nf == 0) {
323+ errstr(err, sizeof err);
324+ reply(&t->work, &rhdr, err);
325+ t->busy = 0;
326+ return;
327+ }
328+
329+ f->mode = t->work.mode;
330+ freefile(f->f);
331+ f->f = nf;
332+ rhdr.qid = f->f->qid;
333+ rhdr.iounit = getiounit(f->fid);
334+ reply(&t->work, &rhdr, 0);
335+ t->busy = 0;
336+}
337+
338+void
339+Xremove(Fsrpc *t)
340+{
341+ char err[ERRMAX], *path;
342+ Fcall rhdr;
343+ Fid *f;
344+
345+ if(readonly) {
346+ reply(&t->work, &rhdr, Ereadonly);
347+ t->busy = 0;
348+ return;
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
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+ if(readonly) {
388+ reply(&t->work, &rhdr, Ereadonly);
389+ t->busy = 0;
390+ return;
391+ }
392+ f = getfid(t->work.fid);
393+ if(f == 0) {
394+ reply(&t->work, &rhdr, Ebadfid);
395+ t->busy = 0;
396+ return;
397+ }
398+ strings = emallocz(t->work.nstat); /* ample */
399+ if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){
400+ rerrstr(err, sizeof err);
401+ reply(&t->work, &rhdr, err);
402+ t->busy = 0;
403+ free(strings);
404+ return;
405+ }
406+
407+ if(f->fid >= 0)
408+ s = dirfwstat(f->fid, &d);
409+ else {
410+ path = makepath(f->f, "");
411+ s = dirwstat(path, &d);
412+ free(path);
413+ }
414+ if(s < 0) {
415+ rerrstr(err, sizeof err);
416+ reply(&t->work, &rhdr, err);
417+ }
418+ else {
419+ /* wstat may really be rename */
420+ if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
421+ free(f->f->name);
422+ f->f->name = estrdup(d.name);
423+ }
424+ reply(&t->work, &rhdr, 0);
425+ }
426+ free(strings);
427+ t->busy = 0;
428+}
429+
430+/*
431+ * based on libthread's threadsetname, but drags in less library code.
432+ * actually just sets the arguments displayed.
433+ */
434+void
435+procsetname(char *fmt, ...)
436+{
437+ int fd;
438+ char *cmdname;
439+ char buf[128];
440+ va_list arg;
441+
442+ va_start(arg, fmt);
443+ cmdname = vsmprint(fmt, arg);
444+ va_end(arg);
445+ if (cmdname == nil)
446+ return;
447+ snprint(buf, sizeof buf, "#p/%d/args", getpid());
448+ if((fd = open(buf, OWRITE)) >= 0){
449+ write(fd, cmdname, strlen(cmdname)+1);
450+ close(fd);
451+ }
452+ free(cmdname);
453+}
454+
455+void
456+slave(Fsrpc *f)
457+{
458+ Proc *p;
459+ uintptr pid;
460+ Fcall rhdr;
461+ static int nproc;
462+
463+ if(readonly){
464+ switch(f->work.type){
465+ case Twrite:
466+ reply(&f->work, &rhdr, Ereadonly);
467+ f->busy = 0;
468+ return;
469+ case Topen:
470+ if((f->work.mode&3) == OWRITE || (f->work.mode&OTRUNC)){
471+ reply(&f->work, &rhdr, Ereadonly);
472+ f->busy = 0;
473+ return;
474+ }
475+ }
476+ }
477+ for(;;) {
478+ for(p = Proclist; p; p = p->next) {
479+ if(p->busy == 0) {
480+ f->pid = p->pid;
481+ p->busy = 1;
482+ pid = (uintptr)rendezvous((void*)p->pid, f);
483+ if(pid != p->pid)
484+ fatal("rendezvous sync fail");
485+ return;
486+ }
487+ }
488+
489+ if(++nproc > MAXPROC)
490+ fatal("too many procs");
491+
492+ pid = rfork(RFPROC|RFMEM);
493+ switch(pid) {
494+ case -1:
495+ fatal("rfork");
496+
497+ case 0:
498+ if (local[0] != '\0')
499+ if (netdir[0] != '\0')
500+ procsetname("%s: %s -> %s", netdir,
501+ local, remote);
502+ else
503+ procsetname("%s -> %s", local, remote);
504+ blockingslave();
505+ fatal("slave");
506+
507+ default:
508+ p = malloc(sizeof(Proc));
509+ if(p == 0)
510+ fatal("out of memory");
511+
512+ p->busy = 0;
513+ p->pid = pid;
514+ p->next = Proclist;
515+ Proclist = p;
516+
517+ rendezvous((void*)pid, p);
518+ }
519+ }
520+}
521+
522+void
523+blockingslave(void)
524+{
525+ Fsrpc *p;
526+ Fcall rhdr;
527+ Proc *m;
528+ uintptr pid;
529+
530+ notify(flushaction);
531+
532+ pid = getpid();
533+
534+ m = rendezvous((void*)pid, 0);
535+
536+ for(;;) {
537+ p = rendezvous((void*)pid, (void*)pid);
538+ if(p == (void*)~0) /* Interrupted */
539+ continue;
540+
541+ DEBUG(DFD, "\tslave: %p %F b %d p %p\n", pid, &p->work, p->busy, p->pid);
542+ if(p->flushtag != NOTAG)
543+ goto flushme;
544+
545+ switch(p->work.type) {
546+ case Tread:
547+ slaveread(p);
548+ break;
549+
550+ case Twrite:
551+ slavewrite(p);
552+ break;
553+
554+ case Topen:
555+ slaveopen(p);
556+ break;
557+
558+ default:
559+ reply(&p->work, &rhdr, "exportfs: slave type error");
560+ }
561+ if(p->flushtag != NOTAG) {
562+flushme:
563+ p->work.type = Tflush;
564+ p->work.tag = p->flushtag;
565+ reply(&p->work, &rhdr, 0);
566+ }
567+ p->busy = 0;
568+ m->busy = 0;
569+ }
570+}
571+
572+int
573+openmount(int sfd)
574+{
575+ int p[2];
576+ char *arg[10], fdbuf[20], mbuf[20];
577+
578+ if(pipe(p) < 0)
579+ return -1;
580+
581+ switch(rfork(RFPROC|RFMEM|RFNOWAIT|RFNAMEG|RFFDG)){
582+ case -1:
583+ return -1;
584+
585+ default:
586+ close(sfd);
587+ close(p[0]);
588+ return p[1];
589+
590+ case 0:
591+ break;
592+ }
593+
594+ close(p[1]);
595+
596+ arg[0] = "exportfs";
597+ snprint(fdbuf, sizeof fdbuf, "-S/fd/%d", sfd);
598+ arg[1] = fdbuf;
599+ snprint(mbuf, sizeof mbuf, "-m%lud", messagesize-IOHDRSZ);
600+ arg[2] = mbuf;
601+ arg[3] = nil;
602+
603+ close(0);
604+ close(1);
605+ dup(p[0], 0);
606+ dup(p[0], 1);
607+ exec("/bin/exportfs", arg);
608+ _exits("whoops: exec failed");
609+ return -1;
610+}
611+
612+void
613+slaveopen(Fsrpc *p)
614+{
615+ char err[ERRMAX], *path;
616+ Fcall *work, rhdr;
617+ Fid *f;
618+ Dir *d;
619+
620+ work = &p->work;
621+
622+ f = getfid(work->fid);
623+ if(f == 0) {
624+ reply(work, &rhdr, Ebadfid);
625+ return;
626+ }
627+ if(f->fid >= 0) {
628+ close(f->fid);
629+ f->fid = -1;
630+ }
631+
632+ path = makepath(f->f, "");
633+ DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
634+
635+ p->canint = 1;
636+ if(p->flushtag != NOTAG){
637+ free(path);
638+ return;
639+ }
640+ /* There is a race here I ignore because there are no locks */
641+ f->fid = open(path, work->mode);
642+ free(path);
643+ p->canint = 0;
644+ if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
645+ Error:
646+ errstr(err, sizeof err);
647+ reply(work, &rhdr, err);
648+ return;
649+ }
650+ f->f->qid = d->qid;
651+ free(d);
652+ if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */
653+ f->fid = openmount(f->fid);
654+ if(f->fid < 0)
655+ goto Error;
656+ }
657+
658+ DEBUG(DFD, "\topen: fd %d\n", f->fid);
659+ f->mode = work->mode;
660+ f->offset = 0;
661+ rhdr.iounit = getiounit(f->fid);
662+ rhdr.qid = f->f->qid;
663+ reply(work, &rhdr, 0);
664+}
665+
666+void
667+slaveread(Fsrpc *p)
668+{
669+ Fid *f;
670+ int n, r;
671+ Fcall *work, rhdr;
672+ char *data, err[ERRMAX];
673+
674+ work = &p->work;
675+
676+ f = getfid(work->fid);
677+ if(f == 0) {
678+ reply(work, &rhdr, Ebadfid);
679+ return;
680+ }
681+
682+ n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
683+ p->canint = 1;
684+ if(p->flushtag != NOTAG)
685+ return;
686+ data = malloc(n);
687+ if(data == nil)
688+ fatal(Enomem);
689+
690+ /* can't just call pread, since directories must update the offset */
691+ if(patternfile != nil && (f->f->qid.type&QTDIR))
692+ r = preaddir(f, (uchar*)data, n, work->offset);
693+ else
694+ r = pread(f->fid, data, n, work->offset);
695+ p->canint = 0;
696+ if(r < 0) {
697+ free(data);
698+ errstr(err, sizeof err);
699+ reply(work, &rhdr, err);
700+ return;
701+ }
702+
703+ DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
704+
705+ rhdr.data = data;
706+ rhdr.count = r;
707+ reply(work, &rhdr, 0);
708+ free(data);
709+}
710+
711+void
712+slavewrite(Fsrpc *p)
713+{
714+ char err[ERRMAX];
715+ Fcall *work, rhdr;
716+ Fid *f;
717+ int n;
718+
719+ work = &p->work;
720+
721+ f = getfid(work->fid);
722+ if(f == 0) {
723+ reply(work, &rhdr, Ebadfid);
724+ return;
725+ }
726+
727+ n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
728+ p->canint = 1;
729+ if(p->flushtag != NOTAG)
730+ return;
731+ n = pwrite(f->fid, work->data, n, work->offset);
732+ p->canint = 0;
733+ if(n < 0) {
734+ errstr(err, sizeof err);
735+ reply(work, &rhdr, err);
736+ return;
737+ }
738+
739+ DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
740+
741+ rhdr.count = n;
742+ reply(work, &rhdr, 0);
743+}
744+
745+void
746+reopen(Fid *f)
747+{
748+ USED(f);
749+ fatal("reopen");
750+}
751+
752+void
753+flushaction(void *a, char *cause)
754+{
755+ USED(a);
756+ if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
757+ fprint(2, "exportsrv: note: %s\n", cause);
758+ exits("noted");
759+ }
760+ if(strncmp(cause, "kill", 4) == 0)
761+ noted(NDFLT);
762+
763+ noted(NCONT);
764+}
sys/src/cmd/exportfs/mkfile+18−0
@@ -0,0 +1,18 @@
1+</$objtype/mkfile
2+
3+TARG=exportfs
4+OFILES=\
5+ exportfs.$O\
6+ exportsrv.$O\
7+ pattern.$O\
8+
9+HFILES=exportfs.h\
10+
11+BIN=/$objtype/bin
12+
13+UPDATE=\
14+ mkfile\
15+ $HFILES\
16+ ${OFILES:%.$O=%.c}\
17+
18+</sys/src/cmd/mkone
sys/src/cmd/exportfs/pattern.c+154−0
@@ -0,0 +1,154 @@
1+#include <u.h>
2+#include <libc.h>
3+#include <fcall.h>
4+#include <bio.h>
5+#include <regexp.h>
6+#define Extern
7+#include "exportfs.h"
8+
9+Reprog **exclude, **include;
10+char *patternfile;
11+
12+void
13+exclusions(void)
14+{
15+ Biobuf *f;
16+ int ni, nmaxi, ne, nmaxe;
17+ char *line;
18+
19+ if(patternfile == nil)
20+ return;
21+
22+ f = Bopen(patternfile, OREAD);
23+ if(f == nil)
24+ fatal("cannot open patternfile");
25+ ni = 0;
26+ nmaxi = 100;
27+ include = malloc(nmaxi*sizeof(*include));
28+ if(include == nil)
29+ fatal("out of memory");
30+ include[0] = nil;
31+ ne = 0;
32+ nmaxe = 100;
33+ exclude = malloc(nmaxe*sizeof(*exclude));
34+ if(exclude == nil)
35+ fatal("out of memory");
36+ exclude[0] = nil;
37+ while(line = Brdline(f, '\n')){
38+ line[Blinelen(f) - 1] = 0;
39+ if(strlen(line) < 2 || line[1] != ' ')
40+ continue;
41+ switch(line[0]){
42+ case '+':
43+ if(ni+1 >= nmaxi){
44+ nmaxi = 2*nmaxi;
45+ include = realloc(include, nmaxi*sizeof(*include));
46+ if(include == nil)
47+ fatal("out of memory");
48+ }
49+ DEBUG(DFD, "\tinclude %s\n", line+2);
50+ include[ni] = regcomp(line+2);
51+ include[++ni] = nil;
52+ break;
53+ case '-':
54+ if(ne+1 >= nmaxe){
55+ nmaxe = 2*nmaxe;
56+ exclude = realloc(exclude, nmaxe*sizeof(*exclude));
57+ if(exclude == nil)
58+ fatal("out of memory");
59+ }
60+ DEBUG(DFD, "\texclude %s\n", line+2);
61+ exclude[ne] = regcomp(line+2);
62+ exclude[++ne] = nil;
63+ break;
64+ default:
65+ DEBUG(DFD, "ignoring pattern %s\n", line);
66+ break;
67+ }
68+ }
69+ Bterm(f);
70+}
71+
72+int
73+excludefile(char *path)
74+{
75+ Reprog **re;
76+ char *p;
77+
78+ if(*(path+1) == 0)
79+ p = "/";
80+ else
81+ p = path+1;
82+
83+ DEBUG(DFD, "checking %s\n", path);
84+ for(re = include; *re != nil; re++){
85+ if(regexec(*re, p, nil, 0) != 1){
86+ DEBUG(DFD, "excluded+ %s\n", path);
87+ return -1;
88+ }
89+ }
90+ for(re = exclude; *re != nil; re++){
91+ if(regexec(*re, p, nil, 0) == 1){
92+ DEBUG(DFD, "excluded- %s\n", path);
93+ return -1;
94+ }
95+ }
96+ return 0;
97+}
98+
99+int
100+preaddir(Fid *f, uchar *data, int n, vlong offset)
101+{
102+ int r = 0, m;
103+ Dir *d;
104+
105+ DEBUG(DFD, "\tpreaddir n=%d wo=%lld fo=%lld\n", n, offset, f->offset);
106+ if(offset == 0 && f->offset != 0){
107+ if(seek(f->fid, 0, 0) != 0)
108+ return -1;
109+ f->offset = f->cdir = f->ndir = 0;
110+ free(f->dir);
111+ f->dir = nil;
112+ }else if(offset != f->offset){
113+ werrstr("can't seek dir %lld to %lld", f->offset, offset);
114+ return -1;
115+ }
116+
117+ while(n > 0){
118+ if(f->dir == nil){
119+ f->ndir = dirread(f->fid, &f->dir);
120+ if(f->ndir < 0)
121+ return f->ndir;
122+ if(f->ndir == 0)
123+ return r;
124+ }
125+ d = &f->dir[f->cdir++];
126+ if(exclude){
127+ char *p = makepath(f->f, d->name);
128+ if(excludefile(p)){
129+ free(p);
130+ goto skipentry;
131+ }
132+ free(p);
133+ }
134+ m = convD2M(d, data, n);
135+ DEBUG(DFD, "\t\tconvD2M %d\n", m);
136+ if(m <= BIT16SZ){
137+ DEBUG(DFD, "\t\t\tneeded %d\n", GBIT16(data));
138+ /* not enough room for full entry; leave for next time */
139+ f->cdir--;
140+ return r;
141+ }else{
142+ data += m;
143+ n -= m;
144+ r += m;
145+ f->offset += m;
146+ }
147+skipentry: if(f->cdir >= f->ndir){
148+ f->cdir = f->ndir = 0;
149+ free(f->dir);
150+ f->dir = nil;
151+ }
152+ }
153+ return r;
154+}
sys/src/cmd/uem/tests/bg_256.rc+5−1
@@ -30,7 +30,11 @@ echo '************************ PWD = '$PWD · 29 unmodified lines
3030
3131 # setup
3232 #
33−NUM=32
33+NUM=16
34+
35+# exportfs 14181: warning: process exceeds 100 file descriptors
36+# exportfs: No more work buffers
37+#NUM=32
3438 #NUM=256
3539
3640 I_MAX=4
sys/src/cmd/uem/tests/pbg_4.rc+3−1
@@ -26,7 +26,9 @@ CMD='../8.poke -L '$TESTDIR · 25 unmodified lines
2626
2727 # setup
2828 #
29−NUM=32
29+#NUM=64 # succeds
30+NUM=75 # succeds
31+NUM=80 # fails
3032
3133 # NUM=32 # (with 1,4,4) gives
3234 # exportfs 929: warning: process exceeds 100 file descriptors