4 static void dowormcopy(void);
5 static int dodevcopy(void);
11 int newconf; /* clear before start */
12 int modconf; /* write back when done */
20 static Device* confdev;
21 static int copyworm = 0, copydev = 0;
22 static char *src, *dest;
26 static int readonlyset;
27 static int resetparams;
30 { "blocksize", RBUFSIZE, },
31 { "daddrbits", sizeof(Off)*8, },
32 { "indirblks", NIBLOCK, },
33 { "dirblks", NDBLOCK, },
34 { "namelen", NAMELEN, },
39 devcmpr(Device *d1, Device *d2)
42 if(d1 == nil || d2 == nil || d1->type != d2->type)
47 fprint(2, "can't compare dev: %Z\n", d1);
74 if(devcmpr(d1->cw.c, d2->cw.c))
88 if(d1->wren.file || d2->wren.file){
89 if(d1->wren.file == nil || d2->wren.file == nil)
91 return !!strcmp(d1->wren.file, d2->wren.file);
93 if(d1->wren.ctrl == d2->wren.ctrl)
94 if(d1->wren.targ == d2->wren.targ)
95 if(d1->wren.lun == d2->wren.lun)
100 if(d1->part.base == d2->part.base)
101 if(d1->part.size == d2->part.size) {
113 cdiag(char *s, int c1)
118 print("config diag: %s -- <%c>\n", s, c1);
132 f.nextiter = n+f.diriter;
133 if(n == f.lastiter) {
143 if(*f.charp++ != '-') {
144 cdiag("- expected", f.charp[-1]);
148 if(*f.charp++ != '>') {
149 cdiag("> expected", f.charp[-1]);
156 f.nextiter = n+f.diriter;
159 if(!isascii(c) || !isdigit(c)) {
160 cdiag("number expected", c);
164 while(isascii(c) && isdigit(c)) {
178 d = ialloc(sizeof(Device), 0);
181 if(d->cat.first == 0)
184 d->cat.last->link = t;
189 if(c == '(' && m == ')')
191 else if(c == '[' && m == ']')
193 else if(c == '{' && m == '}')
195 } while (d->type == 0);
197 if(d->cat.first == d->cat.last)
207 if (d->type != Devwren || d->wren.mapped)
209 for (map = devmap; map != nil; map = map->next)
210 if (devcmpr(d, map->fdev) == 0)
214 if (access(map->to, AEXIST) >= 0){
216 print("map: mapped wren %Z to existing file %s\n", d, map->to);
217 d->wren.file = map->to; /* wren -> file mapping */
218 } else if (map->tdev != nil){
220 print("map: mapped wren %Z to dev %Z\n", d, map->tdev);
221 *d = *map->tdev; /* wren -> wren mapping */
223 fprint(2, "bad mapping %Z to %s; no such file or device", d, map->to);
236 d = ialloc(sizeof(Device), 0);
240 cdiag("unknown type", c);
243 case '(': /* (d+) one or multiple cat */
244 case '[': /* [d+] one or multiple interleave */
245 case '{': /* {d+} a mirrored device and optional mirrors */
248 case 'f': /* fd fake worm */
257 case '/': /* /path/to/file mapped file */
258 case '"': /* "/path/to/file" mapped file */
259 case '\'': /* '/path/to/file' mapped file */
264 for(e = s+1; *e; e++)
265 if(*e == ')' || *e == ']' || *e == '}')
270 if((e = strchr(s, c)) == nil){
271 cdiag("unterminated string", c);
279 d->wren.file = ialloc((e - s) + 1, 0);
280 memmove(d->wren.file, s, e - s);
281 d->wren.file[e - s] = 0;
284 case 'w': /* w[#.]#[.#] wren [ctrl] unit [lun] */
292 case 'r': /* r# worm side */
293 case 'l': /* l# labelled-worm side */
297 d->wren.targ = cnumb();
302 d->wren.lun = cnumb();
306 d->wren.ctrl = d->wren.targ;
307 d->wren.targ = d->wren.lun;
308 d->wren.lun = cnumb();
313 if(c == 'r') /* worms are virtual and not uniqued */
318 map(d); /* subject wrens to optional mapping */
321 case 'o': /* o ro part of last cw */
323 cdiag("no cw to match", c);
326 return f.lastcw->cw.ro;
328 case 'j': /* DD jukebox */
334 case 'c': /* cache/worm */
338 d->cw.ro = ialloc(sizeof(Device), 0);
339 d->cw.ro->type = Devro;
340 d->cw.ro->ro.parent = d;
344 case 'p': /* pd#.# partition base% size% */
346 d->part.d = config();
347 d->part.base = cnumb();
350 cdiag("dot expected", c);
351 d->part.size = cnumb();
354 case 'x': /* xD swab a device's metadata */
356 d->swab.d = config();
359 d->dlink = f.devlist;
376 cdiag("junk on end", *f.charp);
390 * if b is a prefix of a, return 0.
393 astrcmp(char *a, char *b)
398 if(memcmp(a, b, n) != 0)
405 if(isascii(c) && isdigit(c))
415 for (fsp = fspar; fsp->name != nil; fsp++)
416 if (strcmp(name, fsp->name) == 0)
422 * continue to parse obsolete keywords so that old configurations can
428 char word[Maxword+1];
441 for (cp = p->iobuf; *cp != '\0'; cp++) {
442 cp = getwrd(word, cp);
445 else if (word[0] == '#')
446 while (*cp != '\n' && *cp != '\0')
448 else if(strcmp(word, "service") == 0) {
449 cp = getwrd(word, cp);
451 strncpy(service, word, sizeof service);
452 } else if(strcmp(word, "noauth") == 0){
455 } else if(strcmp(word, "nonone") == 0){
458 } else if(strcmp(word, "noatime") == 0){
461 } else if(strcmp(word, "readonly") == 0){
464 } else if(strcmp(word, "newcache") == 0){
466 } else if(strcmp(word, "ipauth") == 0) /* obsolete */
467 cp = getwrd(word, cp);
468 else if(astrcmp(word, "ip") == 0) /* obsolete */
469 cp = getwrd(word, cp);
470 else if(astrcmp(word, "ipgw") == 0) /* obsolete */
471 cp = getwrd(word, cp);
472 else if(astrcmp(word, "ipsntp") == 0) /* obsolete */
473 cp = getwrd(word, cp);
474 else if(astrcmp(word, "ipmask") == 0) /* obsolete */
475 cp = getwrd(word, cp);
476 else if(strcmp(word, "filsys") == 0) {
477 cp = getwrd(word, cp);
478 for(fs = filsys; fs < filsys + nelem(filsys) - 1 &&
480 if(strcmp(fs->name, word) == 0)
482 if (fs >= filsys + nelem(filsys) - 1)
483 panic("out of filsys structures");
484 if (fs->name && strcmp(fs->name, word) == 0 &&
486 cp = getwrd(word, cp); /* swallow conf */
488 fs->name = strdup(word);
489 cp = getwrd(word, cp);
493 fs->conf = strdup(word);
495 } else if ((fsp = getpar(word)) != nil) {
496 cp = getwrd(word, cp);
497 if (!isascii(word[0]) || !isdigit(word[0]))
498 fprint(2, "bad %s value: %s", fsp->name, word);
500 fsp->declared = atol(word);
503 panic("unknown keyword in config block: %s", word);
508 panic("syntax error in config block at `%s'", word);
514 cmd_printconf(int, char *[])
519 iob = getbuf(confdev, 0, Brd);
522 if(checktag(iob, Tconfig, 0)){
527 print("config %s\n", nvrgetconfig());
528 for(s = p = iob->iobuf; *p != 0 && p < iob->iobuf+BUFSIZE; ){
531 if (strncmp(s, "ip", 2) != 0) /* don't print obsolete cmds */
532 print("%.*s", utfnlen(s, p-s), s);
536 print("%.*s", utfnlen(s, p-s), s);
552 cons.chan = fs_chaninit(1, 0);
556 * part 1 -- read the config file
558 devnone = iconfig("n");
562 print("config %s\n", cp);
564 confdev = d = iconfig(cp);
567 p = getbuf(d, 0, Bmod);
568 memset(p->iobuf, 0, RBUFSIZE);
569 settag(p, Tconfig, 0);
571 p = getbuf(d, 0, Brd|Bmod);
572 if(!p || checktag(p, Tconfig, 0))
578 for (fsp = fspar; fsp->name != nil; fsp++)
583 for (fsp = fspar; fsp->name != nil; fsp++) {
584 /* supply defaults from this cwfs instance */
585 if (fsp->declared == 0) {
586 fsp->declared = fsp->actual;
589 /* warn if declared value is not our compiled-in value */
590 if (fsp->declared != fsp->actual)
591 fprint(2, "warning: config %s %ld != compiled-in %ld\n",
592 fsp->name, fsp->declared, fsp->actual);
596 memset(p->iobuf, 0, BUFSIZE);
597 p->flags |= Bmod|Bimm;
599 ep = p->iobuf + RBUFSIZE - 1;
601 cp = seprint(cp, ep, "service %s\n", service);
602 for(fs=filsys; fs->name; fs++)
603 if(fs->conf && fs->conf[0] != '\0')
604 cp = seprint(cp, ep, "filsys %s %s\n", fs->name,
607 cp = seprint(cp, ep, "noauth\n");
609 cp = seprint(cp, ep, "nonone\n");
611 cp = seprint(cp, ep, "noatime\n");
613 cp = seprint(cp, ep, "readonly\n");
615 cp = seprint(cp, ep, "newcache\n");
616 for (fsp = fspar; fsp->name != nil; fsp++)
617 cp = seprint(cp, ep, "%s %ld\n",
618 fsp->name, fsp->declared);
621 f.modconf = f.newconf = 0;
627 print("service %s\n", service);
631 * part 2 -- squeeze out the deleted filesystems
633 for(fs=filsys; fs->name; fs++)
634 if(fs->conf == nil || fs->conf[0] == '\0') {
635 for(; fs->name; fs++)
639 if(filsys[0].name == nil)
643 * part 3 -- compile the device expression
646 for(fs=filsys; fs->name; fs++) {
648 print("filsys %s %s\n", fs->name, fs->conf);
649 fs->dev = iconfig(fs->conf);
659 * part 4 -- initialize the devices
661 for(fs=filsys; fs->name; fs++) {
663 print("sysinit: %s\n", fs->name);
664 if(fs->flags & FREAM)
666 if(fs->flags & FRECOVER)
672 * part 5 -- optionally copy devices or worms
675 dowormcopy(); /* can return if user quits early */
676 panic("copyworm bailed out!");
680 panic("copydev failed!");
682 panic("copydev done.");
685 /* an unfinished idea. a non-blocking rawchar() would help. */
694 blockok(Device *d, Off a)
696 Iobuf *p = getbuf(d, a, Brd);
699 fprint(2, "i/o error reading %Z block %lld\n", d, (Wideoff)a);
707 * special case for fake worms only:
708 * we need to size the inner cw's worm device.
709 * in particular, we want to avoid copying the fake-worm bitmap
710 * at the end of the device.
712 * N.B.: for real worms (e.g. cw jukes), we need to compute devsize(cw(juke)),
713 * *NOT* devsize(juke).
718 Device *worm = dev, *cw;
720 if (dev->type == Devfworm) {
722 if (cw != nil && cw->type == Devcw)
729 * return the number of the highest-numbered block actually written, plus 1.
730 * 0 indicates an error.
733 writtensize(Device *worm)
735 Devsize lim = devsize(worm);
739 print("devsize(%Z) = %lld\n", worm, (Wideoff)lim);
740 if (!blockok(worm, 0) || !blockok(worm, lim-1))
743 if(userabort("sanity checks"))
746 /* find worm's last valid block in case "worm" is an (f)worm */
748 if (userabort("sizing")) {
749 lim = 0; /* you lose */
753 p = getbuf(worm, lim, Brd);
754 if (p != 0) { /* actually read one okay? */
760 print("limit(%Z) = %lld\n", worm, (Wideoff)lim);
766 /* copy worm fs from "main"'s inner worm to "output" */
771 Device *fdev, *from, *to = nil;
777 * convert file system names into Filsyss and Devices.
782 panic("main file system missing");
784 from = wormof(fdev); /* fake worm special */
785 if (from->type != Devfworm && from->type != Devcw) {
786 print("main file system is not a worm; copyworm may not do what you want!\n");
787 print("waiting for 20 seconds...\n");
791 f2 = fsstr("output");
793 print("no output file system - check only\n\n");
794 print("reading worm from %Z (worm %Z)\n", fdev, from);
797 print("\ncopying worm from %Z (worm %Z) to %Z, starting in 8 seconds\n",
801 if (userabort("preparing to copy"))
805 * initialise devices, size them, more sanity checking.
809 if (0 && fdev != from) {
811 print("debugging, sizing %Z first\n", fdev);
814 lim = writtensize(from);
816 panic("no blocks to copy on %Z", from);
818 print("reaming %Z in 8 seconds\n", to);
820 if (userabort("preparing to ream & copy"))
824 print("copying worm: %lld blocks from %Z to %Z\n",
825 (Wideoff)lim, from, to);
827 /* can't read to's blocks in case to is a real WORM device */
830 * Copy written fs blocks, a block at a time (or just read
831 * if no "output" fs).
834 for (a = 0; a < lim; a++) {
835 if (userabort("copy"))
837 p = getbuf(from, a, Brd);
839 * if from is a real WORM device, we'll get errors trying to
840 * read unwritten blocks, but the unwritten blocks need not
844 print("%lld not written yet; can't read\n", (Wideoff)a);
847 if (to != 0 && devwrite(to, p->addr, p->iobuf) != 0) {
848 print("out block %lld: write error; bailing",
854 print("block %lld %T\n", (Wideoff)a, time(nil));
858 * wrap up: sync target, loop
860 print("copied %lld blocks from %Z to %Z\n", (Wideoff)a, from, to);
863 print("looping; reset the machine at any time.\n");
865 delay(10000); /* await reset */
868 /* copy device from src to dest */
878 * convert config strings into Devices.
881 if(f.error || from == nil) {
882 print("bad src device %s\n", src);
886 if(f.error || to == nil) {
887 print("bad dest device %s\n", dest);
892 * initialise devices, size them, more sanity checking.
898 panic("no blocks to copy on %Z", from);
900 tosize = devsize(to);
902 panic("no blocks to copy on %Z", to);
904 /* use smaller of the device sizes */
908 print("copy %Z to %Z in 8 seconds\n", from, to);
910 if (userabort("preparing to copy"))
912 print("copying dev: %lld blocks from %Z to %Z\n", (Wideoff)lim,
916 * Copy all blocks, a block at a time.
919 for (a = 0; a < lim; a++) {
920 if (userabort("copy"))
922 p = getbuf(from, a, Brd);
924 * if from is a real WORM device, we'll get errors trying to
925 * read unwritten blocks, but the unwritten blocks need not
929 fprint(2, "%lld not written yet; can't read\n", (Wideoff)a);
932 if (to != 0 && devwrite(to, p->addr, p->iobuf) != 0) {
933 print("out block %lld: write error; bailing",
939 print("block %lld %T\n", (Wideoff)a, time(nil));
943 * wrap up: sync target
945 print("copied %lld blocks from %Z to %Z\n", (Wideoff)a, from, to);
953 if (dev && !testconfig(dev)){
954 nvrsetconfig(dev); /* if it fails, it will complain */
965 char word[Maxword+1], *cp;
968 if(!setconfig(conf.confdev) && !conf.configfirst)
973 if ((line = Brdline(&bin, '\n')) == nil)
975 line[Blinelen(&bin)-1] = '\0';
977 cp = getwrd(word, line);
978 if (word[0] == '\0' || word[0] == '#')
980 if(strcmp(word, "end") == 0)
982 if(strcmp(word, "halt") == 0)
984 if(strcmp(word, "queryjuke") == 0) {
986 if(testconfig(word) == 0)
987 querychanger(iconfig(word));
990 if(strcmp(word, "copyworm") == 0) {
994 if(strcmp(word, "copydev") == 0) {
995 cp = getwrd(word, cp);
1000 if(testconfig(word))
1002 dest = strdup(word);
1006 if(strcmp(word, "noattach") == 0) {
1007 noattach = !noattach;
1008 print("attach %s\n", noattach ? "disallowed" : "allowed");
1011 if(strcmp(word, "noauth") == 0) {
1013 print("auth %s\n", noauth ? "disabled" : "enabled");
1018 if(strcmp(word, "nonone") == 0) {
1020 print("none %s\n", nonone ? "disabled" : "enabled");
1025 if(strcmp(word, "noatime") == 0) {
1027 print("atime %s\n", noatime ? "disabled" : "enabled");
1032 if(strcmp(word, "readonly") == 0) {
1033 readonly = !readonly;
1034 print("filesystem %s\n", readonly ? "readonly" : "writable");
1040 if(strcmp(word, "ream") == 0) {
1044 if(strcmp(word, "recover") == 0) {
1048 if(strcmp(word, "filsys") == 0) {
1053 if(strcmp(word, "nvram") == 0) {
1055 if(testconfig(word))
1057 /* if it fails, it will complain */
1061 if(strcmp(word, "config") == 0) {
1063 if(!testconfig(word) && nvrsetconfig(word) == 0)
1067 if(strcmp(word, "service") == 0) {
1069 strncpy(service, word, sizeof service);
1073 if (strcmp(word, "resetparams") == 0) {
1079 * continue to parse obsolete keywords so that old
1080 * configurations can still work.
1082 if (strcmp(word, "ipauth") != 0 &&
1083 astrcmp(word, "ip") != 0 &&
1084 astrcmp(word, "ipgw") != 0 &&
1085 astrcmp(word, "ipmask") != 0 &&
1086 astrcmp(word, "ipsntp") != 0) {
1087 print("unknown config command\n");
1088 print("\ttype end to get out\n");
1097 cp = getwrd(word, cp);
1098 for(fs=filsys; fs->name; fs++)
1099 if(strcmp(word, fs->name) == 0)
1101 if (fs->name == nil) {
1102 memset(fs, 0, sizeof *fs);
1103 fs->name = strdup(word);
1116 else if(!testconfig(word))
1117 fs->conf = strdup(word);