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