vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

devcons.c (23243B)


      1 #include	"u.h"
      2 #include	"lib.h"
      3 #include	"mem.h"
      4 #include	"dat.h"
      5 #include	"fns.h"
      6 #include	"error.h"
      7 
      8 #include	"authsrv.h"
      9 
     10 void	(*consdebug)(void) = nil;
     11 void	(*screenputs)(char*, int) = nil;
     12 
     13 Queue*	kbdq;			/* unprocessed console input */
     14 Queue*	lineq;			/* processed console input */
     15 Queue*	kprintoq;		/* console output, for /dev/kprint */
     16 ulong	kprintinuse;		/* test and set whether /dev/kprint is open */
     17 int	iprintscreenputs = 1;
     18 
     19 int	panicking;
     20 
     21 static struct
     22 {
     23 	QLock lk;
     24 
     25 	int	raw;		/* true if we shouldn't process input */
     26 	Ref	ctl;		/* number of opens to the control file */
     27 	int	x;		/* index into line */
     28 	char	line[1024];	/* current input line */
     29 
     30 	int	count;
     31 	int	ctlpoff;
     32 
     33 	/* a place to save up characters at interrupt time before dumping them in the queue */
     34 	Lock	lockputc;
     35 	char	istage[1024];
     36 	char	*iw;
     37 	char	*ir;
     38 	char	*ie;
     39 } kbd = {
     40 	.iw	= kbd.istage,
     41 	.ir	= kbd.istage,
     42 	.ie	= kbd.istage + sizeof(kbd.istage),
     43 };
     44 
     45 char	*sysname;
     46 vlong	fasthz = 1000000000ULL;  // Plan 9 VX = nsecs
     47 
     48 static void	seedrand(void);
     49 static int	readtime(ulong, char*, int);
     50 static int	readbintime(char*, int);
     51 static int	writetime(char*, int);
     52 static int	writebintime(char*, int);
     53 
     54 enum
     55 {
     56 	CMhalt,
     57 	CMreboot,
     58 	CMpanic,
     59 };
     60 
     61 Cmdtab rebootmsg[] =
     62 {
     63 	CMhalt,		"halt",		1,
     64 	CMreboot,	"reboot",	0,
     65 	CMpanic,	"panic",	0,
     66 };
     67 
     68 void
     69 printinit(void)
     70 {
     71 	lineq = qopen(2*1024, 0, nil, nil);
     72 	if(lineq == nil)
     73 		panic("printinit");
     74 	qnoblock(lineq, 1);
     75 }
     76 
     77 #if 0 // Plan 9 VX
     78 int
     79 consactive(void)
     80 {
     81 	if(serialoq)
     82 		return qlen(serialoq) > 0;
     83 	return 0;
     84 }
     85 #endif
     86 
     87 #if 0 // Plan 9 VX
     88 void
     89 prflush(void)
     90 {
     91 	ulong now;
     92 
     93 	now = m->ticks;
     94 	while(consactive())
     95 		if(m->ticks - now >= HZ)
     96 			break;
     97 }
     98 #endif
     99 
    100 /*
    101  * Log console output so it can be retrieved via /dev/kmesg.
    102  * This is good for catching boot-time messages after the fact.
    103  */
    104 struct {
    105 	Lock lk;
    106 	char buf[16384];
    107 	uint n;
    108 } kmesg;
    109 
    110 static void
    111 kmesgputs(char *str, int n)
    112 {
    113 	uint nn, d;
    114 
    115 	ilock(&kmesg.lk);
    116 	/* take the tail of huge writes */
    117 	if(n > sizeof kmesg.buf){
    118 		d = n - sizeof kmesg.buf;
    119 		str += d;
    120 		n -= d;
    121 	}
    122 
    123 	/* slide the buffer down to make room */
    124 	nn = kmesg.n;
    125 	if(nn + n >= sizeof kmesg.buf){
    126 		d = nn + n - sizeof kmesg.buf;
    127 		if(d)
    128 			memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
    129 		nn -= d;
    130 	}
    131 
    132 	/* copy the data in */
    133 	memmove(kmesg.buf+nn, str, n);
    134 	nn += n;
    135 	kmesg.n = nn;
    136 	iunlock(&kmesg.lk);
    137 }
    138 
    139 /*
    140  *   Print a string on the console.  Convert \n to \r\n for serial
    141  *   line consoles.  Locking of the queues is left up to the screen
    142  *   or uart code.  Multi-line messages to serial consoles may get
    143  *   interspersed with other messages.
    144  */
    145 static void
    146 putstrn0(char *str, int n, int usewrite)
    147 {
    148 
    149 	if(!islo())
    150 		usewrite = 0;
    151 
    152 	/*
    153 	 *  how many different output devices do we need?
    154 	 */
    155 	kmesgputs(str, n);
    156 
    157 	/*
    158 	 *  if someone is reading /dev/kprint,
    159 	 *  put the message there.
    160 	 *  if not and there's an attached bit mapped display,
    161 	 *  put the message there.
    162 	 *
    163 	 *  if there's a serial line being used as a console,
    164 	 *  put the message there.
    165 	 */
    166 	if(kprintoq != nil && !qisclosed(kprintoq)){
    167 		if(usewrite)
    168 			qwrite(kprintoq, str, n);
    169 		else
    170 			qiwrite(kprintoq, str, n);
    171 	}else if(screenputs != nil)
    172 		screenputs(str, n);
    173 
    174 	uartputs(str, n);
    175 #if 0 // Plan 9 VX
    176 	if(serialoq == nil){
    177 		uartputs(str, n);
    178 		return;
    179 	}
    180 
    181 	while(n > 0) {
    182 		t = memchr(str, '\n', n);
    183 		if(t && !kbd.raw) {
    184 			m = t-str;
    185 			if(usewrite){
    186 				qwrite(serialoq, str, m);
    187 				qwrite(serialoq, "\r\n", 2);
    188 			} else {
    189 				qiwrite(serialoq, str, m);
    190 				qiwrite(serialoq, "\r\n", 2);
    191 			}
    192 			n -= m+1;
    193 			str = t+1;
    194 		} else {
    195 			if(usewrite)
    196 				qwrite(serialoq, str, n);
    197 			else
    198 				qiwrite(serialoq, str, n);
    199 			break;
    200 		}
    201 	}
    202 #endif
    203 }
    204 
    205 void
    206 putstrn(char *str, int n)
    207 {
    208 	putstrn0(str, n, 0);
    209 }
    210 
    211 int noprint;
    212 
    213 int
    214 print(char *fmt, ...)
    215 {
    216 	int n;
    217 	va_list arg;
    218 	char buf[PRINTSIZE];
    219 
    220 	if(noprint)
    221 		return -1;
    222 
    223 	va_start(arg, fmt);
    224 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
    225 	va_end(arg);
    226 	putstrn(buf, n);
    227 
    228 	return n;
    229 }
    230 
    231 /*
    232  * Want to interlock iprints to avoid interlaced output on 
    233  * multiprocessor, but don't want to deadlock if one processor
    234  * dies during print and another has something important to say.
    235  * Make a good faith effort.
    236  */
    237 #if 0 // Plan 9 VX
    238 static Lock iprintlock;
    239 static int
    240 iprintcanlock(Lock *l)
    241 {
    242 	int i;
    243 	
    244 	for(i=0; i<1000; i++){
    245 		if(canlock(l))
    246 			return 1;
    247 		if(l->m == MACHP(m->machno))
    248 			return 0;
    249 		microdelay(100);
    250 	}
    251 	return 0;
    252 }
    253 
    254 int
    255 iprint(char *fmt, ...)
    256 {
    257 	int n, s, locked;
    258 	va_list arg;
    259 	char buf[PRINTSIZE];
    260 
    261 	s = splhi();
    262 	va_start(arg, fmt);
    263 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
    264 	va_end(arg);
    265 	locked = iprintcanlock(&iprintlock);
    266 	if(screenputs != nil && iprintscreenputs)
    267 		screenputs(buf, n);
    268 	uartputs(buf, n);
    269 	if(locked)
    270 		unlock(&iprintlock);
    271 	splx(s);
    272 
    273 	return n;
    274 }
    275 
    276 void
    277 panic(char *fmt, ...)
    278 {
    279 	int n, s;
    280 	va_list arg;
    281 	char buf[PRINTSIZE];
    282 
    283 	kprintoq = nil;	/* don't try to write to /dev/kprint */
    284 
    285 	if(panicking)
    286 		for(;;);
    287 	panicking = 1;
    288 
    289 	s = splhi();
    290 	strcpy(buf, "panic: ");
    291 	va_start(arg, fmt);
    292 	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
    293 	va_end(arg);
    294 	iprint("%s\n", buf);
    295 	if(consdebug)
    296 		(*consdebug)();
    297 	splx(s);
    298 	prflush();
    299 	buf[n] = '\n';
    300 	putstrn(buf, n+1);
    301 	dumpstack();
    302 
    303 	restoretty(); exit(1);
    304 }
    305 
    306 /* libmp at least contains a few calls to sysfatal; simulate with panic */
    307 void
    308 sysfatal(char *fmt, ...)
    309 {
    310 	char err[256];
    311 	va_list arg;
    312 
    313 	va_start(arg, fmt);
    314 	vseprint(err, err + sizeof err, fmt, arg);
    315 	va_end(arg);
    316 	panic("sysfatal: %s", err);
    317 }
    318 
    319 void
    320 _assert(char *fmt)
    321 {
    322 	panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
    323 }
    324 #endif
    325 
    326 int
    327 pprint(char *fmt, ...)
    328 {
    329 	int n;
    330 	Chan *c;
    331 	va_list arg;
    332 	char buf[2*PRINTSIZE];
    333 
    334 	if(up == nil || up->fgrp == nil)
    335 		return 0;
    336 
    337 	c = up->fgrp->fd[2];
    338 	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
    339 		return 0;
    340 	n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
    341 	va_start(arg, fmt);
    342 	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
    343 	va_end(arg);
    344 
    345 	if(waserror())
    346 		return 0;
    347 	devtab[c->type]->write(c, buf, n, c->offset);
    348 	poperror();
    349 
    350 	lock(&c->ref.lk);
    351 	c->offset += n;
    352 	unlock(&c->ref.lk);
    353 
    354 	return n;
    355 }
    356 
    357 static void
    358 echoscreen(char *buf, int n)
    359 {
    360 	char *e, *p;
    361 	char ebuf[128];
    362 	int x;
    363 
    364 	p = ebuf;
    365 	e = ebuf + sizeof(ebuf) - 4;
    366 	while(n-- > 0){
    367 		if(p >= e){
    368 			screenputs(ebuf, p - ebuf);
    369 			p = ebuf;
    370 		}
    371 		x = *buf++;
    372 		if(x == 0x15){
    373 			*p++ = '^';
    374 			*p++ = 'U';
    375 			*p++ = '\n';
    376 		} else
    377 			*p++ = x;
    378 	}
    379 	if(p != ebuf)
    380 		screenputs(ebuf, p - ebuf);
    381 }
    382 
    383 #if 0 // Plan 9 VX
    384 static void
    385 echoserialoq(char *buf, int n)
    386 {
    387 	char *e, *p;
    388 	char ebuf[128];
    389 	int x;
    390 
    391 	p = ebuf;
    392 	e = ebuf + sizeof(ebuf) - 4;
    393 	while(n-- > 0){
    394 		if(p >= e){
    395 			qiwrite(serialoq, ebuf, p - ebuf);
    396 			p = ebuf;
    397 		}
    398 		x = *buf++;
    399 		if(x == '\n'){
    400 			*p++ = '\r';
    401 			*p++ = '\n';
    402 		} else if(x == 0x15){
    403 			*p++ = '^';
    404 			*p++ = 'U';
    405 			*p++ = '\n';
    406 		} else
    407 			*p++ = x;
    408 	}
    409 	if(p != ebuf)
    410 		qiwrite(serialoq, ebuf, p - ebuf);
    411 }
    412 #endif
    413 
    414 void
    415 echo(char *buf, int n)
    416 {
    417 	static int ctrlt;
    418 	int x;
    419 	char *e, *p;
    420 
    421 	if(n == 0)
    422 		return;
    423 
    424 	e = buf+n;
    425 	for(p = buf; p < e; p++){
    426 		switch(*p){
    427 		case 0x10:	/* ^P */
    428 			if(cpuserver && !kbd.ctlpoff){
    429 				active.exiting = 1;
    430 				return;
    431 			}
    432 			break;
    433 		case 0x14:	/* ^T */
    434 			ctrlt++;
    435 			if(ctrlt > 2)
    436 				ctrlt = 2;
    437 			continue;
    438 		}
    439 
    440 		if(ctrlt != 2)
    441 			continue;
    442 
    443 		/* ^T escapes */
    444 		ctrlt = 0;
    445 		switch(*p){
    446 		case 'S':
    447 			x = splhi();
    448 			dumpstack();
    449 			procdump();
    450 			splx(x);
    451 			return;
    452 		case 's':
    453 			dumpstack();
    454 			return;
    455 		case 'x':
    456 			xsummary();
    457 			ixsummary();
    458 			mallocsummary();
    459 		//	memorysummary();
    460 			pagersummary();
    461 			return;
    462 		case 'd':
    463 			if(consdebug == nil)
    464 				consdebug = rdb;
    465 			else
    466 				consdebug = nil;
    467 			print("consdebug now %#p\n", consdebug);
    468 			return;
    469 		case 'D':
    470 			if(consdebug == nil)
    471 				consdebug = rdb;
    472 			consdebug();
    473 			return;
    474 		case 'p':
    475 			x = spllo();
    476 			procdump();
    477 			splx(x);
    478 			return;
    479 		case 'q':
    480 			scheddump();
    481 			return;
    482 		case 'k':
    483 			killbig("^t ^t k");
    484 			return;
    485 		case 'r':
    486 			restoretty(); exit(0);
    487 			return;
    488 		}
    489 	}
    490 
    491 	qproduce(kbdq, buf, n);
    492 	if(kbd.raw)
    493 		return;
    494 	kmesgputs(buf, n);
    495 	if(screenputs != nil)
    496 		echoscreen(buf, n);
    497 	uartecho(buf, n);	// Plan 9 VX
    498 }
    499 
    500 /*
    501  *  Called by a uart interrupt for console input.
    502  *
    503  *  turn '\r' into '\n' before putting it into the queue.
    504  */
    505 int
    506 kbdcr2nl(Queue *q, int ch)
    507 {
    508 	char *next;
    509 
    510 	ilock(&kbd.lockputc);		/* just a mutex */
    511 	if(ch == '\r' && !kbd.raw)
    512 		ch = '\n';
    513 	next = kbd.iw+1;
    514 	if(next >= kbd.ie)
    515 		next = kbd.istage;
    516 	if(next != kbd.ir){
    517 		*kbd.iw = ch;
    518 		kbd.iw = next;
    519 	}
    520 	iunlock(&kbd.lockputc);
    521 	return 0;
    522 }
    523 
    524 /*
    525  *  Put character, possibly a rune, into read queue at interrupt time.
    526  *  Called at interrupt time to process a character.
    527  */
    528 int
    529 kbdputc(Queue *q, int ch)
    530 {
    531 	int n;
    532 	Rune r;
    533 	char buf[UTFmax];
    534 	
    535 	r = ch;
    536 	n = runetochar(buf, &r);
    537 	echo(buf, n);
    538 	return 0;
    539 
    540 #if 0 // Plan 9 VX
    541 	int i, n;
    542 	char buf[3];
    543 	Rune r;
    544 	char *next;
    545 
    546 	if(kbd.ir == nil)
    547 		return 0;		/* in case we're not inited yet */
    548 	
    549 	ilock(&kbd.lockputc);		/* just a mutex */
    550 	r = ch;
    551 	n = runetochar(buf, &r);
    552 	for(i = 0; i < n; i++){
    553 		next = kbd.iw+1;
    554 		if(next >= kbd.ie)
    555 			next = kbd.istage;
    556 		if(next == kbd.ir)
    557 			break;
    558 		*kbd.iw = buf[i];
    559 		kbd.iw = next;
    560 	}
    561 	iunlock(&kbd.lockputc);
    562 	return 0;
    563 #endif
    564 }
    565 
    566 /*
    567  *  we save up input characters till clock time to reduce
    568  *  per character interrupt overhead.
    569  */
    570 #if 0 // Plan 9 VX
    571 static void
    572 kbdputcclock(void)
    573 {
    574 	char *iw;
    575 
    576 	/* this amortizes cost of qproduce */
    577 	if(kbd.iw != kbd.ir){
    578 		iw = kbd.iw;
    579 		if(iw < kbd.ir){
    580 			echo(kbd.ir, kbd.ie-kbd.ir);
    581 			kbd.ir = kbd.istage;
    582 		}
    583 		if(kbd.ir != iw){
    584 			echo(kbd.ir, iw-kbd.ir);
    585 			kbd.ir = iw;
    586 		}
    587 	}
    588 }
    589 #endif
    590 
    591 enum{
    592 	Qdir,
    593 	Qbintime,
    594 	Qcons,
    595 	Qconsctl,
    596 	Qcputime,
    597 	Qdrivers,
    598 	Qkmesg,
    599 	Qkprint,
    600 	Qhostdomain,
    601 	Qhostowner,
    602 	Qnull,
    603 	Qosversion,
    604 	Qpgrpid,
    605 	Qpid,
    606 	Qppid,
    607 	Qrandom,
    608 	Qreboot,
    609 	Qswap,
    610 	Qsysname,
    611 	Qsysstat,
    612 	Qtime,
    613 	Quser,
    614 	Qzero,
    615 };
    616 
    617 enum
    618 {
    619 	VLNUMSIZE=	22,
    620 };
    621 
    622 static Dirtab consdir[]={
    623 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
    624 	"bintime",	{Qbintime},	24,		0664,
    625 	"cons",		{Qcons},	0,		0660,
    626 	"consctl",	{Qconsctl},	0,		0220,
    627 	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
    628 	"drivers",	{Qdrivers},	0,		0444,
    629 	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,
    630 	"hostowner",	{Qhostowner},	0,		0664,
    631 	"kmesg",	{Qkmesg},	0,		0440,
    632 	"kprint",	{Qkprint, 0, QTEXCL},	0,	DMEXCL|0440,
    633 	"null",		{Qnull},	0,		0666,
    634 	"osversion",	{Qosversion},	0,		0444,
    635 	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,
    636 	"pid",		{Qpid},		NUMSIZE,	0444,
    637 	"ppid",		{Qppid},	NUMSIZE,	0444,
    638 	"random",	{Qrandom},	0,		0444,
    639 	"reboot",	{Qreboot},	0,		0664,
    640 	"swap",		{Qswap},	0,		0664,
    641 	"sysname",	{Qsysname},	0,		0664,
    642 	"sysstat",	{Qsysstat},	0,		0666,
    643 	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664,
    644 	"user",		{Quser},	0,		0666,
    645 	"zero",		{Qzero},	0,		0444,
    646 };
    647 
    648 int
    649 readnum(ulong off, char *buf, ulong n, ulong val, int size)
    650 {
    651 	char tmp[64];
    652 
    653 	snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
    654 	tmp[size-1] = ' ';
    655 	if(off >= size)
    656 		return 0;
    657 	if(off+n > size)
    658 		n = size-off;
    659 	memmove(buf, tmp+off, n);
    660 	return n;
    661 }
    662 
    663 int
    664 readstr(ulong off, char *buf, ulong n, char *str)
    665 {
    666 	int size;
    667 
    668 	size = strlen(str);
    669 	if(off >= size)
    670 		return 0;
    671 	if(off+n > size)
    672 		n = size-off;
    673 	memmove(buf, str+off, n);
    674 	return n;
    675 }
    676 
    677 static void
    678 consinit(void)
    679 {
    680 	todinit();
    681 	randominit();
    682 #if 0 // Plan 9 VX
    683 	/*
    684 	 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
    685 	 * processing it every 22 ms should be fine
    686 	 */
    687 	addclock0link(kbdputcclock, 22);
    688 #endif
    689 }
    690 
    691 static Chan*
    692 consattach(char *spec)
    693 {
    694 	return devattach('c', spec);
    695 }
    696 
    697 static Walkqid*
    698 conswalk(Chan *c, Chan *nc, char **name, int nname)
    699 {
    700 	return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
    701 }
    702 
    703 static int
    704 consstat(Chan *c, uchar *dp, int n)
    705 {
    706 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
    707 }
    708 
    709 static Chan*
    710 consopen(Chan *c, int omode)
    711 {
    712 	c->aux = nil;
    713 	c = devopen(c, omode, consdir, nelem(consdir), devgen);
    714 	switch((ulong)c->qid.path){
    715 	case Qconsctl:
    716 		incref(&kbd.ctl);
    717 		break;
    718 
    719 	case Qkprint:
    720 		if(tas(&kprintinuse) != 0){
    721 			c->flag &= ~COPEN;
    722 			error(Einuse);
    723 		}
    724 		if(kprintoq == nil){
    725 			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
    726 			if(kprintoq == nil){
    727 				c->flag &= ~COPEN;
    728 				error(Enomem);
    729 			}
    730 			qnoblock(kprintoq, 1);
    731 		}else
    732 			qreopen(kprintoq);
    733 		c->iounit = qiomaxatomic;
    734 		break;
    735 	}
    736 	return c;
    737 }
    738 
    739 static void
    740 consclose(Chan *c)
    741 {
    742 	switch((ulong)c->qid.path){
    743 	/* last close of control file turns off raw */
    744 	case Qconsctl:
    745 		if(c->flag&COPEN){
    746 			if(decref(&kbd.ctl) == 0)
    747 				kbd.raw = 0;
    748 		}
    749 		break;
    750 
    751 	/* close of kprint allows other opens */
    752 	case Qkprint:
    753 		if(c->flag & COPEN){
    754 			kprintinuse = 0;
    755 			qhangup(kprintoq, nil);
    756 		}
    757 		break;
    758 	}
    759 }
    760 
    761 static long
    762 consread(Chan *c, void *buf, long n, vlong off)
    763 {
    764 	ulong l;
    765 	Mach *mp;
    766 	char *b, *bp, ch;
    767 	char tmp[256];		/* must be >= 18*NUMSIZE (Qswap) */
    768 	int i, k, id, send;
    769 	vlong offset = off;
    770 
    771 	if(n <= 0)
    772 		return n;
    773 
    774 	switch((ulong)c->qid.path){
    775 	case Qdir:
    776 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
    777 
    778 	case Qcons:
    779 		qlock(&kbd.lk);
    780 		if(waserror()) {
    781 			qunlock(&kbd.lk);
    782 			nexterror();
    783 		}
    784 		while(!qcanread(lineq)){
    785 			if(qread(kbdq, &ch, 1) == 0)
    786 				continue;
    787 			send = 0;
    788 			if(ch == 0){
    789 				/* flush output on rawoff -> rawon */
    790 				if(kbd.x > 0)
    791 					send = !qcanread(kbdq);
    792 			}else if(kbd.raw){
    793 				kbd.line[kbd.x++] = ch;
    794 				send = !qcanread(kbdq);
    795 			}else{
    796 				switch(ch){
    797 				case '\b':
    798 					if(kbd.x > 0)
    799 						kbd.x--;
    800 					break;
    801 				case 0x15:	/* ^U */
    802 					kbd.x = 0;
    803 					break;
    804 				case '\n':
    805 				case 0x04:	/* ^D */
    806 					send = 1;
    807 				default:
    808 					if(ch != 0x04)
    809 						kbd.line[kbd.x++] = ch;
    810 					break;
    811 				}
    812 			}
    813 			if(send || kbd.x == sizeof kbd.line){
    814 				qwrite(lineq, kbd.line, kbd.x);
    815 				kbd.x = 0;
    816 			}
    817 		}
    818 		n = qread(lineq, buf, n);
    819 		qunlock(&kbd.lk);
    820 		poperror();
    821 		return n;
    822 
    823 	case Qcputime:
    824 		k = offset;
    825 		if(k >= 6*NUMSIZE)
    826 			return 0;
    827 		if(k+n > 6*NUMSIZE)
    828 			n = 6*NUMSIZE - k;
    829 		/* easiest to format in a separate buffer and copy out */
    830 		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
    831 			l = up->time[i];
    832 			if(i == TReal)
    833 				l = msec() - l;
    834 			l = TK2MS(l);
    835 			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
    836 		}
    837 		memmove(buf, tmp+k, n);
    838 		return n;
    839 
    840 	case Qkmesg:
    841 		/*
    842 		 * This is unlocked to avoid tying up a process
    843 		 * that's writing to the buffer.  kmesg.n never 
    844 		 * gets smaller, so worst case the reader will
    845 		 * see a slurred buffer.
    846 		 */
    847 		if(off >= kmesg.n)
    848 			n = 0;
    849 		else{
    850 			if(off+n > kmesg.n)
    851 				n = kmesg.n - off;
    852 			memmove(buf, kmesg.buf+off, n);
    853 		}
    854 		return n;
    855 		
    856 	case Qkprint:
    857 		return qread(kprintoq, buf, n);
    858 
    859 	case Qpgrpid:
    860 		return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
    861 
    862 	case Qpid:
    863 		return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
    864 
    865 	case Qppid:
    866 		return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
    867 
    868 	case Qtime:
    869 		return readtime((ulong)offset, buf, n);
    870 
    871 	case Qbintime:
    872 		return readbintime(buf, n);
    873 
    874 	case Qhostowner:
    875 		return readstr((ulong)offset, buf, n, eve);
    876 
    877 	case Qhostdomain:
    878 		return readstr((ulong)offset, buf, n, hostdomain);
    879 
    880 	case Quser:
    881 		return readstr((ulong)offset, buf, n, up->user);
    882 
    883 	case Qnull:
    884 		return 0;
    885 
    886 	case Qsysstat:
    887 		b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1);	/* +1 for NUL */
    888 		bp = b;
    889 		for(id = 0; id < 32; id++) {
    890 			if(active.machs & (1<<id)) {
    891 				mp = MACHP(id);
    892 				readnum(0, bp, NUMSIZE, id, NUMSIZE);
    893 				bp += NUMSIZE;
    894 				readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
    895 				bp += NUMSIZE;
    896 				readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
    897 				bp += NUMSIZE;
    898 				readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
    899 				bp += NUMSIZE;
    900 				readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
    901 				bp += NUMSIZE;
    902 				readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
    903 				bp += NUMSIZE;
    904 				readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
    905 				bp += NUMSIZE;
    906 				readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
    907 				bp += NUMSIZE;
    908 				readnum(0, bp, NUMSIZE,
    909 					(mp->perf.avg_inidle*100)/mp->perf.period,
    910 					NUMSIZE);
    911 				bp += NUMSIZE;
    912 				readnum(0, bp, NUMSIZE,
    913 					(mp->perf.avg_inintr*100)/mp->perf.period,
    914 					NUMSIZE);
    915 				bp += NUMSIZE;
    916 				*bp++ = '\n';
    917 			}
    918 		}
    919 		if(waserror()){
    920 			free(b);
    921 			nexterror();
    922 		}
    923 		n = readstr((ulong)offset, buf, n, b);
    924 		free(b);
    925 		poperror();
    926 		return n;
    927 
    928 	case Qswap:
    929 		tmp[0] = 0;
    930 
    931 		return readstr((ulong)offset, buf, n, tmp);
    932 
    933 	case Qsysname:
    934 		if(sysname == nil)
    935 			return 0;
    936 		return readstr((ulong)offset, buf, n, sysname);
    937 
    938 	case Qrandom:
    939 		return randomread(buf, n);
    940 
    941 	case Qdrivers:
    942 		b = malloc(READSTR);
    943 		if(b == nil)
    944 			error(Enomem);
    945 		n = 0;
    946 		for(i = 0; devtab[i] != nil; i++)
    947 			n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
    948 		if(waserror()){
    949 			free(b);
    950 			nexterror();
    951 		}
    952 		n = readstr((ulong)offset, buf, n, b);
    953 		free(b);
    954 		poperror();
    955 		return n;
    956 
    957 	case Qzero:
    958 		memset(buf, 0, n);
    959 		return n;
    960 
    961 	case Qosversion:
    962 		snprint(tmp, sizeof tmp, "2000");
    963 		n = readstr((ulong)offset, buf, n, tmp);
    964 		return n;
    965 
    966 	default:
    967 		print("consread %#llux\n", c->qid.path);
    968 		error(Egreg);
    969 	}
    970 	return -1;		/* never reached */
    971 }
    972 
    973 static long
    974 conswrite(Chan *c, void *va, long n, vlong off)
    975 {
    976 	char buf[256], ch;
    977 	long l, bp;
    978 	char *a;
    979 	Mach *mp;
    980 	int id, fd;
    981 	Chan *swc;
    982 	ulong offset;
    983 	Cmdbuf *cb;
    984 	Cmdtab *ct;
    985 
    986 	a = va;
    987 	offset = off;
    988 
    989 	switch((ulong)c->qid.path){
    990 	case Qcons:
    991 		/*
    992 		 * Can't page fault in putstrn, so copy the data locally.
    993 		 */
    994 		l = n;
    995 		while(l > 0){
    996 			bp = l;
    997 			if(bp > sizeof buf)
    998 				bp = sizeof buf;
    999 			memmove(buf, a, bp);
   1000 			putstrn0(buf, bp, 1);
   1001 			a += bp;
   1002 			l -= bp;
   1003 		}
   1004 		break;
   1005 
   1006 	case Qconsctl:
   1007 		if(n >= sizeof(buf))
   1008 			n = sizeof(buf)-1;
   1009 		strncpy(buf, a, n);
   1010 		buf[n] = 0;
   1011 		for(a = buf; a;){
   1012 			if(strncmp(a, "rawon", 5) == 0){
   1013 				kbd.raw = 1;
   1014 				/* clumsy hack - wake up reader */
   1015 				ch = 0;
   1016 				qwrite(kbdq, &ch, 1);			
   1017 			} else if(strncmp(a, "rawoff", 6) == 0){
   1018 				kbd.raw = 0;
   1019 			} else if(strncmp(a, "ctlpon", 6) == 0){
   1020 				kbd.ctlpoff = 0;
   1021 			} else if(strncmp(a, "ctlpoff", 7) == 0){
   1022 				kbd.ctlpoff = 1;
   1023 			}
   1024 			if((a = strchr(a, ' ')))
   1025 				a++;
   1026 		}
   1027 		break;
   1028 
   1029 	case Qtime:
   1030 		if(!iseve())
   1031 			error(Eperm);
   1032 		return writetime(a, n);
   1033 
   1034 	case Qbintime:
   1035 		if(!iseve())
   1036 			error(Eperm);
   1037 		return writebintime(a, n);
   1038 
   1039 	case Qhostowner:
   1040 		return hostownerwrite(a, n);
   1041 
   1042 	case Qhostdomain:
   1043 		return hostdomainwrite(a, n);
   1044 
   1045 	case Quser:
   1046 		return userwrite(a, n);
   1047 
   1048 	case Qnull:
   1049 		break;
   1050 
   1051 	case Qreboot:
   1052 		if(!iseve())
   1053 			error(Eperm);
   1054 		cb = parsecmd(a, n);
   1055 
   1056 		if(waserror()) {
   1057 			free(cb);
   1058 			nexterror();
   1059 		}
   1060 		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
   1061 		switch(ct->index) {
   1062 		case CMhalt:
   1063 			reboot(nil, 0, 0);
   1064 			break;
   1065 		case CMreboot:
   1066 			rebootcmd(cb->nf-1, cb->f+1);
   1067 			break;
   1068 		case CMpanic:
   1069 			*(ulong*)0=0;
   1070 			panic("/dev/reboot");
   1071 		}
   1072 		poperror();
   1073 		free(cb);
   1074 		break;
   1075 
   1076 	case Qsysstat:
   1077 		for(id = 0; id < 32; id++) {
   1078 			if(active.machs & (1<<id)) {
   1079 				mp = MACHP(id);
   1080 				mp->cs = 0;
   1081 				mp->intr = 0;
   1082 				mp->syscall = 0;
   1083 				mp->pfault = 0;
   1084 				mp->tlbfault = 0;
   1085 				mp->tlbpurge = 0;
   1086 			}
   1087 		}
   1088 		break;
   1089 
   1090 	case Qswap:
   1091 		if(n >= sizeof buf)
   1092 			error(Egreg);
   1093 		memmove(buf, va, n);	/* so we can NUL-terminate */
   1094 		buf[n] = 0;
   1095 		/* start a pager if not already started */
   1096 		if(strncmp(buf, "start", 5) == 0){
   1097 			kickpager();
   1098 			break;
   1099 		}
   1100 		if(!iseve())
   1101 			error(Eperm);
   1102 		if(buf[0]<'0' || '9'<buf[0])
   1103 			error(Ebadarg);
   1104 		fd = strtoul(buf, 0, 0);
   1105 		swc = fdtochan(fd, -1, 1, 1);
   1106 		setswapchan(swc);
   1107 		break;
   1108 
   1109 	case Qsysname:
   1110 		if(offset != 0)
   1111 			error(Ebadarg);
   1112 		if(n <= 0 || n >= sizeof buf)
   1113 			error(Ebadarg);
   1114 		strncpy(buf, a, n);
   1115 		buf[n] = 0;
   1116 		if(buf[n-1] == '\n')
   1117 			buf[n-1] = 0;
   1118 		kstrdup(&sysname, buf);
   1119 		break;
   1120 
   1121 	default:
   1122 		print("conswrite: %#llux\n", c->qid.path);
   1123 		error(Egreg);
   1124 	}
   1125 	return n;
   1126 }
   1127 
   1128 Dev consdevtab = {
   1129 	'c',
   1130 	"cons",
   1131 
   1132 	devreset,
   1133 	consinit,
   1134 	devshutdown,
   1135 	consattach,
   1136 	conswalk,
   1137 	consstat,
   1138 	consopen,
   1139 	devcreate,
   1140 	consclose,
   1141 	consread,
   1142 	devbread,
   1143 	conswrite,
   1144 	devbwrite,
   1145 	devremove,
   1146 	devwstat,
   1147 };
   1148 
   1149 static	ulong	randn;
   1150 
   1151 static void
   1152 seedrand(void)
   1153 {
   1154 	if(!waserror()){
   1155 		randomread((void*)&randn, sizeof(randn));
   1156 		poperror();
   1157 	}
   1158 }
   1159 
   1160 int
   1161 nrand(int n)
   1162 {
   1163 	if(randn == 0)
   1164 		seedrand();
   1165 	randn = randn*1103515245 + 12345 + msec();
   1166 	return (randn>>16) % n;
   1167 }
   1168 
   1169 int
   1170 rand(void)
   1171 {
   1172 	nrand(1);
   1173 	return randn;
   1174 }
   1175 
   1176 static uvlong uvorder = 0x0001020304050607ULL;
   1177 
   1178 static uchar*
   1179 le2vlong(vlong *to, uchar *f)
   1180 {
   1181 	uchar *t, *o;
   1182 	int i;
   1183 
   1184 	t = (uchar*)to;
   1185 	o = (uchar*)&uvorder;
   1186 	for(i = 0; i < sizeof(vlong); i++)
   1187 		t[o[i]] = f[i];
   1188 	return f+sizeof(vlong);
   1189 }
   1190 
   1191 static uchar*
   1192 vlong2le(uchar *t, vlong from)
   1193 {
   1194 	uchar *f, *o;
   1195 	int i;
   1196 
   1197 	f = (uchar*)&from;
   1198 	o = (uchar*)&uvorder;
   1199 	for(i = 0; i < sizeof(vlong); i++)
   1200 		t[i] = f[o[i]];
   1201 	return t+sizeof(vlong);
   1202 }
   1203 
   1204 static long order = 0x00010203;
   1205 
   1206 static uchar*
   1207 le2long(long *to, uchar *f)
   1208 {
   1209 	uchar *t, *o;
   1210 	int i;
   1211 
   1212 	t = (uchar*)to;
   1213 	o = (uchar*)&order;
   1214 	for(i = 0; i < sizeof(long); i++)
   1215 		t[o[i]] = f[i];
   1216 	return f+sizeof(long);
   1217 }
   1218 
   1219 /*static*/ uchar*
   1220 long2le(uchar *t, long from)
   1221 {
   1222 	uchar *f, *o;
   1223 	int i;
   1224 
   1225 	f = (uchar*)&from;
   1226 	o = (uchar*)&order;
   1227 	for(i = 0; i < sizeof(long); i++)
   1228 		t[i] = f[o[i]];
   1229 	return t+sizeof(long);
   1230 }
   1231 
   1232 char *Ebadtimectl = "bad time control";
   1233 
   1234 /*
   1235  *  like the old #c/time but with added info.  Return
   1236  *
   1237  *	secs	nanosecs	fastticks	fasthz
   1238  */
   1239 static int
   1240 readtime(ulong off, char *buf, int n)
   1241 {
   1242 	vlong	nsec, ticks;
   1243 	long sec;
   1244 	char str[7*NUMSIZE];
   1245 
   1246 	nsec = todget(&ticks);
   1247 	if(fasthz == 0LL)
   1248 		fastticks((uvlong*)&fasthz);
   1249 	sec = nsec/1000000000ULL;
   1250 	snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
   1251 		NUMSIZE-1, sec,
   1252 		VLNUMSIZE-1, nsec,
   1253 		VLNUMSIZE-1, ticks,
   1254 		VLNUMSIZE-1, fasthz);
   1255 	return readstr(off, buf, n, str);
   1256 }
   1257 
   1258 /*
   1259  *  set the time in seconds
   1260  */
   1261 static int
   1262 writetime(char *buf, int n)
   1263 {
   1264 	char b[13];
   1265 	long i;
   1266 	vlong now;
   1267 
   1268 	if(n >= sizeof(b))
   1269 		error(Ebadtimectl);
   1270 	strncpy(b, buf, n);
   1271 	b[n] = 0;
   1272 	i = strtol(b, 0, 0);
   1273 	if(i <= 0)
   1274 		error(Ebadtimectl);
   1275 	now = i*1000000000LL;
   1276 	todset(now, 0, 0);
   1277 	return n;
   1278 }
   1279 
   1280 /*
   1281  *  read binary time info.  all numbers are little endian.
   1282  *  ticks and nsec are syncronized.
   1283  */
   1284 static int
   1285 readbintime(char *buf, int n)
   1286 {
   1287 	int i;
   1288 	vlong nsec, ticks;
   1289 	uchar *b = (uchar*)buf;
   1290 
   1291 	i = 0;
   1292 	if(fasthz == 0LL)
   1293 		fastticks((uvlong*)&fasthz);
   1294 	nsec = todget(&ticks);
   1295 	if(n >= 3*sizeof(uvlong)){
   1296 		vlong2le(b+2*sizeof(uvlong), fasthz);
   1297 		i += sizeof(uvlong);
   1298 	}
   1299 	if(n >= 2*sizeof(uvlong)){
   1300 		vlong2le(b+sizeof(uvlong), ticks);
   1301 		i += sizeof(uvlong);
   1302 	}
   1303 	if(n >= 8){
   1304 		vlong2le(b, nsec);
   1305 		i += sizeof(vlong);
   1306 	}
   1307 	return i;
   1308 }
   1309 
   1310 /*
   1311  *  set any of the following
   1312  *	- time in nsec
   1313  *	- nsec trim applied over some seconds
   1314  *	- clock frequency
   1315  */
   1316 static int
   1317 writebintime(char *buf, int n)
   1318 {
   1319 	uchar *p;
   1320 	vlong delta;
   1321 	long period;
   1322 
   1323 	n--;
   1324 	p = (uchar*)buf + 1;
   1325 	switch(*buf){
   1326 	case 'n':
   1327 		if(n < sizeof(vlong))
   1328 			error(Ebadtimectl);
   1329 		le2vlong(&delta, p);
   1330 		todset(delta, 0, 0);
   1331 		break;
   1332 	case 'd':
   1333 		if(n < sizeof(vlong)+sizeof(long))
   1334 			error(Ebadtimectl);
   1335 		p = le2vlong(&delta, p);
   1336 		le2long(&period, p);
   1337 		todset(-1, delta, period);
   1338 		break;
   1339 	case 'f':
   1340 		if(n < sizeof(uvlong))
   1341 			error(Ebadtimectl);
   1342 		le2vlong(&fasthz, p);
   1343 		todsetfreq(fasthz);
   1344 		break;
   1345 	}
   1346 	return n;
   1347 }
   1348 
   1349 // Plan 9 VX
   1350 int
   1351 tailkmesg(char *a, int n)
   1352 {
   1353 	ilock(&kmesg.lk);
   1354 	if(n > kmesg.n)
   1355 		n = kmesg.n;
   1356 	memmove(a, kmesg.buf+kmesg.n-n, n);
   1357 	iunlock(&kmesg.lk);
   1358 	return n;
   1359 }