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