]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sbin/hastd/pjdlog.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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  * $FreeBSD$
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <assert.h>
36 #include <errno.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <syslog.h>
42
43 #include "pjdlog.h"
44
45 static int pjdlog_mode = PJDLOG_MODE_STD;
46 static int pjdlog_debug_level = 0;
47 static char pjdlog_prefix[128];
48
49 /*
50  * Configure where the logs should go.
51  * By default they are send to stdout/stderr, but after going into background
52  * (eg. by calling daemon(3)) application is responsible for changing mode to
53  * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
54  */
55 void
56 pjdlog_mode_set(int mode)
57 {
58
59         assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
60
61         pjdlog_mode = mode;
62 }
63
64 /*
65  * Return current mode.
66  */
67 int
68 pjdlog_mode_get(void)
69 {
70
71         return (pjdlog_mode);
72 }
73
74 /*
75  * Set debug level. All the logs above the level specified here will be
76  * ignored.
77  */
78 void
79 pjdlog_debug_set(int level)
80 {
81
82         assert(level >= 0);
83
84         pjdlog_debug_level = level;
85 }
86
87 /*
88  * Return current debug level.
89  */
90 int
91 pjdlog_debug_get(void)
92 {
93
94         return (pjdlog_debug_level);
95 }
96
97 /*
98  * Set prefix that will be used before each log.
99  * Setting prefix to NULL will remove it.
100  */
101 void
102 pjdlog_prefix_set(const char *fmt, ...)
103 {
104         va_list ap;
105
106         va_start(ap, fmt);
107         pjdlog_prefix_setv(fmt, ap);
108         va_end(ap);
109 }
110
111 /*
112  * Set prefix that will be used before each log.
113  * Setting prefix to NULL will remove it.
114  */
115 void
116 pjdlog_prefix_setv(const char *fmt, va_list ap)
117 {
118
119         assert(fmt != NULL);
120
121         vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
122 }
123
124 /*
125  * Convert log level into string.
126  */
127 static const char *
128 pjdlog_level_string(int loglevel)
129 {
130
131         switch (loglevel) {
132         case LOG_EMERG:
133                 return ("EMERG");
134         case LOG_ALERT:
135                 return ("ALERT");
136         case LOG_CRIT:
137                 return ("CRIT");
138         case LOG_ERR:
139                 return ("ERROR");
140         case LOG_WARNING:
141                 return ("WARNING");
142         case LOG_NOTICE:
143                 return ("NOTICE");
144         case LOG_INFO:
145                 return ("INFO");
146         case LOG_DEBUG:
147                 return ("DEBUG");
148         }
149         assert(!"Invalid log level.");
150         abort();        /* XXX: gcc */
151 }
152
153 /*
154  * Common log routine.
155  */
156 void
157 pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
158 {
159         va_list ap;
160
161         va_start(ap, fmt);
162         pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
163         va_end(ap);
164 }
165
166 /*
167  * Common log routine, which can handle regular log level as well as debug
168  * level. We decide here where to send the logs (stdout/stderr or syslog).
169  */
170 void
171 pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
172     va_list ap)
173 {
174
175         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
176             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
177             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
178             loglevel == LOG_INFO || loglevel == LOG_DEBUG);
179         assert(loglevel != LOG_DEBUG || debuglevel > 0);
180         assert(error >= -1);
181
182         /* Ignore debug above configured level. */
183         if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
184                 return;
185
186         switch (pjdlog_mode) {
187         case PJDLOG_MODE_STD:
188             {
189                 FILE *out;
190
191                 /*
192                  * We send errors and warning to stderr and the rest to stdout.
193                  */
194                 switch (loglevel) {
195                 case LOG_EMERG:
196                 case LOG_ALERT:
197                 case LOG_CRIT:
198                 case LOG_ERR:
199                 case LOG_WARNING:
200                         out = stderr;
201                         break;
202                 case LOG_NOTICE:
203                 case LOG_INFO:
204                 case LOG_DEBUG:
205                         out = stdout;
206                         break;
207                 default:
208                         assert(!"Invalid loglevel.");
209                         abort();        /* XXX: gcc */
210                 }
211
212                 fprintf(out, "[%s]", pjdlog_level_string(loglevel));
213                 /* Attach debuglevel if this is debug log. */
214                 if (loglevel == LOG_DEBUG)
215                         fprintf(out, "[%d]", debuglevel);
216                 fprintf(out, " ");
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                 break;
223             }
224         case PJDLOG_MODE_SYSLOG:
225             {
226                 char log[1024];
227                 int len;
228
229                 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
230                 if ((size_t)len < sizeof(log))
231                         len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
232                 if (error != -1 && (size_t)len < sizeof(log)) {
233                         (void)snprintf(log + len, sizeof(log) - len, ": %s.",
234                             strerror(error));
235                 }
236                 syslog(loglevel, "%s", log);
237                 break;
238             }
239         default:
240                 assert(!"Invalid mode.");
241         }
242 }
243
244 /*
245  * Regular logs.
246  */
247 void
248 pjdlogv(int loglevel, const char *fmt, va_list ap)
249 {
250
251         /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
252         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
253             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
254             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
255             loglevel == LOG_INFO);
256
257         pjdlogv_common(loglevel, 0, -1, fmt, ap);
258 }
259
260 /*
261  * Regular logs.
262  */
263 void
264 pjdlog(int loglevel, const char *fmt, ...)
265 {
266         va_list ap;
267
268         va_start(ap, fmt);
269         pjdlogv(loglevel, fmt, ap);
270         va_end(ap);
271 }
272
273 /*
274  * Debug logs.
275  */
276 void
277 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
278 {
279
280         pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
281 }
282
283 /*
284  * Debug logs.
285  */
286 void
287 pjdlog_debug(int debuglevel, const char *fmt, ...)
288 {
289         va_list ap;
290
291         va_start(ap, fmt);
292         pjdlogv_debug(debuglevel, fmt, ap);
293         va_end(ap);
294 }
295
296 /*
297  * Error logs with errno logging.
298  */
299 void
300 pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
301 {
302
303         pjdlogv_common(loglevel, 0, errno, fmt, ap);
304 }
305
306 /*
307  * Error logs with errno logging.
308  */
309 void
310 pjdlog_errno(int loglevel, const char *fmt, ...)
311 {
312         va_list ap;
313
314         va_start(ap, fmt);
315         pjdlogv_errno(loglevel, fmt, ap);
316         va_end(ap);
317 }
318
319 /*
320  * Log error, errno and exit.
321  */
322 void
323 pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
324 {
325
326         pjdlogv_errno(LOG_ERR, fmt, ap);
327         exit(exitcode);
328 }
329
330 /*
331  * Log error, errno and exit.
332  */
333 void
334 pjdlog_exit(int exitcode, const char *fmt, ...)
335 {
336         va_list ap;
337
338         va_start(ap, fmt);
339         pjdlogv_exit(exitcode, fmt, ap);
340         /* NOTREACHED */
341         va_end(ap);
342 }
343
344 /*
345  * Log error and exit.
346  */
347 void
348 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
349 {
350
351         pjdlogv(LOG_ERR, fmt, ap);
352         exit(exitcode);
353 }
354
355 /*
356  * Log error and exit.
357  */
358 void
359 pjdlog_exitx(int exitcode, const char *fmt, ...)
360 {
361         va_list ap;
362
363         va_start(ap, fmt);
364         pjdlogv_exitx(exitcode, fmt, ap);
365         /* NOTREACHED */
366         va_end(ap);
367 }