xref: /inferno-os/os/port/devcons.c (revision 6e425a9de8c003b5a733621a6b6730ec3cc902b8)
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 void
308 sysfatal(char *fmt, ...)
309 {
310 	va_list arg;
311 	char buf[64];
312 
313 	va_start(arg, fmt);
314 	vsnprint(buf, sizeof(buf), fmt, arg);
315 	va_end(arg);
316 	panic("sysfatal: %s", buf);
317 }
318 
319 int
320 pprint(char *fmt, ...)
321 {
322 	int n;
323 	Chan *c;
324 	Osenv *o;
325 	va_list arg;
326 	char buf[2*PRINTSIZE];
327 
328 	n = sprint(buf, "%s %ld: ", up->text, up->pid);
329 	va_start(arg, fmt);
330 	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
331 	va_end(arg);
332 
333 	o = up->env;
334 	if(o->fgrp == 0) {
335 		print("%s", buf);
336 		return 0;
337 	}
338 	c = o->fgrp->fd[2];
339 	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) {
340 		print("%s", buf);
341 		return 0;
342 	}
343 
344 	if(waserror()) {
345 		print("%s", buf);
346 		return 0;
347 	}
348 	devtab[c->type]->write(c, buf, n, c->offset);
349 	poperror();
350 
351 	lock(c);
352 	c->offset += n;
353 	unlock(c);
354 
355 	return n;
356 }
357 
358 void
359 echo(Rune r, char *buf, int n)
360 {
361 	if(kbd.raw)
362 		return;
363 
364 	if(r == '\n'){
365 		if(printq)
366 			qiwrite(printq, "\r", 1);
367 	} else if(r == 0x15){
368 		buf = "^U\n";
369 		n = 3;
370 	}
371 	if(consoleprint && screenputs != nil)
372 		screenputs(buf, n);
373 	if(printq)
374 		qiwrite(printq, buf, n);
375 }
376 
377 /*
378  *	Debug key support.  Allows other parts of the kernel to register debug
379  *	key handlers, instead of devcons.c having to know whatever's out there.
380  *	A kproc is used to invoke most handlers, rather than tying up the CPU at
381  *	splhi, which can choke some device drivers (eg softmodem).
382  */
383 typedef struct {
384 	Rune	r;
385 	char	*m;
386 	void	(*f)(Rune);
387 	int	i;	/* function called at interrupt time */
388 } Dbgkey;
389 
390 static struct {
391 	Rendez;
392 	Dbgkey	*work;
393 	Dbgkey	keys[50];
394 	int	nkeys;
395 	int	on;
396 } dbg;
397 
398 static Dbgkey *
399 finddbgkey(Rune r)
400 {
401 	int i;
402 	Dbgkey *dp;
403 
404 	for(dp = dbg.keys, i = 0; i < dbg.nkeys; i++, dp++)
405 		if(dp->r == r)
406 			return dp;
407 	return nil;
408 }
409 
410 static int
411 dbgwork(void *)
412 {
413 	return dbg.work != 0;
414 }
415 
416 static void
417 dbgproc(void *)
418 {
419 	Dbgkey *dp;
420 
421 	setpri(PriRealtime);
422 	for(;;) {
423 		do {
424 			sleep(&dbg, dbgwork, 0);
425 			dp = dbg.work;
426 		} while(dp == nil);
427 		dp->f(dp->r);
428 		dbg.work = nil;
429 	}
430 }
431 
432 void
433 debugkey(Rune r, char *msg, void (*fcn)(), int iflag)
434 {
435 	Dbgkey *dp;
436 
437 	if(dbg.nkeys >= nelem(dbg.keys))
438 		return;
439 	if(finddbgkey(r) != nil)
440 		return;
441 	for(dp = &dbg.keys[dbg.nkeys++] - 1; dp >= dbg.keys; dp--) {
442 		if(strcmp(dp->m, msg) < 0)
443 			break;
444 		dp[1] = dp[0];
445 	}
446 	dp++;
447 	dp->r = r;
448 	dp->m = msg;
449 	dp->f = fcn;
450 	dp->i = iflag;
451 }
452 
453 static int
454 isdbgkey(Rune r)
455 {
456 	static int ctrlt;
457 	Dbgkey *dp;
458 	int echoctrlt = ctrlt;
459 
460 	/*
461 	 * ^t hack BUG
462 	 */
463 	if(dbg.on || (ctrlt >= 2)) {
464 		if(r == 0x14 || r == 0x05) {
465 			ctrlt++;
466 			return 0;
467 		}
468 		if(dp = finddbgkey(r)) {
469 			if(dp->i || ctrlt > 2)
470 				dp->f(r);
471 			else {
472 				dbg.work = dp;
473 				wakeup(&dbg);
474 			}
475 			ctrlt = 0;
476 			return 1;
477 		}
478 		ctrlt = 0;
479 	}
480 	else if(r == 0x14){
481 		ctrlt++;
482 		return 1;
483 	}
484 	else
485 		ctrlt = 0;
486 	if(echoctrlt){
487 		char buf[3];
488 
489 		buf[0] = 0x14;
490 		while(--echoctrlt >= 0){
491 			echo(buf[0], buf, 1);
492 			qproduce(kbdq, buf, 1);
493 		}
494 	}
495 	return 0;
496 }
497 
498 static void
499 dbgtoggle(Rune)
500 {
501 	dbg.on = !dbg.on;
502 	print("Debug keys %s\n", dbg.on ? "HOT" : "COLD");
503 }
504 
505 static void
506 dbghelp(void)
507 {
508 	int i;
509 	Dbgkey *dp;
510 	Dbgkey *dp2;
511 	static char fmt[] = "%c: %-22s";
512 
513 	dp = dbg.keys;
514 	dp2 = dp + (dbg.nkeys + 1)/2;
515 	for(i = dbg.nkeys; i > 1; i -= 2, dp++, dp2++) {
516 		print(fmt, dp->r, dp->m);
517 		print(fmt, dp2->r, dp2->m);
518 		print("\n");
519 	}
520 	if(i)
521 		print(fmt, dp->r, dp->m);
522 	print("\n");
523 }
524 
525 static void
526 debuginit(void)
527 {
528 	kproc("consdbg", dbgproc, nil, 0);
529 	debugkey('|', "HOT|COLD keys", dbgtoggle, 0);
530 	debugkey('?', "help", dbghelp, 0);
531 }
532 
533 /*
534  *  Called by a uart interrupt for console input.
535  *
536  *  turn '\r' into '\n' before putting it into the queue.
537  */
538 int
539 kbdcr2nl(Queue *q, int ch)
540 {
541 	if(ch == '\r')
542 		ch = '\n';
543 	return kbdputc(q, ch);
544 }
545 
546 /*
547  *  Put character, possibly a rune, into read queue at interrupt time.
548  *  Performs translation for compose sequences
549  *  Called at interrupt time to process a character.
550  */
551 int
552 kbdputc(Queue *q, int ch)
553 {
554 	int n;
555 	char buf[3];
556 	Rune r;
557 	static Rune kc[15];
558 	static int nk, collecting = 0;
559 
560 	r = ch;
561 	if(r == Latin) {
562 		collecting = 1;
563 		nk = 0;
564 		return 0;
565 	}
566 	if(collecting) {
567 		int c;
568 		nk += runetochar((char*)&kc[nk], &r);
569 		c = latin1(kc, nk);
570 		if(c < -1)	/* need more keystrokes */
571 			return 0;
572 		collecting = 0;
573 		if(c == -1) {	/* invalid sequence */
574 			echo(kc[0], (char*)kc, nk);
575 			qproduce(q, kc, nk);
576 			return 0;
577 		}
578 		r = (Rune)c;
579 	}
580 	kbd.c = r;
581 	n = runetochar(buf, &r);
582 	if(n == 0)
583 		return 0;
584 	if(!isdbgkey(r)) {
585 		echo(r, buf, n);
586 		qproduce(q, buf, n);
587 	}
588 	return 0;
589 }
590 
591 void
592 kbdrepeat(int rep)
593 {
594 	kbd.repeat = rep;
595 	kbd.count = 0;
596 }
597 
598 void
599 kbdclock(void)
600 {
601 	if(kbd.repeat == 0)
602 		return;
603 	if(kbd.repeat==1 && ++kbd.count>HZ){
604 		kbd.repeat = 2;
605 		kbd.count = 0;
606 		return;
607 	}
608 	if(++kbd.count&1)
609 		kbdputc(kbdq, kbd.c);
610 }
611 
612 enum{
613 	Qdir,
614 	Qcons,
615 	Qsysctl,
616 	Qconsctl,
617 	Qdrivers,
618 	Qhostowner,
619 	Qkeyboard,
620 	Qklog,
621 	Qkprint,
622 	Qscancode,
623 	Qmemory,
624 	Qmsec,
625 	Qnull,
626 	Qpin,
627 	Qrandom,
628 	Qnotquiterandom,
629 	Qsysname,
630 	Qtime,
631 	Quser,
632 	Qjit,
633 };
634 
635 static Dirtab consdir[]=
636 {
637 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
638 	"cons",		{Qcons},	0,		0660,
639 	"consctl",	{Qconsctl},	0,		0220,
640 	"sysctl",	{Qsysctl},	0,		0644,
641 	"drivers",	{Qdrivers},	0,		0444,
642 	"hostowner",	{Qhostowner},	0,	0644,
643 	"keyboard",	{Qkeyboard},	0,		0666,
644 	"klog",		{Qklog},	0,		0444,
645 	"kprint",		{Qkprint},	0,		0444,
646 	"scancode",	{Qscancode},	0,		0444,
647 	"memory",	{Qmemory},	0,		0444,
648 	"msec",		{Qmsec},	NUMSIZE,	0444,
649 	"null",		{Qnull},	0,		0666,
650 	"pin",		{Qpin},		0,		0666,
651 	"random",	{Qrandom},	0,		0444,
652 	"notquiterandom", {Qnotquiterandom}, 0,	0444,
653 	"sysname",	{Qsysname},	0,		0664,
654 	"time",		{Qtime},	0,		0664,
655 	"user",		{Quser},	0,	0644,
656 	"jit",		{Qjit},	0,	0666,
657 };
658 
659 ulong	boottime;		/* seconds since epoch at boot */
660 
661 long
662 seconds(void)
663 {
664 	return boottime + TK2SEC(MACHP(0)->ticks);
665 }
666 
667 vlong
668 mseconds(void)
669 {
670 	return ((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)));
671 }
672 
673 vlong
674 osusectime(void)
675 {
676 	return (((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)))*1000);
677 }
678 
679 vlong
680 nsec(void)
681 {
682 	return osusectime()*1000;	/* TO DO */
683 }
684 
685 int
686 readnum(ulong off, char *buf, ulong n, ulong val, int size)
687 {
688 	char tmp[64];
689 
690 	if(size > 64) size = 64;
691 
692 	snprint(tmp, sizeof(tmp), "%*.0lud ", size, val);
693 	if(off >= size)
694 		return 0;
695 	if(off+n > size)
696 		n = size-off;
697 	memmove(buf, tmp+off, n);
698 	return n;
699 }
700 
701 int
702 readstr(ulong off, char *buf, ulong n, char *str)
703 {
704 	int size;
705 
706 	size = strlen(str);
707 	if(off >= size)
708 		return 0;
709 	if(off+n > size)
710 		n = size-off;
711 	memmove(buf, str+off, n);
712 	return n;
713 }
714 
715 void
716 fddump()
717 {
718 	Proc *p;
719 	Osenv *o;
720 	int i;
721 	Chan *c;
722 
723 	p = proctab(6);
724 	o = p->env;
725 	for(i = 0; i <= o->fgrp->maxfd; i++) {
726 		if((c = o->fgrp->fd[i]) == nil)
727 			continue;
728 		print("%d: %s\n", i, c->name == nil? "???": c->name->s);
729 	}
730 }
731 
732 static void
733 qpanic(Rune)
734 {
735 	panic("User requested panic.");
736 }
737 
738 static void
739 rexit(Rune)
740 {
741 	exit(0);
742 }
743 
744 static void
745 consinit(void)
746 {
747 	randominit();
748 	debuginit();
749 	debugkey('f', "files/6", fddump, 0);
750 	debugkey('q', "panic", qpanic, 1);
751 	debugkey('r', "exit", rexit, 1);
752 	klogq = qopen(128*1024, 0, 0, 0);
753 }
754 
755 static Chan*
756 consattach(char *spec)
757 {
758 	return devattach('c', spec);
759 }
760 
761 static Walkqid*
762 conswalk(Chan *c, Chan *nc, char **name, int nname)
763 {
764 	return devwalk(c, nc, name, nname, consdir, nelem(consdir), devgen);
765 }
766 
767 static int
768 consstat(Chan *c, uchar *dp, int n)
769 {
770 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
771 }
772 
773 static void
774 flushkbdline(Queue *q)
775 {
776 	if(kbd.x){
777 		qwrite(q, kbd.line, kbd.x);
778 		kbd.x = 0;
779 	}
780 }
781 
782 static Chan*
783 consopen(Chan *c, int omode)
784 {
785 	c->aux = 0;
786 	switch((ulong)c->qid.path){
787 	case Qconsctl:
788 		if(!iseve())
789 			error(Eperm);
790 		qlock(&kbd);
791 		kbd.ctl++;
792 		qunlock(&kbd);
793 		break;
794 
795 	case Qkeyboard:
796 		if((omode & 3) != OWRITE) {
797 			qlock(&kbd);
798 			kbd.kbdr++;
799 			flushkbdline(kbdq);
800 			kbd.raw = 1;
801 			qunlock(&kbd);
802 		}
803 		break;
804 
805 	case Qscancode:
806 		qlock(&kbd);
807 		if(kscanq || !kscanid) {
808 			qunlock(&kbd);
809 			c->flag &= ~COPEN;
810 			if(kscanq)
811 				error(Einuse);
812 			else
813 				error(Ebadarg);
814 		}
815 		kscanq = qopen(256, 0, nil, nil);
816 		qunlock(&kbd);
817 		break;
818 
819 	case Qkprint:
820 		if((omode & 3) != OWRITE) {
821 			wlock(&kprintq);
822 			if(kprintq.q != nil){
823 				wunlock(&kprintq);
824 				error(Einuse);
825 			}
826 			kprintq.q = qopen(32*1024, Qcoalesce, nil, nil);
827 			if(kprintq.q == nil){
828 				wunlock(&kprintq);
829 				error(Enomem);
830 			}
831 			qnoblock(kprintq.q, 1);
832 			wunlock(&kprintq);
833 			c->iounit = qiomaxatomic;
834 		}
835 		break;
836 	}
837 	return devopen(c, omode, consdir, nelem(consdir), devgen);
838 }
839 
840 static void
841 consclose(Chan *c)
842 {
843 	if((c->flag&COPEN) == 0)
844 		return;
845 
846 	switch((ulong)c->qid.path){
847 	case Qconsctl:
848 		/* last close of control file turns off raw */
849 		qlock(&kbd);
850 		if(--kbd.ctl == 0)
851 			kbd.raw = 0;
852 		qunlock(&kbd);
853 		break;
854 
855 	case Qkeyboard:
856 		if(c->mode != OWRITE) {
857 			qlock(&kbd);
858 			--kbd.kbdr;
859 			qunlock(&kbd);
860 		}
861 		break;
862 
863 	case Qscancode:
864 		qlock(&kbd);
865 		if(kscanq) {
866 			qfree(kscanq);
867 			kscanq = 0;
868 		}
869 		qunlock(&kbd);
870 		break;
871 
872 	case Qkprint:
873 		wlock(&kprintq);
874 		qfree(kprintq.q);
875 		kprintq.q = nil;
876 		wunlock(&kprintq);
877 		break;
878 	}
879 }
880 
881 static long
882 consread(Chan *c, void *buf, long n, vlong offset)
883 {
884 	int l;
885 	Osenv *o;
886 	int ch, eol, i;
887 	char *p, tmp[128];
888 	char *cbuf = buf;
889 
890 	if(n <= 0)
891 		return n;
892 	o = up->env;
893 	switch((ulong)c->qid.path){
894 	case Qdir:
895 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
896 	case Qsysctl:
897 		return readstr(offset, buf, n, VERSION);
898 	case Qcons:
899 	case Qkeyboard:
900 		qlock(&kbd);
901 		if(waserror()) {
902 			qunlock(&kbd);
903 			nexterror();
904 		}
905 		if(kbd.raw || kbd.kbdr) {
906 			if(qcanread(lineq))
907 				n = qread(lineq, buf, n);
908 			else {
909 				/* read as much as possible */
910 				do {
911 					i = qread(kbdq, cbuf, n);
912 					cbuf += i;
913 					n -= i;
914 				} while(n>0 && qcanread(kbdq));
915 				n = cbuf - (char*)buf;
916 			}
917 		} else {
918 			while(!qcanread(lineq)) {
919 				qread(kbdq, &kbd.line[kbd.x], 1);
920 				ch = kbd.line[kbd.x];
921 				eol = 0;
922 				switch(ch){
923 				case '\b':
924 					if(kbd.x)
925 						kbd.x--;
926 					break;
927 				case 0x15:
928 					kbd.x = 0;
929 					break;
930 				case '\n':
931 				case 0x04:
932 					eol = 1;
933 				default:
934 					kbd.line[kbd.x++] = ch;
935 					break;
936 				}
937 				if(kbd.x == sizeof(kbd.line) || eol) {
938 					if(ch == 0x04)
939 						kbd.x--;
940 					qwrite(lineq, kbd.line, kbd.x);
941 					kbd.x = 0;
942 				}
943 			}
944 			n = qread(lineq, buf, n);
945 		}
946 		qunlock(&kbd);
947 		poperror();
948 		return n;
949 
950 	case Qscancode:
951 		if(offset == 0)
952 			return readstr(0, buf, n, kscanid);
953 		else
954 			return qread(kscanq, buf, n);
955 
956 	case Qpin:
957 		p = "pin set";
958 		if(up->env->pgrp->pin == Nopin)
959 			p = "no pin";
960 		return readstr(offset, buf, n, p);
961 
962 	case Qtime:
963 		snprint(tmp, sizeof(tmp), "%.lld", (vlong)mseconds()*1000);
964 		return readstr(offset, buf, n, tmp);
965 
966 	case Qhostowner:
967 		return readstr(offset, buf, n, eve);
968 
969 	case Quser:
970 		return readstr(offset, buf, n, o->user);
971 
972 	case Qjit:
973 		snprint(tmp, sizeof(tmp), "%d", cflag);
974 		return readstr(offset, buf, n, tmp);
975 
976 	case Qnull:
977 		return 0;
978 
979 	case Qmsec:
980 		return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
981 
982 	case Qsysname:
983 		if(sysname == nil)
984 			return 0;
985 		return readstr(offset, buf, n, sysname);
986 
987 	case Qnotquiterandom:
988 		genrandom(buf, n);
989 		return n;
990 
991 	case Qrandom:
992 		return randomread(buf, n);
993 
994 	case Qmemory:
995 		return poolread(buf, n, offset);
996 
997 	case Qdrivers:
998 		p = malloc(READSTR);
999 		if(p == nil)
1000 			error(Enomem);
1001 		l = 0;
1002 		for(i = 0; devtab[i] != nil; i++)
1003 			l += snprint(p+l, READSTR-l, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
1004 		if(waserror()){
1005 			free(p);
1006 			nexterror();
1007 		}
1008 		n = readstr(offset, buf, n, p);
1009 		free(p);
1010 		poperror();
1011 		return n;
1012 
1013 	case Qklog:
1014 		return qread(klogq, buf, n);
1015 
1016 	case Qkprint:
1017 		rlock(&kprintq);
1018 		if(waserror()){
1019 			runlock(&kprintq);
1020 			nexterror();
1021 		}
1022 		n = qread(kprintq.q, buf, n);
1023 		poperror();
1024 		runlock(&kprintq);
1025 		return n;
1026 
1027 	default:
1028 		print("consread %llud\n", c->qid.path);
1029 		error(Egreg);
1030 	}
1031 	return -1;		/* never reached */
1032 }
1033 
1034 static long
1035 conswrite(Chan *c, void *va, long n, vlong offset)
1036 {
1037 	vlong t;
1038 	long l, bp;
1039 	char *a = va;
1040 	Cmdbuf *cb;
1041 	Cmdtab *ct;
1042 	char buf[256];
1043 	int x;
1044 
1045 	switch((ulong)c->qid.path){
1046 	case Qcons:
1047 		/*
1048 		 * Can't page fault in putstrn, so copy the data locally.
1049 		 */
1050 		l = n;
1051 		while(l > 0){
1052 			bp = l;
1053 			if(bp > sizeof buf)
1054 				bp = sizeof buf;
1055 			memmove(buf, a, bp);
1056 			putstrn0(a, bp, 1);
1057 			a += bp;
1058 			l -= bp;
1059 		}
1060 		break;
1061 
1062 	case Qconsctl:
1063 		if(n >= sizeof(buf))
1064 			n = sizeof(buf)-1;
1065 		strncpy(buf, a, n);
1066 		buf[n] = 0;
1067 		for(a = buf; a;){
1068 			if(strncmp(a, "rawon", 5) == 0){
1069 				qlock(&kbd);
1070 				flushkbdline(kbdq);
1071 				kbd.raw = 1;
1072 				qunlock(&kbd);
1073 			} else if(strncmp(a, "rawoff", 6) == 0){
1074 				qlock(&kbd);
1075 				kbd.raw = 0;
1076 				kbd.x = 0;
1077 				qunlock(&kbd);
1078 			}
1079 			if(a = strchr(a, ' '))
1080 				a++;
1081 		}
1082 		break;
1083 
1084 	case Qkeyboard:
1085 		for(x=0; x<n; ) {
1086 			Rune r;
1087 			x += chartorune(&r, &a[x]);
1088 			kbdputc(kbdq, r);
1089 		}
1090 		break;
1091 
1092 	case Qtime:
1093 		if(n >= sizeof(buf))
1094 			n = sizeof(buf)-1;
1095 		strncpy(buf, a, n);
1096 		buf[n] = 0;
1097 		t = strtoll(buf, 0, 0)/1000000;
1098 		boottime = t - TK2SEC(MACHP(0)->ticks);
1099 		break;
1100 
1101 	case Qhostowner:
1102 		if(!iseve())
1103 			error(Eperm);
1104 		if(offset != 0 || n >= sizeof(buf))
1105 			error(Ebadarg);
1106 		memmove(buf, a, n);
1107 		buf[n] = '\0';
1108 		if(n > 0 && buf[n-1] == '\n')
1109 			buf[--n] = 0;
1110 		if(n <= 0)
1111 			error(Ebadarg);
1112 		renameuser(eve, buf);
1113 		renameproguser(eve, buf);
1114 		kstrdup(&eve, buf);
1115 		kstrdup(&up->env->user, buf);
1116 		break;
1117 
1118 	case Quser:
1119 		if(!iseve())
1120 			error(Eperm);
1121 		if(offset != 0)
1122 			error(Ebadarg);
1123 		if(n <= 0 || n >= sizeof(buf))
1124 			error(Ebadarg);
1125 		strncpy(buf, a, n);
1126 		buf[n] = 0;
1127 		if(buf[n-1] == '\n')
1128 			buf[n-1] = 0;
1129 		kstrdup(&up->env->user, buf);
1130 		break;
1131 
1132 	case Qjit:
1133 		if(n >= sizeof(buf))
1134 			n = sizeof(buf)-1;
1135 		strncpy(buf, va, n);
1136 		buf[n] = '\0';
1137 		x = atoi(buf);
1138 		if(x < 0 || x > 9)
1139 			error(Ebadarg);
1140 		cflag = x;
1141 		return n;
1142 
1143 	case Qnull:
1144 		break;
1145 
1146 	case Qpin:
1147 		if(up->env->pgrp->pin != Nopin)
1148 			error("pin already set");
1149 		if(n >= sizeof(buf))
1150 			n = sizeof(buf)-1;
1151 		strncpy(buf, va, n);
1152 		buf[n] = '\0';
1153 		up->env->pgrp->pin = atoi(buf);
1154 		return n;
1155 
1156 	case Qsysname:
1157 		if(offset != 0)
1158 			error(Ebadarg);
1159 		if(n <= 0 || n >= sizeof(buf))
1160 			error(Ebadarg);
1161 		strncpy(buf, a, n);
1162 		buf[n] = 0;
1163 		if(buf[n-1] == '\n')
1164 			buf[n-1] = 0;
1165 		kstrdup(&sysname, buf);
1166 		break;
1167 
1168 	case Qsysctl:
1169 		if(!iseve())
1170 			error(Eperm);
1171 		cb = parsecmd(a, n);
1172 		if(waserror()){
1173 			free(cb);
1174 			nexterror();
1175 		}
1176 		ct = lookupcmd(cb, sysctlcmd, nelem(sysctlcmd));
1177 		switch(ct->index){
1178 		case CMreboot:
1179 			reboot();
1180 			break;
1181 		case CMhalt:
1182 			halt();
1183 			break;
1184 		case CMpanic:
1185 			panic("sysctl");
1186 		case CMconsole:
1187 			consoleprint = strcmp(cb->f[1], "off") != 0;
1188 			break;
1189 		case CMbroken:
1190 			keepbroken = 1;
1191 			break;
1192 		case CMnobroken:
1193 			keepbroken = 0;
1194 			break;
1195 		}
1196 		poperror();
1197 		free(cb);
1198 		break;
1199 
1200 	default:
1201 		print("conswrite: %llud\n", c->qid.path);
1202 		error(Egreg);
1203 	}
1204 	return n;
1205 }
1206 
1207 Dev consdevtab = {
1208 	'c',
1209 	"cons",
1210 
1211 	devreset,
1212 	consinit,
1213 	devshutdown,
1214 	consattach,
1215 	conswalk,
1216 	consstat,
1217 	consopen,
1218 	devcreate,
1219 	consclose,
1220 	consread,
1221 	devbread,
1222 	conswrite,
1223 	devbwrite,
1224 	devremove,
1225 	devwstat,
1226 };
1227 
1228 static	ulong	randn;
1229 
1230 static void
1231 seedrand(void)
1232 {
1233 	randomread((void*)&randn, sizeof(randn));
1234 }
1235 
1236 int
1237 nrand(int n)
1238 {
1239 	if(randn == 0)
1240 		seedrand();
1241 	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
1242 	return (randn>>16) % n;
1243 }
1244 
1245 int
1246 rand(void)
1247 {
1248 	nrand(1);
1249 	return randn;
1250 }
1251 
1252 ulong
1253 truerand(void)
1254 {
1255 	ulong x;
1256 
1257 	randomread(&x, sizeof(x));
1258 	return x;
1259 }
1260 
1261 QLock grandomlk;
1262 
1263 void
1264 _genrandomqlock(void)
1265 {
1266 	qlock(&grandomlk);
1267 }
1268 
1269 
1270 void
1271 _genrandomqunlock(void)
1272 {
1273 	qunlock(&grandomlk);
1274 }
1275