xref: /inferno-os/emu/port/main.c (revision 7de2b42d50e3c05cc143e7b51284009b5e185581)
1 #include	"dat.h"
2 #include	"fns.h"
3 #include	"error.h"
4 #include	"interp.h"
5 #include	"kernel.h"
6 #include	"draw.h"
7 #include	"version.h"
8 
9 int		rebootargc = 0;
10 char**		rebootargv;
11 static	char	*imod = "/dis/emuinit.dis";
12 extern	char*	hosttype;
13 char*	tkfont;	/* for libtk/utils.c */
14 int	tkstylus;	/* libinterp/tk.c */
15 extern	int	mflag;
16 	int	dflag;
17 	int vflag;
18 	int	vflag;
19 	Procs	procs;
20 	char	*eve;
21 	int	Xsize	= 640;
22 	int	Ysize	= 480;
23 	int	bflag = 1;
24 	int	sflag;
25 	int	qflag;
26 	int	xtblbit;
27 	ulong	displaychan;
28 char *cputype;
29 
30 static void
31 usage(void)
32 {
33 	fprint(2, "Usage: emu [options...] [file.dis [args...]]\n"
34 		"\t-gXxY\n"
35 		"\t-c[0-9]\n"
36 		"\t-d file.dis\n"
37 		"\t-s\n"
38 		"\t-v\n"
39 		"\t-p<poolname>=maxsize\n"
40 		"\t-f<fontpath>\n"
41 		"\t-r<rootpath>\n"
42 		"\t-7\n"
43 		"\t-B\n"
44 		"\t-C<channel string>\n"
45 		"\t-S\n");
46 
47 	exits("usage");
48 }
49 
50 static void
51 envusage(void)
52 {
53 	fprint(2, "emu: bad option in EMU environment variable (%s)\n", getenv("EMU"));
54 	usage();
55 }
56 
57 static int
58 isnum(char *p)
59 {
60 	if (*p == 0) return 0;
61 	while (*p) {
62 		if (*p < '0' || *p > '9') return 0;
63 		p++;
64 	}
65 	return 1;
66 }
67 
68 static int
69 geom(char *val)
70 {
71 	char *p;
72 	int x, y;
73 	if (val == '\0' || (*val < '0' || *val > '9'))
74 		return 0;
75 	x = strtoul(val, &p, 0);
76 	if(x >= 64)
77 		Xsize = x;
78 	if (*p++ != 'x' || !isnum(p))
79 		return 0;
80 	y = strtoul(p, &p, 0);
81 	if(y >= 48)
82 		Ysize = y;
83 	if (*p != '\0') return 0;
84 	return 1;
85 }
86 
87 static void
88 poolopt(char *str)
89 {
90 	char *var;
91 	int n;
92 	ulong x;
93 
94 	var = str;
95 	while(*str && *str != '=')
96 		str++;
97 	if(*str != '=' || str[1] == '\0')
98 		usage();
99 	*str++ = '\0';
100 	n = strlen(str);
101 	x = atoi(str);
102 	switch(str[n - 1]){
103 	case 'k':
104 	case 'K':
105 		x *= 1024;
106 		break;
107 	case 'm':
108 	case 'M':
109 		x *= 1024*1024;
110 		break;
111 	}
112 	if(poolsetsize(var, x) == 0)
113 		usage();
114 }
115 
116 static void
117 option(int argc, char *argv[], void (*badusage)(void))
118 {
119 	char *cp;
120 
121 	ARGBEGIN {
122 	default:
123 		badusage();
124 	case 'g':		/* Window geometry */
125 		if (geom(EARGF(badusage())) == 0)
126 			badusage();
127 		break;
128 	case 'b':		/* jit array bounds checking (obsolete, now on by default) */
129 		break;
130 	case 'B':		/* suppress jit array bounds checks */
131 		bflag = 0;
132 		break;
133 	case 'c':		/* Compile on the fly */
134 		cp = EARGF(badusage());
135 		if (!isnum(cp))
136 			badusage();
137 		cflag = atoi(cp);
138 		if(cflag < 0|| cflag > 9)
139 			usage();
140 		break;
141 	case 'I':	/* (temporary option) run without cons */
142 		dflag++;
143 		break;
144 	case 'd':		/* run as a daemon */
145 		dflag++;
146 		imod = EARGF(badusage());
147 		break;
148 	case 's':		/* No trap handling */
149 		sflag++;
150 		break;
151 	case 'm':		/* gc mark and sweep */
152 		cp = EARGF(badusage());
153 		if (!isnum(cp))
154 			badusage();
155 		mflag = atoi(cp);
156 		if(mflag < 0|| mflag > 9)
157 			usage();
158 		break;
159 	case 'p':		/* pool option */
160 		poolopt(EARGF(badusage()));
161 		break;
162 	case 'f':		/* Set font path */
163 		tkfont = EARGF(badusage());
164 		break;
165 	case 'r':		/* Set inferno root */
166 		strecpy(rootdir, rootdir+sizeof(rootdir), EARGF(badusage()));
167 		break;
168 	case '7':		/* use 7 bit colormap in X */
169 		xtblbit = 1;
170 		break;
171 	case 'G':		/* allow global access to file system (obsolete) */
172 		break;
173 	case	'C':		/* channel specification for display */
174 		cp = EARGF(badusage());
175 		displaychan = strtochan(cp);
176 		if(displaychan == 0){
177 			fprint(2, "emu: invalid channel specifier (-C): %q\n", cp);
178 			exits("usage");
179 		}
180 		break;
181 	case 'S':
182 		tkstylus = 1;
183 		break;
184 	case 'v':
185 		vflag = 1;	/* print startup messages */
186 		break;
187 	} ARGEND
188 }
189 
190 static void
191 savestartup(int argc, char *argv[])
192 {
193 	int i;
194 
195 	rebootargc = argc;
196 	rebootargv = malloc((argc+1)*sizeof(char*));
197 	if(rebootargv == nil)
198 		panic("can't save startup args");
199 	for(i = 0; i < argc; i++) {
200 		rebootargv[i] = strdup(argv[i]);
201 		if(rebootargv[i] == nil)
202 			panic("can't save startup args");
203 	}
204 	rebootargv[i] = nil;
205 }
206 
207 void
208 putenvq(char *name, char *val, int conf)
209 {
210 	val = smprint("%q", val);
211 	ksetenv(name, val, conf);
212 	free(val);
213 }
214 
215 void
216 putenvqv(char *name, char **v, int n, int conf)
217 {
218 	Fmt f;
219 	int i;
220 	char *val;
221 
222 	fmtstrinit(&f);
223 	for(i=0; i<n; i++)
224 		fmtprint(&f, "%s%q", i?" ":"", v[i]);
225 	val = fmtstrflush(&f);
226 	ksetenv(name, val, conf);
227 	free(val);
228 }
229 
230 void
231 main(int argc, char *argv[])
232 {
233 	char *opt, *p;
234 	char *enva[20];
235 	int envc;
236 
237 	quotefmtinstall();
238 	savestartup(argc, argv);
239 	/* set default root now, so either $EMU or -r can override it later */
240 	if((p = getenv("INFERNO")) != nil || (p = getenv("ROOT")) != nil)
241 		strecpy(rootdir, rootdir+sizeof(rootdir), p);
242 	opt = getenv("EMU");
243 	if(opt != nil && *opt != '\0') {
244 		enva[0] = "emu";
245 		envc = tokenize(opt, &enva[1], sizeof(enva)-1) + 1;
246 		enva[envc] = 0;
247 		option(envc, enva, envusage);
248 	}
249 	option(argc, argv, usage);
250 	eve = strdup("inferno");
251 
252 	opt = "interp";
253 	if(cflag)
254 		opt = "compile";
255 
256 	if(vflag)
257 		print("Inferno %s main (pid=%d) %s\n", VERSION, getpid(), opt);
258 
259 	libinit(imod);
260 }
261 
262 void
263 emuinit(void *imod)
264 {
265 	Osenv *e;
266 	char *wdir;
267 
268 	e = up->env;
269 	e->pgrp = newpgrp();
270 	e->fgrp = newfgrp(nil);
271 	e->egrp = newegrp();
272 	e->errstr = e->errbuf0;
273 	e->syserrstr = e->errbuf1;
274 	e->user = strdup("");
275 
276 	links();
277 	chandevinit();
278 
279 	if(waserror())
280 		panic("setting root and dot");
281 
282 	e->pgrp->slash = namec("#/", Atodir, 0, 0);
283 	cnameclose(e->pgrp->slash->name);
284 	e->pgrp->slash->name = newcname("/");
285 	e->pgrp->dot = cclone(e->pgrp->slash);
286 	poperror();
287 
288 	strcpy(up->text, "main");
289 
290 	if(kopen("#c/cons", OREAD) != 0)
291 		fprint(2, "failed to make fd0 from #c/cons: %r\n");
292 	kopen("#c/cons", OWRITE);
293 	kopen("#c/cons", OWRITE);
294 
295 	/* the setid cannot precede the bind of #U */
296 	kbind("#U", "/", MAFTER|MCREATE);
297 	setid(eve, 0);
298 	kbind("#^", "/dev", MBEFORE);	/* snarf */
299 	kbind("#^", "/chan", MBEFORE);
300 	kbind("#m", "/dev", MBEFORE);	/* pointer */
301 	kbind("#c", "/dev", MBEFORE);
302 	kbind("#p", "/prog", MREPL);
303 	kbind("#d", "/fd", MREPL);
304 	kbind("#I", "/net", MAFTER);	/* will fail on Plan 9 */
305 
306 	/* BUG: we actually only need to do these on Plan 9 */
307 	kbind("#U/dev", "/dev", MAFTER);
308 	kbind("#U/net", "/net", MAFTER);
309 	kbind("#U/net.alt", "/net.alt", MAFTER);
310 
311 	if(cputype != nil)
312 		ksetenv("cputype", cputype, 1);
313 	putenvqv("emuargs", rebootargv, rebootargc, 1);
314 	putenvq("emuroot", rootdir, 1);
315 	ksetenv("emuhost", hosttype, 1);
316 	wdir = malloc(1024);
317 	if(wdir != nil){
318 		if(getwd(wdir, 1024) != nil)
319 			putenvq("emuwdir", wdir, 1);
320 		free(wdir);
321 	}
322 
323 	kproc("main", disinit, imod, KPDUPFDG|KPDUPPG|KPDUPENVG);
324 
325 	for(;;)
326 		ospause();
327 }
328 
329 void
330 errorf(char *fmt, ...)
331 {
332 	va_list arg;
333 	char buf[PRINTSIZE];
334 
335 	va_start(arg, fmt);
336 	vseprint(buf, buf+sizeof(buf), fmt, arg);
337 	va_end(arg);
338 	error(buf);
339 }
340 
341 void
342 error(char *err)
343 {
344 	if(err != up->env->errstr && up->env->errstr != nil)
345 		kstrcpy(up->env->errstr, err, ERRMAX);
346 //	ossetjmp(up->estack[NERR-1]);
347 	nexterror();
348 }
349 
350 void
351 exhausted(char *resource)
352 {
353 	char buf[64];
354 	int n;
355 
356 	n = snprint(buf, sizeof(buf), "no free %s\n", resource);
357 	iprint(buf);
358 	buf[n-1] = 0;
359 	error(buf);
360 }
361 
362 void
363 nexterror(void)
364 {
365 	oslongjmp(nil, up->estack[--up->nerr], 1);
366 }
367 
368 /* for dynamic modules - functions not macros */
369 
370 void*
371 waserr(void)
372 {
373 	up->nerr++;
374 	return up->estack[up->nerr-1];
375 }
376 
377 void
378 poperr(void)
379 {
380 	up->nerr--;
381 }
382 
383 char*
384 enverror(void)
385 {
386 	return up->env->errstr;
387 }
388 
389 void
390 panic(char *fmt, ...)
391 {
392 	va_list arg;
393 	char buf[512];
394 
395 	va_start(arg, fmt);
396 	vseprint(buf, buf+sizeof(buf), fmt, arg);
397 	va_end(arg);
398 	fprint(2, "panic: %s\n", buf);
399 	if(sflag)
400 		abort();
401 
402 	cleanexit(0);
403 }
404 
405 int
406 iprint(char *fmt, ...)
407 {
408 
409 	int n;
410 	va_list va;
411 	char buf[1024];
412 
413 	va_start(va, fmt);
414 	n = vseprint(buf, buf+sizeof buf, fmt, va) - buf;
415 	va_end(va);
416 
417 	write(1, buf, n);
418 	return 1;
419 }
420 
421 void
422 _assert(char *fmt)
423 {
424 	panic("assert failed: %s", fmt);
425 }
426 
427 /*
428  * mainly for libmp
429  */
430 void
431 sysfatal(char *fmt, ...)
432 {
433 	va_list arg;
434 	char buf[64];
435 
436 	va_start(arg, fmt);
437 	vsnprint(buf, sizeof(buf), fmt, arg);
438 	va_end(arg);
439 	error(buf);
440 }
441 
442 void
443 oserror(void)
444 {
445 	oserrstr(up->env->errstr, ERRMAX);
446 	error(up->env->errstr);
447 }
448