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 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 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 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 177 iseve(void) 178 { 179 return strcmp(eve, up->env->user) == 0; 180 } 181 182 static Chan* 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* 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 201 consstat(Chan *c, uchar *db, int n) 202 { 203 return devstat(c, db, n, contab, nelem(contab), devgen); 204 } 205 206 static Chan* 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 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 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 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 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 600 seedrand(void) 601 { 602 randomread((void*)&randn, sizeof(randn)); 603 } 604 605 int 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 615 rand(void) 616 { 617 nrand(1); 618 return randn; 619 } 620 621 ulong 622 truerand(void) 623 { 624 ulong x; 625 626 randomread(&x, sizeof(x)); 627 return x; 628 } 629 630 QLock grandomlk; 631 632 void 633 _genrandomqlock(void) 634 { 635 qlock(&grandomlk); 636 } 637 638 639 void 640 _genrandomqunlock(void) 641 { 642 qunlock(&grandomlk); 643 } 644