1# 2# RPCG RPX-Lite AW 3# 4 5implement Init; 6 7include "sys.m"; 8 sys: Sys; 9 10include "draw.m"; 11 12include "keyring.m"; 13 kr: Keyring; 14 15include "security.m"; 16 auth: Auth; 17 18include "sh.m"; 19 20Init: module 21{ 22 init: fn(); 23}; 24 25Bootpreadlen: con 128; 26 27# standard flash partitions 28 29flashparts := array[] of { 30 # rpcg monitor at 0x300000 to end 31 "add params 0 0x20000", 32 "add boot 0x20000 0x40000", 33 "add kernel 0x40000 0xC0000", 34 "add fs 0xC0000 end", 35}; 36 37ethername := "ether0"; 38 39# 40# initialise flash translation 41# mount flash file system 42# add devices 43# start a shell or window manager 44# 45 46init() 47{ 48 sys = load Sys Sys->PATH; 49 kr = load Keyring Keyring->PATH; 50 auth = load Auth Auth->PATH; 51 if(auth != nil) 52 auth->init(); 53 54 sys->bind("/", "/", Sys->MREPL); 55 56 localok := 0; 57 if(lfs() >= 0){ 58 # let's just take a closer look 59 sys->bind("/n/local/nvfs", "/nvfs", Sys->MREPL|Sys->MCREATE); 60 (rc, nil) := sys->stat("/n/local/dis/sh.dis"); 61 if(rc >= 0) 62 localok = 1; 63 else 64 err("local file system unusable"); 65 } 66 netok := sys->bind("#l", "/net", Sys->MREPL) >= 0; 67 if(!netok){ 68 netok = sys->bind("#l1", "/net", Sys->MREPL) >= 0; 69 if(netok) 70 ethername = "ether1"; 71 } 72 if(netok) 73 configether(); 74 dobind("#I", "/net", sys->MAFTER); # IP 75 dobind("#p", "/prog", sys->MREPL); # prog 76 sys->bind("#d", "/fd", Sys->MREPL); 77 dobind("#c", "/dev", sys->MREPL); # console 78 dobind("#t", "/dev", sys->MAFTER); # serial line 79 drawok := sys->bind("#i", "/dev", sys->MAFTER) >= 0; # draw 80 sys->bind("#m", "/dev", sys->MAFTER); # pointer 81 sys->bind("#e", "/env", sys->MREPL|sys->MCREATE); # environment 82 sys->bind("#A", "/dev", Sys->MAFTER); # optional audio 83 timefile: string; 84 rootsource: string; 85 cfd := sys->open("/dev/consctl", Sys->OWRITE); 86 if(cfd != nil) 87 sys->fprint(cfd, "rawon"); 88 for(;;){ 89 (rootsource, timefile) = askrootsource(localok, netok); 90 if(rootsource == nil) 91 break; # internal 92 (rc, nil) := sys->stat(rootsource+"/dis/sh.dis"); 93 if(rc < 0) 94 err("%s has no shell"); 95 else if(sys->bind(rootsource, "/", Sys->MAFTER) < 0) 96 sys->print("can't bind %s on /: %r\n", rootsource); 97 else{ 98 sys->bind(rootsource+"/dis", "/dis", Sys->MBEFORE|Sys->MCREATE); 99 break; 100 } 101 } 102 cfd = nil; 103 104 setsysname("rpxlite"); # set system name 105 106 now := getclock(timefile, rootsource); 107 setclock("/dev/time", now); 108 if(timefile != "#r/rtc") 109 setclock("#r/rtc", now/big 1000000); 110 111 sys->chdir("/"); 112 if(netok){ 113 start("ndb/dns", nil); 114 start("ndb/cs", nil); 115 } 116 startup := "/nvfs/startup"; 117 if(sys->open(startup, Sys->OREAD) != nil){ 118 shell := load Command Sh->PATH; 119 if(shell != nil){ 120 sys->print("Running %s\n", startup); 121 shell->init(nil, "sh" :: startup :: nil); 122 } 123 } 124 user := username("inferno"); 125 (ok, nil) := sys->stat("/dis/wm/wm.dis"); 126 if(drawok && ok >= 0) 127 (ok, nil) = sys->stat("/dis/wm/logon.dis"); 128 if(drawok && ok >= 0 && userok(user)){ 129 wm := load Command "/dis/wm/wm.dis"; 130 if(wm != nil){ 131 fd := sys->open("/nvfs/user", Sys->OWRITE); 132 if(fd != nil){ 133 sys->fprint(fd, "%s", user); 134 fd = nil; 135 } 136 spawn wm->init(nil, list of {"wm/wm", "wm/logon", "-l", "-u", user}); 137 exit; 138 } 139 sys->print("init: can't load wm/logon: %r"); 140 } 141 sh := load Command Sh->PATH; 142 if(sh == nil){ 143 err(sys->sprint("can't load %s: %r", Sh->PATH)); 144 hang(); 145 } 146 spawn sh->init(nil, "sh" :: nil); 147} 148 149start(cmd: string, args: list of string) 150{ 151 disfile := cmd; 152 if(disfile[0] != '/') 153 disfile = "/dis/"+disfile+".dis"; 154 (ok, nil) := sys->stat(disfile); 155 if(ok >= 0){ 156 dis := load Command disfile; 157 if(dis == nil) 158 sys->print("init: can't load %s: %r\n", disfile); 159 else 160 spawn dis->init(nil, cmd :: args); 161 } 162} 163 164dobind(f, t: string, flags: int) 165{ 166 if(sys->bind(f, t, flags) < 0) 167 err(sys->sprint("can't bind %s on %s: %r", f, t)); 168} 169 170# 171# Set system name from nvram if possible 172# 173setsysname(def: string) 174{ 175 v := array of byte def; 176 fd := sys->open("/nvfs/ID", sys->OREAD); 177 if(fd == nil) 178 fd = sys->open("/env/sysname", sys->OREAD); 179 if(fd != nil){ 180 buf := array[Sys->NAMEMAX] of byte; 181 nr := sys->read(fd, buf, len buf); 182 while(nr > 0 && buf[nr-1] == byte '\n') 183 nr--; 184 if(nr > 0) 185 v = buf[0:nr]; 186 } 187 fd = sys->open("/dev/sysname", sys->OWRITE); 188 if(fd != nil) 189 sys->write(fd, v, len v); 190} 191 192getclock(timefile: string, timedir: string): big 193{ 194 now := big 0; 195 if(timefile != nil){ 196 fd := sys->open(timefile, Sys->OREAD); 197 if(fd != nil){ 198 b := array[64] of byte; 199 n := sys->read(fd, b, len b-1); 200 if(n > 0){ 201 now = big string b[0:n]; 202 if(now <= big 16r20000000) 203 now = big 0; # remote itself is not initialised 204 } 205 } 206 } 207 if(now == big 0){ 208 if(timedir != nil){ 209 (ok, dir) := sys->stat(timedir); 210 if(ok < 0) { 211 sys->print("init: stat %s: %r", timedir); 212 return big 0; 213 } 214 now = big dir.atime; 215 }else{ 216 now = big 993826747000000; 217 sys->print("time warped\n"); 218 } 219 } 220 return now; 221} 222 223setclock(timefile: string, now: big) 224{ 225 fd := sys->open(timefile, sys->OWRITE); 226 if (fd == nil) { 227 sys->print("init: can't open %s: %r", timefile); 228 return; 229 } 230 231 b := sys->aprint("%ubd", now); 232 if (sys->write(fd, b, len b) != len b) 233 sys->print("init: can't write to %s: %r", timefile); 234} 235 236srv() 237{ 238 sys->print("remote debug srv..."); 239 fd := sys->open("/dev/eia0ctl", Sys->OWRITE); 240 if(fd != nil) 241 sys->fprint(fd, "b115200"); 242 243 fd = sys->open("/dev/eia0", Sys->ORDWR); 244 if (fd == nil){ 245 err(sys->sprint("can't open /dev/eia0: %r")); 246 return; 247 } 248 if (sys->export(fd, "/", Sys->EXPASYNC) < 0){ 249 err(sys->sprint("can't export on serial port: %r")); 250 return; 251 } 252} 253 254err(s: string) 255{ 256 sys->fprint(sys->fildes(2), "init: %s\n", s); 257} 258 259hang() 260{ 261 <-chan of int; 262} 263 264tried := 0; 265 266askrootsource(localok: int, netok: int): (string, string) 267{ 268 stdin := sys->fildes(0); 269 sources := "kernel" :: nil; 270 if(netok) 271 sources = "remote" :: sources; 272 if(localok){ 273 sources = "local" :: sources; 274 if(netok) 275 sources = "local+remote" :: sources; 276 } 277 for(;;) { 278 s := ""; 279 if (tried == 0 && (s = rf("/nvfs/rootsource", nil)) != nil) { 280 tried = 1; 281 if (s[len s - 1] == '\n') 282 s = s[:len s - 1]; 283 sys->print("/nvfs/rootsource: root from %s\n", s); 284 } else { 285 sys->print("root from ("); 286 cm := ""; 287 for(l := sources; l != nil; l = tl l){ 288 sys->print("%s%s", cm, hd l); 289 cm = ","; 290 } 291 sys->print(")[%s] ", hd sources); 292 293 s = getline(stdin, hd sources); # default 294 } 295 (nil, choice) := sys->tokenize(s, "\t "); 296 if(choice == nil) 297 choice = sources; 298 opt := hd choice; 299 case opt { 300 * => 301 sys->print("\ninvalid boot option: '%s'\n", opt); 302 "kernel" => 303 return (nil, "#r/rtc"); 304 "local" => 305 return ("/n/local", "#r/rtc"); 306 "local+remote" => 307 if(netfs("/n/remote") >= 0) 308 return ("/n/local", "/n/remote/dev/time"); 309 "remote" => 310 if(netfs("/n/remote") >= 0) 311 return ("/n/remote", "/n/remote/dev/time"); 312 } 313 } 314} 315 316getline(fd: ref Sys->FD, default: string): string 317{ 318 result := ""; 319 buf := array[10] of byte; 320 i := 0; 321 for(;;) { 322 n := sys->read(fd, buf[i:], len buf - i); 323 if(n < 1) 324 break; 325 i += n; 326 while(i >0 && (nutf := sys->utfbytes(buf, i)) > 0){ 327 s := string buf[0:nutf]; 328 for (j := 0; j < len s; j++) 329 case s[j] { 330 '\b' => 331 if(result != nil) 332 result = result[0:len result-1]; 333 'u'&16r1F => 334 sys->print("^U\n"); 335 result = ""; 336 '\r' => 337 ; 338 * => 339 sys->print("%c", s[j]); 340 if(s[j] == '\n' || s[j] >= 16r80){ 341 if(s[j] != '\n') 342 result[len result] = s[j]; 343 if(result == nil) 344 return default; 345 return result; 346 } 347 result[len result] = s[j]; 348 } 349 buf[0:] = buf[nutf:i]; 350 i -= nutf; 351 } 352 } 353 return default; 354} 355 356# 357# serve local DOS file system using flash translation layer 358# 359lfs(): int 360{ 361 if(!flashpart("#F/flash/flashctl", flashparts)) 362 return -1; 363 if(!ftlinit("#F/flash/fs")) 364 return -1; 365 c := chan of string; 366 spawn startfs(c, "/dis/dossrv.dis", "dossrv" :: "-f" :: "#X/ftldata" :: "-m" :: "/n/local" :: nil); 367 if(<-c != nil) 368 return -1; 369 return 0; 370} 371 372startfs(c: chan of string, file: string, args: list of string) 373{ 374 fs := load Command file; 375 if(fs == nil){ 376 sys->print("can't load %s: %r\n", file); 377 c <-= "load failed"; 378 } 379 { 380 fs->init(nil, args); 381 }exception e { 382 "*" => 383 c <-= "failed"; 384 exit; 385 * => 386 c <-= "unknown exception"; 387 exit; 388 } 389 c <-= nil; 390} 391 392# 393# partition flash 394# 395flashdone := 0; 396 397flashpart(ctl: string, parts: array of string): int 398{ 399 if(flashdone) 400 return 1; 401 cfd := sys->open(ctl, Sys->ORDWR); 402 if(cfd == nil){ 403 sys->print("can't open %s: %r\n", ctl); 404 return 0; 405 } 406 for(i := 0; i < len parts; i++) 407 if(sys->fprint(cfd, "%s", parts[i]) < 0){ 408 sys->print("can't %q to %s: %r\n", parts[i], ctl); 409 return 0; 410 } 411 flashdone = 1; 412 return 1; 413} 414 415# 416# set up flash translation layer 417# 418ftldone := 0; 419 420ftlinit(flashmem: string): int 421{ 422 if(ftldone) 423 return 1; 424 sys->print("Set flash translation of %s...\n", flashmem); 425 fd := sys->open("#X/ftlctl", Sys->OWRITE); 426 if(fd == nil){ 427 sys->print("can't open #X/ftlctl: %r\n"); 428 return 0; 429 } 430 if(sys->fprint(fd, "init %s", flashmem) <= 0){ 431 sys->print("can't init flash translation: %r\n"); 432 return 0; 433 } 434 ftldone = 1; 435 return 1; 436} 437 438configether() 439{ 440 if(ethername == nil) 441 return; 442 fd := sys->open("/nvfs/etherparams", Sys->OREAD); 443 if(fd == nil) 444 return; 445 ctl := sys->open("/net/"+ethername+"/clone", Sys->OWRITE); 446 if(ctl == nil){ 447 sys->print("init: can't open %s's clone: %r\n", ethername); 448 return; 449 } 450 b := array[1024] of byte; 451 n := sys->read(fd, b, len b); 452 if(n <= 0) 453 return; 454 for(i := 0; i < n;){ 455 for(e := i; e < n && b[e] != byte '\n'; e++) 456 ; 457 s := string b[i:e]; 458 if(sys->fprint(ctl, "%s", s) < 0) 459 sys->print("init: ctl write to %s: %s: %r\n", ethername, s); 460 i = e+1; 461 } 462} 463 464donebind := 0; 465 466# 467# set up network mount 468# 469netfs(mountpt: string): int 470{ 471 sys->print("bootp ..."); 472 473 fd: ref Sys->FD; 474 if(!donebind){ 475 fd = sys->open("/net/ipifc/clone", sys->OWRITE); 476 if(fd == nil) { 477 sys->print("init: open /net/ipifc/clone: %r\n"); 478 return -1; 479 } 480 if(sys->fprint(fd, "bind ether %s", ethername) < 0) { 481 sys->print("could not bind ether0 interface: %r\n"); 482 return -1; 483 } 484 donebind = 1; 485 }else{ 486 fd = sys->open("/net/ipifc/0/ctl", Sys->OWRITE); 487 if(fd == nil){ 488 sys->print("init: can't reopen /net/ipifc/0/ctl: %r\n"); 489 return -1; 490 } 491 } 492 if ((ip := rf("/nvfs/ip", nil)) != nil) { 493 sys->print("**using %s\n", ip); 494 sys->fprint(fd, "bind ether /net/ether0"); 495 sys->fprint(fd, "add %s ", ip); 496 } else { 497 { 498 if(sys->fprint(fd, "bootp") < 0) 499 sys->print("could not bootp: %r\n"); 500 } exception e { 501 "*" => 502 sys->print("could not bootp: %s\n", e); 503 } 504 } 505 server := rf("/nvfs/fsip", nil); 506 if (server != nil) { 507 if (server[len server - 1] == '\n') 508 server = server[:len server - 1]; 509 sys->print("/nvfs/fsip: server=%s\n", server); 510 } else 511 server = bootp(); 512 if(server == nil || server == "0.0.0.0") 513 return -1; 514 515 net := "tcp"; # how to specify il? 516 svcname := net + "!" + server + "!6666"; 517 518 sys->print("dial %s...", svcname); 519 520 (ok, c) := sys->dial(svcname, nil); 521 if(ok < 0){ 522 sys->print("can't dial %s: %r\n", svcname); 523 return -1; 524 } 525 526 sys->print("\nConnected ...\n"); 527 if(kr != nil){ 528 err: string; 529 sys->print("Authenticate ..."); 530 ai := kr->readauthinfo("/nvfs/default"); 531 if(ai == nil){ 532 sys->print("readauthinfo /nvfs/default failed: %r\n"); 533 sys->print("trying mount as `nobody'\n"); 534 } 535 (c.dfd, err) = auth->client("none", ai, c.dfd); 536 if(c.dfd == nil){ 537 sys->print("authentication failed: %s\n", err); 538 return -1; 539 } 540 } 541 542 sys->print("mount %s...", mountpt); 543 544 c.cfd = nil; 545 n := sys->mount(c.dfd, nil, mountpt, sys->MREPL, ""); 546 if(n > 0) 547 return 0; 548 if(n < 0) 549 sys->print("%r"); 550 return -1; 551} 552 553bootp(): string 554{ 555 fd := sys->open("/net/bootp", sys->OREAD); 556 if(fd == nil) { 557 sys->print("init: can't open /net/bootp: %r"); 558 return nil; 559 } 560 561 buf := array[Bootpreadlen] of byte; 562 nr := sys->read(fd, buf, len buf); 563 fd = nil; 564 if(nr <= 0) { 565 sys->print("init: read /net/bootp: %r"); 566 return nil; 567 } 568 569 (ntok, ls) := sys->tokenize(string buf, " \t\n"); 570 while(ls != nil) { 571 if(hd ls == "fsip"){ 572 ls = tl ls; 573 break; 574 } 575 ls = tl ls; 576 } 577 if(ls == nil) { 578 sys->print("init: server address not in bootp read"); 579 return nil; 580 } 581 582 srv := hd ls; 583 584 sys->print("%s\n", srv); 585 586 return srv; 587} 588 589username(def: string): string 590{ 591 return rf("/nvfs/user", def); 592} 593 594userok(user: string): int 595{ 596 (ok, d) := sys->stat("/usr/"+user); 597 return ok >= 0 && (d.mode & Sys->DMDIR) != 0; 598} 599 600rf(file: string, default: string): string 601{ 602 fd := sys->open(file, Sys->OREAD); 603 if(fd != nil){ 604 buf := array[128] of byte; 605 nr := sys->read(fd, buf, len buf); 606 if(nr > 0) 607 return string buf[0:nr]; 608 } 609 return default; 610} 611