]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sbin/hastd/pjdlog.c
MFS r217050: Make minidumps work on i386/XEN.
[FreeBSD/releng/8.2.git] / sbin / hastd / pjdlog.c
1 /*-
2  * Copyright (c) 2009-2010 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <syslog.h>
40
41 #include "pjdlog.h"
42
43 static int pjdlog_mode = PJDLOG_MODE_STD;
44 static int pjdlog_debug_level = 0;
45 static char pjdlog_prefix[128];
46
47 /*
48  * Configure where the logs should go.
49  * By default they are send to stdout/stderr, but after going into background
50  * (eg. by calling daemon(3)) application is responsible for changing mode to
51  * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
52  */
53 void
54 pjdlog_mode_set(int mode)
55 {
56
57         assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
58
59         pjdlog_mode = mode;
60
61         if (mode == PJDLOG_MODE_SYSLOG)
62                 openlog(NULL, LOG_PID, LOG_DAEMON);
63 }
64
65 /*
66  * Return current mode.
67  */
68 int
69 pjdlog_mode_get(void)
70 {
71
72         return (pjdlog_mode);
73 }
74
75 /*
76  * Set debug level. All the logs above the level specified here will be
77  * ignored.
78  */
79 void
80 pjdlog_debug_set(int level)
81 {
82
83         assert(level >= 0);
84
85         pjdlog_debug_level = level;
86 }
87
88 /*
89  * Return current debug level.
90  */
91 int
92 pjdlog_debug_get(void)
93 {
94
95         return (pjdlog_debug_level);
96 }
97
98 /*
99  * Set prefix that will be used before each log.
100  * Setting prefix to NULL will remove it.
101  */
102 void
103 pjdlog_prefix_set(const char *fmt, ...)
104 {
105         va_list ap;
106
107         va_start(ap, fmt);
108         pjdlog_prefix_setv(fmt, ap);
109         va_end(ap);
110 }
111
112 /*
113  * Set prefix that will be used before each log.
114  * Setting prefix to NULL will remove it.
115  */
116 void
117 pjdlog_prefix_setv(const char *fmt, va_list ap)
118 {
119
120         assert(fmt != NULL);
121
122         vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
123 }
124
125 /*
126  * Convert log level into string.
127  */
128 static const char *
129 pjdlog_level_string(int loglevel)
130 {
131
132         switch (loglevel) {
133         case LOG_EMERG:
134                 return ("EMERG");
135         case LOG_ALERT:
136                 return ("ALERT");
137         case LOG_CRIT:
138                 return ("CRIT");
139         case LOG_ERR:
140                 return ("ERROR");
141         case LOG_WARNING:
142                 return ("WARNING");
143         case LOG_NOTICE:
144                 return ("NOTICE");
145         case LOG_INFO:
146                 return ("INFO");
147         case LOG_DEBUG:
148                 return ("DEBUG");
149         }
150         assert(!"Invalid log level.");
151         abort();        /* XXX: gcc */
152 }
153
154 /*
155  * Common log routine.
156  */
157 void
158 pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
159 {
160         va_list ap;
161
162         va_start(ap, fmt);
163         pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
164         va_end(ap);
165 }
166
167 /*
168  * Common log routine, which can handle regular log level as well as debug
169  * level. We decide here where to send the logs (stdout/stderr or syslog).
170  */
171 void
172 pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
173     va_list ap)
174 {
175
176         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
177             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
178             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
179             loglevel == LOG_INFO || loglevel == LOG_DEBUG);
180         assert(loglevel != LOG_DEBUG || debuglevel > 0);
181         assert(error >= -1);
182
183         /* Ignore debug above configured level. */
184         if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
185                 return;
186
187         switch (pjdlog_mode) {
188         case PJDLOG_MODE_STD:
189             {
190                 FILE *out;
191
192                 /*
193                  * We send errors and warning to stderr and the rest to stdout.
194                  */
195                 switch (loglevel) {
196                 case LOG_EMERG:
197                 case LOG_ALERT:
198                 case LOG_CRIT:
199                 case LOG_ERR:
200                 case LOG_WARNING:
201                         out = stderr;
202                         break;
203                 case LOG_NOTICE:
204                 case LOG_INFO:
205                 case LOG_DEBUG:
206                         out = stdout;
207                         break;
208                 default:
209                         assert(!"Invalid loglevel.");
210                         abort();        /* XXX: gcc */
211                 }
212
213                 fprintf(out, "[%s]", pjdlog_level_string(loglevel));
214                 /* Attach debuglevel if this is debug log. */
215                 if (loglevel == LOG_DEBUG)
216                         fprintf(out, "[%d]", debuglevel);
217                 fprintf(out, " %s", pjdlog_prefix);
218                 vfprintf(out, fmt, ap);
219                 if (error != -1)
220                         fprintf(out, ": %s.", strerror(error));
221                 fprintf(out, "\n");
222                 fflush(out);
223                 break;
224             }
225         case PJDLOG_MODE_SYSLOG:
226             {
227                 char log[1024];
228                 int len;
229
230                 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
231                 if ((size_t)len < sizeof(log))
232                         len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
233                 if (error != -1 && (size_t)len < sizeof(log)) {
234                         (void)snprintf(log + len, sizeof(log) - len, ": %s.",
235                             strerror(error));
236                 }
237                 syslog(loglevel, "%s", log);
238                 break;
239             }
240         default:
241                 assert(!"Invalid mode.");
242         }
243 }
244
245 /*
246  * Regular logs.
247  */
248 void
249 pjdlogv(int loglevel, const char *fmt, va_list ap)
250 {
251
252         /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
253         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
254             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
255             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
256             loglevel == LOG_INFO);
257
258         pjdlogv_common(loglevel, 0, -1, fmt, ap);
259 }
260
261 /*
262  * Regular logs.
263  */
264 void
265 pjdlog(int loglevel, const char *fmt, ...)
266 {
267         va_list ap;
268
269         va_start(ap, fmt);
270         pjdlogv(loglevel, fmt, ap);
271         va_end(ap);
272 }
273
274 /*
275  * Debug logs.
276  */
277 void
278 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
279 {
280
281         pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
282 }
283
284 /*
285  * Debug logs.
286  */
287 void
288 pjdlog_debug(int debuglevel, const char *fmt, ...)
289 {
290         va_list ap;
291
292         va_start(ap, fmt);
293         pjdlogv_debug(debuglevel, fmt, ap);
294         va_end(ap);
295 }
296
297 /*
298  * Error logs with errno logging.
299  */
300 void
301 pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
302 {
303
304         pjdlogv_common(loglevel, 0, errno, fmt, ap);
305 }
306
307 /*
308  * Error logs with errno logging.
309  */
310 void
311 pjdlog_errno(int loglevel, const char *fmt, ...)
312 {
313         va_list ap;
314
315         va_start(ap, fmt);
316         pjdlogv_errno(loglevel, fmt, ap);
317         va_end(ap);
318 }
319
320 /*
321  * Log error, errno and exit.
322  */
323 void
324 pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
325 {
326
327         pjdlogv_errno(LOG_ERR, fmt, ap);
328         exit(exitcode);
329         /* NOTREACHED */
330 }
331
332 /*
333  * Log error, errno and exit.
334  */
335 void
336 pjdlog_exit(int exitcode, const char *fmt, ...)
337 {
338         va_list ap;
339
340         va_start(ap, fmt);
341         pjdlogv_exit(exitcode, fmt, ap);
342         /* NOTREACHED */
343         va_end(ap);
344 }
345
346 /*
347  * Log error and exit.
348  */
349 void
350 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
351 {
352
353         pjdlogv(LOG_ERR, fmt, ap);
354         exit(exitcode);
355         /* NOTREACHED */
356 }
357
358 /*
359  * Log error and exit.
360  */
361 void
362 pjdlog_exitx(int exitcode, const char *fmt, ...)
363 {
364         va_list ap;
365
366         va_start(ap, fmt);
367         pjdlogv_exitx(exitcode, fmt, ap);
368         /* NOTREACHED */
369         va_end(ap);
370 }
371
372 /*
373  * Log assertion and exit.
374  */
375 void
376 pjdlog_verify(const char *func, const char *file, int line,
377     const char *failedexpr)
378 {
379
380         if (func == NULL) {
381                 pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
382                     failedexpr, file, line);
383         } else {
384                 pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
385                     failedexpr, func, file, line);
386         }
387         abort();
388         /* NOTREACHED */
389 }
390