xref: /inferno-os/os/init/pcinit.b (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1implement Init;
2
3include "sys.m";
4	sys: Sys;
5
6include "draw.m";
7	draw: Draw;
8
9include "keyring.m";
10	kr: Keyring;
11
12include "security.m";
13	auth: Auth;
14
15include "styx.m";
16
17	dosfs : Dosfs;
18
19PROMPT:		con 1;		# boot from prompt?  (0 means boot from fs)
20SHELL:		con 0;		# Start a Shell, not Logon
21INIT: 		con "/init";	# file to read init commands from
22
23startip := 0;
24
25Bootpreadlen:	con 128;
26
27Init: module
28{
29	init:	fn();
30};
31
32Logon: module
33{
34	init:	fn(ctxt: ref Draw->Context, argv: list of string);
35};
36
37Sh: module
38{
39	init:	fn(ctxt: ref Draw->Context, argv: list of string);
40};
41
42lfs(dev: string): int
43{
44	(ok, dir) := sys->stat(dev);
45	if (ok < 0) {
46		sys->print("init: stat %s: %r\n", dev);
47		return -1;
48	}
49	pipefd := array[2] of ref Sys->FD;
50 	dosfs = load Dosfs "#/./dosfs";
51	if(dosfs == nil) {
52		sys->fprint(sys->fildes(2),"load #/.dosfs: %r\n");
53		return -1;
54	}
55
56	dosfs->init(dev, "", 0);
57	if(sys->pipe(pipefd) < 0){
58		sys->fprint(sys->fildes(2),"pipe %r\n");
59		exit;
60	}
61	spawn dosfs->dossrv(pipefd[1]);
62
63	n := sys->mount(pipefd[0], "/", sys->MREPL|sys->MCREATE, "");
64	if(n<0) {
65		sys->print("couldn't mount. %r\n");
66		return -1;
67	}
68
69	dosfs->setup();
70
71	sys->print("mounted %s at /\n", dev);
72
73	return 0;
74}
75
76ipinit()
77{
78	fd := sys->open("/nvfs/IP", sys->OREAD);
79	if(fd == nil)
80		return;
81
82	buf := array[128] of byte;
83	nr := sys->read(fd, buf, len buf);
84	if(nr <= 0)
85		return;
86
87	cfd := sys->open("/net/ipifc/clone", sys->ORDWR);
88	if(cfd == nil) {
89		sys->print("init: open /net/ipifc/clone: %r");
90		exit;
91	}
92
93	sys->fprint(cfd, "bind ether ether0");
94	sys->fprint(cfd, "%s", string buf[0:nr]);
95}
96
97netfs(): int
98{
99	cfd := sys->open("/net/ipifc/clone", sys->ORDWR);
100	if(cfd == nil) {
101		sys->print("init: open /net/ipifc/clone: %r");
102		exit;
103	}
104	sys->fprint(cfd, "bind ether ether0");
105
106	server:= bootp(cfd);
107	sys->print("dial...");
108	(ok, c) := sys->dial("tcp!" + server + "!6666", nil);
109	if(ok < 0)
110		return -1;
111
112	if(kr != nil && auth != nil){
113		err: string;
114		sys->print("Authenticate ...");
115		ai := kr->readauthinfo("/nvfs/default");
116		if(ai == nil){
117			sys->print("readauthinfo /nvfs/default failed: %r\n");
118			sys->print("trying mount as `nobody'\n");
119		}
120		(c.dfd, err) = auth->client("none", ai, c.dfd);
121		if(c.dfd == nil){
122			sys->print("authentication failed: %s\n", err);
123			return -1;
124		}
125	}
126
127	sys->print("mount ...");
128
129	c.cfd = nil;
130	n := sys->mount(c.dfd, "/", sys->MREPL, "");
131	if(n > 0)
132		return 0;
133
134	return -1;
135}
136
137init()
138{
139	spec: string;
140
141	sys = load Sys Sys->PATH;
142	kr = load Keyring Keyring->PATH;
143	auth = load Auth Auth->PATH;
144	if(auth != nil)
145		auth->init();
146
147	sys->print("**\n** Inferno\n** Vita Nuova\n**\n\n\n");
148
149	#
150	# Setup what we need to call a server and
151	# Authenticate
152	#
153	sys->bind("#l", "/net", sys->MREPL);
154	sys->bind("#I", "/net", sys->MAFTER);
155	sys->bind("#c", "/dev", sys->MAFTER);
156
157	sys->print("Non-volatile ram read ...\n");
158
159	nvramfd := sys->open("#H/hd0nvram", sys->ORDWR);
160	if(nvramfd != nil) {
161		spec = "#Fhd0nvram";
162		if(sys->bind(spec, "/nvfs", sys->MAFTER) < 0)
163			sys->print("init: bind %s: %r\n", spec);
164		sys->print("mounted tinyfs");
165		nvramfd = nil;
166	}
167
168	sys->print("\n\n");
169
170	if(!PROMPT) {
171		if(lfs("#H/hd0fs") == 0)
172			startip = 1;
173		else
174			bootfrom();
175	} else
176		bootfrom();
177
178	sys->bind("#l", "/net", sys->MBEFORE);
179	sys->bind("#I", "/net", sys->MBEFORE);
180	sys->bind("#c", "/dev", sys->MBEFORE);
181
182	if(startip)
183		ipinit();
184
185	setsysname();
186
187	sys->print("clock...\n");
188	setclock();
189
190	if(SHELL) {
191		sys->print("shell...\n");
192
193		logon := load Logon "/dis/sh.dis";
194		if(logon == nil) {
195			sys->print("init: load /dis/wm/logon.dis: %r");
196			exit;
197		}
198		dc: ref Draw->Context;
199		spawn logon->init(dc, nil);
200		exit;
201	}
202
203	runprogs();
204}
205
206bootfrom()
207{
208	buf := array[128] of byte;
209	stdin := sys->fildes(0);
210
211	fsdev := "#H/hd0disk";
212
213	loop: for(;;) {
214		sys->print("boot from [fs, net]: ");
215
216		n := sys->read(stdin, buf, len buf);
217		if(n <= 0)
218			continue;
219		if(buf[n-1] == byte '\n')
220			n--;
221
222		(nil, choice) := sys->tokenize(string buf[:n], "\t ");
223		if(choice == nil)
224			continue;
225
226		opt := hd choice;
227		choice = tl choice;
228
229		case opt {
230		* =>
231			sys->print("\ninvalid boot option: '%s'\n", opt);
232			break;
233		"fs" or "" =>
234			if(choice != nil)
235				fsdev = hd choice;
236			if(lfs(fsdev) == 0) {
237				startip = 1;
238				break loop;
239			}
240		"net" =>
241			if(netfs() == 0)
242				break loop;
243		}
244	}
245}
246
247runprogs()
248{
249	fd:= sys->open(INIT, Sys->OREAD);
250	if(fd == nil) {
251		sys->print("open %s: %r\n", INIT);
252		return;
253	}
254
255	dc := ref Draw->Context;
256	dc.ctomux = chan of int;
257
258	for(l:=1;;l++) {
259		(e, line):= getline(fd);
260		if(e != nil) {
261			sys->print(INIT+":%d: %s\n", l, e);
262			return;
263		}
264		if(line == nil)
265			break;
266		if(line == "\n" || line[0] == '#')
267			continue;
268		if(line[len line-1] == '\n')
269			line = line[:len line-1];
270		(n, f):= sys->tokenize(line, " \t");
271		if(n < 0) {
272			sys->print(INIT+":%d: tokenize: %r\n", l);
273			return;
274		}
275		if(n < 2) {
276			sys->print(INIT+":%d: not enough fields\n", l);
277			continue;
278		}
279		e = run(dc, f);
280		if(e != nil)
281			sys->print(INIT+":%d: %s\n", l, e);
282	}
283}
284
285run(dc: ref Draw->Context, argv: list of string): string
286{
287	c:= hd argv;
288	argv = tl argv;
289	prog:= hd argv;
290	ext:= ".dis";
291	if(prog[len prog-4:] == ".dis")
292		ext = "";
293	sh:= load Sh prog+ext;
294	if(sh == nil)
295		sh = load Sh "/dis/"+prog+ext;
296	if(sh == nil)
297		return sys->sprint("%s: load: %r", prog);
298
299	case c {
300	"run" =>
301		e:= ref Sys->Exception;
302		if(sys->rescue("fail:*", e))
303			return prog+": "+e.name;
304		sh->init(dc, argv);
305		return nil;
306	"spawn" =>
307		spawn sh->init(dc, argv);
308		return nil;
309	}
310	return c+": unknown command";
311}
312
313getline(fd: ref Sys->FD): (string, string)
314{
315	s:= "";
316	buf:= array[1] of byte;
317	for(;;) {
318		n:= sys->read(fd, buf, 1);
319		if(n < 0)
320			return (sys->sprint("getline: read: %r\n"), nil);
321		if(n == 0)
322			return (nil, s);
323		s += string buf;
324		if(buf[0] == byte '\n')
325			return (nil, s);
326	}
327}
328
329setclock()
330{
331	(ok, dir) := sys->stat("/");
332	if (ok < 0) {
333		sys->print("init: stat /: %r");
334		return;
335	}
336
337	fd := sys->open("/dev/time", sys->OWRITE);
338	if (fd == nil) {
339		sys->print("init: open /dev/time: %r\n");
340		return;
341	}
342
343	# Time is kept as microsecs, atime is in secs
344	b := array of byte sys->sprint("%d000000", dir.atime);
345	if (sys->write(fd, b, len b) != len b)
346		sys->print("init: write /dev/time: %r");
347}
348
349#
350# Set system name from nvram
351#
352setsysname()
353{
354	fd := sys->open("/nvfs/ID", sys->OREAD);
355	if(fd == nil)
356		return;
357	fds := sys->open("/dev/sysname", sys->OWRITE);
358	if(fds == nil)
359		return;
360	buf := array[128] of byte;
361	nr := sys->read(fd, buf, len buf);
362	if(nr <= 0)
363		return;
364	sys->write(fds, buf, nr);
365}
366
367bootp(cfd: ref sys->FD): string
368{
369	sys->print("bootp ...");
370
371	sys->fprint(cfd, "bootp");
372
373	fd := sys->open("/net/bootp", sys->OREAD);
374	if(fd == nil) {
375		sys->print("init: open /net/bootp: %r");
376		exit;
377	}
378
379
380	buf := array[Bootpreadlen] of byte;
381	nr := sys->read(fd, buf, len buf);
382	fd = nil;
383	if(nr <= 0) {
384		sys->print("init: read /net/bootp: %r");
385		exit;
386	}
387	(ntok, ls) := sys->tokenize(string buf, " \t\n");
388	while(ls != nil) {
389		if(hd ls == "fsip"){
390			ls = tl ls;
391			break;
392		}
393		ls = tl ls;
394	}
395	if(ls == nil) {
396		sys->print("init: server address not in bootp read");
397		exit;
398	}
399
400	srv := hd ls;
401
402	sys->print("(ip=%s)", srv);
403
404	return srv;
405}
406