Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <auth.h>
4
#include <fcall.h>
5
#include "../boot/boot.h"
6
 
7
#define PARTSRV "partfs.sdXX"
8
 
9
enum {
10
	Dontpost,
11
	Post,
12
};
13
 
14
char	cputype[64];
15
char	sys[2*64];
16
char 	reply[256];
17
int	printcol;
18
int	mflag;
19
int	fflag;
20
int	kflag;
21
int	debugboot;
22
int	nousbboot;
23
 
24
char	*bargv[Nbarg];
25
int	bargc;
26
 
27
static void	swapproc(void);
28
static Method	*rootserver(char*);
29
static void	kbmap(void);
30
 
31
/*
32
 * we should inherit the standard fds all referring to /dev/cons,
33
 * but we're being paranoid.
34
 */
35
static void
36
opencons(void)
37
{
38
	close(0);
39
	close(1);
40
	close(2);
41
	bind("#c", "/dev", MBEFORE);
42
	open("/dev/cons", OREAD);
43
	open("/dev/cons", OWRITE);
44
	open("/dev/cons", OWRITE);
45
}
46
 
47
/*
48
 * init will reinitialize its namespace.
49
 * #ec gets us plan9.ini settings (*var variables).
50
 */
51
static void
52
bindenvsrv(void)
53
{
54
	bind("#ec", "/env", MREPL);
55
	bind("#e", "/env", MBEFORE|MCREATE);
56
	bind("#s", "/srv/", MREPL|MCREATE);
57
}
58
 
59
static void
60
debuginit(int argc, char **argv)
61
{
62
	int fd;
63
 
64
	if(getenv("debugboot"))
65
		debugboot = 1;
66
	if(getenv("nousbboot"))
67
		nousbboot = 1;
68
#ifdef DEBUG
69
	print("argc=%d\n", argc);
70
	for(fd = 0; fd < argc; fd++)
71
		print("%#p %s ", argv[fd], argv[fd]);
72
	print("\n");
73
#endif	/* DEBUG */
74
	SET(fd);
75
	USED(argc, argv, fd);
76
}
77
 
78
/*
79
 * read disk partition tables here so that readnvram via factotum
80
 * can see them.  ideally we would have this information in
81
 * environment variables before attaching #S, which would then
82
 * parse them and create partitions.
83
 */
84
static void
85
partinit(void)
86
{
87
	char *rdparts;
88
 
89
	rdparts = getenv("readparts");
90
	if(rdparts)
91
		readparts();
92
	free(rdparts);
93
}
94
 
95
/*
96
 *  pick a method and initialize it
97
 */
98
static Method *
99
pickmethod(int argc, char **argv)
100
{
101
	Method *mp;
102
 
103
	if(method[0].name == nil)
104
		fatal("no boot methods");
105
	mp = rootserver(argc ? *argv : 0);
106
	(*mp->config)(mp);
107
	return mp;
108
}
109
 
110
/*
111
 *  authentication agent
112
 *  sets hostowner, creating an auth discontinuity
113
 */
114
static void
115
doauth(int cpuflag)
116
{
117
	dprint("auth...");
118
	authentication(cpuflag);
119
}
120
 
121
/*
122
 *  connect to the root file system
123
 */
124
static int
125
connectroot(Method *mp, int islocal, int ishybrid)
126
{
127
	int fd, n;
128
	char buf[32];
129
 
130
	fd = (*mp->connect)();
131
	if(fd < 0)
132
		fatal("can't connect to file server");
133
	if(getenv("srvold9p"))
134
		fd = old9p(fd);
135
	if(!islocal && !ishybrid){
136
		if(cfs)
137
			fd = (*cfs)(fd);
138
	}
139
	print("version...");
140
	buf[0] = '\0';
141
	n = fversion(fd, 0, buf, sizeof buf);
142
	if(n < 0)
143
		fatal("can't init 9P");
144
	srvcreate("boot", fd);
145
	return fd;
146
}
147
 
148
/*
149
 *  create the name space, mount the root fs
150
 */
