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