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