xref: /csrg-svn/sys/kern/subr_prf.c (revision 30549)
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*30549Skarels  *	@(#)subr_prf.c	7.4 (Berkeley) 02/21/87
723381Smckusick  */
829946Skarels #include "../machine/mtpr.h"
931Sbill 
1017094Sbloom #include "param.h"
1117094Sbloom #include "systm.h"
1217094Sbloom #include "seg.h"
1317094Sbloom #include "buf.h"
1417094Sbloom #include "conf.h"
1517094Sbloom #include "reboot.h"
1617094Sbloom #include "vm.h"
1717094Sbloom #include "msgbuf.h"
1817094Sbloom #include "dir.h"
1917094Sbloom #include "user.h"
2017094Sbloom #include "proc.h"
2117577Sbloom #include "ioctl.h"
2217094Sbloom #include "tty.h"
2318364Skarels #include "syslog.h"
2431Sbill 
2516724Sralph #define TOCONS	0x1
2616724Sralph #define TOTTY	0x2
2716724Sralph #define TOLOG	0x4
2816724Sralph 
2931Sbill /*
3031Sbill  * In case console is off,
3131Sbill  * panicstr contains argument to last
3231Sbill  * call to panic.
3331Sbill  */
3431Sbill char	*panicstr;
3531Sbill 
36*30549Skarels extern	cnputc();			/* standard console putc */
37*30549Skarels extern	struct tty cons;		/* standard console tty */
38*30549Skarels struct	tty *constty;			/* pointer to console "window" tty */
39*30549Skarels int	(*v_putc)() = cnputc;		/* routine to putc on virtual console */
40*30549Skarels 
4131Sbill /*
4231Sbill  * Scaled down version of C Library printf.
432781Swnj  * Used to print diagnostic information directly on console tty.
442781Swnj  * Since it is not interrupt driven, all system activities are
452781Swnj  * suspended.  Printf should not be used for chit-chat.
462781Swnj  *
472781Swnj  * One additional format: %b is supported to decode error registers.
482781Swnj  * Usage is:
492781Swnj  *	printf("reg=%b\n", regval, "<base><arg>*");
502781Swnj  * Where <base> is the output base expressed as a control character,
512781Swnj  * e.g. \10 gives octal; \20 gives hex.  Each arg is a sequence of
522781Swnj  * characters, the first of which gives the bit number to be inspected
532781Swnj  * (origin 1), and the next characters (up to a control character, i.e.
542781Swnj  * a character <= 32), give the name of the register.  Thus
552781Swnj  *	printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
562781Swnj  * would produce output:
5717594Skarels  *	reg=3<BITTWO,BITONE>
5831Sbill  */
5929946Skarels #if defined(tahoe)
6029946Skarels int	consintr;
6129946Skarels #endif
6229946Skarels 
6331Sbill /*VARARGS1*/
6431Sbill printf(fmt, x1)
652781Swnj 	char *fmt;
662781Swnj 	unsigned x1;
6731Sbill {
6829946Skarels #if defined(tahoe)
6929946Skarels 	register int savintr;
70285Sbill 
7129946Skarels 	savintr = consintr, consintr = 0;	/* disable interrupts */
7229946Skarels #endif
7316724Sralph 	prf(fmt, &x1, TOCONS | TOLOG, (struct tty *)0);
7416724Sralph 	logwakeup();
7529946Skarels #if defined(tahoe)
7629946Skarels 	consintr = savintr;			/* reenable interrupts */
7729946Skarels #endif
78285Sbill }
79285Sbill 
802377Swnj /*
8125389Skarels  * Uprintf prints to the current user's terminal.
8225389Skarels  * It may block if the tty queue is overfull.
8325389Skarels  * Should determine whether current terminal user is related
8425389Skarels  * to this process.
852377Swnj  */
862377Swnj /*VARARGS1*/
872377Swnj uprintf(fmt, x1)
882781Swnj 	char *fmt;
892377Swnj 	unsigned x1;
90285Sbill {
9126250Skarels #ifdef notdef
9225389Skarels 	register struct proc *p;
9326250Skarels #endif
9425389Skarels 	register struct tty *tp;
95285Sbill 
9625389Skarels 	if ((tp = u.u_ttyp) == NULL)
9725389Skarels 		return;
9825389Skarels #ifdef notdef
9925389Skarels 	if (tp->t_pgrp && (p = pfind(tp->t_pgrp)))
10026250Skarels 		if (p->p_uid != u.u_uid)	/* doesn't account for setuid */
10125389Skarels 			return;
10225389Skarels #endif
10325389Skarels 	(void)ttycheckoutq(tp, 1);
10425389Skarels 	prf(fmt, &x1, TOTTY, tp);
105285Sbill }
106285Sbill 
10718364Skarels /*
10818364Skarels  * tprintf prints on the specified terminal (console if none)
10918364Skarels  * and logs the message.  It is designed for error messages from
11025389Skarels  * single-open devices, and may be called from interrupt level
11125389Skarels  * (does not sleep).
11218364Skarels  */
11316724Sralph /*VARARGS2*/
11425389Skarels tprintf(tp, fmt, x1)
11525389Skarels 	register struct tty *tp;
11616724Sralph 	char *fmt;
11716724Sralph 	unsigned x1;
11816724Sralph {
11925389Skarels 	int flags = TOTTY | TOLOG;
12016724Sralph 
12125389Skarels 	logpri(LOG_INFO);
12229946Skarels 	if (tp == (struct tty *)NULL)
12329946Skarels 		tp = &cons;
12425389Skarels 	if (ttycheckoutq(tp, 0) == 0)
12525389Skarels 		flags = TOLOG;
12625389Skarels 	prf(fmt, &x1, flags, tp);
12725389Skarels 	logwakeup();
12816724Sralph }
12916724Sralph 
13016724Sralph /*
13116724Sralph  * Log writes to the log buffer,
13217594Skarels  * and guarantees not to sleep (so can be called by interrupt routines).
13318364Skarels  * If there is no process reading the log yet, it writes to the console also.
13416724Sralph  */
13516724Sralph /*VARARGS2*/
13616724Sralph log(level, fmt, x1)
13716724Sralph 	char *fmt;
13816724Sralph 	unsigned x1;
13916724Sralph {
14016724Sralph 	register s = splhigh();
14118364Skarels 	extern int log_open;
14216724Sralph 
14325389Skarels 	logpri(level);
14416724Sralph 	prf(fmt, &x1, TOLOG, (struct tty *)0);
14516724Sralph 	splx(s);
14618364Skarels 	if (!log_open)
14718364Skarels 		prf(fmt, &x1, TOCONS, (struct tty *)0);
14816724Sralph 	logwakeup();
14916724Sralph }
15016724Sralph 
15125389Skarels logpri(level)
15225389Skarels 	int level;
15325389Skarels {
15425389Skarels 
15525389Skarels 	putchar('<', TOLOG, (struct tty *)0);
15626356Skarels 	printn((u_long)level, 10, TOLOG, (struct tty *)0);
15725389Skarels 	putchar('>', TOLOG, (struct tty *)0);
15825389Skarels }
15925389Skarels 
16016724Sralph prf(fmt, adx, flags, ttyp)
1612781Swnj 	register char *fmt;
1622781Swnj 	register u_int *adx;
16316724Sralph 	struct tty *ttyp;
164285Sbill {
1652434Swnj 	register int b, c, i;
16631Sbill 	char *s;
1672678Swnj 	int any;
16831Sbill 
16931Sbill loop:
1702377Swnj 	while ((c = *fmt++) != '%') {
17116724Sralph 		if (c == '\0')
17231Sbill 			return;
17316724Sralph 		putchar(c, flags, ttyp);
17431Sbill 	}
1752377Swnj again:
17631Sbill 	c = *fmt++;
17729946Skarels 	/* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */
1782377Swnj 	switch (c) {
1792377Swnj 
1802377Swnj 	case 'l':
1812377Swnj 		goto again;
1822377Swnj 	case 'x': case 'X':
1832377Swnj 		b = 16;
1842377Swnj 		goto number;
1852377Swnj 	case 'd': case 'D':
18629946Skarels 		b = -10;
18729946Skarels 		goto number;
18829946Skarels 	case 'u':
1892377Swnj 		b = 10;
1902377Swnj 		goto number;
1912377Swnj 	case 'o': case 'O':
1922377Swnj 		b = 8;
1932377Swnj number:
19416724Sralph 		printn((u_long)*adx, b, flags, ttyp);
1952377Swnj 		break;
1962377Swnj 	case 'c':
1972434Swnj 		b = *adx;
19829946Skarels #if ENDIAN == LITTLE
1992434Swnj 		for (i = 24; i >= 0; i -= 8)
2002434Swnj 			if (c = (b >> i) & 0x7f)
20116724Sralph 				putchar(c, flags, ttyp);
20229946Skarels #endif
20329946Skarels #if ENDIAN == BIG
20429946Skarels 		if (c = (b & 0x7f))
20529946Skarels 			putchar(c, flags, ttyp);
20629946Skarels #endif
2072377Swnj 		break;
2082678Swnj 	case 'b':
2092678Swnj 		b = *adx++;
2102678Swnj 		s = (char *)*adx;
21116724Sralph 		printn((u_long)b, *s++, flags, ttyp);
2122678Swnj 		any = 0;
2132678Swnj 		if (b) {
2142678Swnj 			while (i = *s++) {
2152678Swnj 				if (b & (1 << (i-1))) {
21629946Skarels 					putchar(any ? ',' : '<', flags, ttyp);
2172678Swnj 					any = 1;
2182678Swnj 					for (; (c = *s) > 32; s++)
21916724Sralph 						putchar(c, flags, ttyp);
2202678Swnj 				} else
2212678Swnj 					for (; *s > 32; s++)
2222678Swnj 						;
2232678Swnj 			}
2243878Swnj 			if (any)
22516724Sralph 				putchar('>', flags, ttyp);
2262678Swnj 		}
2272678Swnj 		break;
2282678Swnj 
2292377Swnj 	case 's':
23031Sbill 		s = (char *)*adx;
231285Sbill 		while (c = *s++)
23216724Sralph 			putchar(c, flags, ttyp);
2332377Swnj 		break;
2343736Sroot 
2353736Sroot 	case '%':
23616724Sralph 		putchar('%', flags, ttyp);
2373736Sroot 		break;
23831Sbill 	}
23931Sbill 	adx++;
24031Sbill 	goto loop;
24131Sbill }
24231Sbill 
2432781Swnj /*
2442781Swnj  * Printn prints a number n in base b.
2452781Swnj  * We don't use recursion to avoid deep kernel stacks.
2462781Swnj  */
24716724Sralph printn(n, b, flags, ttyp)
2483101Swnj 	u_long n;
24916724Sralph 	struct tty *ttyp;
25031Sbill {
2512434Swnj 	char prbuf[11];
2522377Swnj 	register char *cp;
25331Sbill 
25429946Skarels 	if (b == -10) {
25529946Skarels 		if ((int)n < 0) {
25629946Skarels 			putchar('-', flags, ttyp);
25729946Skarels 			n = (unsigned)(-(int)n);
25829946Skarels 		}
25929946Skarels 		b = -b;
26031Sbill 	}
2612434Swnj 	cp = prbuf;
2622377Swnj 	do {
2632377Swnj 		*cp++ = "0123456789abcdef"[n%b];
2642377Swnj 		n /= b;
2652377Swnj 	} while (n);
2662377Swnj 	do
26716724Sralph 		putchar(*--cp, flags, ttyp);
2682434Swnj 	while (cp > prbuf);
26931Sbill }
27031Sbill 
27131Sbill /*
2721184Sbill  * Panic is called on unresolvable fatal errors.
2732781Swnj  * It prints "panic: mesg", and then reboots.
2742781Swnj  * If we are called twice, then we avoid trying to
2752781Swnj  * sync the disks as this often leads to recursive panics.
27631Sbill  */
27731Sbill panic(s)
2782781Swnj 	char *s;
27931Sbill {
2805416Swnj 	int bootopt = RB_AUTOBOOT;
2812377Swnj 
2825416Swnj 	if (panicstr)
2835416Swnj 		bootopt |= RB_NOSYNC;
2849758Ssam 	else {
2859758Ssam 		panicstr = s;
2868950Sroot 	}
2873285Swnj 	printf("panic: %s\n", s);
2882781Swnj 	boot(RB_PANIC, bootopt);
28931Sbill }
29031Sbill 
29131Sbill /*
2922941Swnj  * Warn that a system table is full.
2932941Swnj  */
2942941Swnj tablefull(tab)
2952941Swnj 	char *tab;
2962941Swnj {
2972941Swnj 
29824839Seric 	log(LOG_ERR, "%s: table is full\n", tab);
2992941Swnj }
3002941Swnj 
3012941Swnj /*
3022781Swnj  * Hard error is the preface to plaintive error messages
3032941Swnj  * about failing disk transfers.
3042781Swnj  */
3052941Swnj harderr(bp, cp)
3062678Swnj 	struct buf *bp;
3072941Swnj 	char *cp;
30831Sbill {
30931Sbill 
3102941Swnj 	printf("%s%d%c: hard error sn%d ", cp,
31124759Skarels 	    minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno);
31231Sbill }
3132781Swnj 
314285Sbill /*
3152377Swnj  * Print a character on console or users terminal.
316285Sbill  * If destination is console then the last MSGBUFS characters
317285Sbill  * are saved in msgbuf for inspection later.
318285Sbill  */
3191785Sbill /*ARGSUSED*/
32017594Skarels putchar(c, flags, tp)
3212377Swnj 	register int c;
32217594Skarels 	struct tty *tp;
323285Sbill {
324*30549Skarels 	int startflags = flags;
325285Sbill 
326*30549Skarels 	if (panicstr)
327*30549Skarels 		constty = 0;
328*30549Skarels 	if ((flags & TOCONS) && tp == 0 && constty) {
329*30549Skarels 		tp = constty;
330*30549Skarels 		flags |= TOTTY;
331*30549Skarels 	}
33216724Sralph 	if (flags & TOTTY) {
33325389Skarels 		register s = spltty();
33425389Skarels 
33525389Skarels 		if (tp && (tp->t_state & (TS_CARR_ON | TS_ISOPEN)) ==
33625389Skarels 		    (TS_CARR_ON | TS_ISOPEN)) {
3372377Swnj 			if (c == '\n')
3384970Swnj 				(void) ttyoutput('\r', tp);
3394970Swnj 			(void) ttyoutput(c, tp);
3402360Skre 			ttstart(tp);
341*30549Skarels 		} else if ((flags & TOCONS) && tp == constty)
342*30549Skarels 			constty = 0;
34325389Skarels 		splx(s);
3442360Skre 	}
34529946Skarels 	/*
34629946Skarels 	 * Can send to log only after memory management enabled:
34729946Skarels 	 * this has happened by the time maxmem is set.
34829946Skarels 	 */
34929946Skarels 	if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && maxmem) {
3502172Swnj 		if (msgbuf.msg_magic != MSG_MAGIC) {
35112494Ssam 			register int i;
35212494Ssam 
3532172Swnj 			msgbuf.msg_magic = MSG_MAGIC;
35416724Sralph 			msgbuf.msg_bufx = msgbuf.msg_bufr = 0;
35512494Ssam 			for (i=0; i < MSG_BSIZE; i++)
35612494Ssam 				msgbuf.msg_bufc[i] = 0;
3572172Swnj 		}
35826427Sbloom 		msgbuf.msg_bufc[msgbuf.msg_bufx++] = c;
3592172Swnj 		if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE)
3602172Swnj 			msgbuf.msg_bufx = 0;
361285Sbill 	}
362*30549Skarels 	if ((flags & TOCONS) && constty == 0 && c != '\0')
363*30549Skarels 		(*v_putc)(c);
364285Sbill }
365