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