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