xref: /inferno-os/os/port/devcons.c (revision a60fa48ce2f27a689f276bea9538b5db2b74ff86)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 #include	<version.h>
8 #include	"mp.h"
9 #include	"libsec.h"
10 #include	"keyboard.h"
11 
12 extern int cflag;
13 extern int keepbroken;
14 
15 void	(*serwrite)(char *, int);
16 
17 Queue*	kscanq;			/* keyboard raw scancodes (when needed) */
18 char*	kscanid;		/* name of raw scan format (if defined) */
19 Queue*	kbdq;			/* unprocessed console input */
20 Queue*	lineq;			/* processed console input */
21 Queue*	printq;			/* console output */
22 Queue*	klogq;			/* kernel print (log) output */
23 int	iprintscreenputs;
24 
25 static struct
26 {
27 	RWlock;
28 	Queue*	q;
29 } kprintq;
30 
31 static struct
32 {
33 	QLock;
34 
35 	int	raw;		/* true if we shouldn't process input */
36 	int	ctl;		/* number of opens to the control file */
37 	int	kbdr;		/* number of open reads to the keyboard */
38 	int	scan;		/* true if reading raw scancodes */
39 	int	x;		/* index into line */
40 	char	line[1024];	/* current input line */
41 
42 	char	c;
43 	int	count;
44 	int	repeat;
45 } kbd;
46 
47 char*	sysname;
48 char*	eve;
49 
50 enum
51 {
52 	CMreboot,
53 	CMhalt,
54 	CMpanic,
55 	CMbroken,
56 	CMnobroken,
57 	CMconsole,
58 };
59 
60 static Cmdtab sysctlcmd[] =
61 {
62 	CMreboot,	"reboot",	0,
63 	CMhalt,	"halt", 0,
64 	CMpanic,	"panic", 0,
65 	CMconsole,	"console", 1,
66 	CMbroken,	"broken", 0,
67 	CMnobroken,	"nobroken", 0,
68 };
69 
70 void
71 printinit(void)
72 {
73 	lineq = qopen(2*1024, 0, nil, nil);
74 	if(lineq == nil)
75 		panic("printinit");
76 	qnoblock(lineq, 1);
77 }
78 
79 /*
80  *  return true if current user is eve
81  */
82 int
83 iseve(void)
84 {
85 	Osenv *o;
86 
87 	o = up->env;
88 	return strcmp(eve, o->user) == 0;
89 }
90 
91 static int
92 consactive(void)
93 {
94 	if(printq)
95 		return qlen(printq) > 0;
96 	return 0;
97 }
98 
99 static void
100 prflush(void)
101 {
102 	ulong now;
103 
104 	now = m->ticks;
105 	while(serwrite==nil && consactive())
106 		if(m->ticks - now >= HZ)
107 			break;
108 }
109 
110 /*
111  *   Print a string on the console.  Convert \n to \r\n for serial
112  *   line consoles.  Locking of the queues is left up to the screen
113  *   or uart code.  Multi-line messages to serial consoles may get
114  *   interspersed with other messages.
115  */
116 static void
117 putstrn0(char *str, int n, int usewrite)
118 {
119 	int m;
120 	char *t;
121 	char buf[PRINTSIZE+2];
122 
123 	/*
124 	 *  if kprint is open, put the message there, otherwise
125 	 *  if there's an attached bit mapped display,
126 	 *  put the message there.
127 	 */
128 	m = consoleprint;
129 	if(canrlock(&kprintq)){
130 		if(kprintq.q != nil){
131 			if(waserror()){
132 				runlock(&kprintq);
133 				nexterror();
134 			}
135 			if(usewrite)
136 				qwrite(kprintq.q, str, n);
137 			else
138 				qiwrite(kprintq.q, str, n);
139 			poperror();
140 			m = 0;
141 		}
142 		runlock(&kprintq);
143 	}
144 	if(m && screenputs != nil)
145 		screenputs(str, n);
146 
147 	/*
148 	 *  if there's a serial line being used as a console,
149 	 *  put the message there.
150 	 */
151 	if(serwrite != nil) {
152 		serwrite(str, n);
153 		return;
154 	}
155 
156 	if(printq == 0)
157 		return;
158 
159 	while(n > 0) {
160 		t = memchr(str, '\n', n);
161 		if(t && !kbd.raw) {
162 			m = t - str;
163 			if(m > sizeof(buf)-2)
164 				m = sizeof(buf)-2;
165 			memmove(buf, str, m);
166 			buf[m] = '\r';
167 			buf[m+1] = '\n';
168 			if(usewrite)
169 				qwrite(printq, buf, m+2);
170 			else
171 				qiwrite(printq, buf, m+2);
172 			str = t + 1;
173 			n -= m + 1;
174 		} else {
175 			if(usewrite)
176 				qwrite(printq, str, n);
177 			else
178 				qiwrite(printq, str, n);
179 			break;
180 		}
181 	}
182 }
183 
184 void
185 putstrn(char *str, int n)
186 {
187 	putstrn0(str, n, 0);
188 }
189 
190 int
191 snprint(char *s, int n, char *fmt, ...)
192 {
193 	va_list arg;
194 
195 	va_start(arg, fmt);
196 	n = vseprint(s, s+n, fmt, arg) - s;
197 	va_end(arg);
198 
199 	return n;
200 }
201 
202 int
203 sprint(char *s, char *fmt, ...)
204 {
205 	int n;
206 	va_list arg;
207 
208 	va_start(arg, fmt);
209 	n = vseprint(s, s+PRINTSIZE, fmt, arg) - s;
210 	va_end(arg);
211 
212 	return n;
213 }
214 
215 int
216 print(char *fmt, ...)
217 {
218 	int n;
219 	va_list arg;
220 	char buf[PRINTSIZE];
221 
222 	va_start(arg, fmt);
223 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
224 	va_end(arg);
225 	putstrn(buf, n);
226 
227 	return n;
228 }
229 
230 int
231 fprint(int fd, char *fmt, ...)
232 {
233 	int n;
234 	va_list arg;
235 	char buf[PRINTSIZE];
236 
237 	USED(fd);
238 	va_start(arg, fmt);
239 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
240 	va_end(arg);
241 	putstrn(buf, n);
242 
243 	return n;
244 }
245 
246 int
247 kprint(char *fmt, ...)
248 {
249 	va_list arg;
250 	char buf[PRINTSIZE];
251 	int n;
252 
253 	va_start(arg, fmt);
254 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
255 	va_end(arg);
256 	if(qfull(klogq))
257 		qflush(klogq);
258 	return qproduce(klogq, buf, n);
259 }
260 
261 int
262 iprint(char *fmt, ...)
263 {
264 	int n, s;
265 	va_list arg;
266 	char buf[PRINTSIZE];
267 
268 	s = splhi();
269 	va_start(arg, fmt);
270 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
271 	va_end(arg);
272 	if(screenputs != nil && iprintscreenputs)
273 		screenputs(buf, n);
274 	uartputs(buf, n);
275 	splx(s);
276 
277 	return n;
278 }
279 
280 void
281 panic(char *fmt, ...)
282 {
283 	int n;
284 	va_list arg;
285 	char buf[PRINTSIZE];
286 
287 	setpanic();
288 	kprintq.q = nil;
289 	strcpy(buf, "panic: ");
290 	va_start(arg, fmt);
291 	n = vseprint(buf+strlen(buf), buf+sizeof(buf)-1, fmt, arg) - buf;
292 	va_end(arg);
293 	buf[n] = '\n';
294 	putstrn(buf, n+1);
295 	spllo();
296 	dumpstack();
297 
298 	exit(1);
299 }
300 
301 void
302 _assert(char *fmt)
303 {
304 	panic("assert failed: %s", fmt);
305 }
306 
307 /*
308  * mainly for libmp
309  */
310 void
311 sysfatal(char *fmt, ...)
312 {
313 	va_list arg;
314 	char buf[64];
315 
316 	va_start(arg, fmt);
317 	vsnprint(buf, sizeof(buf), fmt, arg);
318 	va_end(arg);
319 	error(buf);
320 }
321 
322 int
323 pprint(char *fmt, ...)
324 {
325 	int n;
326 	Chan *c;
327 	Osenv *o;
328 	va_list arg;
329 	char buf[2*PRINTSIZE];
330 
331 	n = sprint(buf, "%s %ld: ", up->text, up->pid);
332 	va_start(arg, fmt);
333 	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
334 	va_end(arg);
335 
336 	o = up->env;
337 	if(o->fgrp == 0) {
338 		print("%s", buf);
339 		return 0;
340 	}
341 	c = o->fgrp->fd[2];
342 	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) {
343 		print("%s", buf);
344 		return 0;
345 	}
346 
347 	if(waserror()) {
348 		print("%s", buf);
349 		return 0;
350 	}
351 	devtab[c->type]->write(c, buf, n, c->offset);
352 	poperror();
353 
354 	lock(c);
355 	c->offset += n;
356 	unlock(c);
357 
358 	return n;
359 }
360 
361 void
362 echo(Rune r, char *buf, int n)
363 {
364 	if(kbd.raw)
365 		return;
366 
367 	if(r == '\n'){
368 		if(printq)
369 			qiwrite(printq, "\r", 1);
370 	} else if(r == 0x15){
371 		buf = "^U\n";
372 		n = 3;
373 	}
374 	if(consoleprint && screenputs != nil)
375 		screenputs(buf, n);
376 	if(printq)
377 		qiwrite(printq, buf, n);
378 }
379 
380 /*
381  *	Debug key support.  Allows other parts of the kernel to register debug
382  *	key handlers, instead of devcons.c having to know whatever's out there.
383  *	A kproc is used to invoke most handlers, rather than tying up the CPU at
384  *	splhi, which can choke some device drivers (eg softmodem).
385  */
386 typedef struct {
387 	Rune	r;
388 	char	*m;
389 	void	(*f)(Rune);
390 	int	i;	/* function called at interrupt time */
391 } Dbgkey;
392 
393 static struct {
394 	Rendez;
395 	Dbgkey	*work;
396 	Dbgkey	keys[50];
397 	int	nkeys;
398 	int	on;
399 } dbg;
400 
401 static Dbgkey *
402 finddbgkey(Rune r)
403 {
404 	int i;
405 	Dbgkey *dp;
406 
407 	for(dp = dbg.keys, i = 0; i < dbg.nkeys; i++, dp++)
408 		if(dp->r == r)
409 			return dp;
410 	return nil;
411 }
412 
413 static int
414 dbgwork(void *)
415 {
416 	return dbg.work != 0;
417 }
418 
419 static void
420 dbgproc(void *)
421 {
422 	Dbgkey *dp;
423 
424 	setpri(PriRealtime);
425 	for(;;) {
426 		do {
427 			sleep(&dbg, dbgwork, 0);
428 			dp = dbg.work;
429 		} while(dp == nil);
430 		dp->f(dp->r);
431 		dbg.work = nil;
432 	}
433 }
434 
435 void
436 debugkey(Rune r, char *msg, void (*fcn)(), int iflag)
437 {
438 	Dbgkey *dp;
439 
440 	if(dbg.nkeys >= nelem(dbg.keys))
441 		return;
442 	if(finddbgkey(r) != nil)
443 		return;
444 	for(dp = &dbg.keys[dbg.nkeys++] - 1; dp >= dbg.keys; dp--) {
445 		if(strcmp(dp->m, msg) < 0)
446 			break;
447 		dp[1] = dp[0];
448 	}
449 	dp++;
450 	dp->r = r;
451 	dp->m = msg;
452 	dp->f = fcn;
453 	dp->i = iflag;
454 }
455 
456 static int
457 isdbgkey(Rune r)
458 {
459 	static int ctrlt;
460 	Dbgkey *dp;
461 	int echoctrlt = ctrlt;
462 
463 	/*
464 	 * ^t hack BUG
465 	 */
466 	if(dbg.on || (ctrlt >= 2)) {
467 		if(r == 0x14 || r == 0x05) {
468 			ctrlt++;
469 			return 0;
470 		}
471 		if(dp = finddbgkey(r)) {
472 			if(dp->i || ctrlt > 2)
473 				dp->f(r);
474 			else {
475 				dbg.work = dp;
476 				wakeup(&dbg);
477 			}
478 			ctrlt = 0;
479 			return 1;
480 		}
481 		ctrlt = 0;
482 	}
483 	else if(r == 0x14){
484 		ctrlt++;
485 		return 1;
486 	}
487 	else
488 		ctrlt = 0;
489 	if(echoctrlt){
490 		char buf[3];
491 
492 		buf[0] = 0x14;
493 		while(--echoctrlt >= 0){
494 			echo(buf[0], buf, 1);
495 			qproduce(kbdq, buf, 1);
496 		}
497 	}
498 	return 0;
499 }
500 
501 static void
502 dbgtoggle(Rune)
503 {
504 	dbg.on = !dbg.on;
505 	print("Debug keys %s\n", dbg.on ? "HOT" : "COLD");
506 }
507 
508 static void
509 dbghelp(void)
510 {
511 	int i;
512 	Dbgkey *dp;
513 	Dbgkey *dp2;
514 	static char fmt[] = "%c: %-22s";
515 
516 	dp = dbg.keys;
517 	dp2 = dp + (dbg.nkeys + 1)/2;
518 	for(i = dbg.nkeys; i > 1; i -= 2, dp++, dp2++) {
519 		print(fmt, dp->r, dp->m);
520 		print(fmt, dp2->r, dp2->m);
521 		print("\n");
522 	}
523 	if(i)
524 		print(fmt, dp->r, dp->m);
525 	print("\n");
526 }
527 
528 static void
529 debuginit(void)
530 {
531 	kproc("consdbg", dbgproc, nil, 0);
532 	debugkey('|', "HOT|COLD keys", dbgtoggle, 0);
533 	debugkey('?', "help", dbghelp, 0);
534 }
535 
536 /*
537  *  Called by a uart interrupt for console input.
538  *
539  *  turn '\r' into '\n' before putting it into the queue.
540  */
541 int
542 kbdcr2nl(Queue *q, int ch)
543 {
544 	if(ch == '\r')
545 		ch = '\n';
546 	return kbdputc(q, ch);
547 }
548 
549 /*
550  *  Put character, possibly a rune, into read queue at interrupt time.
551  *  Performs translation for compose sequences
552  *  Called at interrupt time to process a character.
553  */
554 int
555 kbdputc(Queue *q, int ch)
556 {
557 	int n;
558 	char buf[3];
559 	Rune r;
560 	static Rune kc[15];
561 	static int nk, collecting = 0;
562 
563 	r = ch;
564 	if(r == Latin) {
565 		collecting = 1;
566 		nk = 0;
567 		return 0;
568 	}
569 	if(collecting) {
570 		int c;
571 		nk += runetochar((char*)&kc[nk], &r);
572 		c = latin1(kc, nk);
573 		if(c < -1)	/* need more keystrokes */
574 			return 0;
575 		collecting = 0;
576 		if(c == -1) {	/* invalid sequence */
577 			echo(kc[0], (char*)kc, nk);
578 			qproduce(q, kc, nk);
579 			return 0;
580 		}
581 		r = (Rune)c;
582 	}
583 	kbd.c = r;
584 	n = runetochar(buf, &r);
585 	if(n == 0)
586 		return 0;
587 	if(!isdbgkey(r)) {
588 		echo(r, buf, n);
589 		qproduce(q, buf, n);
590 	}
591 	return 0;
592 }
593 
594 void
595 kbdrepeat(int rep)
596 {
597 	kbd.repeat = rep;
598 	kbd.count = 0;
599 }
600 
601 void
602 kbdclock(void)
603 {
604 	if(kbd.repeat == 0)
605 		return;
606 	if(kbd.repeat==1 && ++kbd.count>HZ){
607 		kbd.repeat = 2;
608 		kbd.count = 0;
609 		return;
610 	}
611 	if(++kbd.count&1)
612 		kbdputc(kbdq, kbd.c);
613 }
614 
615 enum{
616 	Qdir,
617 	Qcons,
618 	Qsysctl,
619 	Qconsctl,
620 	Qdrivers,
621 	Qhostowner,
622 	Qkeyboard,
623 	Qklog,
624 	Qkprint,
625 	Qscancode,
626 	Qmemory,
627 	Qmsec,
628 	Qnull,
629 	Qpin,
630 	Qrandom,
631 	Qnotquiterandom,
632 	Qsysname,
633 	Qtime,
634 	Quser,
635 	Qjit,
636 };
637 
638 static Dirtab consdir[]=
639 {
640 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
641 	"cons",		{Qcons},	0,		0660,
642 	"consctl",	{Qconsctl},	0,		0220,
643 	"sysctl",	{Qsysctl},	0,		0644,
644 	"drivers",	{Qdrivers},	0,		0444,
645 	"hostowner",	{Qhostowner},	0,	0644,
646 	"keyboard",	{Qkeyboard},	0,		0666,
647 	"klog",		{Qklog},	0,		0444,
648 	"kprint",		{Qkprint},	0,		0444,
649 	"scancode",	{Qscancode},	0,		0444,
650 	"memory",	{Qmemory},	0,		0444,
651 	"msec",		{Qmsec},	NUMSIZE,	0444,
652 	"null",		{Qnull},	0,		0666,
653 	"pin",		{Qpin},		0,		0666,
654 	"random",	{Qrandom},	0,		0444,
655 	"notquiterandom", {Qnotquiterandom}, 0,	0444,
656 	"sysname",	{Qsysname},	0,		0664,
657 	"time",		{Qtime},	0,		0664,
658 	"user",		{Quser},	0,	0644,
659 	"jit",		{Qjit},	0,	0666,
660 };
661 
662 ulong	boottime;		/* seconds since epoch at boot */
663 
664 long
665 seconds(void)
666 {
667 	return boottime + TK2SEC(MACHP(0)->ticks);
668 }
669 
670 vlong
671 mseconds(void)
672 {
673 	return ((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)));
674 }
675 
676 vlong
677 osusectime(void)
678 {
679 	return (((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)))*1000);
680 }
681 
682 vlong
683 nsec(void)
684 {
685 	return osusectime()*1000;	/* TO DO */
686 }
687 
688 int
689 readnum(ulong off, char *buf, ulong n, ulong val, int size)
690 {
691 	char tmp[64];
692 
693 	if(size > 64) size = 64;
694 
695 	snprint(tmp, sizeof(tmp), "%*.0lud ", size, val);
696 	if(off >= size)
697 		return 0;
698 	if(off+n > size)
699 		n = size-off;
700 	memmove(buf, tmp+off, n);
701 	return n;
702 }
703 
704 int
705 readstr(ulong off, char *buf, ulong n, char *str)
706 {
707 	int size;
708 
709 	size = strlen(str);
710 	if(off >= size)
711 		return 0;
712 	if(off+n > size)
713 		n = size-off;
714 	memmove(buf, str+off, n);
715 	return n;
716 }
717 
718 void
719 fddump()
720 {
721 	Proc *p;
722 	Osenv *o;
723 	int i;
724 	Chan *c;
725 
726 	p = proctab(6);
727 	o = p->env;
728 	for(i = 0; i <= o->fgrp->maxfd; i++) {
729 		if((c = o->fgrp->fd[i]) == nil)
730 			continue;
731 		print("%d: %s\n", i, c->name == nil? "???": c->name->s);
732 	}
733 }
734 
735 static void
736 qpanic(Rune)
737 {
738 	panic("User requested panic.");
739 }
740 
741 static void
742 rexit(Rune)
743 {
744 	exit(0);
745 }
746 
747 static void
748 consinit(void)
749 {
750 	randominit();
751 	debuginit();
752 	debugkey('f', "files/6", fddump, 0);
753 	debugkey('q', "panic", qpanic, 1);
754 	debugkey('r', "exit", rexit, 1);
755 	klogq = qopen(128*1024, 0, 0, 0);
756 }
757 
758 static Chan*
759 consattach(char *spec)
760 {
761 	return devattach('c', spec);
762 }
763 
764 static Walkqid*
765 conswalk(Chan *c, Chan *nc, char **name, int nname)
766 {
767 	return devwalk(c, nc, name, nname, consdir, nelem(consdir), devgen);
768 }
769 
770 static int
771 consstat(Chan *c, uchar *dp, int n)
772 {
773 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
774 }
775 
776 static void
777 flushkbdline(Queue *q)
778 {
779 	if(kbd.x){
780 		qwrite(q, kbd.line, kbd.x);
781 		kbd.x = 0;
782 	}
783 }
784 
785 static Chan*
786 consopen(Chan *c, int omode)
787 {
788 	c->aux = 0;
789 	switch((ulong)c->qid.path){
790 	case Qconsctl:
791 		if(!iseve())
792 			error(Eperm);
793 		qlock(&kbd);
794 		kbd.ctl++;
795 		qunlock(&kbd);
796 		break;
797 
798 	case Qkeyboard:
799 		if((omode & 3) != OWRITE) {
800 			qlock(&kbd);
801 			kbd.kbdr++;
802 			flushkbdline(kbdq);
803 			kbd.raw = 1;
804 			qunlock(&kbd);
805 		}
806 		break;
807 
808 	case Qscancode:
809 		qlock(&kbd);
810 		if(kscanq || !kscanid) {
811 			qunlock(&kbd);
812 			c->flag &= ~COPEN;
813 			if(kscanq)
814 				error(Einuse);
815 			else
816 				error(Ebadarg);
817 		}
818 		kscanq = qopen(256, 0, nil, nil);
819 		qunlock(&kbd);
820 		break;
821 
822 	case Qkprint:
823 		if((omode & 3) != OWRITE) {
824 			wlock(&kprintq);
825 			if(kprintq.q != nil){
826 				wunlock(&kprintq);
827 				error(Einuse);
828 			}
829 			kprintq.q = qopen(32*1024, Qcoalesce, nil, nil);
830 			if(kprintq.q == nil){
831 				wunlock(&kprintq);
832 				error(Enomem);
833 			}
834 			qnoblock(kprintq.q, 1);
835 			wunlock(&kprintq);
836 			c->iounit = qiomaxatomic;
837 		}
838 		break;
839 	}
840 	return devopen(c, omode, consdir, nelem(consdir), devgen);
841 }
842 
843 static void
844 consclose(Chan *c)
845 {
846 	if((c->flag&COPEN) == 0)
847 		return;
848 
849 	switch((ulong)c->qid.path){
850 	case Qconsctl:
851 		/* last close of control file turns off raw */
852 		qlock(&kbd);
853 		if(--kbd.ctl == 0)
854 			kbd.raw = 0;
855 		qunlock(&kbd);
856 		break;
857 
858 	case Qkeyboard:
859 		if(c->mode != OWRITE) {
860 			qlock(&kbd);
861 			--kbd.kbdr;
862 			qunlock(&kbd);
863 		}
864 		break;
865 
866 	case Qscancode:
867 		qlock(&kbd);
868 		if(kscanq) {
869 			qfree(kscanq);
870 			kscanq = 0;
871 		}
872 		qunlock(&kbd);
873 		break;
874 
875 	case Qkprint:
876 		wlock(&kprintq);
877 		qfree(kprintq.q);
878 		kprintq.q = nil;
879 		wunlock(&kprintq);
880 		break;
881 	}
882 }
883 
884 static long
885 consread(Chan *c, void *buf, long n, vlong offset)
886 {
887 	int l;
888 	Osenv *o;
889 	int ch, eol, i;
890 	char *p, tmp[128];
891 	char *cbuf = buf;
892 
893 	if(n <= 0)
894 		return n;
895 	o = up->env;
896 	switch((ulong)c->qid.path){
897 	case Qdir:
898 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
899 	case Qsysctl:
900 		return readstr(offset, buf, n, VERSION);
901 	case Qcons:
902 	case Qkeyboard:
903 		qlock(&kbd);
904 		if(waserror()) {
905 			qunlock(&kbd);
906 			nexterror();
907 		}
908 		if(kbd.raw || kbd.kbdr) {
909 			if(qcanread(lineq))
910 				n = qread(lineq, buf, n);
911 			else {
912 				/* read as much as possible */
913 				do {
914 					i = qread(kbdq, cbuf, n);
915 					cbuf += i;
916 					n -= i;
917 				} while(n>0 && qcanread(kbdq));
918 				n = cbuf - (char*)buf;
919 			}
920 		} else {
921 			while(!qcanread(lineq)) {
922 				qread(kbdq, &kbd.line[kbd.x], 1);
923 				ch = kbd.line[kbd.x];
924 				eol = 0;
925 				switch(ch){
926 				case '\b':
927 					if(kbd.x)
928 						kbd.x--;
929 					break;
930 				case 0x15:
931 					kbd.x = 0;
932 					break;
933 				case '\n':
934 				case 0x04:
935 					eol = 1;
936 				default:
937 					kbd.line[kbd.x++] = ch;
938 					break;
939 				}
940 				if(kbd.x == sizeof(kbd.line) || eol) {
941 					if(ch == 0x04)
942 						kbd.x--;
943 					qwrite(lineq, kbd.line, kbd.x);
944 					kbd.x = 0;
945 				}
946 			}
947 			n = qread(lineq, buf, n);
948 		}
949 		qunlock(&kbd);
950 		poperror();
951 		return n;
952 
953 	case Qscancode:
954 		if(offset == 0)
955 			return readstr(0, buf, n, kscanid);
956 		else
957 			return qread(kscanq, buf, n);
958 
959 	case Qpin:
960 		p = "pin set";
961 		if(up->env->pgrp->pin == Nopin)
962 			p = "no pin";
963 		return readstr(offset, buf, n, p);
964 
965 	case Qtime:
966 		snprint(tmp, sizeof(tmp), "%.lld", (vlong)mseconds()*1000);
967 		return readstr(offset, buf, n, tmp);
968 
969 	case Qhostowner:
970 		return readstr(offset, buf, n, eve);
971 
972 	case Quser:
973 		return readstr(offset, buf, n, o->user);
974 
975 	case Qjit:
976 		snprint(tmp, sizeof(tmp), "%d", cflag);
977 		return readstr(offset, buf, n, tmp);
978 
979 	case Qnull:
980 		return 0;
981 
982 	case Qmsec:
983 		return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
984 
985 	case Qsysname:
986 		if(sysname == nil)
987 			return 0;
988 		return readstr(offset, buf, n, sysname);
989 
990 	case Qnotquiterandom:
991 		genrandom(buf, n);
992 		return n;
993 
994 	case Qrandom:
995 		return randomread(buf, n);
996 
997 	case Qmemory:
998 		return poolread(buf, n, offset);
999 
1000 	case Qdrivers:
1001 		p = malloc(READSTR);
1002 		if(p == nil)
1003 			error(Enomem);
1004 		l = 0;
1005 		for(i = 0; devtab[i] != nil; i++)
1006 			l += snprint(p+l, READSTR-l, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
1007 		if(waserror()){
1008 			free(p);
1009 			nexterror();
1010 		}
1011 		n = readstr(offset, buf, n, p);
1012 		free(p);
1013 		poperror();
1014 		return n;
1015 
1016 	case Qklog:
1017 		return qread(klogq, buf, n);
1018 
1019 	case Qkprint:
1020 		rlock(&kprintq);
1021 		if(waserror()){
1022 			runlock(&kprintq);
1023 			nexterror();
1024 		}
1025 		n = qread(kprintq.q, buf, n);
1026 		poperror();
1027 		runlock(&kprintq);
1028 		return n;
1029 
1030 	default:
1031 		print("consread %llud\n", c->qid.path);
1032 		error(Egreg);
1033 	}
1034 	return -1;		/* never reached */
1035 }
1036 
1037 static long
1038 conswrite(Chan *c, void *va, long n, vlong offset)
1039 {
1040 	vlong t;
1041 	long l, bp;
1042 	char *a = va;
1043 	Cmdbuf *cb;
1044 	Cmdtab *ct;
1045 	char buf[256];
1046 	int x;
1047 
1048 	switch((ulong)c->qid.path){
1049 	case Qcons:
1050 		/*
1051 		 * Can't page fault in putstrn, so copy the data locally.
1052 		 */
1053 		l = n;
1054 		while(l > 0){
1055 			bp = l;
1056 			if(bp > sizeof buf)
1057 				bp = sizeof buf;
1058 			memmove(buf, a, bp);
1059 			putstrn0(a, bp, 1);
1060 			a += bp;
1061 			l -= bp;
1062 		}
1063 		break;
1064 
1065 	case Qconsctl:
1066 		if(n >= sizeof(buf))
1067 			n = sizeof(buf)-1;
1068 		strncpy(buf, a, n);
1069 		buf[n] = 0;
1070 		for(a = buf; a;){
1071 			if(strncmp(a, "rawon", 5) == 0){
1072 				qlock(&kbd);
1073 				flushkbdline(kbdq);
1074 				kbd.raw = 1;
1075 				qunlock(&kbd);
1076 			} else if(strncmp(a, "rawoff", 6) == 0){
1077 				qlock(&kbd);
1078 				kbd.raw = 0;
1079 				kbd.x = 0;
1080 				qunlock(&kbd);
1081 			}
1082 			if(a = strchr(a, ' '))
1083 				a++;
1084 		}
1085 		break;
1086 
1087 	case Qkeyboard:
1088 		for(x=0; x<n; ) {
1089 			Rune r;
1090 			x += chartorune(&r, &a[x]);
1091 			kbdputc(kbdq, r);
1092 		}
1093 		break;
1094 
1095 	case Qtime:
1096 		if(n >= sizeof(buf))
1097 			n = sizeof(buf)-1;
1098 		strncpy(buf, a, n);
1099 		buf[n] = 0;
1100 		t = strtoll(buf, 0, 0)/1000000;
1101 		boottime = t - TK2SEC(MACHP(0)->ticks);
1102 		break;
1103 
1104 	case Qhostowner:
1105 		if(!iseve())
1106 			error(Eperm);
1107 		if(offset != 0 || n >= sizeof(buf))
1108 			error(Ebadarg);
1109 		memmove(buf, a, n);
1110 		buf[n] = '\0';
1111 		if(n > 0 && buf[n-1] == '\n')
1112 			buf[--n] = 0;
1113 		if(n <= 0)
1114 			error(Ebadarg);
1115 		renameuser(eve, buf);
1116 		renameproguser(eve, buf);
1117 		kstrdup(&eve, buf);
1118 		kstrdup(&up->env->user, buf);
1119 		break;
1120 
1121 	case Quser:
1122 		if(!iseve())
1123 			error(Eperm);
1124 		if(offset != 0)
1125 			error(Ebadarg);
1126 		if(n <= 0 || n >= sizeof(buf))
1127 			error(Ebadarg);
1128 		strncpy(buf, a, n);
1129 		buf[n] = 0;
1130 		if(buf[n-1] == '\n')
1131 			buf[n-1] = 0;
1132 		kstrdup(&up->env->user, buf);
1133 		break;
1134 
1135 	case Qjit:
1136 		if(n >= sizeof(buf))
1137 			n = sizeof(buf)-1;
1138 		strncpy(buf, va, n);
1139 		buf[n] = '\0';
1140 		x = atoi(buf);
1141 		if(x < 0 || x > 9)
1142 			error(Ebadarg);
1143 		cflag = x;
1144 		return n;
1145 
1146 	case Qnull:
1147 		break;
1148 
1149 	case Qpin:
1150 		if(up->env->pgrp->pin != Nopin)
1151 			error("pin already set");
1152 		if(n >= sizeof(buf))
1153 			n = sizeof(buf)-1;
1154 		strncpy(buf, va, n);
1155 		buf[n] = '\0';
1156 		up->env->pgrp->pin = atoi(buf);
1157 		return n;
1158 
1159 	case Qsysname:
1160 		if(offset != 0)
1161 			error(Ebadarg);
1162 		if(n <= 0 || n >= sizeof(buf))
1163 			error(Ebadarg);
1164 		strncpy(buf, a, n);
1165 		buf[n] = 0;
1166 		if(buf[n-1] == '\n')
1167 			buf[n-1] = 0;
1168 		kstrdup(&sysname, buf);
1169 		break;
1170 
1171 	case Qsysctl:
1172 		if(!iseve())
1173 			error(Eperm);
1174 		cb = parsecmd(a, n);
1175 		if(waserror()){
1176 			free(cb);
1177 			nexterror();
1178 		}
1179 		ct = lookupcmd(cb, sysctlcmd, nelem(sysctlcmd));
1180 		switch(ct->index){
1181 		case CMreboot:
1182 			reboot();
1183 			break;
1184 		case CMhalt:
1185 			halt();
1186 			break;
1187 		case CMpanic:
1188 			panic("sysctl");
1189 		case CMconsole:
1190 			consoleprint = strcmp(cb->f[1], "off") != 0;
1191 			break;
1192 		case CMbroken:
1193 			keepbroken = 1;
1194 			break;
1195 		case CMnobroken:
1196 			keepbroken = 0;
1197 			break;
1198 		}
1199 		poperror();
1200 		free(cb);
1201 		break;
1202 
1203 	default:
1204 		print("conswrite: %llud\n", c->qid.path);
1205 		error(Egreg);
1206 	}
1207 	return n;
1208 }
1209 
1210 Dev consdevtab = {
1211 	'c',
1212 	"cons",
1213 
1214 	devreset,
1215 	consinit,
1216 	devshutdown,
1217 	consattach,
1218 	conswalk,
1219 	consstat,
1220 	consopen,
1221 	devcreate,
1222 	consclose,
1223 	consread,
1224 	devbread,
1225 	conswrite,
1226 	devbwrite,
1227 	devremove,
1228 	devwstat,
1229 };
1230 
1231 static	ulong	randn;
1232 
1233 static void
1234 seedrand(void)
1235 {
1236 	randomread((void*)&randn, sizeof(randn));
1237 }
1238 
1239 int
1240 nrand(int n)
1241 {
1242 	if(randn == 0)
1243 		seedrand();
1244 	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
1245 	return (randn>>16) % n;
1246 }
1247 
1248 int
1249 rand(void)
1250 {
1251 	nrand(1);
1252 	return randn;
1253 }
1254 
1255 ulong
1256 truerand(void)
1257 {
1258 	ulong x;
1259 
1260 	randomread(&x, sizeof(x));
1261 	return x;
1262 }
1263 
1264 QLock grandomlk;
1265 
1266 void
1267 _genrandomqlock(void)
1268 {
1269 	qlock(&grandomlk);
1270 }
1271 
1272 
1273 void
1274 _genrandomqunlock(void)
1275 {
1276 	qunlock(&grandomlk);
1277 }
1278