Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
82
return0(void *v)
83
{
84
	return 0;
85
}
86
 
87
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
102
consactive(void)
103
{
104
	if(serialoq)
105
		return qlen(serialoq) > 0;
106
	return 0;
107
}
108
 
109
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
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
150
putstrn(char *str, int n)
151
{
152
	putstrn0(str, n, 0);
153
}
154
 
155
int noprint;
156
 
157
int
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
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
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
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
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
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
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
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
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
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
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
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*
558
consattach(char *spec)
559
{
560
	return devattach('c', spec);
561
}
562
 
563
static Walkqid*
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
570
consstat(Chan *c, uchar *dp, int n)
571
{
572
	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
573
}
574
 
575
static Chan*
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
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
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
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*
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*
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*
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
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
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
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
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
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