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