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[3]; 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[3]; 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 Qpin, 630 Qrandom, 631 Qnotquiterandom, 632 Qsysname, 633 Qtime, 634 Quser, 635 Qjit, 636 }; 637 638 static Dirtab consdir[]= 639 { 640 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 641 "cons", {Qcons}, 0, 0660, 642 "consctl", {Qconsctl}, 0, 0220, 643 "sysctl", {Qsysctl}, 0, 0644, 644 "drivers", {Qdrivers}, 0, 0444, 645 "hostowner", {Qhostowner}, 0, 0644, 646 "keyboard", {Qkeyboard}, 0, 0666, 647 "klog", {Qklog}, 0, 0444, 648 "kprint", {Qkprint}, 0, 0444, 649 "scancode", {Qscancode}, 0, 0444, 650 "memory", {Qmemory}, 0, 0444, 651 "msec", {Qmsec}, NUMSIZE, 0444, 652 "null", {Qnull}, 0, 0666, 653 "pin", {Qpin}, 0, 0666, 654 "random", {Qrandom}, 0, 0444, 655 "notquiterandom", {Qnotquiterandom}, 0, 0444, 656 "sysname", {Qsysname}, 0, 0664, 657 "time", {Qtime}, 0, 0664, 658 "user", {Quser}, 0, 0644, 659 "jit", {Qjit}, 0, 0666, 660 }; 661 662 ulong boottime; /* seconds since epoch at boot */ 663 664 long 665 seconds(void) 666 { 667 return boottime + TK2SEC(MACHP(0)->ticks); 668 } 669 670 vlong 671 mseconds(void) 672 { 673 return ((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks))); 674 } 675 676 vlong 677 osusectime(void) 678 { 679 return (((vlong)boottime*1000)+((vlong)(TK2MS(MACHP(0)->ticks)))*1000); 680 } 681 682 vlong 683 nsec(void) 684 { 685 return osusectime()*1000; /* TO DO */ 686 } 687 688 int 689 readnum(ulong off, char *buf, ulong n, ulong val, int size) 690 { 691 char tmp[64]; 692 693 if(size > 64) size = 64; 694 695 snprint(tmp, sizeof(tmp), "%*.0lud ", size, val); 696 if(off >= size) 697 return 0; 698 if(off+n > size) 699 n = size-off; 700 memmove(buf, tmp+off, n); 701 return n; 702 } 703 704 int 705 readstr(ulong off, char *buf, ulong n, char *str) 706 { 707 int size; 708 709 size = strlen(str); 710 if(off >= size) 711 return 0; 712 if(off+n > size) 713 n = size-off; 714 memmove(buf, str+off, n); 715 return n; 716 } 717 718 void 719 fddump() 720 { 721 Proc *p; 722 Osenv *o; 723 int i; 724 Chan *c; 725 726 p = proctab(6); 727 o = p->env; 728 for(i = 0; i <= o->fgrp->maxfd; i++) { 729 if((c = o->fgrp->fd[i]) == nil) 730 continue; 731 print("%d: %s\n", i, c->name == nil? "???": c->name->s); 732 } 733 } 734 735 static void 736 qpanic(Rune) 737 { 738 panic("User requested panic."); 739 } 740 741 static void 742 rexit(Rune) 743 { 744 exit(0); 745 } 746 747 static void 748 consinit(void) 749 { 750 randominit(); 751 debuginit(); 752 debugkey('f', "files/6", fddump, 0); 753 debugkey('q', "panic", qpanic, 1); 754 debugkey('r', "exit", rexit, 1); 755 klogq = qopen(128*1024, 0, 0, 0); 756 } 757 758 static Chan* 759 consattach(char *spec) 760 { 761 return devattach('c', spec); 762 } 763 764 static Walkqid* 765 conswalk(Chan *c, Chan *nc, char **name, int nname) 766 { 767 return devwalk(c, nc, name, nname, consdir, nelem(consdir), devgen); 768 } 769 770 static int 771 consstat(Chan *c, uchar *dp, int n) 772 { 773 return devstat(c, dp, n, consdir, nelem(consdir), devgen); 774 } 775 776 static void 777 flushkbdline(Queue *q) 778 { 779 if(kbd.x){ 780 qwrite(q, kbd.line, kbd.x); 781 kbd.x = 0; 782 } 783 } 784 785 static Chan* 786 consopen(Chan *c, int omode) 787 { 788 c->aux = 0; 789 switch((ulong)c->qid.path){ 790 case Qconsctl: 791 if(!iseve()) 792 error(Eperm); 793 qlock(&kbd); 794 kbd.ctl++; 795 qunlock(&kbd); 796 break; 797 798 case Qkeyboard: 799 if((omode & 3) != OWRITE) { 800 qlock(&kbd); 801 kbd.kbdr++; 802 flushkbdline(kbdq); 803 kbd.raw = 1; 804 qunlock(&kbd); 805 } 806 break; 807 808 case Qscancode: 809 qlock(&kbd); 810 if(kscanq || !kscanid) { 811 qunlock(&kbd); 812 c->flag &= ~COPEN; 813 if(kscanq) 814 error(Einuse); 815 else 816 error(Ebadarg); 817 } 818 kscanq = qopen(256, 0, nil, nil); 819 qunlock(&kbd); 820 break; 821 822 case Qkprint: 823 if((omode & 3) != OWRITE) { 824 wlock(&kprintq); 825 if(kprintq.q != nil){ 826 wunlock(&kprintq); 827 error(Einuse); 828 } 829 kprintq.q = qopen(32*1024, Qcoalesce, nil, nil); 830 if(kprintq.q == nil){ 831 wunlock(&kprintq); 832 error(Enomem); 833 } 834 qnoblock(kprintq.q, 1); 835 wunlock(&kprintq); 836 c->iounit = qiomaxatomic; 837 } 838 break; 839 } 840 return devopen(c, omode, consdir, nelem(consdir), devgen); 841 } 842 843 static void 844 consclose(Chan *c) 845 { 846 if((c->flag&COPEN) == 0) 847 return; 848 849 switch((ulong)c->qid.path){ 850 case Qconsctl: 851 /* last close of control file turns off raw */ 852 qlock(&kbd); 853 if(--kbd.ctl == 0) 854 kbd.raw = 0; 855 qunlock(&kbd); 856 break; 857 858 case Qkeyboard: 859 if(c->mode != OWRITE) { 860 qlock(&kbd); 861 --kbd.kbdr; 862 qunlock(&kbd); 863 } 864 break; 865 866 case Qscancode: 867 qlock(&kbd); 868 if(kscanq) { 869 qfree(kscanq); 870 kscanq = 0; 871 } 872 qunlock(&kbd); 873 break; 874 875 case Qkprint: 876 wlock(&kprintq); 877 qfree(kprintq.q); 878 kprintq.q = nil; 879 wunlock(&kprintq); 880 break; 881 } 882 } 883 884 static long 885 consread(Chan *c, void *buf, long n, vlong offset) 886 { 887 int l; 888 Osenv *o; 889 int ch, eol, i; 890 char *p, tmp[128]; 891 char *cbuf = buf; 892 893 if(n <= 0) 894 return n; 895 o = up->env; 896 switch((ulong)c->qid.path){ 897 case Qdir: 898 return devdirread(c, buf, n, consdir, nelem(consdir), devgen); 899 case Qsysctl: 900 return readstr(offset, buf, n, VERSION); 901 case Qcons: 902 case Qkeyboard: 903 qlock(&kbd); 904 if(waserror()) { 905 qunlock(&kbd); 906 nexterror(); 907 } 908 if(kbd.raw || kbd.kbdr) { 909 if(qcanread(lineq)) 910 n = qread(lineq, buf, n); 911 else { 912 /* read as much as possible */ 913 do { 914 i = qread(kbdq, cbuf, n); 915 cbuf += i; 916 n -= i; 917 } while(n>0 && qcanread(kbdq)); 918 n = cbuf - (char*)buf; 919 } 920 } else { 921 while(!qcanread(lineq)) { 922 qread(kbdq, &kbd.line[kbd.x], 1); 923 ch = kbd.line[kbd.x]; 924 eol = 0; 925 switch(ch){ 926 case '\b': 927 if(kbd.x) 928 kbd.x--; 929 break; 930 case 0x15: 931 kbd.x = 0; 932 break; 933 case '\n': 934 case 0x04: 935 eol = 1; 936 default: 937 kbd.line[kbd.x++] = ch; 938 break; 939 } 940 if(kbd.x == sizeof(kbd.line) || eol) { 941 if(ch == 0x04) 942 kbd.x--; 943 qwrite(lineq, kbd.line, kbd.x); 944 kbd.x = 0; 945 } 946 } 947 n = qread(lineq, buf, n); 948 } 949 qunlock(&kbd); 950 poperror(); 951 return n; 952 953 case Qscancode: 954 if(offset == 0) 955 return readstr(0, buf, n, kscanid); 956 else 957 return qread(kscanq, buf, n); 958 959 case Qpin: 960 p = "pin set"; 961 if(up->env->pgrp->pin == Nopin) 962 p = "no pin"; 963 return readstr(offset, buf, n, p); 964 965 case Qtime: 966 snprint(tmp, sizeof(tmp), "%.lld", (vlong)mseconds()*1000); 967 return readstr(offset, buf, n, tmp); 968 969 case Qhostowner: 970 return readstr(offset, buf, n, eve); 971 972 case Quser: 973 return readstr(offset, buf, n, o->user); 974 975 case Qjit: 976 snprint(tmp, sizeof(tmp), "%d", cflag); 977 return readstr(offset, buf, n, tmp); 978 979 case Qnull: 980 return 0; 981 982 case Qmsec: 983 return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE); 984 985 case Qsysname: 986 if(sysname == nil) 987 return 0; 988 return readstr(offset, buf, n, sysname); 989 990 case Qnotquiterandom: 991 genrandom(buf, n); 992 return n; 993 994 case Qrandom: 995 return randomread(buf, n); 996 997 case Qmemory: 998 return poolread(buf, n, offset); 999 1000 case Qdrivers: 1001 p = malloc(READSTR); 1002 if(p == nil) 1003 error(Enomem); 1004 l = 0; 1005 for(i = 0; devtab[i] != nil; i++) 1006 l += snprint(p+l, READSTR-l, "#%C %s\n", devtab[i]->dc, devtab[i]->name); 1007 if(waserror()){ 1008 free(p); 1009 nexterror(); 1010 } 1011 n = readstr(offset, buf, n, p); 1012 free(p); 1013 poperror(); 1014 return n; 1015 1016 case Qklog: 1017 return qread(klogq, buf, n); 1018 1019 case Qkprint: 1020 rlock(&kprintq); 1021 if(waserror()){ 1022 runlock(&kprintq); 1023 nexterror(); 1024 } 1025 n = qread(kprintq.q, buf, n); 1026 poperror(); 1027 runlock(&kprintq); 1028 return n; 1029 1030 default: 1031 print("consread %llud\n", c->qid.path); 1032 error(Egreg); 1033 } 1034 return -1; /* never reached */ 1035 } 1036 1037 static long 1038 conswrite(Chan *c, void *va, long n, vlong offset) 1039 { 1040 vlong t; 1041 long l, bp; 1042 char *a = va; 1043 Cmdbuf *cb; 1044 Cmdtab *ct; 1045 char buf[256]; 1046 int x; 1047 1048 switch((ulong)c->qid.path){ 1049 case Qcons: 1050 /* 1051 * Can't page fault in putstrn, so copy the data locally. 1052 */ 1053 l = n; 1054 while(l > 0){ 1055 bp = l; 1056 if(bp > sizeof buf) 1057 bp = sizeof buf; 1058 memmove(buf, a, bp); 1059 putstrn0(a, bp, 1); 1060 a += bp; 1061 l -= bp; 1062 } 1063 break; 1064 1065 case Qconsctl: 1066 if(n >= sizeof(buf)) 1067 n = sizeof(buf)-1; 1068 strncpy(buf, a, n); 1069 buf[n] = 0; 1070 for(a = buf; a;){ 1071 if(strncmp(a, "rawon", 5) == 0){ 1072 qlock(&kbd); 1073 flushkbdline(kbdq); 1074 kbd.raw = 1; 1075 qunlock(&kbd); 1076 } else if(strncmp(a, "rawoff", 6) == 0){ 1077 qlock(&kbd); 1078 kbd.raw = 0; 1079 kbd.x = 0; 1080 qunlock(&kbd); 1081 } 1082 if(a = strchr(a, ' ')) 1083 a++; 1084 } 1085 break; 1086 1087 case Qkeyboard: 1088 for(x=0; x<n; ) { 1089 Rune r; 1090 x += chartorune(&r, &a[x]); 1091 kbdputc(kbdq, r); 1092 } 1093 break; 1094 1095 case Qtime: 1096 if(n >= sizeof(buf)) 1097 n = sizeof(buf)-1; 1098 strncpy(buf, a, n); 1099 buf[n] = 0; 1100 t = strtoll(buf, 0, 0)/1000000; 1101 boottime = t - TK2SEC(MACHP(0)->ticks); 1102 break; 1103 1104 case Qhostowner: 1105 if(!iseve()) 1106 error(Eperm); 1107 if(offset != 0 || n >= sizeof(buf)) 1108 error(Ebadarg); 1109 memmove(buf, a, n); 1110 buf[n] = '\0'; 1111 if(n > 0 && buf[n-1] == '\n') 1112 buf[--n] = 0; 1113 if(n <= 0) 1114 error(Ebadarg); 1115 renameuser(eve, buf); 1116 renameproguser(eve, buf); 1117 kstrdup(&eve, buf); 1118 kstrdup(&up->env->user, buf); 1119 break; 1120 1121 case Quser: 1122 if(!iseve()) 1123 error(Eperm); 1124 if(offset != 0) 1125 error(Ebadarg); 1126 if(n <= 0 || n >= sizeof(buf)) 1127 error(Ebadarg); 1128 strncpy(buf, a, n); 1129 buf[n] = 0; 1130 if(buf[n-1] == '\n') 1131 buf[n-1] = 0; 1132 kstrdup(&up->env->user, buf); 1133 break; 1134 1135 case Qjit: 1136 if(n >= sizeof(buf)) 1137 n = sizeof(buf)-1; 1138 strncpy(buf, va, n); 1139 buf[n] = '\0'; 1140 x = atoi(buf); 1141 if(x < 0 || x > 9) 1142 error(Ebadarg); 1143 cflag = x; 1144 return n; 1145 1146 case Qnull: 1147 break; 1148 1149 case Qpin: 1150 if(up->env->pgrp->pin != Nopin) 1151 error("pin already set"); 1152 if(n >= sizeof(buf)) 1153 n = sizeof(buf)-1; 1154 strncpy(buf, va, n); 1155 buf[n] = '\0'; 1156 up->env->pgrp->pin = atoi(buf); 1157 return n; 1158 1159 case Qsysname: 1160 if(offset != 0) 1161 error(Ebadarg); 1162 if(n <= 0 || n >= sizeof(buf)) 1163 error(Ebadarg); 1164 strncpy(buf, a, n); 1165 buf[n] = 0; 1166 if(buf[n-1] == '\n') 1167 buf[n-1] = 0; 1168 kstrdup(&sysname, buf); 1169 break; 1170 1171 case Qsysctl: 1172 if(!iseve()) 1173 error(Eperm); 1174 cb = parsecmd(a, n); 1175 if(waserror()){ 1176 free(cb); 1177 nexterror(); 1178 } 1179 ct = lookupcmd(cb, sysctlcmd, nelem(sysctlcmd)); 1180 switch(ct->index){ 1181 case CMreboot: 1182 reboot(); 1183 break; 1184 case CMhalt: 1185 halt(); 1186 break; 1187 case CMpanic: 1188 panic("sysctl"); 1189 case CMconsole: 1190 consoleprint = strcmp(cb->f[1], "off") != 0; 1191 break; 1192 case CMbroken: 1193 keepbroken = 1; 1194 break; 1195 case CMnobroken: 1196 keepbroken = 0; 1197 break; 1198 } 1199 poperror(); 1200 free(cb); 1201 break; 1202 1203 default: 1204 print("conswrite: %llud\n", c->qid.path); 1205 error(Egreg); 1206 } 1207 return n; 1208 } 1209 1210 Dev consdevtab = { 1211 'c', 1212 "cons", 1213 1214 devreset, 1215 consinit, 1216 devshutdown, 1217 consattach, 1218 conswalk, 1219 consstat, 1220 consopen, 1221 devcreate, 1222 consclose, 1223 consread, 1224 devbread, 1225 conswrite, 1226 devbwrite, 1227 devremove, 1228 devwstat, 1229 }; 1230 1231 static ulong randn; 1232 1233 static void 1234 seedrand(void) 1235 { 1236 randomread((void*)&randn, sizeof(randn)); 1237 } 1238 1239 int 1240 nrand(int n) 1241 { 1242 if(randn == 0) 1243 seedrand(); 1244 randn = randn*1103515245 + 12345 + MACHP(0)->ticks; 1245 return (randn>>16) % n; 1246 } 1247 1248 int 1249 rand(void) 1250 { 1251 nrand(1); 1252 return randn; 1253 } 1254 1255 ulong 1256 truerand(void) 1257 { 1258 ulong x; 1259 1260 randomread(&x, sizeof(x)); 1261 return x; 1262 } 1263 1264 QLock grandomlk; 1265 1266 void 1267 _genrandomqlock(void) 1268 { 1269 qlock(&grandomlk); 1270 } 1271 1272 1273 void 1274 _genrandomqunlock(void) 1275 { 1276 qunlock(&grandomlk); 1277 } 1278