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