xref: /inferno-os/emu/port/main.c (revision 9bca6be9bfa93b52aeefad1e0ea9965d1fa5c53c)
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