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