1 /* $Id: messages.c 5496 2002-06-07 13:59:06Z alexk $
3 ** Message and error reporting (possibly fatal).
7 ** extern int cleanup(void);
8 ** extern void log(int, const char *, va_list, int);
10 ** message_fatal_cleanup = cleanup;
11 ** message_program_name = argv[0];
13 ** warn("Something horrible happened at %lu", time);
14 ** syswarn("Couldn't unlink temporary file %s", tmpfile);
16 ** die("Something fatal happened at %lu", time);
17 ** sysdie("open of %s failed", filename);
19 ** debug("Some debugging message about %s", string);
20 ** trace(TRACE_PROGRAM, "Program trace output");
21 ** notice("Informational notices");
23 ** message_handlers_warn(1, log);
24 ** warn("This now goes through our log function");
26 ** These functions implement message reporting through user-configurable
27 ** handler functions. debug() only does something if DEBUG is defined,
28 ** trace() supports sending trace messages in one of a number of configurable
29 ** classes of traces so that they can be turned on or off independently, and
30 ** notice() and warn() just output messages as configured. die() similarly
31 ** outputs a message but then exits, normally with a status of 1.
33 ** The sys* versions do the same, but append a colon, a space, and the
34 ** results of strerror(errno) to the end of the message. All functions
35 ** accept printf-style formatting strings and arguments.
37 ** If message_fatal_cleanup is non-NULL, it is called before exit by die and
38 ** sysdie and its return value is used as the argument to exit. It is a
39 ** pointer to a function taking no arguments and returning an int, and can be
40 ** used to call cleanup functions or to exit in some alternate fashion (such
41 ** as by calling _exit).
43 ** If message_program_name is non-NULL, the string it points to, followed by
44 ** a colon and a space, is prepended to all error messages logged through the
45 ** message_log_stdout and message_log_stderr message handlers (the former is
46 ** the default for notice, and the latter is the default for warn and die).
48 ** Honoring error_program_name and printing to stderr is just the default
49 ** handler; with message_handlers_* the handlers for any message function can
50 ** be changed. By default, notice prints to stdout, warn and die print to
51 ** stderr, and the others don't do anything at all. These functions take a
52 ** count of handlers and then that many function pointers, each one to a
53 ** function that takes a message length (the number of characters snprintf
54 ** generates given the format and arguments), a format, an argument list as a
55 ** va_list, and the applicable errno value (if any).
63 #include "inn/messages.h"
66 /* The default handler lists. */
67 static message_handler_func stdout_handlers[2] = {
68 message_log_stdout, NULL
70 static message_handler_func stderr_handlers[2] = {
71 message_log_stderr, NULL
74 /* The list of logging functions currently in effect. */
75 static message_handler_func *debug_handlers = NULL;
76 static message_handler_func *trace_handlers = NULL;
77 static message_handler_func *notice_handlers = stdout_handlers;
78 static message_handler_func *warn_handlers = stderr_handlers;
79 static message_handler_func *die_handlers = stderr_handlers;
81 /* If non-NULL, called before exit and its return value passed to exit. */
82 int (*message_fatal_cleanup)(void) = NULL;
84 /* If non-NULL, prepended (followed by ": ") to messages. */
85 const char *message_program_name = NULL;
87 /* Whether or not we're currently outputting a particular type of trace. */
88 static bool tracing[TRACE_ALL] = { false /* false, ... */ };
92 ** Set the handlers for a particular message function. Takes a pointer to
93 ** the handler list, the count of handlers, and the argument list.
96 message_handlers(message_handler_func **list, int count, va_list args)
100 if (*list != stdout_handlers && *list != stderr_handlers)
102 *list = xmalloc(sizeof(message_handler_func) * (count + 1));
103 for (i = 0; i < count; i++)
104 (*list)[i] = (message_handler_func) va_arg(args, message_handler_func);
105 (*list)[count] = NULL;
110 ** There's no good way of writing these handlers without a bunch of code
111 ** duplication since we can't assume variadic macros, but I can at least make
112 ** it easier to write and keep them consistent.
114 #define HANDLER_FUNCTION(type) \
116 message_handlers_ ## type(int count, ...) \
120 va_start(args, count); \
121 message_handlers(& type ## _handlers, count, args); \
124 HANDLER_FUNCTION(debug)
125 HANDLER_FUNCTION(trace)
126 HANDLER_FUNCTION(notice)
127 HANDLER_FUNCTION(warn)
128 HANDLER_FUNCTION(die)
132 ** Print a message to stdout, supporting message_program_name.
135 message_log_stdout(int len UNUSED, const char *fmt, va_list args, int err)
137 if (message_program_name != NULL)
138 fprintf(stdout, "%s: ", message_program_name);
139 vfprintf(stdout, fmt, args);
141 fprintf(stdout, ": %s", strerror(err));
142 fprintf(stdout, "\n");
147 ** Print a message to stderr, supporting message_program_name. Also flush
148 ** stdout so that errors and regular output occur in the right order.
151 message_log_stderr(int len UNUSED, const char *fmt, va_list args, int err)
154 if (message_program_name != NULL)
155 fprintf(stderr, "%s: ", message_program_name);
156 vfprintf(stderr, fmt, args);
158 fprintf(stderr, ": %s", strerror(err));
159 fprintf(stderr, "\n");
164 ** Log a message to syslog. This is a helper function used to implement all
165 ** of the syslog message log handlers. It takes the same arguments as a
166 ** regular message handler function but with an additional priority
170 message_log_syslog(int pri, int len, const char *fmt, va_list args, int err)
174 buffer = malloc(len + 1);
175 if (buffer == NULL) {
176 fprintf(stderr, "failed to malloc %u bytes at %s line %d: %s",
177 len + 1, __FILE__, __LINE__, strerror(errno));
178 exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1);
180 vsnprintf(buffer, len + 1, fmt, args);
181 syslog(pri, err ? "%s: %m" : "%s", buffer);
187 ** Do the same sort of wrapper to generate all of the separate syslog logging
190 #define SYSLOG_FUNCTION(name, type) \
192 message_log_syslog_ ## name(int l, const char *f, va_list a, int e) \
194 message_log_syslog(LOG_ ## type, l, f, a, e); \
196 SYSLOG_FUNCTION(debug, DEBUG)
197 SYSLOG_FUNCTION(info, INFO)
198 SYSLOG_FUNCTION(notice, NOTICE)
199 SYSLOG_FUNCTION(warning, WARNING)
200 SYSLOG_FUNCTION(err, ERR)
201 SYSLOG_FUNCTION(crit, CRIT)
205 ** Enable or disable tracing for particular classes of messages.
208 message_trace_enable(enum message_trace type, bool enable)
210 if (type > TRACE_ALL)
212 if (type == TRACE_ALL) {
215 for (i = 0; i < TRACE_ALL; i++)
218 tracing[type] = enable;
224 ** All of the message handlers. There's a lot of code duplication here too,
225 ** but each one is still *slightly* different and va_start has to be called
226 ** multiple times, so it's hard to get rid of the duplication.
231 debug(const char *format, ...)
234 message_handler_func *log;
237 if (debug_handlers == NULL)
239 va_start(args, format);
240 length = vsnprintf(NULL, 0, format, args);
244 for (log = debug_handlers; *log != NULL; log++) {
245 va_start(args, format);
246 (**log)(length, format, args, 0);
250 #elif !INN_HAVE_C99_VAMACROS && !INN_HAVE_GNU_VAMACROS
251 void debug(const char *format UNUSED, ...) { }
255 trace(enum message_trace type, const char *format, ...)
258 message_handler_func *log;
261 if (trace_handlers == NULL || !tracing[type])
263 va_start(args, format);
264 length = vsnprintf(NULL, 0, format, args);
268 for (log = trace_handlers; *log != NULL; log++) {
269 va_start(args, format);
270 (**log)(length, format, args, 0);
276 notice(const char *format, ...)
279 message_handler_func *log;
282 va_start(args, format);
283 length = vsnprintf(NULL, 0, format, args);
287 for (log = notice_handlers; *log != NULL; log++) {
288 va_start(args, format);
289 (**log)(length, format, args, 0);
295 sysnotice(const char *format, ...)
298 message_handler_func *log;
302 va_start(args, format);
303 length = vsnprintf(NULL, 0, format, args);
307 for (log = notice_handlers; *log != NULL; log++) {
308 va_start(args, format);
309 (**log)(length, format, args, error);
315 warn(const char *format, ...)
318 message_handler_func *log;
321 va_start(args, format);
322 length = vsnprintf(NULL, 0, format, args);
326 for (log = warn_handlers; *log != NULL; log++) {
327 va_start(args, format);
328 (**log)(length, format, args, 0);
334 syswarn(const char *format, ...)
337 message_handler_func *log;
341 va_start(args, format);
342 length = vsnprintf(NULL, 0, format, args);
346 for (log = warn_handlers; *log != NULL; log++) {
347 va_start(args, format);
348 (**log)(length, format, args, error);
354 die(const char *format, ...)
357 message_handler_func *log;
360 va_start(args, format);
361 length = vsnprintf(NULL, 0, format, args);
364 for (log = die_handlers; *log != NULL; log++) {
365 va_start(args, format);
366 (**log)(length, format, args, 0);
369 exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1);
373 sysdie(const char *format, ...)
376 message_handler_func *log;
380 va_start(args, format);
381 length = vsnprintf(NULL, 0, format, args);
384 for (log = die_handlers; *log != NULL; log++) {
385 va_start(args, format);
386 (**log)(length, format, args, error);
389 exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1);