]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sbin/hastd/pjdlog.c
MFC r219351, r219354, r219369, r219370, r219371, r219372, r219373,
[FreeBSD/stable/8.git] / sbin / hastd / pjdlog.c
1 /*-
2  * Copyright (c) 2009-2010 The FreeBSD Foundation
3  * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4  * All rights reserved.
5  *
6  * This software was developed by Pawel Jakub Dawidek under sponsorship from
7  * the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36
37 #include <assert.h>
38 #include <errno.h>
39 #include <libutil.h>
40 #include <printf.h>
41 #include <stdarg.h>
42 #include <stdint.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <syslog.h>
47
48 #include "pjdlog.h"
49
50 #define PJDLOG_NEVER_INITIALIZED        0
51 #define PJDLOG_NOT_INITIALIZED          1
52 #define PJDLOG_INITIALIZED              2
53
54 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
55 static int pjdlog_mode, pjdlog_debug_level;
56 static char pjdlog_prefix[128];
57
58 static int
59 pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
60     size_t n, int *argt)
61 {
62
63         assert(n >= 1);
64         argt[0] = PA_INT | PA_FLAG_INTMAX;
65         return (1);
66 }
67
68 static int
69 pjdlog_printf_render_humanized_number(struct __printf_io *io,
70     const struct printf_info *pi, const void * const *arg)
71 {
72         char buf[5];
73         intmax_t num;
74         int ret;
75
76         num = *(const intmax_t *)arg[0];
77         humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
78             HN_NOSPACE | HN_DECIMAL);
79         ret = __printf_out(io, pi, buf, strlen(buf));
80         __printf_flush(io);
81         return (ret);
82 }
83
84 static int
85 pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
86     size_t n, int *argt)
87 {
88
89         assert(n >= 1);
90         argt[0] = PA_POINTER;
91         return (1);
92 }
93
94 static int
95 pjdlog_printf_render_sockaddr(struct __printf_io *io,
96     const struct printf_info *pi, const void * const *arg)
97 {
98         const struct sockaddr_storage *ss;
99         char buf[64];
100         int ret;
101
102         ss = *(const struct sockaddr_storage * const *)arg[0];
103         switch (ss->ss_family) {
104         case AF_INET:
105             {
106                 const struct sockaddr_in *sin;
107                 in_addr_t ip;
108                 unsigned int port;
109
110                 sin = (const struct sockaddr_in *)ss;
111                 ip = ntohl(sin->sin_addr.s_addr);
112                 port = ntohs(sin->sin_port);
113
114                 snprintf(buf, sizeof(buf), "%u.%u.%u.%u:%u",
115                     ((ip >> 24) & 0xff), ((ip >> 16) & 0xff),
116                     ((ip >> 8) & 0xff), (ip & 0xff), port);
117                 break;
118             }
119         default:
120                 snprintf(buf, sizeof(buf), "[unsupported family %u]",
121                     (unsigned int)ss->ss_family);
122                 break;
123         }
124         ret = __printf_out(io, pi, buf, strlen(buf));
125         __printf_flush(io);
126         return (ret);
127 }
128
129 void
130 pjdlog_init(int mode)
131 {
132
133         assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
134             pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
135         assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
136
137         if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
138                 __use_xprintf = 1;
139                 register_printf_render_std("T");
140                 register_printf_render('N',
141                     pjdlog_printf_render_humanized_number,
142                     pjdlog_printf_arginfo_humanized_number);
143                 register_printf_render('S',
144                     pjdlog_printf_render_sockaddr,
145                     pjdlog_printf_arginfo_sockaddr);
146         }
147
148         if (mode == PJDLOG_MODE_SYSLOG)
149                 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
150         pjdlog_mode = mode;
151         pjdlog_debug_level = 0;
152         bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
153
154         pjdlog_initialized = PJDLOG_INITIALIZED;
155 }
156
157 void
158 pjdlog_fini(void)
159 {
160
161         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
162
163         if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
164                 closelog();
165
166         pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
167 }
168
169 /*
170  * Configure where the logs should go.
171  * By default they are send to stdout/stderr, but after going into background
172  * (eg. by calling daemon(3)) application is responsible for changing mode to
173  * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
174  */
175 void
176 pjdlog_mode_set(int mode)
177 {
178
179         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
180         assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
181
182         if (pjdlog_mode == mode)
183                 return;
184
185         if (mode == PJDLOG_MODE_SYSLOG)
186                 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
187         else /* if (mode == PJDLOG_MODE_STD) */
188                 closelog();
189
190         pjdlog_mode = mode;
191 }
192
193 /*
194  * Return current mode.
195  */
196 int
197 pjdlog_mode_get(void)
198 {
199
200         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
201
202         return (pjdlog_mode);
203 }
204
205 /*
206  * Set debug level. All the logs above the level specified here will be
207  * ignored.
208  */
209 void
210 pjdlog_debug_set(int level)
211 {
212
213         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
214         assert(level >= 0);
215
216         pjdlog_debug_level = level;
217 }
218
219 /*
220  * Return current debug level.
221  */
222 int
223 pjdlog_debug_get(void)
224 {
225
226         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
227
228         return (pjdlog_debug_level);
229 }
230
231 /*
232  * Set prefix that will be used before each log.
233  * Setting prefix to NULL will remove it.
234  */
235 void
236 pjdlog_prefix_set(const char *fmt, ...)
237 {
238         va_list ap;
239
240         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
241
242         va_start(ap, fmt);
243         pjdlogv_prefix_set(fmt, ap);
244         va_end(ap);
245 }
246
247 /*
248  * Set prefix that will be used before each log.
249  * Setting prefix to NULL will remove it.
250  */
251 void
252 pjdlogv_prefix_set(const char *fmt, va_list ap)
253 {
254
255         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
256         assert(fmt != NULL);
257
258         vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
259 }
260
261 /*
262  * Convert log level into string.
263  */
264 static const char *
265 pjdlog_level_string(int loglevel)
266 {
267
268         switch (loglevel) {
269         case LOG_EMERG:
270                 return ("EMERG");
271         case LOG_ALERT:
272                 return ("ALERT");
273         case LOG_CRIT:
274                 return ("CRIT");
275         case LOG_ERR:
276                 return ("ERROR");
277         case LOG_WARNING:
278                 return ("WARNING");
279         case LOG_NOTICE:
280                 return ("NOTICE");
281         case LOG_INFO:
282                 return ("INFO");
283         case LOG_DEBUG:
284                 return ("DEBUG");
285         }
286         assert(!"Invalid log level.");
287         abort();        /* XXX: gcc */
288 }
289
290 /*
291  * Common log routine.
292  */
293 void
294 pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
295 {
296         va_list ap;
297
298         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
299
300         va_start(ap, fmt);
301         pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
302         va_end(ap);
303 }
304
305 /*
306  * Common log routine, which can handle regular log level as well as debug
307  * level. We decide here where to send the logs (stdout/stderr or syslog).
308  */
309 void
310 pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
311     va_list ap)
312 {
313
314         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
315         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
316             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
317             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
318             loglevel == LOG_INFO || loglevel == LOG_DEBUG);
319         assert(loglevel != LOG_DEBUG || debuglevel > 0);
320         assert(error >= -1);
321
322         /* Ignore debug above configured level. */
323         if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
324                 return;
325
326         switch (pjdlog_mode) {
327         case PJDLOG_MODE_STD:
328             {
329                 FILE *out;
330
331                 /*
332                  * We send errors and warning to stderr and the rest to stdout.
333                  */
334                 switch (loglevel) {
335                 case LOG_EMERG:
336                 case LOG_ALERT:
337                 case LOG_CRIT:
338                 case LOG_ERR:
339                 case LOG_WARNING:
340                         out = stderr;
341                         break;
342                 case LOG_NOTICE:
343                 case LOG_INFO:
344                 case LOG_DEBUG:
345                         out = stdout;
346                         break;
347                 default:
348                         assert(!"Invalid loglevel.");
349                         abort();        /* XXX: gcc */
350                 }
351
352                 fprintf(out, "[%s]", pjdlog_level_string(loglevel));
353                 /* Attach debuglevel if this is debug log. */
354                 if (loglevel == LOG_DEBUG)
355                         fprintf(out, "[%d]", debuglevel);
356                 fprintf(out, " %s", pjdlog_prefix);
357                 vfprintf(out, fmt, ap);
358                 if (error != -1)
359                         fprintf(out, ": %s.", strerror(error));
360                 fprintf(out, "\n");
361                 fflush(out);
362                 break;
363             }
364         case PJDLOG_MODE_SYSLOG:
365             {
366                 char log[1024];
367                 int len;
368
369                 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
370                 if ((size_t)len < sizeof(log))
371                         len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
372                 if (error != -1 && (size_t)len < sizeof(log)) {
373                         (void)snprintf(log + len, sizeof(log) - len, ": %s.",
374                             strerror(error));
375                 }
376                 syslog(loglevel, "%s", log);
377                 break;
378             }
379         default:
380                 assert(!"Invalid mode.");
381         }
382 }
383
384 /*
385  * Regular logs.
386  */
387 void
388 pjdlogv(int loglevel, const char *fmt, va_list ap)
389 {
390
391         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
392
393         /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
394         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
395             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
396             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
397             loglevel == LOG_INFO);
398
399         pjdlogv_common(loglevel, 0, -1, fmt, ap);
400 }
401
402 /*
403  * Regular logs.
404  */
405 void
406 pjdlog(int loglevel, const char *fmt, ...)
407 {
408         va_list ap;
409
410         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
411
412         va_start(ap, fmt);
413         pjdlogv(loglevel, fmt, ap);
414         va_end(ap);
415 }
416
417 /*
418  * Debug logs.
419  */
420 void
421 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
422 {
423
424         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
425
426         pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
427 }
428
429 /*
430  * Debug logs.
431  */
432 void
433 pjdlog_debug(int debuglevel, const char *fmt, ...)
434 {
435         va_list ap;
436
437         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
438
439         va_start(ap, fmt);
440         pjdlogv_debug(debuglevel, fmt, ap);
441         va_end(ap);
442 }
443
444 /*
445  * Error logs with errno logging.
446  */
447 void
448 pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
449 {
450
451         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
452
453         pjdlogv_common(loglevel, 0, errno, fmt, ap);
454 }
455
456 /*
457  * Error logs with errno logging.
458  */
459 void
460 pjdlog_errno(int loglevel, const char *fmt, ...)
461 {
462         va_list ap;
463
464         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
465
466         va_start(ap, fmt);
467         pjdlogv_errno(loglevel, fmt, ap);
468         va_end(ap);
469 }
470
471 /*
472  * Log error, errno and exit.
473  */
474 void
475 pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
476 {
477
478         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
479
480         pjdlogv_errno(LOG_ERR, fmt, ap);
481         exit(exitcode);
482         /* NOTREACHED */
483 }
484
485 /*
486  * Log error, errno and exit.
487  */
488 void
489 pjdlog_exit(int exitcode, const char *fmt, ...)
490 {
491         va_list ap;
492
493         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
494
495         va_start(ap, fmt);
496         pjdlogv_exit(exitcode, fmt, ap);
497         /* NOTREACHED */
498         va_end(ap);
499 }
500
501 /*
502  * Log error and exit.
503  */
504 void
505 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
506 {
507
508         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
509
510         pjdlogv(LOG_ERR, fmt, ap);
511         exit(exitcode);
512         /* NOTREACHED */
513 }
514
515 /*
516  * Log error and exit.
517  */
518 void
519 pjdlog_exitx(int exitcode, const char *fmt, ...)
520 {
521         va_list ap;
522
523         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
524
525         va_start(ap, fmt);
526         pjdlogv_exitx(exitcode, fmt, ap);
527         /* NOTREACHED */
528         va_end(ap);
529 }
530
531 /*
532  * Log failure message and exit.
533  */
534 void
535 pjdlog_abort(const char *func, const char *file, int line,
536     const char *failedexpr, const char *fmt, ...)
537 {
538         va_list ap;
539
540         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
541
542         /*
543          * When there is no message we pass __func__ as 'fmt'.
544          * It would be cleaner to pass NULL or "", but gcc generates a warning
545          * for both of those.
546          */
547         if (fmt != func) {
548                 va_start(ap, fmt);
549                 pjdlogv_critical(fmt, ap);
550                 va_end(ap);
551         }
552         if (failedexpr == NULL) {
553                 if (func == NULL) {
554                         pjdlog_critical("Aborted at file %s, line %d.", file,
555                             line);
556                 } else {
557                         pjdlog_critical("Aborted at function %s, file %s, line %d.",
558                             func, file, line);
559                 }
560         } else {
561                 if (func == NULL) {
562                         pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
563                             failedexpr, file, line);
564                 } else {
565                         pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
566                             failedexpr, func, file, line);
567                 }
568         }
569         abort();
570 }