1 #include "dat.h"
2 #include "fns.h"
3 #include "error.h"
4 #include "version.h"
5 #include "mp.h"
6 #include "libsec.h"
7 #include "keyboard.h"
8
9 extern int cflag;
10 int exdebug;
11 extern int keepbroken;
12
13 enum
14 {
15 Qdir,
16 Qcons,
17 Qconsctl,
18 Qdrivers,
19 Qhostowner,
20 Qhoststdin,
21 Qhoststdout,
22 Qhoststderr,
23 Qjit,
24 Qkeyboard,
25 Qkprint,
26 Qmemory,
27 Qmsec,
28 Qnotquiterandom,
29 Qnull,
30 Qrandom,
31 Qscancode,
32 Qsysctl,
33 Qsysname,
34 Qtime,
35 Quser
36 };
37
38 Dirtab contab[] =
39 {
40 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
41 "cons", {Qcons}, 0, 0666,
42 "consctl", {Qconsctl}, 0, 0222,
43 "drivers", {Qdrivers}, 0, 0444,
44 "hostowner", {Qhostowner}, 0, 0644,
45 "hoststdin", {Qhoststdin}, 0, 0444,
46 "hoststdout", {Qhoststdout}, 0, 0222,
47 "hoststderr", {Qhoststderr}, 0, 0222,
48 "jit", {Qjit}, 0, 0666,
49 "keyboard", {Qkeyboard}, 0, 0666,
50 "kprint", {Qkprint}, 0, 0444,
51 "memory", {Qmemory}, 0, 0444,
52 "msec", {Qmsec}, NUMSIZE, 0444,
53 "notquiterandom", {Qnotquiterandom}, 0, 0444,
54 "null", {Qnull}, 0, 0666,
55 "random", {Qrandom}, 0, 0444,
56 "scancode", {Qscancode}, 0, 0444,
57 "sysctl", {Qsysctl}, 0, 0644,
58 "sysname", {Qsysname}, 0, 0644,
59 "time", {Qtime}, 0, 0644,
60 "user", {Quser}, 0, 0644,
61 };
62
63 Queue* gkscanq; /* Graphics keyboard raw scancodes */
64 char* gkscanid; /* name of raw scan format (if defined) */
65 Queue* gkbdq; /* Graphics keyboard unprocessed input */
66 Queue* kbdq; /* Console window unprocessed keyboard input */
67 Queue* lineq; /* processed console input */
68
69 char *ossysname;
70
71 static struct
72 {
73 RWlock l;
74 Queue* q;
75 } kprintq;
76
77 vlong timeoffset;
78
79 extern int dflag;
80
81 static int sysconwrite(void*, ulong);
82 extern char** rebootargv;
83
84 static struct
85 {
86 QLock q;
87 QLock gq; /* separate lock for the graphical input */
88
89 int raw; /* true if we shouldn't process input */
90 Ref ctl; /* number of opens to the control file */
91 Ref ptr; /* number of opens to the ptr file */
92 int scan; /* true if reading raw scancodes */
93 int x; /* index into line */
94 char line[1024]; /* current input line */
95
96 Rune c;
97 int count;
98 } kbd;
99
100 void
kbdslave(void * a)101 kbdslave(void *a)
102 {
103 char b;
104
105 USED(a);
106 for(;;) {
107 b = readkbd();
108 if(kbd.raw == 0){
109 switch(b){
110 case 0x15:
111 write(1, "^U\n", 3);
112 break;
113 default:
114 write(1, &b, 1);
115 break;
116 }
117 }
118 qproduce(kbdq, &b, 1);
119 }
120 /* pexit("kbdslave", 0); */ /* not reached */
121 }
122
123 void
gkbdputc(Queue * q,int ch)124 gkbdputc(Queue *q, int ch)
125 {
126 int n;
127 Rune r;
128 static uchar kc[5*UTFmax];
129 static int nk, collecting = 0;
130 char buf[UTFmax];
131
132 r = ch;
133 if(r == Latin) {
134 collecting = 1;
135 nk = 0;
136 return;
137 }
138 if(collecting) {
139 int c;
140 nk += runetochar((char*)&kc[nk], &r);
141 c = latin1(kc, nk);
142 if(c < -1) /* need more keystrokes */
143 return;
144 collecting = 0;
145 if(c == -1) { /* invalid sequence */
146 qproduce(q, kc, nk);
147 return;
148 }
149 r = (Rune)c;
150 }
151 n = runetochar(buf, &r);
152 if(n == 0)
153 return;
154 /* if(!isdbgkey(r)) */
155 qproduce(q, buf, n);
156 }
157
158 void
consinit(void)159 consinit(void)
160 {
161 kbdq = qopen(512, 0, nil, nil);
162 if(kbdq == 0)
163 panic("no memory");
164 lineq = qopen(2*1024, 0, nil, nil);
165 if(lineq == 0)
166 panic("no memory");
167 gkbdq = qopen(512, 0, nil, nil);
168 if(gkbdq == 0)
169 panic("no memory");
170 randominit();
171 }
172
173 /*
174 * return true if current user is eve
175 */
176 int
iseve(void)177 iseve(void)
178 {
179 return strcmp(eve, up->env->user) == 0;
180 }
181
182 static Chan*
consattach(char * spec)183 consattach(char *spec)
184 {
185 static int kp;
186
187 if(kp == 0 && !dflag) {
188 kp = 1;
189 kproc("kbd", kbdslave, 0, 0);
190 }
191 return devattach('c', spec);
192 }
193
194 static Walkqid*
conswalk(Chan * c,Chan * nc,char ** name,int nname)195 conswalk(Chan *c, Chan *nc, char **name, int nname)
196 {
197 return devwalk(c, nc, name, nname, contab, nelem(contab), devgen);
198 }
199
200 static int
consstat(Chan * c,uchar * db,int n)201 consstat(Chan *c, uchar *db, int n)
202 {
203 return devstat(c, db, n, contab, nelem(contab), devgen);
204 }
205
206 static Chan*
consopen(Chan * c,int omode)207 consopen(Chan *c, int omode)
208 {
209 c = devopen(c, omode, contab, nelem(contab), devgen);
210 switch((ulong)c->qid.path) {
211 case Qconsctl:
212 incref(&kbd.ctl);
213 break;
214
215 case Qscancode:
216 qlock(&kbd.gq);
217 if(gkscanq != nil || gkscanid == nil) {
218 qunlock(&kbd.q);
219 c->flag &= ~COPEN;
220 if(gkscanq)
221 error(Einuse);
222 else
223 error("not supported");
224 }
225 gkscanq = qopen(256, 0, nil, nil);
226 qunlock(&kbd.gq);
227 break;
228
229 case Qkprint:
230 wlock(&kprintq.l);
231 if(waserror()){
232 wunlock(&kprintq.l);
233 c->flag &= ~COPEN;
234 nexterror();
235 }
236 if(kprintq.q != nil)
237 error(Einuse);
238 kprintq.q = qopen(32*1024, Qcoalesce, nil, nil);
239 if(kprintq.q == nil)
240 error(Enomem);
241 qnoblock(kprintq.q, 1);
242 poperror();
243 wunlock(&kprintq.l);
244 c->iounit = qiomaxatomic;
245 break;
246 }
247 return c;
248 }
249
250 static void
consclose(Chan * c)251 consclose(Chan *c)
252 {
253 if((c->flag & COPEN) == 0)
254 return;
255
256 switch((ulong)c->qid.path) {
257 case Qconsctl:
258 /* last close of control file turns off raw */
259 if(decref(&kbd.ctl) == 0)
260 kbd.raw = 0;
261 break;
262
263 case Qscancode:
264 qlock(&kbd.gq);
265 if(gkscanq) {
266 qfree(gkscanq);
267 gkscanq = nil;
268 }
269 qunlock(&kbd.gq);
270 break;
271
272 case Qkprint:
273 wlock(&kprintq.l);
274 qfree(kprintq.q);
275 kprintq.q = nil;
276 wunlock(&kprintq.l);
277 break;
278 }
279 }
280
281 static long
consread(Chan * c,void * va,long n,vlong offset)282 consread(Chan *c, void *va, long n, vlong offset)
283 {
284 int send;
285 char buf[64], ch;
286
287 if(c->qid.type & QTDIR)
288 return devdirread(c, va, n, contab, nelem(contab), devgen);
289
290 switch((ulong)c->qid.path) {
291 default:
292 error(Egreg);
293
294 case Qsysctl:
295 return readstr(offset, va, n, VERSION);
296
297 case Qsysname:
298 if(ossysname == nil)
299 return 0;
300 return readstr(offset, va, n, ossysname);
301
302 case Qrandom:
303 return randomread(va, n);
304
305 case Qnotquiterandom:
306 genrandom(va, n);
307 return n;
308
309 case Qhostowner:
310 return readstr(offset, va, n, eve);
311
312 case Qhoststdin:
313 return read(0, va, n); /* should be pread */
314
315 case Quser:
316 return readstr(offset, va, n, up->env->user);
317
318 case Qjit:
319 snprint(buf, sizeof(buf), "%d", cflag);
320 return readstr(offset, va, n, buf);
321
322 case Qtime:
323 snprint(buf, sizeof(buf), "%.lld", timeoffset + osusectime());
324 return readstr(offset, va, n, buf);
325
326 case Qdrivers:
327 return devtabread(c, va, n, offset);
328
329 case Qmemory:
330 return poolread(va, n, offset);
331
332 case Qnull:
333 return 0;
334
335 case Qmsec:
336 return readnum(offset, va, n, osmillisec(), NUMSIZE);
337
338 case Qcons:
339 qlock(&kbd.q);
340 if(waserror()){
341 qunlock(&kbd.q);
342 nexterror();
343 }
344
345 if(dflag)
346 error(Enonexist);
347
348 while(!qcanread(lineq)) {
349 if(qread(kbdq, &ch, 1) == 0)
350 continue;
351 send = 0;
352 if(ch == 0){
353 /* flush output on rawoff -> rawon */
354 if(kbd.x > 0)
355 send = !qcanread(kbdq);
356 }else if(kbd.raw){
357 kbd.line[kbd.x++] = ch;
358 send = !qcanread(kbdq);
359 }else{
360 switch(ch){
361 case '\b':
362 if(kbd.x)
363 kbd.x--;
364 break;
365 case 0x15:
366 kbd.x = 0;
367 break;
368 case 0x04:
369 send = 1;
370 break;
371 case '\n':
372 send = 1;
373 default:
374 kbd.line[kbd.x++] = ch;
375 break;
376 }
377 }
378 if(send || kbd.x == sizeof kbd.line){
379 qwrite(lineq, kbd.line, kbd.x);
380 kbd.x = 0;
381 }
382 }
383 n = qread(lineq, va, n);
384 qunlock(&kbd.q);
385 poperror();
386 return n;
387
388 case Qscancode:
389 if(offset == 0)
390 return readstr(0, va, n, gkscanid);
391 return qread(gkscanq, va, n);
392
393 case Qkeyboard:
394 return qread(gkbdq, va, n);
395
396 case Qkprint:
397 rlock(&kprintq.l);
398 if(waserror()){
399 runlock(&kprintq.l);
400 nexterror();
401 }
402 n = qread(kprintq.q, va, n);
403 poperror();
404 runlock(&kprintq.l);
405 return n;
406 }
407 }
408
409 static long
conswrite(Chan * c,void * va,long n,vlong offset)410 conswrite(Chan *c, void *va, long n, vlong offset)
411 {
412 char buf[128], *a, ch;
413 int x;
414
415 if(c->qid.type & QTDIR)
416 error(Eperm);
417
418 switch((ulong)c->qid.path) {
419 default:
420 error(Egreg);
421
422 case Qcons:
423 if(canrlock(&kprintq.l)){
424 if(kprintq.q != nil){
425 if(waserror()){
426 runlock(&kprintq.l);
427 nexterror();
428 }
429 qwrite(kprintq.q, va, n);
430 poperror();
431 runlock(&kprintq.l);
432 return n;
433 }
434 runlock(&kprintq.l);
435 }
436 return write(1, va, n);
437
438 case Qsysctl:
439 return sysconwrite(va, n);
440
441 case Qconsctl:
442 if(n >= sizeof(buf))
443 n = sizeof(buf)-1;
444 strncpy(buf, va, n);
445 buf[n] = 0;
446 for(a = buf; a;){
447 if(strncmp(a, "rawon", 5) == 0){
448 kbd.raw = 1;
449 /* clumsy hack - wake up reader */
450 ch = 0;
451 qwrite(kbdq, &ch, 1);
452 } else if(strncmp(buf, "rawoff", 6) == 0){
453 kbd.raw = 0;
454 }
455 if((a = strchr(a, ' ')) != nil)
456 a++;
457 }
458 break;
459
460 case Qkeyboard:
461 for(x=0; x<n; ) {
462 Rune r;
463 x += chartorune(&r, &((char*)va)[x]);
464 gkbdputc(gkbdq, r);
465 }
466 break;
467
468 case Qnull:
469 break;
470
471 case Qtime:
472 if(n >= sizeof(buf))
473 n = sizeof(buf)-1;
474 strncpy(buf, va, n);
475 buf[n] = '\0';
476 timeoffset = strtoll(buf, 0, 0)-osusectime();
477 break;
478
479 case Qhostowner:
480 if(!iseve())
481 error(Eperm);
482 if(offset != 0 || n >= sizeof(buf))
483 error(Ebadarg);
484 memmove(buf, va, n);
485 buf[n] = '\0';
486 if(n > 0 && buf[n-1] == '\n')
487 buf[--n] = '\0';
488 if(n == 0)
489 error(Ebadarg);
490 /* renameuser(eve, buf); */
491 /* renameproguser(eve, buf); */
492 kstrdup(&eve, buf);
493 kstrdup(&up->env->user, buf);
494 break;
495
496 case Quser:
497 if(!iseve())
498 error(Eperm);
499 if(offset != 0)
500 error(Ebadarg);
501 if(n <= 0 || n >= sizeof(buf))
502 error(Ebadarg);
503 strncpy(buf, va, n);
504 buf[n] = '\0';
505 if(n > 0 && buf[n-1] == '\n')
506 buf[--n] = '\0';
507 if(n == 0)
508 error(Ebadarg);
509 setid(buf, 0);
510 break;
511
512 case Qhoststdout:
513 return write(1, va, n);
514
515 case Qhoststderr:
516 return write(2, va, n);
517
518 case Qjit:
519 if(n >= sizeof(buf))
520 n = sizeof(buf)-1;
521 strncpy(buf, va, n);
522 buf[n] = '\0';
523 x = atoi(buf);
524 if(x < 0 || x > 9)
525 error(Ebadarg);
526 cflag = x;
527 break;
528
529 case Qsysname:
530 if(offset != 0)
531 error(Ebadarg);
532 if(n < 0 || n >= sizeof(buf))
533 error(Ebadarg);
534 strncpy(buf, va, n);
535 buf[n] = '\0';
536 if(buf[n-1] == '\n')
537 buf[n-1] = 0;
538 kstrdup(&ossysname, buf);
539 break;
540 }
541 return n;
542 }
543
544 static int
sysconwrite(void * va,ulong count)545 sysconwrite(void *va, ulong count)
546 {
547 Cmdbuf *cb;
548 int e;
549 cb = parsecmd(va, count);
550 if(waserror()){
551 free(cb);
552 nexterror();
553 }
554 if(cb->nf == 0)
555 error(Enoctl);
556 if(strcmp(cb->f[0], "reboot") == 0){
557 osreboot(rebootargv[0], rebootargv);
558 error("reboot not supported");
559 }else if(strcmp(cb->f[0], "halt") == 0){
560 if(cb->nf > 1)
561 e = atoi(cb->f[1]);
562 else
563 e = 0;
564 cleanexit(e); /* XXX ignored for the time being (and should be a string anyway) */
565 }else if(strcmp(cb->f[0], "broken") == 0)
566 keepbroken = 1;
567 else if(strcmp(cb->f[0], "nobroken") == 0)
568 keepbroken = 0;
569 else if(strcmp(cb->f[0], "exdebug") == 0)
570 exdebug = !exdebug;
571 else
572 error(Enoctl);
573 poperror();
574 free(cb);
575 return count;
576 }
577
578 Dev consdevtab = {
579 'c',
580 "cons",
581
582 consinit,
583 consattach,
584 conswalk,
585 consstat,
586 consopen,
587 devcreate,
588 consclose,
589 consread,
590 devbread,
591 conswrite,
592 devbwrite,
593 devremove,
594 devwstat
595 };
596
597 static ulong randn;
598
599 static void
seedrand(void)600 seedrand(void)
601 {
602 randomread((void*)&randn, sizeof(randn));
603 }
604
605 int
nrand(int n)606 nrand(int n)
607 {
608 if(randn == 0)
609 seedrand();
610 randn = randn*1103515245 + 12345 + osusectime();
611 return (randn>>16) % n;
612 }
613
614 int
rand(void)615 rand(void)
616 {
617 nrand(1);
618 return randn;
619 }
620
621 ulong
truerand(void)622 truerand(void)
623 {
624 ulong x;
625
626 randomread(&x, sizeof(x));
627 return x;
628 }
629
630 QLock grandomlk;
631
632 void
_genrandomqlock(void)633 _genrandomqlock(void)
634 {
635 qlock(&grandomlk);
636 }
637
638
639 void
_genrandomqunlock(void)640 _genrandomqunlock(void)
641 {
642 qunlock(&grandomlk);
643 }
644