xref: /plan9-contrib/sys/src/9/port/devcons.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"io.h"
7 #include	"../port/error.h"
8 
9 #include	"devtab.h"
10 
11 struct {
12 	IOQ;			/* lock to klogputs */
13 	QLock;			/* qlock to getc */
14 }klogq;
15 
16 IOQ	mouseq;
17 IOQ	lineq;			/* lock to getc; interrupt putc's */
18 IOQ	printq;
19 KIOQ	kbdq;
20 
21 static Ref	ctl;		/* number of opens to the control file */
22 static int	raw;		/* true if raw has been requested on ctl file */
23 
24 char	sysname[NAMELEN];
25 
26 /*
27  *  init the queues and set the output routine
28  */
29 void
30 printinit(void)
31 {
32 	initq(&printq);
33 	printq.puts = 0;
34 	initq(&lineq);
35 	initq(&kbdq);
36 	kbdq.putc = kbdputc;
37 	initq(&klogq);
38 	initq(&mouseq);
39 	mouseq.putc = mouseputc;
40 }
41 
42 /*
43  *   Print a string on the console.  Convert \n to \r\n for serial
44  *   line consoles.  Locking of the queues is left up to the screen
45  *   or uart code.  Multi-line messages to serial consoles may get
46  *   interspersed with other messages.
47  */
48 void
49 putstrn(char *str, int n)
50 {
51 	char buf[PRINTSIZE+2];
52 	int m;
53 	char *t;
54 
55 	/*
56 	 *  if there's an attached bit mapped display,
57 	 *  put the message there.  screenputs is defined
58 	 *  as a null macro for systems that have no such
59 	 *  display.
60 	 */
61 	screenputs(str, n);
62 
63 	/*
64 	 *  if there's a serial line being used as a console,
65 	 *  put the message there.  Tack a carriage return
66 	 *  before new lines.
67 	 */
68 	if(printq.puts == 0)
69 		return;
70 
71 	while(n > 0){
72 		t = memchr(str, '\n', n);
73 		if(t){
74 			m = t - str;
75 			memmove(buf, str, m);
76 			buf[m] = '\r';
77 			buf[m+1] = '\n';
78 			(*printq.puts)(&printq, buf, m+2);
79 			str = t + 1;
80 			n -= m + 1;
81 		} else {
82 			(*printq.puts)(&printq, str, n);
83 			break;
84 		}
85 	}
86 }
87 
88 /*
89  *   Print a string in the kernel log.  Ignore overflow.
90  */
91 void
92 klogputs(char *str, long n)
93 {
94 	int s, m;
95 	uchar *nextin;
96 
97 	s = splhi();
98 	lock(&klogq);
99 	while(n){
100 		m = &klogq.buf[NQ] - klogq.in;
101 		if(m > n)
102 			m = n;
103 		memmove(klogq.in, str, m);
104 		n -= m;
105 		str += m;
106 		nextin = klogq.in + m;
107 		if(nextin >= &klogq.buf[NQ])
108 			klogq.in = klogq.buf;
109 		else
110 			klogq.in = nextin;
111 	}
112 	unlock(&klogq);
113 	splx(s);
114 	wakeup(&klogq.r);
115 }
116 
117 int
118 isbrkc(KIOQ *q)
119 {
120 	uchar *p;
121 
122 	for(p=q->out; p!=q->in; ){
123 		if(raw)
124 			return 1;
125 		if(*p==0x04 || *p=='\n')
126 			return 1;
127 		p++;
128 		if(p >= q->buf+sizeof(q->buf))
129 			p = q->buf;
130 	}
131 	return 0;
132 }
133 
134 int
135 sprint(char *s, char *fmt, ...)
136 {
137 	return doprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s;
138 }
139 
140 int
141 snprint(char *s, int n, char *fmt, ...)
142 {
143 	return doprint(s, s+n, fmt, (&fmt+1)) - s;
144 }
145 
146 int
147 print(char *fmt, ...)
148 {
149 	char buf[PRINTSIZE];
150 	int n;
151 
152 	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
153 	putstrn(buf, n);
154 	return n;
155 }
156 
157 int
158 kprint(char *fmt, ...)
159 {
160 	char buf[PRINTSIZE];
161 	int n;
162 
163 	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
164 	klogputs(buf, n);
165 	return n;
166 }
167 
168 void
169 panic(char *fmt, ...)
170 {
171 	char buf[PRINTSIZE];
172 	int n;
173 
174 	strcpy(buf, "panic: ");
175 	n = doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1)) - buf;
176 	buf[n] = '\n';
177 	putstrn(buf, n+1);
178 	dumpstack();
179 	exit(1);
180 }
181 int
182 pprint(char *fmt, ...)
183 {
184 	char buf[2*PRINTSIZE];
185 	Chan *c;
186 	int n;
187 
188 	if(u->p->fgrp == 0)
189 		return 0;
190 
191 	c = u->p->fgrp->fd[2];
192 	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
193 		return 0;
194 	n = sprint(buf, "%s %d: ", u->p->text, u->p->pid);
195 	n = doprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
196 
197 	if(waserror())
198 		return 0;
199 	(*devtab[c->type].write)(c, buf, n, c->offset);
200 	poperror();
201 
202 	lock(c);
203 	c->offset += n;
204 	unlock(c);
205 
206 	return n;
207 }
208 
209 void
210 prflush(void)
211 {
212 	while(printq.in != printq.out) ;
213 }
214 #include <ureg.h>
215 void
216 echo(Rune r, char *buf, int n)
217 {
218 	static int ctrlt;
219 
220 	/*
221 	 * ^p hack
222 	 */
223 	if(r==0x10 && cpuserver)
224 		exit(0);
225 
226 	/*
227 	 * ^t hack BUG
228 	 */
229 	if(ctrlt == 2){
230 		ctrlt = 0;
231 		switch(r){
232 		case 0x14:
233 			break;	/* pass it on */
234 		case 'x':
235 			xsummary();
236 			break;
237 		case 'b':
238 			bitdebug();
239 			break;
240 		case 'd':
241 			consdebug();
242 			return;
243 		case 'p':
244 			procdump();
245 			return;
246 		case 'r':
247 			exit(0);
248 			break;
249 		}
250 	}else if(r == 0x14){
251 		ctrlt++;
252 		return;
253 	}
254 	ctrlt = 0;
255 	if(raw)
256 		return;
257 	if(r == 0x15)
258 		putstrn("^U\n", 3);
259 	else
260 		putstrn(buf, n);
261 }
262 
263 /*
264  *  turn '\r' into '\n' before putting it into the queue
265  */
266 int
267 kbdcr2nl(IOQ *q, int ch)
268 {
269 	if(ch == '\r')
270 		ch = '\n';
271 	return kbdputc(q, ch);
272 }
273 
274 /*
275  *  Put character, possibly a rune, into read queue at interrupt time.
276  *  Always called splhi from processor 0.
277  */
278 int
279 kbdputc(IOQ *q, int ch)
280 {
281 	int i, n;
282 	char buf[3];
283 	Rune r;
284 
285 	USED(q);
286 	r = ch;
287 	n = runetochar(buf, &r);
288 	if(n == 0)
289 		return 0;
290 	echo(r, buf, n);
291 	kbdq.c = r;
292 	for(i=0; i<n; i++){
293 		*kbdq.in++ = buf[i];
294 		if(kbdq.in == kbdq.buf+sizeof(kbdq.buf))
295 			kbdq.in = kbdq.buf;
296 	}
297 	if(raw || r=='\n' || r==0x04)
298 		wakeup(&kbdq.r);
299 	return 0;
300 }
301 
302 void
303 kbdrepeat(int rep)
304 {
305 	kbdq.repeat = rep;
306 	kbdq.count = 0;
307 }
308 
309 void
310 kbdclock(void)
311 {
312 	if(kbdq.repeat == 0)
313 		return;
314 	if(kbdq.repeat==1 && ++kbdq.count>HZ){
315 		kbdq.repeat = 2;
316 		kbdq.count = 0;
317 		return;
318 	}
319 	if(++kbdq.count&1)
320 		kbdputc(&kbdq, kbdq.c);
321 }
322 
323 int
324 consactive(void)
325 {
326 	return printq.in != printq.out;
327 }
328 
329 enum{
330 	Qdir,
331 	Qauth,
332 	Qauthcheck,
333 	Qauthent,
334 	Qclock,
335 	Qcons,
336 	Qconsctl,
337 	Qcputime,
338 	Qhz,
339 	Qkey,
340 	Qhostdomain,
341 	Qhostowner,
342 	Qklog,
343 	Qlights,
344 	Qmsec,
345 	Qnoise,
346 	Qnull,
347 	Qpgrpid,
348 	Qpid,
349 	Qppid,
350 	Qswap,
351 	Qsysname,
352 	Qsysstat,
353 	Qtime,
354 	Quser,
355 };
356 
357 Dirtab consdir[]={
358 	"authenticate",	{Qauth},	0,		0666,
359 	"authcheck",	{Qauthcheck},	0,		0666,
360 	"authenticator", {Qauthent},	0,		0666,
361 	"clock",	{Qclock},	2*NUMSIZE,	0444,
362 	"cons",		{Qcons},	0,		0660,
363 	"consctl",	{Qconsctl},	0,		0220,
364 	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
365 	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,
366 	"hostowner",	{Qhostowner},	NAMELEN,	0664,
367 	"hz",		{Qhz},		NUMSIZE,	0666,
368 	"key",		{Qkey},		DESKEYLEN,	0622,
369 	"klog",		{Qklog},	0,		0444,
370 	"lights",	{Qlights},	0,		0220,
371 	"msec",		{Qmsec},	NUMSIZE,	0444,
372 	"noise",	{Qnoise},	0,		0220,
373 	"null",		{Qnull},	0,		0666,
374 	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,
375 	"pid",		{Qpid},		NUMSIZE,	0444,
376 	"ppid",		{Qppid},	NUMSIZE,	0444,
377 	"swap",		{Qswap},	0,		0664,
378 	"sysname",	{Qsysname},	0,		0664,
379 	"sysstat",	{Qsysstat},	0,		0666,
380 	"time",		{Qtime},	NUMSIZE,	0664,
381  	"user",		{Quser},	NAMELEN,	0666,
382 };
383 
384 #define	NCONS	(sizeof consdir/sizeof(Dirtab))
385 
386 ulong	boottime;		/* seconds since epoch at boot */
387 
388 long
389 seconds(void)
390 {
391 	return boottime + TK2SEC(MACHP(0)->ticks);
392 }
393 
394 int
395 readnum(ulong off, char *buf, ulong n, ulong val, int size)
396 {
397 	char tmp[64];
398 	Fconv fconv = (Fconv){ tmp, tmp+sizeof(tmp), size-1, 0, 0, 'u' };
399 
400 	numbconv(&val, &fconv);
401 	tmp[size-1] = ' ';
402 	if(off >= size)
403 		return 0;
404 	if(off+n > size)
405 		n = size-off;
406 	memmove(buf, tmp+off, n);
407 	return n;
408 }
409 
410 int
411 readstr(ulong off, char *buf, ulong n, char *str)
412 {
413 	int size;
414 
415 	size = strlen(str);
416 	if(off >= size)
417 		return 0;
418 	if(off+n > size)
419 		n = size-off;
420 	memmove(buf, str+off, n);
421 	return n;
422 }
423 
424 void
425 consreset(void)
426 {
427 }
428 
429 void
430 consinit(void)
431 {
432 }
433 
434 Chan*
435 consattach(char *spec)
436 {
437 	return devattach('c', spec);
438 }
439 
440 Chan*
441 consclone(Chan *c, Chan *nc)
442 {
443 	return devclone(c, nc);
444 }
445 
446 int
447 conswalk(Chan *c, char *name)
448 {
449 	return devwalk(c, name, consdir, NCONS, devgen);
450 }
451 
452 void
453 consstat(Chan *c, char *dp)
454 {
455 	devstat(c, dp, consdir, NCONS, devgen);
456 }
457 
458 Chan*
459 consopen(Chan *c, int omode)
460 {
461 	c->aux = 0;
462 	switch(c->qid.path){
463 	case Qconsctl:
464 		if(!iseve())
465 			error(Eperm);
466 		incref(&ctl);
467 		break;
468 	}
469 	return devopen(c, omode, consdir, NCONS, devgen);
470 }
471 
472 void
473 conscreate(Chan *c, char *name, int omode, ulong perm)
474 {
475 	USED(c, name, omode, perm);
476 	error(Eperm);
477 }
478 
479 void
480 consclose(Chan *c)
481 {
482 	/* last close of control file turns off raw */
483 	switch(c->qid.path){
484 	case Qconsctl:
485 		if(c->flag&COPEN){
486 			lock(&ctl);
487 			if(--ctl.ref == 0)
488 				raw = 0;
489 			unlock(&ctl);
490 		}
491 		break;
492 	case Qauth:
493 	case Qauthcheck:
494 	case Qauthent:
495 		authclose(c);
496 		break;
497 	}
498 }
499 
500 long
501 consread(Chan *c, void *buf, long n, ulong offset)
502 {
503 	int ch, i, k, id;
504 	ulong l;
505 	char *cbuf = buf;
506 	char *b, *bp;
507 	char tmp[128];	/* must be >= 6*NUMSIZE */
508 	Mach *mp;
509 
510 	if(n <= 0)
511 		return n;
512 	switch(c->qid.path & ~CHDIR){
513 	case Qdir:
514 		return devdirread(c, buf, n, consdir, NCONS, devgen);
515 
516 	case Qcons:
517 		qlock(&kbdq);
518 		if(waserror()){
519 			qunlock(&kbdq);
520 			nexterror();
521 		}
522 		while(!cangetc(&lineq)){
523 			sleep(&kbdq.r, isbrkc, &kbdq);
524 			do{
525 				lock(&lineq);
526 				ch = getc(&kbdq);
527 				if(raw)
528 					goto Default;
529 				switch(ch){
530 				case '\b':
531 					if(lineq.in != lineq.out){
532 						if(lineq.in == lineq.buf)
533 							lineq.in = lineq.buf+sizeof(lineq.buf);
534 						lineq.in--;
535 					}
536 					break;
537 				case 0x15:
538 					lineq.in = lineq.out;
539 					break;
540 				Default:
541 				default:
542 					*lineq.in = ch;
543 					if(lineq.in >= lineq.buf+sizeof(lineq.buf)-1)
544 						lineq.in = lineq.buf;
545 					else
546 						lineq.in++;
547 				}
548 				unlock(&lineq);
549 			}while(raw==0 && ch!='\n' && ch!=0x04);
550 		}
551 		i = 0;
552 		while(n > 0){
553 			ch = getc(&lineq);
554 			if(ch==-1 || (raw==0 && ch==0x04))
555 				break;
556 			i++;
557 			*cbuf++ = ch;
558 			--n;
559 		}
560 		poperror();
561 		qunlock(&kbdq);
562 		return i;
563 
564 	case Qcputime:
565 		k = offset;
566 		if(k >= 6*NUMSIZE)
567 			return 0;
568 		if(k+n > 6*NUMSIZE)
569 			n = 6*NUMSIZE - k;
570 		/* easiest to format in a separate buffer and copy out */
571 		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
572 			l = u->p->time[i];
573 			if(i == TReal)
574 				l = MACHP(0)->ticks - l;
575 			l = TK2MS(l);
576 			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
577 		}
578 		memmove(buf, tmp+k, n);
579 		return n;
580 
581 	case Qpgrpid:
582 		return readnum(offset, buf, n, u->p->pgrp->pgrpid, NUMSIZE);
583 
584 	case Qpid:
585 		return readnum(offset, buf, n, u->p->pid, NUMSIZE);
586 
587 	case Qppid:
588 		return readnum(offset, buf, n, u->p->parentpid, NUMSIZE);
589 
590 	case Qtime:
591 		return readnum(offset, buf, n, boottime+TK2SEC(MACHP(0)->ticks), 12);
592 
593 	case Qclock:
594 		k = offset;
595 		if(k >= 2*NUMSIZE)
596 			return 0;
597 		if(k+n > 2*NUMSIZE)
598 			n = 2*NUMSIZE - k;
599 		readnum(0, tmp, NUMSIZE, MACHP(0)->ticks, NUMSIZE);
600 		readnum(0, tmp+NUMSIZE, NUMSIZE, HZ, NUMSIZE);
601 		memmove(buf, tmp+k, n);
602 		return n;
603 
604 	case Qkey:
605 		return keyread(buf, n, offset);
606 
607 	case Qauth:
608 		return authread(c, cbuf, n);
609 
610 	case Qauthent:
611 		return authentread(c, cbuf, n);
612 
613 	case Qhostowner:
614 		return readstr(offset, buf, n, eve);
615 
616 	case Qhostdomain:
617 		return readstr(offset, buf, n, hostdomain);
618 
619 	case Quser:
620 		return readstr(offset, buf, n, u->p->user);
621 
622 	case Qnull:
623 		return 0;
624 
625 	case Qklog:
626 		qlock(&klogq);
627 		if(waserror()){
628 			qunlock(&klogq);
629 			nexterror();
630 		}
631 		while(!cangetc(&klogq))
632 			sleep(&klogq.r, cangetc, &klogq);
633 		for(i=0; i<n; i++){
634 			if((ch=getc(&klogq)) == -1)
635 				break;
636 			*cbuf++ = ch;
637 		}
638 		poperror();
639 		qunlock(&klogq);
640 		return i;
641 
642 	case Qmsec:
643 		return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
644 
645 	case Qhz:
646 		return readnum(offset, buf, n, HZ, NUMSIZE);
647 
648 	case Qsysstat:
649 		b = smalloc(conf.nmach*(NUMSIZE*8+1) + 1);	/* +1 for NUL */
650 		bp = b;
651 		for(id = 0; id < 32; id++) {
652 			if(active.machs & (1<<id)) {
653 				mp = MACHP(id);
654 				readnum(0, bp, NUMSIZE, id, NUMSIZE);
655 				bp += NUMSIZE;
656 				readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
657 				bp += NUMSIZE;
658 				readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
659 				bp += NUMSIZE;
660 				readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
661 				bp += NUMSIZE;
662 				readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
663 				bp += NUMSIZE;
664 				readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
665 				bp += NUMSIZE;
666 				readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
667 				bp += NUMSIZE;
668 				readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
669 				bp += NUMSIZE;
670 				*bp++ = '\n';
671 			}
672 		}
673 		n = readstr(offset, buf, n, b);
674 		free(b);
675 		return n;
676 
677 	case Qswap:
678 		sprint(tmp, "%d/%d memory %d/%d swap\n",
679 				palloc.user-palloc.freecount, palloc.user,
680 				conf.nswap-swapalloc.free, conf.nswap);
681 
682 		return readstr(offset, buf, n, tmp);
683 
684 	case Qsysname:
685 		return readstr(offset, buf, n, sysname);
686 
687 	default:
688 		print("consread %lux\n", c->qid);
689 		error(Egreg);
690 	}
691 	return -1;		/* never reached */
692 }
693 
694 void
695 conslights(char *a, int n)
696 {
697 	char line[128];
698 	char *lp;
699 	int c;
700 
701 	lp = line;
702 	while(n--){
703 		*lp++ = c = *a++;
704 		if(c=='\n' || n==0 || lp==&line[sizeof(line)-1])
705 			break;
706 	}
707 	*lp = 0;
708 	lights(strtoul(line, 0, 0));
709 }
710 
711 void
712 consnoise(char *a, int n)
713 {
714 	int freq;
715 	int duration;
716 	char line[128];
717 	char *lp;
718 	int c;
719 
720 	lp = line;
721 	while(n--){
722 		*lp++ = c = *a++;
723 		if(c=='\n' || n==0 || lp==&line[sizeof(line)-1]){
724 			*lp = 0;
725 			freq = strtoul(line, &lp, 0);
726 			while(*lp==' ' || *lp=='\t')
727 				lp++;
728 			duration = strtoul(lp, &lp, 0);
729 			buzz(freq, duration);
730 			lp = line;
731 		}
732 	}
733 }
734 
735 long
736 conswrite(Chan *c, void *va, long n, ulong offset)
737 {
738 	char cbuf[64];
739 	char buf[256];
740 	long l, bp;
741 	char *a = va;
742 	Mach *mp;
743 	int id, fd, ch;
744 	Chan *swc;
745 
746 	switch(c->qid.path){
747 	case Qcons:
748 		l = n;
749 		while(l > 0){
750 			bp = l;
751 			if(bp > sizeof buf)
752 				bp = sizeof buf;
753 			memmove(buf, a, bp);
754 			putstrn(a, bp);
755 			a += bp;
756 			l -= bp;
757 		}
758 		break;
759 
760 	case Qconsctl:
761 		if(n >= sizeof(buf))
762 			n = sizeof(buf)-1;
763 		strncpy(buf, a, n);
764 		buf[n] = 0;
765 		if(strncmp(a, "rawon", 5) == 0){
766 			lock(&lineq);
767 			while((ch=getc(&kbdq)) != -1){
768 				*lineq.in++ = ch;
769 				if(lineq.in == lineq.buf+sizeof(lineq.buf))
770 					lineq.in = lineq.buf;
771 			}
772 			unlock(&lineq);
773 			lock(&ctl);
774 			raw = 1;
775 			unlock(&ctl);
776 		}
777 		else
778 		if(strncmp(a, "rawoff", 6) == 0){
779 			lock(&ctl);
780 			raw = 0;
781 			unlock(&ctl);
782 		}
783 		else
784 			error(Ebadctl);
785 		break;
786 
787 	case Qtime:
788 		if(n<=0 || boottime!=0)	/* write once file */
789 			return 0;
790 		if(n >= sizeof cbuf)
791 			n = sizeof cbuf - 1;
792 		memmove(cbuf, a, n);
793 		cbuf[n-1] = 0;
794 		boottime = strtoul(a, 0, 0)-TK2SEC(MACHP(0)->ticks);
795 		break;
796 
797 	case Qkey:
798 		return keywrite(a, n);
799 
800 	case Qhostowner:
801 		return hostownerwrite(a, n);
802 
803 	case Qhostdomain:
804 		return hostdomainwrite(a, n);
805 
806 	case Quser:
807 		return userwrite(a, n);
808 
809 	case Qauth:
810 		return authwrite(c, a, n);
811 
812 	case Qauthcheck:
813 		return authcheck(c, a, n);
814 
815 	case Qauthent:
816 		return authentwrite(c, a, n);
817 
818 	case Qnull:
819 		break;
820 
821 	case Qnoise:
822 		consnoise(a, n);
823 		break;
824 
825 	case Qlights:
826 		conslights(a, n);
827 		break;
828 
829 	case Qsysstat:
830 		for(id = 0; id < 32; id++) {
831 			if(active.machs & (1<<id)) {
832 				mp = MACHP(id);
833 				mp->cs = 0;
834 				mp->intr = 0;
835 				mp->syscall = 0;
836 				mp->pfault = 0;
837 				mp->tlbfault = 0;
838 				mp->tlbpurge = 0;
839 			}
840 		}
841 		break;
842 
843 	case Qswap:
844 		if(n >= sizeof buf)
845 			error(Egreg);
846 		memmove(buf, va, n);	/* so we can NUL-terminate */
847 		buf[n] = 0;
848 		/* start a pager if not already started */
849 		if(strncmp(buf, "start", 5) == 0){
850 			kickpager();
851 			break;
852 		}
853 		if(cpuserver && strcmp(u->p->user, eve) != 0)
854 			error(Eperm);
855 		if(buf[0]<'0' || '9'<buf[0])
856 			error(Ebadusefd);
857 		fd = strtoul(buf, 0, 0);
858 		swc = fdtochan(fd, -1, 1, 0);
859 		setswapchan(swc);
860 		break;
861 
862 	case Qsysname:
863 		if(offset != 0)
864 			error(Ebadarg);
865 		if(n <= 0 || n >= NAMELEN)
866 			error(Ebadarg);
867 		strncpy(sysname, a, n);
868 		sysname[n] = 0;
869 		if(sysname[n-1] == '\n')
870 			sysname[n-1] = 0;
871 		break;
872 
873 	default:
874 		print("conswrite: %d\n", c->qid.path);
875 		error(Egreg);
876 	}
877 	return n;
878 }
879 
880 void
881 consremove(Chan *c)
882 {
883 	USED(c);
884 	error(Eperm);
885 }
886 
887 void
888 conswstat(Chan *c, char *dp)
889 {
890 	USED(c, dp);
891 	error(Eperm);
892 }
893 
894 int
895 nrand(int n)
896 {
897 	static ulong randn;
898 
899 	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
900 	return (randn>>16) % n;
901 }
902 
903 void
904 setterm(char *f)
905 {
906 	char buf[2*NAMELEN];
907 
908 	sprint(buf, f, conffile);
909 	ksetenv("terminal", buf);
910 }
911