summaryrefslogtreecommitdiff
path: root/os/init
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /os/init
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'os/init')
-rw-r--r--os/init/README5
-rw-r--r--os/init/bootinit.b628
-rw-r--r--os/init/cerf405.b598
-rw-r--r--os/init/cerfinit.b612
-rw-r--r--os/init/evalinit.b119
-rw-r--r--os/init/geninit.b93
-rw-r--r--os/init/i4e.b210
-rw-r--r--os/init/init.b613
-rw-r--r--os/init/ipaqinit.b697
-rw-r--r--os/init/ipeinit.b620
-rw-r--r--os/init/jsinit.b213
-rw-r--r--os/init/mkfile27
-rw-r--r--os/init/mpcinit.b383
-rw-r--r--os/init/pcdemo.b273
-rw-r--r--os/init/pcinit.b405
-rw-r--r--os/init/reminit.b239
-rw-r--r--os/init/rpcginit.b610
-rw-r--r--os/init/shell.b97
-rw-r--r--os/init/soeinit.b613
-rw-r--r--os/init/srvinit.b209
-rw-r--r--os/init/wminit.b231
21 files changed, 7495 insertions, 0 deletions
diff --git a/os/init/README b/os/init/README
new file mode 100644
index 00000000..da86706f
--- /dev/null
+++ b/os/init/README
@@ -0,0 +1,5 @@
+initialisation programs used by various native kernels to set up
+the right environment to invoke a shell, a window system, mux, or
+any specialised application.
+
+even so, there are really more than needed here just now.
diff --git a/os/init/bootinit.b b/os/init/bootinit.b
new file mode 100644
index 00000000..0fcd58ef
--- /dev/null
+++ b/os/init/bootinit.b
@@ -0,0 +1,628 @@
+#
+# Generalized boot Inferno
+#
+
+implement Init;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+ random: Random;
+
+include "tftp.m";
+
+Bootpreadlen: con 128;
+
+Init: module
+{
+ init: fn();
+};
+
+ip: string;
+mask: string;
+fsip: string;
+bootprotocol: string;
+bootserver: string;
+bootfile: string;
+
+debug: con 0;
+
+init()
+{
+ ipavailable: int;
+ sys = load Sys Sys->PATH;
+
+ kexecfd := sys->open("#B/kexec", Sys->OWRITE);
+ if (kexecfd == nil)
+ fatal(sys->sprint("opening #B/kexec: %r"));
+
+ ipavailable = 0;
+ if (dobind("#l", "/net", sys->MREPL) && dobind("#I", "/net", sys->MAFTER))
+ ipavailable = 1;
+
+ dobind("#c", "/dev", sys->MAFTER); # console device
+
+ if (!ipavailable)
+ fatal("no IP stack available");
+ cfd := sys->open("/net/ipifc/clone", sys->ORDWR);
+ if(cfd == nil)
+ fatal(sys->sprint("open /net/ipifc/clone: %r"));
+
+ if (sys->fprint(cfd, "bind ether ether0") < 0)
+ fatal(sys->sprint("binding ether0: %r"));
+
+ fsready := 0;
+
+ fsip = ipconfig(cfd);
+
+ bootstring := getenvdefault("bootpath", "tftp");
+
+ (bootprotocol, bootserver, bootfile) = parsebootstring(bootstring);
+
+ if (bootprotocol == nil)
+ fatal(bootstring + ": unrecognised syntax");
+
+ # Run dhcp if necessary
+ if (bootprotocol == "tftp" && (bootserver == nil || bootfile == nil))
+ dhcp();
+
+ # determine server
+ if (bootprotocol == "net" && bootserver == nil)
+ bootserver = fsip;
+
+ if (bootserver == nil)
+ fatal("couldn't determine boot server");
+
+ if (bootfile == nil)
+ fatal("couldn't determine boot file");
+
+ if (bootprotocol == nil)
+ fatal("couldn't determine boot protocol");
+
+ sys->print("loading %s!%s!%s\n", bootprotocol, bootserver, bootfile);
+
+ if (bootprotocol == "net") {
+ sys->print("Attempting remote mount\n");
+ if (netfs(bootserver) == 0)
+ sys->print("Remote mount successful\n");
+ else
+ fatal(sys->sprint("Remote mount failed: %r"));
+ fd := sys->open("/n/remote" + bootfile, Sys->OREAD);
+ if (fd == nil)
+ fatal(sys->sprint("%s:/n/remote%s: %r", bootserver, bootfile));
+ if (sys->stream(fd, kexecfd, 4096) < 0)
+ fatal(sys->sprint("copying %s: %r", bootfile));
+ }
+ else if (bootprotocol == "tftp") {
+ tftp := load Tftp Tftp->PATH;
+ if (tftp == nil)
+ fatal("can't load tftp module");
+ tftp->init(1);
+ errstr := tftp->receive(bootserver, bootfile, kexecfd);
+ if (errstr != nil)
+ fatal("tftp: " + errstr);
+ }
+ else
+ fatal("protocol " + bootprotocol + " not supported");
+ sys->print("Launching new kernel\n");
+ kexecfd = nil;
+}
+
+parsebootstring(s: string): (string, string, string)
+{
+ proto, server, file: string;
+ (n, l) := sys->tokenize(s, "!");
+ if (n > 3)
+ return (nil, nil, nil);
+ proto = hd l;
+ l = tl l;
+ if (l != nil) {
+ server = hd l;
+ l = tl l;
+ }
+ if (l != nil)
+ file = hd l;
+ case proto {
+ "tftp" =>
+ ;
+ "net" =>
+ # can't have a default file, so n must be 3
+ if (n != 3)
+ return (nil, nil, nil);
+ * =>
+ return (nil, nil, nil);
+ }
+ return (proto, server, file);
+}
+
+dobind(f, t: string, flags: int): int
+{
+ if(sys->bind(f, t, flags) < 0) {
+ err(sys->sprint("can't bind %s on %s: %r", f, t));
+ return 0;
+ }
+ return 1;
+}
+
+err(s: string)
+{
+ sys->fprint(sys->fildes(2), "bootinit: %s\n", s);
+}
+
+hang()
+{
+ <-(chan of int);
+}
+
+fatal(s: string)
+{
+ err(s);
+ hang();
+}
+
+envlist: list of string;
+
+getenv(name: string): string
+{
+ if (envlist == nil) {
+ fd := sys->open("/dev/sysenv", Sys->OREAD);
+ if (fd != nil) {
+ ntok: int;
+ buf := array[1024] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr > 0)
+ (ntok, envlist) = sys->tokenize(string buf, "\n");
+ }
+ }
+ ls := envlist;
+ while(ls != nil) {
+ (ntok2, ls2) := sys->tokenize(hd ls, "=");
+ if(hd ls2 == name)
+ return hd tl ls2;
+ ls = tl ls;
+ }
+ return nil;
+}
+
+getenvdefault(name: string, default: string): string
+{
+ rv := getenv(name);
+ if (rv == nil)
+ return default;
+ return rv;
+}
+
+ipconfig(cfd: ref sys->FD): string
+{
+ ip = getenv("wireip");
+ if (ip == nil)
+ ip = getenv("ip");
+ mask = getenv("ipmask");
+ fsip = getenv("fsip");
+ if (ip != nil && mask != nil) {
+ sys->print("ip %s %s\n", ip, mask);
+ sys->fprint(cfd, "add %s %s", ip, mask);
+ gwip := getenv("gwip");
+ if (gwip != nil) {
+ sys->print("gwip %s\n", gwip);
+ rfd := sys->open("/net/iproute", Sys->ORDWR);
+ if (rfd == nil || sys->fprint(rfd, "add 0.0.0.0 0.0.0.0 %s", gwip) < 0)
+ err(sys->sprint("failed to add default route: %r"));
+ }
+ }
+ if (ip == nil || mask == nil)
+ return bootp(cfd);
+ return fsip;
+}
+
+bootpdone: int;
+
+bootp(cfd: ref sys->FD): string
+{
+ if (bootpdone == 1)
+ return fsip;
+
+ bootpdone = 1;
+
+ sys->print("bootp ...");
+
+ if (sys->fprint(cfd, "bootp") < 0) {
+ sys->print("init: bootp: %r");
+ return nil;
+ }
+
+ fd := sys->open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ err(sys->sprint("open /net/bootp: %r"));
+ return nil;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := sys->read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ err(sys->sprint("read /net/bootp: %r"));
+ return nil;
+ }
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ name := hd ls;
+ ls = tl ls;
+ if (ls == nil)
+ break;
+ value := hd ls;
+ ls = tl ls;
+ if (name == "fsip")
+ fsip = value;
+ else if (name == "ipaddr")
+ ip = value;
+ else if (name == "ipmask")
+ mask = value;
+ }
+ return fsip;
+}
+
+netfs(server: string): int
+{
+ auth = load Auth Auth->PATH;
+ if (auth != nil)
+ auth->init();
+
+ kr = load Keyring Keyring->PATH;
+ sys->print("dial...");
+ (ok, c) := sys->dial("tcp!" + server + "!6666", nil);
+ if(ok < 0)
+ return -1;
+
+ if(kr != nil && auth != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount ...");
+
+ c.cfd = nil;
+ n := sys->mount(c.dfd, nil, "/n/remote", sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ return -1;
+}
+
+#
+#
+# DHCP
+#
+#
+
+Dhcp: adt {
+ op: int;
+ htype: int;
+ hops: int;
+ xid: int;
+ secs: int;
+ flags: int;
+ ciaddr: int;
+ yiaddr: int;
+ siaddr: int;
+ giaddr: int;
+ chaddr: array of byte;
+ sname: string;
+ file: string;
+};
+
+nboputl(buf: array of byte, val: int)
+{
+ buf[0] = byte (val >> 24);
+ buf[1] = byte (val >> 16);
+ buf[2] = byte (val >> 8);
+ buf[3] = byte val;
+}
+
+nboputs(buf: array of byte, val: int)
+{
+ buf[0] = byte (val >> 8);
+ buf[1] = byte val;
+}
+
+nbogets(buf: array of byte): int
+{
+ return (int buf[0] << 8) | int buf[1];
+}
+
+nbogetl(buf: array of byte): int
+{
+ return (int buf[0] << 24) | (int buf[1] << 16) | (int buf[2] << 8) | int buf[3];
+}
+
+stringget(buf: array of byte): string
+{
+ for (x := 0; x < len buf; x++)
+ if (buf[x] == byte 0)
+ break;
+ if (x == 0)
+ return nil;
+ return string buf[0 : x];
+}
+
+memcmp(b1: array of byte, b2: array of byte): int
+{
+ l := len b1;
+ if (l < len b2)
+ return int -b2[l];
+ if (l > len b2)
+ return int b1[l];
+ for (i := 0; i < l; i++) {
+ d := int b1[i] - int b2[i];
+ if (d != 0)
+ return d;
+ }
+ return 0;
+}
+
+memncpy(out: array of byte, in: array of byte)
+{
+ if (in == nil)
+ return;
+ l := len in;
+ if (l > len out)
+ l = len out;
+ out[0 :] = in[0 : l];
+}
+
+memset(out: array of byte, val: byte)
+{
+ for (l := 0; l < len out; l++)
+ out[l] = val;
+}
+
+dhcpsend(dfd: ref Sys->FD, dhcp: ref Dhcp)
+{
+ buf := array[576] of byte;
+ buf[0] = byte dhcp.op;
+ buf[1] = byte dhcp.htype;
+ buf[2] = byte len dhcp.chaddr;
+ buf[3] = byte dhcp.hops;
+ nboputl(buf[4 : 8], dhcp.xid);
+ nboputs(buf[8 : 10], dhcp.secs);
+ nboputs(buf[10 : 12], dhcp.flags);
+ nboputl(buf[12 : 16], dhcp.ciaddr);
+ nboputl(buf[16 : 20], dhcp.yiaddr);
+ nboputl(buf[20 : 24], dhcp.siaddr);
+ nboputl(buf[24 : 28], dhcp.giaddr);
+ memset(buf[28 :], byte 0);
+ memncpy(buf[28 : 44], dhcp.chaddr);
+ memncpy(buf[44 : 108], array of byte dhcp.sname);
+ memncpy(buf[108 : 236], array of byte dhcp.file);
+ sys->write(dfd, buf, len buf);
+}
+
+kill(pid: int)
+{
+ fd := sys->open("#p/" + string pid + "/ctl", sys->OWRITE);
+ if (fd == nil)
+ return;
+
+ msg := array of byte "kill";
+ sys->write(fd, msg, len msg);
+}
+
+ipfmt(ipaddr: int): string
+{
+ return sys->sprint("%ud.%ud.%ud.%ud",
+ (ipaddr >> 24) & 16rff,
+ (ipaddr >> 16) & 16rff,
+ (ipaddr >> 8) & 16rff,
+ ipaddr & 16rff);
+}
+
+dumpdhcp(dhcp: ref Dhcp)
+{
+ sys->print("op %d htype %d hops %d xid %ud\n", dhcp.op, dhcp.htype, dhcp.hops, dhcp.xid);
+ sys->print("secs %d flags 0x%.4ux\n", dhcp.secs, dhcp.flags);
+ sys->print("ciaddr %s\n", ipfmt(dhcp.ciaddr));
+ sys->print("yiaddr %s\n", ipfmt(dhcp.yiaddr));
+ sys->print("siaddr %s\n", ipfmt(dhcp.siaddr));
+ sys->print("giaddr %s\n", ipfmt(dhcp.giaddr));
+ sys->print("chaddr ");
+ for (x := 0; x < len dhcp.chaddr; x++)
+ sys->print("%.2ux", int dhcp.chaddr[x]);
+ sys->print("\n");
+ if (dhcp.sname != nil)
+ sys->print("sname %s\n", dhcp.sname);
+ if (dhcp.file != nil)
+ sys->print("file %s\n", dhcp.file);
+}
+
+dhcplisten(pidc: chan of int, fd: ref Sys->FD, dc: chan of ref Dhcp)
+{
+ pid := sys->pctl(0, nil);
+ pidc <-= pid;
+ buf := array [576] of byte;
+ while (1) {
+ n := sys->read(fd, buf, len buf);
+ dhcp := ref Dhcp;
+ dhcp.op = int buf[0];
+ dhcp.htype = int buf[1];
+ hlen := int buf[2];
+ dhcp.hops = int buf[3];
+ dhcp.xid = nbogetl(buf[4 : 8]);
+ dhcp.secs = nbogets(buf[8 : 10]);
+ dhcp.flags = nbogets(buf[10 : 12]);
+ dhcp.ciaddr = nbogetl(buf[12 : 16]);
+ dhcp.yiaddr = nbogetl(buf[16 : 20]);
+ dhcp.siaddr = nbogetl(buf[20 : 24]);
+ dhcp.giaddr = nbogetl(buf[24: 28]);
+ dhcp.chaddr = buf[28 : 28 + hlen];
+ dhcp.sname = stringget(buf[44 : 108]);
+ dhcp.file = stringget(buf[108 : 236]);
+ dc <-= dhcp;
+ }
+}
+
+timeoutproc(pid: chan of int, howlong: int, c: chan of string)
+{
+ pid <-= sys->pctl(0, nil);
+
+ sys->sleep(howlong);
+
+ # send timeout
+ c <-= "timed out";
+}
+
+tpid := -1;
+tc: chan of string;
+
+timeoutcancel()
+{
+ if (tpid >= 0) {
+ kill(tpid);
+ tpid = -1;
+ }
+}
+
+timeoutstart(howlong: int): (chan of string)
+{
+ timeoutcancel();
+ pidc := chan of int;
+ tc = chan of string;
+ spawn timeoutproc(pidc, howlong, tc);
+ tpid = <- pidc;
+ return tc;
+}
+
+atohn(b: byte): int
+{
+ if (b >= byte '0' && b <= byte '9')
+ return int (b - byte '0');
+ if (b >= byte 'A' && b <= byte 'F')
+ return int b - 'A' + 10;
+ if (b >= byte 'a' && b <= byte 'f')
+ return int b - 'a' + 10;
+ return -1;
+}
+
+atohb(buf: array of byte): int
+{
+ tn := atohn(buf[0]);
+ bn := atohn(buf[1]);
+ if (tn < 0 || bn < 0)
+ return -1;
+ return tn * 16 + bn;
+}
+
+gethaddr(dhcp: ref Dhcp): int
+{
+ fd := sys->open("#l/ether0/addr", Sys->OREAD);
+ if (fd == nil)
+ return 0;
+ buf := array [100] of byte;
+ n := sys->read(fd, buf, len buf);
+ if (n < 0)
+ return 0;
+ dhcp.htype = 1;
+ hlen := n / 2;
+ dhcp.chaddr = array [hlen] of byte;
+ for (i := 0; i < hlen; i++)
+ dhcp.chaddr[i] = byte atohb(buf[i * 2 : i * 2 + 2]);
+ return 1;
+}
+
+parsedq(dq: string): (int, int)
+{
+ (c, l) := sys->tokenize(dq, ".");
+ if (c != 4)
+ return (0, 0);
+ a := hd l;
+ l = tl l;
+ b := hd l;
+ l = tl l;
+ d := hd l;
+ l = tl l;
+ addr := (int a << 24) | (int b << 16) | (int d << 8) | int hd l;
+ return (1, addr);
+}
+
+dhcp()
+{
+ ok: int;
+ conn: Sys->Connection;
+ rdhcp: ref Dhcp;
+
+ if (random == nil)
+ random = load Random Random->PATH;
+
+ (ok, conn) = sys->dial("udp!255.255.255.255!67", "68");
+ if (!ok)
+ fatal(sys->sprint("failed to dial udp broadcast: %r"));
+
+ pidc := chan of int;
+ dc := chan of ref Dhcp;
+ spawn dhcplisten(pidc, conn.dfd, dc);
+ dhcppid := <- pidc;
+ dhcp := ref Dhcp;
+ dhcp.op = 1;
+ dhcp.htype = 1;
+ gethaddr(dhcp);
+ dhcp.hops = 0;
+ dhcp.xid = random->randomint(Random->NotQuiteRandom);
+ dhcp.secs = 0;
+ dhcp.flags = 0;
+ (ok, dhcp.ciaddr) = parsedq(ip);
+ dhcp.yiaddr = 0;
+ dhcp.siaddr = 0;
+ dhcp.giaddr = 0;
+ if (bootfile != "bootp")
+ dhcp.file = bootfile;
+ else
+ dhcp.file = nil;
+ ok = 0;
+ for (count := 0; !ok && count < 5; count++) {
+ mtc := timeoutstart(3000);
+ dhcpsend(conn.dfd, dhcp);
+ timedout := 0;
+ do {
+ alt {
+ <- mtc =>
+ timedout = 1;
+ rdhcp = <- dc =>
+ if (debug)
+ dumpdhcp(rdhcp);
+ if (rdhcp.ciaddr != dhcp.ciaddr || rdhcp.xid != dhcp.xid
+ || memcmp(rdhcp.chaddr, dhcp.chaddr) != 0) {
+ break;
+ }
+ if (rdhcp.file != nil) {
+ ok = 1;
+ timeoutcancel();
+ }
+ }
+ } while (!timedout && !ok);
+ dhcp.xid++;
+ }
+ if (ok) {
+ if (bootfile == nil)
+ bootfile = rdhcp.file;
+ if (bootserver == nil)
+ bootserver = ipfmt(rdhcp.siaddr);
+ }
+ else
+ err("bootp timed out");
+ kill(dhcppid);
+}
diff --git a/os/init/cerf405.b b/os/init/cerf405.b
new file mode 100644
index 00000000..b02dd5a2
--- /dev/null
+++ b/os/init/cerf405.b
@@ -0,0 +1,598 @@
+#
+# Intrinsyc Cerf cube 405EP, also Manga switch
+#
+# this encrusted version will be simplified shortly
+#
+
+implement Init;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+
+include "dhcp.m";
+ dhcpclient: Dhcpclient;
+ Bootconf: import dhcpclient;
+
+include "sh.m";
+
+Init: module
+{
+ init: fn();
+};
+
+Bootpreadlen: con 128;
+Microsec: con 1000000;
+Notime: con big 800000000 * big Microsec; # fairly arbitrary time in 1995 to check validity
+
+# conventional Inferno NAND flash partitions
+nandparts := array[] of {
+ # bootstrap from 0 to 0x210000
+ "add boot 0 0x210000",
+ "add fs 0x210000 end"
+};
+
+userdefault := array[] of {
+ "inferno inferno",
+ "sys sys"
+};
+
+ethername := "/net/ether0";
+
+#
+# initialise flash translation
+# mount flash file system
+# add devices
+# start a shell or window manager
+#
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+
+ sys->bind("/", "/", Sys->MREPL);
+ if(sys->bind("/boot", "/", Sys->MAFTER) < 0)
+ sys->print("can't bind /boot after /: %r\n");
+ sys->bind("/boot/nvfs", "/nvfs", Sys->MREPL);
+
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ localok := 0;
+ if(lfs() >= 0){
+ # let's just take a closer look
+ sys->bind("/n/local/nvfs", "/nvfs", Sys->MBEFORE|Sys->MCREATE);
+ (rc, nil) := sys->stat("/n/local/dis/sh.dis");
+ if(rc >= 0)
+ localok = 1;
+ else
+ err("local file system unusable");
+ }
+
+ netok := sys->bind("#l", "/net", Sys->MREPL) >= 0;
+ if(!netok){
+ netok = sys->bind("#l1", "/net", Sys->MREPL) >= 0;
+ if(netok)
+ ethername = "/net/ether1";
+ }
+ if(netok)
+ configether();
+
+ dobind("#I", "/net", sys->MAFTER); # IP
+ dobind("#p", "/prog", sys->MREPL); # prog
+ sys->bind("#d", "/fd", Sys->MREPL);
+ dobind("#c", "/dev", sys->MREPL); # console
+ dobind("#t", "/dev", sys->MAFTER); # serial line
+ drawok := sys->bind("#i", "/dev", sys->MAFTER) >= 0; # draw
+ sys->bind("#m", "/dev", sys->MAFTER); # pointer
+ sys->bind("#e", "/env", sys->MREPL|sys->MCREATE); # environment
+ sys->bind("#A", "/dev", Sys->MAFTER); # optional audio
+ sys->bind("#ʟ", "/dev", Sys->MAFTER); # logfs
+
+ timefile: string;
+ rootsource: string;
+ cfd := sys->open("/dev/consctl", Sys->OWRITE);
+ if(cfd != nil)
+ sys->fprint(cfd, "rawon");
+ for(;;){
+ (rootsource, timefile) = askrootsource(localok, netok);
+ if(rootsource == nil)
+ break; # internal
+ (rc, nil) := sys->stat(rootsource+"/dis/sh.dis");
+ if(rc < 0)
+ err("%s has no shell");
+ else if(sys->bind(rootsource, "/", Sys->MAFTER) < 0)
+ sys->print("can't bind %s on /: %r\n", rootsource);
+ else{
+ sys->bind("/n/local", rootsource+"/n/local", Sys->MREPL|Sys->MCREATE);
+ sys->unmount("#//./boot", "/");
+ sys->bind(rootsource+"/dis", "/dis", Sys->MBEFORE|Sys->MCREATE);
+ break;
+ }
+ }
+ cfd = nil;
+
+ setsysname("cerf"); # set system name
+
+ rtc := big rf("#r/rtc", "0") * big Microsec;
+ now := big 0;
+ if(timefile != nil){ # synchronise with remote time if it's valid
+ now = big rf(timefile, "0");
+ if(now < Notime && rootsource != nil)
+ now = big filetime(rootsource) * big Microsec; # try the time of the root directory
+ if(now >= Notime){
+ setclock("#r/rtc", now/big Microsec);
+ rtc = now;
+ }
+ }
+ if(now < Notime)
+ now = rtc;
+ setclock("/dev/time", now);
+
+ sys->chdir("/");
+ if(netok){
+ start("ndb/dns", nil);
+ start("ndb/cs", nil);
+ }
+ startup := "/nvfs/startup";
+ if(sys->open(startup, Sys->OREAD) != nil){
+ shell := load Command Sh->PATH;
+ if(shell != nil){
+ sys->print("Running %s\n", startup);
+ shell->init(nil, "sh" :: startup :: nil);
+ }
+ }
+ user := rdenv("user", "inferno");
+ (ok, nil) := sys->stat("/dis/wm/wm.dis");
+ if(drawok && ok >= 0)
+ (ok, nil) = sys->stat("/dis/wm/logon.dis");
+ if(drawok && ok >= 0 && userok(user)){
+ wm := load Command "/dis/wm/wm.dis";
+ if(wm != nil){
+ fd := sys->open("/nvfs/user", Sys->OWRITE);
+ if(fd != nil){
+ sys->fprint(fd, "%s", user);
+ fd = nil;
+ }
+ spawn wm->init(nil, list of {"wm/wm", "wm/logon", "-l", "-u", user});
+ exit;
+ }
+ sys->print("init: can't load wm/logon: %r");
+ }
+ sh := load Command Sh->PATH;
+ if(sh == nil){
+ err(sys->sprint("can't load %s: %r", Sh->PATH));
+ hang();
+ }
+ spawn sh->init(nil, "sh" :: nil);
+}
+
+start(cmd: string, args: list of string)
+{
+ disfile := cmd;
+ if(disfile[0] != '/')
+ disfile = "/dis/"+disfile+".dis";
+ (ok, nil) := sys->stat(disfile);
+ if(ok >= 0){
+ dis := load Command disfile;
+ if(dis == nil)
+ sys->print("init: can't load %s: %r\n", disfile);
+ else
+ spawn dis->init(nil, cmd :: args);
+ }
+}
+
+dobind(f, t: string, flags: int)
+{
+ if(sys->bind(f, t, flags) < 0)
+ err(sys->sprint("can't bind %s on %s: %r", f, t));
+}
+
+#
+# Set system name from nvram if possible
+#
+setsysname(def: string)
+{
+ v := array of byte def;
+ fd := sys->open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ fd = sys->open("/env/sysname", sys->OREAD);
+ if(fd != nil){
+ buf := array[Sys->NAMEMAX] of byte;
+ nr := sys->read(fd, buf, len buf);
+ while(nr > 0 && buf[nr-1] == byte '\n')
+ nr--;
+ if(nr > 0)
+ v = buf[0:nr];
+ }
+ fd = sys->open("/dev/sysname", sys->OWRITE);
+ if(fd != nil)
+ sys->write(fd, v, len v);
+}
+
+filetime(name: string): int
+{
+ (ok, dir) := sys->stat(name);
+ if(ok < 0)
+ return 0;
+ return dir.atime;
+}
+
+setclock(timefile: string, now: big)
+{
+ fd := sys->open(timefile, sys->OWRITE);
+ if(fd == nil)
+ sys->print("init: can't open %s: %r\n", timefile);
+ else if(sys->fprint(fd, "%bud", now) < 0)
+ sys->print("init: can't write to %s: %r\n", timefile);
+}
+
+err(s: string)
+{
+ sys->fprint(sys->fildes(2), "init: %s\n", s);
+}
+
+hang()
+{
+ <-chan of int;
+}
+
+tried := 0;
+
+askrootsource(localok: int, netok: int): (string, string)
+{
+ stdin := sys->fildes(0);
+ sources := "kernel" :: nil;
+ if(netok)
+ sources = "remote" :: sources;
+ if(localok){
+ sources = "local" :: sources;
+ if(netok)
+ sources = "local+remote" :: sources;
+ }
+ for(;;){
+ s := "";
+ if(tried == 0 && (s = rdenv("rootsource", nil)) != nil){
+ tried = 1;
+ sys->print("rootsource: root from %s\n", s);
+ } else {
+ sys->print("root from (");
+ cm := "";
+ for(l := sources; l != nil; l = tl l){
+ sys->print("%s%s", cm, hd l);
+ cm = ",";
+ }
+ sys->print(")[%s] ", hd sources);
+
+ s = getline(stdin, hd sources); # default
+ }
+ (nil, choice) := sys->tokenize(s, "\t ");
+ if(choice == nil)
+ choice = sources;
+ opt := hd choice;
+ case opt {
+ * =>
+ sys->print("\ninvalid boot option: '%s'\n", opt);
+ "kernel" =>
+ return (nil, nil);
+ "local" =>
+ return ("/n/local", nil);
+ "local+remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/local", nil);
+ "remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/remote", "/n/remote/dev/time");
+ }
+ }
+}
+
+getline(fd: ref Sys->FD, default: string): string
+{
+ result := "";
+ buf := array[10] of byte;
+ i := 0;
+ for(;;){
+ n := sys->read(fd, buf[i:], len buf - i);
+ if(n < 1)
+ break;
+ i += n;
+ while(i >0 && (nutf := sys->utfbytes(buf, i)) > 0){
+ s := string buf[0:nutf];
+ for(j := 0; j < len s; j++)
+ case s[j] {
+ '\b' =>
+ if(result != nil)
+ result = result[0:len result-1];
+ 'u'&16r1F =>
+ sys->print("^U\n");
+ result = "";
+ '\r' =>
+ ;
+ * =>
+ sys->print("%c", s[j]);
+ if(s[j] == '\n' || s[j] >= 16r80){
+ if(s[j] != '\n')
+ result[len result] = s[j];
+ if(result == nil)
+ return default;
+ return result;
+ }
+ result[len result] = s[j];
+ }
+ buf[0:] = buf[nutf:i];
+ i -= nutf;
+ }
+ }
+ return default;
+}
+
+#
+# serve local file system using logfs
+#
+lfs(): int
+{
+ if(!flashpart("#F1/flash1/flashctl", nandparts))
+ return -1;
+ if(!logfsinit("#F1/flash1/fs"))
+ return -1;
+ mfd := sys->open("/dev/logfsmain", Sys->ORDWR);
+ if(mfd == nil){
+ sys->print("can't open /dev/logfsmain: %r\n");
+ return -1;
+ }
+ if(sys->mount(mfd, nil, "/n/local", Sys->MREPL|Sys->MCREATE, nil) < 0){
+ sys->print("can't mount /dev/logfsmain on /n/local: %r\n");
+ return -1;
+ }
+ return 0;
+}
+
+#
+# partition flash
+#
+flashdone := 0;
+
+flashpart(ctl: string, parts: array of string): int
+{
+ if(flashdone)
+ return 1;
+ cfd := sys->open(ctl, Sys->ORDWR);
+ if(cfd == nil){
+ sys->print("can't open %s: %r\n", ctl);
+ return 0;
+ }
+ for(i := 0; i < len parts; i++)
+ if(sys->fprint(cfd, "%s", parts[i]) < 0){
+ sys->print("can't %q to %s: %r\n", parts[i], ctl);
+ return 0;
+ }
+ flashdone = 1;
+ return 1;
+}
+
+#
+# set up logfs
+#
+logfsdone := 0;
+
+logfsinit(flashmem: string): int
+{
+ if(logfsdone)
+ return 1;
+ fd := sys->open("/dev/logfsctl", Sys->OWRITE);
+ if(fd == nil){
+ if(sys->bind("#ʟ", "/dev", Sys->MBEFORE) < 0)
+ return -1;
+ fd = sys->open("/dev/logfsctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("can't open /dev/logfsctl: %r\n");
+ return -1;
+ }
+ }
+ sys->print("Set logfs main on %s...\n", flashmem);
+ if(!ctlw(fd, "logfs", "fsys main config "+flashmem))
+ return -1;
+ if(!ctlw(fd, "logfs", "fsys main"))
+ return -1;
+ cm := rf("#e/logfsformat", nil);
+ if(cm == "yes"){
+ if(!ctlw(fd, "logfs", "format 0"))
+ return -1;
+ }
+ cf := rf("#e/logfsopen", nil);
+ if(cf == nil)
+ cf = "open";
+ if(!ctlw(fd, "logfs", cf))
+ return -1;
+ for(i := 0; i < len userdefault; i++)
+ ctlw(fd, "logfs", "uname "+userdefault[i]);
+ logfsdone = 1;
+ return 1;
+}
+
+ctlw(fd: ref Sys->FD, w: string, cmd: string): int
+{
+ if(sys->fprint(fd, "%s", cmd) < 0){
+ sys->print("%s ctl %q: %r\n", w, cmd);
+ return 0;
+ }
+ return 1;
+}
+
+configether()
+{
+ if(ethername == nil)
+ return;
+ fd := sys->open("/nvfs/etherparams", Sys->OREAD);
+ if(fd == nil)
+ return;
+ ctl := sys->open(ethername+"/clone", Sys->OWRITE);
+ if(ctl == nil){
+ sys->print("init: can't open %s/clone: %r\n", ethername);
+ return;
+ }
+ b := array[1024] of byte;
+ n := sys->read(fd, b, len b);
+ if(n <= 0)
+ return;
+ for(i := 0; i < n;){
+ for(e := i; e < n && b[e] != byte '\n'; e++)
+ ;
+ s := string b[i:e];
+ if(sys->fprint(ctl, "%s", s) < 0)
+ sys->print("init: ctl write to %s/clone: %s: %r\n", ethername, s);
+ i = e+1;
+ }
+}
+
+donebind := 0;
+server: string;
+
+#
+# set up network mount
+#
+netfs(mountpt: string): int
+{
+ fd: ref Sys->FD;
+ if(!donebind){
+ fd = sys->open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil){
+ sys->print("init: open /net/ipifc/clone: %r\n");
+ return -1;
+ }
+ if(sys->fprint(fd, "bind ether %s", ethername) < 0){
+ sys->print("could not bind %s interface: %r\n", ethername);
+ return -1;
+ }
+ donebind = 1;
+ }else{
+ fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n");
+ return -1;
+ }
+ }
+ server = rdenv("fsip", nil);
+ if((ip := rdenv("ip", nil)) != nil){
+ sys->print("**using %s\n", ip);
+ sys->fprint(fd, "bind ether /net/ether0");
+ s := rdenv("ipmask", nil);
+ if(s == nil)
+ s = rdenv("netmask", nil); # alternative name used by some bootstraps
+ sys->fprint(fd, "add %s %s", ip, s);
+ gate := rdenv("ipgw", nil);
+ if(gate == nil)
+ gate = rdenv("gateway", nil);
+ if(gate != nil){
+ rfd := sys->open("/net/iproute", Sys->OWRITE);
+ if(rfd != nil){
+ sys->fprint(rfd, "add 0 0 %s", gate);
+ sys->print("set gateway %s\n", gate);
+ }
+ }
+ }else if(server == nil){
+ sys->print("dhcp...");
+ dhcpclient = load Dhcpclient Dhcpclient->PATH;
+ if(dhcpclient == nil){
+ sys->print("can't load dhcpclient: %r\n");
+ return -1;
+ }
+ dhcpclient->init();
+ (cfg, nil, e) := dhcpclient->dhcp("/net", fd, "/net/ether0/addr", nil, nil);
+ if(e != nil){
+ sys->print("dhcp: %s\n", e);
+ return -1;
+ }
+ if(server == nil)
+ server = cfg.getip(Dhcpclient->OP9fs);
+ dhcpclient = nil;
+ }
+ if(server == nil || server == "0.0.0.0"){
+ sys->print("no file server address\n");
+ return -1;
+ }
+ sys->print("fs=%s\n", server);
+
+ net := "tcp"; # how to specify il?
+ svcname := net + "!" + server + "!6666";
+
+ sys->print("dial %s...", svcname);
+
+ (ok, c) := sys->dial(svcname, nil);
+ if(ok < 0){
+ sys->print("can't dial %s: %r\n", svcname);
+ return -1;
+ }
+
+ sys->print("\nConnected ...\n");
+ if(kr != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `none'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount %s...", mountpt);
+
+ c.cfd = nil;
+ n := sys->mount(c.dfd, nil, mountpt, Sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ if(n < 0)
+ sys->print("%r");
+ return -1;
+}
+
+username(def: string): string
+{
+ return rdenv("user", def);
+}
+
+userok(user: string): int
+{
+ (ok, d) := sys->stat("/usr/"+user);
+ return ok >= 0 && (d.mode & Sys->DMDIR) != 0;
+}
+
+rdenv(name: string, def: string): string
+{
+ s := rf("#e/"+name, nil);
+ if(s != nil)
+ return s;
+ return rf("/nvfs/"+name, def);
+}
+
+rf(file: string, default: string): string
+{
+ fd := sys->open(file, Sys->OREAD);
+ if(fd != nil){
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr > 0){
+ s := string buf[0:nr];
+ while(s != nil && ((c := s[len s-1]) == '\n' || c == '\r'))
+ s = s[0: len s-1];
+ if(s != nil)
+ return s;
+ }
+ }
+ return default;
+}
diff --git a/os/init/cerfinit.b b/os/init/cerfinit.b
new file mode 100644
index 00000000..96d2b784
--- /dev/null
+++ b/os/init/cerfinit.b
@@ -0,0 +1,612 @@
+#
+# Intrinsyc Cerf cube
+#
+
+implement Init;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+
+include "sh.m";
+
+Init: module
+{
+ init: fn();
+};
+
+Bootpreadlen: con 128;
+
+# standard flash partitions
+
+flashparts := array[] of {
+ # bootstrap at 0x0 to 0x20000
+ "add script 0x20000 0x40000",
+ "add kernel 0x100000 0x200000",
+ "add fs 0x200000 end",
+};
+
+ethername := "ether0";
+
+#
+# initialise flash translation
+# mount flash file system
+# add devices
+# start a shell or window manager
+#
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->bind("/", "/", Sys->MREPL);
+
+ localok := 0;
+ if(lfs() >= 0){
+ # let's just take a closer look
+ sys->bind("/n/local/nvfs", "/nvfs", Sys->MREPL|Sys->MCREATE);
+ (rc, nil) := sys->stat("/n/local/dis/sh.dis");
+ if(rc >= 0)
+ localok = 1;
+ else
+ err("local file system unusable");
+ }
+ netok := sys->bind("#l", "/net", Sys->MREPL) >= 0;
+ if(!netok){
+ netok = sys->bind("#l1", "/net", Sys->MREPL) >= 0;
+ if(netok)
+ ethername = "ether1";
+ }
+ if(netok)
+ configether();
+ dobind("#I", "/net", sys->MAFTER); # IP
+ dobind("#p", "/prog", sys->MREPL); # prog
+ sys->bind("#d", "/fd", Sys->MREPL);
+ dobind("#c", "/dev", sys->MREPL); # console
+ dobind("#t", "/dev", sys->MAFTER); # serial line
+ drawok := sys->bind("#i", "/dev", sys->MAFTER) >= 0; # draw
+ sys->bind("#m", "/dev", sys->MAFTER); # pointer
+ sys->bind("#e", "/env", sys->MREPL|sys->MCREATE); # environment
+ sys->bind("#A", "/dev", Sys->MAFTER); # optional audio
+ timefile: string;
+ rootsource: string;
+ scale := 1;
+ cfd := sys->open("/dev/consctl", Sys->OWRITE);
+ if(cfd != nil)
+ sys->fprint(cfd, "rawon");
+ for(;;){
+ (rootsource, timefile, scale) = askrootsource(localok, netok);
+ if(rootsource == nil)
+ break; # internal
+ (rc, nil) := sys->stat(rootsource+"/dis/sh.dis");
+ if(rc < 0)
+ err("%s has no shell");
+ else if(sys->bind(rootsource, "/", Sys->MAFTER) < 0)
+ sys->print("can't bind %s on /: %r\n", rootsource);
+ else{
+ sys->bind(rootsource+"/dis", "/dis", Sys->MBEFORE|Sys->MCREATE);
+ break;
+ }
+ }
+ cfd = nil;
+
+ setsysname("cerf"); # set system name
+
+ now := getclock(timefile, rootsource);
+ if(scale == 1)
+ now *= big 1000000;
+ setclock("/dev/time", now);
+ if(timefile != "#r/rtc")
+ setclock("#r/rtc", now/big 1000000);
+
+ sys->chdir("/");
+ if(netok){
+ start("ndb/dns", nil);
+ start("ndb/cs", nil);
+ }
+ startup := "/nvfs/startup";
+ if(sys->open(startup, Sys->OREAD) != nil){
+ shell := load Command Sh->PATH;
+ if(shell != nil){
+ sys->print("Running %s\n", startup);
+ shell->init(nil, "sh" :: startup :: nil);
+ }
+ }
+ user := username("inferno");
+ (ok, nil) := sys->stat("/dis/wm/wm.dis");
+ if(drawok && ok >= 0)
+ (ok, nil) = sys->stat("/dis/wm/logon.dis");
+ if(drawok && ok >= 0 && userok(user)){
+ wm := load Command "/dis/wm/wm.dis";
+ if(wm != nil){
+ fd := sys->open("/nvfs/user", Sys->OWRITE);
+ if(fd != nil){
+ sys->fprint(fd, "%s", user);
+ fd = nil;
+ }
+ spawn wm->init(nil, list of {"wm/wm", "wm/logon", "-l", "-u", user});
+ exit;
+ }
+ sys->print("init: can't load wm/logon: %r");
+ }
+ sh := load Command Sh->PATH;
+ if(sh == nil){
+ err(sys->sprint("can't load %s: %r", Sh->PATH));
+ hang();
+ }
+ spawn sh->init(nil, "sh" :: nil);
+}
+
+start(cmd: string, args: list of string)
+{
+ disfile := cmd;
+ if(disfile[0] != '/')
+ disfile = "/dis/"+disfile+".dis";
+ (ok, nil) := sys->stat(disfile);
+ if(ok >= 0){
+ dis := load Command disfile;
+ if(dis == nil)
+ sys->print("init: can't load %s: %r\n", disfile);
+ else
+ spawn dis->init(nil, cmd :: args);
+ }
+}
+
+dobind(f, t: string, flags: int)
+{
+ if(sys->bind(f, t, flags) < 0)
+ err(sys->sprint("can't bind %s on %s: %r", f, t));
+}
+
+#
+# Set system name from nvram if possible
+#
+setsysname(def: string)
+{
+ v := array of byte def;
+ fd := sys->open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ fd = sys->open("/env/sysname", sys->OREAD);
+ if(fd != nil){
+ buf := array[Sys->NAMEMAX] of byte;
+ nr := sys->read(fd, buf, len buf);
+ while(nr > 0 && buf[nr-1] == byte '\n')
+ nr--;
+ if(nr > 0)
+ v = buf[0:nr];
+ }
+ fd = sys->open("/dev/sysname", sys->OWRITE);
+ if(fd != nil)
+ sys->write(fd, v, len v);
+}
+
+getclock(timefile: string, timedir: string): big
+{
+ now := big 0;
+ if(timefile != nil){
+ fd := sys->open(timefile, Sys->OREAD);
+ if(fd != nil){
+ b := array[64] of byte;
+ n := sys->read(fd, b, len b-1);
+ if(n > 0){
+ now = big string b[0:n];
+ if(now <= big 16r20000000)
+ now = big 0; # remote itself is not initialised
+ }
+ }
+ }
+ if(now == big 0){
+ if(timedir != nil){
+ (ok, dir) := sys->stat(timedir);
+ if(ok < 0) {
+ sys->print("init: stat %s: %r", timedir);
+ return big 0;
+ }
+ now = big dir.atime;
+ }else{
+ now = big 993826747000000;
+ sys->print("time warped\n");
+ }
+ }
+ return now;
+}
+
+setclock(timefile: string, now: big)
+{
+ fd := sys->open(timefile, sys->OWRITE);
+ if (fd == nil) {
+ sys->print("init: can't open %s: %r", timefile);
+ return;
+ }
+
+ b := sys->aprint("%ubd", now);
+ if (sys->write(fd, b, len b) != len b)
+ sys->print("init: can't write to %s: %r", timefile);
+}
+
+srv()
+{
+ sys->print("remote debug srv...");
+ fd := sys->open("/dev/eia0ctl", Sys->OWRITE);
+ if(fd != nil)
+ sys->fprint(fd, "b115200");
+
+ fd = sys->open("/dev/eia0", Sys->ORDWR);
+ if (fd == nil){
+ err(sys->sprint("can't open /dev/eia0: %r"));
+ return;
+ }
+ if (sys->export(fd, "/", Sys->EXPASYNC) < 0){
+ err(sys->sprint("can't export on serial port: %r"));
+ return;
+ }
+}
+
+err(s: string)
+{
+ sys->fprint(sys->fildes(2), "init: %s\n", s);
+}
+
+hang()
+{
+ <-chan of int;
+}
+
+tried := 0;
+
+askrootsource(localok: int, netok: int): (string, string, int)
+{
+ stdin := sys->fildes(0);
+ sources := "kernel" :: nil;
+ if(netok)
+ sources = "remote" :: sources;
+ if(localok){
+ sources = "local" :: sources;
+ if(netok)
+ sources = "local+remote" :: sources;
+ }
+ for(;;) {
+ s := "";
+ if (tried == 0 && (s = rf("/nvfs/rootsource", nil)) != nil) {
+ tried = 1;
+ if (s[len s - 1] == '\n')
+ s = s[:len s - 1];
+ sys->print("/nvfs/rootsource: root from %s\n", s);
+ } else {
+ sys->print("root from (");
+ cm := "";
+ for(l := sources; l != nil; l = tl l){
+ sys->print("%s%s", cm, hd l);
+ cm = ",";
+ }
+ sys->print(")[%s] ", hd sources);
+
+ s = getline(stdin, hd sources); # default
+ }
+ (nil, choice) := sys->tokenize(s, "\t ");
+ if(choice == nil)
+ choice = sources;
+ opt := hd choice;
+ case opt {
+ * =>
+ sys->print("\ninvalid boot option: '%s'\n", opt);
+ "kernel" =>
+ return (nil, "#r/rtc", 1);
+ "local" =>
+ return ("/n/local", "#r/rtc", 1);
+ "local+remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/local", "/n/remote/dev/time", 1000000);
+ "remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/remote", "/n/remote/dev/time", 1000000);
+ }
+ }
+}
+
+getline(fd: ref Sys->FD, default: string): string
+{
+ result := "";
+ buf := array[10] of byte;
+ i := 0;
+ for(;;) {
+ n := sys->read(fd, buf[i:], len buf - i);
+ if(n < 1)
+ break;
+ i += n;
+ while(i >0 && (nutf := sys->utfbytes(buf, i)) > 0){
+ s := string buf[0:nutf];
+ for (j := 0; j < len s; j++)
+ case s[j] {
+ '\b' =>
+ if(result != nil)
+ result = result[0:len result-1];
+ 'u'&16r1F =>
+ sys->print("^U\n");
+ result = "";
+ '\r' =>
+ ;
+ * =>
+ sys->print("%c", s[j]);
+ if(s[j] == '\n' || s[j] >= 16r80){
+ if(s[j] != '\n')
+ result[len result] = s[j];
+ if(result == nil)
+ return default;
+ return result;
+ }
+ result[len result] = s[j];
+ }
+ buf[0:] = buf[nutf:i];
+ i -= nutf;
+ }
+ }
+ return default;
+}
+
+#
+# serve local DOS file system using flash translation layer
+#
+lfs(): int
+{
+ if(!flashpart("#F/flash/flashctl", flashparts))
+ return -1;
+ if(!ftlinit("#F/flash/fs"))
+ return -1;
+ c := chan of string;
+ spawn startfs(c, "/dis/dossrv.dis", "dossrv" :: "-f" :: "#X/ftldata" :: "-m" :: "/n/local" :: nil);
+ if(<-c != nil)
+ return -1;
+ return 0;
+}
+
+startfs(c: chan of string, file: string, args: list of string)
+{
+ fs := load Command file;
+ if(fs == nil){
+ sys->print("can't load %s: %r\n", file);
+ c <-= "load failed";
+ }
+ {
+ fs->init(nil, args);
+ }exception e {
+ "*" =>
+ c <-= "failed";
+ exit;
+ * =>
+ c <-= "unknown exception";
+ exit;
+ }
+ c <-= nil;
+}
+
+#
+# partition flash
+#
+flashdone := 0;
+
+flashpart(ctl: string, parts: array of string): int
+{
+ if(flashdone)
+ return 1;
+ cfd := sys->open(ctl, Sys->ORDWR);
+ if(cfd == nil){
+ sys->print("can't open %s: %r\n", ctl);
+ return 0;
+ }
+ for(i := 0; i < len parts; i++)
+ if(sys->fprint(cfd, "%s", parts[i]) < 0){
+ sys->print("can't %q to %s: %r\n", parts[i], ctl);
+ return 0;
+ }
+ flashdone = 1;
+ return 1;
+}
+
+#
+# set up flash translation layer
+#
+ftldone := 0;
+
+ftlinit(flashmem: string): int
+{
+ if(ftldone)
+ return 1;
+ sys->print("Set flash translation of %s...\n", flashmem);
+ fd := sys->open("#X/ftlctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("can't open #X/ftlctl: %r\n");
+ return 0;
+ }
+ if(sys->fprint(fd, "init %s", flashmem) <= 0){
+ sys->print("can't init flash translation: %r\n");
+ return 0;
+ }
+ ftldone = 1;
+ return 1;
+}
+
+configether()
+{
+ if(ethername == nil)
+ return;
+ fd := sys->open("/nvfs/etherparams", Sys->OREAD);
+ if(fd == nil)
+ return;
+ ctl := sys->open("/net/"+ethername+"/clone", Sys->OWRITE);
+ if(ctl == nil){
+ sys->print("init: can't open %s's clone: %r\n", ethername);
+ return;
+ }
+ b := array[1024] of byte;
+ n := sys->read(fd, b, len b);
+ if(n <= 0)
+ return;
+ for(i := 0; i < n;){
+ for(e := i; e < n && b[e] != byte '\n'; e++)
+ ;
+ s := string b[i:e];
+ if(sys->fprint(ctl, "%s", s) < 0)
+ sys->print("init: ctl write to %s: %s: %r\n", ethername, s);
+ i = e+1;
+ }
+}
+
+donebind := 0;
+
+#
+# set up network mount
+#
+netfs(mountpt: string): int
+{
+ sys->print("bootp ...");
+
+ fd: ref Sys->FD;
+ if(!donebind){
+ fd = sys->open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil) {
+ sys->print("init: open /net/ipifc/clone: %r\n");
+ return -1;
+ }
+ if(sys->fprint(fd, "bind ether %s", ethername) < 0) {
+ sys->print("could not bind %s interface: %r\n", ethername);
+ return -1;
+ }
+ donebind = 1;
+ }else{
+ fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n");
+ return -1;
+ }
+ }
+ if ((ip := rf("/nvfs/ip", nil)) != nil) {
+ sys->print("**using %s\n", ip);
+ sys->fprint(fd, "bind ether /net/ether0");
+ sys->fprint(fd, "add %s ", ip);
+ } else {
+ {
+ if(sys->fprint(fd, "bootp") < 0)
+ sys->print("could not bootp: %r\n");
+ } exception e {
+ "*" =>
+ sys->print("could not bootp: %s\n", e);
+ }
+ }
+ server := rf("/nvfs/fsip", nil);
+ if (server != nil) {
+ if (server[len server - 1] == '\n')
+ server = server[:len server - 1];
+ sys->print("/nvfs/fsip: server=%s\n", server);
+ } else
+ server = bootp();
+ if(server == nil || server == "0.0.0.0")
+ return -1;
+
+ net := "tcp"; # how to specify il?
+ svcname := net + "!" + server + "!6666";
+
+ sys->print("dial %s...", svcname);
+
+ (ok, c) := sys->dial(svcname, nil);
+ if(ok < 0){
+ sys->print("can't dial %s: %r\n", svcname);
+ return -1;
+ }
+
+ sys->print("\nConnected ...\n");
+ if(kr != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount %s...", mountpt);
+
+ c.cfd = nil;
+ n := sys->mount(c.dfd, nil, mountpt, sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ if(n < 0)
+ sys->print("%r");
+ return -1;
+}
+
+bootp(): string
+{
+ fd := sys->open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ sys->print("init: can't open /net/bootp: %r");
+ return nil;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := sys->read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ sys->print("init: read /net/bootp: %r");
+ return nil;
+ }
+
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ sys->print("init: server address not in bootp read");
+ return nil;
+ }
+
+ srv := hd ls;
+
+ sys->print("%s\n", srv);
+
+ return srv;
+}
+
+username(def: string): string
+{
+ return rf("/nvfs/user", def);
+}
+
+userok(user: string): int
+{
+ (ok, d) := sys->stat("/usr/"+user);
+ return ok >= 0 && (d.mode & Sys->DMDIR) != 0;
+}
+
+rf(file: string, default: string): string
+{
+ fd := sys->open(file, Sys->OREAD);
+ if(fd != nil){
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr > 0)
+ return string buf[0:nr];
+ }
+ return default;
+}
diff --git a/os/init/evalinit.b b/os/init/evalinit.b
new file mode 100644
index 00000000..1e33c6f9
--- /dev/null
+++ b/os/init/evalinit.b
@@ -0,0 +1,119 @@
+implement Init;
+
+#
+# ARM evaluator 7t
+#
+
+include "sys.m";
+sys: Sys;
+FD, Connection, sprint, Dir: import sys;
+print, fprint, open, bind, mount, dial, sleep, read: import sys;
+
+include "draw.m";
+include "sh.m";
+draw: Draw;
+Context: import draw;
+
+Init: module
+{
+ init: fn();
+};
+
+Logon: module
+{
+ init: fn(ctxt: ref Context, argv: list of string);
+};
+
+Bootpreadlen: con 128;
+
+init()
+{
+ sys = load Sys Sys->PATH;
+# kr = load Keyring Keyring->PATH;
+# auth = load Auth Auth->PATH;
+# if(auth != nil)
+# auth->init();
+
+ sys->print("**\n** Inferno\n** Vita Nuova\n**\n");
+
+# sys->print("Setup boot net services ...\n");
+
+ #
+ # Setup what we need to call a server and
+ # Authenticate
+ #
+# bind("#l", "/net", sys->MREPL);
+# bind("#I", "/net", sys->MAFTER);
+ bind("#c", "/dev", sys->MAFTER);
+ bind("#r", "/dev", sys->MAFTER);
+# nvramfd := sys->open("#r/nvram", sys->ORDWR);
+# if(nvramfd != nil){
+# spec = "#Fnvram";
+# if(bind(spec, "/nvfs", sys->MAFTER) < 0)
+# print("init: bind %s: %r\n", spec);
+# }
+
+# setsysname();
+
+ #
+ # default namespace
+ #
+ bind("#c", "/dev", sys->MREPL); # console
+ bind("#t", "/dev", sys->MAFTER); # serial port
+ bind("#r", "/dev", sys->MAFTER); # RTC
+# if(spec != nil)
+# bind(spec, "/nvfs", sys->MBEFORE|sys->MCREATE); # our keys
+# bind("#l", "/net", sys->MBEFORE); # ethernet
+# bind("#I", "/net", sys->MBEFORE); # TCP/IP
+ bind("#p", "/prog", sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+
+ sys->print("clock...\n");
+ setclock();
+
+ sys->print("logon...\n");
+
+# sys->chdir("/usr/inferno");
+# logon := load Logon "/dis/sh.dis";
+# spawn logon->init(dc, nil);
+ ts := load Sh "/dis/sh.dis";
+ ts->init(nil, nil);
+}
+
+setclock()
+{
+ (ok, dir) := sys->stat("/");
+ if (ok < 0) {
+ print("init: stat /: %r");
+ return;
+ }
+
+ fd := sys->open("/dev/time", sys->OWRITE);
+ if (fd == nil) {
+ print("init: open /dev/time: %r");
+ return;
+ }
+
+ # Time is kept as microsecs, atime is in secs
+ b := array of byte sprint("%d000000", dir.atime);
+ if (sys->write(fd, b, len b) != len b)
+ print("init: write /dev/time: %r");
+}
+
+#
+# Set system name from nvram
+#
+setsysname()
+{
+ fd := open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ return;
+ fds := open("/dev/sysname", sys->OWRITE);
+ if(fds == nil)
+ return;
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr <= 0)
+ return;
+ sys->write(fds, buf, nr);
+}
diff --git a/os/init/geninit.b b/os/init/geninit.b
new file mode 100644
index 00000000..7e63d24f
--- /dev/null
+++ b/os/init/geninit.b
@@ -0,0 +1,93 @@
+implement Init;
+#
+# init program for native inferno, generic pc version
+#
+include "sys.m";
+sys: Sys;
+FD, Connection, sprint, Dir: import sys;
+print, fprint, open, bind, mount, dial, sleep, read, chdir: import sys;
+
+include "draw.m";
+draw: Draw;
+Context: import draw;
+
+include "keyring.m";
+kr: Keyring;
+
+Init: module
+{
+ init: fn();
+};
+
+Shell: module
+{
+ init: fn(ctxt: ref Context, argv: list of string);
+};
+
+init()
+{
+
+ sys = load Sys Sys->PATH;
+ stdin := sys->fildes(0);
+ kr = load Keyring Keyring->PATH;
+
+ sys->print("**\n** Inferno\n** Vita Nuova\n**\n");
+
+ sys->print("Setup boot net services ...\n");
+
+ #
+ # Setup what we need to call a server and
+ # Authenticate
+ #
+ sys->print("Bind console ...\n");
+ bind("#c", "/dev", sys->MAFTER);
+
+ setsysname();
+ print("Standalone mode\n");
+ #
+ # default namespace
+ #
+ sys->unmount(nil, "/dev");
+ bind("#p", "/prog", sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+ bind("#c", "/dev", sys->MBEFORE); # console
+ bind("#m", "/dev", sys->MAFTER); # mouse setup device
+ bind("#t", "/dev", sys->MAFTER); # serial device
+
+ mouse := load Shell "/dis/mouse.dis";
+ if (mouse != nil) {
+ print("Setting up mouse\n");
+ mouse->init(nil, "/dis/mouse.dis" :: nil);
+ mouse = nil;
+ }
+
+ # create fake nameserver db that can be written to later
+ ramfile := load Shell "/dis/ramfile.dis";
+ if (ramfile != nil) {
+ ramfile->init(nil, "/dis/ramfile.dis" :: "/services/dns/db" :: "" :: nil);
+ ramfile = nil;
+ }
+
+ print("Console...\n");
+ shell := load Shell "/dis/sh.dis";
+ if(shell == nil) {
+ print("init: load /dis/sh.dis: %r\n");
+ exit;
+ }
+ print("starting shell\n");
+ shell->init(nil, "/dis/sh.dis" :: nil);
+ print("shell exited, bye bye\n");
+}
+
+
+#
+# Set system name from nvram
+#
+setsysname()
+{
+ fds := open("/dev/sysname", sys->OWRITE);
+ if(fds == nil)
+ return;
+ buf := array of byte "genericpc";
+ sys->write(fds, buf, len buf);
+}
diff --git a/os/init/i4e.b b/os/init/i4e.b
new file mode 100644
index 00000000..f670e8d5
--- /dev/null
+++ b/os/init/i4e.b
@@ -0,0 +1,210 @@
+implement Init;
+
+#
+# init program for Inferno 4thEd demo box
+#
+
+include "sys.m";
+ sys: Sys;
+ FD, Connection, Dir: import sys;
+
+include "draw.m";
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+
+include "dhcp.m";
+ dhcpclient: Dhcpclient;
+ Bootconf: import dhcpclient;
+
+I4EBOOT: con "/lib/boot.sh";
+
+Init: module
+{
+ init: fn();
+};
+
+Command: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+Bootpreadlen: con 128;
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->print("**\n** Inferno\n** Vita Nuova\n**\n");
+
+ sys->print("Setup boot net services ...\n");
+
+ #
+ # Setup what we need to call a server and
+ # Authenticate
+ #
+ dobind("#l", "/net", Sys->MREPL);
+ dobind("#I", "/net", Sys->MAFTER);
+ dobind("#c", "/dev", Sys->MAFTER);
+
+
+ fd := sys->open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil)
+ fail(sys->sprint("iopen /net/ipifc/clone: %r"));
+
+ if(sys->fprint(fd, "bind ether /net/ether0") < 0)
+ fail(sys->sprint("could not bind interface: %r"));
+
+ fsip: string;
+
+ dhcpclient = load Dhcpclient Dhcpclient->PATH;
+ if(dhcpclient == nil)
+ fail(sys->sprint("can't load dhcpclient: %r"));
+
+ sys->print("dhcp...");
+ dhcpclient->init();
+ (cfg, nil, e) := dhcpclient->dhcp("/net", fd, "/net/ether0/addr", nil, nil);
+ if(e != nil)
+ fail(sys->sprint("dhcp: %s", e));
+ fsip = cfg.getip(Dhcpclient->OP9fs);
+ if(fsip == nil)
+ fail("server address not in bootp/dhcp reply");
+ dhcpclient = nil;
+
+ infd := sys->open("/dev/cons", Sys->OREAD);
+ if(infd == nil)
+ sys->print("warning: no kbd\n");
+
+ err := rootfs(fsip);
+ if(err != nil)
+ fail(err);
+
+ #
+ # default namespace
+ #
+ dobind("#c", "/dev", Sys->MREPL); # console
+ dobind("#p", "/prog", Sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+ sys->pctl(Sys->NEWENV, nil);
+ dobind("#e", "/env", Sys->MREPL|Sys->MCREATE); # env device
+
+ sys->print("clock...\n");
+ setclock();
+
+ sys->print("boot...\n");
+ sys->pctl(Sys->NEWFD, 0::1::2::nil);
+ done := chan of string;
+ spawn boot(done);
+ err = <- done;
+ if(err != nil)
+ fail("boot script failed: "+err);
+ fail("boot script exit");
+}
+
+rootfs(server: string): string
+{
+ ok: int;
+ c: Connection;
+
+ sys->print("readauthinfo...\n");
+ ai := kr->readauthinfo("/keydb/mutual");
+ if(ai == nil)
+ return sys->sprint("readauthinfo /keydb/mutual failed: %r");
+
+ addr := "tcp!" + server + "!9999";
+ for(gap := 3;; gap *= 2){
+ sys->print("Connect (%s)...", addr);
+ (ok, c) = sys->dial(addr, nil);
+ if(ok != -1)
+ break;
+ sys->print("failed: %r\n");
+ if(gap > 60)
+ gap = 60;
+ sys->sleep(gap*1000);
+ }
+
+ sys->print("\nConnected ...");
+ if(kr != nil && auth != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil)
+ return sys->sprint("authentication failed: %s", err);
+ }
+ sys->print("mount ...");
+
+ c.cfd = nil;
+ sys->pctl(Sys->NEWNS, nil);
+ if(sys->mount(c.dfd, nil, "/", sys->MREPL, "") < 0) # TO DO: would be better to mount behind
+ return sys->sprint("mount failed: %r");
+ sys->chdir("/");
+ return nil;
+}
+
+boot(done: chan of string)
+{
+ {
+ shell := load Command "/dis/sh.dis";
+ if(shell == nil){
+ done <-= sys->sprint("load /dis/sh.dis: %r");
+ exit;
+ }
+ shell->init(nil, "/dis/sh.dis"::I4EBOOT::nil);
+ } exception e {
+ "*" =>
+ done <-= e;
+ exit;
+ }
+ done <-= nil;
+}
+
+setclock()
+{
+ (ok, dir) := sys->stat("/");
+ if(ok < 0){
+ sys->print("stat /: %r");
+ return;
+ }
+
+ fd := sys->open("/dev/time", sys->OWRITE);
+ if(fd == nil){
+ sys->print("open /dev/time: %r");
+ return;
+ }
+
+ # Time is kept as microsecs, atime is in secs
+ b := array of byte sys->sprint("%d000000", dir.atime);
+ if(sys->write(fd, b, len b) != len b)
+ sys->print("write /dev/time: %r");
+}
+
+#
+# Bind wrapper which reports errors
+#
+
+dobind(f, t: string, flags: int)
+{
+ if(sys->bind(f, t, flags) < 0)
+ sys->print("bind(%s, %s, %d) failed: %r\n", f, t, flags);
+}
+
+fail(msg: string)
+{
+ sys->print("%s\n", msg);
+ sys->bind("/", "#//n/remote", Sys->MREPL);
+ sys->bind("#//", "/", Sys->MREPL);
+ shell := load Command "#//dis/sh.dis";
+ if(shell == nil){
+ sys->print("cannot load shell: %r\n");
+ exit;
+ }
+ shell->init(nil, "/dis/sh.dis"::"-i"::nil);
+ exit;
+}
diff --git a/os/init/init.b b/os/init/init.b
new file mode 100644
index 00000000..655b0cf3
--- /dev/null
+++ b/os/init/init.b
@@ -0,0 +1,613 @@
+implement Init;
+
+include "sys.m";
+sys: Sys;
+FD, Connection, sprint, Dir: import sys;
+print, fprint, open, bind, mount, dial, sleep, read: import sys;
+
+include "draw.m";
+draw: Draw;
+Context, Display, Font, Rect, Point, Image, Screen: import draw;
+
+include "prefab.m";
+prefab: Prefab;
+Environ, Element, Compound, Style: import prefab;
+
+include "mpeg.m";
+
+include "ir.m";
+tirc: chan of int; # translated remote input (from irslave)
+irstopc: chan of int; # channel to irslave
+
+include "keyring.m";
+kr: Keyring;
+IPint: import kr;
+
+Init: module
+{
+ init: fn();
+};
+
+Shell: module
+{
+ init: fn(ctxt: ref Context, argv: list of string);
+};
+
+Signon: con "Dialing Local Service Provider\nWait a moment ...";
+Login: con "Connected to Service Provider";
+Intro: con "/mpeg/youwill2";
+Garden: con "The Garden of Delights\nHieronymus Bosch";
+
+rootfs(server: string): int
+{
+ ok, n: int;
+ c: Connection;
+ err: string;
+
+ (ok, c) = dial("tcp!" + server + "!6666", nil);
+ if(ok < 0)
+ return -1;
+
+ if(kr != nil){
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ (ai, err) = register(server);
+ if(err != nil){
+ status("registration failed: "+err+"\nPress a key on your remote\ncontrol to continue.");
+ # register() may have failed before Ir loaded.
+ if(tirc!=nil){
+ <-tirc;
+ irstopc <-= 1;
+ }
+ }
+ statusbox = nil;
+ }
+ (id_or_err, secret) := kr->auth(c.dfd, ai, 0);
+ if(secret == nil){
+ status("authentication failed: "+err);
+ sys->sleep(2000);
+ statusbox = nil;
+ (ai, err) = register(server);
+ if(err != nil){
+ status("registration failed: "+err+"\nPress a key on your remote\ncontrol to continue.");
+ # register() may have failed before Ir loaded.
+ if(tirc!=nil){
+ <-tirc;
+ irstopc <-= 1;
+ }
+ }
+ statusbox = nil;
+ } else {
+ # no line encryption
+ algbuf := array of byte "none";
+ kr->sendmsg(c.dfd, algbuf, len algbuf);
+ }
+ }
+
+ c.cfd = nil;
+ n = mount(c.dfd, nil, "/", sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ return -1;
+}
+
+ones: ref Image;
+screen: ref Screen;
+menuenv, tvenv: ref Environ;
+Bootpreadlen: con 128;
+textfont: ref Font;
+disp: ref Display;
+env: ref Environ;
+statusbox: ref Compound;
+
+init()
+{
+ shell: Shell;
+ nr, ntok: int;
+ c: ref Compound;
+ ls: list of string;
+ le, te, xe: ref Element;
+ spec: string;
+
+ sys = load Sys Sys->PATH;
+ draw = load Draw Draw->PATH;
+ prefab = load Prefab Prefab->PATH;
+ kr = load Keyring Keyring->PATH;
+
+ disp = Display.allocate(nil);
+ ones = disp.ones;
+
+ textfont = Font.open(disp, "*default*");
+ screencolor := disp.rgb(161, 195, 209);
+
+ menustyle := ref Style(
+ textfont, # titlefont
+ textfont, # textfont
+ disp.color(16r55), # elemcolor
+ disp.color(draw->Black), # edgecolor
+ disp.color(draw->Yellow), # titlecolor
+ disp.color(draw->Black), # textcolor
+ disp.color(draw->White)); # highlightcolor
+
+ screen = Screen.allocate(disp.image, screencolor, 0);
+ screen.image.draw(screen.image.r, screencolor, ones, (0, 0));
+ menuenv = ref Environ(screen, menustyle);
+
+ logo := disp.open("/lucent");
+ phone := disp.open("/phone");
+ if(phone == nil || logo == nil) {
+ print("open: /phone or /lucent: %r\n");
+ exit;
+ }
+
+ #
+ # Setup what we need to call a server and
+ # Authenticate
+ #
+ bind("#l", "/net", sys->MREPL);
+ bind("#I", "/net", sys->MAFTER);
+ bind("#c", "/dev", sys->MAFTER);
+ bind("#H", "/dev", sys->MAFTER);
+ nvramfd := sys->open("#H/hd0nvram", sys->ORDWR);
+ if(nvramfd != nil){
+ spec = sys->sprint("#Fhd0nvram", nvramfd.fd);
+ if(bind(spec, "/nvfs", sys->MAFTER|sys->MCREATE) < 0)
+ print("init: bind %s: %r\n", spec);
+ }
+
+ setsysname(); # set up system name
+
+ fd := open("/net/ipifc", sys->OWRITE);
+ if(fd == nil) {
+ print("init: open /net/ipifc: %r");
+ exit;
+ }
+ fprint(fd, "bootp /net/ether0");
+
+ fd = open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ print("init: open /net/bootp: %r");
+ exit;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr = read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ print("init: read /net/bootp: %r");
+ exit;
+ }
+
+ (ntok, ls) = sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ print("init: server address not in bootp read");
+ exit;
+ }
+
+ zr := Rect((0,0), (0,0));
+
+ le = Element.icon(menuenv, logo.r, logo, ones);
+ le = Element.elist(menuenv, le, Prefab->EVertical);
+ xe = Element.icon(menuenv, phone.r, phone, ones);
+ xe = Element.elist(menuenv, xe, Prefab->EHorizontal);
+ te = Element.text(menuenv, Signon, zr, Prefab->EText);
+ xe.append(te);
+ xe.adjust(Prefab->Adjpack, Prefab->Adjleft);
+ le.append(xe);
+ le.adjust(Prefab->Adjpack, Prefab->Adjup);
+ c = Compound.box(menuenv, (150, 100),
+ Element.text(menuenv, "Inferno", zr, Prefab->ETitle), le);
+ c.draw();
+
+ while(rootfs(hd ls) < 0)
+ sleep(1000);
+
+ #
+ # default namespace
+ #
+ bind("#c", "/dev", sys->MBEFORE); # console
+ bind("#H", "/dev", sys->MAFTER);
+ if(spec != nil)
+ bind(spec, "/nvfs", sys->MBEFORE|sys->MCREATE); # our keys
+ bind("#E", "/dev", sys->MBEFORE); # mpeg
+ bind("#l", "/net", sys->MBEFORE); # ethernet
+ bind("#I", "/net", sys->MBEFORE); # TCP/IP
+ bind("#V", "/dev", sys->MAFTER); # hauppauge TV
+ bind("#p", "/prog", sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+
+ setclock();
+
+ le = Element.icon(menuenv, logo.r, logo, ones);
+ le = Element.elist(menuenv, le, Prefab->EVertical);
+ xe = Element.text(menuenv, Login, zr, Prefab->EText);
+ le.append(xe);
+
+ i := disp.newimage(Rect((0, 0), (320, 240)), 3, 0, 0);
+ i.draw(i.r, menustyle.elemcolor, ones, i.r.min);
+ xe = Element.icon(menuenv, i.r, i, ones);
+ le.append(xe);
+
+ le.adjust(Prefab->Adjpack, Prefab->Adjup);
+ c = Compound.box(menuenv, (160, 50),
+ Element.text(menuenv, "Inferno", zr, Prefab->ETitle), le);
+ c.draw();
+
+ xc: chan of string;
+ mpeg := load Mpeg Mpeg->PATH;
+ if(mpeg != nil) {
+ xc = chan of string;
+ r := (hd tl tl c.contents.kids).r;
+ s := mpeg->play(disp, c.image, 1, r, Intro, xc);
+ if(s != "") {
+ print("mpeg: %s\n", s);
+ xc = nil;
+ }
+ }
+
+ i2 := disp.open("/icons/delight.bit");
+ i.draw(i.r, i2, ones, i2.r.min);
+ i2 = nil;
+ if(xc != nil)
+ <-xc;
+
+ le.append(Element.text(menuenv, Garden, le.r, Prefab->EText));
+ le.adjust(Prefab->Adjpack, Prefab->Adjup);
+ c = Compound.box(menuenv, (160, 50),
+ Element.text(menuenv, "Inferno", zr, Prefab->ETitle), le);
+ c.draw();
+
+ sleep(5000);
+
+ # Do a bind to force applications to use IR module built
+ # into the kernel.
+ if(bind("#/./ir", Ir->PATH, sys->MREPL) < 0)
+ print("init: bind ir: %r\n");
+ # Uncomment the next line to load sh.dis.
+# shell = load Shell "/dis/sh.dis";
+ dc : ref Context;
+ # Comment the next 2 lines to load sh.dis.
+ shell = load Shell "/dis/mux/mux.dis";
+ dc = ref Context(screen, disp, nil, nil, nil, nil, nil);
+ if(shell == nil) {
+ print("init: load /dis/sh.dis: %r");
+ exit;
+ }
+ shell->init(dc, nil);
+}
+
+setclock()
+{
+ (ok, dir) := sys->stat("/");
+ if (ok < 0) {
+ print("init: stat /: %r");
+ return;
+ }
+
+ fd := sys->open("/dev/time", sys->OWRITE);
+ if (fd == nil) {
+ print("init: open /dev/time: %r");
+ return;
+ }
+
+ # Time is kept as microsecs, atime is in secs
+ b := array of byte sprint("%d000000", dir.atime);
+ if (sys->write(fd, b, len b) != len b)
+ print("init: write /dev/time: %r");
+}
+
+register(signer: string): (ref Keyring->Authinfo, string)
+{
+
+ # get box id
+ fd := sys->open("/nvfs/ID", sys->OREAD);
+ if(fd == nil){
+ fd = sys->create("/nvfs/ID", sys->OWRITE, 8r664);
+ if(fd == nil)
+ return (nil, "can't create /nvfs/ID");
+ if(sys->fprint(fd, "LT%d", randomint()) < 0)
+ return (nil, "can't write /nvfs/ID");
+ fd = sys->open("/nvfs/ID", sys->OREAD);
+ }
+ if(fd == nil)
+ return (nil, "can't open /nvfs/ID");
+
+ buf := array[64] of byte;
+ n := sys->read(fd, buf, (len buf) - 1);
+ if(n <= 0)
+ return (nil, "can't read /nvfs/ID");
+
+ boxid := string buf[0:n];
+ fd = nil;
+ buf = nil;
+
+ # Set-up for user input via remote control.
+ tirc = chan of int;
+ irstopc = chan of int;
+ spawn irslave(tirc, irstopc);
+ case dialogue("Register with your service provider?", "yes\nno") {
+ 0 =>
+ ;
+ * =>
+ return (nil, "registration not desired");
+ }
+
+ # a holder
+ info := ref Keyring->Authinfo;
+
+ # contact signer
+# status("looking for signer");
+# signer := virgil->virgil("$SIGNER");
+# if(signer == nil)
+# return (nil, "can't find signer");
+ status("dialing tcp!"+signer+"!6671");
+ (ok, c) := sys->dial("tcp!"+signer+"!6671", nil);
+ if(!ok)
+ return (nil, "can't contact signer");
+
+ # get signer's public key and diffie helman parameters
+ status("getting signer's key");
+ spkbuf := kr->getmsg(c.dfd);
+ if(spkbuf == nil)
+ return (nil, "can't read signer's key");
+ info.spk = kr->strtopk(string spkbuf);
+ if(info.spk == nil)
+ return (nil, "bad key from signer");
+ alphabuf := kr->getmsg(c.dfd);
+ if(alphabuf == nil)
+ return (nil, "can't read dh alpha");
+ info.alpha = IPint.b64toip(string alphabuf);
+ pbuf := kr->getmsg(c.dfd);
+ if(pbuf == nil)
+ return (nil, "can't read dh mod");
+ info.p = IPint.b64toip(string pbuf);
+
+ # generate our key from system parameters
+ status("generating our key");
+ info.mysk = kr->genSKfromPK(info.spk, boxid);
+ if(info.mysk == nil)
+ return (nil, "can't generate our own key");
+ info.mypk = kr->sktopk(info.mysk);
+
+ # send signer our public key
+ mypkbuf := array of byte kr->pktostr(info.mypk);
+ kr->sendmsg(c.dfd, mypkbuf, len mypkbuf);
+
+ # get blind certificate
+ status("getting blinded certificate");
+ certbuf := kr->getmsg(c.dfd);
+ if(certbuf == nil)
+ return (nil, "can't read signed key");
+
+ # verify we've got the right stuff
+ if(!verify(boxid, spkbuf, mypkbuf, certbuf))
+ return (nil, "verification failed, try again");
+
+ # contact counter signer
+ status("dialing tcp!"+signer+"!6672");
+ (ok, c) = sys->dial("tcp!"+signer+"!6672", nil);
+ if(!ok)
+ return (nil, "can't contact countersigner");
+
+ # send boxid
+ buf = array of byte boxid;
+ kr->sendmsg(c.dfd, buf, len buf);
+
+ # get blinding mask
+ status("unblinding certificate");
+ mask := kr->getmsg(c.dfd);
+ if(len mask != len certbuf)
+ return (nil, "bad mask length");
+ for(i := 0; i < len mask; i++)
+ certbuf[i] = certbuf[i] ^ mask[i];
+ info.cert = kr->strtocert(string certbuf);
+
+ status("verifying certificate");
+ state := kr->sha(mypkbuf, len mypkbuf, nil, nil);
+ if(kr->verify(info.spk, info.cert, state) == 0)
+ return (nil, "bad certificate");
+
+ status("storing keys");
+ kr->writeauthinfo("/nvfs/default", info);
+
+ status("Congratulations, you are registered.\nPress a key to continue.");
+ <-tirc;
+ irstopc <-= 1;
+
+ return (info, nil);
+}
+
+dialogue(expl: string, selection: string): int
+{
+ c := Compound.textbox(menuenv, ((100, 100), (100, 100)), expl, selection);
+ c.draw();
+ for(;;){
+ (key, index, nil) := c.select(c.contents, 0, tirc);
+ case key {
+ Ir->Select =>
+ return index;
+ Ir->Enter =>
+ return -1;
+ }
+ }
+}
+
+status(expl: string)
+{
+# title := Element.text(menuenv, "registration\nstatus", ((0,0),(0,0)), Prefab->ETitle);
+# msg := Element.text(menuenv, expl, ((0,0),(0,0)), Prefab->EText);
+# c := Compound.box(menuenv, (100, 100), title, msg);
+
+ c := Compound.textbox(menuenv, ((100, 100),(100,100)), "Registration status", expl);
+ c.draw();
+ statusbox = c;
+}
+
+pro:= array[] of {
+ "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf",
+ "hotel", "india", "juliet", "kilo", "lima", "mike", "nancy", "oscar",
+ "poppa", "quebec", "romeo", "sierra", "tango", "uniform",
+ "victor", "whiskey", "xray", "yankee", "zulu"
+};
+
+#
+# prompt for acceptance
+#
+verify(boxid: string, hispk, mypk, cert: array of byte): int
+{
+ s: string;
+
+ # hash the string
+ state := kr->md5(hispk, len hispk, nil, nil);
+ kr->md5(mypk, len mypk, nil, state);
+ digest := array[Keyring->MD5dlen] of byte;
+ kr->md5(cert, len cert, digest, state);
+
+ title := Element.elist(menuenv, nil, Prefab->EVertical);
+ subtitle := Element.text(menuenv, "Telephone your service provider\n to register. You will need\nthe following:\n", ((0,0),(0,0)), Prefab->ETitle);
+ title.append(subtitle);
+
+ line := Element.text(menuenv, "boxid is '"+boxid+"'.", ((0,0),(0,0)), Prefab->ETitle);
+ title.append(line);
+ for(i := 0; i < len digest; i++){
+ line = Element.elist(menuenv, nil, Prefab->EHorizontal);
+ s = (string (2*i)) + ": " + pro[((int digest[i])>>4)%len pro];
+ line.append(Element.text(menuenv, s, ((0,0),(0,0)), Prefab->ETitle));
+
+ s = (string (2*i+1)) + ": " + pro[(int digest[i])%len pro] + "\n";
+ line.append(Element.text(menuenv, s, ((0,0),(200,0)), Prefab->ETitle));
+
+ line.adjust(Prefab->Adjequal, Prefab->Adjleft);
+ title.append(line);
+ }
+ title.adjust(Prefab->Adjpack, Prefab->Adjleft);
+
+ le := Element.elist(menuenv, nil, Prefab->EHorizontal);
+ le.append(Element.text(menuenv, " accept ", ((0, 0), (0, 0)), Prefab->EText));
+ le.append(Element.text(menuenv, " reject ", ((0, 0), (0, 0)), Prefab->EText));
+ le.adjust(Prefab->Adjpack, Prefab->Adjleft);
+
+ c := Compound.box(menuenv, (50, 50), title, le);
+ c.draw();
+
+ for(;;){
+ (key, index, nil) := c.select(c.contents, 0, tirc);
+ case key {
+ Ir->Select =>
+ if(index == 0)
+ return 1;
+ return 0;
+ Ir->Enter =>
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+randomint(): int
+{
+ fd := sys->open("/dev/random", sys->OREAD);
+ if(fd == nil)
+ return 0;
+ buf := array[4] of byte;
+ sys->read(fd, buf, 4);
+ rand := 0;
+ for(i := 0; i < 4; i++)
+ rand = (rand<<8) | int buf[i];
+ return rand;
+}
+
+# Reads real (if possible) or simulated remote, returns Ir events on irc.
+# Must be a separate thread to be able to 1) read raw Ir input channel
+# and 2) write translated Ir input data on output channel.
+irslave(irc, stopc: chan of int)
+{
+ in, irpid: int;
+ buf: list of int;
+ outc: chan of int;
+
+ irchan := chan of int; # Untranslated Ir input channel.
+ irpidch := chan of int; # Ir reader pid channel.
+ irmod := load Ir "#/./ir"; # Module built into kernel.
+
+ if(irmod==nil){
+ print("irslave: failed to load #/./ir");
+ return;
+ }
+ if(irmod->init(irchan, irpidch)<0){
+ print("irslave: failed to initialize ir");
+ return;
+ }
+ irpid =<-irpidch;
+
+ hdbuf := 0;
+ dummy := chan of int;
+ for(;;){
+ if(buf == nil){
+ outc = dummy;
+ }else{
+ outc = irc;
+ hdbuf = hd buf;
+ }
+ alt{
+ in = <-irchan =>
+ buf = append(buf, in);
+ outc <-= irmod->translate(hdbuf) =>
+ buf = tl buf;
+ <-stopc =>{
+ killir(irpid);
+ return;
+ }
+ }
+ }
+}
+
+append(l: list of int, i: int): list of int
+{
+ if(l == nil)
+ return i :: nil;
+ return hd l :: append(tl l, i);
+}
+
+killir(irpid: int)
+{
+ pid := sys->sprint("%d", irpid);
+ fd := sys->open("#p/"+pid+"/ctl", sys->OWRITE);
+ if(fd==nil) {
+ print("init: process %s: %r\n", pid);
+ return;
+ }
+
+ msg := array of byte "kill";
+ n := sys->write(fd, msg, len msg);
+ if(n < 0) {
+ print("init: message for %s: %r\n", pid);
+ return;
+ }
+}
+
+#
+# Set system name from nvram
+#
+setsysname()
+{
+ fd := open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ return;
+ fds := open("/dev/sysname", sys->OWRITE);
+ if(fds == nil)
+ return;
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr <= 0)
+ return;
+ sys->write(fds, buf, nr);
+}
diff --git a/os/init/ipaqinit.b b/os/init/ipaqinit.b
new file mode 100644
index 00000000..40ddd529
--- /dev/null
+++ b/os/init/ipaqinit.b
@@ -0,0 +1,697 @@
+#
+# ipaq
+#
+# TO DO: read params from params flash
+#
+
+implement Init;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+
+include "dhcp.m";
+ dhcpclient: Dhcpclient;
+ Bootconf: import dhcpclient;
+
+include "keyboard.m";
+
+include "sh.m";
+
+Init: module
+{
+ init: fn();
+};
+
+Bootpreadlen: con 128;
+
+ethername := "ether0";
+
+# standard Inferno flash partitions
+
+flashparts := array[] of {
+ # bootstrap at 0x0 to 0x40000, don't touch
+ "add params 0x40000 0x80000",
+ "add kernel 0x80000 0x140000",
+ "add fs 0x140000 end",
+};
+
+#
+# initialise flash translation
+# mount flash file system
+# add devices
+# start a shell or window manager
+#
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->bind("/", "/", Sys->MREPL);
+
+ lightup();
+
+ localok := 0;
+ if(lfs() >= 0){
+ # let's just take a closer look
+ sys->bind("/n/local/nvfs", "/nvfs", Sys->MREPL|Sys->MCREATE);
+ (rc, nil) := sys->stat("/n/local/dis/sh.dis");
+ if(rc >= 0)
+ localok = 1;
+ else
+ err("local file system unusable");
+ }
+ netok := sys->bind("#l", "/net", Sys->MREPL) >= 0;
+ if(!netok){
+ netok = sys->bind("#l1", "/net", Sys->MREPL) >= 0;
+ if(netok)
+ ethername = "ether1";
+ }
+ if(netok)
+ configether();
+
+ dobind("#I", "/net", sys->MAFTER); # IP
+ dobind("#p", "/prog", sys->MREPL); # prog
+ dobind("#c", "/dev", sys->MREPL); # console
+ sys->bind("#d", "/fd", Sys->MREPL);
+ dobind("#t", "/dev", sys->MAFTER); # serial line
+ dobind("#i", "/dev", sys->MAFTER); # draw
+ dobind("#m", "/dev", Sys->MAFTER); # pointer
+ sys->bind("#e", "/env", sys->MREPL|sys->MCREATE); # environment
+ sys->bind("#A", "/dev", Sys->MAFTER); # optional audio
+ dobind("#T","/dev",sys->MAFTER); # touch screen and other ipaq devices
+
+ timefile: string;
+ rootsource: string;
+ cfd := sys->open("/dev/consctl", Sys->OWRITE);
+ if(cfd != nil)
+ sys->fprint(cfd, "rawon");
+ for(;;){
+ (rootsource, timefile) = askrootsource(localok, netok);
+ if(rootsource == nil)
+ break; # internal
+ (rc, nil) := sys->stat(rootsource+"/dis/sh.dis");
+ if(rc < 0)
+ err("%s has no shell");
+ else if(sys->bind(rootsource, "/", Sys->MAFTER) < 0)
+ sys->print("can't bind %s on /: %r\n", rootsource);
+ else{
+ sys->bind(rootsource+"/dis", "/dis", Sys->MBEFORE|Sys->MCREATE);
+ break;
+ }
+ }
+ cfd = nil;
+
+ setsysname("ipaq"); # set system name
+
+ now := getclock(timefile, rootsource);
+ setclock("/dev/time", now);
+ if(timefile != "#r/rtc")
+ setclock("#r/rtc", now/big 1000000);
+
+ sys->chdir("/");
+ if(netok){
+ start("ndb/dns", nil);
+ start("ndb/cs", nil);
+ }
+ calibrate();
+ startup := "/nvfs/startup";
+ if(sys->open(startup, Sys->OREAD) != nil){
+ shell := load Command Sh->PATH;
+ if(shell != nil){
+ sys->print("Running %s\n", startup);
+ shell->init(nil, "sh" :: startup :: nil);
+ }
+ }
+ user := rdenv("user", "inferno");
+ (ok, nil) := sys->stat("/dis/wm/wm.dis");
+ if(ok >= 0)
+ (ok, nil) = sys->stat("/dis/wm/logon.dis");
+ if(ok >= 0 && userok(user)){
+ wm := load Command "/dis/wm/wm.dis";
+ if(wm != nil){
+ fd := sys->open("/nvfs/user", Sys->OWRITE);
+ if(fd != nil){
+ sys->fprint(fd, "%s", user);
+ fd = nil;
+ }
+ spawn wm->init(nil, list of {"wm/wm", "wm/logon", "-l", "-n", "lib/ipaqns", "-u", user});
+ exit;
+ }
+ sys->print("init: can't load wm/logon: %r");
+ }
+ sh := load Command Sh->PATH;
+ if(sh == nil){
+ err(sys->sprint("can't load %s: %r", Sh->PATH));
+ hang();
+ }
+ spawn sh->init(nil, "sh" :: nil);
+}
+
+start(cmd: string, args: list of string)
+{
+ disfile := cmd;
+ if(disfile[0] != '/')
+ disfile = "/dis/"+disfile+".dis";
+ (ok, nil) := sys->stat(disfile);
+ if(ok >= 0){
+ dis := load Command disfile;
+ if(dis == nil)
+ sys->print("init: can't load %s: %r\n", disfile);
+ else
+ spawn dis->init(nil, cmd :: args);
+ }
+}
+
+dobind(f, t: string, flags: int)
+{
+ if(sys->bind(f, t, flags) < 0)
+ err(sys->sprint("can't bind %s on %s: %r", f, t));
+}
+
+lightup()
+{
+ # backlight
+ fd := sys->open("#T/ipaqctl", Sys->OWRITE);
+ if(fd != nil)
+ sys->fprint(fd, "light 1 1 0x80");
+}
+
+#
+# Set system name from nvram if possible
+#
+setsysname(def: string)
+{
+ v := array of byte def;
+ fd := sys->open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ fd = sys->open("/env/sysname", sys->OREAD);
+ if(fd != nil){
+ buf := array[Sys->NAMEMAX] of byte;
+ nr := sys->read(fd, buf, len buf);
+ while(nr > 0 && buf[nr-1] == byte '\n')
+ nr--;
+ if(nr > 0)
+ v = buf[0:nr];
+ }
+ fd = sys->open("/dev/sysname", sys->OWRITE);
+ if(fd != nil)
+ sys->write(fd, v, len v);
+}
+
+getclock(timefile: string, timedir: string): big
+{
+ now := big 0;
+ if(timefile != nil){
+ fd := sys->open(timefile, Sys->OREAD);
+ if(fd != nil){
+ b := array[64] of byte;
+ n := sys->read(fd, b, len b-1);
+ if(n > 0){
+ now = big string b[0:n];
+ if(now <= big 16r20000000)
+ now = big 0; # remote itself is not initialised
+ }
+ }
+ }
+ if(now == big 0){
+ if(timedir != nil){
+ (ok, dir) := sys->stat(timedir);
+ if(ok < 0) {
+ sys->print("init: stat %s: %r", timedir);
+ return big 0;
+ }
+ now = big dir.atime;
+ }else{
+ now = big 993826747000000;
+ sys->print("time warped\n");
+ }
+ }
+ return now;
+}
+
+setclock(timefile: string, now: big)
+{
+ fd := sys->open(timefile, sys->OWRITE);
+ if (fd == nil) {
+ sys->print("init: can't open %s: %r", timefile);
+ return;
+ }
+
+ b := sys->aprint("%ubd", now);
+ if (sys->write(fd, b, len b) != len b)
+ sys->print("init: can't write to %s: %r", timefile);
+}
+
+srv()
+{
+ sys->print("remote debug srv...");
+ fd := sys->open("/dev/eia0ctl", Sys->OWRITE);
+ if(fd != nil)
+ sys->fprint(fd, "b115200");
+
+ fd = sys->open("/dev/eia0", Sys->ORDWR);
+ if (fd == nil){
+ err(sys->sprint("can't open /dev/eia0: %r"));
+ return;
+ }
+ if (sys->export(fd, "/", Sys->EXPASYNC) < 0){
+ err(sys->sprint("can't export on serial port: %r"));
+ return;
+ }
+}
+
+err(s: string)
+{
+ sys->fprint(sys->fildes(2), "init: %s\n", s);
+}
+
+hang()
+{
+ <-(chan of int);
+}
+
+tried := 0;
+
+askrootsource(localok: int, netok: int): (string, string)
+{
+ stdin := sys->fildes(0);
+ sources := "kernel" :: nil;
+ if(netok)
+ sources = "remote" :: sources;
+ if(localok){
+ sources = "local" :: sources;
+ if(netok)
+ sources = "local+remote" :: sources;
+ }
+Query:
+ for(;;) {
+ s := "";
+ if (tried == 0 && (s = rdenv("rootsource", nil)) != nil) {
+ tried = 1;
+ if (s[len s - 1] == '\n')
+ s = s[:len s - 1];
+ sys->print("/nvfs/rootsource: root from %s\n", s);
+ } else {
+ sys->print("root from (");
+ cm := "";
+ for(l := sources; l != nil; l = tl l){
+ sys->print("%s%s", cm, hd l);
+ cm = ",";
+ }
+ sys->print(")[%s] ", hd sources);
+
+ s = getline(stdin, hd sources); # default
+ }
+ case s[0] {
+ Keyboard->Right or Keyboard->Left =>
+ sources = append(hd sources, tl sources);
+ sys->print("\n");
+ continue Query;
+ Keyboard->Down =>
+ s = hd sources;
+ sys->print(" %s\n", s);
+ }
+ (nil, choice) := sys->tokenize(s, "\t ");
+ if(choice == nil)
+ choice = sources;
+ opt := hd choice;
+ case opt {
+ * =>
+ sys->print("\ninvalid boot option: '%s'\n", opt);
+ "kernel" =>
+ return (nil, "#r/rtc");
+ "local" =>
+ return ("/n/local", "#r/rtc");
+ "local+remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/local", "/n/remote/dev/time");
+ "remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/remote", "/n/remote/dev/time");
+ }
+ }
+}
+
+getline(fd: ref Sys->FD, default: string): string
+{
+ result := "";
+ buf := array[10] of byte;
+ i := 0;
+ for(;;) {
+ n := sys->read(fd, buf[i:], len buf - i);
+ if(n < 1)
+ break;
+ i += n;
+ while(i >0 && (nutf := sys->utfbytes(buf, i)) > 0){
+ s := string buf[0:nutf];
+ for (j := 0; j < len s; j++)
+ case s[j] {
+ '\b' =>
+ if(result != nil)
+ result = result[0:len result-1];
+ 'u'&16r1F =>
+ sys->print("^U\n");
+ result = "";
+ '\r' =>
+ ;
+ * =>
+ sys->print("%c", s[j]);
+ if(s[j] == '\n' || s[j] >= 16r80){
+ if(s[j] != '\n')
+ result[len result] = s[j];
+ if(result == nil)
+ return default;
+ return result;
+ }
+ result[len result] = s[j];
+ }
+ buf[0:] = buf[nutf:i];
+ i -= nutf;
+ }
+ }
+ return default;
+}
+
+append(v: string, l: list of string): list of string
+{
+ if(l == nil)
+ return v :: nil;
+ return hd l :: append(v, tl l);
+}
+
+#
+# serve local DOS or kfs file system using flash translation layer
+#
+lfs(): int
+{
+ if(!flashpart("#F/flash/flashctl", flashparts))
+ return -1;
+ if(!ftlinit("#F/flash/fs"))
+ return -1;
+ if(iskfs("#X/ftldata"))
+ return lkfs("#X/ftldata");
+ c := chan of string;
+ spawn startfs(c, "/dis/dossrv.dis", "dossrv" :: "-f" :: "#X/ftldata" :: "-m" :: "/n/local" :: nil, nil);
+ if(<-c != nil)
+ return -1;
+ return 0;
+}
+
+wmagic := "kfs wren device\n";
+
+iskfs(file: string): int
+{
+ fd := sys->open(file, Sys->OREAD);
+ if(fd == nil)
+ return 0;
+ buf := array[512] of byte;
+ n := sys->read(fd, buf, len buf);
+ if(n < len buf)
+ return 0;
+ if(string buf[256:256+len wmagic] != wmagic)
+ return 0;
+ RBUFSIZE := int string buf[256+len wmagic:256+len wmagic+12];
+ if(RBUFSIZE % 512)
+ return 0; # bad block size
+ return 1;
+}
+
+lkfs(file: string): int
+{
+ p := array[2] of ref Sys->FD;
+ if(sys->pipe(p) < 0)
+ return -1;
+ c := chan of string;
+ spawn startfs(c, "/dis/disk/kfs.dis", "disk/kfs" :: "-A" :: "-n" :: "main" :: file :: nil, p[0]);
+ if(<-c != nil)
+ return -1;
+ p[0] = nil;
+ return sys->mount(p[1], nil, "/n/local", Sys->MREPL|Sys->MCREATE, nil);
+}
+
+startfs(c: chan of string, file: string, args: list of string, fd: ref Sys->FD)
+{
+ if(fd != nil){
+ sys->pctl(Sys->NEWFD, fd.fd :: 1 :: 2 :: nil);
+ sys->dup(fd.fd, 0);
+ }
+ fs := load Command file;
+ if(fs == nil){
+ sys->print("can't load %s: %r\n", file);
+ c <-= "load failed";
+ }
+ {
+ fs->init(nil, args);
+ c <-= nil;
+ }exception {
+ "*" =>
+ c <-= "failed";
+ * =>
+ c <-= "unknown exception";
+ }
+}
+
+#
+# partition flash
+#
+flashdone := 0;
+
+flashpart(ctl: string, parts: array of string): int
+{
+ if(flashdone)
+ return 1;
+ cfd := sys->open(ctl, Sys->ORDWR);
+ if(cfd == nil){
+ sys->print("can't open %s: %r\n", ctl);
+ return 0;
+ }
+ for(i := 0; i < len parts; i++)
+ if(sys->fprint(cfd, "%s", parts[i]) < 0){
+ sys->print("can't %q to %s: %r\n", parts[i], ctl);
+ return 0;
+ }
+ flashdone = 1;
+ return 1;
+}
+
+#
+# set up flash translation layer
+#
+ftldone := 0;
+
+ftlinit(flashmem: string): int
+{
+ if(ftldone)
+ return 1;
+ sys->print("Set flash translation of %s...\n", flashmem);
+ fd := sys->open("#X/ftlctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("can't open #X/ftlctl: %r\n");
+ return 0;
+ }
+ if(sys->fprint(fd, "init %s", flashmem) <= 0){
+ sys->print("can't init flash translation: %r\n");
+ return 0;
+ }
+ ftldone = 1;
+ return 1;
+}
+
+configether()
+{
+ if(ethername == nil)
+ return;
+ fd := sys->open("/nvfs/etherparams", Sys->OREAD);
+ if(fd == nil)
+ return;
+ ctl := sys->open("/net/"+ethername+"/clone", Sys->OWRITE);
+ if(ctl == nil){
+ sys->print("init: can't open %s's clone: %r\n", ethername);
+ return;
+ }
+ b := array[1024] of byte;
+ n := sys->read(fd, b, len b);
+ if(n <= 0)
+ return;
+ for(i := 0; i < n;){
+ for(e := i; e < n && b[e] != byte '\n'; e++)
+ ;
+ s := string b[i:e];
+ if(sys->fprint(ctl, "%s", s) < 0)
+ sys->print("init: ctl write to %s: %s: %r\n", ethername, s);
+ i = e+1;
+ }
+}
+
+donebind := 0;
+
+#
+# set up network mount
+#
+netfs(mountpt: string): int
+{
+ fd: ref Sys->FD;
+ if(!donebind){
+ fd = sys->open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil) {
+ sys->print("init: open /net/ipifc/clone: %r\n");
+ return -1;
+ }
+ if(sys->fprint(fd, "bind ether %s", ethername) < 0) {
+ sys->print("could not bind ether0 interface: %r\n");
+ return -1;
+ }
+ donebind = 1;
+ }else{
+ fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n");
+ return -1;
+ }
+ }
+ server := rdenv("fsip", nil);
+ if((ip := rdenv("ip", nil)) != nil) {
+ sys->print("**using %s\n", ip);
+ sys->fprint(fd, "bind ether /net/ether0");
+ sys->fprint(fd, "add %s ", ip);
+ if((ipgw := rdenv("ipgw", nil)) != nil){
+ rfd := sys->open("/net/iproute", Sys->OWRITE);
+ if(rfd != nil){
+ sys->fprint(rfd, "add 0 0 %s", ipgw);
+ sys->print("**using ipgw=%s\n", ipgw);
+ }
+ }
+ }else if(server == nil){
+ sys->print("dhcp...");
+ dhcpclient = load Dhcpclient Dhcpclient->PATH;
+ if(dhcpclient == nil){
+ sys->print("can't load dhcpclient: %r\n");
+ return -1;
+ }
+ dhcpclient->init();
+ (cfg, nil, e) := dhcpclient->dhcp("/net", fd, "/net/ether0/addr", nil, nil);
+ if(e != nil){
+ sys->print("dhcp: %s\n", e);
+ return -1;
+ }
+ if(server == nil)
+ server = cfg.getip(Dhcpclient->OP9fs);
+ dhcpclient = nil;
+ }
+ if(server == nil || server == "0.0.0.0"){
+ sys->print("no file server address\n");
+ return -1;
+ }
+ sys->print("fs=%s\n", server);
+
+ net := "tcp"; # how to specify il?
+ svcname := net + "!" + server + "!6666";
+
+ sys->print("dial %s...", svcname);
+
+ (ok, c) := sys->dial(svcname, nil);
+ if(ok < 0){
+ sys->print("can't dial %s: %r\n", svcname);
+ return -1;
+ }
+
+ sys->print("\nConnected ...\n");
+ if(kr != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount %s...", mountpt);
+
+ c.cfd = nil;
+ n := sys->mount(c.dfd, nil, mountpt, sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ if(n < 0)
+ sys->print("%r");
+ return -1;
+}
+
+calibrate()
+{
+ val := rf("/nvfs/calibrate", nil);
+ if(val != nil){
+ fd := sys->open("/dev/touchctl", Sys->OWRITE);
+ if(fd != nil && sys->fprint(fd, "%s", val) >= 0)
+ return;
+ }
+ done := chan of int;
+ spawn docal(done);
+ <-done;
+}
+
+docal(done: chan of int)
+{
+ sys->pctl(Sys->FORKFD, nil);
+ ofd := sys->create("/nvfs/calibrate", Sys->OWRITE, 8r644);
+ if(ofd != nil)
+ sys->dup(ofd.fd, 1);
+ cal := load Command "/dis/touchcal.dis";
+ if(cal != nil){
+ {
+ cal->init(nil, "touchcal" :: nil);
+ }exception{
+ "fail:*" =>
+ ;
+ }
+ }
+ done <-= 1;
+}
+
+userok(user: string): int
+{
+ (ok, d) := sys->stat("/usr/"+user);
+ return ok >= 0 && (d.mode & Sys->DMDIR) != 0;
+}
+
+rdenv(name: string, def: string): string
+{
+ s := rf("#e/"+name, nil);
+ if(s != nil)
+ return s;
+ s = rf("/nvfs/"+name, def);
+ while(s != nil && ((c := s[len s-1]) == '\n' || c == '\r'))
+ s = s[0: len s-1];
+ if(s != nil)
+ return s;
+ return def;
+}
+
+rf(file: string, default: string): string
+{
+ fd := sys->open(file, Sys->OREAD);
+ if(fd != nil){
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr > 0)
+ return string buf[0:nr];
+ }
+ return default;
+}
diff --git a/os/init/ipeinit.b b/os/init/ipeinit.b
new file mode 100644
index 00000000..7182ded3
--- /dev/null
+++ b/os/init/ipeinit.b
@@ -0,0 +1,620 @@
+#
+# ipEngine-1
+#
+
+implement Init;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+
+include "sh.m";
+
+Init: module
+{
+ init: fn();
+};
+
+Bootpreadlen: con 128;
+
+# standard flash partitions
+
+flashparts := array[] of {
+ # bootstrap at 0x0 to 0x6000
+ "add boot 0 0x6000",
+ "add param 0x6000 0x10000",
+ "add kernel 0x10000 0x110000",
+ "add fs 0x110000 end",
+};
+
+ethername := "ether0";
+
+#
+# initialise flash translation
+# mount flash file system
+# add devices
+# start a shell or window manager
+#
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->bind("/", "/", Sys->MREPL);
+
+ localok := 0;
+ if(lfs() >= 0){
+ # let's just take a closer look
+ sys->bind("/n/local/nvfs", "/nvfs", Sys->MREPL|Sys->MCREATE);
+ (rc, nil) := sys->stat("/n/local/dis/sh.dis");
+ if(rc >= 0)
+ localok = 1;
+ else
+ err("local file system unusable");
+ }
+ netok := sys->bind("#l", "/net", Sys->MREPL) >= 0;
+ if(!netok){
+ netok = sys->bind("#l1", "/net", Sys->MREPL) >= 0;
+ if(netok)
+ ethername = "ether1";
+ }
+ if(netok)
+ configether();
+ dobind("#I", "/net", sys->MAFTER); # IP
+ dobind("#p", "/prog", sys->MREPL); # prog
+ sys->bind("#d", "/fd", Sys->MREPL);
+ dobind("#c", "/dev", sys->MREPL); # console
+ dobind("#t", "/dev", sys->MAFTER); # serial line
+ drawok := sys->bind("#i", "/dev", sys->MAFTER) >= 0; # draw
+ sys->bind("#m", "/dev", sys->MAFTER); # pointer
+ sys->bind("#e", "/env", sys->MREPL|sys->MCREATE); # environment
+ sys->bind("#A", "/dev", Sys->MAFTER); # optional audio
+ timefile: string;
+ rootsource: string;
+ cfd := sys->open("/dev/consctl", Sys->OWRITE);
+ if(cfd != nil)
+ sys->fprint(cfd, "rawon");
+ for(;;){
+ (rootsource, timefile) = askrootsource(localok, netok);
+ if(rootsource == nil)
+ break; # internal
+ (rc, nil) := sys->stat(rootsource+"/dis/sh.dis");
+ if(rc < 0)
+ err("%s has no shell");
+ else if(sys->bind(rootsource, "/", Sys->MAFTER) < 0)
+ sys->print("can't bind %s on /: %r\n", rootsource);
+ else{
+ sys->bind(rootsource+"/dis", "/dis", Sys->MBEFORE|Sys->MCREATE);
+ break;
+ }
+ }
+ cfd = nil;
+
+ setsysname("ipe"); # set system name
+
+ now := getclock(timefile, rootsource);
+ setclock("/dev/time", now);
+ if(timefile != "#r/rtc")
+ setclock("#r/rtc", now/big 1000000);
+
+ sys->chdir("/");
+ if(netok){
+ start("ndb/dns", nil);
+ start("ndb/cs", nil);
+ }
+ startup := "/nvfs/startup";
+ if(sys->open(startup, Sys->OREAD) != nil){
+ shell := load Command Sh->PATH;
+ if(shell != nil){
+ sys->print("Running %s\n", startup);
+ shell->init(nil, "sh" :: startup :: nil);
+ }
+ }
+ user := username("inferno");
+ (ok, nil) := sys->stat("/dis/wm/wm.dis");
+ if(drawok && ok >= 0)
+ (ok, nil) = sys->stat("/dis/wm/logon.dis");
+ if(drawok && ok >= 0 && userok(user)){
+ wm := load Command "/dis/wm/wm.dis";
+ if(wm != nil){
+ fd := sys->open("/nvfs/user", Sys->OWRITE);
+ if(fd != nil){
+ sys->fprint(fd, "%s", user);
+ fd = nil;
+ }
+ spawn wm->init(nil, list of {"wm/wm", "wm/logon", "-l", "-u", user});
+ exit;
+ }
+ sys->print("init: can't load wm/logon: %r");
+ }
+ sh := load Command Sh->PATH;
+ if(sh == nil){
+ err(sys->sprint("can't load %s: %r", Sh->PATH));
+ hang();
+ }
+ spawn sh->init(nil, "sh" :: nil);
+}
+
+start(cmd: string, args: list of string)
+{
+ disfile := cmd;
+ if(disfile[0] != '/')
+ disfile = "/dis/"+disfile+".dis";
+ (ok, nil) := sys->stat(disfile);
+ if(ok >= 0){
+ dis := load Command disfile;
+ if(dis == nil)
+ sys->print("init: can't load %s: %r\n", disfile);
+ else
+ spawn dis->init(nil, cmd :: args);
+ }
+}
+
+dobind(f, t: string, flags: int)
+{
+ if(sys->bind(f, t, flags) < 0)
+ err(sys->sprint("can't bind %s on %s: %r", f, t));
+}
+
+#
+# Set system name from nvram if possible
+#
+setsysname(def: string)
+{
+ v := array of byte def;
+ fd := sys->open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ fd = sys->open("/env/sysname", sys->OREAD);
+ if(fd != nil){
+ buf := array[Sys->NAMEMAX] of byte;
+ nr := sys->read(fd, buf, len buf);
+ while(nr > 0 && buf[nr-1] == byte '\n')
+ nr--;
+ if(nr > 0)
+ v = buf[0:nr];
+ }
+ fd = sys->open("/dev/sysname", sys->OWRITE);
+ if(fd != nil)
+ sys->write(fd, v, len v);
+}
+
+getclock(timefile: string, timedir: string): big
+{
+ now := big 0;
+ if(timefile != nil){
+ fd := sys->open(timefile, Sys->OREAD);
+ if(fd != nil){
+ b := array[64] of byte;
+ n := sys->read(fd, b, len b-1);
+ if(n > 0){
+ now = big string b[0:n];
+ if(now <= big 16r20000000)
+ now = big 0; # remote itself is not initialised
+ }
+ }
+ }
+ if(now == big 0){
+ if(timedir != nil){
+ (ok, dir) := sys->stat(timedir);
+ if(ok < 0) {
+ sys->print("init: stat %s: %r", timedir);
+ return big 0;
+ }
+ now = big dir.atime;
+ }else{
+ now = big 993826747000000;
+ sys->print("time warped\n");
+ }
+ }
+ return now;
+}
+
+setclock(timefile: string, now: big)
+{
+ fd := sys->open(timefile, sys->OWRITE);
+ if (fd == nil) {
+ sys->print("init: can't open %s: %r", timefile);
+ return;
+ }
+
+ b := sys->aprint("%ubd", now);
+ if (sys->write(fd, b, len b) != len b)
+ sys->print("init: can't write to %s: %r", timefile);
+}
+
+srv()
+{
+ sys->print("remote debug srv...");
+ fd := sys->open("/dev/eia0ctl", Sys->OWRITE);
+ if(fd != nil)
+ sys->fprint(fd, "b115200");
+
+ fd = sys->open("/dev/eia0", Sys->ORDWR);
+ if (fd == nil){
+ err(sys->sprint("can't open /dev/eia0: %r"));
+ return;
+ }
+ if (sys->export(fd, "/", Sys->EXPASYNC) < 0){
+ err(sys->sprint("can't export on serial port: %r"));
+ return;
+ }
+}
+
+err(s: string)
+{
+ sys->fprint(sys->fildes(2), "init: %s\n", s);
+}
+
+hang()
+{
+ <-chan of int;
+}
+
+tried := 0;
+
+askrootsource(localok: int, netok: int): (string, string)
+{
+ stdin := sys->fildes(0);
+ sources := "kernel" :: nil;
+ if(netok)
+ sources = "remote" :: sources;
+ if(localok){
+ sources = "local" :: sources;
+ if(netok)
+ sources = "local+remote" :: sources;
+ }
+ for(;;) {
+ s := "";
+ if (tried == 0 && (s = rf("/nvfs/rootsource", nil)) != nil) {
+ tried = 1;
+ if (s[len s - 1] == '\n')
+ s = s[:len s - 1];
+ sys->print("/nvfs/rootsource: root from %s\n", s);
+ } else {
+ sys->print("root from (");
+ cm := "";
+ for(l := sources; l != nil; l = tl l){
+ sys->print("%s%s", cm, hd l);
+ cm = ",";
+ }
+ sys->print(")[%s] ", hd sources);
+
+ s = getline(stdin, hd sources); # default
+ }
+ (nil, choice) := sys->tokenize(s, "\t ");
+ if(choice == nil)
+ choice = sources;
+ opt := hd choice;
+ case opt {
+ * =>
+ sys->print("\ninvalid boot option: '%s'\n", opt);
+ "kernel" =>
+ return (nil, "#r/rtc");
+ "local" =>
+ return ("/n/local", "#r/rtc");
+ "local+remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/local", "/n/remote/dev/time");
+ "remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/remote", "/n/remote/dev/time");
+ }
+ }
+}
+
+getline(fd: ref Sys->FD, default: string): string
+{
+ result := "";
+ buf := array[10] of byte;
+ i := 0;
+ for(;;) {
+ n := sys->read(fd, buf[i:], len buf - i);
+ if(n < 1)
+ break;
+ i += n;
+ while(i >0 && (nutf := sys->utfbytes(buf, i)) > 0){
+ s := string buf[0:nutf];
+ for (j := 0; j < len s; j++)
+ case s[j] {
+ '\b' =>
+ if(result != nil)
+ result = result[0:len result-1];
+ 'u'&16r1F =>
+ sys->print("^U\n");
+ result = "";
+ '\r' =>
+ ;
+ * =>
+ sys->print("%c", s[j]);
+ if(s[j] == '\n' || s[j] >= 16r80){
+ if(s[j] != '\n')
+ result[len result] = s[j];
+ if(result == nil)
+ return default;
+ return result;
+ }
+ result[len result] = s[j];
+ }
+ buf[0:] = buf[nutf:i];
+ i -= nutf;
+ }
+ }
+ return default;
+}
+
+#
+# serve local DOS file system using flash translation layer
+#
+lfs(): int
+{
+ if(!flashpart("#F/flash/flashctl", flashparts))
+ return -1;
+ if(!ftlinit("#F/flash/fs"))
+ return -1;
+ c := chan of string;
+ spawn startfs(c, "/dis/dossrv.dis", "dossrv" :: "-f" :: "#X/ftldata" :: "-m" :: "/n/local" :: nil);
+ if(<-c != nil)
+ return -1;
+ return 0;
+}
+
+startfs(c: chan of string, file: string, args: list of string)
+{
+ fs := load Command file;
+ if(fs == nil){
+ sys->print("can't load %s: %r\n", file);
+ c <-= "load failed";
+ }
+ {
+ fs->init(nil, args);
+ }exception e {
+ "*" =>
+ c <-= "failed";
+ exit;
+ * =>
+ c <-= "unknown exception";
+ exit;
+ }
+ c <-= nil;
+}
+
+#
+# partition flash
+#
+flashdone := 0;
+
+flashpart(ctl: string, parts: array of string): int
+{
+ if(flashdone)
+ return 1;
+ cfd := sys->open(ctl, Sys->ORDWR);
+ if(cfd == nil){
+ sys->print("can't open %s: %r\n", ctl);
+ return 0;
+ }
+ for(i := 0; i < len parts; i++)
+ if(sys->fprint(cfd, "%s", parts[i]) < 0){
+ sys->print("can't %q to %s: %r\n", parts[i], ctl);
+ return 0;
+ }
+ flashdone = 1;
+ return 1;
+}
+
+#
+# set up flash translation layer
+#
+ftldone := 0;
+
+ftlinit(flashmem: string): int
+{
+ if(ftldone)
+ return 1;
+ sys->print("Set flash translation of %s...\n", flashmem);
+ fd := sys->open("#X/ftlctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("can't open #X/ftlctl: %r\n");
+ return 0;
+ }
+ if(sys->fprint(fd, "init %s", flashmem) <= 0){
+ sys->print("can't init flash translation: %r\n");
+ return 0;
+ }
+ ftldone = 1;
+ return 1;
+}
+
+configether()
+{
+ if(ethername == nil)
+ return;
+ fd := sys->open("/nvfs/etherparams", Sys->OREAD);
+ if(fd == nil)
+ return;
+ ctl := sys->open("/net/"+ethername+"/clone", Sys->OWRITE);
+ if(ctl == nil){
+ sys->print("init: can't open %s's clone: %r\n", ethername);
+ return;
+ }
+ b := array[1024] of byte;
+ n := sys->read(fd, b, len b);
+ if(n <= 0)
+ return;
+ for(i := 0; i < n;){
+ for(e := i; e < n && b[e] != byte '\n'; e++)
+ ;
+ s := string b[i:e];
+ if(sys->fprint(ctl, "%s", s) < 0)
+ sys->print("init: ctl write to %s: %s: %r\n", ethername, s);
+ i = e+1;
+ }
+}
+
+donebind := 0;
+
+#
+# set up network mount
+#
+netfs(mountpt: string): int
+{
+ sys->print("bootp ...");
+
+ fd: ref Sys->FD;
+ if(!donebind){
+ fd = sys->open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil) {
+ sys->print("init: open /net/ipifc/clone: %r\n");
+ return -1;
+ }
+ if(sys->fprint(fd, "bind ether %s", ethername) < 0) {
+ sys->print("could not bind ether0 interface: %r\n");
+ return -1;
+ }
+ donebind = 1;
+ }else{
+ fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n");
+ return -1;
+ }
+ }
+ if ((ip := rf("/nvfs/ip", nil)) != nil || (ip = rf("#e/myip", nil)) != nil) {
+ sys->print("**using %s\n", ip);
+ sys->fprint(fd, "bind ether /net/ether0");
+ sys->fprint(fd, "add %s %s", ip, rf("#e/netmask", nil));
+ gate := rf("#e/gateway", nil);
+ if(gate != nil){
+ rfd := sys->open("/net/iproute", Sys->OWRITE);
+ if(rfd != nil){
+ sys->fprint(rfd, "add 0 0 %s", gate);
+ sys->print("set gateway %s\n", gate);
+ }
+ }
+ } else {
+ {
+ if(sys->fprint(fd, "bootp") < 0)
+ sys->print("could not bootp: %r\n");
+ } exception e {
+ "*" =>
+ sys->print("could not bootp: %s\n", e);
+ }
+ }
+ server := rf("/nvfs/fsip", nil);
+ if(server == nil)
+ server = rf("#e/fsip", nil);
+ if (server != nil) {
+ if (server[len server - 1] == '\n')
+ server = server[:len server - 1];
+ sys->print("/nvfs/fsip: server=%s\n", server);
+ } else
+ server = bootp();
+ if(server == nil || server == "0.0.0.0")
+ return -1;
+
+ net := "tcp"; # how to specify il?
+ svcname := net + "!" + server + "!6666";
+
+ sys->print("dial %s...", svcname);
+
+ (ok, c) := sys->dial(svcname, nil);
+ if(ok < 0){
+ sys->print("can't dial %s: %r\n", svcname);
+ return -1;
+ }
+
+ sys->print("\nConnected ...\n");
+ if(kr != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount %s...", mountpt);
+
+ c.cfd = nil;
+ n := sys->mount(c.dfd, nil, mountpt, sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ if(n < 0)
+ sys->print("%r");
+ return -1;
+}
+
+bootp(): string
+{
+ fd := sys->open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ sys->print("init: can't open /net/bootp: %r");
+ return nil;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := sys->read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ sys->print("init: read /net/bootp: %r");
+ return nil;
+ }
+
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ sys->print("init: server address not in bootp read");
+ return nil;
+ }
+
+ srv := hd ls;
+
+ sys->print("%s\n", srv);
+
+ return srv;
+}
+
+username(def: string): string
+{
+ return rf("/nvfs/user", def);
+}
+
+userok(user: string): int
+{
+ (ok, d) := sys->stat("/usr/"+user);
+ return ok >= 0 && (d.mode & Sys->DMDIR) != 0;
+}
+
+rf(file: string, default: string): string
+{
+ fd := sys->open(file, Sys->OREAD);
+ if(fd != nil){
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr > 0)
+ return string buf[0:nr];
+ }
+ return default;
+}
diff --git a/os/init/jsinit.b b/os/init/jsinit.b
new file mode 100644
index 00000000..a8c9cc68
--- /dev/null
+++ b/os/init/jsinit.b
@@ -0,0 +1,213 @@
+implement Init;
+#
+# init program for standalone wm using TK
+#
+include "sys.m";
+sys: Sys;
+ FD, Connection, sprint, Dir: import sys;
+ print, fprint, open, bind, mount, dial, sleep, read: import sys;
+
+include "draw.m";
+ draw: Draw;
+ Context: import draw;
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+
+Init: module
+{
+ init: fn();
+};
+
+Logon: module
+{
+ init: fn(ctxt: ref Context, argv: list of string);
+};
+
+rootfs(server: string): int
+{
+ ok, n: int;
+ c: Connection;
+
+ (ok, c) = dial("tcp!" + server + "!6666", nil);
+ if(ok < 0)
+ return -1;
+
+ sys->print("Connected ...");
+ if(kr != nil && auth != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount ...");
+
+ c.cfd = nil;
+ n = mount(c.dfd, nil, "/", sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ return -1;
+}
+
+Bootpreadlen: con 128;
+
+init()
+{
+ spec: string;
+
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->print("**\n** Inferno\n** Vita Nuova\n**\n");
+
+ sys->print("Setup boot net services ...\n");
+
+ #
+ # Setup what we need to call a server and
+ # Authenticate
+ #
+ bind("#l", "/net", sys->MREPL);
+ bind("#I", "/net", sys->MAFTER);
+ bind("#c", "/dev", sys->MAFTER);
+ bind("#r", "/dev", sys->MAFTER);
+ nvramfd := sys->open("#r/nvram", sys->ORDWR);
+ if(nvramfd != nil){
+ spec = "#Fnvram";
+ if(bind(spec, "/nvfs", sys->MAFTER) < 0)
+ print("init: bind %s: %r\n", spec);
+ nvramfd = nil;
+ }
+
+ setsysname();
+
+ sys->print("bootp...");
+
+ fd := open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil) {
+ print("init: open /net/ipifc/clone: %r\n");
+ exit;
+ }
+ cfg := array of byte "bind ether ether";
+ if(sys->write(fd, cfg, len cfg) != len cfg) {
+ sys->print("could not bind interface: %r\n");
+ exit;
+ }
+ cfg = array of byte "bootp";
+ if(sys->write(fd, cfg, len cfg) != len cfg) {
+ sys->print("could not bootp: %r\n");
+ exit;
+ }
+
+ fd = open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ print("init: open /net/bootp: %r");
+ exit;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ print("init: read /net/bootp: %r");
+ exit;
+ }
+
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ print("init: server address not in bootp read");
+ exit;
+ }
+
+ srv := hd ls;
+ sys->print("server %s\nConnect ...\n", srv);
+
+ while(rootfs(srv) < 0)
+ sleep(1000);
+
+ sys->print("done\n");
+
+ #
+ # default namespace
+ #
+ bind("#c", "/dev", sys->MBEFORE); # console
+ bind("#r", "/dev", sys->MAFTER);
+ if(spec != nil)
+ bind(spec, "/nvfs", sys->MBEFORE|sys->MCREATE); # our keys
+ bind("#l", "/net", sys->MBEFORE); # ethernet
+ bind("#I", "/net", sys->MBEFORE); # TCP/IP
+ bind("#p", "/prog", sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+
+ sys->print("clock...\n");
+ setclock();
+
+ sys->print("logon...\n");
+
+ logon := load Logon "/dis/wm/logon.dis";
+ if(logon == nil) {
+ print("init: load /dis/wm/logon.dis: %r");
+ exit;
+ }
+ dc: ref Context;
+ spawn logon->init(dc, nil);
+}
+
+setclock()
+{
+ (ok, dir) := sys->stat("/");
+ if (ok < 0) {
+ print("init: stat /: %r");
+ return;
+ }
+
+ fd := sys->open("/dev/time", sys->OWRITE);
+ if (fd == nil) {
+ print("init: open /dev/time: %r");
+ return;
+ }
+
+ # Time is kept as microsecs, atime is in secs
+ b := array of byte sprint("%d000000", dir.atime);
+ if (sys->write(fd, b, len b) != len b)
+ print("init: write /dev/time: %r");
+}
+
+#
+# Set system name from nvram
+#
+setsysname()
+{
+ fd := open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ return;
+ fds := open("/dev/sysname", sys->OWRITE);
+ if(fds == nil)
+ return;
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr <= 0)
+ return;
+ sys->write(fds, buf, nr);
+}
diff --git a/os/init/mkfile b/os/init/mkfile
new file mode 100644
index 00000000..e027809d
--- /dev/null
+++ b/os/init/mkfile
@@ -0,0 +1,27 @@
+<../../mkconfig
+
+OBJ=\
+ wminit.dis\
+
+all:V: $OBJ
+install:V: all
+installall:V: all
+
+clean nuke:V:
+ rm -f *.dis *.sbl
+
+INCLD=\
+ -I$ROOT/module\
+
+%.dis: %.b
+ limbo $INCLD -gw $stem.b
+
+%.s: %.b
+ limbo $INCLD -w -G -S $stem.b
+
+ir%.dis: ../../appl/lib/ir%.b
+ limbo $INCLD -gw $prereq
+
+ir%.s: ../../appl/lib/ir%.b
+ limbo $INCLD -w -G -S $prereq
+
diff --git a/os/init/mpcinit.b b/os/init/mpcinit.b
new file mode 100644
index 00000000..bef89fa2
--- /dev/null
+++ b/os/init/mpcinit.b
@@ -0,0 +1,383 @@
+implement Init;
+#
+# init program for Motorola 800 series (serial console only)
+#
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+ draw: Draw;
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+
+Init: module
+{
+ init: fn();
+};
+
+Shell: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+Bootpreadlen: con 128;
+
+# option switches
+UseLocalFS: con 1<<0;
+EtherBoot: con 1<<1;
+Prompting: con 1<<3;
+
+lfs(): int
+{
+ if(!ftlinit("#F/flash/flash", 1024*1024, 1024*1024))
+ return -1;
+ if(mountkfs("#X/ftldata", "main", "flash") < 0)
+ return -1;
+ if(sys->bind("#Kmain", "/n/local", sys->MREPL) < 0){
+ sys->print("can't bind #Kmain to /n/local: %r\n");
+ return -1;
+ }
+ if(sys->bind("/n/local", "/", Sys->MCREATE|Sys->MREPL) < 0){
+ sys->print("can't bind /n/local after /: %r\n");
+ return -1;
+ }
+ return 0;
+}
+
+donebind := 0;
+
+#
+# set up network mount
+#
+netfs(mountpt: string): int
+{
+ sys->print("bootp ...");
+
+ fd: ref Sys->FD;
+ if(!donebind){
+ fd = sys->open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil) {
+ sys->print("init: open /net/ipifc/clone: %r\n");
+ return -1;
+ }
+ if(sys->fprint(fd, "bind ether %s", "/net/ether0") < 0) {
+ sys->print("could not bind ether0 interface: %r\n");
+ return -1;
+ }
+ donebind = 1;
+ }else{
+ fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n");
+ return -1;
+ }
+ }
+ if(sys->fprint(fd, "bootp") < 0){
+ sys->print("init: bootp failed: %r\n");
+ return -1;
+ }
+
+ server := bootp();
+ if(server == nil)
+ return -1;
+
+ net := "tcp"; # how to specify il?
+ svcname := net + "!" + server + "!6666";
+
+ sys->print("dial %s...", svcname);
+
+ (ok, c) := sys->dial(svcname, nil);
+ if(ok < 0){
+ sys->print("can't dial %s: %r\n", svcname);
+ return -1;
+ }
+
+ sys->print("\nConnected ...\n");
+ if(kr != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount %s...", mountpt);
+
+ c.cfd = nil;
+ n := sys->mount(c.dfd, nil, mountpt, sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ if(n < 0)
+ sys->print("%r");
+ return -1;
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->print("**\n** Inferno\n** Vita Nuova\n**\n");
+
+ optsw := options();
+ sys->print("Switch options: 0x%ux\n", optsw);
+
+ #
+ # Setup what we need to call a server and
+ # Authenticate
+ #
+ sys->bind("#l", "/net", sys->MREPL);
+ sys->bind("#I", "/net", sys->MAFTER);
+ sys->bind("#c", "/dev", sys->MAFTER);
+
+ fsready := 0;
+ mountpt := "/";
+ usertc := 0;
+
+ if((optsw & Prompting) == 0){
+ if(optsw & UseLocalFS){
+ sys->print("Option: use local file system\n");
+ if(lfs() == 0){
+ fsready = 1;
+ mountpt = "/n/remote";
+ }
+ }
+
+ if(optsw & EtherBoot){
+ sys->print("Attempting remote mount\n");
+ if(netfs(mountpt) == 0)
+ fsready = 1;
+ }
+ }
+
+ if(fsready == 0){
+
+ sys->print("\n\n");
+
+ stdin := sys->fildes(0);
+ buf := array[128] of byte;
+ sources := "fs" :: "net" :: nil;
+
+ loop: for(;;) {
+ sys->print("root from (");
+ cm := "";
+ for(l := sources; l != nil; l = tl l){
+ sys->print("%s%s", cm, hd l);
+ cm = ",";
+ }
+ sys->print(")[%s] ", hd sources);
+
+ n := sys->read(stdin, buf, len buf);
+ if(n <= 0)
+ continue;
+ if(buf[n-1] == byte '\n')
+ n--;
+
+ (nil, choice) := sys->tokenize(string buf[0:n], "\t ");
+
+ if(choice == nil)
+ choice = sources;
+ opt := hd choice;
+ case opt {
+ * =>
+ sys->print("\ninvalid boot option: '%s'\n", opt);
+ break;
+ "fs" or "" =>
+ if(lfs() == 0){
+ usertc = 1;
+ break loop;
+ }
+ "net" =>
+ if(netfs("/") == 0)
+ break loop;
+ }
+ }
+ }
+
+ #
+ # default namespace
+ #
+ sys->unmount(nil, "/dev");
+ sys->bind("#c", "/dev", sys->MBEFORE); # console
+ sys->bind("#l", "/net", sys->MBEFORE); # ethernet
+ sys->bind("#I", "/net", sys->MBEFORE); # TCP/IP
+ sys->bind("#p", "/prog", sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+
+ setsysname();
+
+ sys->print("clock...\n");
+ setclock(usertc, mountpt);
+
+ sys->print("Console...\n");
+
+ shell := load Shell "/dis/sh.dis";
+ if(shell == nil) {
+ sys->print("init: load /dis/sh.dis: %r");
+ exit;
+ }
+ dc: ref Draw->Context;
+ shell->init(dc, nil);
+}
+
+setclock(usertc: int, timedir: string)
+{
+ now := 0;
+ if(usertc){
+ fd := sys->open("#r/rtc", Sys->OREAD);
+ if(fd != nil){
+ b := array[64] of byte;
+ n := sys->read(fd, b, len b-1);
+ if(n > 0){
+ b[n] = byte 0;
+ now = int string b;
+ if(now <= 16r20000000)
+ now = 0; # rtc itself is not initialised
+ }
+ }
+ }
+ if(now == 0){
+ (ok, dir) := sys->stat(timedir);
+ if (ok < 0) {
+ sys->print("init: stat %s: %r", timedir);
+ return;
+ }
+ now = dir.atime;
+ }
+ fd := sys->open("/dev/time", sys->OWRITE);
+ if (fd == nil) {
+ sys->print("init: can't open /dev/time: %r");
+ return;
+ }
+
+ # Time is kept as microsecs, atime is in secs
+ b := array of byte sys->sprint("%ud000000", now);
+ if (sys->write(fd, b, len b) != len b)
+ sys->print("init: can't write /dev/time: %r");
+}
+
+#
+# Set system name from nvram
+#
+setsysname()
+{
+ fd := sys->open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ return;
+ fds := sys->open("/dev/sysname", sys->OWRITE);
+ if(fds == nil)
+ return;
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr <= 0)
+ return;
+ sys->write(fds, buf, nr);
+}
+
+#
+# fetch options from switch DS2
+#
+options(): int
+{
+ fd := sys->open("#r/switch", Sys->OREAD);
+ if(fd == nil){
+ sys->print("can't open #r/switch: %r\n");
+ return 0;
+ }
+ b := array[20] of byte;
+ n := sys->read(fd, b, len b);
+ s := string b[0:n];
+ return int s;
+}
+
+bootp(): string
+{
+ fd := sys->open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ sys->print("init: can't open /net/bootp: %r");
+ return nil;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := sys->read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ sys->print("init: read /net/bootp: %r");
+ return nil;
+ }
+
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ sys->print("init: server address not in bootp read");
+ return nil;
+ }
+
+ srv := hd ls;
+
+ sys->print("%s\n", srv);
+
+ return srv;
+}
+
+#
+# set up flash translation layer
+#
+ftldone := 0;
+
+ftlinit(flashmem: string, offset: int, length: int): int
+{
+ if(ftldone)
+ return 1;
+ sys->print("Set flash translation of %s at offset %d (%d bytes)\n", flashmem, offset, length);
+ fd := sys->open("#X/ftlctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("can't open #X/ftlctl: %r\n");
+ return 0;
+ }
+ if(sys->fprint(fd, "init %s %ud %ud", flashmem, offset, length) <= 0){
+ sys->print("can't init flash translation: %r");
+ return 0;
+ }
+ ftldone = 1;
+ return 1;
+}
+
+#
+# Mount kfs filesystem
+#
+mountkfs(devname: string, fsname: string, options: string): int
+{
+ fd := sys->open("#Kcons/kfsctl", sys->OWRITE);
+ if(fd == nil) {
+ sys->print("could not open #Kcons/kfsctl: %r\n");
+ return -1;
+ }
+ if(sys->fprint(fd, "filsys %s %s %s", fsname, devname, options) <= 0){
+ sys->print("could not write #Kcons/kfsctl: %r\n");
+ return -1;
+ }
+ if(options == "ro")
+ sys->fprint(fd, "cons flashwrite");
+ return 0;
+}
diff --git a/os/init/pcdemo.b b/os/init/pcdemo.b
new file mode 100644
index 00000000..5a7ec76b
--- /dev/null
+++ b/os/init/pcdemo.b
@@ -0,0 +1,273 @@
+#
+# Init shell ``with the kitchen sink'', for development purposes.
+#
+implement InitShell;
+
+include "sys.m";
+include "draw.m";
+
+sys: Sys;
+FD, Connection, sprint, Dir: import sys;
+print, fprint, open, bind, mount, dial, sleep, read: import sys;
+
+stderr: ref sys->FD; # standard error FD
+
+InitShell: module
+{
+ init: fn(nil: ref Draw->Context, nil: list of string);
+};
+
+Sh: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+init(nil: ref Draw->Context, nil: list of string)
+{
+ sys = load Sys Sys->PATH;
+ stderr = sys->fildes(2);
+
+ sys->print("Welcome to Inferno...\n");
+
+ sys->pctl(Sys->NEWNS, nil);
+ if (imount("/n/remote")) {
+ bind("/n/remote", "/", sys->MAFTER);
+ bind("/n/remote/dis", "/dis", sys->MBEFORE);
+ mountkfs("#W/flash0fs", "fs", "/n/local", sys->MREPL);
+ }
+ else {
+ # bind("#U/pcdemo", "/", sys->MREPL);
+ # mountkfs("#U/pcdemo.kfs", "fs", "/", sys->MBEFORE);
+ # bind("#U/pcdemo/usr", "/usr", sys->MAFTER);
+ mountkfs("#R/ramdisk", "fs", "/", sys->MBEFORE);
+ bind("/services", "/data", sys->MREPL|sys->MCREATE);
+ }
+
+ namespace();
+ srv();
+
+ if (1) {
+ bind("/icons/oldlogon.bit", "/icons/logon.bit", sys->MREPL);
+ bind("/icons/tk/oldinferno.bit", "/icons/tk/inferno.bit", sys->MREPL);
+ }
+
+ sys->print("starting shell (type wm/logon or wm/wmcp)\n");
+ shell := sysenv("shell");
+ if (shell == nil)
+ shell = "/dis/sh.dis";
+ sh := load Sh shell;
+ spawn sh->init(nil, nil);
+}
+
+namespace()
+{
+ # Bind anything useful we can get our hands on. Ignore errors.
+ sys->print("namespace...\n");
+ sys->bind("#I", "/net", sys->MAFTER); # IP
+ sys->bind("#I1", "/net.alt", sys->MREPL); # second IP for PPP tests
+ sys->bind("#p", "/prog", sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+ sys->bind("#i", "/dev", sys->MREPL); # draw device
+ sys->bind("#t", "/dev", sys->MAFTER); # serial line
+ sys->bind("#c", "/dev", sys->MAFTER); # console device
+ sys->bind("#W", "/dev", sys->MAFTER); # Flash
+ sys->bind("#O", "/dev", sys->MAFTER); # Modem
+ sys->bind("#T", "/dev", sys->MAFTER); # Touchscreen
+ sys->bind("#H", "/dev", sys->MAFTER); # Ata disk device
+ sys->bind("#b", "/dev", sys->MAFTER); # debug device
+ sys->bind("#c", "/chan", sys->MREPL);
+ sys->bind("/data", "/usr/inferno", sys->MREPL|sys->MCREATE);
+ sys->bind("/data", "/usr/charon", sys->MREPL|sys->MCREATE);
+ sys->bind("/data", "/usr/shaggy", sys->MREPL|sys->MCREATE);
+}
+
+mountkfs(devname: string, fsname: string, where: string, flags: int): int
+{
+ sys->print("mount kfs...\n");
+ fd := sys->open("#Kcons/kfsctl", sys->OWRITE);
+ if (fd == nil) {
+ sys->fprint(stderr, "could not open #Kcons/kfsctl: %r\n");
+ return 0;
+ }
+ kfsopt := "";
+ kfsrw := sysenv("kfsrw");
+# if (kfsrw != "1")
+# kfsopt = " ronly";
+ b := array of byte ("filsys " + fsname + " " + devname + kfsopt);
+ if (sys->write(fd, b, len b) < 0) {
+ sys->fprint(stderr, "could not write #Kcons/kfsctl: %r\n");
+ return 0;
+ }
+ if (sys->bind("#K" + fsname, where, flags) < 0) {
+ sys->fprint(stderr, "could not bind %s to %s: %r\n", "#K" + fsname, where);
+ return 0;
+ }
+ return 1;
+}
+
+dialfs(server: string, where: string): int
+{
+ ok, n: int;
+ c: Connection;
+
+ (ok, c) = dial("tcp!" + server + "!6666", nil);
+ if(ok < 0)
+ return 0;
+
+ sys->print("mount...");
+
+ c.cfd = nil;
+ n = mount(c.dfd, where, sys->MREPL, "");
+ if(n > 0)
+ return 1;
+ sys->print("mount failed: %r\n");
+ return 0;
+}
+
+Bootpreadlen: con 128;
+
+imount(where: string): int
+{
+ sys->print("bootp...");
+ if (sys->bind("#I", "/net", sys->MREPL) < 0) {
+ sys->fprint(stderr, "could not bind ip device: %r\n");
+ return 0;
+ }
+ if (sys->bind("#l", "/net", sys->MAFTER) < 0) {
+ sys->fprint(stderr, "could not bind ether device: %r\n");
+ return 0;
+ }
+
+ fd := sys->open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil) {
+ sys->print("init: open /net/ipifc: %r");
+ return 0;
+ }
+
+ cfg := array of byte "bind ether ether0";
+ if(sys->write(fd, cfg, len cfg) != len cfg) {
+ sys->fprint(stderr, "could not bind interface: %r\n");
+ return 0;
+ }
+ cfg = array of byte "bootp";
+ if(sys->write(fd, cfg, len cfg) != len cfg) {
+ sys->fprint(stderr, "could not bootp: %r\n");
+ return 0;
+ }
+
+ bfd := sys->open("/net/bootp", sys->OREAD);
+ if(bfd == nil) {
+ sys->print("init: can't open /net/bootp: %r");
+ return 0;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := sys->read(bfd, buf, len buf);
+ bfd = nil;
+ if(nr <= 0) {
+ sys->print("init: read /net/bootp: %r");
+ return 0;
+ }
+
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ sys->print("init: server address not in bootp read");
+ return 0;
+ }
+
+ server := hd ls;
+ sys->print("imount: server %s\n", server);
+
+ return dialfs(server, where);
+}
+
+srv()
+{
+ remotedebug := sysenv("remotedebug");
+ if(remotedebug != "1")
+ return;
+ remotespeed := sysenv("remotespeed");
+ if (remotespeed == nil)
+ remotespeed = "38400";
+
+ sys->print("srv...");
+ if(echoto("#t/eia0ctl", "b" + remotespeed) < 0)
+ return;
+
+ fd := sys->open("/dev/eia0", Sys->ORDWR);
+ if (fd == nil) {
+ sys->print("eia data open: %r\n");
+ return;
+ }
+ if (sys->export(fd, Sys->EXPASYNC) < 0) {
+ sys->print("export: %r\n");
+ return;
+ }
+ sys->print("ok\n");
+}
+
+sysenv(param: string): string
+{
+ fd := sys->open("#c/sysenv", sys->OREAD);
+ if (fd == nil)
+ return(nil);
+ buf := array[4096] of byte;
+ nb := sys->read(fd, buf, len buf);
+ (nfl,fl) := sys->tokenize(string buf, "\n");
+ while (fl != nil) {
+ pair := hd fl;
+ (npl, pl) := sys->tokenize(pair, "=");
+ if (npl > 1) {
+ if ((hd pl) == param)
+ return hd tl pl;
+ }
+ fl = tl fl;
+ }
+ return nil;
+}
+
+echoto(fname, str: string): int
+{
+ fd := sys->open(fname, Sys->OWRITE);
+ if(fd == nil) {
+ sys->print("%s: %r\n", fname);
+ return -1;
+ }
+ x := array of byte str;
+ if(sys->write(fd, x, len x) == -1) {
+ sys->print("write: %r\n");
+ return -1;
+ }
+ return 0;
+}
+
+hang()
+{
+ c := chan of int;
+ <- c;
+}
+
+#
+# Set system name from nvram
+#
+setsysname()
+{
+ fd := open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ return;
+ fds := open("/dev/sysname", sys->OWRITE);
+ if(fds == nil)
+ return;
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr <= 0)
+ return;
+ sys->write(fds, buf, nr);
+}
diff --git a/os/init/pcinit.b b/os/init/pcinit.b
new file mode 100644
index 00000000..98899b45
--- /dev/null
+++ b/os/init/pcinit.b
@@ -0,0 +1,405 @@
+implement Init;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+ draw: Draw;
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+
+include "styx.m";
+
+ dosfs : Dosfs;
+
+PROMPT: con 1; # boot from prompt? (0 means boot from fs)
+SHELL: con 0; # Start a Shell, not Logon
+INIT: con "/init"; # file to read init commands from
+
+startip := 0;
+
+Bootpreadlen: con 128;
+
+Init: module
+{
+ init: fn();
+};
+
+Logon: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+Sh: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+lfs(dev: string): int
+{
+ (ok, dir) := sys->stat(dev);
+ if (ok < 0) {
+ sys->print("init: stat %s: %r\n", dev);
+ return -1;
+ }
+ pipefd := array[2] of ref Sys->FD;
+ dosfs = load Dosfs "#/./dosfs";
+ if(dosfs == nil) {
+ sys->fprint(sys->fildes(2),"load #/.dosfs: %r\n");
+ return -1;
+ }
+
+ dosfs->init(dev, "", 0);
+ if(sys->pipe(pipefd) < 0){
+ sys->fprint(sys->fildes(2),"pipe %r\n");
+ exit;
+ }
+ spawn dosfs->dossrv(pipefd[1]);
+
+ n := sys->mount(pipefd[0], "/", sys->MREPL|sys->MCREATE, "");
+ if(n<0) {
+ sys->print("couldn't mount. %r\n");
+ return -1;
+ }
+
+ dosfs->setup();
+
+ sys->print("mounted %s at /\n", dev);
+
+ return 0;
+}
+
+ipinit()
+{
+ fd := sys->open("/nvfs/IP", sys->OREAD);
+ if(fd == nil)
+ return;
+
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr <= 0)
+ return;
+
+ cfd := sys->open("/net/ipifc/clone", sys->ORDWR);
+ if(cfd == nil) {
+ sys->print("init: open /net/ipifc/clone: %r");
+ exit;
+ }
+
+ sys->fprint(cfd, "bind ether ether0");
+ sys->fprint(cfd, "%s", string buf[0:nr]);
+}
+
+netfs(): int
+{
+ cfd := sys->open("/net/ipifc/clone", sys->ORDWR);
+ if(cfd == nil) {
+ sys->print("init: open /net/ipifc/clone: %r");
+ exit;
+ }
+ sys->fprint(cfd, "bind ether ether0");
+
+ server:= bootp(cfd);
+ sys->print("dial...");
+ (ok, c) := sys->dial("tcp!" + server + "!6666", nil);
+ if(ok < 0)
+ return -1;
+
+ if(kr != nil && auth != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount ...");
+
+ c.cfd = nil;
+ n := sys->mount(c.dfd, "/", sys->MREPL, "");
+ if(n > 0)
+ return 0;
+
+ return -1;
+}
+
+init()
+{
+ spec: string;
+
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->print("**\n** Inferno\n** Vita Nuova\n**\n\n\n");
+
+ #
+ # Setup what we need to call a server and
+ # Authenticate
+ #
+ sys->bind("#l", "/net", sys->MREPL);
+ sys->bind("#I", "/net", sys->MAFTER);
+ sys->bind("#c", "/dev", sys->MAFTER);
+
+ sys->print("Non-volatile ram read ...\n");
+
+ nvramfd := sys->open("#H/hd0nvram", sys->ORDWR);
+ if(nvramfd != nil) {
+ spec = "#Fhd0nvram";
+ if(sys->bind(spec, "/nvfs", sys->MAFTER) < 0)
+ sys->print("init: bind %s: %r\n", spec);
+ sys->print("mounted tinyfs");
+ nvramfd = nil;
+ }
+
+ sys->print("\n\n");
+
+ if(!PROMPT) {
+ if(lfs("#H/hd0fs") == 0)
+ startip = 1;
+ else
+ bootfrom();
+ } else
+ bootfrom();
+
+ sys->bind("#l", "/net", sys->MBEFORE);
+ sys->bind("#I", "/net", sys->MBEFORE);
+ sys->bind("#c", "/dev", sys->MBEFORE);
+
+ if(startip)
+ ipinit();
+
+ setsysname();
+
+ sys->print("clock...\n");
+ setclock();
+
+ if(SHELL) {
+ sys->print("shell...\n");
+
+ logon := load Logon "/dis/sh.dis";
+ if(logon == nil) {
+ sys->print("init: load /dis/wm/logon.dis: %r");
+ exit;
+ }
+ dc: ref Draw->Context;
+ spawn logon->init(dc, nil);
+ exit;
+ }
+
+ runprogs();
+}
+
+bootfrom()
+{
+ buf := array[128] of byte;
+ stdin := sys->fildes(0);
+
+ fsdev := "#H/hd0disk";
+
+ loop: for(;;) {
+ sys->print("boot from [fs, net]: ");
+
+ n := sys->read(stdin, buf, len buf);
+ if(n <= 0)
+ continue;
+ if(buf[n-1] == byte '\n')
+ n--;
+
+ (nil, choice) := sys->tokenize(string buf[:n], "\t ");
+ if(choice == nil)
+ continue;
+
+ opt := hd choice;
+ choice = tl choice;
+
+ case opt {
+ * =>
+ sys->print("\ninvalid boot option: '%s'\n", opt);
+ break;
+ "fs" or "" =>
+ if(choice != nil)
+ fsdev = hd choice;
+ if(lfs(fsdev) == 0) {
+ startip = 1;
+ break loop;
+ }
+ "net" =>
+ if(netfs() == 0)
+ break loop;
+ }
+ }
+}
+
+runprogs()
+{
+ fd:= sys->open(INIT, Sys->OREAD);
+ if(fd == nil) {
+ sys->print("open %s: %r\n", INIT);
+ return;
+ }
+
+ dc := ref Draw->Context;
+ dc.ctomux = chan of int;
+
+ for(l:=1;;l++) {
+ (e, line):= getline(fd);
+ if(e != nil) {
+ sys->print(INIT+":%d: %s\n", l, e);
+ return;
+ }
+ if(line == nil)
+ break;
+ if(line == "\n" || line[0] == '#')
+ continue;
+ if(line[len line-1] == '\n')
+ line = line[:len line-1];
+ (n, f):= sys->tokenize(line, " \t");
+ if(n < 0) {
+ sys->print(INIT+":%d: tokenize: %r\n", l);
+ return;
+ }
+ if(n < 2) {
+ sys->print(INIT+":%d: not enough fields\n", l);
+ continue;
+ }
+ e = run(dc, f);
+ if(e != nil)
+ sys->print(INIT+":%d: %s\n", l, e);
+ }
+}
+
+run(dc: ref Draw->Context, argv: list of string): string
+{
+ c:= hd argv;
+ argv = tl argv;
+ prog:= hd argv;
+ ext:= ".dis";
+ if(prog[len prog-4:] == ".dis")
+ ext = "";
+ sh:= load Sh prog+ext;
+ if(sh == nil)
+ sh = load Sh "/dis/"+prog+ext;
+ if(sh == nil)
+ return sys->sprint("%s: load: %r", prog);
+
+ case c {
+ "run" =>
+ e:= ref Sys->Exception;
+ if(sys->rescue("fail:*", e))
+ return prog+": "+e.name;
+ sh->init(dc, argv);
+ return nil;
+ "spawn" =>
+ spawn sh->init(dc, argv);
+ return nil;
+ }
+ return c+": unknown command";
+}
+
+getline(fd: ref Sys->FD): (string, string)
+{
+ s:= "";
+ buf:= array[1] of byte;
+ for(;;) {
+ n:= sys->read(fd, buf, 1);
+ if(n < 0)
+ return (sys->sprint("getline: read: %r\n"), nil);
+ if(n == 0)
+ return (nil, s);
+ s += string buf;
+ if(buf[0] == byte '\n')
+ return (nil, s);
+ }
+}
+
+setclock()
+{
+ (ok, dir) := sys->stat("/");
+ if (ok < 0) {
+ sys->print("init: stat /: %r");
+ return;
+ }
+
+ fd := sys->open("/dev/time", sys->OWRITE);
+ if (fd == nil) {
+ sys->print("init: open /dev/time: %r\n");
+ return;
+ }
+
+ # Time is kept as microsecs, atime is in secs
+ b := array of byte sys->sprint("%d000000", dir.atime);
+ if (sys->write(fd, b, len b) != len b)
+ sys->print("init: write /dev/time: %r");
+}
+
+#
+# Set system name from nvram
+#
+setsysname()
+{
+ fd := sys->open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ return;
+ fds := sys->open("/dev/sysname", sys->OWRITE);
+ if(fds == nil)
+ return;
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr <= 0)
+ return;
+ sys->write(fds, buf, nr);
+}
+
+bootp(cfd: ref sys->FD): string
+{
+ sys->print("bootp ...");
+
+ sys->fprint(cfd, "bootp");
+
+ fd := sys->open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ sys->print("init: open /net/bootp: %r");
+ exit;
+ }
+
+
+ buf := array[Bootpreadlen] of byte;
+ nr := sys->read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ sys->print("init: read /net/bootp: %r");
+ exit;
+ }
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ sys->print("init: server address not in bootp read");
+ exit;
+ }
+
+ srv := hd ls;
+
+ sys->print("(ip=%s)", srv);
+
+ return srv;
+}
diff --git a/os/init/reminit.b b/os/init/reminit.b
new file mode 100644
index 00000000..b87ff996
--- /dev/null
+++ b/os/init/reminit.b
@@ -0,0 +1,239 @@
+implement Init;
+#
+# init program for standalone remote pc kernel - for benchmarking
+#
+include "sys.m";
+sys: Sys;
+FD, Connection, sprint, Dir: import sys;
+print, fprint, open, bind, mount, dial, sleep, read, chdir: import sys;
+
+include "draw.m";
+draw: Draw;
+Context: import draw;
+
+include "keyring.m";
+kr: Keyring;
+
+include "security.m";
+auth: Auth;
+
+Init: module
+{
+ init: fn();
+};
+
+Shell: module
+{
+ init: fn(ctxt: ref Context, argv: list of string);
+};
+
+remotefs(server: string): int
+{
+ ok, n: int;
+ c: Connection;
+
+ (ok, c) = dial("tcp!" + server + "!6666", nil);
+ if(ok < 0)
+ return -1;
+
+ sys->print("Connected ...\n");
+ if(kr != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount ...\n");
+
+ c.cfd = nil;
+ n = mount(c.dfd, "/n/remote", sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ return -1;
+}
+
+Bootpreadlen: con 128;
+
+bootp(): string
+{
+#
+# BUG: if bootp fails, can't then use "add ether" correctly
+#
+ fd := open("/net/ipifc", sys->OWRITE);
+ if(fd == nil) {
+ print("init: open /net/ipifc: %r");
+ return nil;
+ }
+ fprint(fd, "bootp /net/ether0");
+
+ fd = open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ print("init: open /net/bootp: %r\n");
+ return nil;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := read(fd, buf, len buf);
+ fd = nil;
+ if(nr > 0) {
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip") {
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ srv : string;
+ if(ls == nil || ((srv = hd ls) == "0.0.0.0")) {
+ print("init: server address not in bootp read\n");
+ return nil;
+ }
+ return srv;
+ }
+ return nil;
+}
+
+init()
+{
+
+ sys = load Sys Sys->PATH;
+ stdin := sys->fildes(0);
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->print("**\n** Inferno\n** Vita Nuova\n**\n");
+
+ sys->print("Setup boot net services ...\n");
+
+ #
+ # Setup what we need to call a server and
+ # Authenticate
+ #
+ sys->print("Bind ethernet ...\n");
+ bind("#l", "/net", sys->MREPL);
+ sys->print("Bind IP ...\n");
+ bind("#I", "/net", sys->MAFTER);
+ sys->print("Bind console ...\n");
+ bind("#c", "/dev", sys->MAFTER);
+
+ setsysname();
+ if (1) {
+ print("bootp ...\n");
+ srv := bootp();
+ if (srv != nil)
+ if (remotefs(srv) < 0)
+ print("No remote filesystem\n");
+ else {
+ print("Remote filesystem mounted\n");
+ bind("/n/remote/dis", "/dis", sys->MBEFORE);
+ bind("/n/remote/dis/lib", "/dis/lib", sys->MBEFORE);
+ }
+ } else {
+ print("Standalone mode\n");
+ fd := open("/net/ipifc", sys->OWRITE);
+ if(fd == nil) {
+ print("init: open /net/ipifc: %r");
+ exit;
+ }
+ fprint(fd, "add ether /net/ether0 %s %s", "200.1.1.60", "255.255.255.0");
+ fd = nil;
+ }
+ #
+ # default namespace
+ #
+ sys->unmount(nil, "/dev");
+ bind("#c", "/dev", sys->MBEFORE); # console
+ bind("#l", "/net", sys->MBEFORE); # ethernet
+ bind("#I", "/net", sys->MBEFORE); # TCP/IP
+ bind("#p", "/prog", sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+
+ bind("#T", "/dev", sys->MBEFORE); # kprof device
+ bind("#x", "/dev", sys->MBEFORE); # bench device
+
+ print("clock...\n");
+ setclock();
+
+ print("Server...\n");
+ dc: ref Context;
+ cs := load Shell "/dis/ndb/cs.dis";
+ if(cs == nil)
+ print("Server not loaded\n");
+ else
+ cs->init(dc, "cs" :: nil);
+ server := load Shell "/dis/lib/srv.dis";
+ if(server == nil)
+ print("Server not loaded\n");
+ else {
+# server->init(dc, "srv" :: nil);
+ }
+
+ print("Console...\n");
+sys->chdir("/n/remote/usr/john/appl/bench");
+ shell := load Shell "/dis/sh.dis";
+ if(shell == nil) {
+ print("init: load /dis/sh.dis: %r");
+ exit;
+ }
+ shell->init(dc, nil);
+}
+
+setclock()
+{
+ (ok, dir) := sys->stat("/");
+ if (ok < 0) {
+ print("init: stat /: %r");
+ return;
+ }
+
+ fd := sys->open("/dev/time", sys->OWRITE);
+ if (fd == nil) {
+ print("init: open /dev/time: %r");
+ return;
+ }
+
+ # Time is kept as microsecs, atime is in secs
+ b := array of byte sprint("%d000000", dir.atime);
+ if (sys->write(fd, b, len b) != len b)
+ print("init: write /dev/time: %r");
+}
+
+#
+# Set system name from nvram
+#
+setsysname()
+{
+ fd := open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ return;
+ fds := open("/dev/sysname", sys->OWRITE);
+ if(fds == nil)
+ return;
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr <= 0)
+ return;
+ sys->write(fds, buf, nr);
+}
+
+readline(fd: ref Sys->FD): string
+{
+ l := array [128] of byte;
+ nb := sys->read(fd, l, len l);
+ if(nb <= 1)
+ return "";
+ return string l[0:nb-1];
+}
+
diff --git a/os/init/rpcginit.b b/os/init/rpcginit.b
new file mode 100644
index 00000000..ce142d84
--- /dev/null
+++ b/os/init/rpcginit.b
@@ -0,0 +1,610 @@
+#
+# RPCG RPX-Lite AW
+#
+
+implement Init;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+
+include "sh.m";
+
+Init: module
+{
+ init: fn();
+};
+
+Bootpreadlen: con 128;
+
+# standard flash partitions
+
+flashparts := array[] of {
+ # rpcg monitor at 0x300000 to end
+ "add params 0 0x20000",
+ "add boot 0x20000 0x40000",
+ "add kernel 0x40000 0xC0000",
+ "add fs 0xC0000 end",
+};
+
+ethername := "ether0";
+
+#
+# initialise flash translation
+# mount flash file system
+# add devices
+# start a shell or window manager
+#
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->bind("/", "/", Sys->MREPL);
+
+ localok := 0;
+ if(lfs() >= 0){
+ # let's just take a closer look
+ sys->bind("/n/local/nvfs", "/nvfs", Sys->MREPL|Sys->MCREATE);
+ (rc, nil) := sys->stat("/n/local/dis/sh.dis");
+ if(rc >= 0)
+ localok = 1;
+ else
+ err("local file system unusable");
+ }
+ netok := sys->bind("#l", "/net", Sys->MREPL) >= 0;
+ if(!netok){
+ netok = sys->bind("#l1", "/net", Sys->MREPL) >= 0;
+ if(netok)
+ ethername = "ether1";
+ }
+ if(netok)
+ configether();
+ dobind("#I", "/net", sys->MAFTER); # IP
+ dobind("#p", "/prog", sys->MREPL); # prog
+ sys->bind("#d", "/fd", Sys->MREPL);
+ dobind("#c", "/dev", sys->MREPL); # console
+ dobind("#t", "/dev", sys->MAFTER); # serial line
+ drawok := sys->bind("#i", "/dev", sys->MAFTER) >= 0; # draw
+ sys->bind("#m", "/dev", sys->MAFTER); # pointer
+ sys->bind("#e", "/env", sys->MREPL|sys->MCREATE); # environment
+ sys->bind("#A", "/dev", Sys->MAFTER); # optional audio
+ timefile: string;
+ rootsource: string;
+ cfd := sys->open("/dev/consctl", Sys->OWRITE);
+ if(cfd != nil)
+ sys->fprint(cfd, "rawon");
+ for(;;){
+ (rootsource, timefile) = askrootsource(localok, netok);
+ if(rootsource == nil)
+ break; # internal
+ (rc, nil) := sys->stat(rootsource+"/dis/sh.dis");
+ if(rc < 0)
+ err("%s has no shell");
+ else if(sys->bind(rootsource, "/", Sys->MAFTER) < 0)
+ sys->print("can't bind %s on /: %r\n", rootsource);
+ else{
+ sys->bind(rootsource+"/dis", "/dis", Sys->MBEFORE|Sys->MCREATE);
+ break;
+ }
+ }
+ cfd = nil;
+
+ setsysname("rpxlite"); # set system name
+
+ now := getclock(timefile, rootsource);
+ setclock("/dev/time", now);
+ if(timefile != "#r/rtc")
+ setclock("#r/rtc", now/big 1000000);
+
+ sys->chdir("/");
+ if(netok){
+ start("ndb/dns", nil);
+ start("ndb/cs", nil);
+ }
+ startup := "/nvfs/startup";
+ if(sys->open(startup, Sys->OREAD) != nil){
+ shell := load Command Sh->PATH;
+ if(shell != nil){
+ sys->print("Running %s\n", startup);
+ shell->init(nil, "sh" :: startup :: nil);
+ }
+ }
+ user := username("inferno");
+ (ok, nil) := sys->stat("/dis/wm/wm.dis");
+ if(drawok && ok >= 0)
+ (ok, nil) = sys->stat("/dis/wm/logon.dis");
+ if(drawok && ok >= 0 && userok(user)){
+ wm := load Command "/dis/wm/wm.dis";
+ if(wm != nil){
+ fd := sys->open("/nvfs/user", Sys->OWRITE);
+ if(fd != nil){
+ sys->fprint(fd, "%s", user);
+ fd = nil;
+ }
+ spawn wm->init(nil, list of {"wm/wm", "wm/logon", "-l", "-u", user});
+ exit;
+ }
+ sys->print("init: can't load wm/logon: %r");
+ }
+ sh := load Command Sh->PATH;
+ if(sh == nil){
+ err(sys->sprint("can't load %s: %r", Sh->PATH));
+ hang();
+ }
+ spawn sh->init(nil, "sh" :: nil);
+}
+
+start(cmd: string, args: list of string)
+{
+ disfile := cmd;
+ if(disfile[0] != '/')
+ disfile = "/dis/"+disfile+".dis";
+ (ok, nil) := sys->stat(disfile);
+ if(ok >= 0){
+ dis := load Command disfile;
+ if(dis == nil)
+ sys->print("init: can't load %s: %r\n", disfile);
+ else
+ spawn dis->init(nil, cmd :: args);
+ }
+}
+
+dobind(f, t: string, flags: int)
+{
+ if(sys->bind(f, t, flags) < 0)
+ err(sys->sprint("can't bind %s on %s: %r", f, t));
+}
+
+#
+# Set system name from nvram if possible
+#
+setsysname(def: string)
+{
+ v := array of byte def;
+ fd := sys->open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ fd = sys->open("/env/sysname", sys->OREAD);
+ if(fd != nil){
+ buf := array[Sys->NAMEMAX] of byte;
+ nr := sys->read(fd, buf, len buf);
+ while(nr > 0 && buf[nr-1] == byte '\n')
+ nr--;
+ if(nr > 0)
+ v = buf[0:nr];
+ }
+ fd = sys->open("/dev/sysname", sys->OWRITE);
+ if(fd != nil)
+ sys->write(fd, v, len v);
+}
+
+getclock(timefile: string, timedir: string): big
+{
+ now := big 0;
+ if(timefile != nil){
+ fd := sys->open(timefile, Sys->OREAD);
+ if(fd != nil){
+ b := array[64] of byte;
+ n := sys->read(fd, b, len b-1);
+ if(n > 0){
+ now = big string b[0:n];
+ if(now <= big 16r20000000)
+ now = big 0; # remote itself is not initialised
+ }
+ }
+ }
+ if(now == big 0){
+ if(timedir != nil){
+ (ok, dir) := sys->stat(timedir);
+ if(ok < 0) {
+ sys->print("init: stat %s: %r", timedir);
+ return big 0;
+ }
+ now = big dir.atime;
+ }else{
+ now = big 993826747000000;
+ sys->print("time warped\n");
+ }
+ }
+ return now;
+}
+
+setclock(timefile: string, now: big)
+{
+ fd := sys->open(timefile, sys->OWRITE);
+ if (fd == nil) {
+ sys->print("init: can't open %s: %r", timefile);
+ return;
+ }
+
+ b := sys->aprint("%ubd", now);
+ if (sys->write(fd, b, len b) != len b)
+ sys->print("init: can't write to %s: %r", timefile);
+}
+
+srv()
+{
+ sys->print("remote debug srv...");
+ fd := sys->open("/dev/eia0ctl", Sys->OWRITE);
+ if(fd != nil)
+ sys->fprint(fd, "b115200");
+
+ fd = sys->open("/dev/eia0", Sys->ORDWR);
+ if (fd == nil){
+ err(sys->sprint("can't open /dev/eia0: %r"));
+ return;
+ }
+ if (sys->export(fd, "/", Sys->EXPASYNC) < 0){
+ err(sys->sprint("can't export on serial port: %r"));
+ return;
+ }
+}
+
+err(s: string)
+{
+ sys->fprint(sys->fildes(2), "init: %s\n", s);
+}
+
+hang()
+{
+ <-chan of int;
+}
+
+tried := 0;
+
+askrootsource(localok: int, netok: int): (string, string)
+{
+ stdin := sys->fildes(0);
+ sources := "kernel" :: nil;
+ if(netok)
+ sources = "remote" :: sources;
+ if(localok){
+ sources = "local" :: sources;
+ if(netok)
+ sources = "local+remote" :: sources;
+ }
+ for(;;) {
+ s := "";
+ if (tried == 0 && (s = rf("/nvfs/rootsource", nil)) != nil) {
+ tried = 1;
+ if (s[len s - 1] == '\n')
+ s = s[:len s - 1];
+ sys->print("/nvfs/rootsource: root from %s\n", s);
+ } else {
+ sys->print("root from (");
+ cm := "";
+ for(l := sources; l != nil; l = tl l){
+ sys->print("%s%s", cm, hd l);
+ cm = ",";
+ }
+ sys->print(")[%s] ", hd sources);
+
+ s = getline(stdin, hd sources); # default
+ }
+ (nil, choice) := sys->tokenize(s, "\t ");
+ if(choice == nil)
+ choice = sources;
+ opt := hd choice;
+ case opt {
+ * =>
+ sys->print("\ninvalid boot option: '%s'\n", opt);
+ "kernel" =>
+ return (nil, "#r/rtc");
+ "local" =>
+ return ("/n/local", "#r/rtc");
+ "local+remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/local", "/n/remote/dev/time");
+ "remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/remote", "/n/remote/dev/time");
+ }
+ }
+}
+
+getline(fd: ref Sys->FD, default: string): string
+{
+ result := "";
+ buf := array[10] of byte;
+ i := 0;
+ for(;;) {
+ n := sys->read(fd, buf[i:], len buf - i);
+ if(n < 1)
+ break;
+ i += n;
+ while(i >0 && (nutf := sys->utfbytes(buf, i)) > 0){
+ s := string buf[0:nutf];
+ for (j := 0; j < len s; j++)
+ case s[j] {
+ '\b' =>
+ if(result != nil)
+ result = result[0:len result-1];
+ 'u'&16r1F =>
+ sys->print("^U\n");
+ result = "";
+ '\r' =>
+ ;
+ * =>
+ sys->print("%c", s[j]);
+ if(s[j] == '\n' || s[j] >= 16r80){
+ if(s[j] != '\n')
+ result[len result] = s[j];
+ if(result == nil)
+ return default;
+ return result;
+ }
+ result[len result] = s[j];
+ }
+ buf[0:] = buf[nutf:i];
+ i -= nutf;
+ }
+ }
+ return default;
+}
+
+#
+# serve local DOS file system using flash translation layer
+#
+lfs(): int
+{
+ if(!flashpart("#F/flash/flashctl", flashparts))
+ return -1;
+ if(!ftlinit("#F/flash/fs"))
+ return -1;
+ c := chan of string;
+ spawn startfs(c, "/dis/dossrv.dis", "dossrv" :: "-f" :: "#X/ftldata" :: "-m" :: "/n/local" :: nil);
+ if(<-c != nil)
+ return -1;
+ return 0;
+}
+
+startfs(c: chan of string, file: string, args: list of string)
+{
+ fs := load Command file;
+ if(fs == nil){
+ sys->print("can't load %s: %r\n", file);
+ c <-= "load failed";
+ }
+ {
+ fs->init(nil, args);
+ }exception e {
+ "*" =>
+ c <-= "failed";
+ exit;
+ * =>
+ c <-= "unknown exception";
+ exit;
+ }
+ c <-= nil;
+}
+
+#
+# partition flash
+#
+flashdone := 0;
+
+flashpart(ctl: string, parts: array of string): int
+{
+ if(flashdone)
+ return 1;
+ cfd := sys->open(ctl, Sys->ORDWR);
+ if(cfd == nil){
+ sys->print("can't open %s: %r\n", ctl);
+ return 0;
+ }
+ for(i := 0; i < len parts; i++)
+ if(sys->fprint(cfd, "%s", parts[i]) < 0){
+ sys->print("can't %q to %s: %r\n", parts[i], ctl);
+ return 0;
+ }
+ flashdone = 1;
+ return 1;
+}
+
+#
+# set up flash translation layer
+#
+ftldone := 0;
+
+ftlinit(flashmem: string): int
+{
+ if(ftldone)
+ return 1;
+ sys->print("Set flash translation of %s...\n", flashmem);
+ fd := sys->open("#X/ftlctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("can't open #X/ftlctl: %r\n");
+ return 0;
+ }
+ if(sys->fprint(fd, "init %s", flashmem) <= 0){
+ sys->print("can't init flash translation: %r\n");
+ return 0;
+ }
+ ftldone = 1;
+ return 1;
+}
+
+configether()
+{
+ if(ethername == nil)
+ return;
+ fd := sys->open("/nvfs/etherparams", Sys->OREAD);
+ if(fd == nil)
+ return;
+ ctl := sys->open("/net/"+ethername+"/clone", Sys->OWRITE);
+ if(ctl == nil){
+ sys->print("init: can't open %s's clone: %r\n", ethername);
+ return;
+ }
+ b := array[1024] of byte;
+ n := sys->read(fd, b, len b);
+ if(n <= 0)
+ return;
+ for(i := 0; i < n;){
+ for(e := i; e < n && b[e] != byte '\n'; e++)
+ ;
+ s := string b[i:e];
+ if(sys->fprint(ctl, "%s", s) < 0)
+ sys->print("init: ctl write to %s: %s: %r\n", ethername, s);
+ i = e+1;
+ }
+}
+
+donebind := 0;
+
+#
+# set up network mount
+#
+netfs(mountpt: string): int
+{
+ sys->print("bootp ...");
+
+ fd: ref Sys->FD;
+ if(!donebind){
+ fd = sys->open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil) {
+ sys->print("init: open /net/ipifc/clone: %r\n");
+ return -1;
+ }
+ if(sys->fprint(fd, "bind ether %s", ethername) < 0) {
+ sys->print("could not bind ether0 interface: %r\n");
+ return -1;
+ }
+ donebind = 1;
+ }else{
+ fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n");
+ return -1;
+ }
+ }
+ if ((ip := rf("/nvfs/ip", nil)) != nil) {
+ sys->print("**using %s\n", ip);
+ sys->fprint(fd, "bind ether /net/ether0");
+ sys->fprint(fd, "add %s ", ip);
+ } else {
+ {
+ if(sys->fprint(fd, "bootp") < 0)
+ sys->print("could not bootp: %r\n");
+ } exception e {
+ "*" =>
+ sys->print("could not bootp: %s\n", e);
+ }
+ }
+ server := rf("/nvfs/fsip", nil);
+ if (server != nil) {
+ if (server[len server - 1] == '\n')
+ server = server[:len server - 1];
+ sys->print("/nvfs/fsip: server=%s\n", server);
+ } else
+ server = bootp();
+ if(server == nil || server == "0.0.0.0")
+ return -1;
+
+ net := "tcp"; # how to specify il?
+ svcname := net + "!" + server + "!6666";
+
+ sys->print("dial %s...", svcname);
+
+ (ok, c) := sys->dial(svcname, nil);
+ if(ok < 0){
+ sys->print("can't dial %s: %r\n", svcname);
+ return -1;
+ }
+
+ sys->print("\nConnected ...\n");
+ if(kr != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount %s...", mountpt);
+
+ c.cfd = nil;
+ n := sys->mount(c.dfd, nil, mountpt, sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ if(n < 0)
+ sys->print("%r");
+ return -1;
+}
+
+bootp(): string
+{
+ fd := sys->open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ sys->print("init: can't open /net/bootp: %r");
+ return nil;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := sys->read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ sys->print("init: read /net/bootp: %r");
+ return nil;
+ }
+
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ sys->print("init: server address not in bootp read");
+ return nil;
+ }
+
+ srv := hd ls;
+
+ sys->print("%s\n", srv);
+
+ return srv;
+}
+
+username(def: string): string
+{
+ return rf("/nvfs/user", def);
+}
+
+userok(user: string): int
+{
+ (ok, d) := sys->stat("/usr/"+user);
+ return ok >= 0 && (d.mode & Sys->DMDIR) != 0;
+}
+
+rf(file: string, default: string): string
+{
+ fd := sys->open(file, Sys->OREAD);
+ if(fd != nil){
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr > 0)
+ return string buf[0:nr];
+ }
+ return default;
+}
diff --git a/os/init/shell.b b/os/init/shell.b
new file mode 100644
index 00000000..e0b19ec9
--- /dev/null
+++ b/os/init/shell.b
@@ -0,0 +1,97 @@
+implement InitShell;
+
+include "sys.m";
+include "draw.m";
+
+sys: Sys;
+
+InitShell: module
+{
+ init: fn(nil: ref Draw->Context, nil: list of string);
+};
+
+Sh: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+init(nil: ref Draw->Context, nil: list of string)
+{
+ shell := load Sh "/dis/sh.dis";
+
+ sys = load Sys Sys->PATH;
+
+ if(sys != nil)
+ sys->print("init: starting shell\n");
+
+# sys->bind("#I", "/net", sys->MAFTER); # IP
+ sys->bind("#p", "/prog", sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+ sys->bind("#i", "/dev", sys->MREPL); # draw device
+ sys->bind("#t", "/dev", sys->MAFTER); # serial line
+ sys->bind("#c", "/dev", sys->MAFTER); # console device
+ sys->bind("#W","/dev",sys->MAFTER); # Flash
+# sys->bind("#O", "/dev", sys->MAFTER); # Modem
+# sys->bind("#T","/dev",sys->MAFTER); # Touchscreen
+
+ srv();
+
+ spawn shell->init(nil, nil);
+}
+
+srv()
+{
+ remotedebug := sysenv("remotedebug");
+ if(remotedebug != "1")
+ return;
+
+ sys->print("srv...");
+ if(echoto("#t/eia0ctl", "b38400") < 0)
+ return;
+
+ fd := sys->open("/dev/eia0", Sys->ORDWR);
+ if (fd == nil) {
+ sys->print("eia data open: %r\n");
+ return;
+ }
+ if (sys->export(fd, "/", Sys->EXPASYNC) < 0) {
+ sys->print("export: %r\n");
+ return;
+ }
+ sys->print("ok\n");
+}
+
+sysenv(param: string): string
+{
+ fd := sys->open("#c/sysenv", sys->OREAD);
+ if (fd == nil)
+ return(nil);
+ buf := array[4096] of byte;
+ nb := sys->read(fd, buf, len buf);
+ (nfl,fl) := sys->tokenize(string buf, "\n");
+ while (fl != nil) {
+ pair := hd fl;
+ (npl, pl) := sys->tokenize(pair, "=");
+ if (npl > 1) {
+ if ((hd pl) == param)
+ return hd tl pl;
+ }
+ fl = tl fl;
+ }
+ return nil ;
+}
+
+echoto(fname, str: string): int
+{
+ fd := sys->open(fname, Sys->OWRITE);
+ if(fd == nil) {
+ sys->print("%s: %r\n", fname);
+ return -1;
+ }
+ x := array of byte str;
+ if(sys->write(fd, x, len x) == -1) {
+ sys->print("write: %r\n");
+ return -1;
+ }
+ return 0;
+}
diff --git a/os/init/soeinit.b b/os/init/soeinit.b
new file mode 100644
index 00000000..cae7f5bd
--- /dev/null
+++ b/os/init/soeinit.b
@@ -0,0 +1,613 @@
+#
+# Soekris 4501
+#
+
+implement Init;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "keyring.m";
+ kr: Keyring;
+
+include "security.m";
+ auth: Auth;
+
+include "sh.m";
+
+Init: module
+{
+ init: fn();
+};
+
+Bootpreadlen: con 128;
+
+# standard flash partitions
+
+#flashparts := array[] of {
+# # bootstrap at 0x0 to 0x20000
+# "add script 0x20000 0x40000",
+# "add kernel 0x100000 0x200000",
+# "add fs 0x200000 end",
+#};
+flashparts: array of string;
+
+ethername := "ether0";
+
+#
+# initialise flash translation
+# mount flash file system
+# add devices
+# start a shell or window manager
+#
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->bind("/", "/", Sys->MREPL);
+
+ localok := 0;
+ if(lfs() >= 0){
+ # let's just take a closer look
+ sys->bind("/n/local/nvfs", "/nvfs", Sys->MREPL|Sys->MCREATE);
+ (rc, nil) := sys->stat("/n/local/dis/sh.dis");
+ if(rc >= 0)
+ localok = 1;
+ else
+ err("local file system unusable");
+ }
+ netok := sys->bind("#l", "/net", Sys->MREPL) >= 0;
+ if(!netok){
+ netok = sys->bind("#l1", "/net", Sys->MREPL) >= 0;
+ if(netok)
+ ethername = "ether1";
+ }
+ if(netok)
+ configether();
+ dobind("#I", "/net", sys->MAFTER); # IP
+ dobind("#p", "/prog", sys->MREPL); # prog
+ sys->bind("#d", "/fd", Sys->MREPL);
+ dobind("#c", "/dev", sys->MREPL); # console
+ dobind("#t", "/dev", sys->MAFTER); # serial line
+ drawok := sys->bind("#i", "/dev", sys->MAFTER) >= 0; # draw
+ sys->bind("#m", "/dev", sys->MAFTER); # pointer
+ sys->bind("#e", "/env", sys->MREPL|sys->MCREATE); # environment
+ sys->bind("#A", "/dev", Sys->MAFTER); # optional audio
+ timefile: string;
+ rootsource: string;
+ scale := 1;
+ cfd := sys->open("/dev/consctl", Sys->OWRITE);
+ if(cfd != nil)
+ sys->fprint(cfd, "rawon");
+ for(;;){
+ (rootsource, timefile, scale) = askrootsource(localok, netok);
+ if(rootsource == nil)
+ break; # internal
+ (rc, nil) := sys->stat(rootsource+"/dis/sh.dis");
+ if(rc < 0)
+ err("%s has no shell");
+ else if(sys->bind(rootsource, "/", Sys->MAFTER) < 0)
+ sys->print("can't bind %s on /: %r\n", rootsource);
+ else{
+ sys->bind(rootsource+"/dis", "/dis", Sys->MBEFORE|Sys->MCREATE);
+ break;
+ }
+ }
+ cfd = nil;
+
+ setsysname("soe"); # set system name
+
+ now := getclock(timefile, rootsource);
+ if(scale == 1)
+ now *= big 1000000;
+ setclock("/dev/time", now);
+ if(timefile != "#r/rtc")
+ setclock("#r/rtc", now/big 1000000);
+
+ sys->chdir("/");
+ if(netok){
+ start("ndb/dns", nil);
+ start("ndb/cs", nil);
+ }
+ startup := "/nvfs/startup";
+ if(sys->open(startup, Sys->OREAD) != nil){
+ shell := load Command Sh->PATH;
+ if(shell != nil){
+ sys->print("Running %s\n", startup);
+ shell->init(nil, "sh" :: startup :: nil);
+ }
+ }
+ user := username("inferno");
+ (ok, nil) := sys->stat("/dis/wm/wm.dis");
+ if(drawok && ok >= 0)
+ (ok, nil) = sys->stat("/dis/wm/logon.dis");
+ if(drawok && ok >= 0 && userok(user)){
+ wm := load Command "/dis/wm/wm.dis";
+ if(wm != nil){
+ fd := sys->open("/nvfs/user", Sys->OWRITE);
+ if(fd != nil){
+ sys->fprint(fd, "%s", user);
+ fd = nil;
+ }
+ spawn wm->init(nil, list of {"wm/wm", "wm/logon", "-l", "-u", user});
+ exit;
+ }
+ sys->print("init: can't load wm/logon: %r");
+ }
+ sh := load Command Sh->PATH;
+ if(sh == nil){
+ err(sys->sprint("can't load %s: %r", Sh->PATH));
+ hang();
+ }
+ spawn sh->init(nil, "sh" :: nil);
+}
+
+start(cmd: string, args: list of string)
+{
+ disfile := cmd;
+ if(disfile[0] != '/')
+ disfile = "/dis/"+disfile+".dis";
+ (ok, nil) := sys->stat(disfile);
+ if(ok >= 0){
+ dis := load Command disfile;
+ if(dis == nil)
+ sys->print("init: can't load %s: %r\n", disfile);
+ else
+ spawn dis->init(nil, cmd :: args);
+ }
+}
+
+dobind(f, t: string, flags: int)
+{
+ if(sys->bind(f, t, flags) < 0)
+ err(sys->sprint("can't bind %s on %s: %r", f, t));
+}
+
+#
+# Set system name from nvram if possible
+#
+setsysname(def: string)
+{
+ v := array of byte def;
+ fd := sys->open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ fd = sys->open("/env/sysname", sys->OREAD);
+ if(fd != nil){
+ buf := array[Sys->NAMEMAX] of byte;
+ nr := sys->read(fd, buf, len buf);
+ while(nr > 0 && buf[nr-1] == byte '\n')
+ nr--;
+ if(nr > 0)
+ v = buf[0:nr];
+ }
+ fd = sys->open("/dev/sysname", sys->OWRITE);
+ if(fd != nil)
+ sys->write(fd, v, len v);
+}
+
+getclock(timefile: string, timedir: string): big
+{
+ now := big 0;
+ if(timefile != nil){
+ fd := sys->open(timefile, Sys->OREAD);
+ if(fd != nil){
+ b := array[64] of byte;
+ n := sys->read(fd, b, len b-1);
+ if(n > 0){
+ now = big string b[0:n];
+ if(now <= big 16r20000000)
+ now = big 0; # remote itself is not initialised
+ }
+ }
+ }
+ if(now == big 0){
+ if(timedir != nil){
+ (ok, dir) := sys->stat(timedir);
+ if(ok < 0) {
+ sys->print("init: stat %s: %r", timedir);
+ return big 0;
+ }
+ now = big dir.atime;
+ }else{
+ now = big 993826747000000;
+ sys->print("time warped\n");
+ }
+ }
+ return now;
+}
+
+setclock(timefile: string, now: big)
+{
+ fd := sys->open(timefile, sys->OWRITE);
+ if (fd == nil) {
+ sys->print("init: can't open %s: %r", timefile);
+ return;
+ }
+
+ b := sys->aprint("%ubd", now);
+ if (sys->write(fd, b, len b) != len b)
+ sys->print("init: can't write to %s: %r", timefile);
+}
+
+srv()
+{
+ sys->print("remote debug srv...");
+ fd := sys->open("/dev/eia0ctl", Sys->OWRITE);
+ if(fd != nil)
+ sys->fprint(fd, "b115200");
+
+ fd = sys->open("/dev/eia0", Sys->ORDWR);
+ if (fd == nil){
+ err(sys->sprint("can't open /dev/eia0: %r"));
+ return;
+ }
+ if (sys->export(fd, "/", Sys->EXPASYNC) < 0){
+ err(sys->sprint("can't export on serial port: %r"));
+ return;
+ }
+}
+
+err(s: string)
+{
+ sys->fprint(sys->fildes(2), "init: %s\n", s);
+}
+
+hang()
+{
+ <-chan of int;
+}
+
+tried := 0;
+
+askrootsource(localok: int, netok: int): (string, string, int)
+{
+ stdin := sys->fildes(0);
+ sources := "kernel" :: nil;
+ if(netok)
+ sources = "remote" :: sources;
+ if(localok){
+ sources = "local" :: sources;
+ if(netok)
+ sources = "local+remote" :: sources;
+ }
+ for(;;) {
+ s := "";
+ if (tried == 0 && (s = rf("/nvfs/rootsource", nil)) != nil) {
+ tried = 1;
+ if (s[len s - 1] == '\n')
+ s = s[:len s - 1];
+ sys->print("/nvfs/rootsource: root from %s\n", s);
+ } else {
+ sys->print("root from (");
+ cm := "";
+ for(l := sources; l != nil; l = tl l){
+ sys->print("%s%s", cm, hd l);
+ cm = ",";
+ }
+ sys->print(")[%s] ", hd sources);
+
+ s = getline(stdin, hd sources); # default
+ }
+ (nil, choice) := sys->tokenize(s, "\t ");
+ if(choice == nil)
+ choice = sources;
+ opt := hd choice;
+ case opt {
+ * =>
+ sys->print("\ninvalid boot option: '%s'\n", opt);
+ "kernel" =>
+ return (nil, "#r/rtc", 1);
+ "local" =>
+ return ("/n/local", "#r/rtc", 1);
+ "local+remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/local", "/n/remote/dev/time", 1000000);
+ "remote" =>
+ if(netfs("/n/remote") >= 0)
+ return ("/n/remote", "/n/remote/dev/time", 1000000);
+ }
+ }
+}
+
+getline(fd: ref Sys->FD, default: string): string
+{
+ result := "";
+ buf := array[10] of byte;
+ i := 0;
+ for(;;) {
+ n := sys->read(fd, buf[i:], len buf - i);
+ if(n < 1)
+ break;
+ i += n;
+ while(i >0 && (nutf := sys->utfbytes(buf, i)) > 0){
+ s := string buf[0:nutf];
+ for (j := 0; j < len s; j++)
+ case s[j] {
+ '\b' =>
+ if(result != nil)
+ result = result[0:len result-1];
+ 'u'&16r1F =>
+ sys->print("^U\n");
+ result = "";
+ '\r' =>
+ ;
+ * =>
+ sys->print("%c", s[j]);
+ if(s[j] == '\n' || s[j] >= 16r80){
+ if(s[j] != '\n')
+ result[len result] = s[j];
+ if(result == nil)
+ return default;
+ return result;
+ }
+ result[len result] = s[j];
+ }
+ buf[0:] = buf[nutf:i];
+ i -= nutf;
+ }
+ }
+ return default;
+}
+
+#
+# serve local DOS file system using flash translation layer
+#
+lfs(): int
+{
+ if(!flashpart("#F/flash/flashctl", flashparts))
+ return -1;
+ if(!ftlinit("#F/flash/fs"))
+ return -1;
+ c := chan of string;
+ spawn startfs(c, "/dis/dossrv.dis", "dossrv" :: "-f" :: "#X/ftldata" :: "-m" :: "/n/local" :: nil);
+ if(<-c != nil)
+ return -1;
+ return 0;
+}
+
+startfs(c: chan of string, file: string, args: list of string)
+{
+ fs := load Command file;
+ if(fs == nil){
+ sys->print("can't load %s: %r\n", file);
+ c <-= "load failed";
+ }
+ {
+ fs->init(nil, args);
+ }exception e {
+ "*" =>
+ c <-= "failed";
+ exit;
+ * =>
+ c <-= "unknown exception";
+ exit;
+ }
+ c <-= nil;
+}
+
+#
+# partition flash
+#
+flashdone := 0;
+
+flashpart(ctl: string, parts: array of string): int
+{
+ if(flashdone)
+ return 1;
+ cfd := sys->open(ctl, Sys->ORDWR);
+ if(cfd == nil){
+ sys->print("can't open %s: %r\n", ctl);
+ return 0;
+ }
+ for(i := 0; i < len parts; i++)
+ if(sys->fprint(cfd, "%s", parts[i]) < 0){
+ sys->print("can't %q to %s: %r\n", parts[i], ctl);
+ return 0;
+ }
+ flashdone = 1;
+ return 1;
+}
+
+#
+# set up flash translation layer
+#
+ftldone := 0;
+
+ftlinit(flashmem: string): int
+{
+ if(ftldone)
+ return 1;
+ sys->print("Set flash translation of %s...\n", flashmem);
+ fd := sys->open("#X/ftlctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("can't open #X/ftlctl: %r\n");
+ return 0;
+ }
+ if(sys->fprint(fd, "init %s", flashmem) <= 0){
+ sys->print("can't init flash translation: %r\n");
+ return 0;
+ }
+ ftldone = 1;
+ return 1;
+}
+
+configether()
+{
+ if(ethername == nil)
+ return;
+ fd := sys->open("/nvfs/etherparams", Sys->OREAD);
+ if(fd == nil)
+ return;
+ ctl := sys->open("/net/"+ethername+"/clone", Sys->OWRITE);
+ if(ctl == nil){
+ sys->print("init: can't open %s's clone: %r\n", ethername);
+ return;
+ }
+ b := array[1024] of byte;
+ n := sys->read(fd, b, len b);
+ if(n <= 0)
+ return;
+ for(i := 0; i < n;){
+ for(e := i; e < n && b[e] != byte '\n'; e++)
+ ;
+ s := string b[i:e];
+ if(sys->fprint(ctl, "%s", s) < 0)
+ sys->print("init: ctl write to %s: %s: %r\n", ethername, s);
+ i = e+1;
+ }
+}
+
+donebind := 0;
+
+#
+# set up network mount
+#
+netfs(mountpt: string): int
+{
+ sys->print("bootp ...");
+
+ fd: ref Sys->FD;
+ if(!donebind){
+ fd = sys->open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil) {
+ sys->print("init: open /net/ipifc/clone: %r\n");
+ return -1;
+ }
+ if(sys->fprint(fd, "bind ether %s", ethername) < 0) {
+ sys->print("could not bind ether0 interface: %r\n");
+ return -1;
+ }
+ donebind = 1;
+ }else{
+ fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE);
+ if(fd == nil){
+ sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n");
+ return -1;
+ }
+ }
+ if ((ip := rf("/nvfs/ip", nil)) != nil) {
+ sys->print("**using %s\n", ip);
+ sys->fprint(fd, "bind ether /net/ether0");
+ sys->fprint(fd, "add %s ", ip);
+ } else {
+ {
+ if(sys->fprint(fd, "bootp") < 0)
+ sys->print("could not bootp: %r\n");
+ } exception e {
+ "*" =>
+ sys->print("could not bootp: %s\n", e);
+ }
+ }
+ server := rf("/nvfs/fsip", nil);
+ if (server != nil) {
+ if (server[len server - 1] == '\n')
+ server = server[:len server - 1];
+ sys->print("/nvfs/fsip: server=%s\n", server);
+ } else
+ server = bootp();
+ if(server == nil || server == "0.0.0.0")
+ return -1;
+
+ net := "tcp"; # how to specify il?
+ svcname := net + "!" + server + "!6666";
+
+ sys->print("dial %s...", svcname);
+
+ (ok, c) := sys->dial(svcname, nil);
+ if(ok < 0){
+ sys->print("can't dial %s: %r\n", svcname);
+ return -1;
+ }
+
+ sys->print("\nConnected ...\n");
+ if(kr != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount %s...", mountpt);
+
+ c.cfd = nil;
+ n := sys->mount(c.dfd, nil, mountpt, sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ if(n < 0)
+ sys->print("%r");
+ return -1;
+}
+
+bootp(): string
+{
+ fd := sys->open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ sys->print("init: can't open /net/bootp: %r");
+ return nil;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := sys->read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ sys->print("init: read /net/bootp: %r");
+ return nil;
+ }
+
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ sys->print("init: server address not in bootp read");
+ return nil;
+ }
+
+ srv := hd ls;
+
+ sys->print("%s\n", srv);
+
+ return srv;
+}
+
+username(def: string): string
+{
+ return rf("/nvfs/user", def);
+}
+
+userok(user: string): int
+{
+ (ok, d) := sys->stat("/usr/"+user);
+ return ok >= 0 && (d.mode & Sys->DMDIR) != 0;
+}
+
+rf(file: string, default: string): string
+{
+ fd := sys->open(file, Sys->OREAD);
+ if(fd != nil){
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr > 0)
+ return string buf[0:nr];
+ }
+ return default;
+}
diff --git a/os/init/srvinit.b b/os/init/srvinit.b
new file mode 100644
index 00000000..2c1c1b69
--- /dev/null
+++ b/os/init/srvinit.b
@@ -0,0 +1,209 @@
+implement Init;
+#
+# init program for standalone wm using TK
+#
+include "sys.m";
+sys: Sys;
+ FD, Connection, sprint, Dir: import sys;
+ print, fprint, open, bind, mount, dial, sleep, read: import sys;
+
+include "security.m";
+ auth: Auth;
+
+include "draw.m";
+ draw: Draw;
+ Context: import draw;
+
+include "keyring.m";
+ kr: Keyring;
+
+Init: module
+{
+ init: fn();
+};
+
+Command: module
+{
+ init: fn(ctxt: ref Context, argv: list of string);
+};
+
+rootfs(server: string): int
+{
+ ok, n: int;
+ c: Connection;
+
+ (ok, c) = dial("tcp!" + server + "!6666", nil);
+ if(ok < 0) {
+ sys->print("cannot connected to %s: %r\n", server);
+ return -1;
+ }
+
+ sys->print("Connected ...");
+ if(kr != nil && auth != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount ...");
+
+ c.cfd = nil;
+ n = mount(c.dfd, "/", sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ return -1;
+}
+
+Bootpreadlen: con 128;
+
+init()
+{
+ spec: string;
+
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->print("**\n** Inferno\n** Vita Nuova\n**\n");
+
+ sys->print("Setup boot net services ...\n");
+
+ #
+ # Setup what we need to call a server and
+ # Authenticate
+ #
+ bind("#l", "/net", sys->MREPL);
+ bind("#I", "/net", sys->MAFTER);
+ bind("#c", "/dev", sys->MAFTER);
+ bind("#H", "/dev", sys->MAFTER);
+ nvramfd := sys->open("#H/hd0nvram", sys->ORDWR);
+ if(nvramfd != nil){
+ spec = "#Fhd0nvram";
+ if(bind(spec, "/nvfs", sys->MAFTER) < 0)
+ print("init: bind %s: %r\n", spec);
+ }
+
+ setsysname();
+
+ sys->print("bootp...");
+
+ fd := open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil) {
+ print("init: open /net/ipifc/clone: %r\n");
+ exit;
+ }
+ cfg := array of byte "bind ether ether0";
+ if(sys->write(fd, cfg, len cfg) != len cfg) {
+ sys->print("could not bind interface: %r\n");
+ exit;
+ }
+ cfg = array of byte "bootp";
+ if(sys->write(fd, cfg, len cfg) != len cfg) {
+ sys->print("could not bootp: %r\n");
+ exit;
+ }
+
+ fd = open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ print("init: open /net/bootp: %r");
+ exit;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ print("init: read /net/bootp: %r");
+ exit;
+ }
+
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ print("init: server address not in bootp read");
+ exit;
+ }
+
+ srv := hd ls;
+ sys->print("server %s\nConnect ...\n", srv);
+
+ retrycount := 0;
+ while(rootfs(srv) < 0 && retrycount++ < 5)
+ sleep(1000);
+
+ sys->print("done\n");
+
+ #
+ # default namespace
+ #
+ bind("#c", "/dev", sys->MREPL); # console
+ bind("#l", "/net", sys->MREPL); # ethernet
+ bind("#I", "/net", sys->MBEFORE); # TCP/IP
+ bind("#p", "/prog", sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+
+ sys->print("clock...\n");
+ setclock();
+
+ sys->print("sh...\n");
+ sh := load Command "/dis/sh.dis";
+ if (sh == nil)
+ print("cannot load /dis/sh.dis: %r\n");
+
+ sh->init(nil, "sh" :: "-i" :: nil);
+}
+
+setclock()
+{
+ (ok, dir) := sys->stat("/");
+ if (ok < 0) {
+ print("init: stat /: %r");
+ return;
+ }
+
+ fd := sys->open("/dev/time", sys->OWRITE);
+ if (fd == nil) {
+ print("init: open /dev/time: %r");
+ return;
+ }
+
+ # Time is kept as microsecs, atime is in secs
+ b := array of byte sprint("%d000000", dir.atime);
+ if (sys->write(fd, b, len b) != len b)
+ print("init: write /dev/time: %r");
+}
+
+#
+# Set system name from nvram
+#
+setsysname()
+{
+ fd := open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ return;
+ fds := open("/dev/sysname", sys->OWRITE);
+ if(fds == nil)
+ return;
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr <= 0)
+ return;
+ sys->write(fds, buf, nr);
+}
diff --git a/os/init/wminit.b b/os/init/wminit.b
new file mode 100644
index 00000000..89312ec2
--- /dev/null
+++ b/os/init/wminit.b
@@ -0,0 +1,231 @@
+implement Init;
+#
+# init program for standalone wm using TK
+#
+include "sys.m";
+sys: Sys;
+ FD, Connection, sprint, Dir: import sys;
+ print, fprint, open, bind, mount, dial, sleep, read: import sys;
+
+include "security.m";
+ auth: Auth;
+
+include "draw.m";
+ draw: Draw;
+ Context: import draw;
+
+include "keyring.m";
+ kr: Keyring;
+
+Init: module
+{
+ init: fn();
+};
+
+Command: module
+{
+ init: fn(ctxt: ref Context, argv: list of string);
+};
+
+rootfs(server: string): int
+{
+ ok, n: int;
+ c: Connection;
+
+ (ok, c) = dial("tcp!" + server + "!6666", nil);
+ if(ok < 0)
+ return -1;
+
+ sys->print("Connected ...");
+ if(kr != nil && auth != nil){
+ err: string;
+ sys->print("Authenticate ...");
+ ai := kr->readauthinfo("/nvfs/default");
+ if(ai == nil){
+ sys->print("readauthinfo /nvfs/default failed: %r\n");
+ sys->print("trying mount as `nobody'\n");
+ }
+ (c.dfd, err) = auth->client("none", ai, c.dfd);
+ if(c.dfd == nil){
+ sys->print("authentication failed: %s\n", err);
+ return -1;
+ }
+ }
+
+ sys->print("mount ...");
+
+ c.cfd = nil;
+ n = mount(c.dfd, nil, "/", sys->MREPL, "");
+ if(n > 0)
+ return 0;
+ return -1;
+}
+
+Bootpreadlen: con 128;
+
+init()
+{
+ spec: string;
+
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ auth = load Auth Auth->PATH;
+ if(auth != nil)
+ auth->init();
+
+ sys->print("**\n** Inferno\n** Vita Nuova\n**\n");
+
+ sys->print("Setup boot net services ...\n");
+
+ #
+ # Setup what we need to call a server and
+ # Authenticate
+ #
+ bind("#l", "/net", sys->MREPL);
+ bind("#I", "/net", sys->MAFTER);
+ bind("#c", "/dev", sys->MAFTER);
+ bind("#H", "/dev", sys->MAFTER);
+ nvramfd := sys->open("#H/hd0nvram", sys->ORDWR);
+ if(nvramfd != nil){
+ spec = "#Fhd0nvram";
+ if(bind(spec, "/nvfs", sys->MAFTER) < 0)
+ print("init: bind %s: %r\n", spec);
+ }
+
+ setsysname();
+
+ sys->print("bootp...");
+
+ fd := open("/net/ipifc/clone", sys->OWRITE);
+ if(fd == nil) {
+ print("init: open /net/ipifc/clone: %r\n");
+ exit;
+ }
+ cfg := array of byte "bind ether ether0";
+ if(sys->write(fd, cfg, len cfg) != len cfg) {
+ sys->print("could not bind interface: %r\n");
+ exit;
+ }
+ cfg = array of byte "bootp";
+ if(sys->write(fd, cfg, len cfg) != len cfg) {
+ sys->print("could not bootp: %r\n");
+ exit;
+ }
+
+ fd = open("/net/bootp", sys->OREAD);
+ if(fd == nil) {
+ print("init: open /net/bootp: %r");
+ exit;
+ }
+
+ buf := array[Bootpreadlen] of byte;
+ nr := read(fd, buf, len buf);
+ fd = nil;
+ if(nr <= 0) {
+ print("init: read /net/bootp: %r");
+ exit;
+ }
+
+ (ntok, ls) := sys->tokenize(string buf, " \t\n");
+ while(ls != nil) {
+ if(hd ls == "fsip"){
+ ls = tl ls;
+ break;
+ }
+ ls = tl ls;
+ }
+ if(ls == nil) {
+ print("init: server address not in bootp read");
+ exit;
+ }
+
+ srv := hd ls;
+ sys->print("server %s\nConnect ...\n", srv);
+
+ retrycount := 0;
+ while(rootfs(srv) < 0 && retrycount++ < 5)
+ sleep(1000);
+
+ cfd := sys->open("/dev/cons", Sys->OWRITE);
+ if (cfd != nil) {
+ sys->dup(cfd.fd, 1);
+ sys->dup(cfd.fd, 2);
+ }
+ cfd = nil;
+
+ sys->print("done\n");
+
+ #
+ # default namespace
+ #
+ bind("#c", "/dev", sys->MREPL); # console
+ bind("#t", "/dev", sys->MAFTER); # serial port
+ bind("#H", "/dev", sys->MAFTER);
+ if(spec != nil)
+ bind(spec, "/nvfs", sys->MBEFORE|sys->MCREATE); # our keys
+ bind("#E", "/dev", sys->MBEFORE); # mpeg
+ bind("#l", "/net", sys->MBEFORE); # ethernet
+ bind("#I", "/net", sys->MBEFORE); # TCP/IP
+ bind("#V", "/dev", sys->MAFTER); # hauppauge TV
+ bind("#p", "/prog", sys->MREPL); # prog device
+ sys->bind("#d", "/fd", Sys->MREPL);
+ if(bind("#m", "/dev", sys->MAFTER) >= 0){ # mouse setup device
+ mouse := load Command "/dis/mouse.dis";
+ if (mouse != nil) {
+ print("Setting up mouse\n");
+ mouse->init(nil, "/dis/mouse.dis" :: nil);
+ mouse = nil;
+ }
+ }
+
+ sys->print("clock...\n");
+ setclock();
+
+ sys->print("logon...\n");
+
+ logon := load Command "/dis/wm/logon.dis";
+ if(logon == nil) {
+ print("init: load /dis/wm/logon.dis: %r");
+ logon = load Command "/dis/sh.dis";
+ }
+ dc: ref Context;
+ spawn logon->init(dc, nil);
+}
+
+setclock()
+{
+ (ok, dir) := sys->stat("/");
+ if (ok < 0) {
+ print("init: stat /: %r");
+ return;
+ }
+
+ fd := sys->open("/dev/time", sys->OWRITE);
+ if (fd == nil) {
+ print("init: open /dev/time: %r");
+ return;
+ }
+
+ # Time is kept as microsecs, atime is in secs
+ b := array of byte sprint("%d000000", dir.atime);
+ if (sys->write(fd, b, len b) != len b)
+ print("init: write /dev/time: %r");
+}
+
+#
+# Set system name from nvram
+#
+setsysname()
+{
+ fd := open("/nvfs/ID", sys->OREAD);
+ if(fd == nil)
+ return;
+ fds := open("/dev/sysname", sys->OWRITE);
+ if(fds == nil)
+ return;
+ buf := array[128] of byte;
+ nr := sys->read(fd, buf, len buf);
+ if(nr <= 0)
+ return;
+ sys->write(fds, buf, nr);
+}