summaryrefslogtreecommitdiff
path: root/os/init/rpcginit.b
diff options
context:
space:
mode:
Diffstat (limited to 'os/init/rpcginit.b')
-rw-r--r--os/init/rpcginit.b610
1 files changed, 610 insertions, 0 deletions
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;
+}