]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sbin/hastd/pjdlog.c
MFC r208028,r210368,r210702,r210869,r210870,r210872,r210873,r210875,r210876,
[FreeBSD/stable/8.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, " ");
218                 fprintf(out, "%s", pjdlog_prefix);
219                 vfprintf(out, fmt, ap);
220                 if (error != -1)
221                         fprintf(out, ": %s.", strerror(error));
222                 fprintf(out, "\n");
223                 fflush(out);
224                 break;
225             }
226         case PJDLOG_MODE_SYSLOG:
227             {
228                 char log[1024];
229                 int len;
230
231                 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
232                 if ((size_t)len < sizeof(log))
233                         len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
234                 if (error != -1 && (size_t)len < sizeof(log)) {
235                         (void)snprintf(log + len, sizeof(log) - len, ": %s.",
236                             strerror(error));
237                 }
238                 syslog(loglevel, "%s", log);
239                 break;
240             }
241         default:
242                 assert(!"Invalid mode.");
243         }
244 }
245
246 /*
247  * Regular logs.
248  */
249 void
250 pjdlogv(int loglevel, const char *fmt, va_list ap)
251 {
252
253         /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
254         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
255             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
256             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
257             loglevel == LOG_INFO);
258
259         pjdlogv_common(loglevel, 0, -1, fmt, ap);
260 }
261
262 /*
263  * Regular logs.
264  */
265 void
266 pjdlog(int loglevel, const char *fmt, ...)
267 {
268         va_list ap;
269
270         va_start(ap, fmt);
271         pjdlogv(loglevel, fmt, ap);
272         va_end(ap);
273 }
274
275 /*
276  * Debug logs.
277  */
278 void
279 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
280 {
281
282         pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
283 }
284
285 /*
286  * Debug logs.
287  */
288 void
289 pjdlog_debug(int debuglevel, const char *fmt, ...)
290 {
291         va_list ap;
292
293         va_start(ap, fmt);
294         pjdlogv_debug(debuglevel, fmt, ap);
295         va_end(ap);
296 }
297
298 /*
299  * Error logs with errno logging.
300  */
301 void
302 pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
303 {
304
305         pjdlogv_common(loglevel, 0, errno, fmt, ap);
306 }
307
308 /*
309  * Error logs with errno logging.
310  */
311 void
312 pjdlog_errno(int loglevel, const char *fmt, ...)
313 {
314         va_list ap;
315
316         va_start(ap, fmt);
317         pjdlogv_errno(loglevel, fmt, ap);
318         va_end(ap);
319 }
320
321 /*
322  * Log error, errno and exit.
323  */
324 void
325 pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
326 {
327
328         pjdlogv_errno(LOG_ERR, fmt, ap);
329         exit(exitcode);
330         /* NOTREACHED */
331 }
332
333 /*
334  * Log error, errno and exit.
335  */
336 void
337 pjdlog_exit(int exitcode, const char *fmt, ...)
338 {
339         va_list ap;
340
341         va_start(ap, fmt);
342         pjdlogv_exit(exitcode, fmt, ap);
343         /* NOTREACHED */
344         va_end(ap);
345 }
346
347 /*
348  * Log error and exit.
349  */
350 void
351 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
352 {
353
354         pjdlogv(LOG_ERR, fmt, ap);
355         exit(exitcode);
356         /* NOTREACHED */
357 }
358
359 /*
360  * Log error and exit.
361  */
362 void
363 pjdlog_exitx(int exitcode, const char *fmt, ...)
364 {
365         va_list ap;
366
367         va_start(ap, fmt);
368         pjdlogv_exitx(exitcode, fmt, ap);
369         /* NOTREACHED */
370         va_end(ap);
371 }
372
373 /*
374  * Log assertion and exit.
375  */
376 void
377 pjdlog_verify(const char *func, const char *file, int line,
378     const char *failedexpr)
379 {
380
381         if (func == NULL) {
382                 pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
383                     failedexpr, file, line);
384         } else {
385                 pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
386                     failedexpr, func, file, line);
387         }
388         abort();
389         /* NOTREACHED */
390 }
391