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