1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 #include <version.h>
8 #include "mp.h"
9 #include "libsec.h"
10 #include "keyboard.h"
11
12 extern int cflag;
13 extern int keepbroken;
14
15 void (*serwrite)(char *, int);
16
17 Queue* kscanq; /* keyboard raw scancodes (when needed) */
18 char* kscanid; /* name of raw scan format (if defined) */
19 Queue* kbdq; /* unprocessed console input */
20 Queue* lineq; /* processed console input */
21 Queue* printq; /* console output */
22 Queue* klogq; /* kernel print (log) output */
23 int iprintscreenputs;
24
25 static struct
26 {
27 RWlock;
28 Queue* q;
29 } kprintq;
30
31 static struct
32 {
33 QLock;
34
35 int raw; /* true if we shouldn't process input */
36 int ctl; /* number of opens to the control file */
37 int kbdr; /* number of open reads to the keyboard */
38 int scan; /* true if reading raw scancodes */
39 int x; /* index into line */
40 char line[1024]; /* current input line */
41
42 char c;
43 int count;
44 int repeat;
45 } kbd;
46
47 char* sysname;
48 char* eve;
49
50 enum
51 {
52 CMreboot,
53 CMhalt,
54 CMpanic,
55 CMbroken,
56 CMnobroken,
57 CMconsole,
58 };
59
60 static Cmdtab sysctlcmd[] =
61 {
62 CMreboot, "reboot", 0,
63 CMhalt, "halt", 0,
64 CMpanic, "panic", 0,
65 CMconsole, "console", 1,
66 CMbroken, "broken", 0,
67 CMnobroken, "nobroken", 0,
68 };
69
70 void
printinit(void)71 printinit(void)
72 {
73 lineq = qopen(2*1024, 0, nil, nil);
74 if(lineq == nil)
75 panic("printinit");
76 qnoblock(lineq, 1);
77 }
78
79 /*
80 * return true if current user is eve
81 */
82 int
iseve(void)83 iseve(void)
84 {
85 Osenv *o;
86
87 o = up->env;
88 return strcmp(eve, o->user) == 0;
89 }
90
91 static int
consactive(void)92 consactive(void)
93 {
94 if(printq)
95 return qlen(printq) > 0;
96 return 0;
97 }
98
99 static void
prflush(void)100 prflush(void)
101 {
102 ulong now;
103
104 now = m->ticks;
105 while(serwrite==nil && consactive())
106 if(m->ticks - now >= HZ)
107 break;
108 }
109
110 /*
111 * Print a string on the console. Convert \n to \r\n for serial
112 * line consoles. Locking of the queues is left up to the screen
113 * or uart code. Multi-line messages to serial consoles may get
114 * interspersed with other messages.
115 */
116 static void
putstrn0(char * str,int n,int usewrite)117 putstrn0(char *str, int n, int usewrite)
118 {
119 int m;
120 char *t;
121 char buf[PRINTSIZE+2];
122
123 /*
124 * if kprint is open, put the message there, otherwise
125 * if there's an attached bit mapped display,
126 * put the message there.
127 */
128 m = consoleprint;
129 if(canrlock(&kprintq)){
130 if(kprintq.q != nil){
131 if(waserror()){
132 runlock(&kprintq);
133 nexterror();
134 }
135 if(usewrite)
136 qwrite(kprintq.q, str, n);
137 else
138 qiwrite(kprintq.q, str, n);
139 poperror();
140 m = 0;
141 }
142 runlock(&kprintq);
143 }
144 if(m && screenputs != nil)
145 screenputs(str, n);
146
147 /*
148 * if there's a serial line being used as a console,
149 * put the message there.
150 */
151 if(serwrite != nil) {
152 serwrite(str, n);
153 return;
154 }
155
156 if(printq == 0)
157 return;
158
159 while(n > 0) {
160 t = memchr(str, '\n', n);
161 if(t && !kbd.raw) {
162 m = t - str;
163 if(m > sizeof(buf)-2)
164 m = sizeof(buf)-2;
165 memmove(buf, str, m);
166 buf[m] = '\r';
167 buf[m+1] = '\n';
168 if(usewrite)
169 qwrite(printq, buf, m+2);
170 else
171 qiwrite(printq, buf, m+2);
172 str = t + 1;
173 n -= m + 1;
174 } else {
175 if(usewrite)
176 qwrite(printq, str, n);
177 else
178 qiwrite(printq, str, n);
179 break;
180 }
181 }
182 }
183
184 void
putstrn(char * str,int n)185 putstrn(char *str, int n)
186 {
187 putstrn0(str, n, 0);
188 }
189
190 int
snprint(char * s,int n,char * fmt,...)191 snprint(char *s, int n, char *fmt, ...)
192 {
193 va_list arg;
194
195 va_start(arg, fmt);
196 n = vseprint(s, s+n, fmt, arg) - s;
197 va_end(arg);
198
199 return n;
200 }
201
202 int
sprint(char * s,char * fmt,...)203 sprint(char *s, char *fmt, ...)
204 {
205 int n;
206 va_list arg;
207
208 va_start(arg, fmt);
209 n = vseprint(s, s+PRINTSIZE, fmt, arg) - s;
210 va_end(arg);
211
212 return n;
213 }
214
215 int
print(char * fmt,...)216 print(char *fmt, ...)
217 {
218 int n;
219 va_list arg;
220 char buf[PRINTSIZE];
221
222 va_start(arg, fmt);
223 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
224 va_end(arg);
225 putstrn(buf, n);
226
227 return n;
228 }
229
230 int
fprint(int fd,char * fmt,...)231 fprint(int fd, char *fmt, ...)
232 {
233 int n;
234 va_list arg;
235 char buf[PRINTSIZE];
236
237 USED(fd);
238 va_start(arg, fmt);
239 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
240 va_end(arg);
241 putstrn(buf, n);
242
243 return n;
244 }
245
246 int
kprint(char * fmt,...)247 kprint(char *fmt, ...)
248 {
249 va_list arg;
250 char buf[PRINTSIZE];
251 int n;
252
253 va_start(arg, fmt);
254 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
255 va_end(arg);
256 if(qfull(klogq))
257 qflush(klogq);
258 return qproduce(klogq, buf, n);
259 }
260
261 int
iprint(char * fmt,...)262 iprint(char *fmt, ...)
263 {
264 int n, s;
265 va_list arg;
266 char buf[PRINTSIZE];
267
268 s = splhi();
269 va_start(arg, fmt);
270 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
271 va_end(arg);
272 if(screenputs != nil && iprintscreenputs)
273 screenputs(buf, n);
274 uartputs(buf, n);
275 splx(s);
276
277 return n;
278 }
279
280 void
panic(char * fmt,...)281 panic(char *fmt, ...)
282 {
283 int n;
284 va_list arg;
285 char buf[PRINTSIZE];
286
287 setpanic();
288 kprintq.q = nil;
289 strcpy(buf, "panic: ");
290 va_start(arg, fmt);
291 n = vseprint(buf+strlen(buf), buf+sizeof(buf)-1, fmt, arg) - buf;
292 va_end(arg);
293 buf[n] = '\n';
294 putstrn(buf, n+1);
295 spllo();
296 dumpstack();
297
298 exit(1);
299 }
300
301 void
_assert(char * fmt)302 _assert(char *fmt)
303 {
304 panic("assert failed: %s", fmt);
305 }
306
307 /*
308 * mainly for libmp
309 */
310 void
sysfatal(char * fmt,...)311 sysfatal(char *fmt, ...)
312 {
313 va_list arg;
314 char buf[64];
315
316 va_start(arg, fmt);
317 vsnprint(buf, sizeof(buf), fmt, arg);
318 va_end(arg);
319 error(buf);
320 }
321
322 int
pprint(char * fmt,...)323 pprint(char *fmt, ...)
324 {
325 int n;
326 Chan *c;
327 Osenv *o;
328 va_list arg;
329 char buf[2*PRINTSIZE];
330
331 n = sprint(buf, "%s %ld: ", up->text, up->pid);
332 va_start(arg, fmt);
333 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
334 va_end(arg);
335
336 o = up->env;
337 if(o->fgrp == 0) {
338 print("%s", buf);
339 return 0;
340 }
341 c = o->fgrp->fd[2];
342 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) {
343 print("%s", buf);
344 return 0;
345 }
346
347 if(waserror()) {
348 print("%s", buf);
349 return 0;
350 }
351 devtab[c->type]->write(c, buf, n, c->offset);
352 poperror();
353
354 lock(c);
355 c->offset += n;
356 unlock(c);
357
358 return n;
359 }
360
361 void
echo(Rune r,char * buf,int n)362 echo(Rune r, char *buf, int n)
363 {
364 if(kbd.raw)
365 return;
366
367 if(r == '\n'){
368 if(printq)
369 qiwrite(printq, "\r", 1);
370 } else if(r == 0x15){
371 buf = "^U\n";
372 n = 3;
373 }
374 if(consoleprint && screenputs != nil)
375 screenputs(buf, n);
376 if(printq)
377 qiwrite(printq, buf, n);
378 }
379
380 /*
381 * Debug key support. Allows other parts of the kernel to register debug
382 * key handlers, instead of devcons.c having to know whatever's out there.
383 * A kproc is used to invoke most handlers, rather than tying up the CPU at
384 * splhi, which can choke some device drivers (eg softmodem).
385 */
386 typedef struct {
387 Rune r;
388 char *m;
389 void (*f)(Rune);
390 int i; /* function called at interrupt time */
391 } Dbgkey;
392
393 static struct {
394 Rendez;
395 Dbgkey *work;
396 Dbgkey keys[50];
397 int nkeys;
398 int on;
399 } dbg;
400
401 static Dbgkey *
finddbgkey(Rune r)402 finddbgkey(Rune r)
403 {
404 int i;
405 Dbgkey *dp;
406
407 for(dp = dbg.keys, i = 0; i < dbg.nkeys; i++, dp++)
408 if(dp->r == r)
409 return dp;
410 return nil;
411 }
412
413 static int
dbgwork(void *)414 dbgwork(void *)
415 {
416 return dbg.work != 0;
417 }
418
419 static void
dbgproc(void *)420 dbgproc(void *)
421 {
422 Dbgkey *dp;
423
424 setpri(PriRealtime);
425 for(;;) {
426 do {
427 sleep(&dbg, dbgwork, 0);
428 dp = dbg.work;
429 } while(dp == nil);
430 dp->f(dp->r);
431 dbg.work = nil;
432 }
433 }
434
435 void
debugkey(Rune r,char * msg,void (* fcn)(),int iflag)436 debugkey(Rune r, char *msg, void (*fcn)(), int iflag)
437 {
438 Dbgkey *dp;
439
440 if(dbg.nkeys >= nelem(dbg.keys))
441 return;
442 if(finddbgkey(r) != nil)
443 return;
444 for(dp = &dbg.keys[dbg.nkeys++] - 1; dp >= dbg.keys; dp--) {
445 if(strcmp(dp->m, msg) < 0)
446 break;
447 dp[1] = dp[0];
448 }
449 dp++;
450 dp->r = r;
451 dp->m = msg;
452 dp->f = fcn;
453 dp->i = iflag;
454 }
455
456 static int
isdbgkey(Rune r)457 isdbgkey(Rune r)
458 {
459 static int ctrlt;
460 Dbgkey *dp;
461 int echoctrlt = ctrlt;
462
463 /*
464 * ^t hack BUG
465 */
466 if(dbg.on || (ctrlt >= 2)) {
467 if(r == 0x14 || r == 0x05) {
468 ctrlt++;
469 return 0;
470 }
471 if(dp = finddbgkey(r)) {
472 if(dp->i || ctrlt > 2)
473 dp->f(r);
474 else {
475 dbg.work = dp;
476 wakeup(&dbg);
477 }
478 ctrlt = 0;
479 return 1;
480 }
481 ctrlt = 0;
482 }
483 else if(r == 0x14){
484 ctrlt++;
485 return 1;
486 }
487 else
488 ctrlt = 0;
489 if(echoctrlt){
490 char buf[UTFmax];
491
492 buf[0] = 0x14;
493 while(--echoctrlt >= 0){
494 echo(buf[0], buf, 1);
495 qproduce(kbdq, buf, 1);
496 }
497 }
498 return 0;
499 }
500
501 static void
dbgtoggle(Rune)502 dbgtoggle(Rune)
503 {
504 dbg.on = !dbg.on;
505 print("Debug keys %s\n", dbg.on ? "HOT" : "COLD");
506 }
507
508 static void
dbghelp(void)509 dbghelp(void)
510 {
511 int i;
512 Dbgkey *dp;
513 Dbgkey *dp2;
514 static char fmt[] = "%c: %-22s";
515
516 dp = dbg.keys;
517 dp2 = dp + (dbg.nkeys + 1)/2;
518 for(i = dbg.nkeys; i > 1; i -= 2, dp++, dp2++) {
519 print(fmt, dp->r, dp->m);
520 print(fmt, dp2->r, dp2->m);
521 print("\n");
522 }
523 if(i)
524 print(fmt, dp->r, dp->m);
525 print("\n");
526 }
527
528 static void
debuginit(void)529 debuginit(void)
530 {
531 kproc("consdbg", dbgproc, nil, 0);
532 debugkey('|', "HOT|COLD keys", dbgtoggle, 0);
533 debugkey('?', "help", dbghelp, 0);
534 }
535
536 /*
537 * Called by a uart interrupt for console input.
538 *
539 * turn '\r' into '\n' before putting it into the queue.
540 */
541 int
kbdcr2nl(Queue * q,int ch)542 kbdcr2nl(Queue *q, int ch)
543 {
544 if(ch == '\r')
545 ch = '\n';
546 return kbdputc(q, ch);
547 }
548
549 /*
550 * Put character, possibly a rune, into read queue at interrupt time.
551 * Performs translation for compose sequences
552 * Called at interrupt time to process a character.
553 */
554 int
kbdputc(Queue * q,int ch)555 kbdputc(Queue *q, int ch)
556 {
557 int n;
558 char buf[UTFmax];
559 Rune r;
560 static Rune kc[15];
561 static int nk, collecting = 0;
562
563 r = ch;
564 if(r == Latin) {
565 collecting = 1;
566 nk = 0;
567 return 0;
568 }
569 if(collecting) {
570 int c;
571 nk += runetochar((char*)&kc[nk], &r);
572 c = latin1(kc, nk);
573 if(c < -1) /* need more keystrokes */
574 return 0;
575 collecting = 0;
576 if(c == -1) { /* invalid sequence */
577 echo(kc[0], (char*)kc, nk);
578 qproduce(q, kc, nk);
579 return 0;
580 }
581 r = (Rune)c;
582 }
583 kbd.c = r;
584 n = runetochar(buf, &r);
585 if(n == 0)
586 return 0;
587 if(!isdbgkey(r)) {
588 echo(r, buf, n);
589 qproduce(q, buf, n);
590 }
591 return 0;
592 }
593
594 void
kbdrepeat(int rep)595 kbdrepeat(int rep)
596 {
597 kbd.repeat = rep;
598 kbd.count = 0;
599 }
600
601 void
kbdclock(void)602 kbdclock(void)
603 {
604 if(kbd.repeat == 0)
605 return;
606 if(kbd.repeat==1 && ++kbd.count>HZ){
607 kbd.repeat = 2;
608 kbd.count = 0;
609 return;
610 }
611 if(++kbd.count&1)
612 kbdputc(kbdq, kbd.c);
613 }
614
615 enum{
616 Qdir,
617 Qcons,
618 Qsysctl,
619 Qconsctl,
620 Qdrivers,
621 Qhostowner,
622 Qkeyboard,
623 Qklog,
624 Qkprint,
625 Qscancode,
626 Qmemory,
627 Qmsec,
628 Qnull,
629 Qrandom,
630 Qnotquiterandom,
631 Qsysname,
632 Qtime,
633 Quser,
634 Qjit,
635 };
636
637 static Dirtab consdir[]=
638 {
639 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
640 "cons", {Qcons}, 0, 0660,
641 "consctl", {Qconsctl}, 0, 0220,
642 "sysctl", {Qsysctl}, 0, 0644,
643 "drivers", {Qdrivers}, 0, 0444,
644 "hostowner", {Qhostowner}, 0, 0644,
645 "keyboard", {Qkeyboard}, 0, 0666,
646 "klog", {Qklog}, 0, 0444,
647 "kprint", {Qkprint}, 0, 0444,
648 "scancode", {Qscancode}, 0, 0444,
649 "memory", {Qmemory}, 0, 0444,
650 "msec", {Qmsec}, NUMSIZE, 0444,
651 "null", {Qnull}, 0, 0666,
652 "random", {Qrandom}, 0, 0444,
653 "notquiterandom", {Qnotquiterandom}, 0, 0444,
654 "sysname", {Qsysname}, 0, 0664,
655 "time", {Qtime}, 0, 0664,
656 "user", {Quser}, 0, 0644,
657 "jit", {Qjit}, 0, 0666,
658 };
659
660 ulong boottime; /* seconds since epoch at boot */
661
662 long
seconds(void)663 seconds(void)
664 {
665 return boottime + TK2SEC(MACHP(0)->ticks);
666 }
667
668 vlong
mseconds(void)669 mseconds(void)
670 {
671 return ((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)));
672 }
673
674 vlong
osusectime(void)675 osusectime(void)
676 {
677 return (((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)))*1000);
678 }
679
680 vlong
nsec(void)681 nsec(void)
682 {
683 return osusectime()*1000; /* TO DO */
684 }
685
686 int
readnum(ulong off,char * buf,ulong n,ulong val,int size)687 readnum(ulong off, char *buf, ulong n, ulong val, int size)
688 {
689 char tmp[64];
690
691 if(size > 64) size = 64;
692
693 snprint(tmp, sizeof(tmp), "%*.0lud ", size, val);
694 if(off >= size)
695 return 0;
696 if(off+n > size)
697 n = size-off;
698 memmove(buf, tmp+off, n);
699 return n;
700 }
701
702 int
readstr(ulong off,char * buf,ulong n,char * str)703 readstr(ulong off, char *buf, ulong n, char *str)
704 {
705 int size;
706
707 size = strlen(str);
708 if(off >= size)
709 return 0;
710 if(off+n > size)
711 n = size-off;
712 memmove(buf, str+off, n);
713 return n;
714 }
715
716 void
fddump()717 fddump()
718 {
719 Proc *p;
720 Osenv *o;
721 int i;
722 Chan *c;
723
724 p = proctab(6);
725 o = p->env;
726 for(i = 0; i <= o->fgrp->maxfd; i++) {
727 if((c = o->fgrp->fd[i]) == nil)
728 continue;
729 print("%d: %s\n", i, c->name == nil? "???": c->name->s);
730 }
731 }
732
733 static void
qpanic(Rune)734 qpanic(Rune)
735 {
736 panic("User requested panic.");
737 }
738
739 static void
rexit(Rune)740 rexit(Rune)
741 {
742 exit(0);
743 }
744
745 static void
consinit(void)746 consinit(void)
747 {
748 randominit();
749 debuginit();
750 debugkey('f', "files/6", fddump, 0);
751 debugkey('q', "panic", qpanic, 1);
752 debugkey('r', "exit", rexit, 1);
753 klogq = qopen(128*1024, 0, 0, 0);
754 }
755
756 static Chan*
consattach(char * spec)757 consattach(char *spec)
758 {
759 return devattach('c', spec);
760 }
761
762 static Walkqid*
conswalk(Chan * c,Chan * nc,char ** name,int nname)763 conswalk(Chan *c, Chan *nc, char **name, int nname)
764 {
765 return devwalk(c, nc, name, nname, consdir, nelem(consdir), devgen);
766 }
767
768 static int
consstat(Chan * c,uchar * dp,int n)769 consstat(Chan *c, uchar *dp, int n)
770 {
771 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
772 }
773
774 static void
flushkbdline(Queue * q)775 flushkbdline(Queue *q)
776 {
777 if(kbd.x){
778 qwrite(q, kbd.line, kbd.x);
779 kbd.x = 0;
780 }
781 }
782
783 static Chan*
consopen(Chan * c,int omode)784 consopen(Chan *c, int omode)
785 {
786 c->aux = 0;
787 switch((ulong)c->qid.path){
788 case Qconsctl:
789 if(!iseve())
790 error(Eperm);
791 qlock(&kbd);
792 kbd.ctl++;
793 qunlock(&kbd);
794 break;
795
796 case Qkeyboard:
797 if((omode & 3) != OWRITE) {
798 qlock(&kbd);
799 kbd.kbdr++;
800 flushkbdline(kbdq);
801 kbd.raw = 1;
802 qunlock(&kbd);
803 }
804 break;
805
806 case Qscancode:
807 qlock(&kbd);
808 if(kscanq || !kscanid) {
809 qunlock(&kbd);
810 c->flag &= ~COPEN;
811 if(kscanq)
812 error(Einuse);
813 else
814 error(Ebadarg);
815 }
816 kscanq = qopen(256, 0, nil, nil);
817 qunlock(&kbd);
818 break;
819
820 case Qkprint:
821 if((omode & 3) != OWRITE) {
822 wlock(&kprintq);
823 if(kprintq.q != nil){
824 wunlock(&kprintq);
825 error(Einuse);
826 }
827 kprintq.q = qopen(32*1024, Qcoalesce, nil, nil);
828 if(kprintq.q == nil){
829 wunlock(&kprintq);
830 error(Enomem);
831 }
832 qnoblock(kprintq.q, 1);
833 wunlock(&kprintq);
834 c->iounit = qiomaxatomic;
835 }
836 break;
837 }
838 return devopen(c, omode, consdir, nelem(consdir), devgen);
839 }
840
841 static void
consclose(Chan * c)842 consclose(Chan *c)
843 {
844 if((c->flag&COPEN) == 0)
845 return;
846
847 switch((ulong)c->qid.path){
848 case Qconsctl:
849 /* last close of control file turns off raw */
850 qlock(&kbd);
851 if(--kbd.ctl == 0)
852 kbd.raw = 0;
853 qunlock(&kbd);
854 break;
855
856 case Qkeyboard:
857 if(c->mode != OWRITE) {
858 qlock(&kbd);
859 --kbd.kbdr;
860 qunlock(&kbd);
861 }
862 break;
863
864 case Qscancode:
865 qlock(&kbd);
866 if(kscanq) {
867 qfree(kscanq);
868 kscanq = 0;
869 }
870 qunlock(&kbd);
871 break;
872
873 case Qkprint:
874 wlock(&kprintq);
875 qfree(kprintq.q);
876 kprintq.q = nil;
877 wunlock(&kprintq);
878 break;
879 }
880 }
881
882 static long
consread(Chan * c,void * buf,long n,vlong offset)883 consread(Chan *c, void *buf, long n, vlong offset)
884 {
885 int l;
886 Osenv *o;
887 int ch, eol, i;
888 char *p, tmp[128];
889 char *cbuf = buf;
890
891 if(n <= 0)
892 return n;
893 o = up->env;
894 switch((ulong)c->qid.path){
895 case Qdir:
896 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
897 case Qsysctl:
898 return readstr(offset, buf, n, VERSION);
899 case Qcons:
900 case Qkeyboard:
901 qlock(&kbd);
902 if(waserror()) {
903 qunlock(&kbd);
904 nexterror();
905 }
906 if(kbd.raw || kbd.kbdr) {
907 if(qcanread(lineq))
908 n = qread(lineq, buf, n);
909 else {
910 /* read as much as possible */
911 do {
912 i = qread(kbdq, cbuf, n);
913 cbuf += i;
914 n -= i;
915 } while(n>0 && qcanread(kbdq));
916 n = cbuf - (char*)buf;
917 }
918 } else {
919 while(!qcanread(lineq)) {
920 qread(kbdq, &kbd.line[kbd.x], 1);
921 ch = kbd.line[kbd.x];
922 eol = 0;
923 switch(ch){
924 case '\b':
925 if(kbd.x)
926 kbd.x--;
927 break;
928 case 0x15:
929 kbd.x = 0;
930 break;
931 case '\n':
932 case 0x04:
933 eol = 1;
934 default:
935 kbd.line[kbd.x++] = ch;
936 break;
937 }
938 if(kbd.x == sizeof(kbd.line) || eol) {
939 if(ch == 0x04)
940 kbd.x--;
941 qwrite(lineq, kbd.line, kbd.x);
942 kbd.x = 0;
943 }
944 }
945 n = qread(lineq, buf, n);
946 }
947 qunlock(&kbd);
948 poperror();
949 return n;
950
951 case Qscancode:
952 if(offset == 0)
953 return readstr(0, buf, n, kscanid);
954 else
955 return qread(kscanq, buf, n);
956
957 case Qtime:
958 snprint(tmp, sizeof(tmp), "%.lld", (vlong)mseconds()*1000);
959 return readstr(offset, buf, n, tmp);
960
961 case Qhostowner:
962 return readstr(offset, buf, n, eve);
963
964 case Quser:
965 return readstr(offset, buf, n, o->user);
966
967 case Qjit:
968 snprint(tmp, sizeof(tmp), "%d", cflag);
969 return readstr(offset, buf, n, tmp);
970
971 case Qnull:
972 return 0;
973
974 case Qmsec:
975 return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
976
977 case Qsysname:
978 if(sysname == nil)
979 return 0;
980 return readstr(offset, buf, n, sysname);
981
982 case Qnotquiterandom:
983 genrandom(buf, n);
984 return n;
985
986 case Qrandom:
987 return randomread(buf, n);
988
989 case Qmemory:
990 return poolread(buf, n, offset);
991
992 case Qdrivers:
993 p = malloc(READSTR);
994 if(p == nil)
995 error(Enomem);
996 l = 0;
997 for(i = 0; devtab[i] != nil; i++)
998 l += snprint(p+l, READSTR-l, "#%C %s\n", devtab[i]->dc, devtab[i]->name);
999 if(waserror()){
1000 free(p);
1001 nexterror();
1002 }
1003 n = readstr(offset, buf, n, p);
1004 free(p);
1005 poperror();
1006 return n;
1007
1008 case Qklog:
1009 return qread(klogq, buf, n);
1010
1011 case Qkprint:
1012 rlock(&kprintq);
1013 if(waserror()){
1014 runlock(&kprintq);
1015 nexterror();
1016 }
1017 n = qread(kprintq.q, buf, n);
1018 poperror();
1019 runlock(&kprintq);
1020 return n;
1021
1022 default:
1023 print("consread %llud\n", c->qid.path);
1024 error(Egreg);
1025 }
1026 return -1; /* never reached */
1027 }
1028
1029 static long
conswrite(Chan * c,void * va,long n,vlong offset)1030 conswrite(Chan *c, void *va, long n, vlong offset)
1031 {
1032 vlong t;
1033 long l, bp;
1034 char *a = va;
1035 Cmdbuf *cb;
1036 Cmdtab *ct;
1037 char buf[256];
1038 int x;
1039
1040 switch((ulong)c->qid.path){
1041 case Qcons:
1042 /*
1043 * Can't page fault in putstrn, so copy the data locally.
1044 */
1045 l = n;
1046 while(l > 0){
1047 bp = l;
1048 if(bp > sizeof buf)
1049 bp = sizeof buf;
1050 memmove(buf, a, bp);
1051 putstrn0(a, bp, 1);
1052 a += bp;
1053 l -= bp;
1054 }
1055 break;
1056
1057 case Qconsctl:
1058 if(n >= sizeof(buf))
1059 n = sizeof(buf)-1;
1060 strncpy(buf, a, n);
1061 buf[n] = 0;
1062 for(a = buf; a;){
1063 if(strncmp(a, "rawon", 5) == 0){
1064 qlock(&kbd);
1065 flushkbdline(kbdq);
1066 kbd.raw = 1;
1067 qunlock(&kbd);
1068 } else if(strncmp(a, "rawoff", 6) == 0){
1069 qlock(&kbd);
1070 kbd.raw = 0;
1071 kbd.x = 0;
1072 qunlock(&kbd);
1073 }
1074 if(a = strchr(a, ' '))
1075 a++;
1076 }
1077 break;
1078
1079 case Qkeyboard:
1080 for(x=0; x<n; ) {
1081 Rune r;
1082 x += chartorune(&r, &a[x]);
1083 kbdputc(kbdq, r);
1084 }
1085 break;
1086
1087 case Qtime:
1088 if(n >= sizeof(buf))
1089 n = sizeof(buf)-1;
1090 strncpy(buf, a, n);
1091 buf[n] = 0;
1092 t = strtoll(buf, 0, 0)/1000000;
1093 boottime = t - TK2SEC(MACHP(0)->ticks);
1094 break;
1095
1096 case Qhostowner:
1097 if(!iseve())
1098 error(Eperm);
1099 if(offset != 0 || n >= sizeof(buf))
1100 error(Ebadarg);
1101 memmove(buf, a, n);
1102 buf[n] = '\0';
1103 if(n > 0 && buf[n-1] == '\n')
1104 buf[--n] = 0;
1105 if(n <= 0)
1106 error(Ebadarg);
1107 renameuser(eve, buf);
1108 renameproguser(eve, buf);
1109 kstrdup(&eve, buf);
1110 kstrdup(&up->env->user, buf);
1111 break;
1112
1113 case Quser:
1114 if(!iseve())
1115 error(Eperm);
1116 if(offset != 0)
1117 error(Ebadarg);
1118 if(n <= 0 || n >= sizeof(buf))
1119 error(Ebadarg);
1120 strncpy(buf, a, n);
1121 buf[n] = 0;
1122 if(buf[n-1] == '\n')
1123 buf[n-1] = 0;
1124 kstrdup(&up->env->user, buf);
1125 break;
1126
1127 case Qjit:
1128 if(n >= sizeof(buf))
1129 n = sizeof(buf)-1;
1130 strncpy(buf, va, n);
1131 buf[n] = '\0';
1132 x = atoi(buf);
1133 if(x < 0 || x > 9)
1134 error(Ebadarg);
1135 cflag = x;
1136 return n;
1137
1138 case Qnull:
1139 break;
1140
1141 case Qsysname:
1142 if(offset != 0)
1143 error(Ebadarg);
1144 if(n <= 0 || n >= sizeof(buf))
1145 error(Ebadarg);
1146 strncpy(buf, a, n);
1147 buf[n] = 0;
1148 if(buf[n-1] == '\n')
1149 buf[n-1] = 0;
1150 kstrdup(&sysname, buf);
1151 break;
1152
1153 case Qsysctl:
1154 if(!iseve())
1155 error(Eperm);
1156 cb = parsecmd(a, n);
1157 if(waserror()){
1158 free(cb);
1159 nexterror();
1160 }
1161 ct = lookupcmd(cb, sysctlcmd, nelem(sysctlcmd));
1162 switch(ct->index){
1163 case CMreboot:
1164 reboot();
1165 break;
1166 case CMhalt:
1167 halt();
1168 break;
1169 case CMpanic:
1170 panic("sysctl");
1171 case CMconsole:
1172 consoleprint = strcmp(cb->f[1], "off") != 0;
1173 break;
1174 case CMbroken:
1175 keepbroken = 1;
1176 break;
1177 case CMnobroken:
1178 keepbroken = 0;
1179 break;
1180 }
1181 poperror();
1182 free(cb);
1183 break;
1184
1185 default:
1186 print("conswrite: %llud\n", c->qid.path);
1187 error(Egreg);
1188 }
1189 return n;
1190 }
1191
1192 Dev consdevtab = {
1193 'c',
1194 "cons",
1195
1196 devreset,
1197 consinit,
1198 devshutdown,
1199 consattach,
1200 conswalk,
1201 consstat,
1202 consopen,
1203 devcreate,
1204 consclose,
1205 consread,
1206 devbread,
1207 conswrite,
1208 devbwrite,
1209 devremove,
1210 devwstat,
1211 };
1212
1213 static ulong randn;
1214
1215 static void
seedrand(void)1216 seedrand(void)
1217 {
1218 randomread((void*)&randn, sizeof(randn));
1219 }
1220
1221 int
nrand(int n)1222 nrand(int n)
1223 {
1224 if(randn == 0)
1225 seedrand();
1226 randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
1227 return (randn>>16) % n;
1228 }
1229
1230 int
rand(void)1231 rand(void)
1232 {
1233 nrand(1);
1234 return randn;
1235 }
1236
1237 ulong
truerand(void)1238 truerand(void)
1239 {
1240 ulong x;
1241
1242 randomread(&x, sizeof(x));
1243 return x;
1244 }
1245
1246 QLock grandomlk;
1247
1248 void
_genrandomqlock(void)1249 _genrandomqlock(void)
1250 {
1251 qlock(&grandomlk);
1252 }
1253
1254
1255 void
_genrandomqunlock(void)1256 _genrandomqunlock(void)
1257 {
1258 qunlock(&grandomlk);
1259 }
1260