1 /*	$NetBSD: msg_output.c,v 1.1.1.1 2009/06/23 10:09:00 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	msg_output 3
6 /* SUMMARY
7 /*	diagnostics output management
8 /* SYNOPSIS
9 /*	#include <msg_output.h>
10 /*
11 /*	typedef void (*MSG_OUTPUT_FN)(int level, char *text)
12 /*
13 /*	void	msg_output(output_fn)
14 /*	MSG_OUTPUT_FN output_fn;
15 /*
16 /*	void	msg_printf(level, format, ...)
17 /*	int	level;
18 /*	const char *format;
19 /*
20 /*	void	msg_vprintf(level, format, ap)
21 /*	int	level;
22 /*	const char *format;
23 /*	va_list ap;
24 /*
25 /*	void	msg_text(level, text)
26 /*	int	level;
27 /*	const char *text;
28 /* DESCRIPTION
29 /*	This module implements low-level output management for the
30 /*	msg(3) diagnostics interface.
31 /*
32 /*	msg_output() registers an output handler for the diagnostics
33 /*	interface. An application can register multiple output handlers.
34 /*	Output handlers are called in the specified order.
35 /*	An output handler takes as arguments a severity level (MSG_INFO,
36 /*	MSG_WARN, MSG_ERROR, MSG_FATAL, MSG_PANIC, monotonically increasing
37 /*	integer values ranging from 0 to MSG_LAST) and pre-formatted,
38 /*	sanitized, text in the form of a null-terminated string.
39 /*
40 /*	msg_printf() and msg_vprintf() format their arguments, sanitize the
41 /*	result, and call the output handlers registered with msg_output().
42 /*
43 /*	msg_text() copies a pre-formatted text, sanitizes the result, and
44 /*	calls the output handlers registered with msg_output().
45 /* REENTRANCY
46 /* .ad
47 /* .fi
48 /*	The above output routines are protected against ordinary
49 /*	recursive calls and against re-entry by signal
50 /*	handlers, with the following limitations:
51 /* .IP \(bu
52 /*	The signal handlers must never return. In other words, the
53 /*	signal handlers must do one or more of the following: call
54 /*	_exit(), kill the process with a signal, and permanently
55 /*	block the process.
56 /* .IP \(bu
57 /*	The signal handlers must call the above output routines not
58 /*	until after msg_output() completes initialization, and not
59 /*	until after the first formatted output to a VSTRING or
60 /*	VSTREAM.
61 /* .IP \(bu
62 /*	Each msg_output() call-back function, and each Postfix or
63 /*	system function called by that call-back function, either
64 /*	must protect itself against recursive calls and re-entry
65 /*	by a terminating signal handler, or it must be called
66 /*	exclusively by functions in the msg_output(3) module.
67 /* .PP
68 /*	When re-entrancy is detected, the requested output operation
69 /*	is skipped. This prevents memory corruption of VSTREAM_ERR
70 /*	data structures, and prevents deadlock on Linux releases
71 /*	that use mutexes within system library routines such as
72 /*	syslog(). This protection exists under the condition that
73 /*	these specific resources are accessed exclusively via
74 /*	msg_output() call-back functions.
75 /* LICENSE
76 /* .ad
77 /* .fi
78 /*	The Secure Mailer license must be distributed with this software.
79 /* AUTHOR(S)
80 /*	Wietse Venema
81 /*	IBM T.J. Watson Research
82 /*	P.O. Box 704
83 /*	Yorktown Heights, NY 10598, USA
84 /*--*/
85 
86 /* System library. */
87 
88 #include <sys_defs.h>
89 #include <stdarg.h>
90 #include <errno.h>
91 
92 /* Utility library. */
93 
94 #include <mymalloc.h>
95 #include <vstring.h>
96 #include <vstream.h>
97 #include <msg_vstream.h>
98 #include <stringops.h>
99 #include <percentm.h>
100 #include <msg_output.h>
101 
102  /*
103   * Global scope, to discourage the compiler from doing smart things.
104   */
105 volatile int msg_vprintf_lock;
106 volatile int msg_text_lock;
107 
108  /*
109   * Private state.
110   */
111 static MSG_OUTPUT_FN *msg_output_fn = 0;
112 static int msg_output_fn_count = 0;
113 static VSTRING *msg_buffer = 0;
114 
115 /* msg_output - specify output handler */
116 
117 void    msg_output(MSG_OUTPUT_FN output_fn)
118 {
119 
120     /*
121      * Allocate all resources during initialization.
122      */
123     if (msg_buffer == 0)
124 	msg_buffer = vstring_alloc(100);
125 
126     /*
127      * We're not doing this often, so avoid complexity and allocate memory
128      * for an exact fit.
129      */
130     if (msg_output_fn_count == 0)
131 	msg_output_fn = (MSG_OUTPUT_FN *) mymalloc(sizeof(*msg_output_fn));
132     else
133 	msg_output_fn = (MSG_OUTPUT_FN *) myrealloc((char *) msg_output_fn,
134 			(msg_output_fn_count + 1) * sizeof(*msg_output_fn));
135     msg_output_fn[msg_output_fn_count++] = output_fn;
136 }
137 
138 /* msg_printf - format text and log it */
139 
140 void    msg_printf(int level, const char *format,...)
141 {
142     va_list ap;
143 
144     va_start(ap, format);
145     msg_vprintf(level, format, ap);
146     va_end(ap);
147 }
148 
149 /* msg_vprintf - format text and log it */
150 
151 void    msg_vprintf(int level, const char *format, va_list ap)
152 {
153     if (msg_vprintf_lock == 0) {
154 	msg_vprintf_lock = 1;
155 	/* On-the-fly initialization for debugging test programs only. */
156 	if (msg_output_fn_count == 0)
157 	    msg_vstream_init("unknown", VSTREAM_ERR);
158 	/* OK if terminating signal handler hijacks control before next stmt. */
159 	vstring_vsprintf(msg_buffer, percentm(format, errno), ap);
160 	msg_text(level, vstring_str(msg_buffer));
161 	msg_vprintf_lock = 0;
162     }
163 }
164 
165 /* msg_text - sanitize and log pre-formatted text */
166 
167 void    msg_text(int level, const char *text)
168 {
169     int     i;
170 
171     /*
172      * Sanitize the text. Use a private copy if necessary.
173      */
174     if (msg_text_lock == 0) {
175 	msg_text_lock = 1;
176 	/* OK if terminating signal handler hijacks control before next stmt. */
177 	if (text != vstring_str(msg_buffer))
178 	    vstring_strcpy(msg_buffer, text);
179 	printable(vstring_str(msg_buffer), '?');
180 	/* On-the-fly initialization for debugging test programs only. */
181 	if (msg_output_fn_count == 0)
182 	    msg_vstream_init("unknown", VSTREAM_ERR);
183 	for (i = 0; i < msg_output_fn_count; i++)
184 	    msg_output_fn[i] (level, vstring_str(msg_buffer));
185 	msg_text_lock = 0;
186     }
187 }
188