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)
13vlong newqid = 0;
14
15enum {
16 Encnone,
17 Encssl,
18 Enctls,
19};
20
21void (*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 */
39int filecnt;
40int freecnt;
41int qidcnt;
42int qfreecnt;
43int ncollision;
44
45int netfd; /* initially stdin */
46int srvfd = -1;
47int nonone = 1;
48char *filterp;
49char *ealgs = "rc4_256 sha1";
50char *aanfilter = "/bin/aan";
51int encproto = Encnone;
52int readonly;
53
54static void mksecret(char *, uchar *);
55static int localread9pmsg(int, void *, uint, ulong *);
56static char *anstring = "tcp!*!0";
57
58char *netdir = "", *local = "", *remote = "";
59
60int filter(int, char *);
61
62void
63usage(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
71static void
72noteconn(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
85void
86main(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 */
404static int
405localread9pmsg(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}
438void
439reply(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
466Fid *
467getfid(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
478int
479freefid(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
511Fid *
512newfid(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
544Fsrpc *
545getsbuf(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
581void
582freefile(File *f)
583{
584 File *parent, *child;
585
586Loop:
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
612File *
613file(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
659void
660initroot(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
697char*
698makepath(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
726int
727qidhash(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
739void
740freeqid(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
761Qidtab*
762qidlookup(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
774int
775qidexists(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
787Qidtab*
788uniqueqid(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
828void
829fatal(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
852void*
853emallocz(uint n)
854{
855 void *p;
856
857 p = mallocz(n, 1);
858 if(p == nil)
859 fatal(Enomem);
860 return p;
861}
862
863char*
864estrdup(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 */
875int
876filter(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
932static void
933mksecret(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
9typedef struct Fsrpc Fsrpc;
10typedef struct Fid Fid;
11typedef struct File File;
12typedef struct Proc Proc;
13typedef struct Qidtab Qidtab;
14
15struct 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
25struct 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
42struct 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
54struct Proc
55{
56 uintptr pid;
57 int busy;
58 Proc *next;
59};
60
61struct Qidtab
62{
63 int ref;
64 int type;
65 int dev;
66 vlong path;
67 vlong uniqpath;
68 Qidtab *next;
69};
70
71enum
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
82char Ebadfid[];
83char Enotdir[];
84char Edupfid[];
85char Eopen[];
86char Exmnt[];
87char Enomem[];
88char Emip[];
89char Enopsmt[];
90
91Extern Fsrpc *Workq;
92Extern int dbg;
93Extern File *root;
94Extern File *psmpt;
95Extern Fid **fhash;
96Extern Fid *fidfree;
97Extern Proc *Proclist;
98Extern char psmap[Npsmpt];
99Extern Qidtab *qidtab[Nqidtab];
100Extern ulong messagesize;
101Extern char Enomem[];
102Extern int srvfd;
103Extern char* patternfile;
104
105/* File system protocol service procedures */
106void Xattach(Fsrpc*);
107void Xauth(Fsrpc*);
108void Xclunk(Fsrpc*);
109void Xcreate(Fsrpc*);
110void Xflush(Fsrpc*);
111void Xnop(Fsrpc*);
112void Xremove(Fsrpc*);
113void Xstat(Fsrpc*);
114void Xversion(Fsrpc*);
115void Xwalk(Fsrpc*);
116void Xwstat(Fsrpc*);
117void slave(Fsrpc*);
118
119void reply(Fcall*, Fcall*, char*);
120Fid *getfid(int);
121int freefid(int);
122Fid *newfid(int);
123Fsrpc *getsbuf(void);
124void initroot(void);
125void fatal(char*, ...);
126char* makepath(File*, char*);
127File *file(File*, char*);
128void freefile(File*);
129void slaveopen(Fsrpc*);
130void slaveread(Fsrpc*);
131void slavewrite(Fsrpc*);
132void blockingslave(void);
133void reopen(Fid *f);
134void noteproc(int, char*);
135void flushaction(void*, char*);
136void pushfcall(char*);
137Qidtab* uniqueqid(Dir*);
138void freeqid(Qidtab*);
139char* estrdup(char*);
140void* emallocz(uint);
141int readmessage(int, char*, int);
142void exclusions(void);
143int excludefile(char*);
144int 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
8extern char *netdir, *local, *remote;
9
10char Ebadfid[] = "Bad fid";
11char Enotdir[] = "Not a directory";
12char Edupfid[] = "Fid already in use";
13char Eopen[] = "Fid already opened";
14char Exmnt[] = "Cannot .. past mount point";
15char Emip[] = "Mount in progress";
16char Enopsmt[] = "Out of pseudo mount points";
17char Enomem[] = "No memory";
18char Eversion[] = "Bad 9P2000 version";
19char Ereadonly[] = "File system read only";
20
21ulong messagesize;
22int readonly;
23
24void
25Xversion(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
42void
43Xauth(Fsrpc *t)
44{
45 Fcall rhdr;
46
47 reply(&t->work, &rhdr, "exportfs: authentication not required");
48 t->busy = 0;
49}
50
51void
52Xflush(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
78void
79Xattach(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
132Fid*
133clonefid(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
154void
155Xwalk(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
215void
216Xclunk(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
236void
237Xstat(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
279static int
280getiounit(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
290void
291Xcreate(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
338void
339Xremove(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
377void
378Xwstat(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 */
434void
435procsetname(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
455void
456slave(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
522void
523blockingslave(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) {
562flushme:
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
572int
573openmount(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
612void
613slaveopen(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
666void
667slaveread(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
711void
712slavewrite(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
745void
746reopen(Fid *f)
747{
748 USED(f);
749 fatal("reopen");
750}
751
752void
753flushaction(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
3TARG=exportfs
4OFILES=\
5 exportfs.$O\
6 exportsrv.$O\
7 pattern.$O\
8
9HFILES=exportfs.h\
10
11BIN=/$objtype/bin
12
13UPDATE=\
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
9Reprog **exclude, **include;
10char *patternfile;
11
12void
13exclusions(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
72int
73excludefile(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
99int
100preaddir(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 }
147skipentry: 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
30 30
31# setup 31# setup
32#32#
33NUM=3233NUM=16
34
35# exportfs 14181: warning: process exceeds 100 file descriptors
36# exportfs: No more work buffers
37#NUM=32
34#NUM=25638#NUM=256
35 39
36I_MAX=440I_MAX=4
sys/src/cmd/uem/tests/pbg_4.rc+3−1
@@ -26,7 +26,9 @@ CMD='../8.poke -L '$TESTDIR · 25 unmodified lines
26 26
27# setup 27# setup
28#28#
29NUM=3229#NUM=64 # succeds
30NUM=75 # succeds
31NUM=80 # fails
30 32
31# NUM=32 # (with 1,4,4) gives33# NUM=32 # (with 1,4,4) gives
32# exportfs 929: warning: process exceeds 100 file descriptors34# exportfs 929: warning: process exceeds 100 file descriptors