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 write(1, &b, 1); 112 qproduce(kbdq, &b, 1); 113 } 114 pexit("kbdslave", 0); 115 } 116 117 void 118 gkbdputc(Queue *q, int ch) 119 { 120 int n; 121 Rune r; 122 static uchar kc[5*UTFmax]; 123 static int nk, collecting = 0; 124 char buf[UTFmax]; 125 126 r = ch; 127 if(r == Latin) { 128 collecting = 1; 129 nk = 0; 130 return; 131 } 132 if(collecting) { 133 int c; 134 nk += runetochar((char*)&kc[nk], &r); 135 c = latin1(kc, nk); 136 if(c < -1) /* need more keystrokes */ 137 return; 138 collecting = 0; 139 if(c == -1) { /* invalid sequence */ 140 qproduce(q, kc, nk); 141 return; 142 } 143 r = (Rune)c; 144 } 145 n = runetochar(buf, &r); 146 if(n == 0) 147 return; 148 /* if(!isdbgkey(r)) */ 149 qproduce(q, buf, n); 150 } 151 152 void 153 consinit(void) 154 { 155 kbdq = qopen(512, 0, 0, 0); 156 if(kbdq == 0) 157 panic("no memory"); 158 lineq = qopen(512, 0, 0, 0); 159 if(lineq == 0) 160 panic("no memory"); 161 gkbdq = qopen(512, 0, 0, 0); 162 if(gkbdq == 0) 163 panic("no memory"); 164 randominit(); 165 } 166 167 /* 168 * return true if current user is eve 169 */ 170 int 171 iseve(void) 172 { 173 return strcmp(eve, up->env->user) == 0; 174 } 175 176 static Chan* 177 consattach(char *spec) 178 { 179 static int kp; 180 181 if (kp == 0 && !dflag) { 182 kproc("kbd", kbdslave, 0, 0); 183 kp = 1; 184 } 185 return devattach('c', spec); 186 } 187 188 static Walkqid* 189 conswalk(Chan *c, Chan *nc, char **name, int nname) 190 { 191 return devwalk(c, nc, name, nname, contab, nelem(contab), devgen); 192 } 193 194 static int 195 consstat(Chan *c, uchar *db, int n) 196 { 197 return devstat(c, db, n, contab, nelem(contab), devgen); 198 } 199 200 static Chan* 201 consopen(Chan *c, int omode) 202 { 203 c = devopen(c, omode, contab, nelem(contab), devgen); 204 switch((ulong)c->qid.path) { 205 case Qconsctl: 206 incref(&kbd.ctl); 207 break; 208 case Qscancode: 209 qlock(&kbd.gq); 210 if(gkscanq || !gkscanid) { 211 qunlock(&kbd.q); 212 c->flag &= ~COPEN; 213 if(gkscanq) 214 error(Einuse); 215 else 216 error(Ebadarg); 217 } 218 gkscanq = qopen(256, 0, nil, nil); 219 qunlock(&kbd.gq); 220 break; 221 case Qkprint: 222 wlock(&kprintq.l); 223 if(kprintq.q != nil){ 224 wunlock(&kprintq.l); 225 c->flag &= ~COPEN; 226 error(Einuse); 227 } 228 kprintq.q = qopen(32*1024, 0, 0, 0); 229 if(kprintq.q == nil){ 230 wunlock(&kprintq.l); 231 c->flag &= ~COPEN; 232 error(Enomem); 233 } 234 qnoblock(kprintq.q, 1); 235 wunlock(&kprintq.l); 236 break; 237 } 238 return c; 239 } 240 241 static void 242 consclose(Chan *c) 243 { 244 if((c->flag & COPEN) == 0) 245 return; 246 247 switch((ulong)c->qid.path) { 248 case Qconsctl: 249 if(decref(&kbd.ctl) == 0) 250 kbd.raw = 0; 251 break; 252 case Qscancode: 253 qlock(&kbd.gq); 254 if(gkscanq) { 255 qfree(gkscanq); 256 gkscanq = 0; 257 } 258 qunlock(&kbd.gq); 259 break; 260 case Qkprint: 261 wlock(&kprintq.l); 262 qfree(kprintq.q); 263 kprintq.q = nil; 264 wunlock(&kprintq.l); 265 break; 266 } 267 } 268 269 static long 270 consread(Chan *c, void *va, long count, vlong offset) 271 { 272 int i, n, ch, eol; 273 char *p, buf[64]; 274 275 if(c->qid.type & QTDIR) 276 return devdirread(c, va, count, contab, nelem(contab), devgen); 277 278 switch((ulong)c->qid.path) { 279 default: 280 error(Egreg); 281 case Qsysctl: 282 return readstr(offset, va, count, VERSION); 283 case Qsysname: 284 if(ossysname == nil) 285 return 0; 286 return readstr(offset, va, count, ossysname); 287 case Qrandom: 288 return randomread(va, count); 289 case Qnotquiterandom: 290 genrandom(va, count); 291 return count; 292 case Qpin: 293 p = "pin set"; 294 if(up->env->pgrp->pin == Nopin) 295 p = "no pin"; 296 return readstr(offset, va, count, p); 297 case Qhostowner: 298 return readstr(offset, va, count, eve); 299 case Qhoststdin: 300 return read(0, va, count); /* should be pread */ 301 case Quser: 302 return readstr(offset, va, count, up->env->user); 303 case Qjit: 304 snprint(buf, sizeof(buf), "%d", cflag); 305 return readstr(offset, va, count, buf); 306 case Qtime: 307 snprint(buf, sizeof(buf), "%.lld", timeoffset + osusectime()); 308 return readstr(offset, va, count, buf); 309 case Qdrivers: 310 p = malloc(READSTR); 311 if(p == nil) 312 error(Enomem); 313 n = 0; 314 for(i = 0; devtab[i] != nil; i++) 315 n += snprint(p+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name); 316 n = readstr(offset, va, count, p); 317 free(p); 318 return n; 319 case Qmemory: 320 return poolread(va, count, offset); 321 322 case Qnull: 323 return 0; 324 case Qmsec: 325 return readnum(offset, va, count, osmillisec(), NUMSIZE); 326 case Qcons: 327 qlock(&kbd.q); 328 if(waserror()){ 329 qunlock(&kbd.q); 330 nexterror(); 331 } 332 333 if(dflag) 334 error(Enonexist); 335 336 while(!qcanread(lineq)) { 337 qread(kbdq, &kbd.line[kbd.x], 1); 338 ch = kbd.line[kbd.x]; 339 if(kbd.raw){ 340 qiwrite(lineq, &kbd.line[kbd.x], 1); 341 continue; 342 } 343 eol = 0; 344 switch(ch) { 345 case '\b': 346 if(kbd.x) 347 kbd.x--; 348 break; 349 case 0x15: 350 kbd.x = 0; 351 break; 352 case '\n': 353 case 0x04: 354 eol = 1; 355 default: 356 kbd.line[kbd.x++] = ch; 357 break; 358 } 359 if(kbd.x == sizeof(kbd.line) || eol){ 360 if(ch == 0x04) 361 kbd.x--; 362 qwrite(lineq, kbd.line, kbd.x); 363 kbd.x = 0; 364 } 365 } 366 n = qread(lineq, va, count); 367 qunlock(&kbd.q); 368 poperror(); 369 return n; 370 case Qscancode: 371 if(offset == 0) 372 return readstr(0, va, count, gkscanid); 373 else 374 return qread(gkscanq, va, count); 375 case Qkeyboard: 376 return qread(gkbdq, va, count); 377 case Qkprint: 378 rlock(&kprintq.l); 379 if(waserror()){ 380 runlock(&kprintq.l); 381 nexterror(); 382 } 383 n = qread(kprintq.q, va, count); 384 poperror(); 385 runlock(&kprintq.l); 386 return n; 387 } 388 } 389 390 static long 391 conswrite(Chan *c, void *va, long count, vlong offset) 392 { 393 char buf[128]; 394 int x; 395 396 USED(offset); 397 398 if(c->qid.type & QTDIR) 399 error(Eperm); 400 401 switch((ulong)c->qid.path) { 402 default: 403 error(Egreg); 404 case Qcons: 405 if(canrlock(&kprintq.l)){ 406 if(kprintq.q != nil){ 407 if(waserror()){ 408 runlock(&kprintq.l); 409 nexterror(); 410 } 411 qwrite(kprintq.q, va, count); 412 poperror(); 413 runlock(&kprintq.l); 414 return count; 415 } 416 runlock(&kprintq.l); 417 } 418 return write(1, va, count); 419 case Qsysctl: 420 return sysconwrite(va, count); 421 case Qconsctl: 422 if(count >= sizeof(buf)) 423 count = sizeof(buf)-1; 424 strncpy(buf, va, count); 425 buf[count] = 0; 426 if(strncmp(buf, "rawon", 5) == 0) { 427 kbd.raw = 1; 428 return count; 429 } 430 else 431 if(strncmp(buf, "rawoff", 6) == 0) { 432 kbd.raw = 0; 433 return count; 434 } 435 error(Ebadctl); 436 case Qkeyboard: 437 for(x=0; x<count; ) { 438 Rune r; 439 x += chartorune(&r, &((char*)va)[x]); 440 gkbdputc(gkbdq, r); 441 } 442 return count; 443 case Qnull: 444 return count; 445 case Qpin: 446 if(up->env->pgrp->pin != Nopin) 447 error("pin already set"); 448 if(count >= sizeof(buf)) 449 count = sizeof(buf)-1; 450 strncpy(buf, va, count); 451 buf[count] = '\0'; 452 up->env->pgrp->pin = atoi(buf); 453 return count; 454 case Qtime: 455 if(count >= sizeof(buf)) 456 count = sizeof(buf)-1; 457 strncpy(buf, va, count); 458 buf[count] = '\0'; 459 timeoffset = strtoll(buf, 0, 0)-osusectime(); 460 return count; 461 case Quser: 462 if(count >= sizeof(buf)) 463 error(Ebadarg); 464 strncpy(buf, va, count); 465 buf[count] = '\0'; 466 if(count > 0 && buf[count-1] == '\n') 467 buf[--count] = '\0'; 468 if(count == 0) 469 error(Ebadarg); 470 if(strcmp(up->env->user, eve) != 0) 471 error(Eperm); 472 setid(buf, 0); 473 return count; 474 case Qhostowner: 475 if(count >= sizeof(buf)) 476 error(Ebadarg); 477 strncpy(buf, va, count); 478 buf[count] = '\0'; 479 if(count > 0 && buf[count-1] == '\n') 480 buf[--count] = '\0'; 481 if(count == 0) 482 error(Ebadarg); 483 if(strcmp(up->env->user, eve) != 0) 484 error(Eperm); 485 kstrdup(&eve, buf); 486 return count; 487 case Qhoststdout: 488 return write(1, va, count); 489 case Qhoststderr: 490 return write(2, va, count); 491 case Qjit: 492 if(count >= sizeof(buf)) 493 count = sizeof(buf)-1; 494 strncpy(buf, va, count); 495 buf[count] = '\0'; 496 x = atoi(buf); 497 if (x < 0 || x > 9) 498 error(Ebadarg); 499 cflag = x; 500 return count; 501 case Qsysname: 502 if(count >= sizeof(buf)) 503 count = sizeof(buf)-1; 504 strncpy(buf, va, count); 505 buf[count] = '\0'; 506 kstrdup(&ossysname, buf); 507 return count; 508 } 509 return 0; 510 } 511 512 static int 513 sysconwrite(void *va, ulong count) 514 { 515 Cmdbuf *cb; 516 int e; 517 cb = parsecmd(va, count); 518 if(waserror()){ 519 free(cb); 520 nexterror(); 521 } 522 if(cb->nf == 0) 523 error(Enoctl); 524 if(strcmp(cb->f[0], "reboot") == 0){ 525 osreboot(rebootargv[0], rebootargv); 526 error("reboot not supported"); 527 }else if(strcmp(cb->f[0], "halt") == 0){ 528 if(cb->nf > 1) 529 e = atoi(cb->f[1]); 530 else 531 e = 0; 532 cleanexit(e); /* XXX ignored for the time being (and should be a string anyway) */ 533 }else if(strcmp(cb->f[0], "broken") == 0) 534 keepbroken = 1; 535 else if(strcmp(cb->f[0], "nobroken") == 0) 536 keepbroken = 0; 537 else if(strcmp(cb->f[0], "exdebug") == 0) 538 exdebug = !exdebug; 539 else 540 error(Enoctl); 541 poperror(); 542 free(cb); 543 return count; 544 } 545 546 Dev consdevtab = { 547 'c', 548 "cons", 549 550 consinit, 551 consattach, 552 conswalk, 553 consstat, 554 consopen, 555 devcreate, 556 consclose, 557 consread, 558 devbread, 559 conswrite, 560 devbwrite, 561 devremove, 562 devwstat 563 }; 564 565 static ulong randn; 566 567 static void 568 seedrand(void) 569 { 570 randomread((void*)&randn, sizeof(randn)); 571 } 572 573 int 574 nrand(int n) 575 { 576 if(randn == 0) 577 seedrand(); 578 randn = randn*1103515245 + 12345 + osusectime(); 579 return (randn>>16) % n; 580 } 581 582 int 583 rand(void) 584 { 585 nrand(1); 586 return randn; 587 } 588 589 ulong 590 truerand(void) 591 { 592 ulong x; 593 594 randomread(&x, sizeof(x)); 595 return x; 596 } 597 598 QLock grandomlk; 599 600 void 601 _genrandomqlock(void) 602 { 603 qlock(&grandomlk); 604 } 605 606 607 void 608 _genrandomqunlock(void) 609 { 610 qunlock(&grandomlk); 611 } 612