diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/init | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/init')
| -rw-r--r-- | os/init/README | 5 | ||||
| -rw-r--r-- | os/init/bootinit.b | 628 | ||||
| -rw-r--r-- | os/init/cerf405.b | 598 | ||||
| -rw-r--r-- | os/init/cerfinit.b | 612 | ||||
| -rw-r--r-- | os/init/evalinit.b | 119 | ||||
| -rw-r--r-- | os/init/geninit.b | 93 | ||||
| -rw-r--r-- | os/init/i4e.b | 210 | ||||
| -rw-r--r-- | os/init/init.b | 613 | ||||
| -rw-r--r-- | os/init/ipaqinit.b | 697 | ||||
| -rw-r--r-- | os/init/ipeinit.b | 620 | ||||
| -rw-r--r-- | os/init/jsinit.b | 213 | ||||
| -rw-r--r-- | os/init/mkfile | 27 | ||||
| -rw-r--r-- | os/init/mpcinit.b | 383 | ||||
| -rw-r--r-- | os/init/pcdemo.b | 273 | ||||
| -rw-r--r-- | os/init/pcinit.b | 405 | ||||
| -rw-r--r-- | os/init/reminit.b | 239 | ||||
| -rw-r--r-- | os/init/rpcginit.b | 610 | ||||
| -rw-r--r-- | os/init/shell.b | 97 | ||||
| -rw-r--r-- | os/init/soeinit.b | 613 | ||||
| -rw-r--r-- | os/init/srvinit.b | 209 | ||||
| -rw-r--r-- | os/init/wminit.b | 231 |
21 files changed, 7495 insertions, 0 deletions
diff --git a/os/init/README b/os/init/README new file mode 100644 index 00000000..da86706f --- /dev/null +++ b/os/init/README @@ -0,0 +1,5 @@ +initialisation programs used by various native kernels to set up +the right environment to invoke a shell, a window system, mux, or +any specialised application. + +even so, there are really more than needed here just now. diff --git a/os/init/bootinit.b b/os/init/bootinit.b new file mode 100644 index 00000000..0fcd58ef --- /dev/null +++ b/os/init/bootinit.b @@ -0,0 +1,628 @@ +# +# Generalized boot Inferno +# + +implement Init; + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "keyring.m"; + kr: Keyring; + +include "security.m"; + auth: Auth; + random: Random; + +include "tftp.m"; + +Bootpreadlen: con 128; + +Init: module +{ + init: fn(); +}; + +ip: string; +mask: string; +fsip: string; +bootprotocol: string; +bootserver: string; +bootfile: string; + +debug: con 0; + +init() +{ + ipavailable: int; + sys = load Sys Sys->PATH; + + kexecfd := sys->open("#B/kexec", Sys->OWRITE); + if (kexecfd == nil) + fatal(sys->sprint("opening #B/kexec: %r")); + + ipavailable = 0; + if (dobind("#l", "/net", sys->MREPL) && dobind("#I", "/net", sys->MAFTER)) + ipavailable = 1; + + dobind("#c", "/dev", sys->MAFTER); # console device + + if (!ipavailable) + fatal("no IP stack available"); + cfd := sys->open("/net/ipifc/clone", sys->ORDWR); + if(cfd == nil) + fatal(sys->sprint("open /net/ipifc/clone: %r")); + + if (sys->fprint(cfd, "bind ether ether0") < 0) + fatal(sys->sprint("binding ether0: %r")); + + fsready := 0; + + fsip = ipconfig(cfd); + + bootstring := getenvdefault("bootpath", "tftp"); + + (bootprotocol, bootserver, bootfile) = parsebootstring(bootstring); + + if (bootprotocol == nil) + fatal(bootstring + ": unrecognised syntax"); + + # Run dhcp if necessary + if (bootprotocol == "tftp" && (bootserver == nil || bootfile == nil)) + dhcp(); + + # determine server + if (bootprotocol == "net" && bootserver == nil) + bootserver = fsip; + + if (bootserver == nil) + fatal("couldn't determine boot server"); + + if (bootfile == nil) + fatal("couldn't determine boot file"); + + if (bootprotocol == nil) + fatal("couldn't determine boot protocol"); + + sys->print("loading %s!%s!%s\n", bootprotocol, bootserver, bootfile); + + if (bootprotocol == "net") { + sys->print("Attempting remote mount\n"); + if (netfs(bootserver) == 0) + sys->print("Remote mount successful\n"); + else + fatal(sys->sprint("Remote mount failed: %r")); + fd := sys->open("/n/remote" + bootfile, Sys->OREAD); + if (fd == nil) + fatal(sys->sprint("%s:/n/remote%s: %r", bootserver, bootfile)); + if (sys->stream(fd, kexecfd, 4096) < 0) + fatal(sys->sprint("copying %s: %r", bootfile)); + } + else if (bootprotocol == "tftp") { + tftp := load Tftp Tftp->PATH; + if (tftp == nil) + fatal("can't load tftp module"); + tftp->init(1); + errstr := tftp->receive(bootserver, bootfile, kexecfd); + if (errstr != nil) + fatal("tftp: " + errstr); + } + else + fatal("protocol " + bootprotocol + " not supported"); + sys->print("Launching new kernel\n"); + kexecfd = nil; +} + +parsebootstring(s: string): (string, string, string) +{ + proto, server, file: string; + (n, l) := sys->tokenize(s, "!"); + if (n > 3) + return (nil, nil, nil); + proto = hd l; + l = tl l; + if (l != nil) { + server = hd l; + l = tl l; + } + if (l != nil) + file = hd l; + case proto { + "tftp" => + ; + "net" => + # can't have a default file, so n must be 3 + if (n != 3) + return (nil, nil, nil); + * => + return (nil, nil, nil); + } + return (proto, server, file); +} + +dobind(f, t: string, flags: int): int +{ + if(sys->bind(f, t, flags) < 0) { + err(sys->sprint("can't bind %s on %s: %r", f, t)); + return 0; + } + return 1; +} + +err(s: string) +{ + sys->fprint(sys->fildes(2), "bootinit: %s\n", s); +} + +hang() +{ + <-(chan of int); +} + +fatal(s: string) +{ + err(s); + hang(); +} + +envlist: list of string; + +getenv(name: string): string +{ + if (envlist == nil) { + fd := sys->open("/dev/sysenv", Sys->OREAD); + if (fd != nil) { + ntok: int; + buf := array[1024] of byte; + nr := sys->read(fd, buf, len buf); + if(nr > 0) + (ntok, envlist) = sys->tokenize(string buf, "\n"); + } + } + ls := envlist; + while(ls != nil) { + (ntok2, ls2) := sys->tokenize(hd ls, "="); + if(hd ls2 == name) + return hd tl ls2; + ls = tl ls; + } + return nil; +} + +getenvdefault(name: string, default: string): string +{ + rv := getenv(name); + if (rv == nil) + return default; + return rv; +} + +ipconfig(cfd: ref sys->FD): string +{ + ip = getenv("wireip"); + if (ip == nil) + ip = getenv("ip"); + mask = getenv("ipmask"); + fsip = getenv("fsip"); + if (ip != nil && mask != nil) { + sys->print("ip %s %s\n", ip, mask); + sys->fprint(cfd, "add %s %s", ip, mask); + gwip := getenv("gwip"); + if (gwip != nil) { + sys->print("gwip %s\n", gwip); + rfd := sys->open("/net/iproute", Sys->ORDWR); + if (rfd == nil || sys->fprint(rfd, "add 0.0.0.0 0.0.0.0 %s", gwip) < 0) + err(sys->sprint("failed to add default route: %r")); + } + } + if (ip == nil || mask == nil) + return bootp(cfd); + return fsip; +} + +bootpdone: int; + +bootp(cfd: ref sys->FD): string +{ + if (bootpdone == 1) + return fsip; + + bootpdone = 1; + + sys->print("bootp ..."); + + if (sys->fprint(cfd, "bootp") < 0) { + sys->print("init: bootp: %r"); + return nil; + } + + fd := sys->open("/net/bootp", sys->OREAD); + if(fd == nil) { + err(sys->sprint("open /net/bootp: %r")); + return nil; + } + + buf := array[Bootpreadlen] of byte; + nr := sys->read(fd, buf, len buf); + fd = nil; + if(nr <= 0) { + err(sys->sprint("read /net/bootp: %r")); + return nil; + } + (ntok, ls) := sys->tokenize(string buf, " \t\n"); + while(ls != nil) { + name := hd ls; + ls = tl ls; + if (ls == nil) + break; + value := hd ls; + ls = tl ls; + if (name == "fsip") + fsip = value; + else if (name == "ipaddr") + ip = value; + else if (name == "ipmask") + mask = value; + } + return fsip; +} + +netfs(server: string): int +{ + auth = load Auth Auth->PATH; + if (auth != nil) + auth->init(); + + kr = load Keyring Keyring->PATH; + 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, nil, "/n/remote", sys->MREPL, ""); + if(n > 0) + return 0; + return -1; +} + +# +# +# DHCP +# +# + +Dhcp: adt { + op: int; + htype: int; + hops: int; + xid: int; + secs: int; + flags: int; + ciaddr: int; + yiaddr: int; + siaddr: int; + giaddr: int; + chaddr: array of byte; + sname: string; + file: string; +}; + +nboputl(buf: array of byte, val: int) +{ + buf[0] = byte (val >> 24); + buf[1] = byte (val >> 16); + buf[2] = byte (val >> 8); + buf[3] = byte val; +} + +nboputs(buf: array of byte, val: int) +{ + buf[0] = byte (val >> 8); + buf[1] = byte val; +} + +nbogets(buf: array of byte): int +{ + return (int buf[0] << 8) | int buf[1]; +} + +nbogetl(buf: array of byte): int +{ + return (int buf[0] << 24) | (int buf[1] << 16) | (int buf[2] << 8) | int buf[3]; +} + +stringget(buf: array of byte): string +{ + for (x := 0; x < len buf; x++) + if (buf[x] == byte 0) + break; + if (x == 0) + return nil; + return string buf[0 : x]; +} + +memcmp(b1: array of byte, b2: array of byte): int +{ + l := len b1; + if (l < len b2) + return int -b2[l]; + if (l > len b2) + return int b1[l]; + for (i := 0; i < l; i++) { + d := int b1[i] - int b2[i]; + if (d != 0) + return d; + } + return 0; +} + +memncpy(out: array of byte, in: array of byte) +{ + if (in == nil) + return; + l := len in; + if (l > len out) + l = len out; + out[0 :] = in[0 : l]; +} + +memset(out: array of byte, val: byte) +{ + for (l := 0; l < len out; l++) + out[l] = val; +} + +dhcpsend(dfd: ref Sys->FD, dhcp: ref Dhcp) +{ + buf := array[576] of byte; + buf[0] = byte dhcp.op; + buf[1] = byte dhcp.htype; + buf[2] = byte len dhcp.chaddr; + buf[3] = byte dhcp.hops; + nboputl(buf[4 : 8], dhcp.xid); + nboputs(buf[8 : 10], dhcp.secs); + nboputs(buf[10 : 12], dhcp.flags); + nboputl(buf[12 : 16], dhcp.ciaddr); + nboputl(buf[16 : 20], dhcp.yiaddr); + nboputl(buf[20 : 24], dhcp.siaddr); + nboputl(buf[24 : 28], dhcp.giaddr); + memset(buf[28 :], byte 0); + memncpy(buf[28 : 44], dhcp.chaddr); + memncpy(buf[44 : 108], array of byte dhcp.sname); + memncpy(buf[108 : 236], array of byte dhcp.file); + sys->write(dfd, buf, len buf); +} + +kill(pid: int) +{ + fd := sys->open("#p/" + string pid + "/ctl", sys->OWRITE); + if (fd == nil) + return; + + msg := array of byte "kill"; + sys->write(fd, msg, len msg); +} + +ipfmt(ipaddr: int): string +{ + return sys->sprint("%ud.%ud.%ud.%ud", + (ipaddr >> 24) & 16rff, + (ipaddr >> 16) & 16rff, + (ipaddr >> 8) & 16rff, + ipaddr & 16rff); +} + +dumpdhcp(dhcp: ref Dhcp) +{ + sys->print("op %d htype %d hops %d xid %ud\n", dhcp.op, dhcp.htype, dhcp.hops, dhcp.xid); + sys->print("secs %d flags 0x%.4ux\n", dhcp.secs, dhcp.flags); + sys->print("ciaddr %s\n", ipfmt(dhcp.ciaddr)); + sys->print("yiaddr %s\n", ipfmt(dhcp.yiaddr)); + sys->print("siaddr %s\n", ipfmt(dhcp.siaddr)); + sys->print("giaddr %s\n", ipfmt(dhcp.giaddr)); + sys->print("chaddr "); + for (x := 0; x < len dhcp.chaddr; x++) + sys->print("%.2ux", int dhcp.chaddr[x]); + sys->print("\n"); + if (dhcp.sname != nil) + sys->print("sname %s\n", dhcp.sname); + if (dhcp.file != nil) + sys->print("file %s\n", dhcp.file); +} + +dhcplisten(pidc: chan of int, fd: ref Sys->FD, dc: chan of ref Dhcp) +{ + pid := sys->pctl(0, nil); + pidc <-= pid; + buf := array [576] of byte; + while (1) { + n := sys->read(fd, buf, len buf); + dhcp := ref Dhcp; + dhcp.op = int buf[0]; + dhcp.htype = int buf[1]; + hlen := int buf[2]; + dhcp.hops = int buf[3]; + dhcp.xid = nbogetl(buf[4 : 8]); + dhcp.secs = nbogets(buf[8 : 10]); + dhcp.flags = nbogets(buf[10 : 12]); + dhcp.ciaddr = nbogetl(buf[12 : 16]); + dhcp.yiaddr = nbogetl(buf[16 : 20]); + dhcp.siaddr = nbogetl(buf[20 : 24]); + dhcp.giaddr = nbogetl(buf[24: 28]); + dhcp.chaddr = buf[28 : 28 + hlen]; + dhcp.sname = stringget(buf[44 : 108]); + dhcp.file = stringget(buf[108 : 236]); + dc <-= dhcp; + } +} + +timeoutproc(pid: chan of int, howlong: int, c: chan of string) +{ + pid <-= sys->pctl(0, nil); + + sys->sleep(howlong); + + # send timeout + c <-= "timed out"; +} + +tpid := -1; +tc: chan of string; + +timeoutcancel() +{ + if (tpid >= 0) { + kill(tpid); + tpid = -1; + } +} + +timeoutstart(howlong: int): (chan of string) +{ + timeoutcancel(); + pidc := chan of int; + tc = chan of string; + spawn timeoutproc(pidc, howlong, tc); + tpid = <- pidc; + return tc; +} + +atohn(b: byte): int +{ + if (b >= byte '0' && b <= byte '9') + return int (b - byte '0'); + if (b >= byte 'A' && b <= byte 'F') + return int b - 'A' + 10; + if (b >= byte 'a' && b <= byte 'f') + return int b - 'a' + 10; + return -1; +} + +atohb(buf: array of byte): int +{ + tn := atohn(buf[0]); + bn := atohn(buf[1]); + if (tn < 0 || bn < 0) + return -1; + return tn * 16 + bn; +} + +gethaddr(dhcp: ref Dhcp): int +{ + fd := sys->open("#l/ether0/addr", Sys->OREAD); + if (fd == nil) + return 0; + buf := array [100] of byte; + n := sys->read(fd, buf, len buf); + if (n < 0) + return 0; + dhcp.htype = 1; + hlen := n / 2; + dhcp.chaddr = array [hlen] of byte; + for (i := 0; i < hlen; i++) + dhcp.chaddr[i] = byte atohb(buf[i * 2 : i * 2 + 2]); + return 1; +} + +parsedq(dq: string): (int, int) +{ + (c, l) := sys->tokenize(dq, "."); + if (c != 4) + return (0, 0); + a := hd l; + l = tl l; + b := hd l; + l = tl l; + d := hd l; + l = tl l; + addr := (int a << 24) | (int b << 16) | (int d << 8) | int hd l; + return (1, addr); +} + +dhcp() +{ + ok: int; + conn: Sys->Connection; + rdhcp: ref Dhcp; + + if (random == nil) + random = load Random Random->PATH; + + (ok, conn) = sys->dial("udp!255.255.255.255!67", "68"); + if (!ok) + fatal(sys->sprint("failed to dial udp broadcast: %r")); + + pidc := chan of int; + dc := chan of ref Dhcp; + spawn dhcplisten(pidc, conn.dfd, dc); + dhcppid := <- pidc; + dhcp := ref Dhcp; + dhcp.op = 1; + dhcp.htype = 1; + gethaddr(dhcp); + dhcp.hops = 0; + dhcp.xid = random->randomint(Random->NotQuiteRandom); + dhcp.secs = 0; + dhcp.flags = 0; + (ok, dhcp.ciaddr) = parsedq(ip); + dhcp.yiaddr = 0; + dhcp.siaddr = 0; + dhcp.giaddr = 0; + if (bootfile != "bootp") + dhcp.file = bootfile; + else + dhcp.file = nil; + ok = 0; + for (count := 0; !ok && count < 5; count++) { + mtc := timeoutstart(3000); + dhcpsend(conn.dfd, dhcp); + timedout := 0; + do { + alt { + <- mtc => + timedout = 1; + rdhcp = <- dc => + if (debug) + dumpdhcp(rdhcp); + if (rdhcp.ciaddr != dhcp.ciaddr || rdhcp.xid != dhcp.xid + || memcmp(rdhcp.chaddr, dhcp.chaddr) != 0) { + break; + } + if (rdhcp.file != nil) { + ok = 1; + timeoutcancel(); + } + } + } while (!timedout && !ok); + dhcp.xid++; + } + if (ok) { + if (bootfile == nil) + bootfile = rdhcp.file; + if (bootserver == nil) + bootserver = ipfmt(rdhcp.siaddr); + } + else + err("bootp timed out"); + kill(dhcppid); +} diff --git a/os/init/cerf405.b b/os/init/cerf405.b new file mode 100644 index 00000000..b02dd5a2 --- /dev/null +++ b/os/init/cerf405.b @@ -0,0 +1,598 @@ +# +# Intrinsyc Cerf cube 405EP, also Manga switch +# +# this encrusted version will be simplified shortly +# + +implement Init; + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "keyring.m"; + kr: Keyring; + +include "security.m"; + auth: Auth; + +include "dhcp.m"; + dhcpclient: Dhcpclient; + Bootconf: import dhcpclient; + +include "sh.m"; + +Init: module +{ + init: fn(); +}; + +Bootpreadlen: con 128; +Microsec: con 1000000; +Notime: con big 800000000 * big Microsec; # fairly arbitrary time in 1995 to check validity + +# conventional Inferno NAND flash partitions +nandparts := array[] of { + # bootstrap from 0 to 0x210000 + "add boot 0 0x210000", + "add fs 0x210000 end" +}; + +userdefault := array[] of { + "inferno inferno", + "sys sys" +}; + +ethername := "/net/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; + + sys->bind("/", "/", Sys->MREPL); + if(sys->bind("/boot", "/", Sys->MAFTER) < 0) + sys->print("can't bind /boot after /: %r\n"); + sys->bind("/boot/nvfs", "/nvfs", Sys->MREPL); + + auth = load Auth Auth->PATH; + if(auth != nil) + auth->init(); + + localok := 0; + if(lfs() >= 0){ + # let's just take a closer look + sys->bind("/n/local/nvfs", "/nvfs", Sys->MBEFORE|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 = "/net/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 + sys->bind("#ʟ", "/dev", Sys->MAFTER); # logfs + + 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("/n/local", rootsource+"/n/local", Sys->MREPL|Sys->MCREATE); + sys->unmount("#//./boot", "/"); + sys->bind(rootsource+"/dis", "/dis", Sys->MBEFORE|Sys->MCREATE); + break; + } + } + cfd = nil; + + setsysname("cerf"); # set system name + + rtc := big rf("#r/rtc", "0") * big Microsec; + now := big 0; + if(timefile != nil){ # synchronise with remote time if it's valid + now = big rf(timefile, "0"); + if(now < Notime && rootsource != nil) + now = big filetime(rootsource) * big Microsec; # try the time of the root directory + if(now >= Notime){ + setclock("#r/rtc", now/big Microsec); + rtc = now; + } + } + if(now < Notime) + now = rtc; + setclock("/dev/time", now); + + 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 := rdenv("user", "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); +} + +filetime(name: string): int +{ + (ok, dir) := sys->stat(name); + if(ok < 0) + return 0; + return dir.atime; +} + +setclock(timefile: string, now: big) +{ + fd := sys->open(timefile, sys->OWRITE); + if(fd == nil) + sys->print("init: can't open %s: %r\n", timefile); + else if(sys->fprint(fd, "%bud", now) < 0) + sys->print("init: can't write to %s: %r\n", timefile); +} + +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 = rdenv("rootsource", nil)) != nil){ + tried = 1; + sys->print("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, nil); + "local" => + return ("/n/local", nil); + "local+remote" => + if(netfs("/n/remote") >= 0) + return ("/n/local", nil); + "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 file system using logfs +# +lfs(): int +{ + if(!flashpart("#F1/flash1/flashctl", nandparts)) + return -1; + if(!logfsinit("#F1/flash1/fs")) + return -1; + mfd := sys->open("/dev/logfsmain", Sys->ORDWR); + if(mfd == nil){ + sys->print("can't open /dev/logfsmain: %r\n"); + return -1; + } + if(sys->mount(mfd, nil, "/n/local", Sys->MREPL|Sys->MCREATE, nil) < 0){ + sys->print("can't mount /dev/logfsmain on /n/local: %r\n"); + return -1; + } + return 0; +} + +# +# 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 logfs +# +logfsdone := 0; + +logfsinit(flashmem: string): int +{ + if(logfsdone) + return 1; + fd := sys->open("/dev/logfsctl", Sys->OWRITE); + if(fd == nil){ + if(sys->bind("#ʟ", "/dev", Sys->MBEFORE) < 0) + return -1; + fd = sys->open("/dev/logfsctl", Sys->OWRITE); + if(fd == nil){ + sys->print("can't open /dev/logfsctl: %r\n"); + return -1; + } + } + sys->print("Set logfs main on %s...\n", flashmem); + if(!ctlw(fd, "logfs", "fsys main config "+flashmem)) + return -1; + if(!ctlw(fd, "logfs", "fsys main")) + return -1; + cm := rf("#e/logfsformat", nil); + if(cm == "yes"){ + if(!ctlw(fd, "logfs", "format 0")) + return -1; + } + cf := rf("#e/logfsopen", nil); + if(cf == nil) + cf = "open"; + if(!ctlw(fd, "logfs", cf)) + return -1; + for(i := 0; i < len userdefault; i++) + ctlw(fd, "logfs", "uname "+userdefault[i]); + logfsdone = 1; + return 1; +} + +ctlw(fd: ref Sys->FD, w: string, cmd: string): int +{ + if(sys->fprint(fd, "%s", cmd) < 0){ + sys->print("%s ctl %q: %r\n", w, cmd); + return 0; + } + return 1; +} + +configether() +{ + if(ethername == nil) + return; + fd := sys->open("/nvfs/etherparams", Sys->OREAD); + if(fd == nil) + return; + ctl := sys->open(ethername+"/clone", Sys->OWRITE); + if(ctl == nil){ + sys->print("init: can't open %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/clone: %s: %r\n", ethername, s); + i = e+1; + } +} + +donebind := 0; +server: string; + +# +# set up network mount +# +netfs(mountpt: string): int +{ + 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 %s interface: %r\n", ethername); + 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; + } + } + server = rdenv("fsip", nil); + if((ip := rdenv("ip", nil)) != nil){ + sys->print("**using %s\n", ip); + sys->fprint(fd, "bind ether /net/ether0"); + s := rdenv("ipmask", nil); + if(s == nil) + s = rdenv("netmask", nil); # alternative name used by some bootstraps + sys->fprint(fd, "add %s %s", ip, s); + gate := rdenv("ipgw", nil); + if(gate == nil) + gate = rdenv("gateway", nil); + if(gate != nil){ + rfd := sys->open("/net/iproute", Sys->OWRITE); + if(rfd != nil){ + sys->fprint(rfd, "add 0 0 %s", gate); + sys->print("set gateway %s\n", gate); + } + } + }else if(server == nil){ + sys->print("dhcp..."); + dhcpclient = load Dhcpclient Dhcpclient->PATH; + if(dhcpclient == nil){ + sys->print("can't load dhcpclient: %r\n"); + return -1; + } + dhcpclient->init(); + (cfg, nil, e) := dhcpclient->dhcp("/net", fd, "/net/ether0/addr", nil, nil); + if(e != nil){ + sys->print("dhcp: %s\n", e); + return -1; + } + if(server == nil) + server = cfg.getip(Dhcpclient->OP9fs); + dhcpclient = nil; + } + if(server == nil || server == "0.0.0.0"){ + sys->print("no file server address\n"); + return -1; + } + sys->print("fs=%s\n", server); + + 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 `none'\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; +} + +username(def: string): string +{ + return rdenv("user", def); +} + +userok(user: string): int +{ + (ok, d) := sys->stat("/usr/"+user); + return ok >= 0 && (d.mode & Sys->DMDIR) != 0; +} + +rdenv(name: string, def: string): string +{ + s := rf("#e/"+name, nil); + if(s != nil) + return s; + return rf("/nvfs/"+name, def); +} + +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){ + s := string buf[0:nr]; + while(s != nil && ((c := s[len s-1]) == '\n' || c == '\r')) + s = s[0: len s-1]; + if(s != nil) + return s; + } + } + return default; +} diff --git a/os/init/cerfinit.b b/os/init/cerfinit.b new file mode 100644 index 00000000..96d2b784 --- /dev/null +++ b/os/init/cerfinit.b @@ -0,0 +1,612 @@ +# +# Intrinsyc Cerf cube +# + +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 { + # bootstrap at 0x0 to 0x20000 + "add script 0x20000 0x40000", + "add kernel 0x100000 0x200000", + "add fs 0x200000 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; + scale := 1; + cfd := sys->open("/dev/consctl", Sys->OWRITE); + if(cfd != nil) + sys->fprint(cfd, "rawon"); + for(;;){ + (rootsource, timefile, scale) = 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("cerf"); # set system name + + now := getclock(timefile, rootsource); + if(scale == 1) + now *= big 1000000; + 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, int) +{ + 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", 1); + "local" => + return ("/n/local", "#r/rtc", 1); + "local+remote" => + if(netfs("/n/remote") >= 0) + return ("/n/local", "/n/remote/dev/time", 1000000); + "remote" => + if(netfs("/n/remote") >= 0) + return ("/n/remote", "/n/remote/dev/time", 1000000); + } + } +} + +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 %s interface: %r\n", ethername); + 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; +} diff --git a/os/init/evalinit.b b/os/init/evalinit.b new file mode 100644 index 00000000..1e33c6f9 --- /dev/null +++ b/os/init/evalinit.b @@ -0,0 +1,119 @@ +implement Init; + +# +# ARM evaluator 7t +# + +include "sys.m"; +sys: Sys; +FD, Connection, sprint, Dir: import sys; +print, fprint, open, bind, mount, dial, sleep, read: import sys; + +include "draw.m"; +include "sh.m"; +draw: Draw; +Context: import draw; + +Init: module +{ + init: fn(); +}; + +Logon: module +{ + init: fn(ctxt: ref 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 + # +# bind("#l", "/net", sys->MREPL); +# bind("#I", "/net", sys->MAFTER); + bind("#c", "/dev", sys->MAFTER); + bind("#r", "/dev", sys->MAFTER); +# nvramfd := sys->open("#r/nvram", sys->ORDWR); +# if(nvramfd != nil){ +# spec = "#Fnvram"; +# if(bind(spec, "/nvfs", sys->MAFTER) < 0) +# print("init: bind %s: %r\n", spec); +# } + +# setsysname(); + + # + # default namespace + # + bind("#c", "/dev", sys->MREPL); # console + bind("#t", "/dev", sys->MAFTER); # serial port + bind("#r", "/dev", sys->MAFTER); # RTC +# if(spec != nil) +# bind(spec, "/nvfs", sys->MBEFORE|sys->MCREATE); # our keys +# bind("#l", "/net", sys->MBEFORE); # ethernet +# bind("#I", "/net", sys->MBEFORE); # TCP/IP + bind("#p", "/prog", sys->MREPL); # prog device + sys->bind("#d", "/fd", Sys->MREPL); + + sys->print("clock...\n"); + setclock(); + + sys->print("logon...\n"); + +# sys->chdir("/usr/inferno"); +# logon := load Logon "/dis/sh.dis"; +# spawn logon->init(dc, nil); + ts := load Sh "/dis/sh.dis"; + ts->init(nil, nil); +} + +setclock() +{ + (ok, dir) := sys->stat("/"); + if (ok < 0) { + print("init: stat /: %r"); + return; + } + + fd := sys->open("/dev/time", sys->OWRITE); + if (fd == nil) { + print("init: open /dev/time: %r"); + return; + } + + # Time is kept as microsecs, atime is in secs + b := array of byte sprint("%d000000", dir.atime); + if (sys->write(fd, b, len b) != len b) + print("init: write /dev/time: %r"); +} + +# +# Set system name from nvram +# +setsysname() +{ + fd := open("/nvfs/ID", sys->OREAD); + if(fd == nil) + return; + fds := 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); +} diff --git a/os/init/geninit.b b/os/init/geninit.b new file mode 100644 index 00000000..7e63d24f --- /dev/null +++ b/os/init/geninit.b @@ -0,0 +1,93 @@ +implement Init; +# +# init program for native inferno, generic pc version +# +include "sys.m"; +sys: Sys; +FD, Connection, sprint, Dir: import sys; +print, fprint, open, bind, mount, dial, sleep, read, chdir: import sys; + +include "draw.m"; +draw: Draw; +Context: import draw; + +include "keyring.m"; +kr: Keyring; + +Init: module +{ + init: fn(); +}; + +Shell: module +{ + init: fn(ctxt: ref Context, argv: list of string); +}; + +init() +{ + + sys = load Sys Sys->PATH; + stdin := sys->fildes(0); + kr = load Keyring Keyring->PATH; + + 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 + # + sys->print("Bind console ...\n"); + bind("#c", "/dev", sys->MAFTER); + + setsysname(); + print("Standalone mode\n"); + # + # default namespace + # + sys->unmount(nil, "/dev"); + bind("#p", "/prog", sys->MREPL); # prog device + sys->bind("#d", "/fd", Sys->MREPL); + bind("#c", "/dev", sys->MBEFORE); # console + bind("#m", "/dev", sys->MAFTER); # mouse setup device + bind("#t", "/dev", sys->MAFTER); # serial device + + mouse := load Shell "/dis/mouse.dis"; + if (mouse != nil) { + print("Setting up mouse\n"); + mouse->init(nil, "/dis/mouse.dis" :: nil); + mouse = nil; + } + + # create fake nameserver db that can be written to later + ramfile := load Shell "/dis/ramfile.dis"; + if (ramfile != nil) { + ramfile->init(nil, "/dis/ramfile.dis" :: "/services/dns/db" :: "" :: nil); + ramfile = nil; + } + + print("Console...\n"); + shell := load Shell "/dis/sh.dis"; + if(shell == nil) { + print("init: load /dis/sh.dis: %r\n"); + exit; + } + print("starting shell\n"); + shell->init(nil, "/dis/sh.dis" :: nil); + print("shell exited, bye bye\n"); +} + + +# +# Set system name from nvram +# +setsysname() +{ + fds := open("/dev/sysname", sys->OWRITE); + if(fds == nil) + return; + buf := array of byte "genericpc"; + sys->write(fds, buf, len buf); +} 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; +} diff --git a/os/init/init.b b/os/init/init.b new file mode 100644 index 00000000..655b0cf3 --- /dev/null +++ b/os/init/init.b @@ -0,0 +1,613 @@ +implement Init; + +include "sys.m"; +sys: Sys; +FD, Connection, sprint, Dir: import sys; +print, fprint, open, bind, mount, dial, sleep, read: import sys; + +include "draw.m"; +draw: Draw; +Context, Display, Font, Rect, Point, Image, Screen: import draw; + +include "prefab.m"; +prefab: Prefab; +Environ, Element, Compound, Style: import prefab; + +include "mpeg.m"; + +include "ir.m"; +tirc: chan of int; # translated remote input (from irslave) +irstopc: chan of int; # channel to irslave + +include "keyring.m"; +kr: Keyring; +IPint: import kr; + +Init: module +{ + init: fn(); +}; + +Shell: module +{ + init: fn(ctxt: ref Context, argv: list of string); +}; + +Signon: con "Dialing Local Service Provider\nWait a moment ..."; +Login: con "Connected to Service Provider"; +Intro: con "/mpeg/youwill2"; +Garden: con "The Garden of Delights\nHieronymus Bosch"; + +rootfs(server: string): int +{ + ok, n: int; + c: Connection; + err: string; + + (ok, c) = dial("tcp!" + server + "!6666", nil); + if(ok < 0) + return -1; + + if(kr != nil){ + ai := kr->readauthinfo("/nvfs/default"); + if(ai == nil){ + (ai, err) = register(server); + if(err != nil){ + status("registration failed: "+err+"\nPress a key on your remote\ncontrol to continue."); + # register() may have failed before Ir loaded. + if(tirc!=nil){ + <-tirc; + irstopc <-= 1; + } + } + statusbox = nil; + } + (id_or_err, secret) := kr->auth(c.dfd, ai, 0); + if(secret == nil){ + status("authentication failed: "+err); + sys->sleep(2000); + statusbox = nil; + (ai, err) = register(server); + if(err != nil){ + status("registration failed: "+err+"\nPress a key on your remote\ncontrol to continue."); + # register() may have failed before Ir loaded. + if(tirc!=nil){ + <-tirc; + irstopc <-= 1; + } + } + statusbox = nil; + } else { + # no line encryption + algbuf := array of byte "none"; + kr->sendmsg(c.dfd, algbuf, len algbuf); + } + } + + c.cfd = nil; + n = mount(c.dfd, nil, "/", sys->MREPL, ""); + if(n > 0) + return 0; + return -1; +} + +ones: ref Image; +screen: ref Screen; +menuenv, tvenv: ref Environ; +Bootpreadlen: con 128; +textfont: ref Font; +disp: ref Display; +env: ref Environ; +statusbox: ref Compound; + +init() +{ + shell: Shell; + nr, ntok: int; + c: ref Compound; + ls: list of string; + le, te, xe: ref Element; + spec: string; + + sys = load Sys Sys->PATH; + draw = load Draw Draw->PATH; + prefab = load Prefab Prefab->PATH; + kr = load Keyring Keyring->PATH; + + disp = Display.allocate(nil); + ones = disp.ones; + + textfont = Font.open(disp, "*default*"); + screencolor := disp.rgb(161, 195, 209); + + menustyle := ref Style( + textfont, # titlefont + textfont, # textfont + disp.color(16r55), # elemcolor + disp.color(draw->Black), # edgecolor + disp.color(draw->Yellow), # titlecolor + disp.color(draw->Black), # textcolor + disp.color(draw->White)); # highlightcolor + + screen = Screen.allocate(disp.image, screencolor, 0); + screen.image.draw(screen.image.r, screencolor, ones, (0, 0)); + menuenv = ref Environ(screen, menustyle); + + logo := disp.open("/lucent"); + phone := disp.open("/phone"); + if(phone == nil || logo == nil) { + print("open: /phone or /lucent: %r\n"); + exit; + } + + # + # Setup what we need to call a server and + # Authenticate + # + bind("#l", "/net", sys->MREPL); + bind("#I", "/net", sys->MAFTER); + bind("#c", "/dev", sys->MAFTER); + bind("#H", "/dev", sys->MAFTER); + nvramfd := sys->open("#H/hd0nvram", sys->ORDWR); + if(nvramfd != nil){ + spec = sys->sprint("#Fhd0nvram", nvramfd.fd); + if(bind(spec, "/nvfs", sys->MAFTER|sys->MCREATE) < 0) + print("init: bind %s: %r\n", spec); + } + + setsysname(); # set up system name + + fd := open("/net/ipifc", sys->OWRITE); + if(fd == nil) { + print("init: open /net/ipifc: %r"); + exit; + } + fprint(fd, "bootp /net/ether0"); + + fd = open("/net/bootp", sys->OREAD); + if(fd == nil) { + print("init: open /net/bootp: %r"); + exit; + } + + buf := array[Bootpreadlen] of byte; + nr = read(fd, buf, len buf); + fd = nil; + if(nr <= 0) { + 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) { + print("init: server address not in bootp read"); + exit; + } + + zr := Rect((0,0), (0,0)); + + le = Element.icon(menuenv, logo.r, logo, ones); + le = Element.elist(menuenv, le, Prefab->EVertical); + xe = Element.icon(menuenv, phone.r, phone, ones); + xe = Element.elist(menuenv, xe, Prefab->EHorizontal); + te = Element.text(menuenv, Signon, zr, Prefab->EText); + xe.append(te); + xe.adjust(Prefab->Adjpack, Prefab->Adjleft); + le.append(xe); + le.adjust(Prefab->Adjpack, Prefab->Adjup); + c = Compound.box(menuenv, (150, 100), + Element.text(menuenv, "Inferno", zr, Prefab->ETitle), le); + c.draw(); + + while(rootfs(hd ls) < 0) + sleep(1000); + + # + # default namespace + # + bind("#c", "/dev", sys->MBEFORE); # console + bind("#H", "/dev", sys->MAFTER); + if(spec != nil) + bind(spec, "/nvfs", sys->MBEFORE|sys->MCREATE); # our keys + bind("#E", "/dev", sys->MBEFORE); # mpeg + bind("#l", "/net", sys->MBEFORE); # ethernet + bind("#I", "/net", sys->MBEFORE); # TCP/IP + bind("#V", "/dev", sys->MAFTER); # hauppauge TV + bind("#p", "/prog", sys->MREPL); # prog device + sys->bind("#d", "/fd", Sys->MREPL); + + setclock(); + + le = Element.icon(menuenv, logo.r, logo, ones); + le = Element.elist(menuenv, le, Prefab->EVertical); + xe = Element.text(menuenv, Login, zr, Prefab->EText); + le.append(xe); + + i := disp.newimage(Rect((0, 0), (320, 240)), 3, 0, 0); + i.draw(i.r, menustyle.elemcolor, ones, i.r.min); + xe = Element.icon(menuenv, i.r, i, ones); + le.append(xe); + + le.adjust(Prefab->Adjpack, Prefab->Adjup); + c = Compound.box(menuenv, (160, 50), + Element.text(menuenv, "Inferno", zr, Prefab->ETitle), le); + c.draw(); + + xc: chan of string; + mpeg := load Mpeg Mpeg->PATH; + if(mpeg != nil) { + xc = chan of string; + r := (hd tl tl c.contents.kids).r; + s := mpeg->play(disp, c.image, 1, r, Intro, xc); + if(s != "") { + print("mpeg: %s\n", s); + xc = nil; + } + } + + i2 := disp.open("/icons/delight.bit"); + i.draw(i.r, i2, ones, i2.r.min); + i2 = nil; + if(xc != nil) + <-xc; + + le.append(Element.text(menuenv, Garden, le.r, Prefab->EText)); + le.adjust(Prefab->Adjpack, Prefab->Adjup); + c = Compound.box(menuenv, (160, 50), + Element.text(menuenv, "Inferno", zr, Prefab->ETitle), le); + c.draw(); + + sleep(5000); + + # Do a bind to force applications to use IR module built + # into the kernel. + if(bind("#/./ir", Ir->PATH, sys->MREPL) < 0) + print("init: bind ir: %r\n"); + # Uncomment the next line to load sh.dis. +# shell = load Shell "/dis/sh.dis"; + dc : ref Context; + # Comment the next 2 lines to load sh.dis. + shell = load Shell "/dis/mux/mux.dis"; + dc = ref Context(screen, disp, nil, nil, nil, nil, nil); + if(shell == nil) { + print("init: load /dis/sh.dis: %r"); + exit; + } + shell->init(dc, nil); +} + +setclock() +{ + (ok, dir) := sys->stat("/"); + if (ok < 0) { + print("init: stat /: %r"); + return; + } + + fd := sys->open("/dev/time", sys->OWRITE); + if (fd == nil) { + print("init: open /dev/time: %r"); + return; + } + + # Time is kept as microsecs, atime is in secs + b := array of byte sprint("%d000000", dir.atime); + if (sys->write(fd, b, len b) != len b) + print("init: write /dev/time: %r"); +} + +register(signer: string): (ref Keyring->Authinfo, string) +{ + + # get box id + fd := sys->open("/nvfs/ID", sys->OREAD); + if(fd == nil){ + fd = sys->create("/nvfs/ID", sys->OWRITE, 8r664); + if(fd == nil) + return (nil, "can't create /nvfs/ID"); + if(sys->fprint(fd, "LT%d", randomint()) < 0) + return (nil, "can't write /nvfs/ID"); + fd = sys->open("/nvfs/ID", sys->OREAD); + } + if(fd == nil) + return (nil, "can't open /nvfs/ID"); + + buf := array[64] of byte; + n := sys->read(fd, buf, (len buf) - 1); + if(n <= 0) + return (nil, "can't read /nvfs/ID"); + + boxid := string buf[0:n]; + fd = nil; + buf = nil; + + # Set-up for user input via remote control. + tirc = chan of int; + irstopc = chan of int; + spawn irslave(tirc, irstopc); + case dialogue("Register with your service provider?", "yes\nno") { + 0 => + ; + * => + return (nil, "registration not desired"); + } + + # a holder + info := ref Keyring->Authinfo; + + # contact signer +# status("looking for signer"); +# signer := virgil->virgil("$SIGNER"); +# if(signer == nil) +# return (nil, "can't find signer"); + status("dialing tcp!"+signer+"!6671"); + (ok, c) := sys->dial("tcp!"+signer+"!6671", nil); + if(!ok) + return (nil, "can't contact signer"); + + # get signer's public key and diffie helman parameters + status("getting signer's key"); + spkbuf := kr->getmsg(c.dfd); + if(spkbuf == nil) + return (nil, "can't read signer's key"); + info.spk = kr->strtopk(string spkbuf); + if(info.spk == nil) + return (nil, "bad key from signer"); + alphabuf := kr->getmsg(c.dfd); + if(alphabuf == nil) + return (nil, "can't read dh alpha"); + info.alpha = IPint.b64toip(string alphabuf); + pbuf := kr->getmsg(c.dfd); + if(pbuf == nil) + return (nil, "can't read dh mod"); + info.p = IPint.b64toip(string pbuf); + + # generate our key from system parameters + status("generating our key"); + info.mysk = kr->genSKfromPK(info.spk, boxid); + if(info.mysk == nil) + return (nil, "can't generate our own key"); + info.mypk = kr->sktopk(info.mysk); + + # send signer our public key + mypkbuf := array of byte kr->pktostr(info.mypk); + kr->sendmsg(c.dfd, mypkbuf, len mypkbuf); + + # get blind certificate + status("getting blinded certificate"); + certbuf := kr->getmsg(c.dfd); + if(certbuf == nil) + return (nil, "can't read signed key"); + + # verify we've got the right stuff + if(!verify(boxid, spkbuf, mypkbuf, certbuf)) + return (nil, "verification failed, try again"); + + # contact counter signer + status("dialing tcp!"+signer+"!6672"); + (ok, c) = sys->dial("tcp!"+signer+"!6672", nil); + if(!ok) + return (nil, "can't contact countersigner"); + + # send boxid + buf = array of byte boxid; + kr->sendmsg(c.dfd, buf, len buf); + + # get blinding mask + status("unblinding certificate"); + mask := kr->getmsg(c.dfd); + if(len mask != len certbuf) + return (nil, "bad mask length"); + for(i := 0; i < len mask; i++) + certbuf[i] = certbuf[i] ^ mask[i]; + info.cert = kr->strtocert(string certbuf); + + status("verifying certificate"); + state := kr->sha(mypkbuf, len mypkbuf, nil, nil); + if(kr->verify(info.spk, info.cert, state) == 0) + return (nil, "bad certificate"); + + status("storing keys"); + kr->writeauthinfo("/nvfs/default", info); + + status("Congratulations, you are registered.\nPress a key to continue."); + <-tirc; + irstopc <-= 1; + + return (info, nil); +} + +dialogue(expl: string, selection: string): int +{ + c := Compound.textbox(menuenv, ((100, 100), (100, 100)), expl, selection); + c.draw(); + for(;;){ + (key, index, nil) := c.select(c.contents, 0, tirc); + case key { + Ir->Select => + return index; + Ir->Enter => + return -1; + } + } +} + +status(expl: string) +{ +# title := Element.text(menuenv, "registration\nstatus", ((0,0),(0,0)), Prefab->ETitle); +# msg := Element.text(menuenv, expl, ((0,0),(0,0)), Prefab->EText); +# c := Compound.box(menuenv, (100, 100), title, msg); + + c := Compound.textbox(menuenv, ((100, 100),(100,100)), "Registration status", expl); + c.draw(); + statusbox = c; +} + +pro:= array[] of { + "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", + "hotel", "india", "juliet", "kilo", "lima", "mike", "nancy", "oscar", + "poppa", "quebec", "romeo", "sierra", "tango", "uniform", + "victor", "whiskey", "xray", "yankee", "zulu" +}; + +# +# prompt for acceptance +# +verify(boxid: string, hispk, mypk, cert: array of byte): int +{ + s: string; + + # hash the string + state := kr->md5(hispk, len hispk, nil, nil); + kr->md5(mypk, len mypk, nil, state); + digest := array[Keyring->MD5dlen] of byte; + kr->md5(cert, len cert, digest, state); + + title := Element.elist(menuenv, nil, Prefab->EVertical); + subtitle := Element.text(menuenv, "Telephone your service provider\n to register. You will need\nthe following:\n", ((0,0),(0,0)), Prefab->ETitle); + title.append(subtitle); + + line := Element.text(menuenv, "boxid is '"+boxid+"'.", ((0,0),(0,0)), Prefab->ETitle); + title.append(line); + for(i := 0; i < len digest; i++){ + line = Element.elist(menuenv, nil, Prefab->EHorizontal); + s = (string (2*i)) + ": " + pro[((int digest[i])>>4)%len pro]; + line.append(Element.text(menuenv, s, ((0,0),(0,0)), Prefab->ETitle)); + + s = (string (2*i+1)) + ": " + pro[(int digest[i])%len pro] + "\n"; + line.append(Element.text(menuenv, s, ((0,0),(200,0)), Prefab->ETitle)); + + line.adjust(Prefab->Adjequal, Prefab->Adjleft); + title.append(line); + } + title.adjust(Prefab->Adjpack, Prefab->Adjleft); + + le := Element.elist(menuenv, nil, Prefab->EHorizontal); + le.append(Element.text(menuenv, " accept ", ((0, 0), (0, 0)), Prefab->EText)); + le.append(Element.text(menuenv, " reject ", ((0, 0), (0, 0)), Prefab->EText)); + le.adjust(Prefab->Adjpack, Prefab->Adjleft); + + c := Compound.box(menuenv, (50, 50), title, le); + c.draw(); + + for(;;){ + (key, index, nil) := c.select(c.contents, 0, tirc); + case key { + Ir->Select => + if(index == 0) + return 1; + return 0; + Ir->Enter => + return 0; + } + } + + return 0; +} + +randomint(): int +{ + fd := sys->open("/dev/random", sys->OREAD); + if(fd == nil) + return 0; + buf := array[4] of byte; + sys->read(fd, buf, 4); + rand := 0; + for(i := 0; i < 4; i++) + rand = (rand<<8) | int buf[i]; + return rand; +} + +# Reads real (if possible) or simulated remote, returns Ir events on irc. +# Must be a separate thread to be able to 1) read raw Ir input channel +# and 2) write translated Ir input data on output channel. +irslave(irc, stopc: chan of int) +{ + in, irpid: int; + buf: list of int; + outc: chan of int; + + irchan := chan of int; # Untranslated Ir input channel. + irpidch := chan of int; # Ir reader pid channel. + irmod := load Ir "#/./ir"; # Module built into kernel. + + if(irmod==nil){ + print("irslave: failed to load #/./ir"); + return; + } + if(irmod->init(irchan, irpidch)<0){ + print("irslave: failed to initialize ir"); + return; + } + irpid =<-irpidch; + + hdbuf := 0; + dummy := chan of int; + for(;;){ + if(buf == nil){ + outc = dummy; + }else{ + outc = irc; + hdbuf = hd buf; + } + alt{ + in = <-irchan => + buf = append(buf, in); + outc <-= irmod->translate(hdbuf) => + buf = tl buf; + <-stopc =>{ + killir(irpid); + return; + } + } + } +} + +append(l: list of int, i: int): list of int +{ + if(l == nil) + return i :: nil; + return hd l :: append(tl l, i); +} + +killir(irpid: int) +{ + pid := sys->sprint("%d", irpid); + fd := sys->open("#p/"+pid+"/ctl", sys->OWRITE); + if(fd==nil) { + print("init: process %s: %r\n", pid); + return; + } + + msg := array of byte "kill"; + n := sys->write(fd, msg, len msg); + if(n < 0) { + print("init: message for %s: %r\n", pid); + return; + } +} + +# +# Set system name from nvram +# +setsysname() +{ + fd := open("/nvfs/ID", sys->OREAD); + if(fd == nil) + return; + fds := 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); +} diff --git a/os/init/ipaqinit.b b/os/init/ipaqinit.b new file mode 100644 index 00000000..40ddd529 --- /dev/null +++ b/os/init/ipaqinit.b @@ -0,0 +1,697 @@ +# +# ipaq +# +# TO DO: read params from params flash +# + +implement Init; + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "keyring.m"; + kr: Keyring; + +include "security.m"; + auth: Auth; + +include "dhcp.m"; + dhcpclient: Dhcpclient; + Bootconf: import dhcpclient; + +include "keyboard.m"; + +include "sh.m"; + +Init: module +{ + init: fn(); +}; + +Bootpreadlen: con 128; + +ethername := "ether0"; + +# standard Inferno flash partitions + +flashparts := array[] of { + # bootstrap at 0x0 to 0x40000, don't touch + "add params 0x40000 0x80000", + "add kernel 0x80000 0x140000", + "add fs 0x140000 end", +}; + +# +# 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); + + lightup(); + + 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 + dobind("#c", "/dev", sys->MREPL); # console + sys->bind("#d", "/fd", Sys->MREPL); + dobind("#t", "/dev", sys->MAFTER); # serial line + dobind("#i", "/dev", sys->MAFTER); # draw + dobind("#m", "/dev", Sys->MAFTER); # pointer + sys->bind("#e", "/env", sys->MREPL|sys->MCREATE); # environment + sys->bind("#A", "/dev", Sys->MAFTER); # optional audio + dobind("#T","/dev",sys->MAFTER); # touch screen and other ipaq devices + + 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("ipaq"); # 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); + } + calibrate(); + 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 := rdenv("user", "inferno"); + (ok, nil) := sys->stat("/dis/wm/wm.dis"); + if(ok >= 0) + (ok, nil) = sys->stat("/dis/wm/logon.dis"); + if(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", "-n", "lib/ipaqns", "-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)); +} + +lightup() +{ + # backlight + fd := sys->open("#T/ipaqctl", Sys->OWRITE); + if(fd != nil) + sys->fprint(fd, "light 1 1 0x80"); +} + +# +# 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; + } +Query: + for(;;) { + s := ""; + if (tried == 0 && (s = rdenv("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 + } + case s[0] { + Keyboard->Right or Keyboard->Left => + sources = append(hd sources, tl sources); + sys->print("\n"); + continue Query; + Keyboard->Down => + s = hd sources; + sys->print(" %s\n", s); + } + (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; +} + +append(v: string, l: list of string): list of string +{ + if(l == nil) + return v :: nil; + return hd l :: append(v, tl l); +} + +# +# serve local DOS or kfs file system using flash translation layer +# +lfs(): int +{ + if(!flashpart("#F/flash/flashctl", flashparts)) + return -1; + if(!ftlinit("#F/flash/fs")) + return -1; + if(iskfs("#X/ftldata")) + return lkfs("#X/ftldata"); + c := chan of string; + spawn startfs(c, "/dis/dossrv.dis", "dossrv" :: "-f" :: "#X/ftldata" :: "-m" :: "/n/local" :: nil, nil); + if(<-c != nil) + return -1; + return 0; +} + +wmagic := "kfs wren device\n"; + +iskfs(file: string): int +{ + fd := sys->open(file, Sys->OREAD); + if(fd == nil) + return 0; + buf := array[512] of byte; + n := sys->read(fd, buf, len buf); + if(n < len buf) + return 0; + if(string buf[256:256+len wmagic] != wmagic) + return 0; + RBUFSIZE := int string buf[256+len wmagic:256+len wmagic+12]; + if(RBUFSIZE % 512) + return 0; # bad block size + return 1; +} + +lkfs(file: string): int +{ + p := array[2] of ref Sys->FD; + if(sys->pipe(p) < 0) + return -1; + c := chan of string; + spawn startfs(c, "/dis/disk/kfs.dis", "disk/kfs" :: "-A" :: "-n" :: "main" :: file :: nil, p[0]); + if(<-c != nil) + return -1; + p[0] = nil; + return sys->mount(p[1], nil, "/n/local", Sys->MREPL|Sys->MCREATE, nil); +} + +startfs(c: chan of string, file: string, args: list of string, fd: ref Sys->FD) +{ + if(fd != nil){ + sys->pctl(Sys->NEWFD, fd.fd :: 1 :: 2 :: nil); + sys->dup(fd.fd, 0); + } + fs := load Command file; + if(fs == nil){ + sys->print("can't load %s: %r\n", file); + c <-= "load failed"; + } + { + fs->init(nil, args); + c <-= nil; + }exception { + "*" => + c <-= "failed"; + * => + c <-= "unknown exception"; + } +} + +# +# 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 +{ + 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; + } + } + server := rdenv("fsip", nil); + if((ip := rdenv("ip", nil)) != nil) { + sys->print("**using %s\n", ip); + sys->fprint(fd, "bind ether /net/ether0"); + sys->fprint(fd, "add %s ", ip); + if((ipgw := rdenv("ipgw", nil)) != nil){ + rfd := sys->open("/net/iproute", Sys->OWRITE); + if(rfd != nil){ + sys->fprint(rfd, "add 0 0 %s", ipgw); + sys->print("**using ipgw=%s\n", ipgw); + } + } + }else if(server == nil){ + sys->print("dhcp..."); + dhcpclient = load Dhcpclient Dhcpclient->PATH; + if(dhcpclient == nil){ + sys->print("can't load dhcpclient: %r\n"); + return -1; + } + dhcpclient->init(); + (cfg, nil, e) := dhcpclient->dhcp("/net", fd, "/net/ether0/addr", nil, nil); + if(e != nil){ + sys->print("dhcp: %s\n", e); + return -1; + } + if(server == nil) + server = cfg.getip(Dhcpclient->OP9fs); + dhcpclient = nil; + } + if(server == nil || server == "0.0.0.0"){ + sys->print("no file server address\n"); + return -1; + } + sys->print("fs=%s\n", server); + + 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; +} + +calibrate() +{ + val := rf("/nvfs/calibrate", nil); + if(val != nil){ + fd := sys->open("/dev/touchctl", Sys->OWRITE); + if(fd != nil && sys->fprint(fd, "%s", val) >= 0) + return; + } + done := chan of int; + spawn docal(done); + <-done; +} + +docal(done: chan of int) +{ + sys->pctl(Sys->FORKFD, nil); + ofd := sys->create("/nvfs/calibrate", Sys->OWRITE, 8r644); + if(ofd != nil) + sys->dup(ofd.fd, 1); + cal := load Command "/dis/touchcal.dis"; + if(cal != nil){ + { + cal->init(nil, "touchcal" :: nil); + }exception{ + "fail:*" => + ; + } + } + done <-= 1; +} + +userok(user: string): int +{ + (ok, d) := sys->stat("/usr/"+user); + return ok >= 0 && (d.mode & Sys->DMDIR) != 0; +} + +rdenv(name: string, def: string): string +{ + s := rf("#e/"+name, nil); + if(s != nil) + return s; + s = rf("/nvfs/"+name, def); + while(s != nil && ((c := s[len s-1]) == '\n' || c == '\r')) + s = s[0: len s-1]; + if(s != nil) + return s; + return def; +} + +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; +} diff --git a/os/init/ipeinit.b b/os/init/ipeinit.b new file mode 100644 index 00000000..7182ded3 --- /dev/null +++ b/os/init/ipeinit.b @@ -0,0 +1,620 @@ +# +# ipEngine-1 +# + +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 { + # bootstrap at 0x0 to 0x6000 + "add boot 0 0x6000", + "add param 0x6000 0x10000", + "add kernel 0x10000 0x110000", + "add fs 0x110000 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("ipe"); # 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 || (ip = rf("#e/myip", nil)) != nil) { + sys->print("**using %s\n", ip); + sys->fprint(fd, "bind ether /net/ether0"); + sys->fprint(fd, "add %s %s", ip, rf("#e/netmask", nil)); + gate := rf("#e/gateway", nil); + if(gate != nil){ + rfd := sys->open("/net/iproute", Sys->OWRITE); + if(rfd != nil){ + sys->fprint(rfd, "add 0 0 %s", gate); + sys->print("set gateway %s\n", gate); + } + } + } 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) + server = rf("#e/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; +} diff --git a/os/init/jsinit.b b/os/init/jsinit.b new file mode 100644 index 00000000..a8c9cc68 --- /dev/null +++ b/os/init/jsinit.b @@ -0,0 +1,213 @@ +implement Init; +# +# init program for standalone wm using TK +# +include "sys.m"; +sys: Sys; + FD, Connection, sprint, Dir: import sys; + print, fprint, open, bind, mount, dial, sleep, read: import sys; + +include "draw.m"; + draw: Draw; + Context: import draw; + +include "keyring.m"; + kr: Keyring; + +include "security.m"; + auth: Auth; + +Init: module +{ + init: fn(); +}; + +Logon: module +{ + init: fn(ctxt: ref Context, argv: list of string); +}; + +rootfs(server: string): int +{ + ok, n: int; + c: Connection; + + (ok, c) = dial("tcp!" + server + "!6666", nil); + if(ok < 0) + return -1; + + sys->print("Connected ..."); + 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 = mount(c.dfd, nil, "/", sys->MREPL, ""); + if(n > 0) + return 0; + return -1; +} + +Bootpreadlen: con 128; + +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"); + + sys->print("Setup boot net services ...\n"); + + # + # Setup what we need to call a server and + # Authenticate + # + bind("#l", "/net", sys->MREPL); + bind("#I", "/net", sys->MAFTER); + bind("#c", "/dev", sys->MAFTER); + bind("#r", "/dev", sys->MAFTER); + nvramfd := sys->open("#r/nvram", sys->ORDWR); + if(nvramfd != nil){ + spec = "#Fnvram"; + if(bind(spec, "/nvfs", sys->MAFTER) < 0) + print("init: bind %s: %r\n", spec); + nvramfd = nil; + } + + setsysname(); + + sys->print("bootp..."); + + fd := open("/net/ipifc/clone", sys->OWRITE); + if(fd == nil) { + print("init: open /net/ipifc/clone: %r\n"); + exit; + } + cfg := array of byte "bind ether ether"; + if(sys->write(fd, cfg, len cfg) != len cfg) { + sys->print("could not bind interface: %r\n"); + exit; + } + cfg = array of byte "bootp"; + if(sys->write(fd, cfg, len cfg) != len cfg) { + sys->print("could not bootp: %r\n"); + exit; + } + + fd = open("/net/bootp", sys->OREAD); + if(fd == nil) { + print("init: open /net/bootp: %r"); + exit; + } + + buf := array[Bootpreadlen] of byte; + nr := read(fd, buf, len buf); + fd = nil; + if(nr <= 0) { + 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) { + print("init: server address not in bootp read"); + exit; + } + + srv := hd ls; + sys->print("server %s\nConnect ...\n", srv); + + while(rootfs(srv) < 0) + sleep(1000); + + sys->print("done\n"); + + # + # default namespace + # + bind("#c", "/dev", sys->MBEFORE); # console + bind("#r", "/dev", sys->MAFTER); + if(spec != nil) + bind(spec, "/nvfs", sys->MBEFORE|sys->MCREATE); # our keys + bind("#l", "/net", sys->MBEFORE); # ethernet + bind("#I", "/net", sys->MBEFORE); # TCP/IP + bind("#p", "/prog", sys->MREPL); # prog device + sys->bind("#d", "/fd", Sys->MREPL); + + sys->print("clock...\n"); + setclock(); + + sys->print("logon...\n"); + + logon := load Logon "/dis/wm/logon.dis"; + if(logon == nil) { + print("init: load /dis/wm/logon.dis: %r"); + exit; + } + dc: ref Context; + spawn logon->init(dc, nil); +} + +setclock() +{ + (ok, dir) := sys->stat("/"); + if (ok < 0) { + print("init: stat /: %r"); + return; + } + + fd := sys->open("/dev/time", sys->OWRITE); + if (fd == nil) { + print("init: open /dev/time: %r"); + return; + } + + # Time is kept as microsecs, atime is in secs + b := array of byte sprint("%d000000", dir.atime); + if (sys->write(fd, b, len b) != len b) + print("init: write /dev/time: %r"); +} + +# +# Set system name from nvram +# +setsysname() +{ + fd := open("/nvfs/ID", sys->OREAD); + if(fd == nil) + return; + fds := 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); +} diff --git a/os/init/mkfile b/os/init/mkfile new file mode 100644 index 00000000..e027809d --- /dev/null +++ b/os/init/mkfile @@ -0,0 +1,27 @@ +<../../mkconfig + +OBJ=\ + wminit.dis\ + +all:V: $OBJ +install:V: all +installall:V: all + +clean nuke:V: + rm -f *.dis *.sbl + +INCLD=\ + -I$ROOT/module\ + +%.dis: %.b + limbo $INCLD -gw $stem.b + +%.s: %.b + limbo $INCLD -w -G -S $stem.b + +ir%.dis: ../../appl/lib/ir%.b + limbo $INCLD -gw $prereq + +ir%.s: ../../appl/lib/ir%.b + limbo $INCLD -w -G -S $prereq + diff --git a/os/init/mpcinit.b b/os/init/mpcinit.b new file mode 100644 index 00000000..bef89fa2 --- /dev/null +++ b/os/init/mpcinit.b @@ -0,0 +1,383 @@ +implement Init; +# +# init program for Motorola 800 series (serial console only) +# +include "sys.m"; + sys: Sys; + +include "draw.m"; + draw: Draw; + +include "keyring.m"; + kr: Keyring; + +include "security.m"; + auth: Auth; + +Init: module +{ + init: fn(); +}; + +Shell: module +{ + init: fn(ctxt: ref Draw->Context, argv: list of string); +}; + +Bootpreadlen: con 128; + +# option switches +UseLocalFS: con 1<<0; +EtherBoot: con 1<<1; +Prompting: con 1<<3; + +lfs(): int +{ + if(!ftlinit("#F/flash/flash", 1024*1024, 1024*1024)) + return -1; + if(mountkfs("#X/ftldata", "main", "flash") < 0) + return -1; + if(sys->bind("#Kmain", "/n/local", sys->MREPL) < 0){ + sys->print("can't bind #Kmain to /n/local: %r\n"); + return -1; + } + if(sys->bind("/n/local", "/", Sys->MCREATE|Sys->MREPL) < 0){ + sys->print("can't bind /n/local after /: %r\n"); + return -1; + } + return 0; +} + +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", "/net/ether0") < 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(sys->fprint(fd, "bootp") < 0){ + sys->print("init: bootp failed: %r\n"); + return -1; + } + + server := bootp(); + if(server == nil) + 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; +} + +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"); + + optsw := options(); + sys->print("Switch options: 0x%ux\n", optsw); + + # + # 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); + + fsready := 0; + mountpt := "/"; + usertc := 0; + + if((optsw & Prompting) == 0){ + if(optsw & UseLocalFS){ + sys->print("Option: use local file system\n"); + if(lfs() == 0){ + fsready = 1; + mountpt = "/n/remote"; + } + } + + if(optsw & EtherBoot){ + sys->print("Attempting remote mount\n"); + if(netfs(mountpt) == 0) + fsready = 1; + } + } + + if(fsready == 0){ + + sys->print("\n\n"); + + stdin := sys->fildes(0); + buf := array[128] of byte; + sources := "fs" :: "net" :: nil; + + loop: for(;;) { + 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); + + n := sys->read(stdin, buf, len buf); + if(n <= 0) + continue; + if(buf[n-1] == byte '\n') + n--; + + (nil, choice) := sys->tokenize(string buf[0:n], "\t "); + + if(choice == nil) + choice = sources; + opt := hd choice; + case opt { + * => + sys->print("\ninvalid boot option: '%s'\n", opt); + break; + "fs" or "" => + if(lfs() == 0){ + usertc = 1; + break loop; + } + "net" => + if(netfs("/") == 0) + break loop; + } + } + } + + # + # default namespace + # + sys->unmount(nil, "/dev"); + sys->bind("#c", "/dev", sys->MBEFORE); # console + sys->bind("#l", "/net", sys->MBEFORE); # ethernet + sys->bind("#I", "/net", sys->MBEFORE); # TCP/IP + sys->bind("#p", "/prog", sys->MREPL); # prog device + sys->bind("#d", "/fd", Sys->MREPL); + + setsysname(); + + sys->print("clock...\n"); + setclock(usertc, mountpt); + + sys->print("Console...\n"); + + shell := load Shell "/dis/sh.dis"; + if(shell == nil) { + sys->print("init: load /dis/sh.dis: %r"); + exit; + } + dc: ref Draw->Context; + shell->init(dc, nil); +} + +setclock(usertc: int, timedir: string) +{ + now := 0; + if(usertc){ + fd := sys->open("#r/rtc", Sys->OREAD); + if(fd != nil){ + b := array[64] of byte; + n := sys->read(fd, b, len b-1); + if(n > 0){ + b[n] = byte 0; + now = int string b; + if(now <= 16r20000000) + now = 0; # rtc itself is not initialised + } + } + } + if(now == 0){ + (ok, dir) := sys->stat(timedir); + if (ok < 0) { + sys->print("init: stat %s: %r", timedir); + return; + } + now = dir.atime; + } + fd := sys->open("/dev/time", sys->OWRITE); + if (fd == nil) { + sys->print("init: can't open /dev/time: %r"); + return; + } + + # Time is kept as microsecs, atime is in secs + b := array of byte sys->sprint("%ud000000", now); + if (sys->write(fd, b, len b) != len b) + sys->print("init: can't 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); +} + +# +# fetch options from switch DS2 +# +options(): int +{ + fd := sys->open("#r/switch", Sys->OREAD); + if(fd == nil){ + sys->print("can't open #r/switch: %r\n"); + return 0; + } + b := array[20] of byte; + n := sys->read(fd, b, len b); + s := string b[0:n]; + return int s; +} + +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; +} + +# +# set up flash translation layer +# +ftldone := 0; + +ftlinit(flashmem: string, offset: int, length: int): int +{ + if(ftldone) + return 1; + sys->print("Set flash translation of %s at offset %d (%d bytes)\n", flashmem, offset, length); + 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 %ud %ud", flashmem, offset, length) <= 0){ + sys->print("can't init flash translation: %r"); + return 0; + } + ftldone = 1; + return 1; +} + +# +# Mount kfs filesystem +# +mountkfs(devname: string, fsname: string, options: string): int +{ + fd := sys->open("#Kcons/kfsctl", sys->OWRITE); + if(fd == nil) { + sys->print("could not open #Kcons/kfsctl: %r\n"); + return -1; + } + if(sys->fprint(fd, "filsys %s %s %s", fsname, devname, options) <= 0){ + sys->print("could not write #Kcons/kfsctl: %r\n"); + return -1; + } + if(options == "ro") + sys->fprint(fd, "cons flashwrite"); + return 0; +} diff --git a/os/init/pcdemo.b b/os/init/pcdemo.b new file mode 100644 index 00000000..5a7ec76b --- /dev/null +++ b/os/init/pcdemo.b @@ -0,0 +1,273 @@ +# +# Init shell ``with the kitchen sink'', for development purposes. +# +implement InitShell; + +include "sys.m"; +include "draw.m"; + +sys: Sys; +FD, Connection, sprint, Dir: import sys; +print, fprint, open, bind, mount, dial, sleep, read: import sys; + +stderr: ref sys->FD; # standard error FD + +InitShell: module +{ + init: fn(nil: ref Draw->Context, nil: list of string); +}; + +Sh: module +{ + init: fn(ctxt: ref Draw->Context, argv: list of string); +}; + +init(nil: ref Draw->Context, nil: list of string) +{ + sys = load Sys Sys->PATH; + stderr = sys->fildes(2); + + sys->print("Welcome to Inferno...\n"); + + sys->pctl(Sys->NEWNS, nil); + if (imount("/n/remote")) { + bind("/n/remote", "/", sys->MAFTER); + bind("/n/remote/dis", "/dis", sys->MBEFORE); + mountkfs("#W/flash0fs", "fs", "/n/local", sys->MREPL); + } + else { + # bind("#U/pcdemo", "/", sys->MREPL); + # mountkfs("#U/pcdemo.kfs", "fs", "/", sys->MBEFORE); + # bind("#U/pcdemo/usr", "/usr", sys->MAFTER); + mountkfs("#R/ramdisk", "fs", "/", sys->MBEFORE); + bind("/services", "/data", sys->MREPL|sys->MCREATE); + } + + namespace(); + srv(); + + if (1) { + bind("/icons/oldlogon.bit", "/icons/logon.bit", sys->MREPL); + bind("/icons/tk/oldinferno.bit", "/icons/tk/inferno.bit", sys->MREPL); + } + + sys->print("starting shell (type wm/logon or wm/wmcp)\n"); + shell := sysenv("shell"); + if (shell == nil) + shell = "/dis/sh.dis"; + sh := load Sh shell; + spawn sh->init(nil, nil); +} + +namespace() +{ + # Bind anything useful we can get our hands on. Ignore errors. + sys->print("namespace...\n"); + sys->bind("#I", "/net", sys->MAFTER); # IP + sys->bind("#I1", "/net.alt", sys->MREPL); # second IP for PPP tests + sys->bind("#p", "/prog", sys->MREPL); # prog device + sys->bind("#d", "/fd", Sys->MREPL); + sys->bind("#i", "/dev", sys->MREPL); # draw device + sys->bind("#t", "/dev", sys->MAFTER); # serial line + sys->bind("#c", "/dev", sys->MAFTER); # console device + sys->bind("#W", "/dev", sys->MAFTER); # Flash + sys->bind("#O", "/dev", sys->MAFTER); # Modem + sys->bind("#T", "/dev", sys->MAFTER); # Touchscreen + sys->bind("#H", "/dev", sys->MAFTER); # Ata disk device + sys->bind("#b", "/dev", sys->MAFTER); # debug device + sys->bind("#c", "/chan", sys->MREPL); + sys->bind("/data", "/usr/inferno", sys->MREPL|sys->MCREATE); + sys->bind("/data", "/usr/charon", sys->MREPL|sys->MCREATE); + sys->bind("/data", "/usr/shaggy", sys->MREPL|sys->MCREATE); +} + +mountkfs(devname: string, fsname: string, where: string, flags: int): int +{ + sys->print("mount kfs...\n"); + fd := sys->open("#Kcons/kfsctl", sys->OWRITE); + if (fd == nil) { + sys->fprint(stderr, "could not open #Kcons/kfsctl: %r\n"); + return 0; + } + kfsopt := ""; + kfsrw := sysenv("kfsrw"); +# if (kfsrw != "1") +# kfsopt = " ronly"; + b := array of byte ("filsys " + fsname + " " + devname + kfsopt); + if (sys->write(fd, b, len b) < 0) { + sys->fprint(stderr, "could not write #Kcons/kfsctl: %r\n"); + return 0; + } + if (sys->bind("#K" + fsname, where, flags) < 0) { + sys->fprint(stderr, "could not bind %s to %s: %r\n", "#K" + fsname, where); + return 0; + } + return 1; +} + +dialfs(server: string, where: string): int +{ + ok, n: int; + c: Connection; + + (ok, c) = dial("tcp!" + server + "!6666", nil); + if(ok < 0) + return 0; + + sys->print("mount..."); + + c.cfd = nil; + n = mount(c.dfd, where, sys->MREPL, ""); + if(n > 0) + return 1; + sys->print("mount failed: %r\n"); + return 0; +} + +Bootpreadlen: con 128; + +imount(where: string): int +{ + sys->print("bootp..."); + if (sys->bind("#I", "/net", sys->MREPL) < 0) { + sys->fprint(stderr, "could not bind ip device: %r\n"); + return 0; + } + if (sys->bind("#l", "/net", sys->MAFTER) < 0) { + sys->fprint(stderr, "could not bind ether device: %r\n"); + return 0; + } + + fd := sys->open("/net/ipifc/clone", sys->OWRITE); + if(fd == nil) { + sys->print("init: open /net/ipifc: %r"); + return 0; + } + + cfg := array of byte "bind ether ether0"; + if(sys->write(fd, cfg, len cfg) != len cfg) { + sys->fprint(stderr, "could not bind interface: %r\n"); + return 0; + } + cfg = array of byte "bootp"; + if(sys->write(fd, cfg, len cfg) != len cfg) { + sys->fprint(stderr, "could not bootp: %r\n"); + return 0; + } + + bfd := sys->open("/net/bootp", sys->OREAD); + if(bfd == nil) { + sys->print("init: can't open /net/bootp: %r"); + return 0; + } + + buf := array[Bootpreadlen] of byte; + nr := sys->read(bfd, buf, len buf); + bfd = nil; + if(nr <= 0) { + sys->print("init: read /net/bootp: %r"); + return 0; + } + + (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 0; + } + + server := hd ls; + sys->print("imount: server %s\n", server); + + return dialfs(server, where); +} + +srv() +{ + remotedebug := sysenv("remotedebug"); + if(remotedebug != "1") + return; + remotespeed := sysenv("remotespeed"); + if (remotespeed == nil) + remotespeed = "38400"; + + sys->print("srv..."); + if(echoto("#t/eia0ctl", "b" + remotespeed) < 0) + return; + + fd := sys->open("/dev/eia0", Sys->ORDWR); + if (fd == nil) { + sys->print("eia data open: %r\n"); + return; + } + if (sys->export(fd, Sys->EXPASYNC) < 0) { + sys->print("export: %r\n"); + return; + } + sys->print("ok\n"); +} + +sysenv(param: string): string +{ + fd := sys->open("#c/sysenv", sys->OREAD); + if (fd == nil) + return(nil); + buf := array[4096] of byte; + nb := sys->read(fd, buf, len buf); + (nfl,fl) := sys->tokenize(string buf, "\n"); + while (fl != nil) { + pair := hd fl; + (npl, pl) := sys->tokenize(pair, "="); + if (npl > 1) { + if ((hd pl) == param) + return hd tl pl; + } + fl = tl fl; + } + return nil; +} + +echoto(fname, str: string): int +{ + fd := sys->open(fname, Sys->OWRITE); + if(fd == nil) { + sys->print("%s: %r\n", fname); + return -1; + } + x := array of byte str; + if(sys->write(fd, x, len x) == -1) { + sys->print("write: %r\n"); + return -1; + } + return 0; +} + +hang() +{ + c := chan of int; + <- c; +} + +# +# Set system name from nvram +# +setsysname() +{ + fd := open("/nvfs/ID", sys->OREAD); + if(fd == nil) + return; + fds := 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); +} 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; +} diff --git a/os/init/reminit.b b/os/init/reminit.b new file mode 100644 index 00000000..b87ff996 --- /dev/null +++ b/os/init/reminit.b @@ -0,0 +1,239 @@ +implement Init; +# +# init program for standalone remote pc kernel - for benchmarking +# +include "sys.m"; +sys: Sys; +FD, Connection, sprint, Dir: import sys; +print, fprint, open, bind, mount, dial, sleep, read, chdir: import sys; + +include "draw.m"; +draw: Draw; +Context: import draw; + +include "keyring.m"; +kr: Keyring; + +include "security.m"; +auth: Auth; + +Init: module +{ + init: fn(); +}; + +Shell: module +{ + init: fn(ctxt: ref Context, argv: list of string); +}; + +remotefs(server: string): int +{ + ok, n: int; + c: Connection; + + (ok, c) = dial("tcp!" + server + "!6666", nil); + if(ok < 0) + return -1; + + sys->print("Connected ...\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 ...\n"); + + c.cfd = nil; + n = mount(c.dfd, "/n/remote", sys->MREPL, ""); + if(n > 0) + return 0; + return -1; +} + +Bootpreadlen: con 128; + +bootp(): string +{ +# +# BUG: if bootp fails, can't then use "add ether" correctly +# + fd := open("/net/ipifc", sys->OWRITE); + if(fd == nil) { + print("init: open /net/ipifc: %r"); + return nil; + } + fprint(fd, "bootp /net/ether0"); + + fd = open("/net/bootp", sys->OREAD); + if(fd == nil) { + print("init: open /net/bootp: %r\n"); + return nil; + } + + buf := array[Bootpreadlen] of byte; + nr := read(fd, buf, len buf); + fd = nil; + if(nr > 0) { + (ntok, ls) := sys->tokenize(string buf, " \t\n"); + while(ls != nil) { + if(hd ls == "fsip") { + ls = tl ls; + break; + } + ls = tl ls; + } + srv : string; + if(ls == nil || ((srv = hd ls) == "0.0.0.0")) { + print("init: server address not in bootp read\n"); + return nil; + } + return srv; + } + return nil; +} + +init() +{ + + sys = load Sys Sys->PATH; + stdin := sys->fildes(0); + 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 + # + sys->print("Bind ethernet ...\n"); + bind("#l", "/net", sys->MREPL); + sys->print("Bind IP ...\n"); + bind("#I", "/net", sys->MAFTER); + sys->print("Bind console ...\n"); + bind("#c", "/dev", sys->MAFTER); + + setsysname(); + if (1) { + print("bootp ...\n"); + srv := bootp(); + if (srv != nil) + if (remotefs(srv) < 0) + print("No remote filesystem\n"); + else { + print("Remote filesystem mounted\n"); + bind("/n/remote/dis", "/dis", sys->MBEFORE); + bind("/n/remote/dis/lib", "/dis/lib", sys->MBEFORE); + } + } else { + print("Standalone mode\n"); + fd := open("/net/ipifc", sys->OWRITE); + if(fd == nil) { + print("init: open /net/ipifc: %r"); + exit; + } + fprint(fd, "add ether /net/ether0 %s %s", "200.1.1.60", "255.255.255.0"); + fd = nil; + } + # + # default namespace + # + sys->unmount(nil, "/dev"); + bind("#c", "/dev", sys->MBEFORE); # console + bind("#l", "/net", sys->MBEFORE); # ethernet + bind("#I", "/net", sys->MBEFORE); # TCP/IP + bind("#p", "/prog", sys->MREPL); # prog device + sys->bind("#d", "/fd", Sys->MREPL); + + bind("#T", "/dev", sys->MBEFORE); # kprof device + bind("#x", "/dev", sys->MBEFORE); # bench device + + print("clock...\n"); + setclock(); + + print("Server...\n"); + dc: ref Context; + cs := load Shell "/dis/ndb/cs.dis"; + if(cs == nil) + print("Server not loaded\n"); + else + cs->init(dc, "cs" :: nil); + server := load Shell "/dis/lib/srv.dis"; + if(server == nil) + print("Server not loaded\n"); + else { +# server->init(dc, "srv" :: nil); + } + + print("Console...\n"); +sys->chdir("/n/remote/usr/john/appl/bench"); + shell := load Shell "/dis/sh.dis"; + if(shell == nil) { + print("init: load /dis/sh.dis: %r"); + exit; + } + shell->init(dc, nil); +} + +setclock() +{ + (ok, dir) := sys->stat("/"); + if (ok < 0) { + print("init: stat /: %r"); + return; + } + + fd := sys->open("/dev/time", sys->OWRITE); + if (fd == nil) { + print("init: open /dev/time: %r"); + return; + } + + # Time is kept as microsecs, atime is in secs + b := array of byte sprint("%d000000", dir.atime); + if (sys->write(fd, b, len b) != len b) + print("init: write /dev/time: %r"); +} + +# +# Set system name from nvram +# +setsysname() +{ + fd := open("/nvfs/ID", sys->OREAD); + if(fd == nil) + return; + fds := 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); +} + +readline(fd: ref Sys->FD): string +{ + l := array [128] of byte; + nb := sys->read(fd, l, len l); + if(nb <= 1) + return ""; + return string l[0:nb-1]; +} + 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; +} diff --git a/os/init/shell.b b/os/init/shell.b new file mode 100644 index 00000000..e0b19ec9 --- /dev/null +++ b/os/init/shell.b @@ -0,0 +1,97 @@ +implement InitShell; + +include "sys.m"; +include "draw.m"; + +sys: Sys; + +InitShell: module +{ + init: fn(nil: ref Draw->Context, nil: list of string); +}; + +Sh: module +{ + init: fn(ctxt: ref Draw->Context, argv: list of string); +}; + +init(nil: ref Draw->Context, nil: list of string) +{ + shell := load Sh "/dis/sh.dis"; + + sys = load Sys Sys->PATH; + + if(sys != nil) + sys->print("init: starting shell\n"); + +# sys->bind("#I", "/net", sys->MAFTER); # IP + sys->bind("#p", "/prog", sys->MREPL); # prog device + sys->bind("#d", "/fd", Sys->MREPL); + sys->bind("#i", "/dev", sys->MREPL); # draw device + sys->bind("#t", "/dev", sys->MAFTER); # serial line + sys->bind("#c", "/dev", sys->MAFTER); # console device + sys->bind("#W","/dev",sys->MAFTER); # Flash +# sys->bind("#O", "/dev", sys->MAFTER); # Modem +# sys->bind("#T","/dev",sys->MAFTER); # Touchscreen + + srv(); + + spawn shell->init(nil, nil); +} + +srv() +{ + remotedebug := sysenv("remotedebug"); + if(remotedebug != "1") + return; + + sys->print("srv..."); + if(echoto("#t/eia0ctl", "b38400") < 0) + return; + + fd := sys->open("/dev/eia0", Sys->ORDWR); + if (fd == nil) { + sys->print("eia data open: %r\n"); + return; + } + if (sys->export(fd, "/", Sys->EXPASYNC) < 0) { + sys->print("export: %r\n"); + return; + } + sys->print("ok\n"); +} + +sysenv(param: string): string +{ + fd := sys->open("#c/sysenv", sys->OREAD); + if (fd == nil) + return(nil); + buf := array[4096] of byte; + nb := sys->read(fd, buf, len buf); + (nfl,fl) := sys->tokenize(string buf, "\n"); + while (fl != nil) { + pair := hd fl; + (npl, pl) := sys->tokenize(pair, "="); + if (npl > 1) { + if ((hd pl) == param) + return hd tl pl; + } + fl = tl fl; + } + return nil ; +} + +echoto(fname, str: string): int +{ + fd := sys->open(fname, Sys->OWRITE); + if(fd == nil) { + sys->print("%s: %r\n", fname); + return -1; + } + x := array of byte str; + if(sys->write(fd, x, len x) == -1) { + sys->print("write: %r\n"); + return -1; + } + return 0; +} diff --git a/os/init/soeinit.b b/os/init/soeinit.b new file mode 100644 index 00000000..cae7f5bd --- /dev/null +++ b/os/init/soeinit.b @@ -0,0 +1,613 @@ +# +# Soekris 4501 +# + +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 { +# # bootstrap at 0x0 to 0x20000 +# "add script 0x20000 0x40000", +# "add kernel 0x100000 0x200000", +# "add fs 0x200000 end", +#}; +flashparts: array of string; + +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; + scale := 1; + cfd := sys->open("/dev/consctl", Sys->OWRITE); + if(cfd != nil) + sys->fprint(cfd, "rawon"); + for(;;){ + (rootsource, timefile, scale) = 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("soe"); # set system name + + now := getclock(timefile, rootsource); + if(scale == 1) + now *= big 1000000; + 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, int) +{ + 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", 1); + "local" => + return ("/n/local", "#r/rtc", 1); + "local+remote" => + if(netfs("/n/remote") >= 0) + return ("/n/local", "/n/remote/dev/time", 1000000); + "remote" => + if(netfs("/n/remote") >= 0) + return ("/n/remote", "/n/remote/dev/time", 1000000); + } + } +} + +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; +} diff --git a/os/init/srvinit.b b/os/init/srvinit.b new file mode 100644 index 00000000..2c1c1b69 --- /dev/null +++ b/os/init/srvinit.b @@ -0,0 +1,209 @@ +implement Init; +# +# init program for standalone wm using TK +# +include "sys.m"; +sys: Sys; + FD, Connection, sprint, Dir: import sys; + print, fprint, open, bind, mount, dial, sleep, read: import sys; + +include "security.m"; + auth: Auth; + +include "draw.m"; + draw: Draw; + Context: import draw; + +include "keyring.m"; + kr: Keyring; + +Init: module +{ + init: fn(); +}; + +Command: module +{ + init: fn(ctxt: ref Context, argv: list of string); +}; + +rootfs(server: string): int +{ + ok, n: int; + c: Connection; + + (ok, c) = dial("tcp!" + server + "!6666", nil); + if(ok < 0) { + sys->print("cannot connected to %s: %r\n", server); + return -1; + } + + sys->print("Connected ..."); + 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 = mount(c.dfd, "/", sys->MREPL, ""); + if(n > 0) + return 0; + return -1; +} + +Bootpreadlen: con 128; + +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"); + + sys->print("Setup boot net services ...\n"); + + # + # Setup what we need to call a server and + # Authenticate + # + bind("#l", "/net", sys->MREPL); + bind("#I", "/net", sys->MAFTER); + bind("#c", "/dev", sys->MAFTER); + bind("#H", "/dev", sys->MAFTER); + nvramfd := sys->open("#H/hd0nvram", sys->ORDWR); + if(nvramfd != nil){ + spec = "#Fhd0nvram"; + if(bind(spec, "/nvfs", sys->MAFTER) < 0) + print("init: bind %s: %r\n", spec); + } + + setsysname(); + + sys->print("bootp..."); + + fd := open("/net/ipifc/clone", sys->OWRITE); + if(fd == nil) { + print("init: open /net/ipifc/clone: %r\n"); + exit; + } + cfg := array of byte "bind ether ether0"; + if(sys->write(fd, cfg, len cfg) != len cfg) { + sys->print("could not bind interface: %r\n"); + exit; + } + cfg = array of byte "bootp"; + if(sys->write(fd, cfg, len cfg) != len cfg) { + sys->print("could not bootp: %r\n"); + exit; + } + + fd = open("/net/bootp", sys->OREAD); + if(fd == nil) { + print("init: open /net/bootp: %r"); + exit; + } + + buf := array[Bootpreadlen] of byte; + nr := read(fd, buf, len buf); + fd = nil; + if(nr <= 0) { + 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) { + print("init: server address not in bootp read"); + exit; + } + + srv := hd ls; + sys->print("server %s\nConnect ...\n", srv); + + retrycount := 0; + while(rootfs(srv) < 0 && retrycount++ < 5) + sleep(1000); + + sys->print("done\n"); + + # + # default namespace + # + bind("#c", "/dev", sys->MREPL); # console + bind("#l", "/net", sys->MREPL); # ethernet + bind("#I", "/net", sys->MBEFORE); # TCP/IP + bind("#p", "/prog", sys->MREPL); # prog device + sys->bind("#d", "/fd", Sys->MREPL); + + sys->print("clock...\n"); + setclock(); + + sys->print("sh...\n"); + sh := load Command "/dis/sh.dis"; + if (sh == nil) + print("cannot load /dis/sh.dis: %r\n"); + + sh->init(nil, "sh" :: "-i" :: nil); +} + +setclock() +{ + (ok, dir) := sys->stat("/"); + if (ok < 0) { + print("init: stat /: %r"); + return; + } + + fd := sys->open("/dev/time", sys->OWRITE); + if (fd == nil) { + print("init: open /dev/time: %r"); + return; + } + + # Time is kept as microsecs, atime is in secs + b := array of byte sprint("%d000000", dir.atime); + if (sys->write(fd, b, len b) != len b) + print("init: write /dev/time: %r"); +} + +# +# Set system name from nvram +# +setsysname() +{ + fd := open("/nvfs/ID", sys->OREAD); + if(fd == nil) + return; + fds := 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); +} diff --git a/os/init/wminit.b b/os/init/wminit.b new file mode 100644 index 00000000..89312ec2 --- /dev/null +++ b/os/init/wminit.b @@ -0,0 +1,231 @@ +implement Init; +# +# init program for standalone wm using TK +# +include "sys.m"; +sys: Sys; + FD, Connection, sprint, Dir: import sys; + print, fprint, open, bind, mount, dial, sleep, read: import sys; + +include "security.m"; + auth: Auth; + +include "draw.m"; + draw: Draw; + Context: import draw; + +include "keyring.m"; + kr: Keyring; + +Init: module +{ + init: fn(); +}; + +Command: module +{ + init: fn(ctxt: ref Context, argv: list of string); +}; + +rootfs(server: string): int +{ + ok, n: int; + c: Connection; + + (ok, c) = dial("tcp!" + server + "!6666", nil); + if(ok < 0) + return -1; + + sys->print("Connected ..."); + 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 = mount(c.dfd, nil, "/", sys->MREPL, ""); + if(n > 0) + return 0; + return -1; +} + +Bootpreadlen: con 128; + +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"); + + sys->print("Setup boot net services ...\n"); + + # + # Setup what we need to call a server and + # Authenticate + # + bind("#l", "/net", sys->MREPL); + bind("#I", "/net", sys->MAFTER); + bind("#c", "/dev", sys->MAFTER); + bind("#H", "/dev", sys->MAFTER); + nvramfd := sys->open("#H/hd0nvram", sys->ORDWR); + if(nvramfd != nil){ + spec = "#Fhd0nvram"; + if(bind(spec, "/nvfs", sys->MAFTER) < 0) + print("init: bind %s: %r\n", spec); + } + + setsysname(); + + sys->print("bootp..."); + + fd := open("/net/ipifc/clone", sys->OWRITE); + if(fd == nil) { + print("init: open /net/ipifc/clone: %r\n"); + exit; + } + cfg := array of byte "bind ether ether0"; + if(sys->write(fd, cfg, len cfg) != len cfg) { + sys->print("could not bind interface: %r\n"); + exit; + } + cfg = array of byte "bootp"; + if(sys->write(fd, cfg, len cfg) != len cfg) { + sys->print("could not bootp: %r\n"); + exit; + } + + fd = open("/net/bootp", sys->OREAD); + if(fd == nil) { + print("init: open /net/bootp: %r"); + exit; + } + + buf := array[Bootpreadlen] of byte; + nr := read(fd, buf, len buf); + fd = nil; + if(nr <= 0) { + 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) { + print("init: server address not in bootp read"); + exit; + } + + srv := hd ls; + sys->print("server %s\nConnect ...\n", srv); + + retrycount := 0; + while(rootfs(srv) < 0 && retrycount++ < 5) + sleep(1000); + + cfd := sys->open("/dev/cons", Sys->OWRITE); + if (cfd != nil) { + sys->dup(cfd.fd, 1); + sys->dup(cfd.fd, 2); + } + cfd = nil; + + sys->print("done\n"); + + # + # default namespace + # + bind("#c", "/dev", sys->MREPL); # console + bind("#t", "/dev", sys->MAFTER); # serial port + bind("#H", "/dev", sys->MAFTER); + if(spec != nil) + bind(spec, "/nvfs", sys->MBEFORE|sys->MCREATE); # our keys + bind("#E", "/dev", sys->MBEFORE); # mpeg + bind("#l", "/net", sys->MBEFORE); # ethernet + bind("#I", "/net", sys->MBEFORE); # TCP/IP + bind("#V", "/dev", sys->MAFTER); # hauppauge TV + bind("#p", "/prog", sys->MREPL); # prog device + sys->bind("#d", "/fd", Sys->MREPL); + if(bind("#m", "/dev", sys->MAFTER) >= 0){ # mouse setup device + mouse := load Command "/dis/mouse.dis"; + if (mouse != nil) { + print("Setting up mouse\n"); + mouse->init(nil, "/dis/mouse.dis" :: nil); + mouse = nil; + } + } + + sys->print("clock...\n"); + setclock(); + + sys->print("logon...\n"); + + logon := load Command "/dis/wm/logon.dis"; + if(logon == nil) { + print("init: load /dis/wm/logon.dis: %r"); + logon = load Command "/dis/sh.dis"; + } + dc: ref Context; + spawn logon->init(dc, nil); +} + +setclock() +{ + (ok, dir) := sys->stat("/"); + if (ok < 0) { + print("init: stat /: %r"); + return; + } + + fd := sys->open("/dev/time", sys->OWRITE); + if (fd == nil) { + print("init: open /dev/time: %r"); + return; + } + + # Time is kept as microsecs, atime is in secs + b := array of byte sprint("%d000000", dir.atime); + if (sys->write(fd, b, len b) != len b) + print("init: write /dev/time: %r"); +} + +# +# Set system name from nvram +# +setsysname() +{ + fd := open("/nvfs/ID", sys->OREAD); + if(fd == nil) + return; + fds := 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); +} |
