xref: /csrg-svn/sys/kern/subr_prf.c (revision 30695)
123381Smckusick /*
229101Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323381Smckusick  * All rights reserved.  The Berkeley software License Agreement
423381Smckusick  * specifies the terms and conditions for redistribution.
523381Smckusick  *
6*30695Skarels  *	@(#)subr_prf.c	7.7 (Berkeley) 03/29/87
723381Smckusick  */
831Sbill 
917094Sbloom #include "param.h"
1017094Sbloom #include "systm.h"
1117094Sbloom #include "seg.h"
1217094Sbloom #include "buf.h"
1317094Sbloom #include "conf.h"
1417094Sbloom #include "reboot.h"
1517094Sbloom #include "vm.h"
1617094Sbloom #include "msgbuf.h"
1717094Sbloom #include "dir.h"
1817094Sbloom #include "user.h"
1917094Sbloom #include "proc.h"
2017577Sbloom #include "ioctl.h"
2117094Sbloom #include "tty.h"
2218364Skarels #include "syslog.h"
2331Sbill 
2430625Skarels #include "../machine/mtpr.h"
2530625Skarels #ifdef KDB
2630625Skarels #include "../machine/kdbparam.h"
2730625Skarels #endif
2830625Skarels 
2916724Sralph #define TOCONS	0x1
3016724Sralph #define TOTTY	0x2
3116724Sralph #define TOLOG	0x4
3216724Sralph 
3331Sbill /*
3431Sbill  * In case console is off,
3531Sbill  * panicstr contains argument to last
3631Sbill  * call to panic.
3731Sbill  */
3831Sbill char	*panicstr;
3931Sbill 
4030549Skarels extern	cnputc();			/* standard console putc */
4130549Skarels extern	struct tty cons;		/* standard console tty */
4230549Skarels struct	tty *constty;			/* pointer to console "window" tty */
4330549Skarels int	(*v_putc)() = cnputc;		/* routine to putc on virtual console */
4430549Skarels 
4531Sbill /*
4631Sbill  * Scaled down version of C Library printf.
472781Swnj  * Used to print diagnostic information directly on console tty.
482781Swnj  * Since it is not interrupt driven, all system activities are
492781Swnj  * suspended.  Printf should not be used for chit-chat.
502781Swnj  *
512781Swnj  * One additional format: %b is supported to decode error registers.
522781Swnj  * Usage is:
532781Swnj  *	printf("reg=%b\n", regval, "<base><arg>*");
542781Swnj  * Where <base> is the output base expressed as a control character,
552781Swnj  * e.g. \10 gives octal; \20 gives hex.  Each arg is a sequence of
562781Swnj  * characters, the first of which gives the bit number to be inspected
572781Swnj  * (origin 1), and the next characters (up to a control character, i.e.
582781Swnj  * a character <= 32), give the name of the register.  Thus
592781Swnj  *	printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
602781Swnj  * would produce output:
6117594Skarels  *	reg=3<BITTWO,BITONE>
6231Sbill  */
6329946Skarels #if defined(tahoe)
6429946Skarels int	consintr;
6529946Skarels #endif
6629946Skarels 
6731Sbill /*VARARGS1*/
6831Sbill printf(fmt, x1)
692781Swnj 	char *fmt;
702781Swnj 	unsigned x1;
7131Sbill {
7229946Skarels #if defined(tahoe)
7329946Skarels 	register int savintr;
74285Sbill 
7529946Skarels 	savintr = consintr, consintr = 0;	/* disable interrupts */
7629946Skarels #endif
7716724Sralph 	prf(fmt, &x1, TOCONS | TOLOG, (struct tty *)0);
7816724Sralph 	logwakeup();
7929946Skarels #if defined(tahoe)
8029946Skarels 	consintr = savintr;			/* reenable interrupts */
8129946Skarels #endif
82285Sbill }
83285Sbill 
842377Swnj /*
8525389Skarels  * Uprintf prints to the current user's terminal.
8625389Skarels  * It may block if the tty queue is overfull.
87*30695Skarels  * No message is printed if the queue does not clear
88*30695Skarels  * in a reasonable time.
8925389Skarels  * Should determine whether current terminal user is related
9025389Skarels  * to this process.
912377Swnj  */
922377Swnj /*VARARGS1*/
932377Swnj uprintf(fmt, x1)
942781Swnj 	char *fmt;
952377Swnj 	unsigned x1;
96285Sbill {
9726250Skarels #ifdef notdef
9825389Skarels 	register struct proc *p;
9926250Skarels #endif
10025389Skarels 	register struct tty *tp;
101285Sbill 
10225389Skarels 	if ((tp = u.u_ttyp) == NULL)
10325389Skarels 		return;
10425389Skarels #ifdef notdef
10525389Skarels 	if (tp->t_pgrp && (p = pfind(tp->t_pgrp)))
10626250Skarels 		if (p->p_uid != u.u_uid)	/* doesn't account for setuid */
10725389Skarels 			return;
10825389Skarels #endif
109*30695Skarels 	if (ttycheckoutq(tp, 1))
110*30695Skarels 		prf(fmt, &x1, TOTTY, tp);
111285Sbill }
112285Sbill 
11318364Skarels /*
11418364Skarels  * tprintf prints on the specified terminal (console if none)
11518364Skarels  * and logs the message.  It is designed for error messages from
11625389Skarels  * single-open devices, and may be called from interrupt level
11725389Skarels  * (does not sleep).
11818364Skarels  */
11916724Sralph /*VARARGS2*/
12025389Skarels tprintf(tp, fmt, x1)
12125389Skarels 	register struct tty *tp;
12216724Sralph 	char *fmt;
12316724Sralph 	unsigned x1;
12416724Sralph {
12525389Skarels 	int flags = TOTTY | TOLOG;
12616724Sralph 
12725389Skarels 	logpri(LOG_INFO);
12829946Skarels 	if (tp == (struct tty *)NULL)
12929946Skarels 		tp = &cons;
13025389Skarels 	if (ttycheckoutq(tp, 0) == 0)
13125389Skarels 		flags = TOLOG;
13225389Skarels 	prf(fmt, &x1, flags, tp);
13325389Skarels 	logwakeup();
13416724Sralph }
13516724Sralph 
13616724Sralph /*
13716724Sralph  * Log writes to the log buffer,
13817594Skarels  * and guarantees not to sleep (so can be called by interrupt routines).
13918364Skarels  * If there is no process reading the log yet, it writes to the console also.
14016724Sralph  */
14116724Sralph /*VARARGS2*/
14216724Sralph log(level, fmt, x1)
14316724Sralph 	char *fmt;
14416724Sralph 	unsigned x1;
14516724Sralph {
14616724Sralph 	register s = splhigh();
14718364Skarels 	extern int log_open;
14816724Sralph 
14925389Skarels 	logpri(level);
15016724Sralph 	prf(fmt, &x1, TOLOG, (struct tty *)0);
15116724Sralph 	splx(s);
15218364Skarels 	if (!log_open)
15318364Skarels 		prf(fmt, &x1, TOCONS, (struct tty *)0);
15416724Sralph 	logwakeup();
15516724Sralph }
15616724Sralph 
15725389Skarels logpri(level)
15825389Skarels 	int level;
15925389Skarels {
16025389Skarels 
16125389Skarels 	putchar('<', TOLOG, (struct tty *)0);
16226356Skarels 	printn((u_long)level, 10, TOLOG, (struct tty *)0);
16325389Skarels 	putchar('>', TOLOG, (struct tty *)0);
16425389Skarels }
16525389Skarels 
16616724Sralph prf(fmt, adx, flags, ttyp)
1672781Swnj 	register char *fmt;
1682781Swnj 	register u_int *adx;
16916724Sralph 	struct tty *ttyp;
170285Sbill {
1712434Swnj 	register int b, c, i;
17231Sbill 	char *s;
1732678Swnj 	int any;
17431Sbill 
17531Sbill loop:
1762377Swnj 	while ((c = *fmt++) != '%') {
17716724Sralph 		if (c == '\0')
17831Sbill 			return;
17916724Sralph 		putchar(c, flags, ttyp);
18031Sbill 	}
1812377Swnj again:
18231Sbill 	c = *fmt++;
18329946Skarels 	/* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */
1842377Swnj 	switch (c) {
1852377Swnj 
1862377Swnj 	case 'l':
1872377Swnj 		goto again;
1882377Swnj 	case 'x': case 'X':
1892377Swnj 		b = 16;
1902377Swnj 		goto number;
1912377Swnj 	case 'd': case 'D':
19229946Skarels 		b = -10;
19329946Skarels 		goto number;
19429946Skarels 	case 'u':
1952377Swnj 		b = 10;
1962377Swnj 		goto number;
1972377Swnj 	case 'o': case 'O':
1982377Swnj 		b = 8;
1992377Swnj number:
20016724Sralph 		printn((u_long)*adx, b, flags, ttyp);
2012377Swnj 		break;
2022377Swnj 	case 'c':
2032434Swnj 		b = *adx;
20429946Skarels #if ENDIAN == LITTLE
2052434Swnj 		for (i = 24; i >= 0; i -= 8)
2062434Swnj 			if (c = (b >> i) & 0x7f)
20716724Sralph 				putchar(c, flags, ttyp);
20829946Skarels #endif
20929946Skarels #if ENDIAN == BIG
21029946Skarels 		if (c = (b & 0x7f))
21129946Skarels 			putchar(c, flags, ttyp);
21229946Skarels #endif
2132377Swnj 		break;
2142678Swnj 	case 'b':
2152678Swnj 		b = *adx++;
2162678Swnj 		s = (char *)*adx;
21716724Sralph 		printn((u_long)b, *s++, flags, ttyp);
2182678Swnj 		any = 0;
2192678Swnj 		if (b) {
2202678Swnj 			while (i = *s++) {
2212678Swnj 				if (b & (1 << (i-1))) {
22229946Skarels 					putchar(any ? ',' : '<', flags, ttyp);
2232678Swnj 					any = 1;
2242678Swnj 					for (; (c = *s) > 32; s++)
22516724Sralph 						putchar(c, flags, ttyp);
2262678Swnj 				} else
2272678Swnj 					for (; *s > 32; s++)
2282678Swnj 						;
2292678Swnj 			}
2303878Swnj 			if (any)
23116724Sralph 				putchar('>', flags, ttyp);
2322678Swnj 		}
2332678Swnj 		break;
2342678Swnj 
2352377Swnj 	case 's':
23631Sbill 		s = (char *)*adx;
237285Sbill 		while (c = *s++)
23816724Sralph 			putchar(c, flags, ttyp);
2392377Swnj 		break;
2403736Sroot 
2413736Sroot 	case '%':
24216724Sralph 		putchar('%', flags, ttyp);
2433736Sroot 		break;
24431Sbill 	}
24531Sbill 	adx++;
24631Sbill 	goto loop;
24731Sbill }
24831Sbill 
2492781Swnj /*
2502781Swnj  * Printn prints a number n in base b.
2512781Swnj  * We don't use recursion to avoid deep kernel stacks.
2522781Swnj  */
25316724Sralph printn(n, b, flags, ttyp)
2543101Swnj 	u_long n;
25516724Sralph 	struct tty *ttyp;
25631Sbill {
2572434Swnj 	char prbuf[11];
2582377Swnj 	register char *cp;
25931Sbill 
26029946Skarels 	if (b == -10) {
26129946Skarels 		if ((int)n < 0) {
26229946Skarels 			putchar('-', flags, ttyp);
26329946Skarels 			n = (unsigned)(-(int)n);
26429946Skarels 		}
26529946Skarels 		b = -b;
26631Sbill 	}
2672434Swnj 	cp = prbuf;
2682377Swnj 	do {
2692377Swnj 		*cp++ = "0123456789abcdef"[n%b];
2702377Swnj 		n /= b;
2712377Swnj 	} while (n);
2722377Swnj 	do
27316724Sralph 		putchar(*--cp, flags, ttyp);
2742434Swnj 	while (cp > prbuf);
27531Sbill }
27631Sbill 
27731Sbill /*
2781184Sbill  * Panic is called on unresolvable fatal errors.
2792781Swnj  * It prints "panic: mesg", and then reboots.
2802781Swnj  * If we are called twice, then we avoid trying to
2812781Swnj  * sync the disks as this often leads to recursive panics.
28231Sbill  */
28331Sbill panic(s)
2842781Swnj 	char *s;
28531Sbill {
28630566Skarels 	int bootopt = RB_AUTOBOOT | RB_DUMP;
2872377Swnj 
2885416Swnj 	if (panicstr)
2895416Swnj 		bootopt |= RB_NOSYNC;
2909758Ssam 	else {
2919758Ssam 		panicstr = s;
2928950Sroot 	}
2933285Swnj 	printf("panic: %s\n", s);
29430625Skarels #ifdef KDB
29530625Skarels 	if (boothowto & RB_KDB) {
29630625Skarels 		int s = splnet();	/* below kdb pri */
29730625Skarels 
29830625Skarels 		setsoftkdb();
29930625Skarels 		splx(s);
30030625Skarels 	}
30130625Skarels #endif
30230566Skarels 	boot(bootopt);
30331Sbill }
30431Sbill 
30531Sbill /*
3062941Swnj  * Warn that a system table is full.
3072941Swnj  */
3082941Swnj tablefull(tab)
3092941Swnj 	char *tab;
3102941Swnj {
3112941Swnj 
31224839Seric 	log(LOG_ERR, "%s: table is full\n", tab);
3132941Swnj }
3142941Swnj 
3152941Swnj /*
3162781Swnj  * Hard error is the preface to plaintive error messages
3172941Swnj  * about failing disk transfers.
3182781Swnj  */
3192941Swnj harderr(bp, cp)
3202678Swnj 	struct buf *bp;
3212941Swnj 	char *cp;
32231Sbill {
32331Sbill 
3242941Swnj 	printf("%s%d%c: hard error sn%d ", cp,
32524759Skarels 	    minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno);
32631Sbill }
3272781Swnj 
328285Sbill /*
3292377Swnj  * Print a character on console or users terminal.
330285Sbill  * If destination is console then the last MSGBUFS characters
331285Sbill  * are saved in msgbuf for inspection later.
332285Sbill  */
3331785Sbill /*ARGSUSED*/
33417594Skarels putchar(c, flags, tp)
3352377Swnj 	register int c;
33617594Skarels 	struct tty *tp;
337285Sbill {
33830549Skarels 	int startflags = flags;
339285Sbill 
34030549Skarels 	if (panicstr)
34130549Skarels 		constty = 0;
34230549Skarels 	if ((flags & TOCONS) && tp == 0 && constty) {
34330549Skarels 		tp = constty;
34430549Skarels 		flags |= TOTTY;
34530549Skarels 	}
34616724Sralph 	if (flags & TOTTY) {
34725389Skarels 		register s = spltty();
34825389Skarels 
34925389Skarels 		if (tp && (tp->t_state & (TS_CARR_ON | TS_ISOPEN)) ==
35025389Skarels 		    (TS_CARR_ON | TS_ISOPEN)) {
3512377Swnj 			if (c == '\n')
3524970Swnj 				(void) ttyoutput('\r', tp);
3534970Swnj 			(void) ttyoutput(c, tp);
3542360Skre 			ttstart(tp);
35530549Skarels 		} else if ((flags & TOCONS) && tp == constty)
35630549Skarels 			constty = 0;
35725389Skarels 		splx(s);
3582360Skre 	}
35929946Skarels 	/*
36029946Skarels 	 * Can send to log only after memory management enabled:
36129946Skarels 	 * this has happened by the time maxmem is set.
36229946Skarels 	 */
36329946Skarels 	if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && maxmem) {
3642172Swnj 		if (msgbuf.msg_magic != MSG_MAGIC) {
36512494Ssam 			register int i;
36612494Ssam 
3672172Swnj 			msgbuf.msg_magic = MSG_MAGIC;
36816724Sralph 			msgbuf.msg_bufx = msgbuf.msg_bufr = 0;
36912494Ssam 			for (i=0; i < MSG_BSIZE; i++)
37012494Ssam 				msgbuf.msg_bufc[i] = 0;
3712172Swnj 		}
37226427Sbloom 		msgbuf.msg_bufc[msgbuf.msg_bufx++] = c;
3732172Swnj 		if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE)
3742172Swnj 			msgbuf.msg_bufx = 0;
375285Sbill 	}
37630549Skarels 	if ((flags & TOCONS) && constty == 0 && c != '\0')
37730549Skarels 		(*v_putc)(c);
378285Sbill }
379