1 #include "u.h" 2 #include "lib.h" 3 #include "dat.h" 4 #include "fns.h" 5 #include "error.h" 6 7 #include "keyboard.h" 8 9 void (*consdebug)(void) = 0; 10 void (*screenputs)(char*, int) = 0; 11 12 Queue* kbdq; /* unprocessed console input */ 13 Queue* lineq; /* processed console input */ 14 Queue* serialoq; /* serial console output */ 15 Queue* kprintoq; /* console output, for /dev/kprint */ 16 long kprintinuse; /* test and set whether /dev/kprint is open */ 17 Lock kprintlock; 18 int iprintscreenputs = 0; 19 20 int panicking; 21 22 struct 23 { 24 int exiting; 25 int machs; 26 } active; 27 28 static struct 29 { 30 QLock lk; 31 32 int raw; /* true if we shouldn't process input */ 33 int ctl; /* number of opens to the control file */ 34 int x; /* index into line */ 35 char line[1024]; /* current input line */ 36 37 int count; 38 int ctlpoff; 39 40 /* a place to save up characters at interrupt time before dumping them in the queue */ 41 Lock lockputc; 42 char istage[1024]; 43 char *iw; 44 char *ir; 45 char *ie; 46 } kbd = { 47 { 0 }, 48 0, 49 0, 50 0, 51 { 0 }, 52 0, 53 0, 54 { 0 }, 55 { 0 }, 56 kbd.istage, 57 kbd.istage, 58 kbd.istage + sizeof(kbd.istage), 59 }; 60 61 char *sysname; 62 vlong fasthz; 63 64 static int readtime(ulong, char*, int); 65 static int readbintime(char*, int); 66 static int writetime(char*, int); 67 static int writebintime(char*, int); 68 69 enum 70 { 71 CMreboot, 72 CMpanic, 73 }; 74 75 Cmdtab rebootmsg[] = 76 { 77 CMreboot, "reboot", 0, 78 CMpanic, "panic", 0, 79 }; 80 81 int 82 return0(void *v) 83 { 84 return 0; 85 } 86 87 void 88 printinit(void) 89 { 90 lineq = qopen(2*1024, 0, 0, nil); 91 if(lineq == nil) 92 panic("printinit"); 93 qnoblock(lineq, 1); 94 95 kbdq = qopen(4*1024, 0, 0, 0); 96 if(kbdq == nil) 97 panic("kbdinit"); 98 qnoblock(kbdq, 1); 99 } 100 101 int 102 consactive(void) 103 { 104 if(serialoq) 105 return qlen(serialoq) > 0; 106 return 0; 107 } 108 109 void 110 prflush(void) 111 { 112 /* 113 ulong now; 114 115 now = m->ticks; 116 while(consactive()) 117 if(m->ticks - now >= HZ) 118 break; 119 */ 120 } 121 122 /* 123 * Print a string on the console. Convert \n to \r\n for serial 124 * line consoles. Locking of the queues is left up to the screen 125 * or uart code. Multi-line messages to serial consoles may get 126 * interspersed with other messages. 127 */ 128 static void 129 putstrn0(char *str, int n, int usewrite) 130 { 131 /* 132 * if someone is reading /dev/kprint, 133 * put the message there. 134 * if not and there's an attached bit mapped display, 135 * put the message there. 136 * 137 * if there's a serial line being used as a console, 138 * put the message there. 139 */ 140 if(kprintoq != nil && !qisclosed(kprintoq)){ 141 if(usewrite) 142 qwrite(kprintoq, str, n); 143 else 144 qiwrite(kprintoq, str, n); 145 }else if(screenputs != 0) 146 screenputs(str, n); 147 } 148 149 void 150 putstrn(char *str, int n) 151 { 152 putstrn0(str, n, 0); 153 } 154 155 int noprint; 156 157 int 158 print(char *fmt, ...) 159 { 160 int n; 161 va_list arg; 162 char buf[PRINTSIZE]; 163 164 if(noprint) 165 return -1; 166 167 va_start(arg, fmt); 168 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; 169 va_end(arg); 170 putstrn(buf, n); 171 172 return n; 173 } 174 175 void 176 panic(char *fmt, ...) 177 { 178 int n; 179 va_list arg; 180 char buf[PRINTSIZE]; 181 182 kprintoq = nil; /* don't try to write to /dev/kprint */ 183 184 if(panicking) 185 for(;;); 186 panicking = 1; 187 188 splhi(); 189 strcpy(buf, "panic: "); 190 va_start(arg, fmt); 191 n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; 192 va_end(arg); 193 buf[n] = '\n'; 194 uartputs(buf, n+1); 195 if(consdebug) 196 (*consdebug)(); 197 spllo(); 198 prflush(); 199 putstrn(buf, n+1); 200 dumpstack(); 201 202 exit(1); 203 } 204 205 int 206 pprint(char *fmt, ...) 207 { 208 int n; 209 Chan *c; 210 va_list arg; 211 char buf[2*PRINTSIZE]; 212 213 if(up == nil || up->fgrp == nil) 214 return 0; 215 216 c = up->fgrp->fd[2]; 217 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) 218 return 0; 219 n = sprint(buf, "%s %lud: ", up->text, up->pid); 220 va_start(arg, fmt); 221 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; 222 va_end(arg); 223 224 if(waserror()) 225 return 0; 226 devtab[c->type]->write(c, buf, n, c->offset); 227 poperror(); 228 229 lock(&c->ref.lk); 230 c->offset += n; 231 unlock(&c->ref.lk); 232 233 return n; 234 } 235 236 static void 237 echoscreen(char *buf, int n) 238 { 239 char *e, *p; 240 char ebuf[128]; 241 int x; 242 243 p = ebuf; 244 e = ebuf + sizeof(ebuf) - 4; 245 while(n-- > 0){ 246 if(p >= e){ 247 screenputs(ebuf, p - ebuf); 248 p = ebuf; 249 } 250 x = *buf++; 251 if(x == 0x15){ 252 *p++ = '^'; 253 *p++ = 'U'; 254 *p++ = '\n'; 255 } else 256 *p++ = x; 257 } 258 if(p != ebuf) 259 screenputs(ebuf, p - ebuf); 260 } 261 262 static void 263 echoserialoq(char *buf, int n) 264 { 265 char *e, *p; 266 char ebuf[128]; 267 int x; 268 269 p = ebuf; 270 e = ebuf + sizeof(ebuf) - 4; 271 while(n-- > 0){ 272 if(p >= e){ 273 qiwrite(serialoq, ebuf, p - ebuf); 274 p = ebuf; 275 } 276 x = *buf++; 277 if(x == '\n'){ 278 *p++ = '\r'; 279 *p++ = '\n'; 280 } else if(x == 0x15){ 281 *p++ = '^'; 282 *p++ = 'U'; 283 *p++ = '\n'; 284 } else 285 *p++ = x; 286 } 287 if(p != ebuf) 288 qiwrite(serialoq, ebuf, p - ebuf); 289 } 290 291 static void 292 echo(char *buf, int n) 293 { 294 static int ctrlt; 295 int x; 296 char *e, *p; 297 298 e = buf+n; 299 for(p = buf; p < e; p++){ 300 switch(*p){ 301 case 0x10: /* ^P */ 302 if(cpuserver && !kbd.ctlpoff){ 303 active.exiting = 1; 304 return; 305 } 306 break; 307 case 0x14: /* ^T */ 308 ctrlt++; 309 if(ctrlt > 2) 310 ctrlt = 2; 311 continue; 312 } 313 314 if(ctrlt != 2) 315 continue; 316 317 /* ^T escapes */ 318 ctrlt = 0; 319 switch(*p){ 320 case 'S': 321 x = splhi(); 322 dumpstack(); 323 procdump(); 324 splx(x); 325 return; 326 case 's': 327 dumpstack(); 328 return; 329 case 'x': 330 xsummary(); 331 ixsummary(); 332 mallocsummary(); 333 pagersummary(); 334 return; 335 case 'd': 336 if(consdebug == 0) 337 consdebug = rdb; 338 else 339 consdebug = 0; 340 print("consdebug now 0x%p\n", consdebug); 341 return; 342 case 'D': 343 if(consdebug == 0) 344 consdebug = rdb; 345 consdebug(); 346 return; 347 case 'p': 348 x = spllo(); 349 procdump(); 350 splx(x); 351 return; 352 case 'q': 353 scheddump(); 354 return; 355 case 'k': 356 killbig(); 357 return; 358 case 'r': 359 exit(0); 360 return; 361 } 362 } 363 364 qproduce(kbdq, buf, n); 365 if(kbd.raw) 366 return; 367 if(screenputs != 0) 368 echoscreen(buf, n); 369 if(serialoq) 370 echoserialoq(buf, n); 371 } 372 373 /* 374 * Called by a uart interrupt for console input. 375 * 376 * turn '\r' into '\n' before putting it into the queue. 377 */ 378 int 379 kbdcr2nl(Queue *q, int ch) 380 { 381 char *next; 382 383 USED(q); 384 ilock(&kbd.lockputc); /* just a mutex */ 385 if(ch == '\r' && !kbd.raw) 386 ch = '\n'; 387 next = kbd.iw+1; 388 if(next >= kbd.ie) 389 next = kbd.istage; 390 if(next != kbd.ir){ 391 *kbd.iw = ch; 392 kbd.iw = next; 393 } 394 iunlock(&kbd.lockputc); 395 return 0; 396 } 397 static 398 void 399 _kbdputc(int c) 400 { 401 Rune r; 402 char buf[UTFmax]; 403 int n; 404 405 r = c; 406 n = runetochar(buf, &r); 407 if(n == 0) 408 return; 409 echo(buf, n); 410 // kbd.c = r; 411 // qproduce(kbdq, buf, n); 412 } 413 414 /* _kbdputc, but with compose translation */ 415 int 416 kbdputc(Queue *q, int c) 417 { 418 int i; 419 static int collecting, nk; 420 static Rune kc[5]; 421 422 if(c == Kalt){ 423 collecting = 1; 424 nk = 0; 425 return 0; 426 } 427 428 if(!collecting){ 429 _kbdputc(c); 430 return 0; 431 } 432 433 kc[nk++] = c; 434 c = latin1(kc, nk); 435 if(c < -1) /* need more keystrokes */ 436 return 0; 437 if(c != -1) /* valid sequence */ 438 _kbdputc(c); 439 else 440 for(i=0; i<nk; i++) 441 _kbdputc(kc[i]); 442 nk = 0; 443 collecting = 0; 444 445 return 0; 446 } 447 448 449 enum{ 450 Qdir, 451 Qbintime, 452 Qcons, 453 Qconsctl, 454 Qcpunote, 455 Qcputime, 456 Qdrivers, 457 Qkprint, 458 Qhostdomain, 459 Qhostowner, 460 Qnull, 461 Qosversion, 462 Qpgrpid, 463 Qpid, 464 Qppid, 465 Qrandom, 466 Qreboot, 467 Qsecstore, 468 Qshowfile, 469 Qsnarf, 470 Qswap, 471 Qsysname, 472 Qsysstat, 473 Qtime, 474 Quser, 475 Qzero, 476 }; 477 478 enum 479 { 480 VLNUMSIZE= 22, 481 }; 482 483 static Dirtab consdir[]={ 484 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 485 "bintime", {Qbintime}, 24, 0664, 486 "cons", {Qcons}, 0, 0660, 487 "consctl", {Qconsctl}, 0, 0220, 488 "cpunote", {Qcpunote}, 0, 0444, 489 "cputime", {Qcputime}, 6*NUMSIZE, 0444, 490 "drivers", {Qdrivers}, 0, 0444, 491 "hostdomain", {Qhostdomain}, DOMLEN, 0664, 492 "hostowner", {Qhostowner}, 0, 0664, 493 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440, 494 "null", {Qnull}, 0, 0666, 495 "osversion", {Qosversion}, 0, 0444, 496 "pgrpid", {Qpgrpid}, NUMSIZE, 0444, 497 "pid", {Qpid}, NUMSIZE, 0444, 498 "ppid", {Qppid}, NUMSIZE, 0444, 499 "random", {Qrandom}, 0, 0444, 500 "reboot", {Qreboot}, 0, 0664, 501 "secstore", {Qsecstore}, 0, 0666, 502 "showfile", {Qshowfile}, 0, 0220, 503 "snarf", {Qsnarf}, 0, 0666, 504 "swap", {Qswap}, 0, 0664, 505 "sysname", {Qsysname}, 0, 0664, 506 "sysstat", {Qsysstat}, 0, 0666, 507 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664, 508 "user", {Quser}, 0, 0666, 509 "zero", {Qzero}, 0, 0444, 510 }; 511 512 char secstorebuf[65536]; 513 Dirtab *secstoretab = &consdir[Qsecstore]; 514 Dirtab *snarftab = &consdir[Qsnarf]; 515 516 int 517 readnum(ulong off, char *buf, ulong n, ulong val, int size) 518 { 519 char tmp[64]; 520 521 snprint(tmp, sizeof(tmp), "%*.0lud", size-1, val); 522 tmp[size-1] = ' '; 523 if(off >= size) 524 return 0; 525 if(off+n > size) 526 n = size-off; 527 memmove(buf, tmp+off, n); 528 return n; 529 } 530 531 int 532 readstr(ulong off, char *buf, ulong n, char *str) 533 { 534 int size; 535 536 size = strlen(str); 537 if(off >= size) 538 return 0; 539 if(off+n > size) 540 n = size-off; 541 memmove(buf, str+off, n); 542 return n; 543 } 544 545 static void 546 consinit(void) 547 { 548 todinit(); 549 randominit(); 550 /* 551 * at 115200 baud, the 1024 char buffer takes 56 ms to process, 552 * processing it every 22 ms should be fine 553 */ 554 /* addclock0link(kbdputcclock, 22); */ 555 } 556 557 static Chan* 558 consattach(char *spec) 559 { 560 return devattach('c', spec); 561 } 562 563 static Walkqid* 564 conswalk(Chan *c, Chan *nc, char **name, int nname) 565 { 566 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen); 567 } 568 569 static int 570 consstat(Chan *c, uchar *dp, int n) 571 { 572 return devstat(c, dp, n, consdir, nelem(consdir), devgen); 573 } 574 575 static Chan* 576 consopen(Chan *c, int omode) 577 { 578 c->aux = nil; 579 c = devopen(c, omode, consdir, nelem(consdir), devgen); 580 switch((ulong)c->qid.path){ 581 case Qconsctl: 582 qlock(&kbd.lk); 583 kbd.ctl++; 584 qunlock(&kbd.lk); 585 break; 586 587 case Qkprint: 588 lock(&kprintlock); 589 if(kprintinuse != 0){ 590 c->flag &= ~COPEN; 591 unlock(&kprintlock); 592 error(Einuse); 593 } 594 kprintinuse = 1; 595 unlock(&kprintlock); 596 if(kprintoq == nil){ 597 kprintoq = qopen(8*1024, Qcoalesce, 0, 0); 598 if(kprintoq == nil){ 599 c->flag &= ~COPEN; 600 error(Enomem); 601 } 602 qnoblock(kprintoq, 1); 603 }else 604 qreopen(kprintoq); 605 c->iounit = qiomaxatomic; 606 break; 607 608 case Qsecstore: 609 if(omode == ORDWR) 610 error(Eperm); 611 if(omode != OREAD) 612 memset(secstorebuf, 0, sizeof secstorebuf); 613 break; 614 615 case Qsnarf: 616 if(omode == ORDWR) 617 error(Eperm); 618 if(omode == OREAD) 619 c->aux = strdup(""); 620 else 621 c->aux = mallocz(SnarfSize, 1); 622 break; 623 } 624 return c; 625 } 626 627 static void 628 consclose(Chan *c) 629 { 630 switch((ulong)c->qid.path){ 631 /* last close of control file turns off raw */ 632 case Qconsctl: 633 if(c->flag&COPEN){ 634 qlock(&kbd.lk); 635 if(--kbd.ctl == 0) 636 kbd.raw = 0; 637 qunlock(&kbd.lk); 638 } 639 break; 640 641 /* close of kprint allows other opens */ 642 case Qkprint: 643 if(c->flag & COPEN){ 644 kprintinuse = 0; 645 qhangup(kprintoq, nil); 646 } 647 break; 648 649 case Qsnarf: 650 if(c->mode == OWRITE) 651 clipwrite(c->aux); 652 free(c->aux); 653 break; 654 } 655 } 656 657 static long 658 consread(Chan *c, void *buf, long n, vlong off) 659 { 660 char *b; 661 char tmp[128]; /* must be >= 6*NUMSIZE */ 662 char *cbuf = buf; 663 int ch, i, eol; 664 vlong offset = off; 665 666 if(n <= 0) 667 return n; 668 switch((ulong)c->qid.path){ 669 case Qdir: 670 return devdirread(c, buf, n, consdir, nelem(consdir), devgen); 671 672 case Qcons: 673 qlock(&kbd.lk); 674 if(waserror()) { 675 qunlock(&kbd.lk); 676 nexterror(); 677 } 678 if(kbd.raw) { 679 if(qcanread(lineq)) 680 n = qread(lineq, buf, n); 681 else { 682 /* read as much as possible */ 683 do { 684 i = qread(kbdq, cbuf, n); 685 cbuf += i; 686 n -= i; 687 } while (n>0 && qcanread(kbdq)); 688 n = cbuf - (char*)buf; 689 } 690 } else { 691 while(!qcanread(lineq)) { 692 qread(kbdq, &kbd.line[kbd.x], 1); 693 ch = kbd.line[kbd.x]; 694 eol = 0; 695 switch(ch){ 696 case '\b': 697 if(kbd.x) 698 kbd.x--; 699 break; 700 case 0x15: 701 kbd.x = 0; 702 break; 703 case '\n': 704 case 0x04: 705 eol = 1; 706 default: 707 kbd.line[kbd.x++] = ch; 708 break; 709 } 710 if(kbd.x == sizeof(kbd.line) || eol){ 711 if(ch == 0x04) 712 kbd.x--; 713 qwrite(lineq, kbd.line, kbd.x); 714 kbd.x = 0; 715 } 716 } 717 n = qread(lineq, buf, n); 718 } 719 qunlock(&kbd.lk); 720 poperror(); 721 return n; 722 723 case Qcpunote: 724 sleep(&up->sleep, return0, nil); 725 726 case Qcputime: 727 return 0; 728 729 case Qkprint: 730 return qread(kprintoq, buf, n); 731 732 case Qpgrpid: 733 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE); 734 735 case Qpid: 736 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE); 737 738 case Qppid: 739 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE); 740 741 case Qtime: 742 return readtime((ulong)offset, buf, n); 743 744 case Qbintime: 745 return readbintime(buf, n); 746 747 case Qhostowner: 748 return readstr((ulong)offset, buf, n, eve); 749 750 case Qhostdomain: 751 return readstr((ulong)offset, buf, n, hostdomain); 752 753 case Quser: 754 return readstr((ulong)offset, buf, n, up->user); 755 756 case Qnull: 757 return 0; 758 759 case Qsnarf: 760 if(offset == 0){ 761 free(c->aux); 762 c->aux = clipread(); 763 } 764 if(c->aux == nil) 765 return 0; 766 return readstr(offset, buf, n, c->aux); 767 768 case Qsecstore: 769 return readstr(offset, buf, n, secstorebuf); 770 771 case Qsysstat: 772 return 0; 773 774 case Qswap: 775 return 0; 776 777 case Qsysname: 778 if(sysname == nil) 779 return 0; 780 return readstr((ulong)offset, buf, n, sysname); 781 782 case Qrandom: 783 return randomread(buf, n); 784 785 case Qdrivers: 786 b = malloc(READSTR); 787 if(b == nil) 788 error(Enomem); 789 n = 0; 790 for(i = 0; devtab[i] != nil; i++) 791 n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name); 792 if(waserror()){ 793 free(b); 794 nexterror(); 795 } 796 n = readstr((ulong)offset, buf, n, b); 797 free(b); 798 poperror(); 799 return n; 800 801 case Qzero: 802 memset(buf, 0, n); 803 return n; 804 805 case Qosversion: 806 snprint(tmp, sizeof tmp, "2000"); 807 n = readstr((ulong)offset, buf, n, tmp); 808 return n; 809 810 default: 811 print("consread 0x%llux\n", c->qid.path); 812 error(Egreg); 813 } 814 return -1; /* never reached */ 815 } 816 817 static long 818 conswrite(Chan *c, void *va, long n, vlong off) 819 { 820 char buf[256]; 821 long l, bp; 822 char *a = va; 823 int fd; 824 Chan *swc; 825 ulong offset = off; 826 Cmdbuf *cb; 827 Cmdtab *ct; 828 829 switch((ulong)c->qid.path){ 830 case Qcons: 831 /* 832 * Can't page fault in putstrn, so copy the data locally. 833 */ 834 l = n; 835 while(l > 0){ 836 bp = l; 837 if(bp > sizeof buf) 838 bp = sizeof buf; 839 memmove(buf, a, bp); 840 putstrn0(buf, bp, 1); 841 a += bp; 842 l -= bp; 843 } 844 break; 845 846 case Qconsctl: 847 if(n >= sizeof(buf)) 848 n = sizeof(buf)-1; 849 strncpy(buf, a, n); 850 buf[n] = 0; 851 for(a = buf; a;){ 852 if(strncmp(a, "rawon", 5) == 0){ 853 qlock(&kbd.lk); 854 if(kbd.x){ 855 qwrite(kbdq, kbd.line, kbd.x); 856 kbd.x = 0; 857 } 858 kbd.raw = 1; 859 qunlock(&kbd.lk); 860 } else if(strncmp(a, "rawoff", 6) == 0){ 861 qlock(&kbd.lk); 862 kbd.raw = 0; 863 kbd.x = 0; 864 qunlock(&kbd.lk); 865 } else if(strncmp(a, "ctlpon", 6) == 0){ 866 kbd.ctlpoff = 0; 867 } else if(strncmp(a, "ctlpoff", 7) == 0){ 868 kbd.ctlpoff = 1; 869 } 870 if((a = strchr(a, ' '))) 871 a++; 872 } 873 break; 874 875 case Qtime: 876 if(!iseve()) 877 error(Eperm); 878 return writetime(a, n); 879 880 case Qbintime: 881 if(!iseve()) 882 error(Eperm); 883 return writebintime(a, n); 884 885 case Qhostowner: 886 return hostownerwrite(a, n); 887 888 case Qhostdomain: 889 return hostdomainwrite(a, n); 890 891 case Quser: 892 return userwrite(a, n); 893 894 case Qnull: 895 break; 896 897 case Qreboot: 898 if(!iseve()) 899 error(Eperm); 900 cb = parsecmd(a, n); 901 902 if(waserror()) { 903 free(cb); 904 nexterror(); 905 } 906 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg)); 907 switch(ct->index) { 908 case CMreboot: 909 rebootcmd(cb->nf-1, cb->f+1); 910 break; 911 case CMpanic: 912 panic("/dev/reboot"); 913 } 914 poperror(); 915 free(cb); 916 break; 917 918 case Qsecstore: 919 if(offset >= sizeof secstorebuf || offset+n+1 >= sizeof secstorebuf) 920 error(Etoobig); 921 secstoretab->qid.vers++; 922 memmove(secstorebuf+offset, va, n); 923 return n; 924 925 case Qshowfile: 926 return showfilewrite(a, n); 927 928 case Qsnarf: 929 if(offset >= SnarfSize || offset+n >= SnarfSize) 930 error(Etoobig); 931 snarftab->qid.vers++; 932 memmove((uchar*)c->aux+offset, va, n); 933 return n; 934 935 case Qsysstat: 936 n = 0; 937 break; 938 939 case Qswap: 940 if(n >= sizeof buf) 941 error(Egreg); 942 memmove(buf, va, n); /* so we can NUL-terminate */ 943 buf[n] = 0; 944 /* start a pager if not already started */ 945 if(strncmp(buf, "start", 5) == 0){ 946 kickpager(); 947 break; 948 } 949 if(cpuserver && !iseve()) 950 error(Eperm); 951 if(buf[0]<'0' || '9'<buf[0]) 952 error(Ebadarg); 953 fd = strtoul(buf, 0, 0); 954 swc = fdtochan(fd, -1, 1, 1); 955 setswapchan(swc); 956 break; 957 958 case Qsysname: 959 if(offset != 0) 960 error(Ebadarg); 961 if(n <= 0 || n >= sizeof buf) 962 error(Ebadarg); 963 strncpy(buf, a, n); 964 buf[n] = 0; 965 if(buf[n-1] == '\n') 966 buf[n-1] = 0; 967 kstrdup(&sysname, buf); 968 break; 969 970 default: 971 print("conswrite: 0x%llux\n", c->qid.path); 972 error(Egreg); 973 } 974 return n; 975 } 976 977 Dev consdevtab = { 978 'c', 979 "cons", 980 981 devreset, 982 consinit, 983 devshutdown, 984 consattach, 985 conswalk, 986 consstat, 987 consopen, 988 devcreate, 989 consclose, 990 consread, 991 devbread, 992 conswrite, 993 devbwrite, 994 devremove, 995 devwstat, 996 }; 997 998 static uvlong uvorder = (uvlong) 0x0001020304050607ULL; 999 1000 static uchar* 1001 le2vlong(vlong *to, uchar *f) 1002 { 1003 uchar *t, *o; 1004 int i; 1005 1006 t = (uchar*)to; 1007 o = (uchar*)&uvorder; 1008 for(i = 0; i < sizeof(vlong); i++) 1009 t[o[i]] = f[i]; 1010 return f+sizeof(vlong); 1011 } 1012 1013 static uchar* 1014 vlong2le(uchar *t, vlong from) 1015 { 1016 uchar *f, *o; 1017 int i; 1018 1019 f = (uchar*)&from; 1020 o = (uchar*)&uvorder; 1021 for(i = 0; i < sizeof(vlong); i++) 1022 t[i] = f[o[i]]; 1023 return t+sizeof(vlong); 1024 } 1025 1026 static long order = 0x00010203; 1027 1028 static uchar* 1029 le2long(long *to, uchar *f) 1030 { 1031 uchar *t, *o; 1032 int i; 1033 1034 t = (uchar*)to; 1035 o = (uchar*)ℴ 1036 for(i = 0; i < sizeof(long); i++) 1037 t[o[i]] = f[i]; 1038 return f+sizeof(long); 1039 } 1040 1041 /* 1042 static uchar* 1043 long2le(uchar *t, long from) 1044 { 1045 uchar *f, *o; 1046 int i; 1047 1048 f = (uchar*)&from; 1049 o = (uchar*)ℴ 1050 for(i = 0; i < sizeof(long); i++) 1051 t[i] = f[o[i]]; 1052 return t+sizeof(long); 1053 } 1054 */ 1055 1056 char *Ebadtimectl = "bad time control"; 1057 1058 /* 1059 * like the old #c/time but with added info. Return 1060 * 1061 * secs nanosecs fastticks fasthz 1062 */ 1063 static int 1064 readtime(ulong off, char *buf, int n) 1065 { 1066 vlong nsec, ticks; 1067 long sec; 1068 char str[7*NUMSIZE]; 1069 1070 nsec = todget(&ticks); 1071 if(fasthz == (vlong)0) 1072 fastticks((uvlong*)&fasthz); 1073 sec = nsec/((uvlong) 1000000000); 1074 snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ", 1075 NUMSIZE-1, sec, 1076 VLNUMSIZE-1, nsec, 1077 VLNUMSIZE-1, ticks, 1078 VLNUMSIZE-1, fasthz); 1079 return readstr(off, buf, n, str); 1080 } 1081 1082 /* 1083 * set the time in seconds 1084 */ 1085 static int 1086 writetime(char *buf, int n) 1087 { 1088 char b[13]; 1089 long i; 1090 vlong now; 1091 1092 if(n >= sizeof(b)) 1093 error(Ebadtimectl); 1094 strncpy(b, buf, n); 1095 b[n] = 0; 1096 i = strtol(b, 0, 0); 1097 if(i <= 0) 1098 error(Ebadtimectl); 1099 now = i*((vlong) 1000000000); 1100 todset(now, 0, 0); 1101 return n; 1102 } 1103 1104 /* 1105 * read binary time info. all numbers are little endian. 1106 * ticks and nsec are syncronized. 1107 */ 1108 static int 1109 readbintime(char *buf, int n) 1110 { 1111 int i; 1112 vlong nsec, ticks; 1113 uchar *b = (uchar*)buf; 1114 1115 i = 0; 1116 if(fasthz == (vlong)0) 1117 fastticks((uvlong*)&fasthz); 1118 nsec = todget(&ticks); 1119 if(n >= 3*sizeof(uvlong)){ 1120 vlong2le(b+2*sizeof(uvlong), fasthz); 1121 i += sizeof(uvlong); 1122 } 1123 if(n >= 2*sizeof(uvlong)){ 1124 vlong2le(b+sizeof(uvlong), ticks); 1125 i += sizeof(uvlong); 1126 } 1127 if(n >= 8){ 1128 vlong2le(b, nsec); 1129 i += sizeof(vlong); 1130 } 1131 return i; 1132 } 1133 1134 /* 1135 * set any of the following 1136 * - time in nsec 1137 * - nsec trim applied over some seconds 1138 * - clock frequency 1139 */ 1140 static int 1141 writebintime(char *buf, int n) 1142 { 1143 uchar *p; 1144 vlong delta; 1145 long period; 1146 1147 n--; 1148 p = (uchar*)buf + 1; 1149 switch(*buf){ 1150 case 'n': 1151 if(n < sizeof(vlong)) 1152 error(Ebadtimectl); 1153 le2vlong(&delta, p); 1154 todset(delta, 0, 0); 1155 break; 1156 case 'd': 1157 if(n < sizeof(vlong)+sizeof(long)) 1158 error(Ebadtimectl); 1159 p = le2vlong(&delta, p); 1160 le2long(&period, p); 1161 todset(-1, delta, period); 1162 break; 1163 case 'f': 1164 if(n < sizeof(uvlong)) 1165 error(Ebadtimectl); 1166 le2vlong(&fasthz, p); 1167 todsetfreq(fasthz); 1168 break; 1169 } 1170 return n; 1171 } 1172 1173 1174 int 1175 iprint(char *fmt, ...) 1176 { 1177 int n, s; 1178 va_list arg; 1179 char buf[PRINTSIZE]; 1180 1181 s = splhi(); 1182 va_start(arg, fmt); 1183 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; 1184 va_end(arg); 1185 if(screenputs != 0 && iprintscreenputs) 1186 screenputs(buf, n); 1187 #undef write 1188 write(2, buf, n); 1189 splx(s); 1190 1191 return n; 1192 } 1193 1194