xref: /inferno-os/os/port/devcons.c (revision 5d0c4cf3fc288434c41cba52dd998ab1d7375a7b)
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[UTFmax];
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[UTFmax];
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 	Qrandom,
630 	Qnotquiterandom,
631 	Qsysname,
632 	Qtime,
633 	Quser,
634 	Qjit,
635 };
636 
637 static Dirtab consdir[]=
638 {
639 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
640 	"cons",		{Qcons},	0,		0660,
641 	"consctl",	{Qconsctl},	0,		0220,
642 	"sysctl",	{Qsysctl},	0,		0644,
643 	"drivers",	{Qdrivers},	0,		0444,
644 	"hostowner",	{Qhostowner},	0,	0644,
645 	"keyboard",	{Qkeyboard},	0,		0666,
646 	"klog",		{Qklog},	0,		0444,
647 	"kprint",		{Qkprint},	0,		0444,
648 	"scancode",	{Qscancode},	0,		0444,
649 	"memory",	{Qmemory},	0,		0444,
650 	"msec",		{Qmsec},	NUMSIZE,	0444,
651 	"null",		{Qnull},	0,		0666,
652 	"random",	{Qrandom},	0,		0444,
653 	"notquiterandom", {Qnotquiterandom}, 0,	0444,
654 	"sysname",	{Qsysname},	0,		0664,
655 	"time",		{Qtime},	0,		0664,
656 	"user",		{Quser},	0,	0644,
657 	"jit",		{Qjit},	0,	0666,
658 };
659 
660 ulong	boottime;		/* seconds since epoch at boot */
661 
662 long
663 seconds(void)
664 {
665 	return boottime + TK2SEC(MACHP(0)->ticks);
666 }
667 
668 vlong
669 mseconds(void)
670 {
671 	return ((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)));
672 }
673 
674 vlong
675 osusectime(void)
676 {
677 	return (((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)))*1000);
678 }
679 
680 vlong
681 nsec(void)
682 {
683 	return osusectime()*1000;	/* TO DO */
684 }
685 
686 int
687 readnum(ulong off, char *buf, ulong n, ulong val, int size)
688 {
689 	char tmp[64];
690 
691 	if(size > 64) size = 64;
692 
693 	snprint(tmp, sizeof(tmp), "%*.0lud ", size, val);
694 	if(off >= size)
695 		return 0;
696 	if(off+n > size)
697 		n = size-off;
698 	memmove(buf, tmp+off, n);
699 	return n;
700 }
701 
702 int
703 readstr(ulong off, char *buf, ulong n, char *str)
704 {
705 	int size;
706 
707 	size = strlen(str);
708 	if(off >= size)
709 		return 0;
710 	if(off+n > size)
711 		n = size-off;
712 	memmove(buf, str+off, n);
713 	return n;
714 }
715 
716 void
717 fddump()
718 {
719 	Proc *p;
720 	Osenv *o;
721 	int i;
722 	Chan *c;
723 
724 	p = proctab(6);
725 	o = p->env;
726 	for(i = 0; i <= o->fgrp->maxfd; i++) {
727 		if((c = o->fgrp->fd[i]) == nil)
728 			continue;
729 		print("%d: %s\n", i, c->name == nil? "???": c->name->s);
730 	}
731 }
732 
733 static void
734 qpanic(Rune)
735 {
736 	panic("User requested panic.");
737 }
738 
739 static void
740 rexit(Rune)
741 {
742 	exit(0);
743 }
744 
745 static void
746 consinit(void)
747 {
748 	randominit();
749 	debuginit();
750 	debugkey('f', "files/6", fddump, 0);
751 	debugkey('q', "panic", qpanic, 1);
752 	debugkey('r', "exit", rexit, 1);
753 	klogq = qopen(128*1024, 0, 0, 0);
754 }
755 
756 static Chan*
757 consattach(char *spec)
758 {
759 	return devattach('c', spec);
760 }
761 
762 static Walkqid*
763 conswalk(Chan *c, Chan *nc, char **name, int nname)
764 {
765 	return devwalk(c, nc, name, nname, consdir, nelem(consdir), devgen);
766 }
767 
768 static int
769 consstat(Chan *c, uchar *dp, int n)
770 {
771 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
772 }
773 
774 static void
775 flushkbdline(Queue *q)
776 {
777 	if(kbd.x){
778 		qwrite(q, kbd.line, kbd.x);
779 		kbd.x = 0;
780 	}
781 }
782 
783 static Chan*
784 consopen(Chan *c, int omode)
785 {
786 	c->aux = 0;
787 	switch((ulong)c->qid.path){
788 	case Qconsctl:
789 		if(!iseve())
790 			error(Eperm);
791 		qlock(&kbd);
792 		kbd.ctl++;
793 		qunlock(&kbd);
794 		break;
795 
796 	case Qkeyboard:
797 		if((omode & 3) != OWRITE) {
798 			qlock(&kbd);
799 			kbd.kbdr++;
800 			flushkbdline(kbdq);
801 			kbd.raw = 1;
802 			qunlock(&kbd);
803 		}
804 		break;
805 
806 	case Qscancode:
807 		qlock(&kbd);
808 		if(kscanq || !kscanid) {
809 			qunlock(&kbd);
810 			c->flag &= ~COPEN;
811 			if(kscanq)
812 				error(Einuse);
813 			else
814 				error(Ebadarg);
815 		}
816 		kscanq = qopen(256, 0, nil, nil);
817 		qunlock(&kbd);
818 		break;
819 
820 	case Qkprint:
821 		if((omode & 3) != OWRITE) {
822 			wlock(&kprintq);
823 			if(kprintq.q != nil){
824 				wunlock(&kprintq);
825 				error(Einuse);
826 			}
827 			kprintq.q = qopen(32*1024, Qcoalesce, nil, nil);
828 			if(kprintq.q == nil){
829 				wunlock(&kprintq);
830 				error(Enomem);
831 			}
832 			qnoblock(kprintq.q, 1);
833 			wunlock(&kprintq);
834 			c->iounit = qiomaxatomic;
835 		}
836 		break;
837 	}
838 	return devopen(c, omode, consdir, nelem(consdir), devgen);
839 }
840 
841 static void
842 consclose(Chan *c)
843 {
844 	if((c->flag&COPEN) == 0)
845 		return;
846 
847 	switch((ulong)c->qid.path){
848 	case Qconsctl:
849 		/* last close of control file turns off raw */
850 		qlock(&kbd);
851 		if(--kbd.ctl == 0)
852 			kbd.raw = 0;
853 		qunlock(&kbd);
854 		break;
855 
856 	case Qkeyboard:
857 		if(c->mode != OWRITE) {
858 			qlock(&kbd);
859 			--kbd.kbdr;
860 			qunlock(&kbd);
861 		}
862 		break;
863 
864 	case Qscancode:
865 		qlock(&kbd);
866 		if(kscanq) {
867 			qfree(kscanq);
868 			kscanq = 0;
869 		}
870 		qunlock(&kbd);
871 		break;
872 
873 	case Qkprint:
874 		wlock(&kprintq);
875 		qfree(kprintq.q);
876 		kprintq.q = nil;
877 		wunlock(&kprintq);
878 		break;
879 	}
880 }
881 
882 static long
883 consread(Chan *c, void *buf, long n, vlong offset)
884 {
885 	int l;
886 	Osenv *o;
887 	int ch, eol, i;
888 	char *p, tmp[128];
889 	char *cbuf = buf;
890 
891 	if(n <= 0)
892 		return n;
893 	o = up->env;
894 	switch((ulong)c->qid.path){
895 	case Qdir:
896 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
897 	case Qsysctl:
898 		return readstr(offset, buf, n, VERSION);
899 	case Qcons:
900 	case Qkeyboard:
901 		qlock(&kbd);
902 		if(waserror()) {
903 			qunlock(&kbd);
904 			nexterror();
905 		}
906 		if(kbd.raw || kbd.kbdr) {
907 			if(qcanread(lineq))
908 				n = qread(lineq, buf, n);
909 			else {
910 				/* read as much as possible */
911 				do {
912 					i = qread(kbdq, cbuf, n);
913 					cbuf += i;
914 					n -= i;
915 				} while(n>0 && qcanread(kbdq));
916 				n = cbuf - (char*)buf;
917 			}
918 		} else {
919 			while(!qcanread(lineq)) {
920 				qread(kbdq, &kbd.line[kbd.x], 1);
921 				ch = kbd.line[kbd.x];
922 				eol = 0;
923 				switch(ch){
924 				case '\b':
925 					if(kbd.x)
926 						kbd.x--;
927 					break;
928 				case 0x15:
929 					kbd.x = 0;
930 					break;
931 				case '\n':
932 				case 0x04:
933 					eol = 1;
934 				default:
935 					kbd.line[kbd.x++] = ch;
936 					break;
937 				}
938 				if(kbd.x == sizeof(kbd.line) || eol) {
939 					if(ch == 0x04)
940 						kbd.x--;
941 					qwrite(lineq, kbd.line, kbd.x);
942 					kbd.x = 0;
943 				}
944 			}
945 			n = qread(lineq, buf, n);
946 		}
947 		qunlock(&kbd);
948 		poperror();
949 		return n;
950 
951 	case Qscancode:
952 		if(offset == 0)
953 			return readstr(0, buf, n, kscanid);
954 		else
955 			return qread(kscanq, buf, n);
956 
957 	case Qtime:
958 		snprint(tmp, sizeof(tmp), "%.lld", (vlong)mseconds()*1000);
959 		return readstr(offset, buf, n, tmp);
960 
961 	case Qhostowner:
962 		return readstr(offset, buf, n, eve);
963 
964 	case Quser:
965 		return readstr(offset, buf, n, o->user);
966 
967 	case Qjit:
968 		snprint(tmp, sizeof(tmp), "%d", cflag);
969 		return readstr(offset, buf, n, tmp);
970 
971 	case Qnull:
972 		return 0;
973 
974 	case Qmsec:
975 		return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
976 
977 	case Qsysname:
978 		if(sysname == nil)
979 			return 0;
980 		return readstr(offset, buf, n, sysname);
981 
982 	case Qnotquiterandom:
983 		genrandom(buf, n);
984 		return n;
985 
986 	case Qrandom:
987 		return randomread(buf, n);
988 
989 	case Qmemory:
990 		return poolread(buf, n, offset);
991 
992 	case Qdrivers:
993 		p = malloc(READSTR);
994 		if(p == nil)
995 			error(Enomem);
996 		l = 0;
997 		for(i = 0; devtab[i] != nil; i++)
998 			l += snprint(p+l, READSTR-l, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
999 		if(waserror()){
1000 			free(p);
1001 			nexterror();
1002 		}
1003 		n = readstr(offset, buf, n, p);
1004 		free(p);
1005 		poperror();
1006 		return n;
1007 
1008 	case Qklog:
1009 		return qread(klogq, buf, n);
1010 
1011 	case Qkprint:
1012 		rlock(&kprintq);
1013 		if(waserror()){
1014 			runlock(&kprintq);
1015 			nexterror();
1016 		}
1017 		n = qread(kprintq.q, buf, n);
1018 		poperror();
1019 		runlock(&kprintq);
1020 		return n;
1021 
1022 	default:
1023 		print("consread %llud\n", c->qid.path);
1024 		error(Egreg);
1025 	}
1026 	return -1;		/* never reached */
1027 }
1028 
1029 static long
1030 conswrite(Chan *c, void *va, long n, vlong offset)
1031 {
1032 	vlong t;
1033 	long l, bp;
1034 	char *a = va;
1035 	Cmdbuf *cb;
1036 	Cmdtab *ct;
1037 	char buf[256];
1038 	int x;
1039 
1040 	switch((ulong)c->qid.path){
1041 	case Qcons:
1042 		/*
1043 		 * Can't page fault in putstrn, so copy the data locally.
1044 		 */
1045 		l = n;
1046 		while(l > 0){
1047 			bp = l;
1048 			if(bp > sizeof buf)
1049 				bp = sizeof buf;
1050 			memmove(buf, a, bp);
1051 			putstrn0(a, bp, 1);
1052 			a += bp;
1053 			l -= bp;
1054 		}
1055 		break;
1056 
1057 	case Qconsctl:
1058 		if(n >= sizeof(buf))
1059 			n = sizeof(buf)-1;
1060 		strncpy(buf, a, n);
1061 		buf[n] = 0;
1062 		for(a = buf; a;){
1063 			if(strncmp(a, "rawon", 5) == 0){
1064 				qlock(&kbd);
1065 				flushkbdline(kbdq);
1066 				kbd.raw = 1;
1067 				qunlock(&kbd);
1068 			} else if(strncmp(a, "rawoff", 6) == 0){
1069 				qlock(&kbd);
1070 				kbd.raw = 0;
1071 				kbd.x = 0;
1072 				qunlock(&kbd);
1073 			}
1074 			if(a = strchr(a, ' '))
1075 				a++;
1076 		}
1077 		break;
1078 
1079 	case Qkeyboard:
1080 		for(x=0; x<n; ) {
1081 			Rune r;
1082 			x += chartorune(&r, &a[x]);
1083 			kbdputc(kbdq, r);
1084 		}
1085 		break;
1086 
1087 	case Qtime:
1088 		if(n >= sizeof(buf))
1089 			n = sizeof(buf)-1;
1090 		strncpy(buf, a, n);
1091 		buf[n] = 0;
1092 		t = strtoll(buf, 0, 0)/1000000;
1093 		boottime = t - TK2SEC(MACHP(0)->ticks);
1094 		break;
1095 
1096 	case Qhostowner:
1097 		if(!iseve())
1098 			error(Eperm);
1099 		if(offset != 0 || n >= sizeof(buf))
1100 			error(Ebadarg);
1101 		memmove(buf, a, n);
1102 		buf[n] = '\0';
1103 		if(n > 0 && buf[n-1] == '\n')
1104 			buf[--n] = 0;
1105 		if(n <= 0)
1106 			error(Ebadarg);
1107 		renameuser(eve, buf);
1108 		renameproguser(eve, buf);
1109 		kstrdup(&eve, buf);
1110 		kstrdup(&up->env->user, buf);
1111 		break;
1112 
1113 	case Quser:
1114 		if(!iseve())
1115 			error(Eperm);
1116 		if(offset != 0)
1117 			error(Ebadarg);
1118 		if(n <= 0 || n >= sizeof(buf))
1119 			error(Ebadarg);
1120 		strncpy(buf, a, n);
1121 		buf[n] = 0;
1122 		if(buf[n-1] == '\n')
1123 			buf[n-1] = 0;
1124 		kstrdup(&up->env->user, buf);
1125 		break;
1126 
1127 	case Qjit:
1128 		if(n >= sizeof(buf))
1129 			n = sizeof(buf)-1;
1130 		strncpy(buf, va, n);
1131 		buf[n] = '\0';
1132 		x = atoi(buf);
1133 		if(x < 0 || x > 9)
1134 			error(Ebadarg);
1135 		cflag = x;
1136 		return n;
1137 
1138 	case Qnull:
1139 		break;
1140 
1141 	case Qsysname:
1142 		if(offset != 0)
1143 			error(Ebadarg);
1144 		if(n <= 0 || n >= sizeof(buf))
1145 			error(Ebadarg);
1146 		strncpy(buf, a, n);
1147 		buf[n] = 0;
1148 		if(buf[n-1] == '\n')
1149 			buf[n-1] = 0;
1150 		kstrdup(&sysname, buf);
1151 		break;
1152 
1153 	case Qsysctl:
1154 		if(!iseve())
1155 			error(Eperm);
1156 		cb = parsecmd(a, n);
1157 		if(waserror()){
1158 			free(cb);
1159 			nexterror();
1160 		}
1161 		ct = lookupcmd(cb, sysctlcmd, nelem(sysctlcmd));
1162 		switch(ct->index){
1163 		case CMreboot:
1164 			reboot();
1165 			break;
1166 		case CMhalt:
1167 			halt();
1168 			break;
1169 		case CMpanic:
1170 			panic("sysctl");
1171 		case CMconsole:
1172 			consoleprint = strcmp(cb->f[1], "off") != 0;
1173 			break;
1174 		case CMbroken:
1175 			keepbroken = 1;
1176 			break;
1177 		case CMnobroken:
1178 			keepbroken = 0;
1179 			break;
1180 		}
1181 		poperror();
1182 		free(cb);
1183 		break;
1184 
1185 	default:
1186 		print("conswrite: %llud\n", c->qid.path);
1187 		error(Egreg);
1188 	}
1189 	return n;
1190 }
1191 
1192 Dev consdevtab = {
1193 	'c',
1194 	"cons",
1195 
1196 	devreset,
1197 	consinit,
1198 	devshutdown,
1199 	consattach,
1200 	conswalk,
1201 	consstat,
1202 	consopen,
1203 	devcreate,
1204 	consclose,
1205 	consread,
1206 	devbread,
1207 	conswrite,
1208 	devbwrite,
1209 	devremove,
1210 	devwstat,
1211 };
1212 
1213 static	ulong	randn;
1214 
1215 static void
1216 seedrand(void)
1217 {
1218 	randomread((void*)&randn, sizeof(randn));
1219 }
1220 
1221 int
1222 nrand(int n)
1223 {
1224 	if(randn == 0)
1225 		seedrand();
1226 	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
1227 	return (randn>>16) % n;
1228 }
1229 
1230 int
1231 rand(void)
1232 {
1233 	nrand(1);
1234 	return randn;
1235 }
1236 
1237 ulong
1238 truerand(void)
1239 {
1240 	ulong x;
1241 
1242 	randomread(&x, sizeof(x));
1243 	return x;
1244 }
1245 
1246 QLock grandomlk;
1247 
1248 void
1249 _genrandomqlock(void)
1250 {
1251 	qlock(&grandomlk);
1252 }
1253 
1254 
1255 void
1256 _genrandomqunlock(void)
1257 {
1258 	qunlock(&grandomlk);
1259 }
1260