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 /* 308 * mainly for libmp 309 */ 310 void 311 sysfatal(char *fmt, ...) 312 { 313 va_list arg; 314 char buf[64]; 315 316 va_start(arg, fmt); 317 vsnprint(buf, sizeof(buf), fmt, arg); 318 va_end(arg); 319 error(buf); 320 } 321 322 int 323 pprint(char *fmt, ...) 324 { 325 int n; 326 Chan *c; 327 Osenv *o; 328 va_list arg; 329 char buf[2*PRINTSIZE]; 330 331 n = sprint(buf, "%s %ld: ", up->text, up->pid); 332 va_start(arg, fmt); 333 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; 334 va_end(arg); 335 336 o = up->env; 337 if(o->fgrp == 0) { 338 print("%s", buf); 339 return 0; 340 } 341 c = o->fgrp->fd[2]; 342 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) { 343 print("%s", buf); 344 return 0; 345 } 346 347 if(waserror()) { 348 print("%s", buf); 349 return 0; 350 } 351 devtab[c->type]->write(c, buf, n, c->offset); 352 poperror(); 353 354 lock(c); 355 c->offset += n; 356 unlock(c); 357 358 return n; 359 } 360 361 void 362 echo(Rune r, char *buf, int n) 363 { 364 if(kbd.raw) 365 return; 366 367 if(r == '\n'){ 368 if(printq) 369 qiwrite(printq, "\r", 1); 370 } else if(r == 0x15){ 371 buf = "^U\n"; 372 n = 3; 373 } 374 if(consoleprint && screenputs != nil) 375 screenputs(buf, n); 376 if(printq) 377 qiwrite(printq, buf, n); 378 } 379 380 /* 381 * Debug key support. Allows other parts of the kernel to register debug 382 * key handlers, instead of devcons.c having to know whatever's out there. 383 * A kproc is used to invoke most handlers, rather than tying up the CPU at 384 * splhi, which can choke some device drivers (eg softmodem). 385 */ 386 typedef struct { 387 Rune r; 388 char *m; 389 void (*f)(Rune); 390 int i; /* function called at interrupt time */ 391 } Dbgkey; 392 393 static struct { 394 Rendez; 395 Dbgkey *work; 396 Dbgkey keys[50]; 397 int nkeys; 398 int on; 399 } dbg; 400 401 static Dbgkey * 402 finddbgkey(Rune r) 403 { 404 int i; 405 Dbgkey *dp; 406 407 for(dp = dbg.keys, i = 0; i < dbg.nkeys; i++, dp++) 408 if(dp->r == r) 409 return dp; 410 return nil; 411 } 412 413 static int 414 dbgwork(void *) 415 { 416 return dbg.work != 0; 417 } 418 419 static void 420 dbgproc(void *) 421 { 422 Dbgkey *dp; 423 424 setpri(PriRealtime); 425 for(;;) { 426 do { 427 sleep(&dbg, dbgwork, 0); 428 dp = dbg.work; 429 } while(dp == nil); 430 dp->f(dp->r); 431 dbg.work = nil; 432 } 433 } 434 435 void 436 debugkey(Rune r, char *msg, void (*fcn)(), int iflag) 437 { 438 Dbgkey *dp; 439 440 if(dbg.nkeys >= nelem(dbg.keys)) 441 return; 442 if(finddbgkey(r) != nil) 443 return; 444 for(dp = &dbg.keys[dbg.nkeys++] - 1; dp >= dbg.keys; dp--) { 445 if(strcmp(dp->m, msg) < 0) 446 break; 447 dp[1] = dp[0]; 448 } 449 dp++; 450 dp->r = r; 451 dp->m = msg; 452 dp->f = fcn; 453 dp->i = iflag; 454 } 455 456 static int 457 isdbgkey(Rune r) 458 { 459 static int ctrlt; 460 Dbgkey *dp; 461 int echoctrlt = ctrlt; 462 463 /* 464 * ^t hack BUG 465 */ 466 if(dbg.on || (ctrlt >= 2)) { 467 if(r == 0x14 || r == 0x05) { 468 ctrlt++; 469 return 0; 470 } 471 if(dp = finddbgkey(r)) { 472 if(dp->i || ctrlt > 2) 473 dp->f(r); 474 else { 475 dbg.work = dp; 476 wakeup(&dbg); 477 } 478 ctrlt = 0; 479 return 1; 480 } 481 ctrlt = 0; 482 } 483 else if(r == 0x14){ 484 ctrlt++; 485 return 1; 486 } 487 else 488 ctrlt = 0; 489 if(echoctrlt){ 490 char buf[UTFmax]; 491 492 buf[0] = 0x14; 493 while(--echoctrlt >= 0){ 494 echo(buf[0], buf, 1); 495 qproduce(kbdq, buf, 1); 496 } 497 } 498 return 0; 499 } 500 501 static void 502 dbgtoggle(Rune) 503 { 504 dbg.on = !dbg.on; 505 print("Debug keys %s\n", dbg.on ? "HOT" : "COLD"); 506 } 507 508 static void 509 dbghelp(void) 510 { 511 int i; 512 Dbgkey *dp; 513 Dbgkey *dp2; 514 static char fmt[] = "%c: %-22s"; 515 516 dp = dbg.keys; 517 dp2 = dp + (dbg.nkeys + 1)/2; 518 for(i = dbg.nkeys; i > 1; i -= 2, dp++, dp2++) { 519 print(fmt, dp->r, dp->m); 520 print(fmt, dp2->r, dp2->m); 521 print("\n"); 522 } 523 if(i) 524 print(fmt, dp->r, dp->m); 525 print("\n"); 526 } 527 528 static void 529 debuginit(void) 530 { 531 kproc("consdbg", dbgproc, nil, 0); 532 debugkey('|', "HOT|COLD keys", dbgtoggle, 0); 533 debugkey('?', "help", dbghelp, 0); 534 } 535 536 /* 537 * Called by a uart interrupt for console input. 538 * 539 * turn '\r' into '\n' before putting it into the queue. 540 */ 541 int 542 kbdcr2nl(Queue *q, int ch) 543 { 544 if(ch == '\r') 545 ch = '\n'; 546 return kbdputc(q, ch); 547 } 548 549 /* 550 * Put character, possibly a rune, into read queue at interrupt time. 551 * Performs translation for compose sequences 552 * Called at interrupt time to process a character. 553 */ 554 int 555 kbdputc(Queue *q, int ch) 556 { 557 int n; 558 char buf[UTFmax]; 559 Rune r; 560 static Rune kc[15]; 561 static int nk, collecting = 0; 562 563 r = ch; 564 if(r == Latin) { 565 collecting = 1; 566 nk = 0; 567 return 0; 568 } 569 if(collecting) { 570 int c; 571 nk += runetochar((char*)&kc[nk], &r); 572 c = latin1(kc, nk); 573 if(c < -1) /* need more keystrokes */ 574 return 0; 575 collecting = 0; 576 if(c == -1) { /* invalid sequence */ 577 echo(kc[0], (char*)kc, nk); 578 qproduce(q, kc, nk); 579 return 0; 580 } 581 r = (Rune)c; 582 } 583 kbd.c = r; 584 n = runetochar(buf, &r); 585 if(n == 0) 586 return 0; 587 if(!isdbgkey(r)) { 588 echo(r, buf, n); 589 qproduce(q, buf, n); 590 } 591 return 0; 592 } 593 594 void 595 kbdrepeat(int rep) 596 { 597 kbd.repeat = rep; 598 kbd.count = 0; 599 } 600 601 void 602 kbdclock(void) 603 { 604 if(kbd.repeat == 0) 605 return; 606 if(kbd.repeat==1 && ++kbd.count>HZ){ 607 kbd.repeat = 2; 608 kbd.count = 0; 609 return; 610 } 611 if(++kbd.count&1) 612 kbdputc(kbdq, kbd.c); 613 } 614 615 enum{ 616 Qdir, 617 Qcons, 618 Qsysctl, 619 Qconsctl, 620 Qdrivers, 621 Qhostowner, 622 Qkeyboard, 623 Qklog, 624 Qkprint, 625 Qscancode, 626 Qmemory, 627 Qmsec, 628 Qnull, 629 Qrandom, 630 Qnotquiterandom, 631 Qsysname, 632 Qtime, 633 Quser, 634 Qjit, 635 }; 636 637 static Dirtab consdir[]= 638 { 639 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 640 "cons", {Qcons}, 0, 0660, 641 "consctl", {Qconsctl}, 0, 0220, 642 "sysctl", {Qsysctl}, 0, 0644, 643 "drivers", {Qdrivers}, 0, 0444, 644 "hostowner", {Qhostowner}, 0, 0644, 645 "keyboard", {Qkeyboard}, 0, 0666, 646 "klog", {Qklog}, 0, 0444, 647 "kprint", {Qkprint}, 0, 0444, 648 "scancode", {Qscancode}, 0, 0444, 649 "memory", {Qmemory}, 0, 0444, 650 "msec", {Qmsec}, NUMSIZE, 0444, 651 "null", {Qnull}, 0, 0666, 652 "random", {Qrandom}, 0, 0444, 653 "notquiterandom", {Qnotquiterandom}, 0, 0444, 654 "sysname", {Qsysname}, 0, 0664, 655 "time", {Qtime}, 0, 0664, 656 "user", {Quser}, 0, 0644, 657 "jit", {Qjit}, 0, 0666, 658 }; 659 660 ulong boottime; /* seconds since epoch at boot */ 661 662 long 663 seconds(void) 664 { 665 return boottime + TK2SEC(MACHP(0)->ticks); 666 } 667 668 vlong 669 mseconds(void) 670 { 671 return ((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks))); 672 } 673 674 vlong 675 osusectime(void) 676 { 677 return (((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)))*1000); 678 } 679 680 vlong 681 nsec(void) 682 { 683 return osusectime()*1000; /* TO DO */ 684 } 685 686 int 687 readnum(ulong off, char *buf, ulong n, ulong val, int size) 688 { 689 char tmp[64]; 690 691 if(size > 64) size = 64; 692 693 snprint(tmp, sizeof(tmp), "%*.0lud ", size, val); 694 if(off >= size) 695 return 0; 696 if(off+n > size) 697 n = size-off; 698 memmove(buf, tmp+off, n); 699 return n; 700 } 701 702 int 703 readstr(ulong off, char *buf, ulong n, char *str) 704 { 705 int size; 706 707 size = strlen(str); 708 if(off >= size) 709 return 0; 710 if(off+n > size) 711 n = size-off; 712 memmove(buf, str+off, n); 713 return n; 714 } 715 716 void 717 fddump() 718 { 719 Proc *p; 720 Osenv *o; 721 int i; 722 Chan *c; 723 724 p = proctab(6); 725 o = p->env; 726 for(i = 0; i <= o->fgrp->maxfd; i++) { 727 if((c = o->fgrp->fd[i]) == nil) 728 continue; 729 print("%d: %s\n", i, c->name == nil? "???": c->name->s); 730 } 731 } 732 733 static void 734 qpanic(Rune) 735 { 736 panic("User requested panic."); 737 } 738 739 static void 740 rexit(Rune) 741 { 742 exit(0); 743 } 744 745 static void 746 consinit(void) 747 { 748 randominit(); 749 debuginit(); 750 debugkey('f', "files/6", fddump, 0); 751 debugkey('q', "panic", qpanic, 1); 752 debugkey('r', "exit", rexit, 1); 753 klogq = qopen(128*1024, 0, 0, 0); 754 } 755 756 static Chan* 757 consattach(char *spec) 758 { 759 return devattach('c', spec); 760 } 761 762 static Walkqid* 763 conswalk(Chan *c, Chan *nc, char **name, int nname) 764 { 765 return devwalk(c, nc, name, nname, consdir, nelem(consdir), devgen); 766 } 767 768 static int 769 consstat(Chan *c, uchar *dp, int n) 770 { 771 return devstat(c, dp, n, consdir, nelem(consdir), devgen); 772 } 773 774 static void 775 flushkbdline(Queue *q) 776 { 777 if(kbd.x){ 778 qwrite(q, kbd.line, kbd.x); 779 kbd.x = 0; 780 } 781 } 782 783 static Chan* 784 consopen(Chan *c, int omode) 785 { 786 c->aux = 0; 787 switch((ulong)c->qid.path){ 788 case Qconsctl: 789 if(!iseve()) 790 error(Eperm); 791 qlock(&kbd); 792 kbd.ctl++; 793 qunlock(&kbd); 794 break; 795 796 case Qkeyboard: 797 if((omode & 3) != OWRITE) { 798 qlock(&kbd); 799 kbd.kbdr++; 800 flushkbdline(kbdq); 801 kbd.raw = 1; 802 qunlock(&kbd); 803 } 804 break; 805 806 case Qscancode: 807 qlock(&kbd); 808 if(kscanq || !kscanid) { 809 qunlock(&kbd); 810 c->flag &= ~COPEN; 811 if(kscanq) 812 error(Einuse); 813 else 814 error(Ebadarg); 815 } 816 kscanq = qopen(256, 0, nil, nil); 817 qunlock(&kbd); 818 break; 819 820 case Qkprint: 821 if((omode & 3) != OWRITE) { 822 wlock(&kprintq); 823 if(kprintq.q != nil){ 824 wunlock(&kprintq); 825 error(Einuse); 826 } 827 kprintq.q = qopen(32*1024, Qcoalesce, nil, nil); 828 if(kprintq.q == nil){ 829 wunlock(&kprintq); 830 error(Enomem); 831 } 832 qnoblock(kprintq.q, 1); 833 wunlock(&kprintq); 834 c->iounit = qiomaxatomic; 835 } 836 break; 837 } 838 return devopen(c, omode, consdir, nelem(consdir), devgen); 839 } 840 841 static void 842 consclose(Chan *c) 843 { 844 if((c->flag&COPEN) == 0) 845 return; 846 847 switch((ulong)c->qid.path){ 848 case Qconsctl: 849 /* last close of control file turns off raw */ 850 qlock(&kbd); 851 if(--kbd.ctl == 0) 852 kbd.raw = 0; 853 qunlock(&kbd); 854 break; 855 856 case Qkeyboard: 857 if(c->mode != OWRITE) { 858 qlock(&kbd); 859 --kbd.kbdr; 860 qunlock(&kbd); 861 } 862 break; 863 864 case Qscancode: 865 qlock(&kbd); 866 if(kscanq) { 867 qfree(kscanq); 868 kscanq = 0; 869 } 870 qunlock(&kbd); 871 break; 872 873 case Qkprint: 874 wlock(&kprintq); 875 qfree(kprintq.q); 876 kprintq.q = nil; 877 wunlock(&kprintq); 878 break; 879 } 880 } 881 882 static long 883 consread(Chan *c, void *buf, long n, vlong offset) 884 { 885 int l; 886 Osenv *o; 887 int ch, eol, i; 888 char *p, tmp[128]; 889 char *cbuf = buf; 890 891 if(n <= 0) 892 return n; 893 o = up->env; 894 switch((ulong)c->qid.path){ 895 case Qdir: 896 return devdirread(c, buf, n, consdir, nelem(consdir), devgen); 897 case Qsysctl: 898 return readstr(offset, buf, n, VERSION); 899 case Qcons: 900 case Qkeyboard: 901 qlock(&kbd); 902 if(waserror()) { 903 qunlock(&kbd); 904 nexterror(); 905 } 906 if(kbd.raw || kbd.kbdr) { 907 if(qcanread(lineq)) 908 n = qread(lineq, buf, n); 909 else { 910 /* read as much as possible */ 911 do { 912 i = qread(kbdq, cbuf, n); 913 cbuf += i; 914 n -= i; 915 } while(n>0 && qcanread(kbdq)); 916 n = cbuf - (char*)buf; 917 } 918 } else { 919 while(!qcanread(lineq)) { 920 qread(kbdq, &kbd.line[kbd.x], 1); 921 ch = kbd.line[kbd.x]; 922 eol = 0; 923 switch(ch){ 924 case '\b': 925 if(kbd.x) 926 kbd.x--; 927 break; 928 case 0x15: 929 kbd.x = 0; 930 break; 931 case '\n': 932 case 0x04: 933 eol = 1; 934 default: 935 kbd.line[kbd.x++] = ch; 936 break; 937 } 938 if(kbd.x == sizeof(kbd.line) || eol) { 939 if(ch == 0x04) 940 kbd.x--; 941 qwrite(lineq, kbd.line, kbd.x); 942 kbd.x = 0; 943 } 944 } 945 n = qread(lineq, buf, n); 946 } 947 qunlock(&kbd); 948 poperror(); 949 return n; 950 951 case Qscancode: 952 if(offset == 0) 953 return readstr(0, buf, n, kscanid); 954 else 955 return qread(kscanq, buf, n); 956 957 case Qtime: 958 snprint(tmp, sizeof(tmp), "%.lld", (vlong)mseconds()*1000); 959 return readstr(offset, buf, n, tmp); 960 961 case Qhostowner: 962 return readstr(offset, buf, n, eve); 963 964 case Quser: 965 return readstr(offset, buf, n, o->user); 966 967 case Qjit: 968 snprint(tmp, sizeof(tmp), "%d", cflag); 969 return readstr(offset, buf, n, tmp); 970 971 case Qnull: 972 return 0; 973 974 case Qmsec: 975 return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE); 976 977 case Qsysname: 978 if(sysname == nil) 979 return 0; 980 return readstr(offset, buf, n, sysname); 981 982 case Qnotquiterandom: 983 genrandom(buf, n); 984 return n; 985 986 case Qrandom: 987 return randomread(buf, n); 988 989 case Qmemory: 990 return poolread(buf, n, offset); 991 992 case Qdrivers: 993 p = malloc(READSTR); 994 if(p == nil) 995 error(Enomem); 996 l = 0; 997 for(i = 0; devtab[i] != nil; i++) 998 l += snprint(p+l, READSTR-l, "#%C %s\n", devtab[i]->dc, devtab[i]->name); 999 if(waserror()){ 1000 free(p); 1001 nexterror(); 1002 } 1003 n = readstr(offset, buf, n, p); 1004 free(p); 1005 poperror(); 1006 return n; 1007 1008 case Qklog: 1009 return qread(klogq, buf, n); 1010 1011 case Qkprint: 1012 rlock(&kprintq); 1013 if(waserror()){ 1014 runlock(&kprintq); 1015 nexterror(); 1016 } 1017 n = qread(kprintq.q, buf, n); 1018 poperror(); 1019 runlock(&kprintq); 1020 return n; 1021 1022 default: 1023 print("consread %llud\n", c->qid.path); 1024 error(Egreg); 1025 } 1026 return -1; /* never reached */ 1027 } 1028 1029 static long 1030 conswrite(Chan *c, void *va, long n, vlong offset) 1031 { 1032 vlong t; 1033 long l, bp; 1034 char *a = va; 1035 Cmdbuf *cb; 1036 Cmdtab *ct; 1037 char buf[256]; 1038 int x; 1039 1040 switch((ulong)c->qid.path){ 1041 case Qcons: 1042 /* 1043 * Can't page fault in putstrn, so copy the data locally. 1044 */ 1045 l = n; 1046 while(l > 0){ 1047 bp = l; 1048 if(bp > sizeof buf) 1049 bp = sizeof buf; 1050 memmove(buf, a, bp); 1051 putstrn0(a, bp, 1); 1052 a += bp; 1053 l -= bp; 1054 } 1055 break; 1056 1057 case Qconsctl: 1058 if(n >= sizeof(buf)) 1059 n = sizeof(buf)-1; 1060 strncpy(buf, a, n); 1061 buf[n] = 0; 1062 for(a = buf; a;){ 1063 if(strncmp(a, "rawon", 5) == 0){ 1064 qlock(&kbd); 1065 flushkbdline(kbdq); 1066 kbd.raw = 1; 1067 qunlock(&kbd); 1068 } else if(strncmp(a, "rawoff", 6) == 0){ 1069 qlock(&kbd); 1070 kbd.raw = 0; 1071 kbd.x = 0; 1072 qunlock(&kbd); 1073 } 1074 if(a = strchr(a, ' ')) 1075 a++; 1076 } 1077 break; 1078 1079 case Qkeyboard: 1080 for(x=0; x<n; ) { 1081 Rune r; 1082 x += chartorune(&r, &a[x]); 1083 kbdputc(kbdq, r); 1084 } 1085 break; 1086 1087 case Qtime: 1088 if(n >= sizeof(buf)) 1089 n = sizeof(buf)-1; 1090 strncpy(buf, a, n); 1091 buf[n] = 0; 1092 t = strtoll(buf, 0, 0)/1000000; 1093 boottime = t - TK2SEC(MACHP(0)->ticks); 1094 break; 1095 1096 case Qhostowner: 1097 if(!iseve()) 1098 error(Eperm); 1099 if(offset != 0 || n >= sizeof(buf)) 1100 error(Ebadarg); 1101 memmove(buf, a, n); 1102 buf[n] = '\0'; 1103 if(n > 0 && buf[n-1] == '\n') 1104 buf[--n] = 0; 1105 if(n <= 0) 1106 error(Ebadarg); 1107 renameuser(eve, buf); 1108 renameproguser(eve, buf); 1109 kstrdup(&eve, buf); 1110 kstrdup(&up->env->user, buf); 1111 break; 1112 1113 case Quser: 1114 if(!iseve()) 1115 error(Eperm); 1116 if(offset != 0) 1117 error(Ebadarg); 1118 if(n <= 0 || n >= sizeof(buf)) 1119 error(Ebadarg); 1120 strncpy(buf, a, n); 1121 buf[n] = 0; 1122 if(buf[n-1] == '\n') 1123 buf[n-1] = 0; 1124 kstrdup(&up->env->user, buf); 1125 break; 1126 1127 case Qjit: 1128 if(n >= sizeof(buf)) 1129 n = sizeof(buf)-1; 1130 strncpy(buf, va, n); 1131 buf[n] = '\0'; 1132 x = atoi(buf); 1133 if(x < 0 || x > 9) 1134 error(Ebadarg); 1135 cflag = x; 1136 return n; 1137 1138 case Qnull: 1139 break; 1140 1141 case Qsysname: 1142 if(offset != 0) 1143 error(Ebadarg); 1144 if(n <= 0 || n >= sizeof(buf)) 1145 error(Ebadarg); 1146 strncpy(buf, a, n); 1147 buf[n] = 0; 1148 if(buf[n-1] == '\n') 1149 buf[n-1] = 0; 1150 kstrdup(&sysname, buf); 1151 break; 1152 1153 case Qsysctl: 1154 if(!iseve()) 1155 error(Eperm); 1156 cb = parsecmd(a, n); 1157 if(waserror()){ 1158 free(cb); 1159 nexterror(); 1160 } 1161 ct = lookupcmd(cb, sysctlcmd, nelem(sysctlcmd)); 1162 switch(ct->index){ 1163 case CMreboot: 1164 reboot(); 1165 break; 1166 case CMhalt: 1167 halt(); 1168 break; 1169 case CMpanic: 1170 panic("sysctl"); 1171 case CMconsole: 1172 consoleprint = strcmp(cb->f[1], "off") != 0; 1173 break; 1174 case CMbroken: 1175 keepbroken = 1; 1176 break; 1177 case CMnobroken: 1178 keepbroken = 0; 1179 break; 1180 } 1181 poperror(); 1182 free(cb); 1183 break; 1184 1185 default: 1186 print("conswrite: %llud\n", c->qid.path); 1187 error(Egreg); 1188 } 1189 return n; 1190 } 1191 1192 Dev consdevtab = { 1193 'c', 1194 "cons", 1195 1196 devreset, 1197 consinit, 1198 devshutdown, 1199 consattach, 1200 conswalk, 1201 consstat, 1202 consopen, 1203 devcreate, 1204 consclose, 1205 consread, 1206 devbread, 1207 conswrite, 1208 devbwrite, 1209 devremove, 1210 devwstat, 1211 }; 1212 1213 static ulong randn; 1214 1215 static void 1216 seedrand(void) 1217 { 1218 randomread((void*)&randn, sizeof(randn)); 1219 } 1220 1221 int 1222 nrand(int n) 1223 { 1224 if(randn == 0) 1225 seedrand(); 1226 randn = randn*1103515245 + 12345 + MACHP(0)->ticks; 1227 return (randn>>16) % n; 1228 } 1229 1230 int 1231 rand(void) 1232 { 1233 nrand(1); 1234 return randn; 1235 } 1236 1237 ulong 1238 truerand(void) 1239 { 1240 ulong x; 1241 1242 randomread(&x, sizeof(x)); 1243 return x; 1244 } 1245 1246 QLock grandomlk; 1247 1248 void 1249 _genrandomqlock(void) 1250 { 1251 qlock(&grandomlk); 1252 } 1253 1254 1255 void 1256 _genrandomqunlock(void) 1257 { 1258 qunlock(&grandomlk); 1259 } 1260