xref: /freebsd/sys/kern/subr_prf.c (revision 380a989b3223d455375b4fae70fd0b9bdd43bafb)
1 /*-
2  * Copyright (c) 1986, 1988, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
39  * $Id: subr_prf.c,v 1.50 1998/09/06 06:25:04 ache Exp $
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/msgbuf.h>
46 #include <sys/malloc.h>
47 #include <sys/proc.h>
48 #include <sys/tty.h>
49 #include <sys/tprintf.h>
50 #include <sys/syslog.h>
51 #include <machine/cons.h>
52 
53 /*
54  * Note that stdarg.h and the ANSI style va_start macro is used for both
55  * ANSI and traditional C compilers.
56  */
57 #include <machine/stdarg.h>
58 
59 #define TOCONS	0x01
60 #define TOTTY	0x02
61 #define TOLOG	0x04
62 
63 struct	tty *constty;			/* pointer to console "window" tty */
64 
65 struct putchar_arg {
66 	int flags;
67 	struct tty *tty;
68 };
69 
70 struct snprintf_arg {
71 	char *str;
72 	size_t remain;
73 };
74 
75 static void (*v_putc)(int) = cnputc;	/* routine to putc on virtual console */
76 static void  logpri __P((int level));
77 static void  msglogchar(int c, void *dummyarg);
78 static void  putchar __P((int ch, void *arg));
79 static char *ksprintn __P((u_long num, int base, int *len));
80 static void  snprintf_func __P((int ch, void *arg));
81 
82 static int consintr = 1;		/* Ok to handle console interrupts? */
83 static int msgbufmapped;		/* Set when safe to use msgbuf */
84 
85 /*
86  * Warn that a system table is full.
87  */
88 void
89 tablefull(tab)
90 	const char *tab;
91 {
92 
93 	log(LOG_ERR, "%s: table is full\n", tab);
94 }
95 
96 /*
97  * Uprintf prints to the controlling terminal for the current process.
98  * It may block if the tty queue is overfull.  No message is printed if
99  * the queue does not clear in a reasonable time.
100  */
101 void
102 uprintf(const char *fmt, ...)
103 {
104 	struct proc *p = curproc;
105 	va_list ap;
106 	struct putchar_arg pca;
107 
108 	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
109 		va_start(ap, fmt);
110 		pca.tty = p->p_session->s_ttyp;
111 		pca.flags = TOTTY;
112 		kvprintf(fmt, putchar, &pca, 10, ap);
113 		va_end(ap);
114 	}
115 }
116 
117 tpr_t
118 tprintf_open(p)
119 	register struct proc *p;
120 {
121 
122 	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
123 		SESSHOLD(p->p_session);
124 		return ((tpr_t) p->p_session);
125 	}
126 	return ((tpr_t) NULL);
127 }
128 
129 void
130 tprintf_close(sess)
131 	tpr_t sess;
132 {
133 
134 	if (sess)
135 		SESSRELE((struct session *) sess);
136 }
137 
138 /*
139  * tprintf prints on the controlling terminal associated
140  * with the given session.
141  */
142 void
143 tprintf(tpr_t tpr, const char *fmt, ...)
144 {
145 	register struct session *sess = (struct session *)tpr;
146 	struct tty *tp = NULL;
147 	int flags = TOLOG;
148 	va_list ap;
149 	struct putchar_arg pca;
150 
151 	logpri(LOG_INFO);
152 	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
153 		flags |= TOTTY;
154 		tp = sess->s_ttyp;
155 	}
156 	va_start(ap, fmt);
157 	pca.tty = tp;
158 	pca.flags = flags;
159 	kvprintf(fmt, putchar, &pca, 10, ap);
160 	va_end(ap);
161 	logwakeup();
162 }
163 
164 /*
165  * Ttyprintf displays a message on a tty; it should be used only by
166  * the tty driver, or anything that knows the underlying tty will not
167  * be revoke(2)'d away.  Other callers should use tprintf.
168  */
169 void
170 ttyprintf(struct tty *tp, const char *fmt, ...)
171 {
172 	va_list ap;
173 	struct putchar_arg pca;
174 	va_start(ap, fmt);
175 	pca.tty = tp;
176 	pca.flags = TOTTY;
177 	kvprintf(fmt, putchar, &pca, 10, ap);
178 	va_end(ap);
179 }
180 
181 extern	int log_open;
182 
183 /*
184  * Log writes to the log buffer, and guarantees not to sleep (so can be
185  * called by interrupt routines).  If there is no process reading the
186  * log yet, it writes to the console also.
187  */
188 void
189 log(int level, const char *fmt, ...)
190 {
191 	register int s;
192 	va_list ap;
193 
194 	s = splhigh();
195 	logpri(level);
196 	va_start(ap, fmt);
197 
198 	kvprintf(fmt, msglogchar, NULL, 10, ap);
199 	va_end(ap);
200 
201 	splx(s);
202 	if (!log_open) {
203 		struct putchar_arg pca;
204 		va_start(ap, fmt);
205 		pca.tty = NULL;
206 		pca.flags = TOCONS;
207 		kvprintf(fmt, putchar, &pca, 10, ap);
208 		va_end(ap);
209 	}
210 	logwakeup();
211 }
212 
213 static void
214 logpri(level)
215 	int level;
216 {
217 	register char *p;
218 
219 	msglogchar('<', NULL);
220 	for (p = ksprintn((u_long)level, 10, NULL); *p;)
221 		msglogchar(*p--, NULL);
222 	msglogchar('>', NULL);
223 }
224 
225 int
226 addlog(const char *fmt, ...)
227 {
228 	register int s;
229 	va_list ap;
230 	int retval;
231 
232 	s = splhigh();
233 	va_start(ap, fmt);
234 	retval = kvprintf(fmt, msglogchar, NULL, 10, ap);
235 	splx(s);
236 	va_end(ap);
237 	if (!log_open) {
238 		struct putchar_arg pca;
239 		va_start(ap, fmt);
240 		pca.tty = NULL;
241 		pca.flags = TOCONS;
242 		kvprintf(fmt, putchar, &pca, 10, ap);
243 		va_end(ap);
244 	}
245 	logwakeup();
246 	return (retval);
247 }
248 
249 int
250 printf(const char *fmt, ...)
251 {
252 	va_list ap;
253 	register int savintr;
254 	struct putchar_arg pca;
255 	int retval;
256 
257 	savintr = consintr;		/* disable interrupts */
258 	consintr = 0;
259 	va_start(ap, fmt);
260 	pca.tty = NULL;
261 	pca.flags = TOCONS | TOLOG;
262 	retval = kvprintf(fmt, putchar, &pca, 10, ap);
263 	va_end(ap);
264 	if (!panicstr)
265 		logwakeup();
266 	consintr = savintr;		/* reenable interrupts */
267 	return retval;
268 }
269 
270 void
271 vprintf(const char *fmt, va_list ap)
272 {
273 	register int savintr;
274 	struct putchar_arg pca;
275 
276 	savintr = consintr;		/* disable interrupts */
277 	consintr = 0;
278 	pca.tty = NULL;
279 	pca.flags = TOCONS | TOLOG;
280 	kvprintf(fmt, putchar, &pca, 10, ap);
281 	if (!panicstr)
282 		logwakeup();
283 	consintr = savintr;		/* reenable interrupts */
284 }
285 
286 /*
287  * Print a character on console or users terminal.  If destination is
288  * the console then the last bunch of characters are saved in msgbuf for
289  * inspection later.
290  */
291 static void
292 putchar(int c, void *arg)
293 {
294 	struct putchar_arg *ap = (struct putchar_arg*) arg;
295 	int flags = ap->flags;
296 	struct tty *tp = ap->tty;
297 	if (panicstr)
298 		constty = NULL;
299 	if ((flags & TOCONS) && tp == NULL && constty) {
300 		tp = constty;
301 		flags |= TOTTY;
302 	}
303 	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
304 	    (flags & TOCONS) && tp == constty)
305 		constty = NULL;
306 	if ((flags & TOLOG))
307 		msglogchar(c, NULL);
308 	if ((flags & TOCONS) && constty == NULL && c != '\0')
309 		(*v_putc)(c);
310 }
311 
312 /*
313  * Scaled down version of sprintf(3).
314  */
315 int
316 sprintf(char *buf, const char *cfmt, ...)
317 {
318 	int retval;
319 	va_list ap;
320 
321 	va_start(ap, cfmt);
322 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
323 	buf[retval] = '\0';
324 	va_end(ap);
325 	return retval;
326 }
327 
328 /*
329  * Scaled down version of vsprintf(3).
330  */
331 int
332 vsprintf(char *buf, const char *cfmt, va_list ap)
333 {
334 	int retval;
335 
336 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
337 	buf[retval] = '\0';
338 	return retval;
339 }
340 
341 /*
342  * Scaled down version of snprintf(3).
343  */
344 int
345 snprintf(char *str, size_t size, const char *format, ...)
346 {
347 	int retval;
348 	va_list ap;
349 
350 	va_start(ap, format);
351 	retval = vsnprintf(str, size, format, ap);
352 	va_end(ap);
353 	return(retval);
354 }
355 
356 /*
357  * Scaled down version of vsnprintf(3).
358  */
359 int
360 vsnprintf(char *str, size_t size, const char *format, va_list ap)
361 {
362 	struct snprintf_arg info;
363 	int retval;
364 
365 	info.str = str;
366 	info.remain = size;
367 	retval = kvprintf(format, snprintf_func, &info, 10, ap);
368 	if (info.remain >= 1)
369 		*info.str++ = '\0';
370 	return retval;
371 }
372 
373 static void
374 snprintf_func(int ch, void *arg)
375 {
376 	struct snprintf_arg *const info = arg;
377 
378 	if (info->remain >= 2) {
379 		*info->str++ = ch;
380 		info->remain--;
381 	}
382 }
383 
384 /*
385  * Put a number (base <= 16) in a buffer in reverse order; return an
386  * optional length and a pointer to the NULL terminated (preceded?)
387  * buffer.
388  */
389 static char *
390 ksprintn(ul, base, lenp)
391 	register u_long ul;
392 	register int base, *lenp;
393 {					/* A long in base 8, plus NULL. */
394 	static char buf[sizeof(long) * NBBY / 3 + 2];
395 	register char *p;
396 
397 	p = buf;
398 	do {
399 		*++p = hex2ascii(ul % base);
400 	} while (ul /= base);
401 	if (lenp)
402 		*lenp = p - buf;
403 	return (p);
404 }
405 
406 /*
407  * Scaled down version of printf(3).
408  *
409  * Two additional formats:
410  *
411  * The format %b is supported to decode error registers.
412  * Its usage is:
413  *
414  *	printf("reg=%b\n", regval, "<base><arg>*");
415  *
416  * where <base> is the output base expressed as a control character, e.g.
417  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
418  * the first of which gives the bit number to be inspected (origin 1), and
419  * the next characters (up to a control character, i.e. a character <= 32),
420  * give the name of the register.  Thus:
421  *
422  *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
423  *
424  * would produce output:
425  *
426  *	reg=3<BITTWO,BITONE>
427  *
428  * XXX:  %D  -- Hexdump, takes pointer and separator string:
429  *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
430  *		("%*D", len, ptr, " " -> XX XX XX XX ...
431  */
432 int
433 kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
434 {
435 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
436 	char *p, *q, *d;
437 	u_char *up;
438 	int ch, n;
439 	u_long ul;
440 	int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
441 	int dwidth;
442 	char padc;
443 	int retval = 0;
444 
445 	if (!func)
446 		d = (char *) arg;
447 	else
448 		d = NULL;
449 
450 	if (fmt == NULL)
451 		fmt = "(fmt null)\n";
452 
453 	if (radix < 2 || radix > 36)
454 		radix = 10;
455 
456 	for (;;) {
457 		padc = ' ';
458 		width = 0;
459 		while ((ch = (u_char)*fmt++) != '%') {
460 			if (ch == '\0')
461 				return retval;
462 			PCHAR(ch);
463 		}
464 		lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
465 		sign = 0; dot = 0; dwidth = 0;
466 reswitch:	switch (ch = (u_char)*fmt++) {
467 		case '.':
468 			dot = 1;
469 			goto reswitch;
470 		case '#':
471 			sharpflag = 1;
472 			goto reswitch;
473 		case '+':
474 			sign = 1;
475 			goto reswitch;
476 		case '-':
477 			ladjust = 1;
478 			goto reswitch;
479 		case '%':
480 			PCHAR(ch);
481 			break;
482 		case '*':
483 			if (!dot) {
484 				width = va_arg(ap, int);
485 				if (width < 0) {
486 					ladjust = !ladjust;
487 					width = -width;
488 				}
489 			} else {
490 				dwidth = va_arg(ap, int);
491 			}
492 			goto reswitch;
493 		case '0':
494 			if (!dot) {
495 				padc = '0';
496 				goto reswitch;
497 			}
498 		case '1': case '2': case '3': case '4':
499 		case '5': case '6': case '7': case '8': case '9':
500 				for (n = 0;; ++fmt) {
501 					n = n * 10 + ch - '0';
502 					ch = *fmt;
503 					if (ch < '0' || ch > '9')
504 						break;
505 				}
506 			if (dot)
507 				dwidth = n;
508 			else
509 				width = n;
510 			goto reswitch;
511 		case 'b':
512 			ul = va_arg(ap, int);
513 			p = va_arg(ap, char *);
514 			for (q = ksprintn(ul, *p++, NULL); *q;)
515 				PCHAR(*q--);
516 
517 			if (!ul)
518 				break;
519 
520 			for (tmp = 0; *p;) {
521 				n = *p++;
522 				if (ul & (1 << (n - 1))) {
523 					PCHAR(tmp ? ',' : '<');
524 					for (; (n = *p) > ' '; ++p)
525 						PCHAR(n);
526 					tmp = 1;
527 				} else
528 					for (; *p > ' '; ++p)
529 						continue;
530 			}
531 			if (tmp)
532 				PCHAR('>');
533 			break;
534 		case 'c':
535 			PCHAR(va_arg(ap, int));
536 			break;
537 		case 'D':
538 			up = va_arg(ap, u_char *);
539 			p = va_arg(ap, char *);
540 			if (!width)
541 				width = 16;
542 			while(width--) {
543 				PCHAR(hex2ascii(*up >> 4));
544 				PCHAR(hex2ascii(*up & 0x0f));
545 				up++;
546 				if (width)
547 					for (q=p;*q;q++)
548 						PCHAR(*q);
549 			}
550 			break;
551 		case 'd':
552 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
553 			sign = 1;
554 			base = 10;
555 			goto number;
556 		case 'l':
557 			lflag = 1;
558 			goto reswitch;
559 		case 'o':
560 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
561 			base = 8;
562 			goto nosign;
563 		case 'p':
564 			ul = (uintptr_t)va_arg(ap, void *);
565 			base = 16;
566 			sharpflag = (width == 0);
567 			goto nosign;
568 		case 'n':
569 		case 'r':
570 			ul = lflag ? va_arg(ap, u_long) :
571 			    sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int);
572 			base = radix;
573 			goto number;
574 		case 's':
575 			p = va_arg(ap, char *);
576 			if (p == NULL)
577 				p = "(null)";
578 			if (!dot)
579 				n = strlen (p);
580 			else
581 				for (n = 0; n < dwidth && p[n]; n++)
582 					continue;
583 
584 			width -= n;
585 
586 			if (!ladjust && width > 0)
587 				while (width--)
588 					PCHAR(padc);
589 			while (n--)
590 				PCHAR(*p++);
591 			if (ladjust && width > 0)
592 				while (width--)
593 					PCHAR(padc);
594 			break;
595 		case 'u':
596 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
597 			base = 10;
598 			goto nosign;
599 		case 'x':
600 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
601 			base = 16;
602 			goto nosign;
603 		case 'z':
604 			ul = lflag ? va_arg(ap, u_long) :
605 			    sign ? (u_long)va_arg(ap, int) : va_arg(ap, u_int);
606 			base = 16;
607 			goto number;
608 nosign:			sign = 0;
609 number:			if (sign && (long)ul < 0L) {
610 				neg = 1;
611 				ul = -(long)ul;
612 			}
613 			p = ksprintn(ul, base, &tmp);
614 			if (sharpflag && ul != 0) {
615 				if (base == 8)
616 					tmp++;
617 				else if (base == 16)
618 					tmp += 2;
619 			}
620 			if (neg)
621 				tmp++;
622 
623 			if (!ladjust && width && (width -= tmp) > 0)
624 				while (width--)
625 					PCHAR(padc);
626 			if (neg)
627 				PCHAR('-');
628 			if (sharpflag && ul != 0) {
629 				if (base == 8) {
630 					PCHAR('0');
631 				} else if (base == 16) {
632 					PCHAR('0');
633 					PCHAR('x');
634 				}
635 			}
636 
637 			while (*p)
638 				PCHAR(*p--);
639 
640 			if (ladjust && width && (width -= tmp) > 0)
641 				while (width--)
642 					PCHAR(padc);
643 
644 			break;
645 		default:
646 			PCHAR('%');
647 			if (lflag)
648 				PCHAR('l');
649 			PCHAR(ch);
650 			break;
651 		}
652 	}
653 #undef PCHAR
654 }
655 
656 /*
657  * Put character in log buffer.
658  */
659 static void
660 msglogchar(int c, void *dummyarg)
661 {
662 	struct msgbuf *mbp;
663 
664 	if (c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
665 		mbp = msgbufp;
666 		mbp->msg_ptr[mbp->msg_bufx++] = c;
667 		if (mbp->msg_bufx >= mbp->msg_size)
668 			mbp->msg_bufx = 0;
669 		/* If the buffer is full, keep the most recent data. */
670 		if (mbp->msg_bufr == mbp->msg_bufx) {
671 			if (++mbp->msg_bufr >= mbp->msg_size)
672 				mbp->msg_bufr = 0;
673 		}
674 	}
675 }
676 
677 void
678 msgbufinit(void *ptr, size_t size)
679 {
680 	char *cp;
681 
682 	cp = (char *)ptr;
683 	msgbufp = (struct msgbuf *) (cp + size - sizeof(*msgbufp));
684 	if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_ptr != cp) {
685 		bzero(cp, size);
686 		msgbufp->msg_magic = MSG_MAGIC;
687 		msgbufp->msg_size = (char *)msgbufp - cp;
688 		msgbufp->msg_ptr = cp;
689 	}
690 	msgbufmapped = 1;
691 }
692 
693 #include "opt_ddb.h"
694 #ifdef DDB
695 #include <ddb/ddb.h>
696 
697 DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
698 {
699 	int i, j;
700 
701 	if (!msgbufmapped) {
702 		db_printf("msgbuf not mapped yet\n");
703 		return;
704 	}
705 	db_printf("msgbufp = %p\n", msgbufp);
706 	db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n",
707 	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
708 	    msgbufp->msg_bufx, msgbufp->msg_ptr);
709 	for (i = 0; i < msgbufp->msg_size; i++) {
710 		j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
711 		db_printf("%c", msgbufp->msg_ptr[j]);
712 	}
713 	db_printf("\n");
714 }
715 
716 #endif /* DDB */
717