1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "../port/error.h" 8 9 #include "devtab.h" 10 11 struct { 12 IOQ; /* lock to klogputs */ 13 QLock; /* qlock to getc */ 14 }klogq; 15 16 IOQ mouseq; 17 IOQ lineq; /* lock to getc; interrupt putc's */ 18 IOQ printq; 19 KIOQ kbdq; 20 21 static Ref ctl; /* number of opens to the control file */ 22 static int raw; /* true if raw has been requested on ctl file */ 23 24 char sysname[NAMELEN]; 25 26 /* 27 * init the queues and set the output routine 28 */ 29 void 30 printinit(void) 31 { 32 initq(&printq); 33 printq.puts = 0; 34 initq(&lineq); 35 initq(&kbdq); 36 kbdq.putc = kbdputc; 37 initq(&klogq); 38 initq(&mouseq); 39 mouseq.putc = mouseputc; 40 } 41 42 /* 43 * Print a string on the console. Convert \n to \r\n for serial 44 * line consoles. Locking of the queues is left up to the screen 45 * or uart code. Multi-line messages to serial consoles may get 46 * interspersed with other messages. 47 */ 48 void 49 putstrn(char *str, int n) 50 { 51 char buf[PRINTSIZE+2]; 52 int m; 53 char *t; 54 55 /* 56 * if there's an attached bit mapped display, 57 * put the message there. screenputs is defined 58 * as a null macro for systems that have no such 59 * display. 60 */ 61 screenputs(str, n); 62 63 /* 64 * if there's a serial line being used as a console, 65 * put the message there. Tack a carriage return 66 * before new lines. 67 */ 68 if(printq.puts == 0) 69 return; 70 71 while(n > 0){ 72 t = memchr(str, '\n', n); 73 if(t){ 74 m = t - str; 75 memmove(buf, str, m); 76 buf[m] = '\r'; 77 buf[m+1] = '\n'; 78 (*printq.puts)(&printq, buf, m+2); 79 str = t + 1; 80 n -= m + 1; 81 } else { 82 (*printq.puts)(&printq, str, n); 83 break; 84 } 85 } 86 } 87 88 /* 89 * Print a string in the kernel log. Ignore overflow. 90 */ 91 void 92 klogputs(char *str, long n) 93 { 94 int s, m; 95 uchar *nextin; 96 97 s = splhi(); 98 lock(&klogq); 99 while(n){ 100 m = &klogq.buf[NQ] - klogq.in; 101 if(m > n) 102 m = n; 103 memmove(klogq.in, str, m); 104 n -= m; 105 str += m; 106 nextin = klogq.in + m; 107 if(nextin >= &klogq.buf[NQ]) 108 klogq.in = klogq.buf; 109 else 110 klogq.in = nextin; 111 } 112 unlock(&klogq); 113 splx(s); 114 wakeup(&klogq.r); 115 } 116 117 int 118 isbrkc(KIOQ *q) 119 { 120 uchar *p; 121 122 for(p=q->out; p!=q->in; ){ 123 if(raw) 124 return 1; 125 if(*p==0x04 || *p=='\n') 126 return 1; 127 p++; 128 if(p >= q->buf+sizeof(q->buf)) 129 p = q->buf; 130 } 131 return 0; 132 } 133 134 int 135 sprint(char *s, char *fmt, ...) 136 { 137 return doprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s; 138 } 139 140 int 141 snprint(char *s, int n, char *fmt, ...) 142 { 143 return doprint(s, s+n, fmt, (&fmt+1)) - s; 144 } 145 146 int 147 print(char *fmt, ...) 148 { 149 char buf[PRINTSIZE]; 150 int n; 151 152 n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 153 putstrn(buf, n); 154 return n; 155 } 156 157 int 158 kprint(char *fmt, ...) 159 { 160 char buf[PRINTSIZE]; 161 int n; 162 163 n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 164 klogputs(buf, n); 165 return n; 166 } 167 168 void 169 panic(char *fmt, ...) 170 { 171 char buf[PRINTSIZE]; 172 int n; 173 174 strcpy(buf, "panic: "); 175 n = doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1)) - buf; 176 buf[n] = '\n'; 177 putstrn(buf, n+1); 178 dumpstack(); 179 exit(1); 180 } 181 int 182 pprint(char *fmt, ...) 183 { 184 char buf[2*PRINTSIZE]; 185 Chan *c; 186 int n; 187 188 if(u->p->fgrp == 0) 189 return 0; 190 191 c = u->p->fgrp->fd[2]; 192 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) 193 return 0; 194 n = sprint(buf, "%s %d: ", u->p->text, u->p->pid); 195 n = doprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 196 197 if(waserror()) 198 return 0; 199 (*devtab[c->type].write)(c, buf, n, c->offset); 200 poperror(); 201 202 lock(c); 203 c->offset += n; 204 unlock(c); 205 206 return n; 207 } 208 209 void 210 prflush(void) 211 { 212 while(printq.in != printq.out) ; 213 } 214 #include <ureg.h> 215 void 216 echo(Rune r, char *buf, int n) 217 { 218 static int ctrlt; 219 220 /* 221 * ^p hack 222 */ 223 if(r==0x10 && cpuserver) 224 exit(0); 225 226 /* 227 * ^t hack BUG 228 */ 229 if(ctrlt == 2){ 230 ctrlt = 0; 231 switch(r){ 232 case 0x14: 233 break; /* pass it on */ 234 case 'x': 235 xsummary(); 236 break; 237 case 'b': 238 bitdebug(); 239 break; 240 case 'd': 241 consdebug(); 242 return; 243 case 'p': 244 procdump(); 245 return; 246 case 'r': 247 exit(0); 248 break; 249 } 250 }else if(r == 0x14){ 251 ctrlt++; 252 return; 253 } 254 ctrlt = 0; 255 if(raw) 256 return; 257 if(r == 0x15) 258 putstrn("^U\n", 3); 259 else 260 putstrn(buf, n); 261 } 262 263 /* 264 * turn '\r' into '\n' before putting it into the queue 265 */ 266 int 267 kbdcr2nl(IOQ *q, int ch) 268 { 269 if(ch == '\r') 270 ch = '\n'; 271 return kbdputc(q, ch); 272 } 273 274 /* 275 * Put character, possibly a rune, into read queue at interrupt time. 276 * Always called splhi from processor 0. 277 */ 278 int 279 kbdputc(IOQ *q, int ch) 280 { 281 int i, n; 282 char buf[3]; 283 Rune r; 284 285 USED(q); 286 r = ch; 287 n = runetochar(buf, &r); 288 if(n == 0) 289 return 0; 290 echo(r, buf, n); 291 kbdq.c = r; 292 for(i=0; i<n; i++){ 293 *kbdq.in++ = buf[i]; 294 if(kbdq.in == kbdq.buf+sizeof(kbdq.buf)) 295 kbdq.in = kbdq.buf; 296 } 297 if(raw || r=='\n' || r==0x04) 298 wakeup(&kbdq.r); 299 return 0; 300 } 301 302 void 303 kbdrepeat(int rep) 304 { 305 kbdq.repeat = rep; 306 kbdq.count = 0; 307 } 308 309 void 310 kbdclock(void) 311 { 312 if(kbdq.repeat == 0) 313 return; 314 if(kbdq.repeat==1 && ++kbdq.count>HZ){ 315 kbdq.repeat = 2; 316 kbdq.count = 0; 317 return; 318 } 319 if(++kbdq.count&1) 320 kbdputc(&kbdq, kbdq.c); 321 } 322 323 int 324 consactive(void) 325 { 326 return printq.in != printq.out; 327 } 328 329 enum{ 330 Qdir, 331 Qauth, 332 Qauthcheck, 333 Qauthent, 334 Qclock, 335 Qcons, 336 Qconsctl, 337 Qcputime, 338 Qhz, 339 Qkey, 340 Qhostdomain, 341 Qhostowner, 342 Qklog, 343 Qlights, 344 Qmsec, 345 Qnoise, 346 Qnull, 347 Qpgrpid, 348 Qpid, 349 Qppid, 350 Qswap, 351 Qsysname, 352 Qsysstat, 353 Qtime, 354 Quser, 355 }; 356 357 Dirtab consdir[]={ 358 "authenticate", {Qauth}, 0, 0666, 359 "authcheck", {Qauthcheck}, 0, 0666, 360 "authenticator", {Qauthent}, 0, 0666, 361 "clock", {Qclock}, 2*NUMSIZE, 0444, 362 "cons", {Qcons}, 0, 0660, 363 "consctl", {Qconsctl}, 0, 0220, 364 "cputime", {Qcputime}, 6*NUMSIZE, 0444, 365 "hostdomain", {Qhostdomain}, DOMLEN, 0664, 366 "hostowner", {Qhostowner}, NAMELEN, 0664, 367 "hz", {Qhz}, NUMSIZE, 0666, 368 "key", {Qkey}, DESKEYLEN, 0622, 369 "klog", {Qklog}, 0, 0444, 370 "lights", {Qlights}, 0, 0220, 371 "msec", {Qmsec}, NUMSIZE, 0444, 372 "noise", {Qnoise}, 0, 0220, 373 "null", {Qnull}, 0, 0666, 374 "pgrpid", {Qpgrpid}, NUMSIZE, 0444, 375 "pid", {Qpid}, NUMSIZE, 0444, 376 "ppid", {Qppid}, NUMSIZE, 0444, 377 "swap", {Qswap}, 0, 0664, 378 "sysname", {Qsysname}, 0, 0664, 379 "sysstat", {Qsysstat}, 0, 0666, 380 "time", {Qtime}, NUMSIZE, 0664, 381 "user", {Quser}, NAMELEN, 0666, 382 }; 383 384 #define NCONS (sizeof consdir/sizeof(Dirtab)) 385 386 ulong boottime; /* seconds since epoch at boot */ 387 388 long 389 seconds(void) 390 { 391 return boottime + TK2SEC(MACHP(0)->ticks); 392 } 393 394 int 395 readnum(ulong off, char *buf, ulong n, ulong val, int size) 396 { 397 char tmp[64]; 398 Fconv fconv = (Fconv){ tmp, tmp+sizeof(tmp), size-1, 0, 0, 'u' }; 399 400 numbconv(&val, &fconv); 401 tmp[size-1] = ' '; 402 if(off >= size) 403 return 0; 404 if(off+n > size) 405 n = size-off; 406 memmove(buf, tmp+off, n); 407 return n; 408 } 409 410 int 411 readstr(ulong off, char *buf, ulong n, char *str) 412 { 413 int size; 414 415 size = strlen(str); 416 if(off >= size) 417 return 0; 418 if(off+n > size) 419 n = size-off; 420 memmove(buf, str+off, n); 421 return n; 422 } 423 424 void 425 consreset(void) 426 { 427 } 428 429 void 430 consinit(void) 431 { 432 } 433 434 Chan* 435 consattach(char *spec) 436 { 437 return devattach('c', spec); 438 } 439 440 Chan* 441 consclone(Chan *c, Chan *nc) 442 { 443 return devclone(c, nc); 444 } 445 446 int 447 conswalk(Chan *c, char *name) 448 { 449 return devwalk(c, name, consdir, NCONS, devgen); 450 } 451 452 void 453 consstat(Chan *c, char *dp) 454 { 455 devstat(c, dp, consdir, NCONS, devgen); 456 } 457 458 Chan* 459 consopen(Chan *c, int omode) 460 { 461 c->aux = 0; 462 switch(c->qid.path){ 463 case Qconsctl: 464 if(!iseve()) 465 error(Eperm); 466 incref(&ctl); 467 break; 468 } 469 return devopen(c, omode, consdir, NCONS, devgen); 470 } 471 472 void 473 conscreate(Chan *c, char *name, int omode, ulong perm) 474 { 475 USED(c, name, omode, perm); 476 error(Eperm); 477 } 478 479 void 480 consclose(Chan *c) 481 { 482 /* last close of control file turns off raw */ 483 switch(c->qid.path){ 484 case Qconsctl: 485 if(c->flag&COPEN){ 486 lock(&ctl); 487 if(--ctl.ref == 0) 488 raw = 0; 489 unlock(&ctl); 490 } 491 break; 492 case Qauth: 493 case Qauthcheck: 494 case Qauthent: 495 authclose(c); 496 break; 497 } 498 } 499 500 long 501 consread(Chan *c, void *buf, long n, ulong offset) 502 { 503 int ch, i, k, id; 504 ulong l; 505 char *cbuf = buf; 506 char *b, *bp; 507 char tmp[128]; /* must be >= 6*NUMSIZE */ 508 Mach *mp; 509 510 if(n <= 0) 511 return n; 512 switch(c->qid.path & ~CHDIR){ 513 case Qdir: 514 return devdirread(c, buf, n, consdir, NCONS, devgen); 515 516 case Qcons: 517 qlock(&kbdq); 518 if(waserror()){ 519 qunlock(&kbdq); 520 nexterror(); 521 } 522 while(!cangetc(&lineq)){ 523 sleep(&kbdq.r, isbrkc, &kbdq); 524 do{ 525 lock(&lineq); 526 ch = getc(&kbdq); 527 if(raw) 528 goto Default; 529 switch(ch){ 530 case '\b': 531 if(lineq.in != lineq.out){ 532 if(lineq.in == lineq.buf) 533 lineq.in = lineq.buf+sizeof(lineq.buf); 534 lineq.in--; 535 } 536 break; 537 case 0x15: 538 lineq.in = lineq.out; 539 break; 540 Default: 541 default: 542 *lineq.in = ch; 543 if(lineq.in >= lineq.buf+sizeof(lineq.buf)-1) 544 lineq.in = lineq.buf; 545 else 546 lineq.in++; 547 } 548 unlock(&lineq); 549 }while(raw==0 && ch!='\n' && ch!=0x04); 550 } 551 i = 0; 552 while(n > 0){ 553 ch = getc(&lineq); 554 if(ch==-1 || (raw==0 && ch==0x04)) 555 break; 556 i++; 557 *cbuf++ = ch; 558 --n; 559 } 560 poperror(); 561 qunlock(&kbdq); 562 return i; 563 564 case Qcputime: 565 k = offset; 566 if(k >= 6*NUMSIZE) 567 return 0; 568 if(k+n > 6*NUMSIZE) 569 n = 6*NUMSIZE - k; 570 /* easiest to format in a separate buffer and copy out */ 571 for(i=0; i<6 && NUMSIZE*i<k+n; i++){ 572 l = u->p->time[i]; 573 if(i == TReal) 574 l = MACHP(0)->ticks - l; 575 l = TK2MS(l); 576 readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); 577 } 578 memmove(buf, tmp+k, n); 579 return n; 580 581 case Qpgrpid: 582 return readnum(offset, buf, n, u->p->pgrp->pgrpid, NUMSIZE); 583 584 case Qpid: 585 return readnum(offset, buf, n, u->p->pid, NUMSIZE); 586 587 case Qppid: 588 return readnum(offset, buf, n, u->p->parentpid, NUMSIZE); 589 590 case Qtime: 591 return readnum(offset, buf, n, boottime+TK2SEC(MACHP(0)->ticks), 12); 592 593 case Qclock: 594 k = offset; 595 if(k >= 2*NUMSIZE) 596 return 0; 597 if(k+n > 2*NUMSIZE) 598 n = 2*NUMSIZE - k; 599 readnum(0, tmp, NUMSIZE, MACHP(0)->ticks, NUMSIZE); 600 readnum(0, tmp+NUMSIZE, NUMSIZE, HZ, NUMSIZE); 601 memmove(buf, tmp+k, n); 602 return n; 603 604 case Qkey: 605 return keyread(buf, n, offset); 606 607 case Qauth: 608 return authread(c, cbuf, n); 609 610 case Qauthent: 611 return authentread(c, cbuf, n); 612 613 case Qhostowner: 614 return readstr(offset, buf, n, eve); 615 616 case Qhostdomain: 617 return readstr(offset, buf, n, hostdomain); 618 619 case Quser: 620 return readstr(offset, buf, n, u->p->user); 621 622 case Qnull: 623 return 0; 624 625 case Qklog: 626 qlock(&klogq); 627 if(waserror()){ 628 qunlock(&klogq); 629 nexterror(); 630 } 631 while(!cangetc(&klogq)) 632 sleep(&klogq.r, cangetc, &klogq); 633 for(i=0; i<n; i++){ 634 if((ch=getc(&klogq)) == -1) 635 break; 636 *cbuf++ = ch; 637 } 638 poperror(); 639 qunlock(&klogq); 640 return i; 641 642 case Qmsec: 643 return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE); 644 645 case Qhz: 646 return readnum(offset, buf, n, HZ, NUMSIZE); 647 648 case Qsysstat: 649 b = smalloc(conf.nmach*(NUMSIZE*8+1) + 1); /* +1 for NUL */ 650 bp = b; 651 for(id = 0; id < 32; id++) { 652 if(active.machs & (1<<id)) { 653 mp = MACHP(id); 654 readnum(0, bp, NUMSIZE, id, NUMSIZE); 655 bp += NUMSIZE; 656 readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE); 657 bp += NUMSIZE; 658 readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE); 659 bp += NUMSIZE; 660 readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE); 661 bp += NUMSIZE; 662 readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE); 663 bp += NUMSIZE; 664 readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE); 665 bp += NUMSIZE; 666 readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE); 667 bp += NUMSIZE; 668 readnum(0, bp, NUMSIZE, mp->load, NUMSIZE); 669 bp += NUMSIZE; 670 *bp++ = '\n'; 671 } 672 } 673 n = readstr(offset, buf, n, b); 674 free(b); 675 return n; 676 677 case Qswap: 678 sprint(tmp, "%d/%d memory %d/%d swap\n", 679 palloc.user-palloc.freecount, palloc.user, 680 conf.nswap-swapalloc.free, conf.nswap); 681 682 return readstr(offset, buf, n, tmp); 683 684 case Qsysname: 685 return readstr(offset, buf, n, sysname); 686 687 default: 688 print("consread %lux\n", c->qid); 689 error(Egreg); 690 } 691 return -1; /* never reached */ 692 } 693 694 void 695 conslights(char *a, int n) 696 { 697 char line[128]; 698 char *lp; 699 int c; 700 701 lp = line; 702 while(n--){ 703 *lp++ = c = *a++; 704 if(c=='\n' || n==0 || lp==&line[sizeof(line)-1]) 705 break; 706 } 707 *lp = 0; 708 lights(strtoul(line, 0, 0)); 709 } 710 711 void 712 consnoise(char *a, int n) 713 { 714 int freq; 715 int duration; 716 char line[128]; 717 char *lp; 718 int c; 719 720 lp = line; 721 while(n--){ 722 *lp++ = c = *a++; 723 if(c=='\n' || n==0 || lp==&line[sizeof(line)-1]){ 724 *lp = 0; 725 freq = strtoul(line, &lp, 0); 726 while(*lp==' ' || *lp=='\t') 727 lp++; 728 duration = strtoul(lp, &lp, 0); 729 buzz(freq, duration); 730 lp = line; 731 } 732 } 733 } 734 735 long 736 conswrite(Chan *c, void *va, long n, ulong offset) 737 { 738 char cbuf[64]; 739 char buf[256]; 740 long l, bp; 741 char *a = va; 742 Mach *mp; 743 int id, fd, ch; 744 Chan *swc; 745 746 switch(c->qid.path){ 747 case Qcons: 748 l = n; 749 while(l > 0){ 750 bp = l; 751 if(bp > sizeof buf) 752 bp = sizeof buf; 753 memmove(buf, a, bp); 754 putstrn(a, bp); 755 a += bp; 756 l -= bp; 757 } 758 break; 759 760 case Qconsctl: 761 if(n >= sizeof(buf)) 762 n = sizeof(buf)-1; 763 strncpy(buf, a, n); 764 buf[n] = 0; 765 if(strncmp(a, "rawon", 5) == 0){ 766 lock(&lineq); 767 while((ch=getc(&kbdq)) != -1){ 768 *lineq.in++ = ch; 769 if(lineq.in == lineq.buf+sizeof(lineq.buf)) 770 lineq.in = lineq.buf; 771 } 772 unlock(&lineq); 773 lock(&ctl); 774 raw = 1; 775 unlock(&ctl); 776 } 777 else 778 if(strncmp(a, "rawoff", 6) == 0){ 779 lock(&ctl); 780 raw = 0; 781 unlock(&ctl); 782 } 783 else 784 error(Ebadctl); 785 break; 786 787 case Qtime: 788 if(n<=0 || boottime!=0) /* write once file */ 789 return 0; 790 if(n >= sizeof cbuf) 791 n = sizeof cbuf - 1; 792 memmove(cbuf, a, n); 793 cbuf[n-1] = 0; 794 boottime = strtoul(a, 0, 0)-TK2SEC(MACHP(0)->ticks); 795 break; 796 797 case Qkey: 798 return keywrite(a, n); 799 800 case Qhostowner: 801 return hostownerwrite(a, n); 802 803 case Qhostdomain: 804 return hostdomainwrite(a, n); 805 806 case Quser: 807 return userwrite(a, n); 808 809 case Qauth: 810 return authwrite(c, a, n); 811 812 case Qauthcheck: 813 return authcheck(c, a, n); 814 815 case Qauthent: 816 return authentwrite(c, a, n); 817 818 case Qnull: 819 break; 820 821 case Qnoise: 822 consnoise(a, n); 823 break; 824 825 case Qlights: 826 conslights(a, n); 827 break; 828 829 case Qsysstat: 830 for(id = 0; id < 32; id++) { 831 if(active.machs & (1<<id)) { 832 mp = MACHP(id); 833 mp->cs = 0; 834 mp->intr = 0; 835 mp->syscall = 0; 836 mp->pfault = 0; 837 mp->tlbfault = 0; 838 mp->tlbpurge = 0; 839 } 840 } 841 break; 842 843 case Qswap: 844 if(n >= sizeof buf) 845 error(Egreg); 846 memmove(buf, va, n); /* so we can NUL-terminate */ 847 buf[n] = 0; 848 /* start a pager if not already started */ 849 if(strncmp(buf, "start", 5) == 0){ 850 kickpager(); 851 break; 852 } 853 if(cpuserver && strcmp(u->p->user, eve) != 0) 854 error(Eperm); 855 if(buf[0]<'0' || '9'<buf[0]) 856 error(Ebadusefd); 857 fd = strtoul(buf, 0, 0); 858 swc = fdtochan(fd, -1, 1, 0); 859 setswapchan(swc); 860 break; 861 862 case Qsysname: 863 if(offset != 0) 864 error(Ebadarg); 865 if(n <= 0 || n >= NAMELEN) 866 error(Ebadarg); 867 strncpy(sysname, a, n); 868 sysname[n] = 0; 869 if(sysname[n-1] == '\n') 870 sysname[n-1] = 0; 871 break; 872 873 default: 874 print("conswrite: %d\n", c->qid.path); 875 error(Egreg); 876 } 877 return n; 878 } 879 880 void 881 consremove(Chan *c) 882 { 883 USED(c); 884 error(Eperm); 885 } 886 887 void 888 conswstat(Chan *c, char *dp) 889 { 890 USED(c, dp); 891 error(Eperm); 892 } 893 894 int 895 nrand(int n) 896 { 897 static ulong randn; 898 899 randn = randn*1103515245 + 12345 + MACHP(0)->ticks; 900 return (randn>>16) % n; 901 } 902 903 void 904 setterm(char *f) 905 { 906 char buf[2*NAMELEN]; 907 908 sprint(buf, f, conffile); 909 ksetenv("terminal", buf); 910 } 911