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