ref: 568002402f2e2c18e807e80903c20337af523412
dir: /emu/port/main.c/
#include "dat.h" #include "fns.h" #include "error.h" #include "interp.h" #include "kernel.h" #include "draw.h" #include "version.h" #define DP if(1){}else print void (*coherence)(void) = nil; /* used by port/lock.c and port/win-x11a.c */ int exdebug = 0; int rebootargc = 0; char** rebootargv; char gkscanid[32] = ""; static char *imod = "/dis/emuinit.dis"; extern char* hosttype; extern char* tkfont; /* for libtk/utils.c */ extern int tkstylus; /* libinterp/tk.c */ extern int mflag; int dflag; int vflag; Procs procs; char *eve; int Xsize = 640; int Ysize = 480; int bflag = 1; int sflag; int qflag; int xtblbit; ulong displaychan; char *cputype; static void usage(void) { fprint(2, "Usage: emu [options...] [file.dis [args...]]\n" "\t-gXxY\n" "\t-c[0-9]\n" "\t-d file.dis\n" "\t-s\n" "\t-v\n" "\t-p<poolname>=maxsize\n" "\t-f<fontpath>\n" "\t-r<rootpath>\n" "\t-7\n" "\t-B\n" "\t-C<channel string>\n" "\t-S\n"); exits("usage"); } static void envusage(void) { fprint(2, "emu: bad option in EMU environment variable (%s)\n", getenv("EMU")); usage(); } static int isnum(char *p) { if (*p == 0) return 0; while (*p) { if (*p < '0' || *p > '9') return 0; p++; } return 1; } static int geom(char *val) { char *p; int x, y; if (val == '\0' || (*val < '0' || *val > '9')) return 0; x = strtoul(val, &p, 0); if(x >= 64) Xsize = x; if (*p++ != 'x' || !isnum(p)) return 0; y = strtoul(p, &p, 0); if(y >= 48) Ysize = y; if (*p != '\0') return 0; return 1; } static void poolopt(char *str) { char *var; int n; ulong x; var = str; while(*str && *str != '=') str++; if(*str != '=' || str[1] == '\0') usage(); *str++ = '\0'; n = strlen(str); x = atoi(str); switch(str[n - 1]){ case 'k': case 'K': x *= 1024; break; case 'm': case 'M': x *= 1024*1024; break; } if(poolsetsize(var, x) == 0) usage(); } static void option(int argc, char *argv[], void (*badusage)(void)) { char *cp; ARGBEGIN { default: badusage(); case 'g': /* Window geometry */ if (geom(EARGF(badusage())) == 0) badusage(); break; case 'b': /* jit array bounds checking (obsolete, now on by default) */ break; case 'B': /* suppress jit array bounds checks */ bflag = 0; break; case 'c': /* Compile on the fly */ cp = EARGF(badusage()); if (!isnum(cp)) badusage(); cflag = atoi(cp); if(cflag < 0|| cflag > 9) usage(); break; case 'I': /* (temporary option) run without cons */ dflag++; break; case 'd': /* run as a daemon */ dflag++; imod = EARGF(badusage()); break; case 's': /* No trap handling */ sflag++; break; case 'm': /* gc mark and sweep */ cp = EARGF(badusage()); if (!isnum(cp)) badusage(); mflag = atoi(cp); if(mflag < 0|| mflag > 9) usage(); break; case 'p': /* pool option */ poolopt(EARGF(badusage())); break; case 'f': /* Set font path */ tkfont = EARGF(badusage()); break; case 'r': /* Set inferno root */ strecpy(rootdir, rootdir+sizeof(rootdir), EARGF(badusage())); break; case '7': /* use 7 bit colormap in X */ xtblbit = 1; break; case 'G': /* allow global access to file system (obsolete) */ break; case 'C': /* channel specification for display */ cp = EARGF(badusage()); displaychan = strtochan(cp); if(displaychan == 0){ fprint(2, "emu: invalid channel specifier (-C): %q\n", cp); exits("usage"); } break; case 'S': tkstylus = 1; break; case 'v': vflag = 1; /* print startup messages */ break; } ARGEND } static void savestartup(int argc, char *argv[]) { int i; rebootargc = argc; rebootargv = malloc((argc+1)*sizeof(char*)); if(rebootargv == nil) panic("can't save startup args"); for(i = 0; i < argc; i++) { rebootargv[i] = strdup(argv[i]); if(rebootargv[i] == nil) panic("can't save startup args"); } rebootargv[i] = nil; } void putenvq(char *name, char *val, int conf) { val = smprint("%q", val); ksetenv(name, val, conf); free(val); } void putenvqv(char *name, char **v, int n, int conf) { Fmt f; int i; char *val; fmtstrinit(&f); for(i=0; i<n; i++) fmtprint(&f, "%s%q", i?" ":"", v[i]); val = fmtstrflush(&f); ksetenv(name, val, conf); free(val); } void nofence(void) { int i; USED(i); } void main(int argc, char *argv[]) { char *opt, *p; char *enva[20]; int envc; if(coherence == nil) coherence = nofence; quotefmtinstall(); savestartup(argc, argv); /* set default root now, so either $EMU or -r can override it later */ if((p = getenv("INFERNO")) != nil || (p = getenv("ROOT")) != nil) strecpy(rootdir, rootdir+sizeof(rootdir), p); opt = getenv("EMU"); if(opt != nil && *opt != '\0') { enva[0] = "emu"; envc = tokenize(opt, &enva[1], sizeof(enva)-1) + 1; enva[envc] = 0; option(envc, enva, envusage); } option(argc, argv, usage); eve = strdup("inferno"); opt = "interp"; if(cflag) opt = "compile"; if(vflag) print("Inferno %s main (pid=%d) %s\n", VERSION, getpid(), opt); libinit(imod); } void emuinit(void *imod) { Osenv *e; char *wdir; e = up->env; e->pgrp = newpgrp(); e->fgrp = newfgrp(nil); e->egrp = newegrp(); e->errstr = e->errbuf0; e->syserrstr = e->errbuf1; e->user = strdup(""); links(); chandevinit(); if(waserror()) panic("setting root and dot"); e->pgrp->slash = namec("#/", Atodir, 0, 0); cnameclose(e->pgrp->slash->name); e->pgrp->slash->name = newcname("/"); e->pgrp->dot = cclone(e->pgrp->slash); poperror(); strcpy(up->text, "main"); if(kopen("#c/cons", OREAD) != 0) fprint(2, "failed to make fd0 from #c/cons: %r\n"); kopen("#c/cons", OWRITE); kopen("#c/cons", OWRITE); /* the setid cannot precede the bind of #U */ kbind("#U", "/", MAFTER|MCREATE); setid(eve, 0); kbind("#^", "/dev", MBEFORE); /* snarf */ kbind("#^", "/chan", MBEFORE); kbind("#m", "/dev", MBEFORE); /* pointer */ kbind("#c", "/dev", MBEFORE); kbind("#p", "/prog", MREPL); kbind("#d", "/fd", MREPL); kbind("#I", "/net", MAFTER); /* will fail on Plan 9 */ /* BUG: we actually only need to do these on Plan 9 */ kbind("#U/dev", "/dev", MAFTER); kbind("#U/net", "/net", MAFTER); kbind("#U/net.alt", "/net.alt", MAFTER); if(cputype != nil) ksetenv("cputype", cputype, 1); putenvqv("emuargs", rebootargv, rebootargc, 1); putenvq("emuroot", rootdir, 1); ksetenv("emuhost", hosttype, 1); wdir = malloc(1024); if(wdir != nil){ if(getwd(wdir, 1024) != nil) putenvq("emuwdir", wdir, 1); free(wdir); } kproc("main", disinit, imod, KPDUPFDG|KPDUPPG|KPDUPENVG); for(;;) ospause(); } void errorf(char *fmt, ...) { va_list arg; char buf[PRINTSIZE]; va_start(arg, fmt); vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); error(buf); } void error(char *err) { DP("error pid %d err %p %s up->nerr %d up->env->errstr %s getcallerpc %p\n", up->pid, err, err, up->nerr, up->env->errstr, getcallerpc(&err)); DP("error pid %d err %p %s up->nerr %d getcallerpc %p\n", up->pid, err, err, up->nerr, getcallerpc(&err)); if(err != up->env->errstr && up->env->errstr != nil){ kstrcpy(up->env->errstr, err, ERRMAX); DP("error after kstrcpy err %p %s up->nerr %d up->env->errstr %s\n", err, err, up->nerr, up->env->errstr); } // ossetjmp(up->estack[NERR-1]); nexterror(); } void exhausted(char *resource) { char buf[64]; int n; n = snprint(buf, sizeof(buf), "no free %s\n", resource); iprint(buf); buf[n-1] = 0; error(buf); } void showjmpbuf(char *str) { DP("%p called %s pid %d up->nerr %d\n", getcallerpc(&str), str, up->pid, up->nerr); for(int i = 0; i<up->nerr; i++){ DP(" i %d: %p has %p", i, up->estack[i], *(uintptr*)(up->estack[i])); /* below segfaults on OpenBSD */ /* DP("has %p", **(uintptr**)(up->estack[i])); */ DP("\n"); } } void nexterror(void) { showjmpbuf("nexterror"); oslongjmp(nil, up->estack[--up->nerr], 1); } /* for dynamic modules - functions not macros */ void* waserr(void) { up->nerr++; return up->estack[up->nerr-1]; } void poperr(void) { up->nerr--; } char* enverror(void) { return up->env->errstr; } void panic(char *fmt, ...) { va_list arg; char buf[512]; va_start(arg, fmt); vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); fprint(2, "panic: %s\n", buf); if(sflag) abort(); cleanexit(0); } int iprint(char *fmt, ...) { int n; va_list va; char buf[1024]; va_start(va, fmt); n = vseprint(buf, buf+sizeof buf, fmt, va) - buf; va_end(va); write(1, buf, n); return 1; } void _assert(char *fmt) { panic("assert failed: %s", fmt); } /* * mainly for libmp */ void sysfatal(char *fmt, ...) { va_list arg; char buf[64]; va_start(arg, fmt); vsnprint(buf, sizeof(buf), fmt, arg); va_end(arg); error(buf); } void oserror(void) { oserrstr(up->env->errstr, ERRMAX); error(up->env->errstr); }