source: web/old/remctl-2.14/util/messages.c @ f6f3e91

web
Last change on this file since f6f3e91 was f6f3e91, checked in by Jessica B. Hamrick <jhamrick@…>, 15 years ago

Preserve directory hierarchy (not sure what happened to it)

  • Property mode set to 100644
File size: 9.4 KB
Line 
1/*
2 * Message and error reporting (non-fatal).
3 *
4 * Usage:
5 *
6 *     extern int cleanup(void);
7 *     extern void log(int, const char *, va_list, int);
8 *
9 *     message_program_name = argv[0];
10 *
11 *     warn("Something horrible happened at %lu", time);
12 *     syswarn("Couldn't unlink temporary file %s", tmpfile);
13 *
14 *     debug("Some debugging message about %s", string);
15 *     notice("Informational notices");
16 *
17 *     message_handlers_warn(1, log);
18 *     warn("This now goes through our log function");
19 *
20 * These functions implement message reporting through user-configurable
21 * handler functions.  debug() only does something if DEBUG is defined, and
22 * notice() and warn() just output messages as configured.
23 *
24 * The sys* versions do the same, but append a colon, a space, and the results
25 * of strerror(errno) to the end of the message.  All functions accept
26 * printf-style formatting strings and arguments.
27 *
28 * If message_program_name is non-NULL, the string it points to, followed by a
29 * colon and a space, is prepended to all error messages logged through the
30 * message_log_stdout and message_log_stderr message handlers (the former is
31 * the default for notice, and the latter is the default for warn).
32 *
33 * Honoring error_program_name and printing to stderr is just the default
34 * handler; with message_handlers_* the handlers for any message function can
35 * be changed.  By default, notice prints to stdout, warn prints to stderr,
36 * and the others don't do anything at all.  These functions take a count of
37 * handlers and then that many function pointers, each one to a function that
38 * takes a message length (the number of characters snprintf generates given
39 * the format and arguments), a format, an argument list as a va_list, and the
40 * applicable errno value (if any).
41 *
42 * Copyright 2008 Board of Trustees, Leland Stanford Jr. University
43 * Copyright (c) 2004, 2005, 2006
44 *     by Internet Systems Consortium, Inc. ("ISC")
45 * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
46 *     2002, 2003 by The Internet Software Consortium and Rich Salz
47 *
48 * See LICENSE for licensing terms.
49 */
50
51#include <config.h>
52#include <portable/system.h>
53
54#include <errno.h>
55#ifdef HAVE_SYSLOG_H
56# include <syslog.h>
57#endif
58
59#ifdef _WIN32
60# include <windows.h>
61# define LOG_DEBUG      EVENTLOG_SUCCESS
62# define LOG_INFO       EVENTLOG_INFORMATION_TYPE
63# define LOG_NOTICE     EVENTLOG_INFORMATION_TYPE
64# define LOG_WARNING    EVENTLOG_WARNING_TYPE
65# define LOG_ERR        EVENTLOG_ERROR_TYPE
66# define LOG_CRIT       EVENTLOG_ERROR_TYPE
67#endif
68
69#include <util/util.h>
70
71/* The default handler lists. */
72static message_handler_func stdout_handlers[2] = {
73    message_log_stdout, NULL
74};
75static message_handler_func stderr_handlers[2] = {
76    message_log_stderr, NULL
77};
78
79/* The list of logging functions currently in effect. */
80static message_handler_func *debug_handlers  = NULL;
81static message_handler_func *notice_handlers = stdout_handlers;
82static message_handler_func *warn_handlers   = stderr_handlers;
83
84/* If non-NULL, prepended (followed by ": ") to messages. */
85const char *message_program_name = NULL;
86
87
88/*
89 * Set the handlers for a particular message function.  Takes a pointer to the
90 * handler list, the count of handlers, and the argument list.
91 */
92static void
93message_handlers(message_handler_func **list, int count, va_list args)
94{
95    int i;
96
97    if (*list != stdout_handlers && *list != stderr_handlers)
98        free(*list);
99    *list = xmalloc(sizeof(message_handler_func) * (count + 1));
100    for (i = 0; i < count; i++)
101        (*list)[i] = (message_handler_func) va_arg(args, message_handler_func);
102    (*list)[count] = NULL;
103}
104
105
106/*
107 * There's no good way of writing these handlers without a bunch of code
108 * duplication since we can't assume variadic macros, but I can at least make
109 * it easier to write and keep them consistent.
110 */
111#define HANDLER_FUNCTION(type)                                  \
112    void                                                        \
113    message_handlers_ ## type(int count, ...)                   \
114    {                                                           \
115        va_list args;                                           \
116                                                                \
117        va_start(args, count);                                  \
118        message_handlers(& type ## _handlers, count, args);     \
119        va_end(args);                                           \
120    }
121HANDLER_FUNCTION(debug)
122HANDLER_FUNCTION(notice)
123HANDLER_FUNCTION(warn)
124
125
126/*
127 * Print a message to stdout, supporting message_program_name.
128 */
129void
130message_log_stdout(int len UNUSED, const char *fmt, va_list args, int err)
131{
132    if (message_program_name != NULL)
133        fprintf(stdout, "%s: ", message_program_name);
134    vfprintf(stdout, fmt, args);
135    if (err)
136        fprintf(stdout, ": %s", strerror(err));
137    fprintf(stdout, "\n");
138    fflush(stdout);
139}
140
141
142/*
143 * Print a message to stderr, supporting message_program_name.  Also flush
144 * stdout so that errors and regular output occur in the right order.
145 */
146void
147message_log_stderr(int len UNUSED, const char *fmt, va_list args, int err)
148{
149    fflush(stdout);
150    if (message_program_name != NULL)
151        fprintf(stderr, "%s: ", message_program_name);
152    vfprintf(stderr, fmt, args);
153    if (err)
154        fprintf(stderr, ": %s", strerror(err));
155    fprintf(stderr, "\n");
156}
157
158
159/*
160 * Log a message to syslog.  This is a helper function used to implement all
161 * of the syslog message log handlers.  It takes the same arguments as a
162 * regular message handler function but with an additional priority argument.
163 *
164 * This needs further attention on Windows.  For example, it currently doesn't
165 * log the errno information.
166 */
167static void
168message_log_syslog(int pri, int len, const char *fmt, va_list args, int err)
169{
170    char *buffer;
171
172    buffer = malloc(len + 1);
173    if (buffer == NULL) {
174        fprintf(stderr, "failed to malloc %u bytes at %s line %d: %s",
175                len + 1, __FILE__, __LINE__, strerror(errno));
176        exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1);
177    }
178    vsnprintf(buffer, len + 1, fmt, args);
179#ifdef _WIN32
180    {
181        HANDLE eventlog;
182
183        eventlog = RegisterEventSource(NULL, message_program_name);
184        if (eventlog != NULL) {
185            ReportEvent(eventlog, pri, 0, 0, NULL, 1, 0, &buffer, NULL);
186            CloseEventLog(eventlog);
187        }
188    }
189#else /* !_WIN32 */
190    if (err == 0)
191        syslog(pri, "%s", buffer);
192    else
193        syslog(pri, "%s: %s", buffer, strerror(err));
194#endif /* !_WIN32 */
195    free(buffer);
196}
197
198
199/*
200 * Do the same sort of wrapper to generate all of the separate syslog logging
201 * functions.
202 */
203#define SYSLOG_FUNCTION(name, type)                                     \
204    void                                                                \
205    message_log_syslog_ ## name(int l, const char *f, va_list a, int e) \
206    {                                                                   \
207        message_log_syslog(LOG_ ## type, l, f, a, e);                   \
208    }
209SYSLOG_FUNCTION(debug,   DEBUG)
210SYSLOG_FUNCTION(info,    INFO)
211SYSLOG_FUNCTION(notice,  NOTICE)
212SYSLOG_FUNCTION(warning, WARNING)
213SYSLOG_FUNCTION(err,     ERR)
214SYSLOG_FUNCTION(crit,    CRIT)
215
216
217/*
218 * All of the message handlers.  There's a lot of code duplication here too,
219 * but each one is still *slightly* different and va_start has to be called
220 * multiple times, so it's hard to get rid of the duplication.
221 */
222
223void
224debug(const char *format, ...)
225{
226    va_list args;
227    message_handler_func *log;
228    int length;
229
230    if (debug_handlers == NULL)
231        return;
232    va_start(args, format);
233    length = vsnprintf(NULL, 0, format, args);
234    va_end(args);
235    if (length < 0)
236        return;
237    for (log = debug_handlers; *log != NULL; log++) {
238        va_start(args, format);
239        (**log)(length, format, args, 0);
240        va_end(args);
241    }
242}
243
244void
245notice(const char *format, ...)
246{
247    va_list args;
248    message_handler_func *log;
249    int length;
250
251    va_start(args, format);
252    length = vsnprintf(NULL, 0, format, args);
253    va_end(args);
254    if (length < 0)
255        return;
256    for (log = notice_handlers; *log != NULL; log++) {
257        va_start(args, format);
258        (**log)(length, format, args, 0);
259        va_end(args);
260    }
261}
262
263void
264sysnotice(const char *format, ...)
265{
266    va_list args;
267    message_handler_func *log;
268    int length;
269    int error = errno;
270
271    va_start(args, format);
272    length = vsnprintf(NULL, 0, format, args);
273    va_end(args);
274    if (length < 0)
275        return;
276    for (log = notice_handlers; *log != NULL; log++) {
277        va_start(args, format);
278        (**log)(length, format, args, error);
279        va_end(args);
280    }
281}
282
283void
284warn(const char *format, ...)
285{
286    va_list args;
287    message_handler_func *log;
288    int length;
289
290    va_start(args, format);
291    length = vsnprintf(NULL, 0, format, args);
292    va_end(args);
293    if (length < 0)
294        return;
295    for (log = warn_handlers; *log != NULL; log++) {
296        va_start(args, format);
297        (**log)(length, format, args, 0);
298        va_end(args);
299    }
300}
301
302void
303syswarn(const char *format, ...)
304{
305    va_list args;
306    message_handler_func *log;
307    int length;
308    int error = errno;
309
310    va_start(args, format);
311    length = vsnprintf(NULL, 0, format, args);
312    va_end(args);
313    if (length < 0)
314        return;
315    for (log = warn_handlers; *log != NULL; log++) {
316        va_start(args, format);
317        (**log)(length, format, args, error);
318        va_end(args);
319    }
320}
Note: See TracBrowser for help on using the repository browser.