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 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 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 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* 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 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* 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* 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 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 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 * 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 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 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 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 614 userabort(char *msg) 615 { 616 USED(msg); 617 return 0; 618 } 619 620 static int 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 * 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 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 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 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 877 setconfig(char *dev) 878 { 879 if (dev != nil && !testconfig(dev)) 880 nvrsetconfig(dev); /* if it fails, it will complain */ 881 } 882 883 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