Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / msg.c
blob3e322c170a0fe635c590d78e83bd2db2fe74a6aa
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* msg 3
6 /* SUMMARY
7 /* diagnostic interface
8 /* SYNOPSIS
9 /* #include <msg.h>
11 /* int msg_verbose;
13 /* void msg_info(format, ...)
14 /* const char *format;
16 /* void msg_warn(format, ...)
17 /* const char *format;
19 /* void msg_error(format, ...)
20 /* const char *format;
22 /* NORETURN msg_fatal(format, ...)
23 /* const char *format;
25 /* NORETURN msg_fatal_status(status, format, ...)
26 /* int status;
27 /* const char *format;
29 /* NORETURN msg_panic(format, ...)
30 /* const char *format;
32 /* MSG_CLEANUP_FN msg_cleanup(cleanup)
33 /* void (*cleanup)(void);
34 /* AUXILIARY FUNCTIONS
35 /* int msg_error_limit(count)
36 /* int count;
38 /* void msg_error_clear()
39 /* DESCRIPTION
40 /* This module reports diagnostics. By default, diagnostics are sent
41 /* to the standard error stream, but the disposition can be changed
42 /* by the user. See the hints below in the SEE ALSO section.
44 /* msg_info(), msg_warn(), msg_error(), msg_fatal*() and msg_panic()
45 /* produce a one-line record with the program name, a severity code
46 /* (except for msg_info()), and an informative message. The program
47 /* name must have been set by calling one of the msg_XXX_init()
48 /* functions (see the SEE ALSO section).
50 /* msg_error() reports a recoverable error and increments the error
51 /* counter. When the error count exceeds a pre-set limit (default: 13)
52 /* the program terminates by calling msg_fatal().
54 /* msg_fatal() reports an unrecoverable error and terminates the program
55 /* with a non-zero exit status.
57 /* msg_fatal_status() reports an unrecoverable error and terminates the
58 /* program with the specified exit status.
60 /* msg_panic() reports an internal inconsistency, terminates the
61 /* program immediately (i.e. without calling the optional user-specified
62 /* cleanup routine), and forces a core dump when possible.
64 /* msg_cleanup() specifies a function that msg_fatal[_status]() should
65 /* invoke before terminating the program, and returns the
66 /* current function pointer. Specify a null argument to disable
67 /* this feature.
69 /* msg_error_limit() sets the error message count limit, and returns.
70 /* the old limit.
72 /* msg_error_clear() sets the error message count to zero.
74 /* msg_verbose is a global flag that can be set to make software
75 /* more verbose about what it is doing. By default the flag is zero.
76 /* By convention, a larger value means more noise.
77 /* REENTRANCY
78 /* .ad
79 /* .fi
80 /* The msg_info() etc. output routines are protected against
81 /* ordinary recursive calls and against re-entry by signal
82 /* handlers.
84 /* Protection against re-entry by signal handlers is subject
85 /* to the following limitations:
86 /* .IP \(bu
87 /* The signal handlers must never return. In other words, the
88 /* signal handlers must do one or more of the following: call
89 /* _exit(), kill the process with a signal, and permanently block
90 /* the process.
91 /* .IP \(bu
92 /* The signal handlers must invoke msg_info() etc. not until
93 /* after the msg_XXX_init() functions complete initialization,
94 /* and not until after the first formatted output to a VSTRING
95 /* or VSTREAM.
96 /* .IP \(bu
97 /* Each msg_cleanup() call-back function, and each Postfix or
98 /* system function invoked by that call-back function, either
99 /* protects itself against recursive calls and re-entry by a
100 /* terminating signal handler, or is called exclusively by the
101 /* msg(3) module.
102 /* .PP
103 /* When re-entrancy is detected, the requested output and
104 /* optional cleanup operations are skipped. Skipping the output
105 /* operations prevents memory corruption of VSTREAM_ERR data
106 /* structures, and prevents deadlock on Linux releases that
107 /* use mutexes within system library routines such as syslog().
108 /* This protection exists under the condition that these
109 /* specific resources are accessed exclusively via the msg_info()
110 /* etc. functions.
111 /* SEE ALSO
112 /* msg_output(3) specify diagnostics disposition
113 /* msg_stdio(3) direct diagnostics to standard I/O stream
114 /* msg_vstream(3) direct diagnostics to VSTREAM.
115 /* msg_syslog(3) direct diagnostics to syslog daemon
116 /* BUGS
117 /* Some output functions may suffer from intentional or accidental
118 /* record length restrictions that are imposed by library routines
119 /* and/or by the runtime environment.
121 /* Code that spawns a child process should almost always reset
122 /* the cleanup handler. The exception is when the parent exits
123 /* immediately and the child continues.
125 /* msg_cleanup() may be unsafe in code that changes process
126 /* privileges, because the call-back routine may run with the
127 /* wrong privileges.
128 /* LICENSE
129 /* .ad
130 /* .fi
131 /* The Secure Mailer license must be distributed with this software.
132 /* AUTHOR(S)
133 /* Wietse Venema
134 /* IBM T.J. Watson Research
135 /* P.O. Box 704
136 /* Yorktown Heights, NY 10598, USA
137 /*--*/
139 /* System libraries. */
141 #include <sys_defs.h>
142 #include <stdlib.h>
143 #include <stdarg.h>
144 #include <unistd.h>
146 /* Application-specific. */
148 #include "msg.h"
149 #include "msg_output.h"
152 * Default is verbose logging off.
154 int msg_verbose = 0;
157 * Private state.
159 static MSG_CLEANUP_FN msg_cleanup_fn = 0;
160 static int msg_error_count = 0;
161 static int msg_error_bound = 13;
164 * The msg_exiting flag prevents us from recursively reporting an error with
165 * msg_fatal*() or msg_panic(), and provides a first-level safety net for
166 * optional cleanup actions against signal handler re-entry problems. Note
167 * that msg_vprintf() implements its own guard against re-entry.
169 * XXX We specify global scope, to discourage the compiler from doing smart
170 * things.
172 volatile int msg_exiting = 0;
174 /* msg_info - report informative message */
176 void msg_info(const char *fmt,...)
178 va_list ap;
180 va_start(ap, fmt);
181 msg_vprintf(MSG_INFO, fmt, ap);
182 va_end(ap);
185 /* msg_warn - report warning message */
187 void msg_warn(const char *fmt,...)
189 va_list ap;
191 va_start(ap, fmt);
192 msg_vprintf(MSG_WARN, fmt, ap);
193 va_end(ap);
196 /* msg_error - report recoverable error */
198 void msg_error(const char *fmt,...)
200 va_list ap;
202 va_start(ap, fmt);
203 msg_vprintf(MSG_ERROR, fmt, ap);
204 va_end(ap);
205 if (++msg_error_count >= msg_error_bound)
206 msg_fatal("too many errors - program terminated");
209 /* msg_fatal - report error and terminate gracefully */
211 NORETURN msg_fatal(const char *fmt,...)
213 va_list ap;
215 if (msg_exiting++ == 0) {
216 va_start(ap, fmt);
217 msg_vprintf(MSG_FATAL, fmt, ap);
218 va_end(ap);
219 if (msg_cleanup_fn)
220 msg_cleanup_fn();
222 sleep(1);
223 /* In case we're running as a signal handler. */
224 _exit(1);
227 /* msg_fatal_status - report error and terminate gracefully */
229 NORETURN msg_fatal_status(int status, const char *fmt,...)
231 va_list ap;
233 if (msg_exiting++ == 0) {
234 va_start(ap, fmt);
235 msg_vprintf(MSG_FATAL, fmt, ap);
236 va_end(ap);
237 if (msg_cleanup_fn)
238 msg_cleanup_fn();
240 sleep(1);
241 /* In case we're running as a signal handler. */
242 _exit(status);
245 /* msg_panic - report error and dump core */
247 NORETURN msg_panic(const char *fmt,...)
249 va_list ap;
251 if (msg_exiting++ == 0) {
252 va_start(ap, fmt);
253 msg_vprintf(MSG_PANIC, fmt, ap);
254 va_end(ap);
256 sleep(1);
257 abort(); /* Die! */
258 /* In case we're running as a signal handler. */
259 _exit(1); /* DIE!! */
262 /* msg_cleanup - specify cleanup routine */
264 MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN cleanup_fn)
266 MSG_CLEANUP_FN old_fn = msg_cleanup_fn;
268 msg_cleanup_fn = cleanup_fn;
269 return (old_fn);
272 /* msg_error_limit - set error message counter limit */
274 int msg_error_limit(int limit)
276 int old = msg_error_bound;
278 msg_error_bound = limit;
279 return (old);
282 /* msg_error_clear - reset error message counter */
284 void msg_error_clear(void)
286 msg_error_count = 0;