Plan 9 from Bell Labs’s /usr/web/sources/contrib/quanstro/root/sys/src/fs/port/config.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#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;
		}
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.