summaryrefslogtreecommitdiff
path: root/sys/src/cmd/cwfs/config.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/cwfs/config.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cwfs/config.c')
-rwxr-xr-xsys/src/cmd/cwfs/config.c1037
1 files changed, 1037 insertions, 0 deletions
diff --git a/sys/src/cmd/cwfs/config.c b/sys/src/cmd/cwfs/config.c
new file mode 100755
index 000000000..bc0d118ea
--- /dev/null
+++ b/sys/src/cmd/cwfs/config.c
@@ -0,0 +1,1037 @@
+#include "all.h"
+#include "io.h"
+
+static void dowormcopy(void);
+static int dodevcopy(void);
+
+struct {
+ char* icharp;
+ char* charp;
+ int error;
+ int newconf; /* clear before start */
+ int modconf; /* write back when done */
+ int nextiter;
+ int lastiter;
+ int diriter;
+ Device* lastcw;
+ Device* devlist;
+} f;
+
+static Device* confdev;
+static int copyworm = 0, copydev = 0;
+static char *src, *dest;
+
+static int resetparams;
+
+Fspar fspar[] = {
+ { "blocksize", RBUFSIZE, },
+ { "daddrbits", sizeof(Off)*8, },
+ { "indirblks", NIBLOCK, },
+ { "dirblks", NDBLOCK, },
+ { "namelen", NAMELEN, },
+ { nil, 0, },
+};
+
+int
+devcmpr(Device *d1, Device *d2)
+{
+ while (d1 != d2) {
+ if(d1 == nil || d2 == nil || d1->type != d2->type)
+ return 1;
+
+ switch(d1->type) {
+ default:
+ print("can't compare dev: %Z\n", d1);
+ panic("devcmp");
+ return 1;
+
+ case Devmcat:
+ case Devmlev:
+ case Devmirr:
+ d1 = d1->cat.first;
+ d2 = d2->cat.first;
+ while(d1 && d2) {
+ if(devcmpr(d1, d2))
+ return 1;
+ d1 = d1->link;
+ d2 = d2->link;
+ }
+ break;
+
+ case Devnone:
+ return 0;
+
+ case Devro:
+ d1 = d1->ro.parent;
+ d2 = d2->ro.parent;
+ break;
+
+ case Devjuke:
+ case Devcw:
+ if(devcmpr(d1->cw.c, d2->cw.c))
+ return 1;
+ d1 = d1->cw.w;
+ d2 = d2->cw.w;
+ break;
+
+ case Devfworm:
+ d1 = d1->fw.fw;
+ d2 = d2->fw.fw;
+ break;
+
+ case Devwren:
+ case Devworm:
+ case Devlworm:
+ if(d1->wren.ctrl == d2->wren.ctrl)
+ if(d1->wren.targ == d2->wren.targ)
+ if(d1->wren.lun == d2->wren.lun)
+ return 0;
+ return 1;
+
+ case Devpart:
+ if(d1->part.base == d2->part.base)
+ if(d1->part.size == d2->part.size) {
+ d1 = d1->part.d;
+ d2 = d2->part.d;
+ break;
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+cdiag(char *s, int c1)
+{
+
+ f.charp--;
+ if(f.error == 0) {
+ print("config diag: %s -- <%c>\n", s, c1);
+ f.error = 1;
+ }
+}
+
+int
+cnumb(void)
+{
+ int c, n;
+
+ c = *f.charp++;
+ if(c == '<') {
+ n = f.nextiter;
+ if(n >= 0) {
+ f.nextiter = n+f.diriter;
+ if(n == f.lastiter) {
+ f.nextiter = -1;
+ f.lastiter = -1;
+ }
+ do {
+ c = *f.charp++;
+ } while (c != '>');
+ return n;
+ }
+ n = cnumb();
+ if(*f.charp++ != '-') {
+ cdiag("- expected", f.charp[-1]);
+ return 0;
+ }
+ c = cnumb();
+ if(*f.charp++ != '>') {
+ cdiag("> expected", f.charp[-1]);
+ return 0;
+ }
+ f.lastiter = c;
+ f.diriter = 1;
+ if(n > c)
+ f.diriter = -1;
+ f.nextiter = n+f.diriter;
+ return n;
+ }
+ if(!isascii(c) || !isdigit(c)) {
+ cdiag("number expected", c);
+ return 0;
+ }
+ n = 0;
+ while(isascii(c) && isdigit(c)) {
+ n = n*10 + (c-'0');
+ c = *f.charp++;
+ }
+ f.charp--;
+ return n;
+}
+
+Device*
+config1(int c)
+{
+ Device *d, *t;
+ int m;
+
+ d = malloc(sizeof(Device));
+ do {
+ t = config();
+ if(d->cat.first == 0)
+ d->cat.first = t;
+ else
+ d->cat.last->link = t;
+ d->cat.last = t;
+ if(f.error)
+ return devnone;
+ m = *f.charp;
+ if(c == '(' && m == ')')
+ d->type = Devmcat;
+ else if(c == '[' && m == ']')
+ d->type = Devmlev;
+ else if(c == '{' && m == '}')
+ d->type = Devmirr;
+ } while (d->type == 0);
+ f.charp++;
+ if(d->cat.first == d->cat.last)
+ d = d->cat.first;
+ return d;
+}
+
+static void
+map(Device *d)
+{
+ Map *map;
+
+ if (d->type != Devwren || d->wren.mapped)
+ return;
+ for (map = devmap; map != nil; map = map->next)
+ if (devcmpr(d, map->fdev) == 0)
+ break;
+ if (map == nil)
+ return;
+ if (access(map->to, AEXIST) >= 0)
+{ print("map: mapped wren %Z to existing file %s\n", d, map->to); // DEBUG
+ d->wren.file = map->to; /* wren -> file mapping */
+}
+ else if (map->tdev != nil)
+{ print("map: mapped wren %Z to dev %Z\n", d, map->tdev); // DEBUG
+ *d = *map->tdev; /* wren -> wren mapping */
+}
+ else
+ print("bad mapping %Z to %s; no such file or device",
+ d, map->to);
+ d->wren.mapped = 1;
+}
+
+Device*
+config(void)
+{
+ int c, m;
+ Device *d;
+ char *icp;
+
+ if(f.error)
+ return devnone;
+ d = malloc(sizeof(Device));
+
+ c = *f.charp++;
+ switch(c) {
+ default:
+ cdiag("unknown type", c);
+ return devnone;
+
+ case '(': /* (d+) one or multiple cat */
+ case '[': /* [d+] one or multiple interleave */
+ case '{': /* {d+} a mirrored device and optional mirrors */
+ return config1(c);
+
+ case 'f': /* fd fake worm */
+ d->type = Devfworm;
+ d->fw.fw = config();
+ break;
+
+ case 'n':
+ d->type = Devnone;
+ break;
+
+ case 'w': /* w[#.]#[.#] wren [ctrl] unit [lun] */
+ case 'r': /* r# worm side */
+ case 'l': /* l# labelled-worm side */
+ icp = f.charp;
+ d->type = Devwren;
+ d->wren.ctrl = 0;
+ d->wren.targ = cnumb();
+ d->wren.lun = 0;
+ m = *f.charp;
+ if(m == '.') {
+ f.charp++;
+ d->wren.lun = cnumb();
+ m = *f.charp;
+ if(m == '.') {
+ f.charp++;
+ d->wren.ctrl = d->wren.targ;
+ d->wren.targ = d->wren.lun;
+ d->wren.lun = cnumb();
+ }
+ }
+ if(f.nextiter >= 0)
+ f.charp = icp-1;
+ if(c == 'r') /* worms are virtual and not uniqued */
+ d->type = Devworm;
+ else if(c == 'l')
+ d->type = Devlworm;
+ else
+ map(d); /* subject wrens to optional mapping */
+ break;
+
+ case 'o': /* o ro part of last cw */
+ if(f.lastcw == 0) {
+ cdiag("no cw to match", c);
+ return devnone;
+ }
+ return f.lastcw->cw.ro;
+
+ case 'j': /* DD jukebox */
+ d->type = Devjuke;
+ d->j.j = config();
+ d->j.m = config();
+ break;
+
+ case 'c': /* cache/worm */
+ d->type = Devcw;
+ d->cw.c = config();
+ d->cw.w = config();
+ d->cw.ro = malloc(sizeof(Device));
+ d->cw.ro->type = Devro;
+ d->cw.ro->ro.parent = d;
+ f.lastcw = d;
+ break;
+
+ case 'p': /* pd#.# partition base% size% */
+ d->type = Devpart;
+ d->part.d = config();
+ d->part.base = cnumb();
+ c = *f.charp++;
+ if(c != '.')
+ cdiag("dot expected", c);
+ d->part.size = cnumb();
+ break;
+
+ case 'x': /* xD swab a device's metadata */
+ d->type = Devswab;
+ d->swab.d = config();
+ break;
+ }
+ d->dlink = f.devlist;
+ f.devlist = d;
+ return d;
+}
+
+Device*
+iconfig(char *s)
+{
+ Device *d;
+
+ f.nextiter = -1;
+ f.lastiter = -1;
+ f.error = 0;
+ f.icharp = s;
+ f.charp = f.icharp;
+ d = config();
+ if(*f.charp) {
+ cdiag("junk on end", *f.charp);
+ f.error = 1;
+ }
+ return d;
+}
+
+int
+testconfig(char *s)
+{
+ iconfig(s);
+ return f.error;
+}
+
+/*
+ * if b is a prefix of a, return 0.
+ */
+int
+astrcmp(char *a, char *b)
+{
+ int n, c;
+
+ n = strlen(b);
+ if(memcmp(a, b, n) != 0)
+ return 1;
+ c = a[n];
+ if(c == '\0')
+ return 0;
+ if(a[n+1])
+ return 1;
+ if(isascii(c) && isdigit(c))
+ return 0;
+ return 1;
+}
+
+static Fspar *
+getpar(char *name)
+{
+ Fspar *fsp;
+
+ for (fsp = fspar; fsp->name != nil; fsp++)
+ if (strcmp(name, fsp->name) == 0)
+ return fsp;
+ return nil;
+}
+
+/*
+ * continue to parse obsolete keywords so that old configurations can
+ * still work.
+ */
+void
+mergeconf(Iobuf *p)
+{
+ char word[Maxword+1];
+ char *cp;
+ Filsys *fs;
+ Fspar *fsp;
+
+ for (cp = p->iobuf; *cp != '\0'; cp++) {
+ cp = getwrd(word, cp);
+ if(word[0] == '\0')
+ break;
+ else if (word[0] == '#')
+ while (*cp != '\n' && *cp != '\0')
+ cp++;
+ else if(strcmp(word, "service") == 0) {
+ cp = getwrd(word, cp);
+ if(service[0] == 0)
+ strncpy(service, word, sizeof service);
+ } else if(strcmp(word, "ipauth") == 0) /* obsolete */
+ cp = getwrd(word, cp);
+ else if(astrcmp(word, "ip") == 0) /* obsolete */
+ cp = getwrd(word, cp);
+ else if(astrcmp(word, "ipgw") == 0) /* obsolete */
+ cp = getwrd(word, cp);
+ else if(astrcmp(word, "ipsntp") == 0) /* obsolete */
+ cp = getwrd(word, cp);
+ else if(astrcmp(word, "ipmask") == 0) /* obsolete */
+ cp = getwrd(word, cp);
+ else if(strcmp(word, "filsys") == 0) {
+ cp = getwrd(word, cp);
+ for(fs = filsys; fs < filsys + nelem(filsys) - 1 &&
+ fs->name; fs++)
+ if(strcmp(fs->name, word) == 0)
+ break;
+ if (fs >= filsys + nelem(filsys) - 1)
+ panic("out of filsys structures");
+ if (fs->name && strcmp(fs->name, word) == 0 &&
+ fs->flags & FEDIT)
+ cp = getwrd(word, cp); /* swallow conf */
+ else {
+ fs->name = strdup(word);
+ cp = getwrd(word, cp);
+ if (word[0] == '\0')
+ fs->conf = nil;
+ else
+ fs->conf = strdup(word);
+ }
+ } else if ((fsp = getpar(word)) != nil) {
+ cp = getwrd(word, cp);
+ if (!isascii(word[0]) || !isdigit(word[0]))
+ print("bad %s value: %s", fsp->name, word);
+ else
+ fsp->declared = atol(word);
+ } else {
+ putbuf(p);
+ panic("unknown keyword in config block: %s", word);
+ }
+
+ if(*cp != '\n') {
+ putbuf(p);
+ panic("syntax error in config block at `%s'", word);
+ }
+ }
+}
+
+void
+cmd_printconf(int, char *[])
+{
+ char *p, *s;
+ Iobuf *iob;
+
+ iob = getbuf(confdev, 0, Brd);
+ if(iob == nil)
+ return;
+ if(checktag(iob, Tconfig, 0)){
+ putbuf(iob);
+ return;
+ }
+
+ print("config %s\n", nvrgetconfig());
+ for(s = p = iob->iobuf; *p != 0 && p < iob->iobuf+BUFSIZE; ){
+ if(*p++ != '\n')
+ continue;
+ if (strncmp(s, "ip", 2) != 0) /* don't print obsolete cmds */
+ print("%.*s", (int)(p-s), s);
+ s = p;
+ }
+ if(p != s)
+ print("%.*s", (int)(p-s), s);
+ print("end\n");
+
+ putbuf(iob);
+}
+
+void
+sysinit(void)
+{
+ int error;
+ char *cp, *ep;
+ Device *d;
+ Filsys *fs;
+ Fspar *fsp;
+ Iobuf *p;
+
+ cons.chan = fs_chaninit(Devcon, 1, 0);
+
+start:
+ /*
+ * part 1 -- read the config file
+ */
+ devnone = iconfig("n");
+
+ cp = nvrgetconfig();
+ print("config %s\n", cp);
+
+ confdev = d = iconfig(cp);
+ devinit(d);
+ if(f.newconf) {
+ p = getbuf(d, 0, Bmod);
+ memset(p->iobuf, 0, RBUFSIZE);
+ settag(p, Tconfig, 0);
+ } else
+ p = getbuf(d, 0, Brd|Bmod);
+ if(!p || checktag(p, Tconfig, 0))
+ panic("config io");
+
+ mergeconf(p);
+
+ if (resetparams) {
+ for (fsp = fspar; fsp->name != nil; fsp++)
+ fsp->declared = 0;
+ resetparams = 0;
+ }
+
+ for (fsp = fspar; fsp->name != nil; fsp++) {
+ /* supply defaults from this cwfs instance */
+ if (fsp->declared == 0) {
+ fsp->declared = fsp->actual;
+ f.modconf = 1;
+ }
+ /* warn if declared value is not our compiled-in value */
+ if (fsp->declared != fsp->actual)
+ print("warning: config %s %ld != compiled-in %ld\n",
+ fsp->name, fsp->declared, fsp->actual);
+ }
+
+ if(f.modconf) {
+ memset(p->iobuf, 0, BUFSIZE);
+ p->flags |= Bmod|Bimm;
+ cp = p->iobuf;
+ ep = p->iobuf + RBUFSIZE - 1;
+ if(service[0])
+ cp = seprint(cp, ep, "service %s\n", service);
+ for(fs=filsys; fs->name; fs++)
+ if(fs->conf && fs->conf[0] != '\0')
+ cp = seprint(cp, ep, "filsys %s %s\n", fs->name,
+ fs->conf);
+
+ for (fsp = fspar; fsp->name != nil; fsp++)
+ cp = seprint(cp, ep, "%s %ld\n",
+ fsp->name, fsp->declared);
+
+ putbuf(p);
+ f.modconf = f.newconf = 0;
+ print("config block written\n");
+ goto start;
+ }
+ putbuf(p);
+
+ print("service %s\n", service);
+
+loop:
+ /*
+ * part 2 -- squeeze out the deleted filesystems
+ */
+ for(fs=filsys; fs->name; fs++)
+ if(fs->conf == nil || fs->conf[0] == '\0') {
+ for(; fs->name; fs++)
+ *fs = *(fs+1);
+ goto loop;
+ }
+ if(filsys[0].name == nil)
+ panic("no filsys");
+
+ /*
+ * part 3 -- compile the device expression
+ */
+ error = 0;
+ for(fs=filsys; fs->name; fs++) {
+ print("filsys %s %s\n", fs->name, fs->conf);
+ fs->dev = iconfig(fs->conf);
+ if(f.error) {
+ error = 1;
+ continue;
+ }
+ }
+ if(error)
+ panic("fs config");
+
+ /*
+ * part 4 -- initialize the devices
+ */
+ for(fs=filsys; fs->name; fs++) {
+ delay(3000);
+ print("sysinit: %s\n", fs->name);
+ if(fs->flags & FREAM)
+ devream(fs->dev, 1);
+ if(fs->flags & FRECOVER)
+ devrecover(fs->dev);
+ devinit(fs->dev);
+ }
+
+ /*
+ * part 5 -- optionally copy devices or worms
+ */
+ if (copyworm) {
+ dowormcopy(); /* can return if user quits early */
+ panic("copyworm bailed out!");
+ }
+ if (copydev)
+ if (dodevcopy() < 0)
+ panic("copydev failed!");
+ else
+ panic("copydev done.");
+}
+
+/* an unfinished idea. a non-blocking rawchar() would help. */
+static int
+userabort(char *msg)
+{
+ USED(msg);
+ return 0;
+}
+
+static int
+blockok(Device *d, Off a)
+{
+ Iobuf *p = getbuf(d, a, Brd);
+
+ if (p == 0) {
+ print("i/o error reading %Z block %lld\n", d, (Wideoff)a);
+ return 0;
+ }
+ putbuf(p);
+ return 1;
+}
+
+/*
+ * special case for fake worms only:
+ * we need to size the inner cw's worm device.
+ * in particular, we want to avoid copying the fake-worm bitmap
+ * at the end of the device.
+ *
+ * N.B.: for real worms (e.g. cw jukes), we need to compute devsize(cw(juke)),
+ * *NOT* devsize(juke).
+ */
+static Device *
+wormof(Device *dev)
+{
+ Device *worm = dev, *cw;
+
+ if (dev->type == Devfworm) {
+ cw = dev->fw.fw;
+ if (cw != nil && cw->type == Devcw)
+ worm = cw->cw.w;
+ }
+ // print("wormof(%Z)=%Z\n", dev, worm);
+ return worm;
+}
+
+/*
+ * return the number of the highest-numbered block actually written, plus 1.
+ * 0 indicates an error.
+ */
+static Devsize
+writtensize(Device *worm)
+{
+ Devsize lim = devsize(worm);
+ Iobuf *p;
+
+ print("devsize(%Z) = %lld\n", worm, (Wideoff)lim);
+ if (!blockok(worm, 0) || !blockok(worm, lim-1))
+ return 0;
+ delay(5*1000);
+ if (userabort("sanity checks"))
+ return 0;
+
+ /* find worm's last valid block in case "worm" is an (f)worm */
+ while (lim > 0) {
+ if (userabort("sizing")) {
+ lim = 0; /* you lose */
+ break;
+ }
+ --lim;
+ p = getbuf(worm, lim, Brd);
+ if (p != 0) { /* actually read one okay? */
+ putbuf(p);
+ break;
+ }
+ }
+ print("limit(%Z) = %lld\n", worm, (Wideoff)lim);
+ if (lim <= 0)
+ return 0;
+ return lim + 1;
+}
+
+/* copy worm fs from "main"'s inner worm to "output" */
+static void
+dowormcopy(void)
+{
+ Filsys *f1, *f2;
+ Device *fdev, *from, *to = nil;
+ Iobuf *p;
+ Off a;
+ Devsize lim;
+
+ /*
+ * convert file system names into Filsyss and Devices.
+ */
+
+ f1 = fsstr("main");
+ if(f1 == nil)
+ panic("main file system missing");
+ fdev = f1->dev;
+ from = wormof(fdev); /* fake worm special */
+ if (from->type != Devfworm && from->type != Devcw) {
+ print("main file system is not a worm; copyworm may not do what you want!\n");
+ print("waiting for 20 seconds...\n");
+ delay(20000);
+ }
+
+ f2 = fsstr("output");
+ if(f2 == nil) {
+ print("no output file system - check only\n\n");
+ print("reading worm from %Z (worm %Z)\n", fdev, from);
+ } else {
+ to = f2->dev;
+ print("\ncopying worm from %Z (worm %Z) to %Z, starting in 8 seconds\n",
+ fdev, from, to);
+ delay(8000);
+ }
+ if (userabort("preparing to copy"))
+ return;
+
+ /*
+ * initialise devices, size them, more sanity checking.
+ */
+
+ devinit(from);
+ if (0 && fdev != from) {
+ devinit(fdev);
+ print("debugging, sizing %Z first\n", fdev);
+ writtensize(fdev);
+ }
+ lim = writtensize(from);
+ if(lim == 0)
+ panic("no blocks to copy on %Z", from);
+ if (to) {
+ print("reaming %Z in 8 seconds\n", to);
+ delay(8000);
+ if (userabort("preparing to ream & copy"))
+ return;
+ devream(to, 0);
+ devinit(to);
+ print("copying worm: %lld blocks from %Z to %Z\n",
+ (Wideoff)lim, from, to);
+ }
+ /* can't read to's blocks in case to is a real WORM device */
+
+ /*
+ * Copy written fs blocks, a block at a time (or just read
+ * if no "output" fs).
+ */
+
+ for (a = 0; a < lim; a++) {
+ if (userabort("copy"))
+ break;
+ p = getbuf(from, a, Brd);
+ /*
+ * if from is a real WORM device, we'll get errors trying to
+ * read unwritten blocks, but the unwritten blocks need not
+ * be contiguous.
+ */
+ if (p == 0) {
+ print("%lld not written yet; can't read\n", (Wideoff)a);
+ continue;
+ }
+ if (to != 0 && devwrite(to, p->addr, p->iobuf) != 0) {
+ print("out block %lld: write error; bailing",
+ (Wideoff)a);
+ break;
+ }
+ putbuf(p);
+ if(a % 20000 == 0)
+ print("block %lld %T\n", (Wideoff)a, time(nil));
+ }
+
+ /*
+ * wrap up: sync target, loop
+ */
+ print("copied %lld blocks from %Z to %Z\n", (Wideoff)a, from, to);
+ sync("wormcopy");
+ delay(2000);
+ print("looping; reset the machine at any time.\n");
+ for (; ; )
+ continue; /* await reset */
+}
+
+/* copy device from src to dest */
+static int
+dodevcopy(void)
+{
+ Device *from, *to;
+ Iobuf *p;
+ Off a;
+ Devsize lim, tosize;
+
+ /*
+ * convert config strings into Devices.
+ */
+ from = iconfig(src);
+ if(f.error || from == nil) {
+ print("bad src device %s\n", src);
+ return -1;
+ }
+ to = iconfig(dest);
+ if(f.error || to == nil) {
+ print("bad dest device %s\n", dest);
+ return -1;
+ }
+
+ /*
+ * initialise devices, size them, more sanity checking.
+ */
+
+ devinit(from);
+ lim = devsize(from);
+ if(lim == 0)
+ panic("no blocks to copy on %Z", from);
+ devinit(to);
+ tosize = devsize(to);
+ if(tosize == 0)
+ panic("no blocks to copy on %Z", to);
+
+ /* use smaller of the device sizes */
+ if (tosize < lim)
+ lim = tosize;
+
+ print("copy %Z to %Z in 8 seconds\n", from, to);
+ delay(8000);
+ if (userabort("preparing to copy"))
+ return -1;
+ print("copying dev: %lld blocks from %Z to %Z\n", (Wideoff)lim,
+ from, to);
+
+ /*
+ * Copy all blocks, a block at a time.
+ */
+
+ for (a = 0; a < lim; a++) {
+ if (userabort("copy"))
+ break;
+ p = getbuf(from, a, Brd);
+ /*
+ * if from is a real WORM device, we'll get errors trying to
+ * read unwritten blocks, but the unwritten blocks need not
+ * be contiguous.
+ */
+ if (p == 0) {
+ print("%lld not written yet; can't read\n", (Wideoff)a);
+ continue;
+ }
+ if (to != 0 && devwrite(to, p->addr, p->iobuf) != 0) {
+ print("out block %lld: write error; bailing",
+ (Wideoff)a);
+ break;
+ }
+ putbuf(p);
+ if(a % 20000 == 0)
+ print("block %lld %T\n", (Wideoff)a, time(nil));
+ }
+
+ /*
+ * wrap up: sync target
+ */
+ print("copied %lld blocks from %Z to %Z\n", (Wideoff)a, from, to);
+ sync("devcopy");
+ return 0;
+}
+
+static void
+setconfig(char *dev)
+{
+ if (dev != nil && !testconfig(dev))
+ nvrsetconfig(dev); /* if it fails, it will complain */
+}
+
+void
+arginit(void)
+{
+ int verb;
+ char *line;
+ char word[Maxword+1], *cp;
+ Filsys *fs;
+
+ if(nvrcheck() == 0) {
+ setconfig(conf.confdev);
+ if (!conf.configfirst)
+ return;
+ }
+
+ /* nvr was bad or invoker requested configuration step */
+ setconfig(conf.confdev);
+ for (;;) {
+ print("config: ");
+ if ((line = Brdline(&bin, '\n')) == nil)
+ return;
+ line[Blinelen(&bin)-1] = '\0';
+
+ cp = getwrd(word, line);
+ if (word[0] == '\0' || word[0] == '#')
+ continue;
+ if(strcmp(word, "end") == 0)
+ return;
+ if(strcmp(word, "halt") == 0)
+ exit();
+ if(strcmp(word, "queryjuke") == 0) {
+ getwrd(word, cp);
+ if(testconfig(word) == 0)
+ querychanger(iconfig(word));
+ continue;
+ }
+
+ if(strcmp(word, "allow") == 0) {
+ wstatallow = 1;
+ writeallow = 1;
+ continue;
+ }
+ if(strcmp(word, "copyworm") == 0) {
+ copyworm = 1;
+ continue;
+ }
+ if(strcmp(word, "copydev") == 0) {
+ cp = getwrd(word, cp);
+ if(testconfig(word))
+ continue;
+ src = strdup(word);
+ getwrd(word, cp);
+ if(testconfig(word))
+ continue;
+ dest = strdup(word);
+ copydev = 1;
+ continue;
+ }
+ if(strcmp(word, "noauth") == 0) {
+ noauth = !noauth;
+ continue;
+ }
+ if(strcmp(word, "noattach") == 0) {
+ noattach = !noattach;
+ continue;
+ }
+ if(strcmp(word, "readonly") == 0) {
+ readonly = 1;
+ continue;
+ }
+
+ if(strcmp(word, "ream") == 0) {
+ verb = FREAM;
+ goto gfsname;
+ }
+ if(strcmp(word, "recover") == 0) {
+ verb = FRECOVER;
+ goto gfsname;
+ }
+ if(strcmp(word, "filsys") == 0) {
+ verb = FEDIT;
+ goto gfsname;
+ }
+
+ if(strcmp(word, "nvram") == 0) {
+ getwrd(word, cp);
+ if(testconfig(word))
+ continue;
+ /* if it fails, it will complain */
+ nvrsetconfig(word);
+ continue;
+ }
+ if(strcmp(word, "config") == 0) {
+ getwrd(word, cp);
+ if(!testconfig(word) && nvrsetconfig(word) == 0)
+ f.newconf = 1;
+ continue;
+ }
+ if(strcmp(word, "service") == 0) {
+ getwrd(word, cp);
+ strncpy(service, word, sizeof service);
+ f.modconf = 1;
+ continue;
+ }
+ if (strcmp(word, "resetparams") == 0) {
+ resetparams++;
+ continue;
+ }
+
+ /*
+ * continue to parse obsolete keywords so that old
+ * configurations can still work.
+ */
+ if (strcmp(word, "ipauth") != 0 &&
+ astrcmp(word, "ip") != 0 &&
+ astrcmp(word, "ipgw") != 0 &&
+ astrcmp(word, "ipmask") != 0 &&
+ astrcmp(word, "ipsntp") != 0) {
+ print("unknown config command\n");
+ print("\ttype end to get out\n");
+ continue;
+ }
+
+ getwrd(word, cp);
+ f.modconf = 1;
+ continue;
+
+ gfsname:
+ cp = getwrd(word, cp);
+ for(fs=filsys; fs->name; fs++)
+ if(strcmp(word, fs->name) == 0)
+ break;
+ if (fs->name == nil) {
+ memset(fs, 0, sizeof *fs);
+ fs->name = strdup(word);
+ }
+ switch(verb) {
+ case FREAM:
+ if(strcmp(fs->name, "main") == 0)
+ wstatallow = 1; /* only set, never reset */
+ /* fallthrough */
+ case FRECOVER:
+ fs->flags |= verb;
+ break;
+ case FEDIT:
+ f.modconf = 1;
+ getwrd(word, cp);
+ fs->flags |= verb;
+ if(word[0] == 0)
+ fs->conf = nil;
+ else if(!testconfig(word))
+ fs->conf = strdup(word);
+ break;
+ }
+ }
+}