| plan 9 kernel history: overview | file list | diff list |
1999/0728/port/devcons.c (diff list | history)
| port/devcons.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1990/0227 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1990/0227 | ||
| 1997/0327 | void (*consdebug)(void); | |
| 1990/0227 | ||
| 1997/0327 | Queue* kbdq; /* unprocessed console input */ Queue* lineq; /* processed console input */ Queue* printq; /* console output */ | |
| 1990/0227 | ||
| 1993/0601 | static struct { QLock; | |
| 1990/0227 | ||
| 1993/0601 | int raw; /* true if we shouldn't process input */ int ctl; /* number of opens to the control file */ int x; /* index into line */ char line[1024]; /* current input line */ | |
| 1990/0227 | ||
| 1995/0815 | Rune c; | |
| 1993/0601 | int count; int repeat; | |
| 1995/0112 | int ctlpoff; | |
| 1993/0601 | } kbd; | |
| 1992/0321 | char sysname[NAMELEN]; | |
| 1999/0219 | vlong fasthz; | |
| 1991/1109 | ||
| 1997/0327 | static ulong randomread(void*, ulong); | |
| 1996/1031 | static void randominit(void); | |
| 1998/0731 | static void seedrand(void); | |
| 1999/0711 | static int readtime(ulong, char*, int); static int readbintime(char*, int); static int writetime(char*, int); static int writebintime(char*, int); | |
| 1995/0910 | ||
| 1990/0227 | void | |
| 1991/0607 | printinit(void) | |
| 1990/0227 | { | |
| 1993/0601 | lineq = qopen(2*1024, 0, 0, 0); | |
| 1997/1105 | if(lineq == nil) panic("printinit"); | |
| 1994/0902 | qnoblock(lineq, 1); | |
| 1990/0227 | } | |
| 1997/0327 | int consactive(void) { if(printq) return qlen(printq) > 0; return 0; } void prflush(void) { while(consactive()) ; } | |
| 1990/0227 | /* | |
| 1991/0809 | * Print a string on the console. Convert \n to \r\n for serial * line consoles. Locking of the queues is left up to the screen * or uart code. Multi-line messages to serial consoles may get * interspersed with other messages. | |
| 1990/0227 | */ | |
| 1994/0208 | static void putstrn0(char *str, int n, int usewrite) | |
| 1990/0227 | { | |
| 1994/1124 | int m; | |
| 1990/0227 | char *t; | |
| 1993/0806 | char buf[PRINTSIZE+2]; | |
| 1990/0227 | ||
| 1991/0809 | /* * if there's an attached bit mapped display, * put the message there. screenputs is defined * as a null macro for systems that have no such * display. */ screenputs(str, n); /* * if there's a serial line being used as a console, | |
| 1993/0807 | * put the message there. | |
| 1991/0809 | */ | |
| 1993/0601 | if(printq == 0) | |
| 1991/0809 | return; | |
| 1993/0806 | while(n > 0) { | |
| 1991/0809 | t = memchr(str, '\n', n); | |
| 1993/0806 | if(t) { | |
| 1991/0809 | m = t - str; memmove(buf, str, m); buf[m] = '\r'; buf[m+1] = '\n'; | |
| 1994/0208 | if(usewrite) | |
| 1994/0902 | qwrite(printq, buf, m+2); | |
| 1994/1124 | else qiwrite(printq, buf, m+2); | |
| 1991/0809 | str = t + 1; n -= m + 1; | |
| 1994/0208 | } else { if(usewrite) | |
| 1994/0902 | qwrite(printq, str, n); | |
| 1998/0512 | else | |
| 1994/1124 | qiwrite(printq, str, n); | |
| 1991/0809 | break; } | |
| 1990/0227 | } } | |
| 1994/0208 | void putstrn(char *str, int n) { putstrn0(str, n, 0); } | |
| 1990/0227 | int | |
| 1995/0117 | snprint(char *s, int n, char *fmt, ...) { | |
| 1996/0214 | va_list arg; va_start(arg, fmt); n = doprint(s, s+n, fmt, arg) - s; va_end(arg); return n; | |
| 1995/0117 | } int | |
| 1990/0227 | sprint(char *s, char *fmt, ...) { | |
| 1996/0214 | int n; | |
| 1997/0327 | va_list arg; | |
| 1996/0214 | va_start(arg, fmt); n = doprint(s, s+PRINTSIZE, fmt, arg) - s; va_end(arg); return n; | |
| 1990/0227 | } int print(char *fmt, ...) { int n; | |
| 1997/0327 | va_list arg; char buf[PRINTSIZE]; | |
| 1990/0227 | ||
| 1996/0214 | va_start(arg, fmt); n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); | |
| 1990/0227 | putstrn(buf, n); | |
| 1993/0806 | ||
| 1990/0227 | return n; } void panic(char *fmt, ...) { int n; | |
| 1997/0327 | va_list arg; char buf[PRINTSIZE]; | |
| 1990/0227 | ||
| 1991/1011 | strcpy(buf, "panic: "); | |
| 1996/0214 | va_start(arg, fmt); n = doprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; va_end(arg); | |
| 1990/0227 | buf[n] = '\n'; putstrn(buf, n+1); | |
| 1994/0224 | spllo(); | |
| 1993/0829 | prflush(); | |
| 1990/0907 | dumpstack(); | |
| 1994/0219 | ||
| 1992/0812 | exit(1); | |
| 1990/0227 | } | |
| 1994/0305 | ||
| 1990/0227 | int pprint(char *fmt, ...) { | |
| 1997/0327 | int n; | |
| 1990/0227 | Chan *c; | |
| 1996/0214 | va_list arg; | |
| 1997/0327 | char buf[2*PRINTSIZE]; | |
| 1990/0227 | ||
| 1993/0501 | if(up->fgrp == 0) | |
| 1991/0720 | return 0; | |
| 1993/0501 | c = up->fgrp->fd[2]; | |
| 1993/0330 | if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) | |
| 1990/0321 | return 0; | |
| 1998/0825 | n = sprint(buf, "%s %lud: ", up->text, up->pid); | |
| 1996/0214 | va_start(arg, fmt); n = doprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); | |
| 1992/0825 | ||
| 1993/0401 | if(waserror()) return 0; | |
| 1997/0327 | devtab[c->type]->write(c, buf, n, c->offset); | |
| 1993/0401 | poperror(); | |
| 1992/0825 | lock(c); | |
| 1990/0227 | c->offset += n; | |
| 1992/0825 | unlock(c); | |
| 1993/0330 | ||
| 1990/0227 | return n; } void | |
| 1991/1223 | echo(Rune r, char *buf, int n) | |
| 1990/0227 | { | |
| 1993/1016 | static int ctrlt, pid; extern ulong etext; | |
| 1998/0808 | int x; | |
| 1990/03091 | ||
| 1990/0227 | /* | |
| 1991/0607 | * ^p hack | |
| 1990/0227 | */ | |
| 1996/0119 | if(r==0x10 && cpuserver && !kbd.ctlpoff){ lock(&active); active.exiting = 1; unlock(&active); } | |
| 1991/0608 | ||
| 1991/0607 | /* * ^t hack BUG */ | |
| 1994/0313 | if(ctrlt == 2){ | |
| 1991/0607 | ctrlt = 0; | |
| 1991/1223 | switch(r){ | |
| 1991/0607 | case 0x14: break; /* pass it on */ | |
| 1994/0813 | case 's': dumpstack(); break; | |
| 1992/0619 | case 'x': xsummary(); | |
| 1993/0819 | ixsummary(); | |
| 1999/0710 | mallocsummary(); | |
| 1999/0110 | pagersummary(); | |
| 1992/0619 | break; | |
| 1992/0411 | case 'd': | |
| 1997/0327 | if(consdebug != nil) consdebug(); | |
| 1992/0411 | return; | |
| 1991/0607 | case 'p': | |
| 1998/0808 | x = spllo(); | |
| 1991/0608 | procdump(); | |
| 1998/0808 | splx(x); | |
| 1991/0607 | return; | |
| 1995/1030 | case 'q': scheddump(); break; | |
| 1995/0319 | case 'k': if(!cpuserver) killbig(); break; | |
| 1991/0607 | case 'r': | |
| 1992/0812 | exit(0); | |
| 1991/0607 | break; } | |
| 1994/0313 | } else if(r == 0x14){ ctrlt++; return; | |
| 1991/0607 | } ctrlt = 0; | |
| 1993/0601 | if(kbd.raw) | |
| 1991/0607 | return; | |
| 1993/0601 | /* * finally, the actual echoing */ | |
| 1993/1005 | if(r == '\n'){ if(printq) | |
| 1994/1124 | qiwrite(printq, "\r", 1); | |
| 1993/1005 | } else if(r == 0x15){ buf = "^U\n"; n = 3; } screenputs(buf, n); if(printq) | |
| 1994/1124 | qiwrite(printq, buf, n); | |
| 1990/0227 | } /* | |
| 1993/0601 | * Called by a uart interrupt for console input. * * turn '\r' into '\n' before putting it into the queue. | |
| 1991/0727 | */ int | |
| 1993/0601 | kbdcr2nl(Queue *q, int ch) | |
| 1991/0727 | { if(ch == '\r') ch = '\n'; return kbdputc(q, ch); } /* | |
| 1991/1223 | * Put character, possibly a rune, into read queue at interrupt time. | |
| 1993/0601 | * Called at interrupt time to process a character. | |
| 1990/0227 | */ | |
| 1991/0607 | int | |
| 1995/0804 | kbdputc(Queue*, int ch) | |
| 1990/0227 | { | |
| 1993/0601 | int n; | |
| 1991/1223 | char buf[3]; Rune r; r = ch; n = runetochar(buf, &r); if(n == 0) return 0; echo(r, buf, n); | |
| 1995/0815 | kbd.c = r; | |
| 1993/0601 | qproduce(kbdq, buf, n); | |
| 1991/0607 | return 0; | |
| 1990/0227 | } void | |
| 1991/0607 | kbdrepeat(int rep) | |
| 1990/0227 | { | |
| 1993/0601 | kbd.repeat = rep; kbd.count = 0; | |
| 1991/0607 | } | |
| 1990/0227 | ||
| 1991/0607 | void kbdclock(void) { | |
| 1993/0601 | if(kbd.repeat == 0) | |
| 1991/0607 | return; | |
| 1993/0601 | if(kbd.repeat==1 && ++kbd.count>HZ){ kbd.repeat = 2; kbd.count = 0; | |
| 1991/0607 | return; | |
| 1990/0227 | } | |
| 1993/0601 | if(++kbd.count&1) kbdputc(kbdq, kbd.c); | |
| 1990/0227 | } enum{ | |
| 1992/0506 | Qdir, | |
| 1993/0330 | Qauth, Qauthcheck, | |
| 1993/0731 | Qauthent, | |
| 1999/0711 | Qbintime, | |
| 1990/0227 | Qcons, | |
| 1991/1224 | Qconsctl, | |
| 1990/0227 | Qcputime, | |
| 1997/0410 | Qdrivers, | |
| 1992/0428 | Qkey, | |
| 1993/0330 | Qhostdomain, Qhostowner, | |
| 1990/0227 | Qnull, Qpgrpid, Qpid, Qppid, | |
| 1995/0910 | Qrandom, | |
| 1996/03071 | Qreboot, | |
| 1991/0705 | Qswap, | |
| 1992/0321 | Qsysname, | |
| 1992/0428 | Qsysstat, Qtime, Quser, | |
| 1999/0710 | Qzero, | |
| 1990/0227 | }; | |
| 1999/0728 | enum { VLNUMSIZE= 22, }; | |
| 1997/0410 | static Dirtab consdir[]={ | |
| 1993/0330 | "authenticate", {Qauth}, 0, 0666, "authcheck", {Qauthcheck}, 0, 0666, | |
| 1993/0731 | "authenticator", {Qauthent}, 0, 0666, | |
| 1999/0711 | "bintime", {Qbintime}, 24, 0664, | |
| 1991/1211 | "cons", {Qcons}, 0, 0660, | |
| 1991/1224 | "consctl", {Qconsctl}, 0, 0220, | |
| 1991/1127 | "cputime", {Qcputime}, 6*NUMSIZE, 0444, | |
| 1997/0410 | "drivers", {Qdrivers}, 0, 0644, | |
| 1993/0402 | "hostdomain", {Qhostdomain}, DOMLEN, 0664, "hostowner", {Qhostowner}, NAMELEN, 0664, | |
| 1992/0428 | "key", {Qkey}, DESKEYLEN, 0622, | |
| 1991/1112 | "null", {Qnull}, 0, 0666, | |
| 1991/1127 | "pgrpid", {Qpgrpid}, NUMSIZE, 0444, "pid", {Qpid}, NUMSIZE, 0444, "ppid", {Qppid}, NUMSIZE, 0444, | |
| 1995/0910 | "random", {Qrandom}, 0, 0664, | |
| 1996/03071 | "reboot", {Qreboot}, 0, 0664, | |
| 1991/1211 | "swap", {Qswap}, 0, 0664, | |
| 1992/0428 | "sysname", {Qsysname}, 0, 0664, "sysstat", {Qsysstat}, 0, 0666, | |
| 1999/0728 | "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664, | |
| 1998/0808 | "user", {Quser}, NAMELEN, 0666, | |
| 1999/0714 | "zero", {Qzero}, 0, 0444, | |
| 1990/0227 | }; int readnum(ulong off, char *buf, ulong n, ulong val, int size) { char tmp[64]; | |
| 1998/0825 | snprint(tmp, sizeof(tmp), "%*.0lud", size-1, val); | |
| 1990/0227 | tmp[size-1] = ' '; | |
| 1990/0312 | if(off >= size) return 0; | |
| 1990/0227 | if(off+n > size) n = size-off; | |
| 1991/0318 | memmove(buf, tmp+off, n); | |
| 1990/0227 | return n; } int readstr(ulong off, char *buf, ulong n, char *str) { int size; size = strlen(str); | |
| 1990/0312 | if(off >= size) return 0; | |
| 1990/0227 | if(off+n > size) n = size-off; | |
| 1991/0318 | memmove(buf, str+off, n); | |
| 1990/0227 | return n; } | |
| 1997/0327 | static void | |
| 1990/0227 | consinit(void) { | |
| 1999/0219 | todinit(); | |
| 1995/0913 | randominit(); | |
| 1990/0227 | } | |
| 1997/0327 | static Chan* | |
| 1990/0227 | consattach(char *spec) { return devattach('c', spec); } | |
| 1997/0327 | static int | |
| 1990/0227 | conswalk(Chan *c, char *name) { | |
| 1997/0327 | return devwalk(c, name, consdir, nelem(consdir), devgen); | |
| 1990/0227 | } | |
| 1997/0327 | static void | |
| 1990/0227 | consstat(Chan *c, char *dp) { | |
| 1997/0327 | devstat(c, dp, consdir, nelem(consdir), devgen); | |
| 1990/0227 | } | |
| 1997/0327 | static Chan* | |
| 1990/0227 | consopen(Chan *c, int omode) { | |
| 1993/0330 | c->aux = 0; | |
| 1991/0607 | switch(c->qid.path){ | |
| 1991/1224 | case Qconsctl: | |
| 1993/0330 | if(!iseve()) | |
| 1991/0620 | error(Eperm); | |
| 1993/0601 | qlock(&kbd); kbd.ctl++; qunlock(&kbd); | |
| 1991/0607 | break; | |
| 1990/0227 | } | |
| 1997/0327 | return devopen(c, omode, consdir, nelem(consdir), devgen); | |
| 1990/0227 | } | |
| 1997/0327 | static void | |
| 1990/0227 | consclose(Chan *c) { | |
| 1991/1224 | /* last close of control file turns off raw */ | |
| 1993/0330 | switch(c->qid.path){ case Qconsctl: if(c->flag&COPEN){ | |
| 1993/0601 | qlock(&kbd); if(--kbd.ctl == 0) kbd.raw = 0; qunlock(&kbd); | |
| 1993/0330 | } | |
| 1993/1031 | break; | |
| 1993/0330 | case Qauth: case Qauthcheck: | |
| 1993/0731 | case Qauthent: | |
| 1993/0330 | authclose(c); | |
| 1991/1224 | } | |
| 1990/0227 | } | |
| 1997/0327 | static long | |
| 1998/0319 | consread(Chan *c, void *buf, long n, vlong off) | |
| 1990/0227 | { ulong l; | |
| 1991/0425 | Mach *mp; | |
| 1993/0725 | char *b, *bp; char tmp[128]; /* must be >= 6*NUMSIZE */ char *cbuf = buf; int ch, i, k, id, eol; | |
| 1999/0711 | vlong offset = off; | |
| 1990/0227 | if(n <= 0) return n; | |
| 1990/11211 | switch(c->qid.path & ~CHDIR){ | |
| 1990/0227 | case Qdir: | |
| 1997/0327 | return devdirread(c, buf, n, consdir, nelem(consdir), devgen); | |
| 1990/0227 | case Qcons: | |
| 1993/0601 | qlock(&kbd); | |
| 1997/0327 | if(waserror()) { | |
| 1993/0601 | qunlock(&kbd); | |
| 1990/0617 | nexterror(); } | |
| 1997/0820 | if(kbd.raw) { if(qcanread(lineq)) n = qread(lineq, buf, n); | |
| 1997/0821 | else { /* read as much as possible */ do { i = qread(kbdq, cbuf, n); cbuf += i; n -= i; } while (n>0 && qcanread(kbdq)); n = cbuf - (char*)buf; } | |
| 1997/0820 | } else { while(!qcanread(lineq)) { qread(kbdq, &kbd.line[kbd.x], 1); ch = kbd.line[kbd.x]; if(kbd.raw){ qiwrite(lineq, kbd.line, kbd.x+1); kbd.x = 0; continue; } eol = 0; switch(ch){ case '\b': if(kbd.x) kbd.x--; break; case 0x15: kbd.x = 0; break; case '\n': case 0x04: eol = 1; default: kbd.line[kbd.x++] = ch; break; } if(kbd.x == sizeof(kbd.line) || eol){ if(ch == 0x04) kbd.x--; qwrite(lineq, kbd.line, kbd.x); kbd.x = 0; } | |
| 1993/0601 | } | |
| 1997/0820 | n = qread(lineq, buf, n); | |
| 1990/0227 | } | |
| 1993/0601 | qunlock(&kbd); | |
| 1993/0725 | poperror(); | |
| 1993/0601 | return n; | |
| 1990/0227 | case Qcputime: | |
| 1991/0411 | k = offset; | |
| 1993/0408 | if(k >= 6*NUMSIZE) | |
| 1990/0312 | return 0; | |
| 1993/0408 | if(k+n > 6*NUMSIZE) n = 6*NUMSIZE - k; | |
| 1990/0227 | /* easiest to format in a separate buffer and copy out */ for(i=0; i<6 && NUMSIZE*i<k+n; i++){ | |
| 1993/0501 | l = up->time[i]; | |
| 1990/0227 | if(i == TReal) l = MACHP(0)->ticks - l; | |
| 1990/0614 | l = TK2MS(l); | |
| 1990/0227 | readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); } | |
| 1991/0318 | memmove(buf, tmp+k, n); | |
| 1990/0227 | return n; case Qpgrpid: | |
| 1998/0617 | return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE); | |
| 1990/0227 | case Qpid: | |
| 1998/0617 | return readnum((ulong)offset, buf, n, up->pid, NUMSIZE); | |
| 1990/0227 | case Qppid: | |
| 1998/0617 | return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE); | |
| 1990/0227 | ||
| 1999/0711 | case Qtime: return readtime((ulong)offset, buf, n); | |
| 1998/0710 | ||
| 1999/0711 | case Qbintime: return readbintime(buf, n); | |
| 1998/0710 | ||
| 1993/0330 | case Qkey: return keyread(buf, n, offset); | |
| 1991/1127 | ||
| 1993/0330 | case Qauth: return authread(c, cbuf, n); | |
| 1992/0323 | ||
| 1998/0422 | case Qauthcheck: return authcheckread(c, cbuf, n); | |
| 1993/0731 | case Qauthent: return authentread(c, cbuf, n); | |
| 1993/0330 | case Qhostowner: | |
| 1998/0617 | return readstr((ulong)offset, buf, n, eve); | |
| 1991/1127 | ||
| 1993/0330 | case Qhostdomain: | |
| 1998/0617 | return readstr((ulong)offset, buf, n, hostdomain); | |
| 1993/0330 | ||
| 1990/0227 | case Quser: | |
| 1998/0617 | return readstr((ulong)offset, buf, n, up->user); | |
| 1990/0227 | ||
| 1991/0607 | case Qnull: return 0; | |
| 1991/0425 | case Qsysstat: | |
| 1992/0814 | b = smalloc(conf.nmach*(NUMSIZE*8+1) + 1); /* +1 for NUL */ bp = b; | |
| 1991/0425 | for(id = 0; id < 32; id++) { if(active.machs & (1<<id)) { mp = MACHP(id); | |
| 1992/0814 | readnum(0, bp, NUMSIZE, id, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE); bp += NUMSIZE; readnum(0, bp, NUMSIZE, mp->load, NUMSIZE); bp += NUMSIZE; *bp++ = '\n'; | |
| 1991/0425 | } } | |
| 1998/0617 | n = readstr((ulong)offset, buf, n, b); | |
| 1992/0814 | free(b); return n; | |
| 1990/0227 | ||
| 1991/0705 | case Qswap: | |
| 1998/0825 | sprint(tmp, "%lud/%lud memory %lud/%lud swap\n", | |
| 1993/1120 | palloc.user-palloc.freecount, | |
| 1993/0910 | palloc.user, conf.nswap-swapalloc.free, conf.nswap); | |
| 1991/0705 | ||
| 1998/0617 | return readstr((ulong)offset, buf, n, tmp); | |
| 1992/0321 | case Qsysname: | |
| 1998/0617 | return readstr((ulong)offset, buf, n, sysname); | |
| 1992/0321 | ||
| 1995/0910 | case Qrandom: return randomread(buf, n); | |
| 1997/0410 | case Qdrivers: | |
| 1997/0417 | b = malloc(READSTR); | |
| 1997/0410 | if(b == nil) error(Enomem); n = 0; for(i = 0; devtab[i] != nil; i++) | |
| 1997/0417 | n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name); | |
| 1998/0617 | n = readstr((ulong)offset, buf, n, b); | |
| 1997/0410 | free(b); return n; | |
| 1995/0910 | ||
| 1999/0710 | case Qzero: memset(buf, 0, n); return n; | |
| 1990/0227 | default: | |
| 1998/0811 | print("consread %lux\n", c->qid.path); | |
| 1991/1127 | error(Egreg); | |
| 1990/0227 | } | |
| 1992/0520 | return -1; /* never reached */ | |
| 1990/0227 | } | |
| 1997/0327 | static long | |
| 1998/0319 | conswrite(Chan *c, void *va, long n, vlong off) | |
| 1990/0227 | { char buf[256]; | |
| 1991/1116 | long l, bp; | |
| 1993/0330 | char *a = va; | |
| 1991/0425 | Mach *mp; | |
| 1993/0601 | int id, fd; | |
| 1991/0705 | Chan *swc; | |
| 1998/0319 | ulong offset = off; | |
| 1990/0227 | ||
| 1990/11211 | switch(c->qid.path){ | |
| 1990/0227 | case Qcons: /* | |
| 1991/1206 | * Can't page fault in putstrn, so copy the data locally. | |
| 1990/0227 | */ l = n; while(l > 0){ | |
| 1991/1116 | bp = l; if(bp > sizeof buf) bp = sizeof buf; memmove(buf, a, bp); | |
| 1994/0208 | putstrn0(a, bp, 1); | |
| 1991/1116 | a += bp; l -= bp; | |
| 1991/1224 | } break; case Qconsctl: if(n >= sizeof(buf)) n = sizeof(buf)-1; strncpy(buf, a, n); buf[n] = 0; for(a = buf; a;){ if(strncmp(a, "rawon", 5) == 0){ | |
| 1993/0601 | qlock(&kbd); if(kbd.x){ | |
| 1994/0902 | qwrite(kbdq, kbd.line, kbd.x); | |
| 1993/0601 | kbd.x = 0; | |
| 1991/1224 | } | |
| 1993/0601 | kbd.raw = 1; qunlock(&kbd); | |
| 1991/1224 | } else if(strncmp(a, "rawoff", 6) == 0){ | |
| 1993/0601 | kbd.raw = 0; | |
| 1993/0725 | kbd.x = 0; | |
| 1995/0112 | } else if(strncmp(a, "ctlpon", 6) == 0){ kbd.ctlpoff = 0; } else if(strncmp(a, "ctlpoff", 7) == 0){ kbd.ctlpoff = 1; | |
| 1991/1224 | } if(a = strchr(a, ' ')) a++; | |
| 1990/0227 | } break; case Qtime: | |
| 1999/0711 | if(!iseve()) error(Eperm); return writetime(a, n); | |
| 1999/0218 | ||
| 1999/0711 | case Qbintime: if(!iseve()) error(Eperm); return writebintime(a, n); | |
| 1999/0218 | ||
| 1991/1127 | case Qkey: | |
| 1993/0330 | return keywrite(a, n); | |
| 1991/1127 | ||
| 1993/0330 | case Qhostowner: return hostownerwrite(a, n); case Qhostdomain: return hostdomainwrite(a, n); | |
| 1990/0227 | case Quser: | |
| 1993/0330 | return userwrite(a, n); | |
| 1990/0227 | ||
| 1993/0330 | case Qauth: return authwrite(c, a, n); case Qauthcheck: return authcheck(c, a, n); | |
| 1993/0731 | case Qauthent: return authentwrite(c, a, n); | |
| 1993/0428 | ||
| 1990/0227 | case Qnull: break; | |
| 1990/11161 | ||
| 1996/03071 | case Qreboot: if(!iseve()) error(Eperm); | |
| 1997/0831 | if(strncmp(a, "reboot", 6) == 0){ print("conswrite: reboot\n"); | |
| 1996/03071 | exit(0); | |
| 1997/0831 | } | |
| 1999/0720 | if(strncmp(a, "panic", 5) == 0) panic("/dev/reboot"); | |
| 1991/0607 | break; | |
| 1991/0425 | case Qsysstat: for(id = 0; id < 32; id++) { if(active.machs & (1<<id)) { mp = MACHP(id); mp->cs = 0; mp->intr = 0; mp->syscall = 0; mp->pfault = 0; mp->tlbfault = 0; mp->tlbpurge = 0; } } break; | |
| 1991/0705 | case Qswap: if(n >= sizeof buf) error(Egreg); memmove(buf, va, n); /* so we can NUL-terminate */ buf[n] = 0; | |
| 1992/0825 | /* start a pager if not already started */ | |
| 1992/0310 | if(strncmp(buf, "start", 5) == 0){ | |
| 1992/0825 | kickpager(); | |
| 1992/0310 | break; } | |
| 1993/0501 | if(cpuserver && !iseve()) | |
| 1992/0310 | error(Eperm); if(buf[0]<'0' || '9'<buf[0]) | |
| 1992/0228 | error(Ebadarg); | |
| 1991/0705 | fd = strtoul(buf, 0, 0); | |
| 1998/0403 | swc = fdtochan(fd, -1, 1, 1); | |
| 1991/0705 | setswapchan(swc); | |
| 1992/0321 | break; case Qsysname: if(offset != 0) error(Ebadarg); if(n <= 0 || n >= NAMELEN) error(Ebadarg); strncpy(sysname, a, n); sysname[n] = 0; if(sysname[n-1] == '\n') sysname[n-1] = 0; | |
| 1992/0310 | break; | |
| 1991/0607 | ||
| 1990/0227 | default: | |
| 1998/0825 | print("conswrite: %lud\n", c->qid.path); | |
| 1990/11211 | error(Egreg); | |
| 1990/0227 | } return n; | |
| 1995/0108 | } | |
| 1990/0227 | void | |
| 1991/1102 | setterm(char *f) { char buf[2*NAMELEN]; sprint(buf, f, conffile); ksetenv("terminal", buf); | |
| 1995/0910 | } | |
| 1997/0327 | Dev consdevtab = { | |
| 1997/0408 | 'c', "cons", | |
| 1997/0327 | devreset, consinit, consattach, devclone, conswalk, consstat, consopen, devcreate, consclose, consread, devbread, conswrite, devbwrite, devremove, devwstat, }; | |
| 1998/0829 | struct Rb | |
| 1995/0910 | { QLock; | |
| 1995/0913 | Rendez producer; Rendez consumer; | |
| 1997/0327 | ulong randomcount; | |
| 1998/0702 | uchar buf[1024]; | |
| 1995/0910 | uchar *ep; uchar *rp; uchar *wp; uchar next; uchar wakeme; | |
| 1996/1029 | ushort bits; ulong randn; | |
| 1995/0910 | } rb; | |
| 1996/1031 | static void | |
| 1998/0731 | seedrand(void) | |
| 1996/1031 | { | |
| 1997/0327 | randomread((void*)&rb.randn, sizeof(rb.randn)); | |
| 1996/1031 | } | |
| 1996/1029 | int nrand(int n) { | |
| 1998/0731 | if(rb.randn == 0) seedrand(); | |
| 1996/1029 | rb.randn = rb.randn*1103515245 + 12345 + MACHP(0)->ticks; return (rb.randn>>16) % n; } | |
| 1995/0910 | ||
| 1998/0731 | int rand(void) { nrand(1); return rb.randn; } | |
| 1995/0913 | static int rbnotfull(void*) { int i; i = rb.rp - rb.wp; return i != 1 && i != (1 - sizeof(rb.buf)); } | |
| 1997/0327 | static int rbnotempty(void*) { return rb.wp != rb.rp; } | |
| 1995/0910 | void | |
| 1995/0913 | genrandom(void*) | |
| 1995/0910 | { | |
| 1995/0913 | up->basepri = PriNormal; up->priority = up->basepri; for(;;){ | |
| 1995/1023 | for(;;) | |
| 1999/0713 | if(++rb.randomcount > 100000) | |
| 1995/1023 | break; | |
| 1998/0829 | if(anyhigher()) sched(); | |
| 1995/0913 | if(!rbnotfull(0)) sleep(&rb.producer, rbnotfull, 0); } } | |
| 1995/0910 | /* * produce random bits in a circular buffer */ | |
| 1997/0413 | static void | |
| 1995/0910 | randomclock(void) { | |
| 1995/1023 | if(rb.randomcount == 0 || !rbnotfull(0)) | |
| 1995/0910 | return; | |
| 1995/1023 | rb.bits = (rb.bits<<2) ^ rb.randomcount; rb.randomcount = 0; | |
| 1995/0913 | ||
| 1995/1023 | rb.next++; if(rb.next != 8/2) | |
| 1995/0910 | return; rb.next = 0; | |
| 1995/1023 | *rb.wp ^= rb.bits; if(rb.wp+1 == rb.ep) rb.wp = rb.buf; else rb.wp = rb.wp+1; | |
| 1995/0910 | if(rb.wakeme) | |
| 1995/0913 | wakeup(&rb.consumer); | |
| 1997/0413 | } static void randominit(void) { addclock0link(randomclock); rb.ep = rb.buf + sizeof(rb.buf); rb.rp = rb.wp = rb.buf; kproc("genrandom", genrandom, 0); | |
| 1995/0910 | } /* * consume random bytes from a circular buffer */ static ulong | |
| 1997/0327 | randomread(void *xp, ulong n) | |
| 1995/0910 | { | |
| 1997/0327 | uchar *e, *p; | |
| 1997/0616 | ulong x; | |
| 1997/0327 | p = xp; | |
| 1995/0910 | if(waserror()){ qunlock(&rb); nexterror(); } qlock(&rb); | |
| 1995/1023 | for(e = p + n; p < e; ){ if(rb.wp == rb.rp){ | |
| 1995/0910 | rb.wakeme = 1; | |
| 1995/1023 | wakeup(&rb.producer); | |
| 1995/0913 | sleep(&rb.consumer, rbnotempty, 0); | |
| 1995/0910 | rb.wakeme = 0; continue; } | |
| 1997/0616 | /* * beating clocks will be precictable if * they are synchronized. Use a cheap pseudo * random number generator to obscure any cycles. */ x = rb.randn*1103515245 ^ *rb.rp; *p++ = rb.randn = x; | |
| 1995/1023 | if(rb.rp+1 == rb.ep) rb.rp = rb.buf; else rb.rp = rb.rp+1; | |
| 1995/0910 | } qunlock(&rb); poperror(); | |
| 1995/0913 | wakeup(&rb.producer); | |
| 1995/0910 | ||
| 1999/0711 | return n; } static uvlong uvorder = 0x0001020304050607ULL; static uchar* le2vlong(vlong *to, uchar *f) { uchar *t, *o; int i; t = (uchar*)to; o = (uchar*)&uvorder; for(i = 0; i < sizeof(vlong); i++) t[o[i]] = f[i]; return f+sizeof(vlong); } static uchar* vlong2le(uchar *t, vlong from) { uchar *f, *o; int i; f = (uchar*)&from; o = (uchar*)&uvorder; for(i = 0; i < sizeof(vlong); i++) t[i] = f[o[i]]; return t+sizeof(vlong); } static long order = 0x00010203; static uchar* le2long(long *to, uchar *f) { uchar *t, *o; int i; t = (uchar*)to; o = (uchar*)ℴ for(i = 0; i < sizeof(long); i++) t[o[i]] = f[i]; return f+sizeof(long); } static uchar* long2le(uchar *t, long from) { uchar *f, *o; int i; f = (uchar*)&from; o = (uchar*)ℴ for(i = 0; i < sizeof(long); i++) t[i] = f[o[i]]; return t+sizeof(long); } char *Ebadtimectl = "bad time control"; /* * like the old #c/time but with added info. Return * * secs nanosecs fastticks fasthz */ static int readtime(ulong off, char *buf, int n) { vlong nsec, ticks; long sec; char str[7*NUMSIZE+4]; // extra 4 bytes are null plus doprint // reserving space for a frigging UTF // char nsec = todget(&ticks); if(fasthz == 0LL) fastticks((uvlong*)&fasthz); sec = nsec/1000000000ULL; snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ", NUMSIZE-1, sec, | |
| 1999/0728 | VLNUMSIZE-1, nsec, VLNUMSIZE-1, ticks, VLNUMSIZE-1, fasthz); | |
| 1999/0711 | return readstr(off, buf, n, str); } /* * set the time in seconds */ static int writetime(char *buf, int n) { char b[13]; long i; vlong now; if(n >= sizeof(b)) error(Ebadtimectl); strncpy(b, buf, n); b[n] = 0; i = strtol(b, 0, 0); if(i <= 0) error(Ebadtimectl); now = i*1000000000LL; todset(now, 0, 0); return n; } /* * read binary time info. all numbers are little endian. * ticks and nsec are syncronized. */ static int readbintime(char *buf, int n) { int i; vlong nsec, ticks; uchar *b = (uchar*)buf; i = 0; if(fasthz == 0LL) fastticks((uvlong*)&fasthz); nsec = todget(&ticks); if(n >= 3*sizeof(uvlong)){ vlong2le(b+2*sizeof(uvlong), fasthz); i += sizeof(uvlong); } if(n >= 2*sizeof(uvlong)){ vlong2le(b+sizeof(uvlong), ticks); i += sizeof(uvlong); } if(n >= 8){ vlong2le(b, nsec); i += sizeof(vlong); } return i; } /* * set any of the following * - time in nsec * - nsec trim applied over some seconds * - clock frequency */ static int writebintime(char *buf, int n) { uchar *p; vlong delta; long period; n--; p = (uchar*)buf + 1; switch(*buf){ case 'n': if(n < sizeof(vlong)) error(Ebadtimectl); le2vlong(&delta, p); todset(delta, 0, 0); break; case 'd': if(n < sizeof(vlong)+sizeof(long)) error(Ebadtimectl); p = le2vlong(&delta, p); le2long(&period, p); todset(-1, delta, period); break; case 'f': if(n < sizeof(uvlong)) error(Ebadtimectl); le2vlong(&fasthz, p); todsetfreq(fasthz); break; } | |
| 1995/0910 | return n; | |
| 1991/1102 | } | |