1 #include "all.h"
2 #include "io.h"
3
4 static void dowormcopy(void);
5 static int dodevcopy(void);
6
7 struct {
8 char* icharp;
9 char* charp;
10 int error;
11 int newconf; /* clear before start */
12 int modconf; /* write back when done */
13 int nextiter;
14 int lastiter;
15 int diriter;
16 Device* lastcw;
17 Device* devlist;
18 } f;
19
20 static Device* confdev;
21 static int copyworm = 0, copydev = 0;
22 static char *src, *dest;
23
24 static int resetparams;
25
26 Fspar fspar[] = {
27 { "blocksize", RBUFSIZE, },
28 { "daddrbits", sizeof(Off)*8, },
29 { "indirblks", NIBLOCK, },
30 { "dirblks", NDBLOCK, },
31 { "namelen", NAMELEN, },
32 { nil, 0, },
33 };
34
35 int
devcmpr(Device * d1,Device * d2)36 devcmpr(Device *d1, Device *d2)
37 {
38 while (d1 != d2) {
39 if(d1 == nil || d2 == nil || d1->type != d2->type)
40 return 1;
41
42 switch(d1->type) {
43 default:
44 print("can't compare dev: %Z\n", d1);
45 panic("devcmp");
46 return 1;
47
48 case Devmcat:
49 case Devmlev:
50 case Devmirr:
51 d1 = d1->cat.first;
52 d2 = d2->cat.first;
53 while(d1 && d2) {
54 if(devcmpr(d1, d2))
55 return 1;
56 d1 = d1->link;
57 d2 = d2->link;
58 }
59 break;
60
61 case Devnone:
62 return 0;
63
64 case Devro:
65 d1 = d1->ro.parent;
66 d2 = d2->ro.parent;
67 break;
68
69 case Devjuke:
70 case Devcw:
71 if(devcmpr(d1->cw.c, d2->cw.c))
72 return 1;
73 d1 = d1->cw.w;
74 d2 = d2->cw.w;
75 break;
76
77 case Devfworm:
78 d1 = d1->fw.fw;
79 d2 = d2->fw.fw;
80 break;
81
82 case Devwren:
83 case Devworm:
84 case Devlworm:
85 if(d1->wren.ctrl == d2->wren.ctrl)
86 if(d1->wren.targ == d2->wren.targ)
87 if(d1->wren.lun == d2->wren.lun)
88 return 0;
89 return 1;
90
91 case Devpart:
92 if(d1->part.base == d2->part.base)
93 if(d1->part.size == d2->part.size) {
94 d1 = d1->part.d;
95 d2 = d2->part.d;
96 break;
97 }
98 return 1;
99 }
100 }
101 return 0;
102 }
103
104 void
cdiag(char * s,int c1)105 cdiag(char *s, int c1)
106 {
107
108 f.charp--;
109 if(f.error == 0) {
110 print("config diag: %s -- <%c>\n", s, c1);
111 f.error = 1;
112 }
113 }
114
115 int
cnumb(void)116 cnumb(void)
117 {
118 int c, n;
119
120 c = *f.charp++;
121 if(c == '<') {
122 n = f.nextiter;
123 if(n >= 0) {
124 f.nextiter = n+f.diriter;
125 if(n == f.lastiter) {
126 f.nextiter = -1;
127 f.lastiter = -1;
128 }
129 do {
130 c = *f.charp++;
131 } while (c != '>');
132 return n;
133 }
134 n = cnumb();
135 if(*f.charp++ != '-') {
136 cdiag("- expected", f.charp[-1]);
137 return 0;
138 }
139 c = cnumb();
140 if(*f.charp++ != '>') {
141 cdiag("> expected", f.charp[-1]);
142 return 0;
143 }
144 f.lastiter = c;
145 f.diriter = 1;
146 if(n > c)
147 f.diriter = -1;
148 f.nextiter = n+f.diriter;
149 return n;
150 }
151 if(!isascii(c) || !isdigit(c)) {
152 cdiag("number expected", c);
153 return 0;
154 }
155 n = 0;
156 while(isascii(c) && isdigit(c)) {
157 n = n*10 + (c-'0');
158 c = *f.charp++;
159 }
160 f.charp--;
161 return n;
162 }
163
164 Device*
config1(int c)165 config1(int c)
166 {
167 Device *d, *t;
168 int m;
169
170 d = malloc(sizeof(Device));
171 do {
172 t = config();
173 if(d->cat.first == 0)
174 d->cat.first = t;
175 else
176 d->cat.last->link = t;
177 d->cat.last = t;
178 if(f.error)
179 return devnone;
180 m = *f.charp;
181 if(c == '(' && m == ')')
182 d->type = Devmcat;
183 else if(c == '[' && m == ']')
184 d->type = Devmlev;
185 else if(c == '{' && m == '}')
186 d->type = Devmirr;
187 } while (d->type == 0);
188 f.charp++;
189 if(d->cat.first == d->cat.last)
190 d = d->cat.first;
191 return d;
192 }
193
194 static void
map(Device * d)195 map(Device *d)
196 {
197 Map *map;
198
199 if (d->type != Devwren || d->wren.mapped)
200 return;
201 for (map = devmap; map != nil; map = map->next)
202 if (devcmpr(d, map->fdev) == 0)
203 break;
204 if (map == nil)
205 return;
206 if (access(map->to, AEXIST) >= 0)
207 { print("map: mapped wren %Z to existing file %s\n", d, map->to); // DEBUG
208 d->wren.file = map->to; /* wren -> file mapping */
209 }
210 else if (map->tdev != nil)
211 { print("map: mapped wren %Z to dev %Z\n", d, map->tdev); // DEBUG
212 *d = *map->tdev; /* wren -> wren mapping */
213 }
214 else
215 print("bad mapping %Z to %s; no such file or device",
216 d, map->to);
217 d->wren.mapped = 1;
218 }
219
220 Device*
config(void)221 config(void)
222 {
223 int c, m;
224 Device *d;
225 char *icp;
226
227 if(f.error)
228 return devnone;
229 d = malloc(sizeof(Device));
230
231 c = *f.charp++;
232 switch(c) {
233 default:
234 cdiag("unknown type", c);
235 return devnone;
236
237 case '(': /* (d+) one or multiple cat */
238 case '[': /* [d+] one or multiple interleave */
239 case '{': /* {d+} a mirrored device and optional mirrors */
240 return config1(c);
241
242 case 'f': /* fd fake worm */
243 d->type = Devfworm;
244 d->fw.fw = config();
245 break;
246
247 case 'n':
248 d->type = Devnone;
249 break;
250
251 case 'w': /* w[#.]#[.#] wren [ctrl] unit [lun] */
252 case 'r': /* r# worm side */
253 case 'l': /* l# labelled-worm side */
254 icp = f.charp;
255 d->type = Devwren;
256 d->wren.ctrl = 0;
257 d->wren.targ = cnumb();
258 d->wren.lun = 0;
259 m = *f.charp;
260 if(m == '.') {
261 f.charp++;
262 d->wren.lun = cnumb();
263 m = *f.charp;
264 if(m == '.') {
265 f.charp++;
266 d->wren.ctrl = d->wren.targ;
267 d->wren.targ = d->wren.lun;
268 d->wren.lun = cnumb();
269 }
270 }
271 if(f.nextiter >= 0)
272 f.charp = icp-1;
273 if(c == 'r') /* worms are virtual and not uniqued */
274 d->type = Devworm;
275 else if(c == 'l')
276 d->type = Devlworm;
277 else
278 map(d); /* subject wrens to optional mapping */
279 break;
280
281 case 'o': /* o ro part of last cw */
282 if(f.lastcw == 0) {
283 cdiag("no cw to match", c);
284 return devnone;
285 }
286 return f.lastcw->cw.ro;
287
288 case 'j': /* DD jukebox */
289 d->type = Devjuke;
290 d->j.j = config();
291 d->j.m = config();
292 break;
293
294 case 'c': /* cache/worm */
295 d->type = Devcw;
296 d->cw.c = config();
297 d->cw.w = config();
298 d->cw.ro = malloc(sizeof(Device));
299 d->cw.ro->type = Devro;
300 d->cw.ro->ro.parent = d;
301 f.lastcw = d;
302 break;
303
304 case 'p': /* pd#.# partition base% size% */
305 d->type = Devpart;
306 d->part.d = config();
307 d->part.base = cnumb();
308 c = *f.charp++;
309 if(c != '.')
310 cdiag("dot expected", c);
311 d->part.size = cnumb();
312 break;
313
314 case 'x': /* xD swab a device's metadata */
315 d->type = Devswab;
316 d->swab.d = config();
317 break;
318 }
319 d->dlink = f.devlist;
320 f.devlist = d;
321 return d;
322 }
323
324 Device*
iconfig(char * s)325 iconfig(char *s)
326 {
327 Device *d;
328
329 f.nextiter = -1;
330 f.lastiter = -1;
331 f.error = 0;
332 f.icharp = s;
333 f.charp = f.icharp;
334 d = config();
335 if(*f.charp) {
336 cdiag("junk on end", *f.charp);
337 f.error = 1;
338 }
339 return d;
340 }
341
342 int
testconfig(char * s)343 testconfig(char *s)
344 {
345 iconfig(s);
346 return f.error;
347 }
348
349 /*
350 * if b is a prefix of a, return 0.
351 */
352 int
astrcmp(char * a,char * b)353 astrcmp(char *a, char *b)
354 {
355 int n, c;
356
357 n = strlen(b);
358 if(memcmp(a, b, n) != 0)
359 return 1;
360 c = a[n];
361 if(c == '\0')
362 return 0;
363 if(a[n+1])
364 return 1;
365 if(isascii(c) && isdigit(c))
366 return 0;
367 return 1;
368 }
369
370 static Fspar *
getpar(char * name)371 getpar(char *name)
372 {
373 Fspar *fsp;
374
375 for (fsp = fspar; fsp->name != nil; fsp++)
376 if (strcmp(name, fsp->name) == 0)
377 return fsp;
378 return nil;
379 }
380
381 /*
382 * continue to parse obsolete keywords so that old configurations can
383 * still work.
384 */
385 void
mergeconf(Iobuf * p)386 mergeconf(Iobuf *p)
387 {
388 char word[Maxword+1];
389 char *cp;
390 Filsys *fs;
391 Fspar *fsp;
392
393 for (cp = p->iobuf; *cp != '\0'; cp++) {
394 cp = getwrd(word, cp);
395 if(word[0] == '\0')
396 break;
397 else if (word[0] == '#')
398 while (*cp != '\n' && *cp != '\0')
399 cp++;
400 else if(strcmp(word, "service") == 0) {
401 cp = getwrd(word, cp);
402 if(service[0] == 0)
403 strncpy(service, word, sizeof service);
404 } else if(strcmp(word, "ipauth") == 0) /* obsolete */
405 cp = getwrd(word, cp);
406 else if(astrcmp(word, "ip") == 0) /* obsolete */
407 cp = getwrd(word, cp);
408 else if(astrcmp(word, "ipgw") == 0) /* obsolete */
409 cp = getwrd(word, cp);
410 else if(astrcmp(word, "ipsntp") == 0) /* obsolete */
411 cp = getwrd(word, cp);
412 else if(astrcmp(word, "ipmask") == 0) /* obsolete */
413 cp = getwrd(word, cp);
414 else if(strcmp(word, "filsys") == 0) {
415 cp = getwrd(word, cp);
416 for(fs = filsys; fs < filsys + nelem(filsys) - 1 &&
417 fs->name; fs++)
418 if(strcmp(fs->name, word) == 0)
419 break;
420 if (fs >= filsys + nelem(filsys) - 1)
421 panic("out of filsys structures");
422 if (fs->name && strcmp(fs->name, word) == 0 &&
423 fs->flags & FEDIT)
424 cp = getwrd(word, cp); /* swallow conf */
425 else {
426 fs->name = strdup(word);
427 cp = getwrd(word, cp);
428 if (word[0] == '\0')
429 fs->conf = nil;
430 else
431 fs->conf = strdup(word);
432 }
433 } else if ((fsp = getpar(word)) != nil) {
434 cp = getwrd(word, cp);
435 if (!isascii(word[0]) || !isdigit(word[0]))
436 print("bad %s value: %s", fsp->name, word);
437 else
438 fsp->declared = atol(word);
439 } else {
440 putbuf(p);
441 panic("unknown keyword in config block: %s", word);
442 }
443
444 if(*cp != '\n') {
445 putbuf(p);
446 panic("syntax error in config block at `%s'", word);
447 }
448 }
449 }
450
451 void
cmd_printconf(int,char * [])452 cmd_printconf(int, char *[])
453 {
454 char *p, *s;
455 Iobuf *iob;
456
457 iob = getbuf(confdev, 0, Brd);
458 if(iob == nil)
459 return;
460 if(checktag(iob, Tconfig, 0)){
461 putbuf(iob);
462 return;
463 }
464
465 print("config %s\n", nvrgetconfig());
466 for(s = p = iob->iobuf; *p != 0 && p < iob->iobuf+BUFSIZE; ){
467 if(*p++ != '\n')
468 continue;
469 if (strncmp(s, "ip", 2) != 0) /* don't print obsolete cmds */
470 print("%.*s", (int)(p-s), s);
471 s = p;
472 }
473 if(p != s)
474 print("%.*s", (int)(p-s), s);
475 print("end\n");
476
477 putbuf(iob);
478 }
479
480 void
sysinit(void)481 sysinit(void)
482 {
483 int error;
484 char *cp, *ep;
485 Device *d;
486 Filsys *fs;
487 Fspar *fsp;
488 Iobuf *p;
489
490 cons.chan = fs_chaninit(Devcon, 1, 0);
491
492 start:
493 /*
494 * part 1 -- read the config file
495 */
496 devnone = iconfig("n");
497
498 cp = nvrgetconfig();
499 print("config %s\n", cp);
500
501 confdev = d = iconfig(cp);
502 devinit(d);
503 if(f.newconf) {
504 p = getbuf(d, 0, Bmod);
505 memset(p->iobuf, 0, RBUFSIZE);
506 settag(p, Tconfig, 0);
507 } else
508 p = getbuf(d, 0, Brd|Bmod);
509 if(!p || checktag(p, Tconfig, 0))
510 panic("config io");
511
512 mergeconf(p);
513
514 if (resetparams) {
515 for (fsp = fspar; fsp->name != nil; fsp++)
516 fsp->declared = 0;
517 resetparams = 0;
518 }
519
520 for (fsp = fspar; fsp->name != nil; fsp++) {
521 /* supply defaults from this cwfs instance */
522 if (fsp->declared == 0) {
523 fsp->declared = fsp->actual;
524 f.modconf = 1;
525 }
526 /* warn if declared value is not our compiled-in value */
527 if (fsp->declared != fsp->actual)
528 print("warning: config %s %ld != compiled-in %ld\n",
529 fsp->name, fsp->declared, fsp->actual);
530 }
531
532 if(f.modconf) {
533 memset(p->iobuf, 0, BUFSIZE);
534 p->flags |= Bmod|Bimm;
535 cp = p->iobuf;
536 ep = p->iobuf + RBUFSIZE - 1;
537 if(service[0])
538 cp = seprint(cp, ep, "service %s\n", service);
539 for(fs=filsys; fs->name; fs++)
540 if(fs->conf && fs->conf[0] != '\0')
541 cp = seprint(cp, ep, "filsys %s %s\n", fs->name,
542 fs->conf);
543
544 for (fsp = fspar; fsp->name != nil; fsp++)
545 cp = seprint(cp, ep, "%s %ld\n",
546 fsp->name, fsp->declared);
547
548 putbuf(p);
549 f.modconf = f.newconf = 0;
550 print("config block written\n");
551 goto start;
552 }
553 putbuf(p);
554
555 print("service %s\n", service);
556
557 loop:
558 /*
559 * part 2 -- squeeze out the deleted filesystems
560 */
561 for(fs=filsys; fs->name; fs++)
562 if(fs->conf == nil || fs->conf[0] == '\0') {
563 for(; fs->name; fs++)
564 *fs = *(fs+1);
565 goto loop;
566 }
567 if(filsys[0].name == nil)
568 panic("no filsys");
569
570 /*
571 * part 3 -- compile the device expression
572 */
573 error = 0;
574 for(fs=filsys; fs->name; fs++) {
575 print("filsys %s %s\n", fs->name, fs->conf);
576 fs->dev = iconfig(fs->conf);
577 if(f.error) {
578 error = 1;
579 continue;
580 }
581 }
582 if(error)
583 panic("fs config");
584
585 /*
586 * part 4 -- initialize the devices
587 */
588 for(fs=filsys; fs->name; fs++) {
589 delay(3000);
590 print("sysinit: %s\n", fs->name);
591 if(fs->flags & FREAM)
592 devream(fs->dev, 1);
593 if(fs->flags & FRECOVER)
594 devrecover(fs->dev);
595 devinit(fs->dev);
596 }
597
598 /*
599 * part 5 -- optionally copy devices or worms
600 */
601 if (copyworm) {
602 dowormcopy(); /* can return if user quits early */
603 panic("copyworm bailed out!");
604 }
605 if (copydev)
606 if (dodevcopy() < 0)
607 panic("copydev failed!");
608 else
609 panic("copydev done.");
610 }
611
612 /* an unfinished idea. a non-blocking rawchar() would help. */
613 static int
userabort(char * msg)614 userabort(char *msg)
615 {
616 USED(msg);
617 return 0;
618 }
619
620 static int
blockok(Device * d,Off a)621 blockok(Device *d, Off a)
622 {
623 Iobuf *p = getbuf(d, a, Brd);
624
625 if (p == 0) {
626 print("i/o error reading %Z block %lld\n", d, (Wideoff)a);
627 return 0;
628 }
629 putbuf(p);
630 return 1;
631 }
632
633 /*
634 * special case for fake worms only:
635 * we need to size the inner cw's worm device.
636 * in particular, we want to avoid copying the fake-worm bitmap
637 * at the end of the device.
638 *
639 * N.B.: for real worms (e.g. cw jukes), we need to compute devsize(cw(juke)),
640 * *NOT* devsize(juke).
641 */
642 static Device *
wormof(Device * dev)643 wormof(Device *dev)
644 {
645 Device *worm = dev, *cw;
646
647 if (dev->type == Devfworm) {
648 cw = dev->fw.fw;
649 if (cw != nil && cw->type == Devcw)
650 worm = cw->cw.w;
651 }
652 // print("wormof(%Z)=%Z\n", dev, worm);
653 return worm;
654 }
655
656 /*
657 * return the number of the highest-numbered block actually written, plus 1.
658 * 0 indicates an error.
659 */
660 static Devsize
writtensize(Device * worm)661 writtensize(Device *worm)
662 {
663 Devsize lim = devsize(worm);
664 Iobuf *p;
665
666 print("devsize(%Z) = %lld\n", worm, (Wideoff)lim);
667 if (!blockok(worm, 0) || !blockok(worm, lim-1))
668 return 0;
669 delay(5*1000);
670 if (userabort("sanity checks"))
671 return 0;
672
673 /* find worm's last valid block in case "worm" is an (f)worm */
674 while (lim > 0) {
675 if (userabort("sizing")) {
676 lim = 0; /* you lose */
677 break;
678 }
679 --lim;
680 p = getbuf(worm, lim, Brd);
681 if (p != 0) { /* actually read one okay? */
682 putbuf(p);
683 break;
684 }
685 }
686 print("limit(%Z) = %lld\n", worm, (Wideoff)lim);
687 if (lim <= 0)
688 return 0;
689 return lim + 1;
690 }
691
692 /* copy worm fs from "main"'s inner worm to "output" */
693 static void
dowormcopy(void)694 dowormcopy(void)
695 {
696 Filsys *f1, *f2;
697 Device *fdev, *from, *to = nil;
698 Iobuf *p;
699 Off a;
700 Devsize lim;
701
702 /*
703 * convert file system names into Filsyss and Devices.
704 */
705
706 f1 = fsstr("main");
707 if(f1 == nil)
708 panic("main file system missing");
709 fdev = f1->dev;
710 from = wormof(fdev); /* fake worm special */
711 if (from->type != Devfworm && from->type != Devcw) {
712 print("main file system is not a worm; copyworm may not do what you want!\n");
713 print("waiting for 20 seconds...\n");
714 delay(20000);
715 }
716
717 f2 = fsstr("output");
718 if(f2 == nil) {
719 print("no output file system - check only\n\n");
720 print("reading worm from %Z (worm %Z)\n", fdev, from);
721 } else {
722 to = f2->dev;
723 print("\ncopying worm from %Z (worm %Z) to %Z, starting in 8 seconds\n",
724 fdev, from, to);
725 delay(8000);
726 }
727 if (userabort("preparing to copy"))
728 return;
729
730 /*
731 * initialise devices, size them, more sanity checking.
732 */
733
734 devinit(from);
735 if (0 && fdev != from) {
736 devinit(fdev);
737 print("debugging, sizing %Z first\n", fdev);
738 writtensize(fdev);
739 }
740 lim = writtensize(from);
741 if(lim == 0)
742 panic("no blocks to copy on %Z", from);
743 if (to) {
744 print("reaming %Z in 8 seconds\n", to);
745 delay(8000);
746 if (userabort("preparing to ream & copy"))
747 return;
748 devream(to, 0);
749 devinit(to);
750 print("copying worm: %lld blocks from %Z to %Z\n",
751 (Wideoff)lim, from, to);
752 }
753 /* can't read to's blocks in case to is a real WORM device */
754
755 /*
756 * Copy written fs blocks, a block at a time (or just read
757 * if no "output" fs).
758 */
759
760 for (a = 0; a < lim; a++) {
761 if (userabort("copy"))
762 break;
763 p = getbuf(from, a, Brd);
764 /*
765 * if from is a real WORM device, we'll get errors trying to
766 * read unwritten blocks, but the unwritten blocks need not
767 * be contiguous.
768 */
769 if (p == 0) {
770 print("%lld not written yet; can't read\n", (Wideoff)a);
771 continue;
772 }
773 if (to != 0 && devwrite(to, p->addr, p->iobuf) != 0) {
774 print("out block %lld: write error; bailing",
775 (Wideoff)a);
776 break;
777 }
778 putbuf(p);
779 if(a % 20000 == 0)
780 print("block %lld %T\n", (Wideoff)a, time(nil));
781 }
782
783 /*
784 * wrap up: sync target, loop
785 */
786 print("copied %lld blocks from %Z to %Z\n", (Wideoff)a, from, to);
787 sync("wormcopy");
788 delay(2000);
789 print("looping; reset the machine at any time.\n");
790 for (; ; )
791 continue; /* await reset */
792 }
793
794 /* copy device from src to dest */
795 static int
dodevcopy(void)796 dodevcopy(void)
797 {
798 Device *from, *to;
799 Iobuf *p;
800 Off a;
801 Devsize lim, tosize;
802
803 /*
804 * convert config strings into Devices.
805 */
806 from = iconfig(src);
807 if(f.error || from == nil) {
808 print("bad src device %s\n", src);
809 return -1;
810 }
811 to = iconfig(dest);
812 if(f.error || to == nil) {
813 print("bad dest device %s\n", dest);
814 return -1;
815 }
816
817 /*
818 * initialise devices, size them, more sanity checking.
819 */
820
821 devinit(from);
822 lim = devsize(from);
823 if(lim == 0)
824 panic("no blocks to copy on %Z", from);
825 devinit(to);
826 tosize = devsize(to);
827 if(tosize == 0)
828 panic("no blocks to copy on %Z", to);
829
830 /* use smaller of the device sizes */
831 if (tosize < lim)
832 lim = tosize;
833
834 print("copy %Z to %Z in 8 seconds\n", from, to);
835 delay(8000);
836 if (userabort("preparing to copy"))
837 return -1;
838 print("copying dev: %lld blocks from %Z to %Z\n", (Wideoff)lim,
839 from, to);
840
841 /*
842 * Copy all blocks, a block at a time.
843 */
844
845 for (a = 0; a < lim; a++) {
846 if (userabort("copy"))
847 break;
848 p = getbuf(from, a, Brd);
849 /*
850 * if from is a real WORM device, we'll get errors trying to
851 * read unwritten blocks, but the unwritten blocks need not
852 * be contiguous.
853 */
854 if (p == 0) {
855 print("%lld not written yet; can't read\n", (Wideoff)a);
856 continue;
857 }
858 if (to != 0 && devwrite(to, p->addr, p->iobuf) != 0) {
859 print("out block %lld: write error; bailing",
860 (Wideoff)a);
861 break;
862 }
863 putbuf(p);
864 if(a % 20000 == 0)
865 print("block %lld %T\n", (Wideoff)a, time(nil));
866 }
867
868 /*
869 * wrap up: sync target
870 */
871 print("copied %lld blocks from %Z to %Z\n", (Wideoff)a, from, to);
872 sync("devcopy");
873 return 0;
874 }
875
876 static void
setconfig(char * dev)877 setconfig(char *dev)
878 {
879 if (dev != nil && !testconfig(dev))
880 nvrsetconfig(dev); /* if it fails, it will complain */
881 }
882
883 void
arginit(void)884 arginit(void)
885 {
886 int verb;
887 char *line;
888 char word[Maxword+1], *cp;
889 Filsys *fs;
890
891 if(nvrcheck() == 0) {
892 setconfig(conf.confdev);
893 if (!conf.configfirst)
894 return;
895 }
896
897 /* nvr was bad or invoker requested configuration step */
898 setconfig(conf.confdev);
899 for (;;) {
900 print("config: ");
901 if ((line = Brdline(&bin, '\n')) == nil)
902 return;
903 line[Blinelen(&bin)-1] = '\0';
904
905 cp = getwrd(word, line);
906 if (word[0] == '\0' || word[0] == '#')
907 continue;
908 if(strcmp(word, "end") == 0)
909 return;
910 if(strcmp(word, "halt") == 0)
911 exit();
912 if(strcmp(word, "queryjuke") == 0) {
913 getwrd(word, cp);
914 if(testconfig(word) == 0)
915 querychanger(iconfig(word));
916 continue;
917 }
918
919 if(strcmp(word, "allow") == 0) {
920 wstatallow = 1;
921 writeallow = 1;
922 continue;
923 }
924 if(strcmp(word, "copyworm") == 0) {
925 copyworm = 1;
926 continue;
927 }
928 if(strcmp(word, "copydev") == 0) {
929 cp = getwrd(word, cp);
930 if(testconfig(word))
931 continue;
932 src = strdup(word);
933 getwrd(word, cp);
934 if(testconfig(word))
935 continue;
936 dest = strdup(word);
937 copydev = 1;
938 continue;
939 }
940 if(strcmp(word, "noauth") == 0) {
941 noauth = !noauth;
942 continue;
943 }
944 if(strcmp(word, "noattach") == 0) {
945 noattach = !noattach;
946 continue;
947 }
948 if(strcmp(word, "readonly") == 0) {
949 readonly = 1;
950 continue;
951 }
952
953 if(strcmp(word, "ream") == 0) {
954 verb = FREAM;
955 goto gfsname;
956 }
957 if(strcmp(word, "recover") == 0) {
958 verb = FRECOVER;
959 goto gfsname;
960 }
961 if(strcmp(word, "filsys") == 0) {
962 verb = FEDIT;
963 goto gfsname;
964 }
965
966 if(strcmp(word, "nvram") == 0) {
967 getwrd(word, cp);
968 if(testconfig(word))
969 continue;
970 /* if it fails, it will complain */
971 nvrsetconfig(word);
972 continue;
973 }
974 if(strcmp(word, "config") == 0) {
975 getwrd(word, cp);
976 if(!testconfig(word) && nvrsetconfig(word) == 0)
977 f.newconf = 1;
978 continue;
979 }
980 if(strcmp(word, "service") == 0) {
981 getwrd(word, cp);
982 strncpy(service, word, sizeof service);
983 f.modconf = 1;
984 continue;
985 }
986 if (strcmp(word, "resetparams") == 0) {
987 resetparams++;
988 continue;
989 }
990
991 /*
992 * continue to parse obsolete keywords so that old
993 * configurations can still work.
994 */
995 if (strcmp(word, "ipauth") != 0 &&
996 astrcmp(word, "ip") != 0 &&
997 astrcmp(word, "ipgw") != 0 &&
998 astrcmp(word, "ipmask") != 0 &&
999 astrcmp(word, "ipsntp") != 0) {
1000 print("unknown config command\n");
1001 print("\ttype end to get out\n");
1002 continue;
1003 }
1004
1005 getwrd(word, cp);
1006 f.modconf = 1;
1007 continue;
1008
1009 gfsname:
1010 cp = getwrd(word, cp);
1011 for(fs=filsys; fs->name; fs++)
1012 if(strcmp(word, fs->name) == 0)
1013 break;
1014 if (fs->name == nil) {
1015 memset(fs, 0, sizeof *fs);
1016 fs->name = strdup(word);
1017 }
1018 switch(verb) {
1019 case FREAM:
1020 if(strcmp(fs->name, "main") == 0)
1021 wstatallow = 1; /* only set, never reset */
1022 /* fallthrough */
1023 case FRECOVER:
1024 fs->flags |= verb;
1025 break;
1026 case FEDIT:
1027 f.modconf = 1;
1028 getwrd(word, cp);
1029 fs->flags |= verb;
1030 if(word[0] == 0)
1031 fs->conf = nil;
1032 else if(!testconfig(word))
1033 fs->conf = strdup(word);
1034 break;
1035 }
1036 }
1037 }
1038