151
static int
152
nsinit(int fd, char **rspp)
153
{
154
	int afd;
155
	char *rp, *rsp;
156
	AuthInfo *ai;
157
	static char rootbuf[64];
158
 
159
	if(bind("/", "/", MREPL) < 0)
160
		fatal("bind /");
161
	rp = getenv("rootspec");
162
	if(rp == nil)
163
		rp = "";
164
 
165
	afd = fauth(fd, rp);
166
	if(afd >= 0){
167
		ai = auth_proxy(afd, auth_getkey, "proto=p9any role=client");
168
		if(ai == nil)
169
			print("authentication failed (%r), trying mount anyways\n");
170
	}
171
	if(mount(fd, afd, "/root", MREPL|MCREATE, rp) < 0)
172
		fatal("mount /");
173
	rsp = rp;
174
	rp = getenv("rootdir");
175
	if(rp == nil)
176
		rp = rootdir;
177
	if(bind(rp, "/", MAFTER|MCREATE) < 0){
178
		if(strncmp(rp, "/root", 5) == 0){
179
			fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
180
			fatal("second bind /");
181
		}
182
		snprint(rootbuf, sizeof rootbuf, "/root/%s", rp);
183
		rp = rootbuf;
184
		if(bind(rp, "/", MAFTER|MCREATE) < 0){
185
			fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
186
			if(strcmp(rootbuf, "/root//plan9") != 0)
187
				fatal("second bind /");
188
			/* undo installer's work */
189
			fprint(2, "**** warning: remove rootdir=/plan9 "
190
				"entry from plan9.ini\n");
191
			rp = "/root";
192
			if(bind(rp, "/", MAFTER|MCREATE) < 0)
193
				fatal("second bind /");
194
		}
195
	}
196
	setenv("rootdir", rp);
197
	*rspp = rsp;
198
	return afd;
199
}
200
 
201
static void
202
execinit(void)
203
{
204
	int iargc;
205
	char *cmd, cmdbuf[64], *iargv[16];
206
 
207
	/* exec init */
208
	cmd = getenv("init");
209
	if(cmd == nil){
210
		sprint(cmdbuf, "/%s/init -%s%s", cputype,
211
			cpuflag ? "c" : "t", mflag ? "m" : "");
212
		cmd = cmdbuf;
213
	}
214
	iargc = tokenize(cmd, iargv, nelem(iargv)-1);
215
	cmd = iargv[0];
216
 
217
	/* make iargv[0] basename(iargv[0]) */
218
	if(iargv[0] = strrchr(iargv[0], '/'))
219
		iargv[0]++;
220
	else
221
		iargv[0] = cmd;
222
 
223
	iargv[iargc] = nil;
224
 
225
	chmod("/srv/" PARTSRV, 0600);
226
	exec(cmd, iargv);
227
	fatal(cmd);
228
}
229
 
230
void
231
boot(int argc, char *argv[])
232
{
233
	int fd, afd, islocal, ishybrid;
234
	char *rsp;
235
	Method *mp;
236
 
237
	fmtinstall('r', errfmt);
238
	opencons();
239
	bindenvsrv();
240
	debuginit(argc, argv);
241
 
242
	ARGBEGIN{
243
	case 'k':
244
		kflag = 1;
245
		break;
246
	case 'm':
247
		mflag = 1;
248
		break;
249
	case 'f':
250
		fflag = 1;
251
		break;
252
	}ARGEND
253
 
254
	readfile("#e/cputype", cputype, sizeof(cputype));
255
 
256
	/*
257
	 *  set up usb keyboard & mouse, if any.
258
	 *  starts partfs on first disk, if any, to permit nvram on usb.
259
	 */
260
	if (!nousbboot)
261
		usbinit(Dontpost);
262
 
263
	dprint("pickmethod...");
264
	mp = pickmethod(argc, argv);
265
	islocal = strcmp(mp->name, "local") == 0;
266
	ishybrid = strcmp(mp->name, "hybrid") == 0;
267
 
268
	kbmap();			/*  load keymap if it's there. */
269
 
270
	/* don't trigger aoe until the network has been configured */
271
	dprint("bind #æ...");
272
	bind("#æ", "/dev", MAFTER);	/* nvram could be here */
273
	dprint("bind #S...");
274
	bind("#S", "/dev", MAFTER);	/* nvram could be here */
275
	dprint("partinit...");
276
	partinit();
277
 
278
	doauth(cpuflag);	/* authentication usually changes hostowner */
279
	rfork(RFNAMEG);		/* leave existing subprocs in own namespace */
280
	if (!nousbboot)
281
		usbinit(Post);	/* restart partfs under the new hostowner id */
282
	fd = connectroot(mp, islocal, ishybrid);
283
	afd = nsinit(fd, &rsp);
284
	close(fd);
285
 
286
	settime(islocal, afd, rsp);
287
	if(afd > 0)
288
		close(afd);
289
	swapproc();
290
	execinit();
291
	exits("failed to exec init");
292
}
293
 
