#include "all.h"
#include "io.h"
#include "../ip/ip.h"
enum{
Mfs = 1<<0,
Mip = 1<<1, // c.f. ip.h for what these mean.
Mservice = 1<<2,
Msntp = 1<<3,
};
struct
{
char* icharp;
char* charp;
int error;
int newconf; /* clear before start */
uint modconf; /* modification bit array */
int nextiter;
int lastiter;
int diriter;
Device* lastcw;
Device* devlist;
} f;
static Device* confdev;
int
devcmpr(Device *d1, Device *d2)
{
while (d1 != d2) {
if(d1 == 0 || d2 == 0 || 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:
case Devide:
case Devmv:
case Devaoe:
case Devia:
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;
}
}
static vlong
cnumb(void)
{
int c;
vlong 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(c < '0' || c > '9') {
cdiag("number expected", c);
return 0;
}
n = 0;
while(c >= '0' && c <= '9') {
n = n*10 + (c-'0');
c = *f.charp++;
}
f.charp--;
return n;
}
static char*
cstring(void)
{
char c, *s, *p, *e;
p = s = ialloc(NAMELEN, 0);
e = p+NAMELEN-1;
f.charp++;
for(; p < e; ){
c = *f.charp;
f.charp++;
if(c == '"'){
if(*f.charp != '"')
break;
f.charp++;
}
if(c == 0){
cdiag("nil in string", '?');
break;
}
*p++ = c;
}
*p = 0;
if(p == s)
cdiag("nil string", *f.charp);
return s;
}
static Device*
config1(int c)
{
Device *d, *t;
int m;
d = ialloc(sizeof(Device), 0);
for(;;) {
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;
break;
}
if(c == '[' && m == ']') {
d->type = Devmlev;
break;
}
if(c == '{' && m == '}') {
d->type = Devmirr;
break;
}
}
f.charp++;
if(d->cat.first == d->cat.last)
d = d->cat.first;
d->dlink = f.devlist;
f.devlist = d;
return d;
}
Device*
config(void)
{
int c, m;
Device *d;
char *icp;
static int seq;
if(f.error)
return devnone;
d = ialloc(sizeof(Device), 0);
d->dno = seq++;
c = *f.charp++;
switch(c) {
default:
print("%x\n", c);
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 'h': /* h[#.]# ide [ctlr] unit */
case 'm': /* m[#.]# marvell sata [ctlr] unit */
case 'e': /* e[#.]# aoe [ctlr] unit */
case 'a': /* a[#.]# iasata [ctlr] unit */
case 'r': /* r# worm side */
case 'l': /* l# labelled-worm side */
icp = f.charp;
if(c == 'm')
d->type = Devmv;
else if(c == 'h')
d->type = Devide;
else if(c == 'e')
d->type = Devaoe;
else if(c == 'a')
d->type = Devia;
else
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;
break;
}
if(c == 'l') {
d->type = Devlworm;
break;
}
break;
case 'o': /* o ro part of last cw */
if(f.lastcw == 0) {
cdiag("no cw to match", c);
return devnone;
}
f.lastcw->cw.ro->dno = d->dno;
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 = ialloc(sizeof(Device), 0);
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();
if(*f.charp == '"'){
d->part.name = cstring();
break;
}
d->part.base = cnumb();
c = *f.charp++;
if(c != '.')
cdiag("dot expected", c);
d->part.size = cnumb();
if(d->part.size > 100){
if(d->part.size <= d->part.base)
cdiag("partion invalid end", '?');
// d->part.size -= d->part.base;
}
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;
}
static char*
strdup(char *s)
{
int n;
char *s1;
n = strlen(s);
s1 = ialloc(n+1, 0);
strcpy(s1, s);
return s1;
}
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;
}
Device*
devstr(char *s)
{
Device *d;
if((d = iconfig(s)) && f.error == 0)
return d;
return 0;
}
static int
testconfig(char *s)
{
iconfig(s);
return f.error;
}
static int
astrcmp(char *a, char *b)
{
int n, c;
n = strlen(b);
if(memcmp(a, b, n))
return 1;
c = a[n];
if(c == 0) {
aindex = 0;
return 0;
}
if(a[n+1])
return 1;
if(c >= '0' && c <= '9') {
aindex = c - '0';
return 0;
}
return 1;
}
static char*
getipflag(char *word, char *cp, uchar *f)
{
*f = 0;
for(;;){
cp = getwd(word, cp);
if(*word == 0)
break;
*f |= strtoipflag(word);
if(*f == 0xff){
print("bad ip flag\n");
continue;
}
}
return cp;
}
static void
mergeconf(Iobuf *p)
{
char word[Maxword+1];
char *cp;
Filsys *fs;
for (cp = p->iobuf; ; cp++) {
cp = getwd(word, cp);
if(strcmp(word, "") == 0)
return;
else if(strcmp(word, "service") == 0) {
cp = getwd(word, cp);
if((f.modconf&Mservice) == 0)
strcpy(service, word);
}
else if(astrcmp(word, "ip") == 0) {
cp = getwd(word, cp);
if((ipaddr[aindex].modfl&Msysip) == 0)
if(chartoip(ipaddr[aindex].sysip, word))
goto bad;
} else if(astrcmp(word, "ipgw") == 0) {
cp = getwd(word, cp);
if((ipaddr[aindex].modfl&Mdefgwip) == 0)
if(chartoip(ipaddr[aindex].defgwip, word))
goto bad;
} else if(astrcmp(word, "ipsntp") == 0) {
cp = getwd(word, cp);
if((f.modconf&Msntp) == 0)
if(chartoip(sntpip, word))
goto bad;
} else if(astrcmp(word, "ipmask") == 0) {
cp = getwd(word, cp);
if((ipaddr[aindex].modfl&Mdefmask) == 0)
if(chartoip(ipaddr[aindex].defmask, word))
goto bad;
}else if(astrcmp(word, "ipflag") == 0){
uchar *p, d;
if((ipaddr[aindex].modfl&Mflag) == 0)
p = &ipaddr[aindex].flag;
else
p = &d;
cp = getipflag(word, cp, p);
if(d== 0xff)
goto bad;
} else if(strcmp(word, "filsys") == 0) {
cp = getwd(word, cp);
for(fs=filsys; fs->name; fs++)
if(strcmp(fs->name, word) == 0) {
if(fs->flags & FEDIT) {
cp = getwd(word, cp);
goto loop;
}
break;
}
fs->name = strdup(word);
cp = getwd(word, cp);
fs->conf = strdup(word);
} else {
bad:
putbuf(p);
panic("unknown word in config block: %s", word);
}
loop:
if(*cp != '\n')
goto bad;
}
}
void
cmd_printconf(int, char *[])
{
char *p, *s;
Iobuf *iob;
iob = getbuf(confdev, 0, Bread);
if(iob == nil)
return;
if(checktag(iob, Tconfig, 0)){
putbuf(iob);
return;
}
print("config %s\n", nvrgetconfig());
s = p = iob->iobuf;
while(*p != 0 && p < iob->iobuf+BUFSIZE){
if(*p++ != '\n')
continue;
print("%.*s", (int)(p-s), s);
s = p;
}
if(p != s)
print("%.*s", (int)(p-s), s);
print("end\n");
putbuf(iob);
}
void
cmd_writeconf(int, char *[])
{
Iobuf *iob;
iob = getbuf(confdev, 0, Bread);
if(iob == nil)
return;
if(checktag(iob, Tconfig, 0)){
putbuf(iob);
return;
}
iob->flags |= Bmod|Bimm;
putbuf(iob);
print("written\n");
}
void
sysinit(void)
{
Filsys *fs;
int error, i;
Device *d;
Iobuf *p;
char *cp, *s, *e;
dofilter(&cons.work);
dofilter(&cons.rate);
dofilter(&cons.bhit);
dofilter(&cons.bread);
dofilter(&cons.brahead);
dofilter(&cons.binit);
cons.chan = 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, Bread|Bmod);
if(!p || checktag(p, Tconfig, 0))
panic("config io");
mergeconf(p);
if(f.modconf) {
memset(p->iobuf, 0, BUFSIZE);
s = p->iobuf;
e = s+BUFSIZE;
p->flags |= Bmod|Bimm;
s = seprint(s, e, "service %s\n", service);
for(fs=filsys; fs->name; fs++)
if(fs->conf)
s = seprint(s, e, "filsys %s %s\n", fs->name, fs->conf);
if(isvalidip(sntpip))
s = seprint(s, e, "ipsntp %I\n", sntpip);
for(i=0; i<10; i++) {
if(isvalidip(ipaddr[i].sysip))
s = seprint(s, e, "ip%d %I\n", i, ipaddr[i].sysip);
if(isvalidip(ipaddr[i].defgwip))
s = seprint(s, e, "ipgw%d %I\n", i, ipaddr[i].defgwip);
if(isvalidip(ipaddr[i].defmask))
s = seprint(s, e, "ipmask%d %I\n", i, ipaddr[i].defmask);
if(ipaddr[i].flag)
s = seprint(s, e, "ipflag%d %φ\n", i, ipaddr[i].flag);
}
putbuf(p);
f.modconf = 0;
f.newconf = 0;
print("config block written\n");
goto start;
}
putbuf(p);
print("service %s\n", service);
if(isvalidip(sntpip))
print("ipsntp %I\n", sntpip);
for(i=0; i<10; i++)
if(isvalidip(ipaddr[i].sysip)) {
print("ip%d %I\n", i, ipaddr[i].sysip);
print("ipgw%d %I\n", i, ipaddr[i].defgwip);
print("ipmask%d %I\n", i, ipaddr[i].defmask);
if(ipaddr[i].flag)
print("ipflag%d %φ\n", i, ipaddr[i].flag);
}
loop:
/*
* part 2 -- squeeze out the deleted filesystems
*/
for(fs=filsys; fs->name; fs++)
if(fs->conf == 0) {
for(; fs->name; fs++)
*fs = *(fs+1);
goto loop;
}
if(filsys[0].name == 0)
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 3½ -- start ethernet
*/
etherstart();
delay(1000); /* hack. pretend this will get all ifs up before we restart */
aoeinit(0);
/*
* 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);
}
}
void
getline(char *line)
{
char *p;
int c;
p = line;
for(;;) {
c = rawchar(0);
if(c == 0 || c == '\n') {
*p = 0;
return;
}
if(c == '\b') {
p--;
continue;
}
*p++ = c;
}
}
void
arginit(void)
{
int verb, c;
char line[2*Maxword], word[Maxword+1], *cp;
uchar ip[Pasize];
Filsys *fs;
if(nvrcheck() == 0){
print("for config mode hit a key within 5 seconds\n");
c = rawchar(5);
if(c == 0) {
print(" no config\n");
return;
}
}
for (;;) {
print("config: ");
getline(line);
cp = getwd(word, line);
if (word[0] == '\0' || word[0] == '#')
continue;
if(strcmp(word, "end") == 0)
return;
if(strcmp(word, "halt") == 0)
exit();
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, "recoversb") == 0){
getwd(word, cp);
conf.recovsb = strtoull(word, 0, 0);
continue;
}
if(strcmp(word, "filsys") == 0) {
verb = FEDIT;
goto gfsname;
}
if(strcmp(word, "nvram") == 0) {
getwd(word, cp);
if(testconfig(word))
continue;
/* if it fails, it will complain */
nvrsetconfig(word);
continue;
}
if(strcmp(word, "config") == 0) {
getwd(word, cp);
if(!testconfig(word) && nvrsetconfig(word) == 0)
f.newconf = 1;
continue;
}
if(strcmp(word, "service") == 0) {
getwd(word, cp);
strcpy(service, word);
f.modconf |= Mservice;
continue;
}
if(astrcmp(word, "ipflag") == 0){
getipflag(word, cp, &ipaddr[aindex].flag);
if(ipaddr[aindex].flag== 0xff)
continue;
f.modconf |= Mip;
ipaddr[aindex].modfl |= Mflag;
continue;
}
if(astrcmp(word, "ip") == 0)
verb = Msysip;
else if(astrcmp(word, "ipgw") == 0)
verb = Mdefgwip;
else if(astrcmp(word, "ipmask") == 0)
verb = Mdefmask;
else if(astrcmp(word, "ipsntp") == 0)
verb = Msntp;
else {
print("unknown config command\n");
print(" type end to get out\n");
continue;
}
getwd(word, cp);
if(chartoip(ip, word)) {
print("bad ip address\n");
continue;
}
switch(verb) {
case Msysip:
memmove(ipaddr[aindex].sysip, ip, Pasize);
break;
case Mdefmask:
memmove(ipaddr[aindex].defmask, ip, Pasize);
break;
case Mdefgwip:
memmove(ipaddr[aindex].defgwip, ip, Pasize);
break;
case Msntp:
memmove(sntpip, ip, Pasize);
/* BOTCH */
f.modconf |= Msntp;
continue;
}
f.modconf |= Mip;
ipaddr[aindex].modfl |= verb;
continue;
gfsname:
cp = getwd(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:
case FRECOVER:
fs->flags |= verb;
break;
case FEDIT:
f.modconf |= Mfs;
getwd(word, cp);
fs->flags |= verb;
if(word[0] == 0)
fs->conf = nil;
else if(!testconfig(word))
fs->conf = strdup(word);
break;
}
}
}
|