changed \&ps to ps in man page
[unix-history] / sys / kern / subr_prf.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1986, 1988, 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)subr_prf.c 7.30 (Berkeley) 6/29/91
34 */
35
36#include "param.h"
37#include "systm.h"
38#include "buf.h"
39#include "conf.h"
40#include "reboot.h"
41#include "msgbuf.h"
42#include "proc.h"
43#include "ioctl.h"
44#include "vnode.h"
45#include "file.h"
46#include "tty.h"
47#include "tprintf.h"
48#include "syslog.h"
49#include "malloc.h"
50
51/*
52 * Note that stdarg.h and the ANSI style va_start macro is used for both
53 * ANSI and traditional C compilers.
54 */
55#include <machine/stdarg.h>
56
57#ifdef KADB
58#include "machine/kdbparam.h"
59#endif
60
61#define TOCONS 0x01
62#define TOTTY 0x02
63#define TOLOG 0x04
64
65struct tty *constty; /* pointer to console "window" tty */
66
67#ifdef KADB
68extern cngetc(); /* standard console getc */
69int (*v_getc)() = cngetc; /* "" getc from virtual console */
70extern cnpoll();
71int (*v_poll)() = cnpoll; /* kdb hook to enable input polling */
72#endif
73extern cnputc(); /* standard console putc */
74int (*v_putc)() = cnputc; /* routine to putc on virtual console */
75
76static void logpri __P((int level));
77static void putchar __P((int ch, int flags, struct tty *tp));
78static char *ksprintn __P((u_long num, int base, int *len));
79void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list));
80
81/*
82 * Variable panicstr contains argument to first call to panic; used
83 * as flag to indicate that the kernel has already called panic.
84 */
85char *panicstr;
86
87/*
88 * Panic is called on unresolvable fatal errors. It prints "panic: mesg",
89 * and then reboots. If we are called twice, then we avoid trying to sync
90 * the disks as this often leads to recursive panics.
91 */
92void
93panic(msg)
94 char *msg;
95{
96 int bootopt = RB_AUTOBOOT | RB_DUMP;
97
98 if (panicstr)
99 bootopt |= RB_NOSYNC;
100 else
101 panicstr = msg;
102 printf("panic: %s\n", msg);
103#ifdef KGDB
104 kgdb_panic();
105#endif
106#ifdef KADB
107 if (boothowto & RB_KDB) {
108 int s;
109
110 s = splnet(); /* below kdb pri */
111 setsoftkdb();
112 splx(s);
113 }
114#endif
115#include "ddb.h"
116#if NDDB > 0
117 Debugger ();
118#else
119/* pg("press key to boot/dump");*/
120#endif
121 boot(bootopt);
122}
123
124/*
125 * Warn that a system table is full.
126 */
127void
128tablefull(tab)
129 char *tab;
130{
131
132 log(LOG_ERR, "%s: table is full\n", tab);
133}
134
135/*
136 * Uprintf prints to the controlling terminal for the current process.
137 * It may block if the tty queue is overfull. No message is printed if
138 * the queue does not clear in a reasonable time.
139 */
140void
141#ifdef __STDC__
142uprintf(const char *fmt, ...)
143#else
144uprintf(fmt /*, va_alist */)
145 char *fmt;
146#endif
147{
148 register struct proc *p = curproc;
149 va_list ap;
150
151 if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
152 va_start(ap, fmt);
153 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
154 va_end(ap);
155 }
156}
157
158tpr_t
159tprintf_open(p)
160 register struct proc *p;
161{
162
163 if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
164 SESSHOLD(p->p_session);
165 return ((tpr_t) p->p_session);
166 }
167 return ((tpr_t) NULL);
168}
169
170void
171tprintf_close(sess)
172 tpr_t sess;
173{
174
175 if (sess)
176 SESSRELE((struct session *) sess);
177}
178
179/*
180 * tprintf prints on the controlling terminal associated
181 * with the given session.
182 */
183void
184#ifdef __STDC__
185tprintf(tpr_t tpr, const char *fmt, ...)
186#else
187tprintf(tpr, fmt /*, va_alist */)
188 tpr_t tpr;
189 char *fmt;
190#endif
191{
192 register struct session *sess = (struct session *)tpr;
193 struct tty *tp = NULL;
194 int flags = TOLOG;
195 va_list ap;
196
197 logpri(LOG_INFO);
198 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
199 flags |= TOTTY;
200 tp = sess->s_ttyp;
201 }
202 va_start(ap, fmt);
203 kprintf(fmt, flags, tp, ap);
204 va_end(ap);
205 logwakeup();
206}
207
208/*
209 * Ttyprintf displays a message on a tty; it should be used only by
210 * the tty driver, or anything that knows the underlying tty will not
211 * be revoke(2)'d away. Other callers should use tprintf.
212 */
213void
214#ifdef __STDC__
215ttyprintf(struct tty *tp, const char *fmt, ...)
216#else
217ttyprintf(tp, fmt /*, va_alist */)
218 struct tty *tp;
219 char *fmt;
220#endif
221{
222 va_list ap;
223
224 va_start(ap, fmt);
225 kprintf(fmt, TOTTY, tp, ap);
226 va_end(ap);
227}
228
229extern int log_open;
230
231/*
232 * Log writes to the log buffer, and guarantees not to sleep (so can be
233 * called by interrupt routines). If there is no process reading the
234 * log yet, it writes to the console also.
235 */
236void
237#ifdef __STDC__
238log(int level, const char *fmt, ...)
239#else
240log(level, fmt /*, va_alist */)
241 int level;
242 char *fmt;
243#endif
244{
245 register int s;
246 va_list ap;
247
248 s = splhigh();
249 logpri(level);
250 va_start(ap, fmt);
251 kprintf(fmt, TOLOG, NULL, ap);
252 splx(s);
253 va_end(ap);
254 if (!log_open) {
255 va_start(ap, fmt);
256 kprintf(fmt, TOCONS, NULL, ap);
257 va_end(ap);
258 }
259 logwakeup();
260}
261
262static void
263logpri(level)
264 int level;
265{
266 register int ch;
267 register char *p;
268
269 putchar('<', TOLOG, NULL);
270 for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
271 putchar(ch, TOLOG, NULL);
272 putchar('>', TOLOG, NULL);
273}
274
275void
276#ifdef __STDC__
277addlog(const char *fmt, ...)
278#else
279addlog(fmt /*, va_alist */)
280 char *fmt;
281#endif
282{
283 register int s;
284 va_list ap;
285
286 s = splhigh();
287 va_start(ap, fmt);
288 kprintf(fmt, TOLOG, NULL, ap);
289 splx(s);
290 va_end(ap);
291 if (!log_open) {
292 va_start(ap, fmt);
293 kprintf(fmt, TOCONS, NULL, ap);
294 va_end(ap);
295 }
296 logwakeup();
297}
298
299int consintr = 1; /* ok to handle console interrupts? */
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 * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
339 *
340 * would produce output:
341 *
342 * reg=3<BITTWO,BITONE>
343 *
344 * The format %r is supposed to pass an additional format string and argument
345 * list recursively.
346 * Its usage is:
347 *
348 * fn(otherstuff, char *fmt, ...)
349 * {
350 * va_list ap;
351 * va_start(ap, fmt);
352 * printf("prefix: %r, other stuff\n", fmt, ap);
353 * va_end(ap);
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;
366 register int ch, n;
367 u_long ul;
368 int base, lflag, tmp, width;
369 char padc;
370
371 for (;;) {
372 padc = ' ';
373 width = 0;
374 while ((ch = *(u_char *)fmt++) != '%') {
375 if (ch == '\0')
376 return;
377 putchar(ch, flags, tp);
378 }
379 lflag = 0;
380reswitch: switch (ch = *(u_char *)fmt++) {
381 case '0':
382 padc = '0';
383 goto reswitch;
384 case '1': case '2': case '3': case '4':
385 case '5': case '6': case '7': case '8': case '9':
386 for (width = 0;; ++fmt) {
387 width = width * 10 + ch - '0';
388 ch = *fmt;
389 if (ch < '0' || ch > '9')
390 break;
391 }
392 goto reswitch;
393 case 'l':
394 lflag = 1;
395 goto reswitch;
396 case 'b':
397 ul = va_arg(ap, int);
398 p = va_arg(ap, char *);
399 for (p = ksprintn(ul, *p++, NULL); ch = *p--;)
400 putchar(ch, flags, tp);
401
402 if (!ul)
403 break;
404
405 for (tmp = 0; n = *p++;) {
406 if (ul & (1 << (n - 1))) {
407 putchar(tmp ? ',' : '<', flags, tp);
408 for (; (n = *p) > ' '; ++p)
409 putchar(n, flags, tp);
410 tmp = 1;
411 } else
412 for (; *p > ' '; ++p);
413 }
414 if (tmp)
415 putchar('>', flags, tp);
416 break;
417 case 'c':
418 putchar(va_arg(ap, int), flags, tp);
419 break;
420 case 'r':
421 p = va_arg(ap, char *);
422 kprintf(p, flags, tp, va_arg(ap, va_list));
423 break;
424 case 's':
425 p = va_arg(ap, char *);
426 while (ch = *p++)
427 putchar(ch, flags, tp);
428 break;
429 case 'd':
430 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
431 if ((long)ul < 0) {
432 putchar('-', flags, tp);
433 ul = -(long)ul;
434 }
435 base = 10;
436 goto number;
437 case 'o':
438 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
439 base = 8;
440 goto number;
441 case 'u':
442 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
443 base = 10;
444 goto number;
445 case 'x':
446 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
447 base = 16;
448number: p = ksprintn(ul, base, &tmp);
449 if (width && (width -= tmp) > 0)
450 while (width--)
451 putchar(padc, flags, tp);
452 while (ch = *p--)
453 putchar(ch, flags, tp);
454 break;
455 default:
456 putchar('%', flags, tp);
457 if (lflag)
458 putchar('l', flags, tp);
459 /* FALLTHROUGH */
460 case '%':
461 putchar(ch, flags, tp);
462 }
463 }
464}
465
466/*
467 * Print a character on console or users terminal. If destination is
468 * the console then the last MSGBUFS characters are saved in msgbuf for
469 * inspection later.
470 */
471static void
472putchar(c, flags, tp)
473 register int c;
474 int flags;
475 struct tty *tp;
476{
477 extern int msgbufmapped;
478 register struct msgbuf *mbp;
479
480 if (panicstr)
481 constty = NULL;
482 if ((flags & TOCONS) && tp == NULL && constty) {
483 tp = constty;
484 flags |= TOTTY;
485 }
486 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
487 (flags & TOCONS) && tp == constty)
488 constty = NULL;
489 if ((flags & TOLOG) &&
490 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
491 mbp = msgbufp;
492 if (mbp->msg_magic != MSG_MAGIC) {
493 bzero((caddr_t)mbp, sizeof(*mbp));
494 mbp->msg_magic = MSG_MAGIC;
495 }
496 mbp->msg_bufc[mbp->msg_bufx++] = c;
497 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
498 mbp->msg_bufx = 0;
499 }
500 if ((flags & TOCONS) && constty == NULL && c != '\0')
501 (*v_putc)(c);
502}
503
504/*
505 * Scaled down version of sprintf(3).
506 */
507#ifdef __STDC__
508sprintf(char *buf, const char *cfmt, ...)
509#else
510sprintf(buf, cfmt /*, va_alist */)
511 char *buf, *cfmt;
512#endif
513{
514 register const char *fmt = cfmt;
515 register char *p, *bp;
516 register int ch, base;
517 u_long ul;
518 int lflag;
519 va_list ap;
520
521 va_start(ap, cfmt);
522 for (bp = buf; ; ) {
523 while ((ch = *(u_char *)fmt++) != '%')
524 if ((*bp++ = ch) == '\0')
525 return ((bp - buf) - 1);
526
527 lflag = 0;
528reswitch: switch (ch = *(u_char *)fmt++) {
529 case 'l':
530 lflag = 1;
531 goto reswitch;
532 case 'c':
533 *bp++ = va_arg(ap, int);
534 break;
535 case 's':
536 p = va_arg(ap, char *);
537 while (*bp++ = *p++)
538 ;
539 --bp;
540 break;
541 case 'd':
542 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
543 if ((long)ul < 0) {
544 *bp++ = '-';
545 ul = -(long)ul;
546 }
547 base = 10;
548 goto number;
549 break;
550 case 'o':
551 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
552 base = 8;
553 goto number;
554 break;
555 case 'u':
556 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
557 base = 10;
558 goto number;
559 break;
560 case 'x':
561 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
562 base = 16;
563number: for (p = ksprintn(ul, base, NULL); ch = *p--;)
564 *bp++ = ch;
565 break;
566 default:
567 *bp++ = '%';
568 if (lflag)
569 *bp++ = 'l';
570 /* FALLTHROUGH */
571 case '%':
572 *bp++ = ch;
573 }
574 }
575 va_end(ap);
576}
577
578/*
579 * Put a number (base <= 16) in a buffer in reverse order; return an
580 * optional length and a pointer to the NULL terminated (preceded?)
581 * buffer.
582 */
583static char *
584ksprintn(ul, base, lenp)
585 register u_long ul;
586 register int base, *lenp;
587{ /* A long in base 8, plus NULL. */
588 static char buf[sizeof(long) * NBBY / 3 + 2];
589 register char *p;
590
591 p = buf;
592 do {
593 *++p = "0123456789abcdef"[ul % base];
594 } while (ul /= base);
595 if (lenp)
596 *lenp = p - buf;
597 return (p);
598}