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