294
static Method*
295
findmethod(char *a)
296
{
297
	Method *mp;
298
	int i, j;
299
	char *cp;
300
 
301
	if((i = strlen(a)) == 0)
302
		return nil;
303
	cp = strchr(a, '!');
304
	if(cp)
305
		i = cp - a;
306
	for(mp = method; mp->name; mp++){
307
		j = strlen(mp->name);
308
		if(j > i)
309
			j = i;
310
		if(strncmp(a, mp->name, j) == 0)
311
			break;
312
	}
313
	if(mp->name)
314
		return mp;
315
	return nil;
316
}
317
 
318
/*
319
 *  ask user from whence cometh the root file system
320
 */
321
static Method*
322
rootserver(char *arg)
323
{
324
	char prompt[256];
325
	Method *mp;
326
	char *cp;
327
	int n;
328
 
329
	/* look for required reply */
330
	dprint("read #e/nobootprompt...");
331
	readfile("#e/nobootprompt", reply, sizeof(reply));
332
	if(reply[0]){
333
		mp = findmethod(reply);
334
		if(mp)
335
			goto HaveMethod;
336
		print("boot method %s not found\n", reply);
337
		reply[0] = 0;
338
	}
339
 
340
	/* make list of methods */
341
	mp = method;
342
	n = sprint(prompt, "root is from (%s", mp->name);
343
	for(mp++; mp->name; mp++)
344
		n += sprint(prompt+n, ", %s", mp->name);
345
	sprint(prompt+n, ")");
346
 
347
	/* create default reply */
348
	dprint("read #e/bootargs...");
349
	readfile("#e/bootargs", reply, sizeof(reply));
350
	if(reply[0] == 0 && arg != 0)
351
		strcpy(reply, arg);
352
	if(reply[0]){
353
		mp = findmethod(reply);
354
		if(mp == 0)
355
			reply[0] = 0;
356
	}
357
	if(reply[0] == 0)
358
		strcpy(reply, method->name);
359
 
360
	/* parse replies */
361
	do{
362
		dprint("outin...");
363
		outin(prompt, reply, sizeof(reply));
364
		mp = findmethod(reply);
365
	}while(mp == nil);
366
 
367
HaveMethod:
368
	bargc = tokenize(reply, bargv, Nbarg-2);
369
	bargv[bargc] = nil;
370
	cp = strchr(reply, '!');
371
	if(cp)
372
		strcpy(sys, cp+1);
373
	dprint("pickmethod done\n");
374
	return mp;
375
}
376
 
377
static void
378
swapproc(void)
379
{
380
	int fd;
381
 
382
	fd = open("#c/swap", OWRITE);
383
	if(fd < 0){
384
		warning("opening #c/swap");
385
		return;
386
	}
387
	if(write(fd, "start", 5) <= 0)
388
		warning("starting swap kproc");
389
	close(fd);
390
}
391
 
392
int
393
old9p(int fd)
394
{
395
	int p[2];
396
 
397
	if(pipe(p) < 0)
398
		fatal("pipe");
399
 
400
	print("srvold9p...");
401
	switch(fork()) {
402
	case -1:
403
		fatal("rfork srvold9p");
404
	case 0:
405
		dup(fd, 1);
406
		close(fd);
407
		dup(p[0], 0);
408
		close(p[0]);
409
		close(p[1]);
410
		execl("/srvold9p", "srvold9p", "-s", 0);
411
		fatal("exec srvold9p");
412
	default:
413
		close(fd);
414
		close(p[0]);
415
	}
416
	return p[1];
417
}
418
 
419
static void
420
kbmap(void)
421
{
422
	char *f;
423
	int n, in, out;
424
	char buf[1024];
425
 
426
	f = getenv("kbmap");
427
	if(f == nil)
428
		return;
429
	if(bind("#κ", "/dev", MAFTER) < 0){
430
		warning("can't bind #κ");
431
		return;
432
	}
433
 
434
	in = open(f, OREAD);
435
	if(in < 0){
436
		warning("can't open kbd map");
437
		return;
438
	}
439
	out = open("/dev/kbmap", OWRITE);
440
	if(out < 0) {
441
		warning("can't open /dev/kbmap");
442
		close(in);
443
		return;
444
	}
445
	while((n = read(in, buf, sizeof(buf))) > 0)
446
		if(write(out, buf, n) != n){
447
			warning("write to /dev/kbmap failed");
448
			break;
449
		}
450
	close(in);
451
	close(out);
452
}