xref: /inferno-os/os/init/rpcginit.b (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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