implement Init; include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; include "keyring.m"; kr: Keyring; include "styx.m"; include "iotrack.m"; include "dossubs.m"; include "dosfs.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){ sys->print("authenticate ..."); ai := kr->readauthinfo("/nvfs/default"); (id_or_err, secret) := kr->auth(c.dfd, ai, 0); if(secret == nil) { sys->print("failed, %s, running as none\n", id_or_err); } else { # no line encryption algbuf := array of byte "none"; kr->sendmsg(c.dfd, algbuf, len algbuf); } } 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; sys->print("**\n** Inferno\n** Lucent Technologies\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"); nvplaces := array[] of { "#H/hd0nvram", "/nvram.data" }; nvramfd: ref sys->FD; for(i := 0; i < len nvplaces; i++) { nvramfd = sys->open(nvplaces[i], sys->ORDWR); if(nvramfd != nil) break; } if(nvramfd != nil) { spec = sys->sprint("#F%d", nvramfd.fd); if(sys->bind(spec, "/nvfs", sys->MAFTER) < 0) sys->print("init: bind %s: %r\n", spec); sys->print("mounted tinyfs"); } sys->print("\n\n"); if(!PROMPT) { if(lfs("#H/hd0disk") == 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; }