Postfix3.3.1
msg.c
[詳解]
1 /*++
2 /* NAME
3 /* msg 3
4 /* SUMMARY
5 /* diagnostic interface
6 /* SYNOPSIS
7 /* #include <msg.h>
8 /*
9 /* int msg_verbose;
10 /*
11 /* void msg_info(format, ...)
12 /* const char *format;
13 /*
14 /* void vmsg_info(format, ap)
15 /* const char *format;
16 /* va_list ap;
17 /*
18 /* void msg_warn(format, ...)
19 /* const char *format;
20 /*
21 /* void vmsg_warn(format, ap)
22 /* const char *format;
23 /* va_list ap;
24 /*
25 /* void msg_error(format, ...)
26 /* const char *format;
27 /*
28 /* void vmsg_error(format, ap)
29 /* const char *format;
30 /* va_list ap;
31 /*
32 /* NORETURN msg_fatal(format, ...)
33 /* const char *format;
34 /*
35 /* NORETURN vmsg_fatal(format, ap)
36 /* const char *format;
37 /* va_list ap;
38 /*
39 /* NORETURN msg_fatal_status(status, format, ...)
40 /* int status;
41 /* const char *format;
42 /*
43 /* NORETURN vmsg_fatal_status(status, format, ap)
44 /* int status;
45 /* const char *format;
46 /* va_list ap;
47 /*
48 /* NORETURN msg_panic(format, ...)
49 /* const char *format;
50 /*
51 /* NORETURN vmsg_panic(format, ap)
52 /* const char *format;
53 /* va_list ap;
54 /*
55 /* MSG_CLEANUP_FN msg_cleanup(cleanup)
56 /* void (*cleanup)(void);
57 /* AUXILIARY FUNCTIONS
58 /* int msg_error_limit(count)
59 /* int count;
60 /*
61 /* void msg_error_clear()
62 /* DESCRIPTION
63 /* This module reports diagnostics. By default, diagnostics are sent
64 /* to the standard error stream, but the disposition can be changed
65 /* by the user. See the hints below in the SEE ALSO section.
66 /*
67 /* msg_info(), msg_warn(), msg_error(), msg_fatal*() and msg_panic()
68 /* produce a one-line record with the program name, a severity code
69 /* (except for msg_info()), and an informative message. The program
70 /* name must have been set by calling one of the msg_XXX_init()
71 /* functions (see the SEE ALSO section).
72 /*
73 /* msg_error() reports a recoverable error and increments the error
74 /* counter. When the error count exceeds a pre-set limit (default: 13)
75 /* the program terminates by calling msg_fatal().
76 /*
77 /* msg_fatal() reports an unrecoverable error and terminates the program
78 /* with a non-zero exit status.
79 /*
80 /* msg_fatal_status() reports an unrecoverable error and terminates the
81 /* program with the specified exit status.
82 /*
83 /* msg_panic() reports an internal inconsistency, terminates the
84 /* program immediately (i.e. without calling the optional user-specified
85 /* cleanup routine), and forces a core dump when possible.
86 /*
87 /* msg_cleanup() specifies a function that msg_fatal[_status]() should
88 /* invoke before terminating the program, and returns the
89 /* current function pointer. Specify a null argument to disable
90 /* this feature.
91 /*
92 /* msg_error_limit() sets the error message count limit, and returns.
93 /* the old limit.
94 /*
95 /* msg_error_clear() sets the error message count to zero.
96 /*
97 /* msg_verbose is a global flag that can be set to make software
98 /* more verbose about what it is doing. By default the flag is zero.
99 /* By convention, a larger value means more noise.
100 /* REENTRANCY
101 /* .ad
102 /* .fi
103 /* The msg_info() etc. output routines are protected against
104 /* ordinary recursive calls and against re-entry by signal
105 /* handlers.
106 /*
107 /* Protection against re-entry by signal handlers is subject
108 /* to the following limitations:
109 /* .IP \(bu
110 /* The signal handlers must never return. In other words, the
111 /* signal handlers must do one or more of the following: call
112 /* _exit(), kill the process with a signal, and permanently block
113 /* the process.
114 /* .IP \(bu
115 /* The signal handlers must invoke msg_info() etc. not until
116 /* after the msg_XXX_init() functions complete initialization,
117 /* and not until after the first formatted output to a VSTRING
118 /* or VSTREAM.
119 /* .IP \(bu
120 /* Each msg_cleanup() call-back function, and each Postfix or
121 /* system function invoked by that call-back function, either
122 /* protects itself against recursive calls and re-entry by a
123 /* terminating signal handler, or is called exclusively by the
124 /* msg(3) module.
125 /* .PP
126 /* When re-entrancy is detected, the requested output and
127 /* optional cleanup operations are skipped. Skipping the output
128 /* operations prevents memory corruption of VSTREAM_ERR data
129 /* structures, and prevents deadlock on Linux releases that
130 /* use mutexes within system library routines such as syslog().
131 /* This protection exists under the condition that these
132 /* specific resources are accessed exclusively via the msg_info()
133 /* etc. functions.
134 /* SEE ALSO
135 /* msg_output(3) specify diagnostics disposition
136 /* msg_stdio(3) direct diagnostics to standard I/O stream
137 /* msg_vstream(3) direct diagnostics to VSTREAM.
138 /* msg_syslog(3) direct diagnostics to syslog daemon
139 /* BUGS
140 /* Some output functions may suffer from intentional or accidental
141 /* record length restrictions that are imposed by library routines
142 /* and/or by the runtime environment.
143 /*
144 /* Code that spawns a child process should almost always reset
145 /* the cleanup handler. The exception is when the parent exits
146 /* immediately and the child continues.
147 /*
148 /* msg_cleanup() may be unsafe in code that changes process
149 /* privileges, because the call-back routine may run with the
150 /* wrong privileges.
151 /* LICENSE
152 /* .ad
153 /* .fi
154 /* The Secure Mailer license must be distributed with this software.
155 /* AUTHOR(S)
156 /* Wietse Venema
157 /* IBM T.J. Watson Research
158 /* P.O. Box 704
159 /* Yorktown Heights, NY 10598, USA
160 /*--*/
161 
162 /* System libraries. */
163 
164 #include <sys_defs.h>
165 #include <stdlib.h>
166 #include <stdarg.h>
167 #include <unistd.h>
168 
169 /* Application-specific. */
170 
171 #include "msg.h"
172 #include "msg_output.h"
173 
174  /*
175  * Default is verbose logging off.
176  */
177 int msg_verbose = 0;
178 
179  /*
180  * Private state.
181  */
182 static MSG_CLEANUP_FN msg_cleanup_fn = 0;
183 static int msg_error_count = 0;
184 static int msg_error_bound = 13;
185 
186  /*
187  * The msg_exiting flag prevents us from recursively reporting an error with
188  * msg_fatal*() or msg_panic(), and provides a first-level safety net for
189  * optional cleanup actions against signal handler re-entry problems. Note
190  * that msg_vprintf() implements its own guard against re-entry.
191  *
192  * XXX We specify global scope, to discourage the compiler from doing smart
193  * things.
194  */
195 volatile int msg_exiting = 0;
196 
197 /* msg_info - report informative message */
198 
199 void msg_info(const char *fmt,...)
200 {
201  va_list ap;
202 
203  va_start(ap, fmt);
204  vmsg_info(fmt, ap);
205  va_end(ap);
206 }
207 
208 void vmsg_info(const char *fmt, va_list ap)
209 {
210  msg_vprintf(MSG_INFO, fmt, ap);
211 }
212 
213 /* msg_warn - report warning message */
214 
215 void msg_warn(const char *fmt,...)
216 {
217  va_list ap;
218 
219  va_start(ap, fmt);
220  vmsg_warn(fmt, ap);
221  va_end(ap);
222 }
223 
224 void vmsg_warn(const char *fmt, va_list ap)
225 {
226  msg_vprintf(MSG_WARN, fmt, ap);
227 }
228 
229 /* msg_error - report recoverable error */
230 
231 void msg_error(const char *fmt,...)
232 {
233  va_list ap;
234 
235  va_start(ap, fmt);
236  vmsg_error(fmt, ap);
237  va_end(ap);
238 }
239 
240 void vmsg_error(const char *fmt, va_list ap)
241 {
242  msg_vprintf(MSG_ERROR, fmt, ap);
243  if (++msg_error_count >= msg_error_bound)
244  msg_fatal("too many errors - program terminated");
245 }
246 
247 /* msg_fatal - report error and terminate gracefully */
248 
249 NORETURN msg_fatal(const char *fmt,...)
250 {
251  va_list ap;
252 
253  va_start(ap, fmt);
254  vmsg_fatal(fmt, ap);
255  /* NOTREACHED */
256 }
257 
258 NORETURN vmsg_fatal(const char *fmt, va_list ap)
259 {
260  if (msg_exiting++ == 0) {
261  msg_vprintf(MSG_FATAL, fmt, ap);
262  if (msg_cleanup_fn)
263  msg_cleanup_fn();
264  }
265  sleep(1);
266  /* In case we're running as a signal handler. */
267  _exit(1);
268 }
269 
270 /* msg_fatal_status - report error and terminate gracefully */
271 
272 NORETURN msg_fatal_status(int status, const char *fmt,...)
273 {
274  va_list ap;
275 
276  va_start(ap, fmt);
277  vmsg_fatal_status(status, fmt, ap);
278  /* NOTREACHED */
279 }
280 
281 NORETURN vmsg_fatal_status(int status, const char *fmt, va_list ap)
282 {
283  if (msg_exiting++ == 0) {
284  msg_vprintf(MSG_FATAL, fmt, ap);
285  if (msg_cleanup_fn)
286  msg_cleanup_fn();
287  }
288  sleep(1);
289  /* In case we're running as a signal handler. */
290  _exit(status);
291 }
292 
293 /* msg_panic - report error and dump core */
294 
295 NORETURN msg_panic(const char *fmt,...)
296 {
297  va_list ap;
298 
299  va_start(ap, fmt);
300  vmsg_panic(fmt, ap);
301  /* NOTREACHED */
302 }
303 
304 NORETURN vmsg_panic(const char *fmt, va_list ap)
305 {
306  if (msg_exiting++ == 0) {
307  msg_vprintf(MSG_PANIC, fmt, ap);
308  }
309  sleep(1);
310  abort(); /* Die! */
311  /* In case we're running as a signal handler. */
312  _exit(1); /* DIE!! */
313 }
314 
315 /* msg_cleanup - specify cleanup routine */
316 
318 {
319  MSG_CLEANUP_FN old_fn = msg_cleanup_fn;
320 
321  msg_cleanup_fn = cleanup_fn;
322  return (old_fn);
323 }
324 
325 /* msg_error_limit - set error message counter limit */
326 
327 int msg_error_limit(int limit)
328 {
329  int old = msg_error_bound;
330 
331  msg_error_bound = limit;
332  return (old);
333 }
334 
335 /* msg_error_clear - reset error message counter */
336 
337 void msg_error_clear(void)
338 {
339  msg_error_count = 0;
340 }
int msg_verbose
Definition: msg.c:177
void msg_error(const char *fmt,...)
Definition: msg.c:231
int msg_error_limit(int limit)
Definition: msg.c:327
#define MSG_WARN
Definition: msg_output.h:29
#define NORETURN
Definition: sys_defs.h:1583
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
void(* MSG_CLEANUP_FN)(void)
Definition: msg.h:23
#define MSG_FATAL
Definition: msg_output.h:31
int const char * fmt
NORETURN vmsg_panic(const char *fmt, va_list ap)
Definition: msg.c:304
#define MSG_PANIC
Definition: msg_output.h:32
#define MSG_INFO
Definition: msg_output.h:28
void msg_vprintf(int level, const char *format, va_list ap)
Definition: msg_output.c:149
void msg_warn(const char *fmt,...)
Definition: msg.c:215
volatile int msg_exiting
Definition: msg.c:195
void vmsg_warn(const char *fmt, va_list ap)
Definition: msg.c:224
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
NORETURN vmsg_fatal(const char *fmt, va_list ap)
Definition: msg.c:258
void vmsg_info(const char *fmt, va_list ap)
Definition: msg.c:208
void vmsg_error(const char *fmt, va_list ap)
Definition: msg.c:240
#define MSG_ERROR
Definition: msg_output.h:30
NORETURN msg_fatal_status(int status, const char *fmt,...)
Definition: msg.c:272
void msg_error_clear(void)
Definition: msg.c:337
NORETURN vmsg_fatal_status(int status, const char *fmt, va_list ap)
Definition: msg.c:281
MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN cleanup_fn)
Definition: msg.c:317
void msg_info(const char *fmt,...)
Definition: msg.c:199