| plan 9 kernel history: overview | file list | diff list |
1990/11211/port/devcons.c (diff list | history)
| port/devcons.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "errno.h" #include "devtab.h" static struct { Lock; uchar buf[4000]; uchar *in; uchar *out; int printing; int c; }printq; typedef struct IOQ IOQ; #define NQ 4096 struct IOQ{ union{ Lock; QLock; }; uchar buf[NQ]; uchar *in; uchar *out; int state; Rendez r; }; IOQ kbdq; /* qlock to getc; interrupt putc's */ IOQ lineq; /* lock to getc; interrupt putc's */ | |
| 1990/1018 | #define SYSLOGMAGIC 0xdeadbeaf #define SYSLOG ((Syslog *)(UNCACHED | 0x1B00)) | |
| 1990/0928 | typedef struct Syslog Syslog; struct Syslog { ulong magic; | |
| 1990/1018 | int wrapped; | |
| 1990/0928 | char *next; | |
| 1990/1018 | char buf[2*1024]; | |
| 1990/0928 | }; | |
| 1990/0227 | void printinit(void) { printq.in = printq.buf; printq.out = printq.buf; lock(&printq); /* allocate lock */ unlock(&printq); kbdq.in = kbdq.buf; kbdq.out = kbdq.buf; lineq.in = lineq.buf; lineq.out = lineq.buf; qlock(&kbdq); /* allocate qlock */ qunlock(&kbdq); lock(&lineq); /* allocate lock */ unlock(&lineq); duartinit(); } /* * Put a string on the console. * n bytes of s are guaranteed to fit in the buffer and is ready to print. * Must be called splhi() and with printq locked. */ void puts(char *s, int n) { if(!printq.printing){ printq.printing = 1; printq.c = *s++; n--; } memcpy(printq.in, s, n); printq.in += n; if(printq.in >= printq.buf+sizeof(printq.buf)) printq.in = printq.buf; } /* * Print a string on the console. This is the high level routine * with a queue to the interrupt handler. BUG: There is no check against * overflow. */ void putstrn(char *str, int n) { int s, c, m; char *t; s = splhi(); lock(&printq); | |
| 1990/0718 | syslog(str, n); | |
| 1990/0227 | while(n > 0){ if(*str == '\n') puts("\r", 1); m = printq.buf+sizeof(printq.buf) - printq.in; if(n < m) m = n; t = memchr(str+1, '\n', m-1); if(t) if(t-str < m) m = t - str; puts(str, m); n -= m; str += m; } unlock(&printq); splx(s); } int cangetc(IOQ *q) { return q->in != q->out; } int isbrkc(IOQ *q) { uchar *p; for(p=q->out; p!=q->in; ){ if(*p==0x04 || *p=='\n') return 1; p++; if(p >= q->buf+sizeof(q->buf)) p = q->buf; } return 0; } int getc(IOQ *q) { int c; if(q->in == q->out) return -1; c = *q->out++; if(q->out == q->buf+sizeof(q->buf)) q->out = q->buf; return c; } int sprint(char *s, char *fmt, ...) { | |
| 1990/06111 | return doprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s; | |
| 1990/0227 | } int print(char *fmt, ...) { char buf[PRINTSIZE]; int n; | |
| 1990/06111 | n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; | |
| 1990/0227 | putstrn(buf, n); return n; } void panic(char *fmt, ...) { char buf[PRINTSIZE]; int n; strcpy(buf, "panic: "); | |
| 1990/06111 | n = doprint(buf+7, buf+sizeof(buf), fmt, (&fmt+1)) - buf; | |
| 1990/0227 | buf[n] = '\n'; putstrn(buf, n+1); | |
| 1990/0907 | dumpstack(); | |
| 1990/0227 | exit(); } int pprint(char *fmt, ...) { char buf[2*PRINTSIZE]; Chan *c; int n; c = u->fd[2]; if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) | |
| 1990/0321 | return 0; | |
| 1990/0227 | n = sprint(buf, "%s %d: ", u->p->text, u->p->pid); | |
| 1990/06111 | n = doprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf; | |
| 1990/0227 | qlock(c); if(waserror()){ qunlock(c); | |
| 1990/0321 | return 0; | |
| 1990/0227 | } (*devtab[c->type].write)(c, buf, n); c->offset += n; qunlock(c); | |
| 1990/0321 | poperror(); | |
| 1990/0227 | return n; } void prflush(void) { while(printq.printing) delay(100); } /* * Get character to print at interrupt time. * Always called splhi from proc 0. */ int conschar(void) { uchar *p; int c; lock(&printq); p = printq.out; if(p == printq.in){ printq.printing = 0; c = -1; }else{ c = *p++; if(p >= printq.buf+sizeof(printq.buf)) p = printq.buf; printq.out = p; } unlock(&printq); return c; } void echo(int c) { char ch; | |
| 1990/03091 | ||
| 1990/0227 | /* * ^t hack BUG */ if(c == 0x14) DEBUG(); if(c == 0x15) putstrn("^U\n", 3); | |
| 1990/0504 | if(c == 0x16) | |
| 1990/0707 | dumpqueues(); | |
| 1990/0227 | else{ ch = c; putstrn(&ch, 1); } } /* * Put character into read queue at interrupt time. * Always called splhi from proc 0. */ void kbdchar(int c) { if(c == '\r') c = '\n'; echo(c); *kbdq.in++ = c; if(kbdq.in == kbdq.buf+sizeof(kbdq.buf)) kbdq.in = kbdq.buf; if(c=='\n' || c==0x04) wakeup(&kbdq.r); } void printslave(void) { int c; c = printq.c; if(c){ printq.c = 0; duartxmit(c); } } int consactive(void) { return printq.in != printq.out; } /* * I/O interface */ enum{ Qdir, Qcons, Qcputime, | |
| 1990/0720 | Qlog, | |
| 1990/0227 | Qnull, | |
| 1990/1018 | /* Qpanic, /**/ | |
| 1990/0227 | Qpgrpid, Qpid, Qppid, Qtime, Quser, | |
| 1990/11161 | Qvmereset, | |
| 1990/0227 | }; Dirtab consdir[]={ | |
| 1990/11211 | "cons", {Qcons}, 0, 0600, "cputime", {Qcputime}, 72, 0600, "log", {Qlog}, BY2PG-8, 0600, "null", {Qnull}, 0, 0600, /* "panic", {Qpanic}, 0, 0666, /**/ "pgrpid", {Qpgrpid}, 12, 0600, "pid", {Qpid}, 12, 0600, "ppid", {Qppid}, 12, 0600, "time", {Qtime}, 12, 0600, "user", {Quser}, 0, 0600, "vmereset", {Qvmereset}, 0, 0600, | |
| 1990/0227 | }; #define NCONS (sizeof consdir/sizeof(Dirtab)) ulong boottime; /* seconds since epoch at boot */ long seconds(void) { | |
| 1990/0620 | return boottime + TK2SEC(MACHP(0)->ticks); | |
| 1990/0227 | } int readnum(ulong off, char *buf, ulong n, ulong val, int size) { char tmp[64]; Op op = (Op){ tmp, tmp+sizeof(tmp), &val, size-1, 0, FUNSIGN|FLONG }; numbconv(&op, 10); tmp[size-1] = ' '; | |
| 1990/0312 | if(off >= size) return 0; | |
| 1990/0227 | if(off+n > size) n = size-off; memcpy(buf, tmp+off, n); return n; } int readstr(ulong off, char *buf, ulong n, char *str) { int size; size = strlen(str); | |
| 1990/0312 | if(off >= size) return 0; | |
| 1990/0227 | if(off+n > size) n = size-off; memcpy(buf, str+off, n); return n; } void consreset(void) { } void consinit(void) { } Chan* consattach(char *spec) { return devattach('c', spec); } Chan* consclone(Chan *c, Chan *nc) { return devclone(c, nc); } int conswalk(Chan *c, char *name) { return devwalk(c, name, consdir, NCONS, devgen); } void consstat(Chan *c, char *dp) { devstat(c, dp, consdir, NCONS, devgen); } Chan* consopen(Chan *c, int omode) { | |
| 1990/11211 | if(c->qid.path==Quser && omode==(OWRITE|OTRUNC)){ | |
| 1990/0227 | /* truncate? */ if(strcmp(u->p->pgrp->user, "bootes") == 0) /* BUG */ u->p->pgrp->user[0] = 0; else | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } return devopen(c, omode, consdir, NCONS, devgen); } void conscreate(Chan *c, char *name, int omode, ulong perm) { | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } void consclose(Chan *c) { } long consread(Chan *c, void *buf, long n) { int ch, i, j, k; ulong l; uchar *out; char *cbuf = buf; char *user; int userlen; char tmp[6*NUMSIZE]; if(n <= 0) return n; | |
| 1990/11211 | switch(c->qid.path & ~CHDIR){ | |
| 1990/0227 | case Qdir: return devdirread(c, buf, n, consdir, NCONS, devgen); case Qcons: qlock(&kbdq); | |
| 1990/0617 | if(waserror()){ qunlock(&kbdq); nexterror(); } | |
| 1990/0227 | while(!cangetc(&lineq)){ sleep(&kbdq.r, (int(*)(void*))isbrkc, &kbdq); do{ ch = getc(&kbdq); switch(ch){ case '\b': if(lineq.in != lineq.out){ if(lineq.in == lineq.buf) lineq.in = lineq.buf+sizeof(lineq.buf); lineq.in--; } break; case 0x15: lineq.in = lineq.out; break; default: *lineq.in++ = ch; if(lineq.in == lineq.buf+sizeof(lineq.buf)) lineq.in = lineq.buf; } }while(ch!='\n' && ch!=0x04); } i = 0; while(n>0){ ch = getc(&lineq); if(ch == 0x04 || ch == -1) break; i++; *cbuf++ = ch; --n; } qunlock(&kbdq); return i; case Qcputime: | |
| 1990/0312 | k = c->offset; if(k >= sizeof tmp) return 0; | |
| 1990/0227 | if(k+n > sizeof tmp) n = sizeof tmp - k; /* easiest to format in a separate buffer and copy out */ for(i=0; i<6 && NUMSIZE*i<k+n; i++){ l = u->p->time[i]; if(i == TReal) l = MACHP(0)->ticks - l; | |
| 1990/0614 | l = TK2MS(l); | |
| 1990/0227 | readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); } memcpy(buf, tmp+k, n); return n; case Qpgrpid: return readnum(c->offset, buf, n, u->p->pgrp->pgrpid, NUMSIZE); case Qpid: return readnum(c->offset, buf, n, u->p->pid, NUMSIZE); case Qppid: return readnum(c->offset, buf, n, u->p->parentpid, NUMSIZE); case Qtime: | |
| 1990/0617 | return readnum(c->offset, buf, n, boottime+TK2SEC(MACHP(0)->ticks), 12); | |
| 1990/0227 | case Quser: return readstr(c->offset, buf, n, u->p->pgrp->user); | |
| 1990/0720 | case Qlog: return readlog(c->offset, buf, n); | |
| 1990/0227 | case Qnull: return 0; default: panic("consread %lux\n", c->qid); return 0; } } long conswrite(Chan *c, void *va, long n) { char cbuf[64]; char buf[256]; long l, m; char *a = va; | |
| 1990/11211 | switch(c->qid.path){ | |
| 1990/0227 | case Qcons: /* * Damn. Can't page fault in putstrn, so copy the data locally. */ l = n; while(l > 0){ m = l; if(m > sizeof buf) m = sizeof buf; memcpy(buf, a, m); putstrn(a, m); a += m; l -= m; } break; case Qtime: if(n<=0 || boottime!=0) /* only one write please */ return 0; if(n >= sizeof cbuf) n = sizeof cbuf - 1; memcpy(cbuf, a, n); cbuf[n-1] = 0; boottime = strtoul(a, 0, 0); break; case Quser: if(u->p->pgrp->user[0]) /* trying to overwrite /dev/user */ | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | if(c->offset >= NAMELEN-1) return 0; if(c->offset+n >= NAMELEN-1) n = NAMELEN-1 - c->offset; memcpy(u->p->pgrp->user+c->offset, a, n); u->p->pgrp->user[c->offset+n] = 0; break; case Qcputime: case Qpgrpid: case Qpid: case Qppid: | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | case Qnull: break; | |
| 1990/11161 | case Qvmereset: if(strcmp(u->p->pgrp->user, "bootes") != 0) | |
| 1990/11211 | error(Eperm); | |
| 1990/11161 | vmereset(); break; | |
| 1990/0227 | default: | |
| 1990/11211 | error(Egreg); | |
| 1990/0227 | } return n; } void consremove(Chan *c) { | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } void conswstat(Chan *c, char *dp) { | |
| 1990/11211 | error(Eperm); | |
| 1990/0720 | } /* | |
| 1990/0912 | * kernel based system log, passed between crashes | |
| 1990/0720 | */ void sysloginit(void) { Syslog *s; | |
| 1990/1018 | int i; | |
| 1990/0720 | s = SYSLOG; | |
| 1990/1018 | if(s->magic!=SYSLOGMAGIC || s->next>=&s->buf[sizeof(s->buf)] || s->next<s->buf){ s->wrapped = 0; | |
| 1990/0720 | s->next = s->buf; s->magic = SYSLOGMAGIC; } } void syslog(char *p, int n) { Syslog *s; char *end; | |
| 1990/1018 | int m; | |
| 1990/0720 | ||
| 1990/1018 | sysloginit(); | |
| 1990/0720 | s = SYSLOG; end = &s->buf[sizeof(s->buf)]; | |
| 1990/1018 | while(n){ if(s->next + n > end) m = end - s->next; else m = n; memcpy(s->next, p, m); s->next += m; p += m; n -= m; if(s->next >= end){ s->wrapped = 1; | |
| 1990/0720 | s->next = s->buf; | |
| 1990/1018 | } | |
| 1990/0720 | } | |
| 1990/0912 | wbflush(); | |
| 1990/0720 | } long | |
| 1990/1018 | readlog(ulong off, char *buf, ulong len) | |
| 1990/0720 | { Syslog *s; char *end; | |
| 1990/1018 | char *start; int n, m; char *p; | |
| 1990/0720 | ||
| 1990/1018 | n = len; p = buf; sysloginit(); | |
| 1990/0720 | s = SYSLOG; | |
| 1990/1018 | end = &s->buf[sizeof(s->buf)]; | |
| 1990/0720 | ||
| 1990/1018 | if(s->wrapped){ start = s->next; m = sizeof(s->buf); } else { start = s->buf; m = s->next - start; } if(off > m) | |
| 1990/0720 | return 0; | |
| 1990/1018 | if(off + n > m) n = m - off; start += off; if(start > end) start -= sizeof(s->buf); | |
| 1990/0720 | ||
| 1990/1018 | while(n > 0){ if(start + n > end) m = end - start; else m = n; memcpy(p, start, m); start += m; p += m; n -= m; if(start >= end) start = s->buf; } return p-buf; } /* * Read and write every byte of the log. This seems to ensure that * on reboot, the bytes will really be in memory. I don't understand -- presotto */ void flushsyslog(void) { Syslog *s; char *p, *end; int x; s = SYSLOG; | |
| 1990/0720 | end = &s->buf[sizeof(s->buf)]; | |
| 1990/1018 | x = splhi(); lock(&printq); for(p = s->buf; p < end; p++) *p = *p; unlock(&printq); splx(x); | |
| 1990/0912 | ||
| 1990/1018 | wbflush(); | |
| 1990/0227 | } | |