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