xref: /inferno-os/appl/cmd/ndb/cs.b (revision a5e7f7282341dff49881e8b7ce247b44fd8bcc7e)
137da2899SCharles.Forsythimplement Cs;
237da2899SCharles.Forsyth
337da2899SCharles.Forsyth#
437da2899SCharles.Forsyth# Connection server translates net!machine!service into
537da2899SCharles.Forsyth# /net/tcp/clone 135.104.9.53!564
637da2899SCharles.Forsyth#
737da2899SCharles.Forsyth
837da2899SCharles.Forsythinclude "sys.m";
937da2899SCharles.Forsyth	sys:	Sys;
1037da2899SCharles.Forsyth
1137da2899SCharles.Forsythinclude "draw.m";
1237da2899SCharles.Forsyth
1337da2899SCharles.Forsythinclude "srv.m";
1437da2899SCharles.Forsyth	srv: Srv;
1537da2899SCharles.Forsyth
1637da2899SCharles.Forsythinclude "bufio.m";
1737da2899SCharles.Forsythinclude "attrdb.m";
1837da2899SCharles.Forsyth	attrdb: Attrdb;
1937da2899SCharles.Forsyth	Attr, Db, Dbentry, Tuples: import attrdb;
2037da2899SCharles.Forsyth
2137da2899SCharles.Forsythinclude "ip.m";
2237da2899SCharles.Forsyth	ip: IP;
2337da2899SCharles.Forsythinclude "ipattr.m";
2437da2899SCharles.Forsyth	ipattr: IPattr;
2537da2899SCharles.Forsyth
2637da2899SCharles.Forsythinclude "arg.m";
2737da2899SCharles.Forsyth
2837da2899SCharles.ForsythCs: module
2937da2899SCharles.Forsyth{
3037da2899SCharles.Forsyth	init:	fn(nil: ref Draw->Context, nil: list of string);
3137da2899SCharles.Forsyth};
3237da2899SCharles.Forsyth
3337da2899SCharles.Forsyth# signature of dial-on-demand module
3437da2899SCharles.ForsythCSdial: module
3537da2899SCharles.Forsyth{
3637da2899SCharles.Forsyth	init:	fn(nil: ref Draw->Context): string;
3737da2899SCharles.Forsyth	connect:	fn(): string;
3837da2899SCharles.Forsyth};
3937da2899SCharles.Forsyth
4037da2899SCharles.ForsythReply: adt
4137da2899SCharles.Forsyth{
4237da2899SCharles.Forsyth	fid:	int;
4337da2899SCharles.Forsyth	pid:	int;
4437da2899SCharles.Forsyth	addrs:	list of string;
4537da2899SCharles.Forsyth	err:	string;
4637da2899SCharles.Forsyth};
4737da2899SCharles.Forsyth
4837da2899SCharles.ForsythCached: adt
4937da2899SCharles.Forsyth{
5037da2899SCharles.Forsyth	expire:	int;
5137da2899SCharles.Forsyth	query:	string;
5237da2899SCharles.Forsyth	addrs:	list of string;
5337da2899SCharles.Forsyth};
5437da2899SCharles.Forsyth
5537da2899SCharles.ForsythNcache: con 16;
5637da2899SCharles.Forsythcache:= array[Ncache] of ref Cached;
5737da2899SCharles.Forsythnextcache := 0;
5837da2899SCharles.Forsyth
5937da2899SCharles.Forsythrlist: list of ref Reply;
6037da2899SCharles.Forsyth
6137da2899SCharles.Forsythndbfile := "/lib/ndb/local";
6237da2899SCharles.Forsythndb: ref Db;
6337da2899SCharles.Forsythmntpt := "/net";
6437da2899SCharles.Forsythmyname: string;
6537da2899SCharles.Forsyth
6637da2899SCharles.Forsythstderr: ref Sys->FD;
6737da2899SCharles.Forsyth
6837da2899SCharles.Forsythverbose := 0;
6937da2899SCharles.Forsythdialmod: CSdial;
7037da2899SCharles.Forsyth
7137da2899SCharles.Forsythinit(ctxt: ref Draw->Context, args: list of string)
7237da2899SCharles.Forsyth{
7337da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
7437da2899SCharles.Forsyth	stderr = sys->fildes(2);
7537da2899SCharles.Forsyth	attrdb = load Attrdb Attrdb->PATH;
7637da2899SCharles.Forsyth	if(attrdb == nil)
7737da2899SCharles.Forsyth		cantload(Attrdb->PATH);
7837da2899SCharles.Forsyth	attrdb->init();
7937da2899SCharles.Forsyth	ip = load IP IP->PATH;
8037da2899SCharles.Forsyth	if(ip == nil)
8137da2899SCharles.Forsyth		cantload(IP->PATH);
8237da2899SCharles.Forsyth	ip->init();
8337da2899SCharles.Forsyth	ipattr = load IPattr IPattr->PATH;
8437da2899SCharles.Forsyth	if(ipattr == nil)
8537da2899SCharles.Forsyth		cantload(IPattr->PATH);
8637da2899SCharles.Forsyth	ipattr->init(attrdb, ip);
8737da2899SCharles.Forsyth
8837da2899SCharles.Forsyth	svcname := "#scs";
8937da2899SCharles.Forsyth	arg := load Arg Arg->PATH;
9037da2899SCharles.Forsyth	if (arg == nil)
9137da2899SCharles.Forsyth		cantload(Arg->PATH);
9237da2899SCharles.Forsyth	arg->init(args);
9337da2899SCharles.Forsyth	arg->setusage("cs [-v] [-x mntpt] [-f database] [-d dialmod]");
9437da2899SCharles.Forsyth	while((c := arg->opt()) != 0)
9537da2899SCharles.Forsyth		case c {
9637da2899SCharles.Forsyth		'v' or 'D' =>
9737da2899SCharles.Forsyth			verbose++;
9837da2899SCharles.Forsyth		'd' =>	# undocumented hack to replace svc/cs/cs
9937da2899SCharles.Forsyth			f := arg->arg();
10037da2899SCharles.Forsyth			if(f != nil){
10137da2899SCharles.Forsyth				dialmod = load CSdial f;
10237da2899SCharles.Forsyth				if(dialmod == nil)
10337da2899SCharles.Forsyth					cantload(f);
10437da2899SCharles.Forsyth			}
10537da2899SCharles.Forsyth		'f' =>
10637da2899SCharles.Forsyth			ndbfile = arg->earg();
10737da2899SCharles.Forsyth		'x' =>
10837da2899SCharles.Forsyth			mntpt = arg->earg();
10937da2899SCharles.Forsyth			svcname = "#scs"+svcpt(mntpt);
11037da2899SCharles.Forsyth		* =>
11137da2899SCharles.Forsyth			arg->usage();
11237da2899SCharles.Forsyth		}
11337da2899SCharles.Forsyth
11437da2899SCharles.Forsyth	if(arg->argv() != nil)
11537da2899SCharles.Forsyth		arg->usage();
11637da2899SCharles.Forsyth	arg = nil;
11737da2899SCharles.Forsyth
11837da2899SCharles.Forsyth	srv = load Srv Srv->PATH;	# hosted Inferno only
11937da2899SCharles.Forsyth	if(srv != nil)
12037da2899SCharles.Forsyth		srv->init();
12137da2899SCharles.Forsyth
12237da2899SCharles.Forsyth	sys->remove(svcname+"/cs");
12337da2899SCharles.Forsyth	sys->unmount(svcname, mntpt);
12437da2899SCharles.Forsyth	publish(svcname);
12537da2899SCharles.Forsyth	if(sys->bind(svcname, mntpt, Sys->MBEFORE) < 0)
12637da2899SCharles.Forsyth		error(sys->sprint("can't bind #s on %s: %r", mntpt));
12737da2899SCharles.Forsyth	file := sys->file2chan(mntpt, "cs");
12837da2899SCharles.Forsyth	if(file == nil)
12937da2899SCharles.Forsyth		error(sys->sprint("can't make %s/cs: %r", mntpt));
13037da2899SCharles.Forsyth	sys->pctl(Sys->FORKFD|Sys->NEWPGRP, nil);
13137da2899SCharles.Forsyth	refresh();
13237da2899SCharles.Forsyth	if(dialmod != nil){
13337da2899SCharles.Forsyth		e := dialmod->init(ctxt);
13437da2899SCharles.Forsyth		if(e != nil)
13537da2899SCharles.Forsyth			error(sys->sprint("can't initialise dial-on-demand: %s", e));
13637da2899SCharles.Forsyth	}
13737da2899SCharles.Forsyth	spawn cs(file);
13837da2899SCharles.Forsyth}
13937da2899SCharles.Forsyth
14037da2899SCharles.Forsythsvcpt(s: string): string
14137da2899SCharles.Forsyth{
14237da2899SCharles.Forsyth	for(i:=0; i<len s; i++)
14337da2899SCharles.Forsyth		if(s[i] == '/')
14437da2899SCharles.Forsyth			s[i] = '_';
14537da2899SCharles.Forsyth	return s;
14637da2899SCharles.Forsyth}
14737da2899SCharles.Forsyth
14837da2899SCharles.Forsythpublish(dir: string)
14937da2899SCharles.Forsyth{
15037da2899SCharles.Forsyth	d := Sys->nulldir;
15137da2899SCharles.Forsyth	d.mode = 8r777;
15237da2899SCharles.Forsyth	if(sys->wstat(dir, d) < 0)
15337da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "cs: can't publish %s: %r\n", dir);
15437da2899SCharles.Forsyth}
15537da2899SCharles.Forsyth
15637da2899SCharles.Forsythcantload(m: string)
15737da2899SCharles.Forsyth{
15837da2899SCharles.Forsyth	error(sys->sprint("cannot load %s: %r", m));
15937da2899SCharles.Forsyth}
16037da2899SCharles.Forsyth
16137da2899SCharles.Forsytherror(s: string)
16237da2899SCharles.Forsyth{
16337da2899SCharles.Forsyth	sys->fprint(sys->fildes(2), "cs: %s\n", s);
16437da2899SCharles.Forsyth	raise "fail:error";
16537da2899SCharles.Forsyth}
16637da2899SCharles.Forsyth
16737da2899SCharles.Forsythrefresh()
16837da2899SCharles.Forsyth{
16937da2899SCharles.Forsyth	myname = sysname();
17037da2899SCharles.Forsyth	if(ndb == nil){
17137da2899SCharles.Forsyth		ndb2 := Db.open(ndbfile);
17237da2899SCharles.Forsyth		if(ndb2 == nil){
17337da2899SCharles.Forsyth			err := sys->sprint("%r");
17437da2899SCharles.Forsyth			ndb2 = Db.open("/lib/ndb/inferno");	# try to get service map at least
17537da2899SCharles.Forsyth			if(ndb2 == nil)
17637da2899SCharles.Forsyth				sys->fprint(sys->fildes(2), "cs: warning: can't open %s: %s\n", ndbfile, err);	# continue without it
17737da2899SCharles.Forsyth		}
17837da2899SCharles.Forsyth		ndb = Db.open(mntpt+"/ndb");
17937da2899SCharles.Forsyth		if(ndb != nil)
18037da2899SCharles.Forsyth			ndb = ndb.append(ndb2);
18137da2899SCharles.Forsyth		else
18237da2899SCharles.Forsyth			ndb = ndb2;
18337da2899SCharles.Forsyth	}else
18437da2899SCharles.Forsyth		ndb.reopen();
18537da2899SCharles.Forsyth}
18637da2899SCharles.Forsyth
18737da2899SCharles.Forsythsysname(): string
18837da2899SCharles.Forsyth{
18937da2899SCharles.Forsyth	t := rf("/dev/sysname");
19037da2899SCharles.Forsyth	if(t != nil)
19137da2899SCharles.Forsyth		return t;
19237da2899SCharles.Forsyth	t = rf("#e/sysname");
19337da2899SCharles.Forsyth	if(t == nil){
19437da2899SCharles.Forsyth		s := rf(mntpt+"/ndb");
19537da2899SCharles.Forsyth		if(s != nil){
196*a5e7f728SCharles.Forsyth			db := Db.sopen(s);
19737da2899SCharles.Forsyth			if(db != nil){
19837da2899SCharles.Forsyth				(e, nil) := db.find(nil, "sys");
19937da2899SCharles.Forsyth				if(e != nil)
20037da2899SCharles.Forsyth					t = e.findfirst("sys");
20137da2899SCharles.Forsyth			}
20237da2899SCharles.Forsyth		}
20337da2899SCharles.Forsyth	}
20437da2899SCharles.Forsyth	if(t != nil){
20537da2899SCharles.Forsyth		fd := sys->open("/dev/sysname", Sys->OWRITE);
20637da2899SCharles.Forsyth		if(fd != nil)
20737da2899SCharles.Forsyth			sys->fprint(fd, "%s", t);
20837da2899SCharles.Forsyth	}
20937da2899SCharles.Forsyth	return t;
21037da2899SCharles.Forsyth}
21137da2899SCharles.Forsyth
21237da2899SCharles.Forsythrf(name: string): string
21337da2899SCharles.Forsyth{
21437da2899SCharles.Forsyth	fd := sys->open(name, Sys->OREAD);
215*a5e7f728SCharles.Forsyth	buf := array[512] of byte;
21637da2899SCharles.Forsyth	n := sys->read(fd, buf, len buf);
21737da2899SCharles.Forsyth	if(n <= 0)
21837da2899SCharles.Forsyth		return nil;
21937da2899SCharles.Forsyth	return string buf[0:n];
22037da2899SCharles.Forsyth}
22137da2899SCharles.Forsyth
22237da2899SCharles.Forsythcs(file: ref Sys->FileIO)
22337da2899SCharles.Forsyth{
22437da2899SCharles.Forsyth	pidc := chan of int;
22537da2899SCharles.Forsyth	donec := chan of ref Reply;
22637da2899SCharles.Forsyth	for (;;) {
22737da2899SCharles.Forsyth		alt {
22837da2899SCharles.Forsyth		(nil, buf, fid, wc) := <-file.write =>
22937da2899SCharles.Forsyth			cleanfid(fid);	# each write cancels previous requests
23037da2899SCharles.Forsyth			if(dialmod != nil){
23137da2899SCharles.Forsyth				e := dialmod->connect();
23237da2899SCharles.Forsyth				if(e != nil){
23337da2899SCharles.Forsyth					if(len e > 5 && e[0:5]=="fail:")
23437da2899SCharles.Forsyth						e = e[5:];
23537da2899SCharles.Forsyth					if(e == "")
23637da2899SCharles.Forsyth						e = "unknown error";
23737da2899SCharles.Forsyth					wc <-= (0, "cs: dial on demand: "+e);
23837da2899SCharles.Forsyth					break;
23937da2899SCharles.Forsyth				}
24037da2899SCharles.Forsyth			}
24137da2899SCharles.Forsyth			if(wc != nil){
24237da2899SCharles.Forsyth				nbytes := len buf;
24337da2899SCharles.Forsyth				query := string buf;
24437da2899SCharles.Forsyth				if(query == "refresh"){
24537da2899SCharles.Forsyth					refresh();
24637da2899SCharles.Forsyth					wc <-= (nbytes, nil);
24737da2899SCharles.Forsyth					break;
24837da2899SCharles.Forsyth				}
24937da2899SCharles.Forsyth				now := time();
25037da2899SCharles.Forsyth				r := ref Reply;
25137da2899SCharles.Forsyth				r.fid = fid;
25237da2899SCharles.Forsyth				spawn request(r, query, nbytes, now, wc, pidc, donec);
25337da2899SCharles.Forsyth				r.pid = <-pidc;
25437da2899SCharles.Forsyth				rlist = r :: rlist;
25537da2899SCharles.Forsyth			}
25637da2899SCharles.Forsyth
25737da2899SCharles.Forsyth		(off, nbytes, fid, rc) := <-file.read =>
25837da2899SCharles.Forsyth			if(rc != nil){
25937da2899SCharles.Forsyth				r := findfid(fid);
26037da2899SCharles.Forsyth				if(r != nil)
26137da2899SCharles.Forsyth					reply(r, off, nbytes, rc);
26237da2899SCharles.Forsyth				else
26337da2899SCharles.Forsyth					rc <-= (nil, "unknown request");
26437da2899SCharles.Forsyth			} else
26537da2899SCharles.Forsyth				;	# cleanfid(fid);		# compensate for csendq in file2chan
26637da2899SCharles.Forsyth
26737da2899SCharles.Forsyth		r := <-donec =>
26837da2899SCharles.Forsyth			r.pid = 0;
26937da2899SCharles.Forsyth		}
27037da2899SCharles.Forsyth	}
27137da2899SCharles.Forsyth}
27237da2899SCharles.Forsyth
27337da2899SCharles.Forsythfindfid(fid: int): ref Reply
27437da2899SCharles.Forsyth{
27537da2899SCharles.Forsyth	for(rl := rlist; rl != nil; rl = tl rl){
27637da2899SCharles.Forsyth		r := hd rl;
27737da2899SCharles.Forsyth		if(r.fid == fid)
27837da2899SCharles.Forsyth			return r;
27937da2899SCharles.Forsyth	}
28037da2899SCharles.Forsyth	return nil;
28137da2899SCharles.Forsyth}
28237da2899SCharles.Forsyth
28337da2899SCharles.Forsythcleanfid(fid: int)
28437da2899SCharles.Forsyth{
28537da2899SCharles.Forsyth	rl := rlist;
28637da2899SCharles.Forsyth	rlist = nil;
28737da2899SCharles.Forsyth	for(; rl != nil; rl = tl rl){
28837da2899SCharles.Forsyth		r := hd rl;
28937da2899SCharles.Forsyth		if(r.fid != fid)
29037da2899SCharles.Forsyth			rlist = r :: rlist;
29137da2899SCharles.Forsyth		else
29237da2899SCharles.Forsyth			killgrp(r.pid);
29337da2899SCharles.Forsyth	}
29437da2899SCharles.Forsyth}
29537da2899SCharles.Forsyth
29637da2899SCharles.Forsythkillgrp(pid: int)
29737da2899SCharles.Forsyth{
29837da2899SCharles.Forsyth	if(pid != 0){
29937da2899SCharles.Forsyth		fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE);
30037da2899SCharles.Forsyth		if(fd == nil || sys->fprint(fd, "killgrp") < 0)
30137da2899SCharles.Forsyth			sys->fprint(stderr, "cs: can't killgrp %d: %r\n", pid);
30237da2899SCharles.Forsyth	}
30337da2899SCharles.Forsyth}
30437da2899SCharles.Forsyth
30537da2899SCharles.Forsythrequest(r: ref Reply, query: string, nbytes: int, now: int, wc: chan of (int, string), pidc: chan of int, donec: chan of ref Reply)
30637da2899SCharles.Forsyth{
30737da2899SCharles.Forsyth	pidc <-= sys->pctl(Sys->NEWPGRP, nil);
30837da2899SCharles.Forsyth	if(query != nil && query[0] == '!'){
30937da2899SCharles.Forsyth		# general query
31037da2899SCharles.Forsyth		(r.addrs, r.err) = genquery(query[1:]);
31137da2899SCharles.Forsyth	}else{
31237da2899SCharles.Forsyth		(r.addrs, r.err) = xlate(query, now);
31337da2899SCharles.Forsyth		if(r.addrs == nil && r.err == nil)
31437da2899SCharles.Forsyth			r.err = "cs: can't translate address";
31537da2899SCharles.Forsyth	}
31637da2899SCharles.Forsyth	if(r.err != nil){
31737da2899SCharles.Forsyth		if(verbose)
31837da2899SCharles.Forsyth			sys->fprint(stderr, "cs: %s: %s\n", query, r.err);
31937da2899SCharles.Forsyth		wc <-= (0, r.err);
32037da2899SCharles.Forsyth	} else
32137da2899SCharles.Forsyth		wc <-= (nbytes, nil);
32237da2899SCharles.Forsyth	donec <-= r;
32337da2899SCharles.Forsyth}
32437da2899SCharles.Forsyth
32537da2899SCharles.Forsythreply(r: ref Reply, off: int, nbytes: int, rc: chan of (array of byte, string))
32637da2899SCharles.Forsyth{
32737da2899SCharles.Forsyth	if(r.err != nil){
32837da2899SCharles.Forsyth		rc <-= (nil, r.err);
32937da2899SCharles.Forsyth		return;
33037da2899SCharles.Forsyth	}
33137da2899SCharles.Forsyth	addr: string = nil;
33237da2899SCharles.Forsyth	if(r.addrs != nil){
33337da2899SCharles.Forsyth		addr = hd r.addrs;
33437da2899SCharles.Forsyth		r.addrs = tl r.addrs;
33537da2899SCharles.Forsyth	}
33637da2899SCharles.Forsyth	off = 0;	# this version ignores offset
33737da2899SCharles.Forsyth	rc <-= reads(addr, off, nbytes);
33837da2899SCharles.Forsyth}
33937da2899SCharles.Forsyth
34037da2899SCharles.Forsyth#
34137da2899SCharles.Forsyth# return the file2chan reply for a read of the given string
34237da2899SCharles.Forsyth#
34337da2899SCharles.Forsythreads(str: string, off, nbytes: int): (array of byte, string)
34437da2899SCharles.Forsyth{
34537da2899SCharles.Forsyth	bstr := array of byte str;
34637da2899SCharles.Forsyth	slen := len bstr;
34737da2899SCharles.Forsyth	if(off < 0 || off >= slen)
34837da2899SCharles.Forsyth		return (nil, nil);
34937da2899SCharles.Forsyth	if(off + nbytes > slen)
35037da2899SCharles.Forsyth		nbytes = slen - off;
35137da2899SCharles.Forsyth	if(nbytes <= 0)
35237da2899SCharles.Forsyth		return (nil, nil);
35337da2899SCharles.Forsyth	return (bstr[off:off+nbytes], nil);
35437da2899SCharles.Forsyth}
35537da2899SCharles.Forsyth
35637da2899SCharles.Forsythlookcache(query: string, now: int): ref Cached
35737da2899SCharles.Forsyth{
35837da2899SCharles.Forsyth	for(i:=0; i<len cache; i++){
35937da2899SCharles.Forsyth		c := cache[i];
36037da2899SCharles.Forsyth		if(c != nil && c.query == query && now < c.expire){
36137da2899SCharles.Forsyth			if(verbose)
36237da2899SCharles.Forsyth				sys->print("cache: %s -> %s\n", query, hd c.addrs);
36337da2899SCharles.Forsyth			return c;
36437da2899SCharles.Forsyth		}
36537da2899SCharles.Forsyth	}
36637da2899SCharles.Forsyth	return nil;
36737da2899SCharles.Forsyth}
36837da2899SCharles.Forsyth
36937da2899SCharles.Forsythputcache(query: string, addrs: list of string, now: int)
37037da2899SCharles.Forsyth{
37137da2899SCharles.Forsyth	ce := ref Cached;
37237da2899SCharles.Forsyth	ce.expire = now+120;
37337da2899SCharles.Forsyth	ce.query = query;
37437da2899SCharles.Forsyth	ce.addrs = addrs;
37537da2899SCharles.Forsyth	cache[nextcache] = ce;
37637da2899SCharles.Forsyth	nextcache = (nextcache+1)%Ncache;
37737da2899SCharles.Forsyth}
37837da2899SCharles.Forsyth
37937da2899SCharles.Forsythxlate(address: string, now: int): (list of string, string)
38037da2899SCharles.Forsyth{
38137da2899SCharles.Forsyth	n: int;
38237da2899SCharles.Forsyth	l, rl, results: list of string;
38337da2899SCharles.Forsyth	repl, netw, mach, service: string;
38437da2899SCharles.Forsyth
38537da2899SCharles.Forsyth	ce := lookcache(address, now);
38637da2899SCharles.Forsyth	if(ce != nil && ce.addrs != nil)
38737da2899SCharles.Forsyth		return (ce.addrs, nil);
38837da2899SCharles.Forsyth
38937da2899SCharles.Forsyth	(n, l) = sys->tokenize(address, "!\n");
39037da2899SCharles.Forsyth	if(n < 2)
39137da2899SCharles.Forsyth		return (nil, "bad format request");
39237da2899SCharles.Forsyth
39337da2899SCharles.Forsyth	netw = hd l;
39437da2899SCharles.Forsyth	if(netw == "net")
39537da2899SCharles.Forsyth		netw = "tcp";	# TO DO: better (needs lib/ndb)
39637da2899SCharles.Forsyth	if(!isnetwork(netw))
39737da2899SCharles.Forsyth		return (nil, "network unavailable "+netw);
39837da2899SCharles.Forsyth	l = tl l;
39937da2899SCharles.Forsyth
40037da2899SCharles.Forsyth	if(!isipnet(netw)) {
40137da2899SCharles.Forsyth		repl = mntpt + "/" + netw + "/clone ";
40237da2899SCharles.Forsyth		for(;;){
40337da2899SCharles.Forsyth			repl += hd l;
40437da2899SCharles.Forsyth			if((l = tl l) == nil)
40537da2899SCharles.Forsyth				break;
40637da2899SCharles.Forsyth			repl += "!";
40737da2899SCharles.Forsyth		}
40837da2899SCharles.Forsyth		return (repl :: nil, nil);	# no need to cache
40937da2899SCharles.Forsyth	}
41037da2899SCharles.Forsyth
41137da2899SCharles.Forsyth	if(n != 3)
41237da2899SCharles.Forsyth		return (nil, "bad format request");
41337da2899SCharles.Forsyth	mach = hd l;
41437da2899SCharles.Forsyth	service = hd tl l;
41537da2899SCharles.Forsyth
41637da2899SCharles.Forsyth	if(!isnumeric(service)) {
41737da2899SCharles.Forsyth		s := xlatesvc(netw, service);
41837da2899SCharles.Forsyth		if(s == nil){
41937da2899SCharles.Forsyth			if(srv != nil)
42037da2899SCharles.Forsyth				s = srv->ipn2p(netw, service);
42137da2899SCharles.Forsyth			if(s == nil)
42237da2899SCharles.Forsyth				return (nil, "cs: can't translate service");
42337da2899SCharles.Forsyth		}
42437da2899SCharles.Forsyth		service = s;
42537da2899SCharles.Forsyth	}
42637da2899SCharles.Forsyth
42737da2899SCharles.Forsyth	attr := ipattr->dbattr(mach);
42837da2899SCharles.Forsyth	if(mach == "*")
42937da2899SCharles.Forsyth		l = "" :: nil;
43037da2899SCharles.Forsyth	else if(attr != "ip") {
43137da2899SCharles.Forsyth		# Symbolic server == "$SVC"
43237da2899SCharles.Forsyth		if(mach[0] == '$' && len mach > 1 && ndb != nil){
43337da2899SCharles.Forsyth			(s, nil) := ipattr->findnetattr(ndb, "sys", myname, mach[1:]);
43437da2899SCharles.Forsyth			if(s == nil){
43537da2899SCharles.Forsyth				names := dblook("infernosite", "", mach[1:]);
43637da2899SCharles.Forsyth				if(names == nil)
43737da2899SCharles.Forsyth					return (nil, "cs: can't translate "+mach);
43837da2899SCharles.Forsyth				s = hd names;
43937da2899SCharles.Forsyth			}
44037da2899SCharles.Forsyth			mach = s;
44137da2899SCharles.Forsyth			attr = ipattr->dbattr(mach);
44237da2899SCharles.Forsyth		}
44337da2899SCharles.Forsyth		if(attr == "sys"){
44437da2899SCharles.Forsyth			results = dblook("sys", mach, "ip");
44537da2899SCharles.Forsyth			if(results != nil)
44637da2899SCharles.Forsyth				attr = "ip";
44737da2899SCharles.Forsyth		}
44837da2899SCharles.Forsyth		if(attr != "ip"){
44937da2899SCharles.Forsyth			err: string;
45037da2899SCharles.Forsyth			(results, err) = querydns(mach, "ip");
45137da2899SCharles.Forsyth			if(err != nil)
45237da2899SCharles.Forsyth				return (nil, err);
45337da2899SCharles.Forsyth		}else if(results == nil)
45437da2899SCharles.Forsyth			results = mach :: nil;
45537da2899SCharles.Forsyth		l = results;
45637da2899SCharles.Forsyth		if(l == nil){
45737da2899SCharles.Forsyth			if(srv != nil)
45837da2899SCharles.Forsyth				l = srv->iph2a(mach);
45937da2899SCharles.Forsyth			if(l == nil)
46037da2899SCharles.Forsyth				return (nil, "cs: unknown host");
46137da2899SCharles.Forsyth		}
46237da2899SCharles.Forsyth	} else
46337da2899SCharles.Forsyth		l = mach :: nil;
46437da2899SCharles.Forsyth
46537da2899SCharles.Forsyth	while(l != nil) {
46637da2899SCharles.Forsyth		s := hd l;
46737da2899SCharles.Forsyth		l = tl l;
468*a5e7f728SCharles.Forsyth		dnetw := netw;
469*a5e7f728SCharles.Forsyth		if(s != nil){
470*a5e7f728SCharles.Forsyth			(divert, err) := ipattr->findnetattr(ndb, "ip", s, "divert-"+netw);
471*a5e7f728SCharles.Forsyth			if(err == nil && divert != nil){
472*a5e7f728SCharles.Forsyth				dnetw = divert;
473*a5e7f728SCharles.Forsyth				if(!isnetwork(dnetw))
474*a5e7f728SCharles.Forsyth					return (nil, "network unavailable "+dnetw);	# XXX should only give up if all addresses fail?
475*a5e7f728SCharles.Forsyth			}
476*a5e7f728SCharles.Forsyth		}
477*a5e7f728SCharles.Forsyth
47837da2899SCharles.Forsyth		if(s != "")
47937da2899SCharles.Forsyth			s[len s] = '!';
48037da2899SCharles.Forsyth		s += service;
48137da2899SCharles.Forsyth
482*a5e7f728SCharles.Forsyth		repl = mntpt+"/"+dnetw+"/clone "+s;
48337da2899SCharles.Forsyth		if(verbose)
48437da2899SCharles.Forsyth			sys->fprint(stderr, "cs: %s!%s!%s -> %s\n", netw, mach, service, repl);
48537da2899SCharles.Forsyth
48637da2899SCharles.Forsyth		rl = repl :: rl;
48737da2899SCharles.Forsyth	}
48837da2899SCharles.Forsyth	rl = reverse(rl);
48937da2899SCharles.Forsyth	putcache(address, rl, now);
49037da2899SCharles.Forsyth	return (rl, nil);
49137da2899SCharles.Forsyth}
49237da2899SCharles.Forsyth
49337da2899SCharles.Forsythquerydns(name: string, rtype: string): (list of string, string)
49437da2899SCharles.Forsyth{
49537da2899SCharles.Forsyth	fd := sys->open(mntpt+"/dns", Sys->ORDWR);
49637da2899SCharles.Forsyth	if(fd == nil)
49737da2899SCharles.Forsyth		return (nil, nil);
49837da2899SCharles.Forsyth	if(sys->fprint(fd, "%s %s", name, rtype) < 0)
49937da2899SCharles.Forsyth		return (nil, sys->sprint("%r"));
50037da2899SCharles.Forsyth	rl: list of string;
50137da2899SCharles.Forsyth	buf := array[256] of byte;
50237da2899SCharles.Forsyth	sys->seek(fd, big 0, 0);
50337da2899SCharles.Forsyth	while((n := sys->read(fd, buf, len buf)) > 0){
50437da2899SCharles.Forsyth		# name rtype value
50537da2899SCharles.Forsyth		(nf, fld) := sys->tokenize(string buf[0:n], " \t");
50637da2899SCharles.Forsyth		if(nf != 3){
50737da2899SCharles.Forsyth			sys->fprint(stderr, "cs: odd result from dns: %s\n", string buf[0:n]);
50837da2899SCharles.Forsyth			continue;
50937da2899SCharles.Forsyth		}
51037da2899SCharles.Forsyth		rl = hd tl tl fld :: rl;
51137da2899SCharles.Forsyth	}
51237da2899SCharles.Forsyth	return (reverse(rl), nil);
51337da2899SCharles.Forsyth}
51437da2899SCharles.Forsyth
51537da2899SCharles.Forsythdblook(attr: string, val: string, rattr: string): list of string
51637da2899SCharles.Forsyth{
51737da2899SCharles.Forsyth	rl: list of string;
51837da2899SCharles.Forsyth	ptr: ref Attrdb->Dbptr;
51937da2899SCharles.Forsyth	for(;;){
52037da2899SCharles.Forsyth		e: ref Dbentry;
52137da2899SCharles.Forsyth		(e, ptr) = ndb.findbyattr(ptr, attr, val, rattr);
52237da2899SCharles.Forsyth		if(e == nil)
52337da2899SCharles.Forsyth			break;
52437da2899SCharles.Forsyth		for(l := e.findbyattr(attr, val, rattr); l != nil; l = tl l){
52537da2899SCharles.Forsyth			(nil, al) := hd l;
52637da2899SCharles.Forsyth			for(; al != nil; al = tl al)
52737da2899SCharles.Forsyth				if(!inlist((hd al).val, rl))
52837da2899SCharles.Forsyth					rl = (hd al).val :: rl;
52937da2899SCharles.Forsyth		}
53037da2899SCharles.Forsyth	}
53137da2899SCharles.Forsyth	return reverse(rl);
53237da2899SCharles.Forsyth}
53337da2899SCharles.Forsyth
53437da2899SCharles.Forsythinlist(s: string, l: list of string): int
53537da2899SCharles.Forsyth{
53637da2899SCharles.Forsyth	for(; l != nil; l = tl l)
53737da2899SCharles.Forsyth		if(hd l == s)
53837da2899SCharles.Forsyth			return 1;
53937da2899SCharles.Forsyth	return 0;
54037da2899SCharles.Forsyth}
54137da2899SCharles.Forsyth
54237da2899SCharles.Forsythreverse(l: list of string): list of string
54337da2899SCharles.Forsyth{
54437da2899SCharles.Forsyth	t: list of string;
54537da2899SCharles.Forsyth	for(; l != nil; l = tl l)
54637da2899SCharles.Forsyth		t = hd l :: t;
54737da2899SCharles.Forsyth	return t;
54837da2899SCharles.Forsyth}
54937da2899SCharles.Forsyth
55037da2899SCharles.Forsythisnumeric(a: string): int
55137da2899SCharles.Forsyth{
55237da2899SCharles.Forsyth	i, c: int;
55337da2899SCharles.Forsyth
55437da2899SCharles.Forsyth	for(i = 0; i < len a; i++) {
55537da2899SCharles.Forsyth		c = a[i];
55637da2899SCharles.Forsyth		if(c < '0' || c > '9')
55737da2899SCharles.Forsyth			return 0;
55837da2899SCharles.Forsyth	}
55937da2899SCharles.Forsyth	return 1;
56037da2899SCharles.Forsyth}
56137da2899SCharles.Forsyth
56237da2899SCharles.Forsythnets: list of string;
56337da2899SCharles.Forsyth
56437da2899SCharles.Forsythisnetwork(s: string) : int
56537da2899SCharles.Forsyth{
56637da2899SCharles.Forsyth	if(find(s, nets))
56737da2899SCharles.Forsyth		return 1;
56837da2899SCharles.Forsyth	(ok, nil) := sys->stat(mntpt+"/"+s+"/clone");
56937da2899SCharles.Forsyth	if(ok >= 0) {
57037da2899SCharles.Forsyth		nets = s :: nets;
57137da2899SCharles.Forsyth		return 1;
57237da2899SCharles.Forsyth	}
57337da2899SCharles.Forsyth	return 0;
57437da2899SCharles.Forsyth}
57537da2899SCharles.Forsyth
57637da2899SCharles.Forsythfind(e: string, l: list of string) : int
57737da2899SCharles.Forsyth{
57837da2899SCharles.Forsyth	for(; l != nil; l = tl l)
57937da2899SCharles.Forsyth		if (e == hd l)
58037da2899SCharles.Forsyth			return 1;
58137da2899SCharles.Forsyth	return 0;
58237da2899SCharles.Forsyth}
58337da2899SCharles.Forsyth
58437da2899SCharles.Forsythisipnet(s: string) : int
58537da2899SCharles.Forsyth{
58637da2899SCharles.Forsyth	return s == "net" || s == "tcp" || s == "udp" || s == "il";
58737da2899SCharles.Forsyth}
58837da2899SCharles.Forsyth
58937da2899SCharles.Forsythxlatesvc(proto: string, s: string): string
59037da2899SCharles.Forsyth{
59137da2899SCharles.Forsyth	if(ndb == nil || s == nil || isnumeric(s))
59237da2899SCharles.Forsyth		return s;
59337da2899SCharles.Forsyth	(e, nil) := ndb.findbyattr(nil, proto, s, "port");
59437da2899SCharles.Forsyth	if(e == nil)
59537da2899SCharles.Forsyth		return nil;
59637da2899SCharles.Forsyth	matches := e.findbyattr(proto, s, "port");
59737da2899SCharles.Forsyth	if(matches == nil)
59837da2899SCharles.Forsyth		return nil;
59937da2899SCharles.Forsyth	(ts, al) := hd matches;
60037da2899SCharles.Forsyth	restricted := "";
60137da2899SCharles.Forsyth	if(ts.hasattr("restricted"))
60237da2899SCharles.Forsyth		restricted = "!r";
60337da2899SCharles.Forsyth	if(verbose > 1)
60437da2899SCharles.Forsyth		sys->print("%s=%q port=%s%s\n", proto, s, (hd al).val, restricted);
60537da2899SCharles.Forsyth	return (hd al).val+restricted;
60637da2899SCharles.Forsyth}
60737da2899SCharles.Forsyth
60837da2899SCharles.Forsythtime(): int
60937da2899SCharles.Forsyth{
61037da2899SCharles.Forsyth	timefd := sys->open("/dev/time", Sys->OREAD);
61137da2899SCharles.Forsyth	if(timefd == nil)
61237da2899SCharles.Forsyth		return 0;
61337da2899SCharles.Forsyth	buf := array[128] of byte;
61437da2899SCharles.Forsyth	sys->seek(timefd, big 0, 0);
61537da2899SCharles.Forsyth	n := sys->read(timefd, buf, len buf);
61637da2899SCharles.Forsyth	if(n < 0)
61737da2899SCharles.Forsyth		return 0;
61837da2899SCharles.Forsyth	return int ((big string buf[0:n]) / big 1000000);
61937da2899SCharles.Forsyth}
62037da2899SCharles.Forsyth
62137da2899SCharles.Forsyth#
62237da2899SCharles.Forsyth# general query: attr1=val1 attr2=val2 ... finds matching tuple(s)
62337da2899SCharles.Forsyth#	where attr1 is the key and val1 can't be *
62437da2899SCharles.Forsyth#
62537da2899SCharles.Forsythgenquery(query: string): (list of string, string)
62637da2899SCharles.Forsyth{
62737da2899SCharles.Forsyth	(tups, err) := attrdb->parseline(query, 0);
62837da2899SCharles.Forsyth	if(err != nil)
62937da2899SCharles.Forsyth		return (nil, "bad query: "+err);
63037da2899SCharles.Forsyth	if(tups == nil)
63137da2899SCharles.Forsyth		return (nil, "bad query");
63237da2899SCharles.Forsyth	pairs := tups.pairs;
63337da2899SCharles.Forsyth	a0 := (hd pairs).attr;
63437da2899SCharles.Forsyth	if(a0 == "ipinfo")
63537da2899SCharles.Forsyth		return (nil, "ipinfo not yet supported");
63637da2899SCharles.Forsyth	v0 := (hd pairs).val;
63737da2899SCharles.Forsyth
63837da2899SCharles.Forsyth	# if((a0 == "dom" || a0 == "ip") && v0 != nil){
63937da2899SCharles.Forsyth	# 	query dns ...
64037da2899SCharles.Forsyth	# }
64137da2899SCharles.Forsyth
64237da2899SCharles.Forsyth	ptr: ref Attrdb->Dbptr;
64337da2899SCharles.Forsyth	e: ref Dbentry;
64437da2899SCharles.Forsyth	for(;;){
64537da2899SCharles.Forsyth		(e, ptr) = ndb.findpair(ptr, a0, v0);
64637da2899SCharles.Forsyth		if(e == nil)
64737da2899SCharles.Forsyth			break;
64837da2899SCharles.Forsyth		for(l := e.lines; l != nil; l = tl l)
64937da2899SCharles.Forsyth			if(qmatch(hd l, tl pairs)){
65037da2899SCharles.Forsyth				ls: list of string;
65137da2899SCharles.Forsyth				for(l = e.lines; l != nil; l = tl l)
65237da2899SCharles.Forsyth					ls = tuptext(hd l) :: ls;
65337da2899SCharles.Forsyth				return (reverse(ls), nil);
65437da2899SCharles.Forsyth			}
65537da2899SCharles.Forsyth	}
65637da2899SCharles.Forsyth	return  (nil, "no match");
65737da2899SCharles.Forsyth}
65837da2899SCharles.Forsyth
65937da2899SCharles.Forsyth#
66037da2899SCharles.Forsyth# see if set of tuples t contains every non-* attr/val pair
66137da2899SCharles.Forsyth#
66237da2899SCharles.Forsythqmatch(t: ref Tuples, av: list of ref Attr): int
66337da2899SCharles.Forsyth{
66437da2899SCharles.ForsythMatch:
66537da2899SCharles.Forsyth	for(; av != nil; av = tl av){
66637da2899SCharles.Forsyth		a := hd av;
66737da2899SCharles.Forsyth		for(pl := t.pairs; pl != nil; pl = tl pl)
66837da2899SCharles.Forsyth			if((hd pl).attr == a.attr &&
66937da2899SCharles.Forsyth			    (a.val == "*" || a.val == (hd pl).val))
67037da2899SCharles.Forsyth				continue Match;
67137da2899SCharles.Forsyth		return 0;
67237da2899SCharles.Forsyth	}
67337da2899SCharles.Forsyth	return 1;
67437da2899SCharles.Forsyth}
67537da2899SCharles.Forsyth
67637da2899SCharles.Forsythtuptext(t: ref Tuples): string
67737da2899SCharles.Forsyth{
67837da2899SCharles.Forsyth	s: string;
67937da2899SCharles.Forsyth	for(pl := t.pairs; pl != nil; pl = tl pl){
68037da2899SCharles.Forsyth		p := hd pl;
68137da2899SCharles.Forsyth		if(s != nil)
68237da2899SCharles.Forsyth			s[len s] = ' ';
68337da2899SCharles.Forsyth		s += sys->sprint("%s=%q", p.attr, p.val);
68437da2899SCharles.Forsyth	}
68537da2899SCharles.Forsyth	return s;
68637da2899SCharles.Forsyth}
687