Deleted Added
full compact
subr_prf.c (10225) subr_prf.c (12819)
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
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.17 1995/08/07 08:40:49 davidg Exp $
39 * $Id: subr_prf.c,v 1.18 1995/08/24 12:54:11 davidg Exp $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/reboot.h>
45#include <sys/msgbuf.h>
46#include <sys/proc.h>
47#include <sys/vnode.h>
48#include <sys/tty.h>
49#include <sys/tprintf.h>
50#include <sys/syslog.h>
51#include <sys/malloc.h>
52#include <machine/cons.h>
53
54/*
55 * Note that stdarg.h and the ANSI style va_start macro is used for both
56 * ANSI and traditional C compilers.
57 */
58#include <machine/stdarg.h>
59
60#ifdef KADB
61#include <machine/kdbparam.h>
62#endif
63
64
65#define TOCONS 0x01
66#define TOTTY 0x02
67#define TOLOG 0x04
68
69struct tty *constty; /* pointer to console "window" tty */
70
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/reboot.h>
45#include <sys/msgbuf.h>
46#include <sys/proc.h>
47#include <sys/vnode.h>
48#include <sys/tty.h>
49#include <sys/tprintf.h>
50#include <sys/syslog.h>
51#include <sys/malloc.h>
52#include <machine/cons.h>
53
54/*
55 * Note that stdarg.h and the ANSI style va_start macro is used for both
56 * ANSI and traditional C compilers.
57 */
58#include <machine/stdarg.h>
59
60#ifdef KADB
61#include <machine/kdbparam.h>
62#endif
63
64
65#define TOCONS 0x01
66#define TOTTY 0x02
67#define TOLOG 0x04
68
69struct tty *constty; /* pointer to console "window" tty */
70
71void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */
71static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */
72
72
73void logpri __P((int level));
73static void logpri __P((int level));
74static void putchar __P((int ch, int flags, struct tty *tp));
75static char *ksprintn __P((u_long num, int base, int *len));
76
74static void putchar __P((int ch, int flags, struct tty *tp));
75static char *ksprintn __P((u_long num, int base, int *len));
76
77int consintr = 1; /* Ok to handle console interrupts? */
77static int consintr = 1; /* Ok to handle console interrupts? */
78
79/*
80 * Variable panicstr contains argument to first call to panic; used as flag
81 * to indicate that the kernel has already called panic.
82 */
83const char *panicstr;
84
85/*
86 * Panic is called on unresolvable fatal errors. It prints "panic: mesg",
87 * and then reboots. If we are called twice, then we avoid trying to sync
88 * the disks as this often leads to recursive panics.
89 */
90#ifdef __GNUC__
91__dead /* panic() does not return */
92#endif
93void
94#ifdef __STDC__
95panic(const char *fmt, ...)
96#else
97panic(fmt, va_alist)
98 char *fmt;
99#endif
100{
101 int bootopt;
102 va_list ap;
103
104 bootopt = RB_AUTOBOOT | RB_DUMP;
105 if (panicstr)
106 bootopt |= RB_NOSYNC;
107 else
108 panicstr = fmt;
109
110 va_start(ap, fmt);
111 printf("panic: %r\n", fmt, ap);
112 va_end(ap);
113
114#ifdef KGDB
115 kgdb_panic();
116#endif
117#ifdef KADB
118 if (boothowto & RB_KDB)
119 kdbpanic();
120#endif
121#ifdef DDB
122 Debugger ("panic");
123#endif
124 boot(bootopt);
125}
126
127/*
128 * Warn that a system table is full.
129 */
130void
131tablefull(tab)
132 const char *tab;
133{
134
135 log(LOG_ERR, "%s: table is full\n", tab);
136}
137
138/*
139 * Uprintf prints to the controlling terminal for the current process.
140 * It may block if the tty queue is overfull. No message is printed if
141 * the queue does not clear in a reasonable time.
142 */
143void
144#ifdef __STDC__
145uprintf(const char *fmt, ...)
146#else
147uprintf(fmt, va_alist)
148 char *fmt;
149#endif
150{
151 register struct proc *p = curproc;
152 va_list ap;
153
154 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
155 va_start(ap, fmt);
156 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
157 va_end(ap);
158 }
159}
160
161tpr_t
162tprintf_open(p)
163 register struct proc *p;
164{
165
166 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
167 SESSHOLD(p->p_session);
168 return ((tpr_t) p->p_session);
169 }
170 return ((tpr_t) NULL);
171}
172
173void
174tprintf_close(sess)
175 tpr_t sess;
176{
177
178 if (sess)
179 SESSRELE((struct session *) sess);
180}
181
182/*
183 * tprintf prints on the controlling terminal associated
184 * with the given session.
185 */
186void
187#ifdef __STDC__
188tprintf(tpr_t tpr, const char *fmt, ...)
189#else
190tprintf(tpr, fmt, va_alist)
191 tpr_t tpr;
192 char *fmt;
193#endif
194{
195 register struct session *sess = (struct session *)tpr;
196 struct tty *tp = NULL;
197 int flags = TOLOG;
198 va_list ap;
199
200 logpri(LOG_INFO);
201 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
202 flags |= TOTTY;
203 tp = sess->s_ttyp;
204 }
205 va_start(ap, fmt);
206 kprintf(fmt, flags, tp, ap);
207 va_end(ap);
208 logwakeup();
209}
210
211/*
212 * Ttyprintf displays a message on a tty; it should be used only by
213 * the tty driver, or anything that knows the underlying tty will not
214 * be revoke(2)'d away. Other callers should use tprintf.
215 */
216void
217#ifdef __STDC__
218ttyprintf(struct tty *tp, const char *fmt, ...)
219#else
220ttyprintf(tp, fmt, va_alist)
221 struct tty *tp;
222 char *fmt;
223#endif
224{
225 va_list ap;
226
227 va_start(ap, fmt);
228 kprintf(fmt, TOTTY, tp, ap);
229 va_end(ap);
230}
231
232extern int log_open;
233
234/*
235 * Log writes to the log buffer, and guarantees not to sleep (so can be
236 * called by interrupt routines). If there is no process reading the
237 * log yet, it writes to the console also.
238 */
239void
240#ifdef __STDC__
241log(int level, const char *fmt, ...)
242#else
243log(level, fmt, va_alist)
244 int level;
245 char *fmt;
246#endif
247{
248 register int s;
249 va_list ap;
250
251 s = splhigh();
252 logpri(level);
253 va_start(ap, fmt);
254 kprintf(fmt, TOLOG, NULL, ap);
255 splx(s);
256 va_end(ap);
257 if (!log_open) {
258 va_start(ap, fmt);
259 kprintf(fmt, TOCONS, NULL, ap);
260 va_end(ap);
261 }
262 logwakeup();
263}
264
78
79/*
80 * Variable panicstr contains argument to first call to panic; used as flag
81 * to indicate that the kernel has already called panic.
82 */
83const char *panicstr;
84
85/*
86 * Panic is called on unresolvable fatal errors. It prints "panic: mesg",
87 * and then reboots. If we are called twice, then we avoid trying to sync
88 * the disks as this often leads to recursive panics.
89 */
90#ifdef __GNUC__
91__dead /* panic() does not return */
92#endif
93void
94#ifdef __STDC__
95panic(const char *fmt, ...)
96#else
97panic(fmt, va_alist)
98 char *fmt;
99#endif
100{
101 int bootopt;
102 va_list ap;
103
104 bootopt = RB_AUTOBOOT | RB_DUMP;
105 if (panicstr)
106 bootopt |= RB_NOSYNC;
107 else
108 panicstr = fmt;
109
110 va_start(ap, fmt);
111 printf("panic: %r\n", fmt, ap);
112 va_end(ap);
113
114#ifdef KGDB
115 kgdb_panic();
116#endif
117#ifdef KADB
118 if (boothowto & RB_KDB)
119 kdbpanic();
120#endif
121#ifdef DDB
122 Debugger ("panic");
123#endif
124 boot(bootopt);
125}
126
127/*
128 * Warn that a system table is full.
129 */
130void
131tablefull(tab)
132 const char *tab;
133{
134
135 log(LOG_ERR, "%s: table is full\n", tab);
136}
137
138/*
139 * Uprintf prints to the controlling terminal for the current process.
140 * It may block if the tty queue is overfull. No message is printed if
141 * the queue does not clear in a reasonable time.
142 */
143void
144#ifdef __STDC__
145uprintf(const char *fmt, ...)
146#else
147uprintf(fmt, va_alist)
148 char *fmt;
149#endif
150{
151 register struct proc *p = curproc;
152 va_list ap;
153
154 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
155 va_start(ap, fmt);
156 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
157 va_end(ap);
158 }
159}
160
161tpr_t
162tprintf_open(p)
163 register struct proc *p;
164{
165
166 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
167 SESSHOLD(p->p_session);
168 return ((tpr_t) p->p_session);
169 }
170 return ((tpr_t) NULL);
171}
172
173void
174tprintf_close(sess)
175 tpr_t sess;
176{
177
178 if (sess)
179 SESSRELE((struct session *) sess);
180}
181
182/*
183 * tprintf prints on the controlling terminal associated
184 * with the given session.
185 */
186void
187#ifdef __STDC__
188tprintf(tpr_t tpr, const char *fmt, ...)
189#else
190tprintf(tpr, fmt, va_alist)
191 tpr_t tpr;
192 char *fmt;
193#endif
194{
195 register struct session *sess = (struct session *)tpr;
196 struct tty *tp = NULL;
197 int flags = TOLOG;
198 va_list ap;
199
200 logpri(LOG_INFO);
201 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
202 flags |= TOTTY;
203 tp = sess->s_ttyp;
204 }
205 va_start(ap, fmt);
206 kprintf(fmt, flags, tp, ap);
207 va_end(ap);
208 logwakeup();
209}
210
211/*
212 * Ttyprintf displays a message on a tty; it should be used only by
213 * the tty driver, or anything that knows the underlying tty will not
214 * be revoke(2)'d away. Other callers should use tprintf.
215 */
216void
217#ifdef __STDC__
218ttyprintf(struct tty *tp, const char *fmt, ...)
219#else
220ttyprintf(tp, fmt, va_alist)
221 struct tty *tp;
222 char *fmt;
223#endif
224{
225 va_list ap;
226
227 va_start(ap, fmt);
228 kprintf(fmt, TOTTY, tp, ap);
229 va_end(ap);
230}
231
232extern int log_open;
233
234/*
235 * Log writes to the log buffer, and guarantees not to sleep (so can be
236 * called by interrupt routines). If there is no process reading the
237 * log yet, it writes to the console also.
238 */
239void
240#ifdef __STDC__
241log(int level, const char *fmt, ...)
242#else
243log(level, fmt, va_alist)
244 int level;
245 char *fmt;
246#endif
247{
248 register int s;
249 va_list ap;
250
251 s = splhigh();
252 logpri(level);
253 va_start(ap, fmt);
254 kprintf(fmt, TOLOG, NULL, ap);
255 splx(s);
256 va_end(ap);
257 if (!log_open) {
258 va_start(ap, fmt);
259 kprintf(fmt, TOCONS, NULL, ap);
260 va_end(ap);
261 }
262 logwakeup();
263}
264
265void
265static void
266logpri(level)
267 int level;
268{
269 register char *p;
270
271 putchar('<', TOLOG, NULL);
272 for (p = ksprintn((u_long)level, 10, NULL); *p;)
273 putchar(*p--, TOLOG, NULL);
274 putchar('>', TOLOG, NULL);
275}
276
277void
278#ifdef __STDC__
279addlog(const char *fmt, ...)
280#else
281addlog(fmt, va_alist)
282 char *fmt;
283#endif
284{
285 register int s;
286 va_list ap;
287
288 s = splhigh();
289 va_start(ap, fmt);
290 kprintf(fmt, TOLOG, NULL, ap);
291 splx(s);
292 va_end(ap);
293 if (!log_open) {
294 va_start(ap, fmt);
295 kprintf(fmt, TOCONS, NULL, ap);
296 va_end(ap);
297 }
298 logwakeup();
299}
300
301void
302#ifdef __STDC__
303printf(const char *fmt, ...)
304#else
305printf(fmt, va_alist)
306 char *fmt;
307#endif
308{
309 va_list ap;
310 register int savintr;
311
312 savintr = consintr; /* disable interrupts */
313 consintr = 0;
314 va_start(ap, fmt);
315 kprintf(fmt, TOCONS | TOLOG, NULL, ap);
316 va_end(ap);
317 if (!panicstr)
318 logwakeup();
319 consintr = savintr; /* reenable interrupts */
320}
321
322/*
323 * Scaled down version of printf(3).
324 *
325 * Two additional formats:
326 *
327 * The format %b is supported to decode error registers.
328 * Its usage is:
329 *
330 * printf("reg=%b\n", regval, "<base><arg>*");
331 *
332 * where <base> is the output base expressed as a control character, e.g.
333 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
334 * the first of which gives the bit number to be inspected (origin 1), and
335 * the next characters (up to a control character, i.e. a character <= 32),
336 * give the name of the register. Thus:
337 *
338 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
339 *
340 * would produce output:
341 *
342 * reg=3<BITTWO,BITONE>
343 *
344 * The format %r passes an additional format string and argument list
345 * recursively. Its usage is:
346 *
347 * fn(char *fmt, ...)
348 * {
349 * va_list ap;
350 * va_start(ap, fmt);
351 * printf("prefix: %r: suffix\n", fmt, ap);
352 * va_end(ap);
353 * }
354 *
355 * Space or zero padding and a field width are supported for the numeric
356 * formats only.
357 */
358void
359kprintf(fmt, flags, tp, ap)
360 register const char *fmt;
361 int flags;
362 struct tty *tp;
363 va_list ap;
364{
365 register char *p, *q;
366 register int ch, n;
367 u_long ul;
368 int base, lflag, tmp, width;
369 char padc;
370
371 if (fmt == NULL)
372 fmt = "(fmt null)\n";
373 for (;;) {
374 padc = ' ';
375 width = 0;
376 while ((ch = *(u_char *)fmt++) != '%') {
377 if (ch == '\0')
378 return;
379 putchar(ch, flags, tp);
380 }
381 lflag = 0;
382reswitch: switch (ch = *(u_char *)fmt++) {
383 case '0':
384 padc = '0';
385 goto reswitch;
386 case '1': case '2': case '3': case '4':
387 case '5': case '6': case '7': case '8': case '9':
388 for (width = 0;; ++fmt) {
389 width = width * 10 + ch - '0';
390 ch = *fmt;
391 if (ch < '0' || ch > '9')
392 break;
393 }
394 goto reswitch;
395 case 'l':
396 lflag = 1;
397 goto reswitch;
398 case 'b':
399 ul = va_arg(ap, int);
400 p = va_arg(ap, char *);
401 for (q = ksprintn(ul, *p++, NULL); *q;)
402 putchar(*q--, flags, tp);
403
404 if (!ul)
405 break;
406
407 for (tmp = 0; *p;) {
408 n = *p++;
409 if (ul & (1 << (n - 1))) {
410 putchar(tmp ? ',' : '<', flags, tp);
411 for (; (n = *p) > ' '; ++p)
412 putchar(n, flags, tp);
413 tmp = 1;
414 } else
415 for (; *p > ' '; ++p)
416 continue;
417 }
418 if (tmp)
419 putchar('>', flags, tp);
420 break;
421 case 'c':
422 putchar(va_arg(ap, int), flags, tp);
423 break;
424 case 'r':
425 p = va_arg(ap, char *);
426 kprintf(p, flags, tp, va_arg(ap, va_list));
427 break;
428 case 's':
429 p = va_arg(ap, char *);
430 if (p == NULL)
431 p = "(null)";
432 while (*p)
433 putchar(*p++, flags, tp);
434 break;
435 case 'd':
436 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
437 if ((long)ul < 0) {
438 putchar('-', flags, tp);
439 ul = -(long)ul;
440 }
441 base = 10;
442 goto number;
443 case 'o':
444 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
445 base = 8;
446 goto number;
447 case 'p':
448 ul = (u_long)va_arg(ap, void *);
449 base = 16;
450 putchar('0', flags, tp);
451 putchar('x', flags, tp);
452 goto number;
453 case 'u':
454 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
455 base = 10;
456 goto number;
457 case 'x':
458 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
459 base = 16;
460number: p = ksprintn(ul, base, &tmp);
461 if (width && (width -= tmp) > 0)
462 while (width--)
463 putchar(padc, flags, tp);
464 while (*p)
465 putchar(*p--, flags, tp);
466 break;
467 default:
468 putchar('%', flags, tp);
469 if (lflag)
470 putchar('l', flags, tp);
471 /* FALLTHROUGH */
472 case '%':
473 putchar(ch, flags, tp);
474 }
475 }
476}
477
478/*
479 * Print a character on console or users terminal. If destination is
480 * the console then the last MSGBUFS characters are saved in msgbuf for
481 * inspection later.
482 */
483static void
484putchar(c, flags, tp)
485 register int c;
486 int flags;
487 struct tty *tp;
488{
489 register struct msgbuf *mbp;
490
491 if (panicstr)
492 constty = NULL;
493 if ((flags & TOCONS) && tp == NULL && constty) {
494 tp = constty;
495 flags |= TOTTY;
496 }
497 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
498 (flags & TOCONS) && tp == constty)
499 constty = NULL;
500 if ((flags & TOLOG) &&
501 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
502 mbp = msgbufp;
503 if (mbp->msg_magic != MSG_MAGIC ||
504 mbp->msg_bufx >= MSG_BSIZE ||
505 mbp->msg_bufr >= MSG_BSIZE) {
506 bzero(mbp, sizeof(struct msgbuf));
507 mbp->msg_magic = MSG_MAGIC;
508 }
509 mbp->msg_bufc[mbp->msg_bufx++] = c;
510 if (mbp->msg_bufx >= MSG_BSIZE)
511 mbp->msg_bufx = 0;
512 /* If the buffer is full, keep the most recent data. */
513 if (mbp->msg_bufr == mbp->msg_bufx) {
514 if (++mbp->msg_bufr >= MSG_BSIZE)
515 mbp->msg_bufr = 0;
516 }
517 }
518 if ((flags & TOCONS) && constty == NULL && c != '\0')
519 (*v_putc)(c);
520}
521
522/*
523 * Scaled down version of sprintf(3).
524 */
525#ifdef __STDC__
526int
527sprintf(char *buf, const char *cfmt, ...)
528#else
529int
530sprintf(buf, cfmt, va_alist)
531 char *buf, *cfmt;
532#endif
533{
534 register const char *fmt = cfmt;
535 register char *p, *bp;
536 register int ch, base;
537 u_long ul;
538 int lflag;
539 va_list ap;
540
541 va_start(ap, cfmt);
542 for (bp = buf; ; ) {
543 while ((ch = *(u_char *)fmt++) != '%')
544 if ((*bp++ = ch) == '\0')
545 return ((bp - buf) - 1);
546
547 lflag = 0;
548reswitch: switch (ch = *(u_char *)fmt++) {
549 case 'l':
550 lflag = 1;
551 goto reswitch;
552 case 'c':
553 *bp++ = va_arg(ap, int);
554 break;
555 case 's':
556 p = va_arg(ap, char *);
557 while (*p)
558 *bp++ = *p++;
559 break;
560 case 'd':
561 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
562 if ((long)ul < 0) {
563 *bp++ = '-';
564 ul = -(long)ul;
565 }
566 base = 10;
567 goto number;
568 break;
569 case 'o':
570 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
571 base = 8;
572 goto number;
573 break;
574 case 'p':
575 ul = (u_long)va_arg(ap, void *);
576 base = 16;
577 *bp++ = '0';
578 *bp++ = 'x';
579 goto number;
580 case 'u':
581 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
582 base = 10;
583 goto number;
584 break;
585 case 'x':
586 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
587 base = 16;
588number: for (p = ksprintn(ul, base, NULL); *p;)
589 *bp++ = *p--;
590 break;
591 default:
592 *bp++ = '%';
593 if (lflag)
594 *bp++ = 'l';
595 /* FALLTHROUGH */
596 case '%':
597 *bp++ = ch;
598 }
599 }
600 va_end(ap);
601}
602
603/*
604 * Put a number (base <= 16) in a buffer in reverse order; return an
605 * optional length and a pointer to the NULL terminated (preceded?)
606 * buffer.
607 */
608static char *
609ksprintn(ul, base, lenp)
610 register u_long ul;
611 register int base, *lenp;
612{ /* A long in base 8, plus NULL. */
613 static char buf[sizeof(long) * NBBY / 3 + 2];
614 register char *p;
615
616 p = buf;
617 do {
618 *++p = "0123456789abcdef"[ul % base];
619 } while (ul /= base);
620 if (lenp)
621 *lenp = p - buf;
622 return (p);
623}
266logpri(level)
267 int level;
268{
269 register char *p;
270
271 putchar('<', TOLOG, NULL);
272 for (p = ksprintn((u_long)level, 10, NULL); *p;)
273 putchar(*p--, TOLOG, NULL);
274 putchar('>', TOLOG, NULL);
275}
276
277void
278#ifdef __STDC__
279addlog(const char *fmt, ...)
280#else
281addlog(fmt, va_alist)
282 char *fmt;
283#endif
284{
285 register int s;
286 va_list ap;
287
288 s = splhigh();
289 va_start(ap, fmt);
290 kprintf(fmt, TOLOG, NULL, ap);
291 splx(s);
292 va_end(ap);
293 if (!log_open) {
294 va_start(ap, fmt);
295 kprintf(fmt, TOCONS, NULL, ap);
296 va_end(ap);
297 }
298 logwakeup();
299}
300
301void
302#ifdef __STDC__
303printf(const char *fmt, ...)
304#else
305printf(fmt, va_alist)
306 char *fmt;
307#endif
308{
309 va_list ap;
310 register int savintr;
311
312 savintr = consintr; /* disable interrupts */
313 consintr = 0;
314 va_start(ap, fmt);
315 kprintf(fmt, TOCONS | TOLOG, NULL, ap);
316 va_end(ap);
317 if (!panicstr)
318 logwakeup();
319 consintr = savintr; /* reenable interrupts */
320}
321
322/*
323 * Scaled down version of printf(3).
324 *
325 * Two additional formats:
326 *
327 * The format %b is supported to decode error registers.
328 * Its usage is:
329 *
330 * printf("reg=%b\n", regval, "<base><arg>*");
331 *
332 * where <base> is the output base expressed as a control character, e.g.
333 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
334 * the first of which gives the bit number to be inspected (origin 1), and
335 * the next characters (up to a control character, i.e. a character <= 32),
336 * give the name of the register. Thus:
337 *
338 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
339 *
340 * would produce output:
341 *
342 * reg=3<BITTWO,BITONE>
343 *
344 * The format %r passes an additional format string and argument list
345 * recursively. Its usage is:
346 *
347 * fn(char *fmt, ...)
348 * {
349 * va_list ap;
350 * va_start(ap, fmt);
351 * printf("prefix: %r: suffix\n", fmt, ap);
352 * va_end(ap);
353 * }
354 *
355 * Space or zero padding and a field width are supported for the numeric
356 * formats only.
357 */
358void
359kprintf(fmt, flags, tp, ap)
360 register const char *fmt;
361 int flags;
362 struct tty *tp;
363 va_list ap;
364{
365 register char *p, *q;
366 register int ch, n;
367 u_long ul;
368 int base, lflag, tmp, width;
369 char padc;
370
371 if (fmt == NULL)
372 fmt = "(fmt null)\n";
373 for (;;) {
374 padc = ' ';
375 width = 0;
376 while ((ch = *(u_char *)fmt++) != '%') {
377 if (ch == '\0')
378 return;
379 putchar(ch, flags, tp);
380 }
381 lflag = 0;
382reswitch: switch (ch = *(u_char *)fmt++) {
383 case '0':
384 padc = '0';
385 goto reswitch;
386 case '1': case '2': case '3': case '4':
387 case '5': case '6': case '7': case '8': case '9':
388 for (width = 0;; ++fmt) {
389 width = width * 10 + ch - '0';
390 ch = *fmt;
391 if (ch < '0' || ch > '9')
392 break;
393 }
394 goto reswitch;
395 case 'l':
396 lflag = 1;
397 goto reswitch;
398 case 'b':
399 ul = va_arg(ap, int);
400 p = va_arg(ap, char *);
401 for (q = ksprintn(ul, *p++, NULL); *q;)
402 putchar(*q--, flags, tp);
403
404 if (!ul)
405 break;
406
407 for (tmp = 0; *p;) {
408 n = *p++;
409 if (ul & (1 << (n - 1))) {
410 putchar(tmp ? ',' : '<', flags, tp);
411 for (; (n = *p) > ' '; ++p)
412 putchar(n, flags, tp);
413 tmp = 1;
414 } else
415 for (; *p > ' '; ++p)
416 continue;
417 }
418 if (tmp)
419 putchar('>', flags, tp);
420 break;
421 case 'c':
422 putchar(va_arg(ap, int), flags, tp);
423 break;
424 case 'r':
425 p = va_arg(ap, char *);
426 kprintf(p, flags, tp, va_arg(ap, va_list));
427 break;
428 case 's':
429 p = va_arg(ap, char *);
430 if (p == NULL)
431 p = "(null)";
432 while (*p)
433 putchar(*p++, flags, tp);
434 break;
435 case 'd':
436 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
437 if ((long)ul < 0) {
438 putchar('-', flags, tp);
439 ul = -(long)ul;
440 }
441 base = 10;
442 goto number;
443 case 'o':
444 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
445 base = 8;
446 goto number;
447 case 'p':
448 ul = (u_long)va_arg(ap, void *);
449 base = 16;
450 putchar('0', flags, tp);
451 putchar('x', flags, tp);
452 goto number;
453 case 'u':
454 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
455 base = 10;
456 goto number;
457 case 'x':
458 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
459 base = 16;
460number: p = ksprintn(ul, base, &tmp);
461 if (width && (width -= tmp) > 0)
462 while (width--)
463 putchar(padc, flags, tp);
464 while (*p)
465 putchar(*p--, flags, tp);
466 break;
467 default:
468 putchar('%', flags, tp);
469 if (lflag)
470 putchar('l', flags, tp);
471 /* FALLTHROUGH */
472 case '%':
473 putchar(ch, flags, tp);
474 }
475 }
476}
477
478/*
479 * Print a character on console or users terminal. If destination is
480 * the console then the last MSGBUFS characters are saved in msgbuf for
481 * inspection later.
482 */
483static void
484putchar(c, flags, tp)
485 register int c;
486 int flags;
487 struct tty *tp;
488{
489 register struct msgbuf *mbp;
490
491 if (panicstr)
492 constty = NULL;
493 if ((flags & TOCONS) && tp == NULL && constty) {
494 tp = constty;
495 flags |= TOTTY;
496 }
497 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
498 (flags & TOCONS) && tp == constty)
499 constty = NULL;
500 if ((flags & TOLOG) &&
501 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
502 mbp = msgbufp;
503 if (mbp->msg_magic != MSG_MAGIC ||
504 mbp->msg_bufx >= MSG_BSIZE ||
505 mbp->msg_bufr >= MSG_BSIZE) {
506 bzero(mbp, sizeof(struct msgbuf));
507 mbp->msg_magic = MSG_MAGIC;
508 }
509 mbp->msg_bufc[mbp->msg_bufx++] = c;
510 if (mbp->msg_bufx >= MSG_BSIZE)
511 mbp->msg_bufx = 0;
512 /* If the buffer is full, keep the most recent data. */
513 if (mbp->msg_bufr == mbp->msg_bufx) {
514 if (++mbp->msg_bufr >= MSG_BSIZE)
515 mbp->msg_bufr = 0;
516 }
517 }
518 if ((flags & TOCONS) && constty == NULL && c != '\0')
519 (*v_putc)(c);
520}
521
522/*
523 * Scaled down version of sprintf(3).
524 */
525#ifdef __STDC__
526int
527sprintf(char *buf, const char *cfmt, ...)
528#else
529int
530sprintf(buf, cfmt, va_alist)
531 char *buf, *cfmt;
532#endif
533{
534 register const char *fmt = cfmt;
535 register char *p, *bp;
536 register int ch, base;
537 u_long ul;
538 int lflag;
539 va_list ap;
540
541 va_start(ap, cfmt);
542 for (bp = buf; ; ) {
543 while ((ch = *(u_char *)fmt++) != '%')
544 if ((*bp++ = ch) == '\0')
545 return ((bp - buf) - 1);
546
547 lflag = 0;
548reswitch: switch (ch = *(u_char *)fmt++) {
549 case 'l':
550 lflag = 1;
551 goto reswitch;
552 case 'c':
553 *bp++ = va_arg(ap, int);
554 break;
555 case 's':
556 p = va_arg(ap, char *);
557 while (*p)
558 *bp++ = *p++;
559 break;
560 case 'd':
561 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
562 if ((long)ul < 0) {
563 *bp++ = '-';
564 ul = -(long)ul;
565 }
566 base = 10;
567 goto number;
568 break;
569 case 'o':
570 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
571 base = 8;
572 goto number;
573 break;
574 case 'p':
575 ul = (u_long)va_arg(ap, void *);
576 base = 16;
577 *bp++ = '0';
578 *bp++ = 'x';
579 goto number;
580 case 'u':
581 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
582 base = 10;
583 goto number;
584 break;
585 case 'x':
586 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
587 base = 16;
588number: for (p = ksprintn(ul, base, NULL); *p;)
589 *bp++ = *p--;
590 break;
591 default:
592 *bp++ = '%';
593 if (lflag)
594 *bp++ = 'l';
595 /* FALLTHROUGH */
596 case '%':
597 *bp++ = ch;
598 }
599 }
600 va_end(ap);
601}
602
603/*
604 * Put a number (base <= 16) in a buffer in reverse order; return an
605 * optional length and a pointer to the NULL terminated (preceded?)
606 * buffer.
607 */
608static char *
609ksprintn(ul, base, lenp)
610 register u_long ul;
611 register int base, *lenp;
612{ /* A long in base 8, plus NULL. */
613 static char buf[sizeof(long) * NBBY / 3 + 2];
614 register char *p;
615
616 p = buf;
617 do {
618 *++p = "0123456789abcdef"[ul % base];
619 } while (ul /= base);
620 if (lenp)
621 *lenp = p - buf;
622 return (p);
623}