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