xref: /plan9-contrib/sys/src/cmd/unix/drawterm/kern/devcons.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
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) = nil;
10 void	(*screenputs)(char*, int) = nil;
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, nil, 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 == nil)
336 				consdebug = rdb;
337 			else
338 				consdebug = nil;
339 			print("consdebug now 0x%p\n", consdebug);
340 			return;
341 		case 'D':
342 			if(consdebug == nil)
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 != nil)
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 	Qsnarf,
468 	Qswap,
469 	Qsysname,
470 	Qsysstat,
471 	Qtime,
472 	Quser,
473 	Qzero,
474 };
475 
476 enum
477 {
478 	VLNUMSIZE=	22,
479 };
480 
481 static Dirtab consdir[]={
482 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
483 	"bintime",	{Qbintime},	24,		0664,
484 	"cons",		{Qcons},	0,		0660,
485 	"consctl",	{Qconsctl},	0,		0220,
486 	"cpunote",	{Qcpunote},	0,		0444,
487 	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
488 	"drivers",	{Qdrivers},	0,		0444,
489 	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,
490 	"hostowner",	{Qhostowner},	0,	0664,
491 	"kprint",		{Qkprint, 0, QTEXCL},	0,	DMEXCL|0440,
492 	"null",		{Qnull},	0,		0666,
493 	"osversion",	{Qosversion},	0,		0444,
494 	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,
495 	"pid",		{Qpid},		NUMSIZE,	0444,
496 	"ppid",		{Qppid},	NUMSIZE,	0444,
497 	"random",	{Qrandom},	0,		0444,
498 	"reboot",	{Qreboot},	0,		0664,
499 	"secstore",	{Qsecstore},	0,		0666,
500 	"snarf",	{Qsnarf},		0,		0666,
501 	"swap",		{Qswap},	0,		0664,
502 	"sysname",	{Qsysname},	0,		0664,
503 	"sysstat",	{Qsysstat},	0,		0666,
504 	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664,
505 	"user",		{Quser},	0,	0666,
506 	"zero",		{Qzero},	0,		0444,
507 };
508 
509 char secstorebuf[65536];
510 Dirtab *secstoretab = &consdir[Qsecstore];
511 Dirtab *snarftab = &consdir[Qsnarf];
512 
513 int
514 readnum(ulong off, char *buf, ulong n, ulong val, int size)
515 {
516 	char tmp[64];
517 
518 	snprint(tmp, sizeof(tmp), "%*.0lud", size-1, val);
519 	tmp[size-1] = ' ';
520 	if(off >= size)
521 		return 0;
522 	if(off+n > size)
523 		n = size-off;
524 	memmove(buf, tmp+off, n);
525 	return n;
526 }
527 
528 int
529 readstr(ulong off, char *buf, ulong n, char *str)
530 {
531 	int size;
532 
533 	size = strlen(str);
534 	if(off >= size)
535 		return 0;
536 	if(off+n > size)
537 		n = size-off;
538 	memmove(buf, str+off, n);
539 	return n;
540 }
541 
542 static void
543 consinit(void)
544 {
545 	todinit();
546 	randominit();
547 	/*
548 	 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
549 	 * processing it every 22 ms should be fine
550 	 */
551 /*	addclock0link(kbdputcclock, 22); */
552 }
553 
554 static Chan*
555 consattach(char *spec)
556 {
557 	return devattach('c', spec);
558 }
559 
560 static Walkqid*
561 conswalk(Chan *c, Chan *nc, char **name, int nname)
562 {
563 	return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
564 }
565 
566 static int
567 consstat(Chan *c, uchar *dp, int n)
568 {
569 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
570 }
571 
572 static Chan*
573 consopen(Chan *c, int omode)
574 {
575 	c->aux = nil;
576 	c = devopen(c, omode, consdir, nelem(consdir), devgen);
577 	switch((ulong)c->qid.path){
578 	case Qconsctl:
579 		qlock(&kbd.lk);
580 		kbd.ctl++;
581 		qunlock(&kbd.lk);
582 		break;
583 
584 	case Qkprint:
585 		if(tas(&kprintinuse) != 0){
586 			c->flag &= ~COPEN;
587 			error(Einuse);
588 		}
589 		if(kprintoq == nil){
590 			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
591 			if(kprintoq == nil){
592 				c->flag &= ~COPEN;
593 				error(Enomem);
594 			}
595 			qnoblock(kprintoq, 1);
596 		}else
597 			qreopen(kprintoq);
598 		c->iounit = qiomaxatomic;
599 		break;
600 
601 	case Qsecstore:
602 		if(omode == ORDWR)
603 			error(Eperm);
604 		if(omode != OREAD)
605 			memset(secstorebuf, 0, sizeof secstorebuf);
606 		break;
607 
608 	case Qsnarf:
609 		if(omode == ORDWR)
610 			error(Eperm);
611 		if(omode == OREAD)
612 			c->aux = strdup("");
613 		else
614 			c->aux = mallocz(SnarfSize, 1);
615 		break;
616 	}
617 	return c;
618 }
619 
620 static void
621 consclose(Chan *c)
622 {
623 	switch((ulong)c->qid.path){
624 	/* last close of control file turns off raw */
625 	case Qconsctl:
626 		if(c->flag&COPEN){
627 			qlock(&kbd.lk);
628 			if(--kbd.ctl == 0)
629 				kbd.raw = 0;
630 			qunlock(&kbd.lk);
631 		}
632 		break;
633 
634 	/* close of kprint allows other opens */
635 	case Qkprint:
636 		if(c->flag & COPEN){
637 			kprintinuse = 0;
638 			qhangup(kprintoq, nil);
639 		}
640 		break;
641 
642 	case Qsnarf:
643 		if(c->mode == OWRITE)
644 			clipwrite(c->aux);
645 		free(c->aux);
646 		break;
647 	}
648 }
649 
650 static long
651 consread(Chan *c, void *buf, long n, vlong off)
652 {
653 	char *b;
654 	char tmp[128];		/* must be >= 6*NUMSIZE */
655 	char *cbuf = buf;
656 	int ch, i, eol;
657 	vlong offset = off;
658 
659 	if(n <= 0)
660 		return n;
661 	switch((ulong)c->qid.path){
662 	case Qdir:
663 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
664 
665 	case Qcons:
666 		qlock(&kbd.lk);
667 		if(waserror()) {
668 			qunlock(&kbd.lk);
669 			nexterror();
670 		}
671 		if(kbd.raw) {
672 			if(qcanread(lineq))
673 				n = qread(lineq, buf, n);
674 			else {
675 				/* read as much as possible */
676 				do {
677 					i = qread(kbdq, cbuf, n);
678 					cbuf += i;
679 					n -= i;
680 				} while (n>0 && qcanread(kbdq));
681 				n = cbuf - (char*)buf;
682 			}
683 		} else {
684 			while(!qcanread(lineq)) {
685 				qread(kbdq, &kbd.line[kbd.x], 1);
686 				ch = kbd.line[kbd.x];
687 				eol = 0;
688 				switch(ch){
689 				case '\b':
690 					if(kbd.x)
691 						kbd.x--;
692 					break;
693 				case 0x15:
694 					kbd.x = 0;
695 					break;
696 				case '\n':
697 				case 0x04:
698 					eol = 1;
699 				default:
700 					kbd.line[kbd.x++] = ch;
701 					break;
702 				}
703 				if(kbd.x == sizeof(kbd.line) || eol){
704 					if(ch == 0x04)
705 						kbd.x--;
706 					qwrite(lineq, kbd.line, kbd.x);
707 					kbd.x = 0;
708 				}
709 			}
710 			n = qread(lineq, buf, n);
711 		}
712 		qunlock(&kbd.lk);
713 		poperror();
714 		return n;
715 
716 	case Qcpunote:
717 		sleep(&up->sleep, return0, nil);
718 
719 	case Qcputime:
720 		return 0;
721 
722 	case Qkprint:
723 		return qread(kprintoq, buf, n);
724 
725 	case Qpgrpid:
726 		return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
727 
728 	case Qpid:
729 		return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
730 
731 	case Qppid:
732 		return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
733 
734 	case Qtime:
735 		return readtime((ulong)offset, buf, n);
736 
737 	case Qbintime:
738 		return readbintime(buf, n);
739 
740 	case Qhostowner:
741 		return readstr((ulong)offset, buf, n, eve);
742 
743 	case Qhostdomain:
744 		return readstr((ulong)offset, buf, n, hostdomain);
745 
746 	case Quser:
747 		return readstr((ulong)offset, buf, n, up->user);
748 
749 	case Qnull:
750 		return 0;
751 
752 	case Qsnarf:
753 		if(offset == 0){
754 			free(c->aux);
755 			c->aux = clipread();
756 		}
757 		if(c->aux == nil)
758 			return 0;
759 		return readstr(offset, buf, n, c->aux);
760 
761 	case Qsecstore:
762 		return readstr(offset, buf, n, secstorebuf);
763 
764 	case Qsysstat:
765 		return 0;
766 
767 	case Qswap:
768 		return 0;
769 
770 	case Qsysname:
771 		if(sysname == nil)
772 			return 0;
773 		return readstr((ulong)offset, buf, n, sysname);
774 
775 	case Qrandom:
776 		return randomread(buf, n);
777 
778 	case Qdrivers:
779 		b = malloc(READSTR);
780 		if(b == nil)
781 			error(Enomem);
782 		n = 0;
783 		for(i = 0; devtab[i] != nil; i++)
784 			n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
785 		if(waserror()){
786 			free(b);
787 			nexterror();
788 		}
789 		n = readstr((ulong)offset, buf, n, b);
790 		free(b);
791 		poperror();
792 		return n;
793 
794 	case Qzero:
795 		memset(buf, 0, n);
796 		return n;
797 
798 	case Qosversion:
799 		snprint(tmp, sizeof tmp, "2000");
800 		n = readstr((ulong)offset, buf, n, tmp);
801 		return n;
802 
803 	default:
804 		print("consread 0x%llux\n", c->qid.path);
805 		error(Egreg);
806 	}
807 	return -1;		/* never reached */
808 }
809 
810 static long
811 conswrite(Chan *c, void *va, long n, vlong off)
812 {
813 	char buf[256];
814 	long l, bp;
815 	char *a = va;
816 	int fd;
817 	Chan *swc;
818 	ulong offset = off;
819 	Cmdbuf *cb;
820 	Cmdtab *ct;
821 
822 	switch((ulong)c->qid.path){
823 	case Qcons:
824 		/*
825 		 * Can't page fault in putstrn, so copy the data locally.
826 		 */
827 		l = n;
828 		while(l > 0){
829 			bp = l;
830 			if(bp > sizeof buf)
831 				bp = sizeof buf;
832 			memmove(buf, a, bp);
833 			putstrn0(buf, bp, 1);
834 			a += bp;
835 			l -= bp;
836 		}
837 		break;
838 
839 	case Qconsctl:
840 		if(n >= sizeof(buf))
841 			n = sizeof(buf)-1;
842 		strncpy(buf, a, n);
843 		buf[n] = 0;
844 		for(a = buf; a;){
845 			if(strncmp(a, "rawon", 5) == 0){
846 				qlock(&kbd.lk);
847 				if(kbd.x){
848 					qwrite(kbdq, kbd.line, kbd.x);
849 					kbd.x = 0;
850 				}
851 				kbd.raw = 1;
852 				qunlock(&kbd.lk);
853 			} else if(strncmp(a, "rawoff", 6) == 0){
854 				qlock(&kbd.lk);
855 				kbd.raw = 0;
856 				kbd.x = 0;
857 				qunlock(&kbd.lk);
858 			} else if(strncmp(a, "ctlpon", 6) == 0){
859 				kbd.ctlpoff = 0;
860 			} else if(strncmp(a, "ctlpoff", 7) == 0){
861 				kbd.ctlpoff = 1;
862 			}
863 			if((a = strchr(a, ' ')))
864 				a++;
865 		}
866 		break;
867 
868 	case Qtime:
869 		if(!iseve())
870 			error(Eperm);
871 		return writetime(a, n);
872 
873 	case Qbintime:
874 		if(!iseve())
875 			error(Eperm);
876 		return writebintime(a, n);
877 
878 	case Qhostowner:
879 		return hostownerwrite(a, n);
880 
881 	case Qhostdomain:
882 		return hostdomainwrite(a, n);
883 
884 	case Quser:
885 		return userwrite(a, n);
886 
887 	case Qnull:
888 		break;
889 
890 	case Qreboot:
891 		if(!iseve())
892 			error(Eperm);
893 		cb = parsecmd(a, n);
894 
895 		if(waserror()) {
896 			free(cb);
897 			nexterror();
898 		}
899 		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
900 		switch(ct->index) {
901 		case CMreboot:
902 			rebootcmd(cb->nf-1, cb->f+1);
903 			break;
904 		case CMpanic:
905 			panic("/dev/reboot");
906 		}
907 		poperror();
908 		free(cb);
909 		break;
910 
911 	case Qsecstore:
912 		if(offset >= sizeof secstorebuf || offset+n+1 >= sizeof secstorebuf)
913 			error(Etoobig);
914 		secstoretab->qid.vers++;
915 		memmove(secstorebuf+offset, va, n);
916 		return n;
917 
918 	case Qsnarf:
919 		if(offset >= SnarfSize || offset+n >= SnarfSize)
920 			error(Etoobig);
921 		snarftab->qid.vers++;
922 		memmove((uchar*)c->aux+offset, va, n);
923 		return n;
924 
925 	case Qsysstat:
926 		n = 0;
927 		break;
928 
929 	case Qswap:
930 		if(n >= sizeof buf)
931 			error(Egreg);
932 		memmove(buf, va, n);	/* so we can NUL-terminate */
933 		buf[n] = 0;
934 		/* start a pager if not already started */
935 		if(strncmp(buf, "start", 5) == 0){
936 			kickpager();
937 			break;
938 		}
939 		if(cpuserver && !iseve())
940 			error(Eperm);
941 		if(buf[0]<'0' || '9'<buf[0])
942 			error(Ebadarg);
943 		fd = strtoul(buf, 0, 0);
944 		swc = fdtochan(fd, -1, 1, 1);
945 		setswapchan(swc);
946 		break;
947 
948 	case Qsysname:
949 		if(offset != 0)
950 			error(Ebadarg);
951 		if(n <= 0 || n >= sizeof buf)
952 			error(Ebadarg);
953 		strncpy(buf, a, n);
954 		buf[n] = 0;
955 		if(buf[n-1] == '\n')
956 			buf[n-1] = 0;
957 		kstrdup(&sysname, buf);
958 		break;
959 
960 	default:
961 		print("conswrite: 0x%llux\n", c->qid.path);
962 		error(Egreg);
963 	}
964 	return n;
965 }
966 
967 Dev consdevtab = {
968 	'c',
969 	"cons",
970 
971 	devreset,
972 	consinit,
973 	devshutdown,
974 	consattach,
975 	conswalk,
976 	consstat,
977 	consopen,
978 	devcreate,
979 	consclose,
980 	consread,
981 	devbread,
982 	conswrite,
983 	devbwrite,
984 	devremove,
985 	devwstat,
986 };
987 
988 static uvlong uvorder = (uvlong) 0x0001020304050607ULL;
989 
990 static uchar*
991 le2vlong(vlong *to, uchar *f)
992 {
993 	uchar *t, *o;
994 	int i;
995 
996 	t = (uchar*)to;
997 	o = (uchar*)&uvorder;
998 	for(i = 0; i < sizeof(vlong); i++)
999 		t[o[i]] = f[i];
1000 	return f+sizeof(vlong);
1001 }
1002 
1003 static uchar*
1004 vlong2le(uchar *t, vlong from)
1005 {
1006 	uchar *f, *o;
1007 	int i;
1008 
1009 	f = (uchar*)&from;
1010 	o = (uchar*)&uvorder;
1011 	for(i = 0; i < sizeof(vlong); i++)
1012 		t[i] = f[o[i]];
1013 	return t+sizeof(vlong);
1014 }
1015 
1016 static long order = 0x00010203;
1017 
1018 static uchar*
1019 le2long(long *to, uchar *f)
1020 {
1021 	uchar *t, *o;
1022 	int i;
1023 
1024 	t = (uchar*)to;
1025 	o = (uchar*)&order;
1026 	for(i = 0; i < sizeof(long); i++)
1027 		t[o[i]] = f[i];
1028 	return f+sizeof(long);
1029 }
1030 
1031 /*
1032 static uchar*
1033 long2le(uchar *t, long from)
1034 {
1035 	uchar *f, *o;
1036 	int i;
1037 
1038 	f = (uchar*)&from;
1039 	o = (uchar*)&order;
1040 	for(i = 0; i < sizeof(long); i++)
1041 		t[i] = f[o[i]];
1042 	return t+sizeof(long);
1043 }
1044 */
1045 
1046 char *Ebadtimectl = "bad time control";
1047 
1048 /*
1049  *  like the old #c/time but with added info.  Return
1050  *
1051  *	secs	nanosecs	fastticks	fasthz
1052  */
1053 static int
1054 readtime(ulong off, char *buf, int n)
1055 {
1056 	vlong	nsec, ticks;
1057 	long sec;
1058 	char str[7*NUMSIZE];
1059 
1060 	nsec = todget(&ticks);
1061 	if(fasthz == (vlong)0)
1062 		fastticks((uvlong*)&fasthz);
1063 	sec = nsec/((uvlong) 1000000000);
1064 	snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ",
1065 		NUMSIZE-1, sec,
1066 		VLNUMSIZE-1, nsec,
1067 		VLNUMSIZE-1, ticks,
1068 		VLNUMSIZE-1, fasthz);
1069 	return readstr(off, buf, n, str);
1070 }
1071 
1072 /*
1073  *  set the time in seconds
1074  */
1075 static int
1076 writetime(char *buf, int n)
1077 {
1078 	char b[13];
1079 	long i;
1080 	vlong now;
1081 
1082 	if(n >= sizeof(b))
1083 		error(Ebadtimectl);
1084 	strncpy(b, buf, n);
1085 	b[n] = 0;
1086 	i = strtol(b, 0, 0);
1087 	if(i <= 0)
1088 		error(Ebadtimectl);
1089 	now = i*((vlong) 1000000000);
1090 	todset(now, 0, 0);
1091 	return n;
1092 }
1093 
1094 /*
1095  *  read binary time info.  all numbers are little endian.
1096  *  ticks and nsec are syncronized.
1097  */
1098 static int
1099 readbintime(char *buf, int n)
1100 {
1101 	int i;
1102 	vlong nsec, ticks;
1103 	uchar *b = (uchar*)buf;
1104 
1105 	i = 0;
1106 	if(fasthz == (vlong)0)
1107 		fastticks((uvlong*)&fasthz);
1108 	nsec = todget(&ticks);
1109 	if(n >= 3*sizeof(uvlong)){
1110 		vlong2le(b+2*sizeof(uvlong), fasthz);
1111 		i += sizeof(uvlong);
1112 	}
1113 	if(n >= 2*sizeof(uvlong)){
1114 		vlong2le(b+sizeof(uvlong), ticks);
1115 		i += sizeof(uvlong);
1116 	}
1117 	if(n >= 8){
1118 		vlong2le(b, nsec);
1119 		i += sizeof(vlong);
1120 	}
1121 	return i;
1122 }
1123 
1124 /*
1125  *  set any of the following
1126  *	- time in nsec
1127  *	- nsec trim applied over some seconds
1128  *	- clock frequency
1129  */
1130 static int
1131 writebintime(char *buf, int n)
1132 {
1133 	uchar *p;
1134 	vlong delta;
1135 	long period;
1136 
1137 	n--;
1138 	p = (uchar*)buf + 1;
1139 	switch(*buf){
1140 	case 'n':
1141 		if(n < sizeof(vlong))
1142 			error(Ebadtimectl);
1143 		le2vlong(&delta, p);
1144 		todset(delta, 0, 0);
1145 		break;
1146 	case 'd':
1147 		if(n < sizeof(vlong)+sizeof(long))
1148 			error(Ebadtimectl);
1149 		p = le2vlong(&delta, p);
1150 		le2long(&period, p);
1151 		todset(-1, delta, period);
1152 		break;
1153 	case 'f':
1154 		if(n < sizeof(uvlong))
1155 			error(Ebadtimectl);
1156 		le2vlong(&fasthz, p);
1157 		todsetfreq(fasthz);
1158 		break;
1159 	}
1160 	return n;
1161 }
1162 
1163 
1164 int
1165 iprint(char *fmt, ...)
1166 {
1167 	int n, s;
1168 	va_list arg;
1169 	char buf[PRINTSIZE];
1170 
1171 	s = splhi();
1172 	va_start(arg, fmt);
1173 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
1174 	va_end(arg);
1175 	if(screenputs != nil && iprintscreenputs)
1176 		screenputs(buf, n);
1177 #undef write
1178 	write(2, buf, n);
1179 	splx(s);
1180 
1181 	return n;
1182 }
1183 
1184