xref: /plan9-contrib/sys/src/9/boot/boot.c (revision a41547ffda0e0a8ab69753330f2e59eeb889e152)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include "../boot/boot.h"
6 
7 char	cputype[64];
8 char	sys[2*64];
9 char 	reply[256];
10 int	printcol;
11 int	mflag;
12 int	fflag;
13 int	kflag;
14 
15 char	*bargv[Nbarg];
16 int	bargc;
17 
18 static void	swapproc(void);
19 static Method	*rootserver(char*);
20 static void	kbmap(void);
21 
22 void
23 boot(int argc, char *argv[])
24 {
25 	int fd, afd;
26 	Method *mp;
27 	char *cmd, cmdbuf[64], *iargv[16];
28 	char rootbuf[64];
29 	int islocal, ishybrid;
30 	char *rp, *rsp;
31 	int iargc, n;
32 	char buf[32];
33 	AuthInfo *ai;
34 
35 	fmtinstall('r', errfmt);
36 
37 	bind("#c", "/dev", MBEFORE);
38 	open("/dev/cons", OREAD);
39 	open("/dev/cons", OWRITE);
40 	open("/dev/cons", OWRITE);
41 	/*
42 	 * init will reinitialize its namespace.
43 	 * #ec gets us plan9.ini settings (*var variables).
44 	 */
45 	bind("#ec", "/env", MREPL);
46 	bind("#e", "/env", MBEFORE|MCREATE);
47 	bind("#s", "/srv", MREPL|MCREATE);
48 #ifdef DEBUG
49 	print("argc=%d\n", argc);
50 	for(fd = 0; fd < argc; fd++)
51 		print("%lux %s ", argv[fd], argv[fd]);
52 	print("\n");
53 #endif DEBUG
54 
55 	ARGBEGIN{
56 	case 'k':
57 		kflag = 1;
58 		break;
59 	case 'm':
60 		mflag = 1;
61 		break;
62 	case 'f':
63 		fflag = 1;
64 		break;
65 	}ARGEND
66 
67 	readfile("#e/cputype", cputype, sizeof(cputype));
68 
69 	/*
70 	 *  pick a method and initialize it
71 	 */
72 	if(method[0].name == nil)
73 		fatal("no boot methods");
74 	mp = rootserver(argc ? *argv : 0);
75 	(*mp->config)(mp);
76 	islocal = strcmp(mp->name, "local") == 0;
77 	ishybrid = strcmp(mp->name, "hybrid") == 0;
78 
79 	/*
80 	 *  load keymap if its there
81 	 */
82 	kbmap();
83 
84 	/*
85  	 *  authentication agent
86 	 */
87 	authentication(cpuflag);
88 
89 	/*
90 	 *  connect to the root file system
91 	 */
92 	fd = (*mp->connect)();
93 	if(fd < 0)
94 		fatal("can't connect to file server");
95 	if(getenv("srvold9p"))
96 		fd = old9p(fd);
97 	if(!islocal && !ishybrid){
98 		if(cfs)
99 			fd = (*cfs)(fd);
100 	}
101 	print("version...");
102 	buf[0] = '\0';
103 	n = fversion(fd, 0, buf, sizeof buf);
104 	if(n < 0)
105 		fatal("can't init 9P");
106 	srvcreate("boot", fd);
107 
108 	/*
109 	 *  create the name space, mount the root fs
110 	 */
111 	if(bind("/", "/", MREPL) < 0)
112 		fatal("bind /");
113 	rp = getenv("rootspec");
114 	if(rp == nil)
115 		rp = "";
116 
117 	afd = fauth(fd, rp);
118 	if(afd >= 0){
119 		ai = auth_proxy(afd, auth_getkey, "proto=p9any role=client");
120 		if(ai == nil)
121 			print("authentication failed (%r), trying mount anyways\n");
122 	}
123 	if(mount(fd, afd, "/root", MREPL|MCREATE, rp) < 0)
124 		fatal("mount /");
125 	rsp = rp;
126 	rp = getenv("rootdir");
127 	if(rp == nil)
128 		rp = rootdir;
129 	if(bind(rp, "/", MAFTER|MCREATE) < 0){
130 		if(strncmp(rp, "/root", 5) == 0){
131 			fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
132 			fatal("second bind /");
133 		}
134 		snprint(rootbuf, sizeof rootbuf, "/root/%s", rp);
135 		rp = rootbuf;
136 		if(bind(rp, "/", MAFTER|MCREATE) < 0){
137 			fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
138 			if(strcmp(rootbuf, "/root//plan9") == 0){
139 				fprint(2, "**** warning: remove rootdir=/plan9 entry from plan9.ini\n");
140 				rp = "/root";
141 				if(bind(rp, "/", MAFTER|MCREATE) < 0)
142 					fatal("second bind /");
143 			}else
144 				fatal("second bind /");
145 		}
146 	}
147 	close(fd);
148 	setenv("rootdir", rp);
149 
150 	settime(islocal, afd, rsp);
151 	if(afd > 0)
152 		close(afd);
153 	swapproc();
154 
155 	cmd = getenv("init");
156 	if(cmd == nil){
157 		sprint(cmdbuf, "/%s/init -%s%s", cputype,
158 			cpuflag ? "c" : "t", mflag ? "m" : "");
159 		cmd = cmdbuf;
160 	}
161 	iargc = tokenize(cmd, iargv, nelem(iargv)-1);
162 	cmd = iargv[0];
163 
164 	/* make iargv[0] basename(iargv[0]) */
165 	if(iargv[0] = strrchr(iargv[0], '/'))
166 		iargv[0]++;
167 	else
168 		iargv[0] = cmd;
169 
170 	iargv[iargc] = nil;
171 
172 	exec(cmd, iargv);
173 	fatal(cmd);
174 }
175 
176 static Method*
177 findmethod(char *a)
178 {
179 	Method *mp;
180 	int i, j;
181 	char *cp;
182 
183 	if((i = strlen(a)) == 0)
184 		return nil;
185 	cp = strchr(a, '!');
186 	if(cp)
187 		i = cp - a;
188 	for(mp = method; mp->name; mp++){
189 		j = strlen(mp->name);
190 		if(j > i)
191 			j = i;
192 		if(strncmp(a, mp->name, j) == 0)
193 			break;
194 	}
195 	if(mp->name)
196 		return mp;
197 	return nil;
198 }
199 
200 /*
201  *  ask user from whence cometh the root file system
202  */
203 static Method*
204 rootserver(char *arg)
205 {
206 	char prompt[256];
207 	Method *mp;
208 	char *cp;
209 	int n;
210 
211 	/* look for required reply */
212 	readfile("#e/nobootprompt", reply, sizeof(reply));
213 	if(reply[0]){
214 		mp = findmethod(reply);
215 		if(mp)
216 			goto HaveMethod;
217 		print("boot method %s not found\n", reply);
218 		reply[0] = 0;
219 	}
220 
221 	/* make list of methods */
222 	mp = method;
223 	n = sprint(prompt, "root is from (%s", mp->name);
224 	for(mp++; mp->name; mp++)
225 		n += sprint(prompt+n, ", %s", mp->name);
226 	sprint(prompt+n, ")");
227 
228 	/* create default reply */
229 	readfile("#e/bootargs", reply, sizeof(reply));
230 	if(reply[0] == 0 && arg != 0)
231 		strcpy(reply, arg);
232 	if(reply[0]){
233 		mp = findmethod(reply);
234 		if(mp == 0)
235 			reply[0] = 0;
236 	}
237 	if(reply[0] == 0)
238 		strcpy(reply, method->name);
239 
240 	/* parse replies */
241 	do{
242 		outin(prompt, reply, sizeof(reply));
243 		mp = findmethod(reply);
244 	}while(mp == nil);
245 
246 HaveMethod:
247 	bargc = tokenize(reply, bargv, Nbarg-2);
248 	bargv[bargc] = nil;
249 	cp = strchr(reply, '!');
250 	if(cp)
251 		strcpy(sys, cp+1);
252 	return mp;
253 }
254 
255 static void
256 swapproc(void)
257 {
258 	int fd;
259 
260 	fd = open("#c/swap", OWRITE);
261 	if(fd < 0){
262 		warning("opening #c/swap");
263 		return;
264 	}
265 	if(write(fd, "start", 5) <= 0)
266 		warning("starting swap kproc");
267 	close(fd);
268 }
269 
270 int
271 old9p(int fd)
272 {
273 	int p[2];
274 
275 	if(pipe(p) < 0)
276 		fatal("pipe");
277 
278 	print("srvold9p...");
279 	switch(fork()) {
280 	case -1:
281 		fatal("rfork srvold9p");
282 	case 0:
283 		dup(fd, 1);
284 		close(fd);
285 		dup(p[0], 0);
286 		close(p[0]);
287 		close(p[1]);
288 		execl("/srvold9p", "srvold9p", "-s", 0);
289 		fatal("exec srvold9p");
290 	default:
291 		close(fd);
292 		close(p[0]);
293 	}
294 	return p[1];
295 }
296 
297 static void
298 kbmap(void)
299 {
300 	char *f;
301 	int in, out;
302 	int n;
303 	char buf[1024];
304 
305 	f = getenv("kbmap");
306 	if(f == nil)
307 		return;
308 	in = open(f, OREAD);
309 	if(in < 0){
310 		warning("can't open kbd map");
311 		return;
312 	}
313 	if(bind("#κ", "/dev", MAFTER) < 0){
314 		warning("can't bind #κ");
315 		close(in);
316 		return;
317 	}
318 	out = open("/dev/kbmap", OWRITE);
319 	if(out < 0){
320 		warning("can't open  /dev/kbmap");
321 		close(out);
322 		return;
323 	}
324 	while((n = read(in, buf, sizeof(buf))) > 0)
325 		if(write(out, buf, n) != n){
326 			warning("write to /dev/kbmap failed");
327 			break;
328 		}
329 	close(in);
330 	close(out);
331 }
332