diff options
Diffstat (limited to 'os/init/i4e.b')
| -rw-r--r-- | os/init/i4e.b | 210 |
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; +} |
