diff options
Diffstat (limited to 'os/init/pcinit.b')
| -rw-r--r-- | os/init/pcinit.b | 405 |
1 files changed, 405 insertions, 0 deletions
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; +} |
