]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sbin/hastd/pjdlog.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38
39 #include <assert.h>
40 #include <errno.h>
41 #include <libutil.h>
42 #include <printf.h>
43 #include <stdarg.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <syslog.h>
49
50 #include "pjdlog.h"
51
52 #define PJDLOG_NEVER_INITIALIZED        0
53 #define PJDLOG_NOT_INITIALIZED          1
54 #define PJDLOG_INITIALIZED              2
55
56 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
57 static int pjdlog_mode, pjdlog_debug_level;
58 static char pjdlog_prefix[128];
59
60 static int
61 pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
62     size_t n, int *argt)
63 {
64
65         assert(n >= 1);
66         argt[0] = PA_INT | PA_FLAG_INTMAX;
67         return (1);
68 }
69
70 static int
71 pjdlog_printf_render_humanized_number(struct __printf_io *io,
72     const struct printf_info *pi, const void * const *arg)
73 {
74         char buf[5];
75         intmax_t num;
76         int ret;
77
78         num = *(const intmax_t *)arg[0];
79         humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
80             HN_NOSPACE | HN_DECIMAL);
81         ret = __printf_out(io, pi, buf, strlen(buf));
82         __printf_flush(io);
83         return (ret);
84 }
85
86 static int
87 pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
88     size_t n, int *argt)
89 {
90
91         assert(n >= 1);
92         argt[0] = PA_POINTER;
93         return (1);
94 }
95
96 static int
97 pjdlog_printf_render_sockaddr(struct __printf_io *io,
98     const struct printf_info *pi, const void * const *arg)
99 {
100         const struct sockaddr_storage *ss;
101         char buf[64];
102         int ret;
103
104         ss = *(const struct sockaddr_storage * const *)arg[0];
105         switch (ss->ss_family) {
106         case AF_INET:
107             {
108                 char addr[INET_ADDRSTRLEN];
109                 const struct sockaddr_in *sin;
110                 unsigned int port;
111
112                 sin = (const struct sockaddr_in *)ss;
113                 port = ntohs(sin->sin_port);
114                 if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
115                     sizeof(addr)) == NULL) {
116                         PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
117                             strerror(errno));
118                 }
119                 snprintf(buf, sizeof(buf), "%s:%u", addr, port);
120                 break;
121             }
122         case AF_INET6:
123             {
124                 char addr[INET6_ADDRSTRLEN];
125                 const struct sockaddr_in6 *sin;
126                 unsigned int port;
127
128                 sin = (const struct sockaddr_in6 *)ss;
129                 port = ntohs(sin->sin6_port);
130                 if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
131                     sizeof(addr)) == NULL) {
132                         PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
133                             strerror(errno));
134                 }
135                 snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
136                 break;
137             }
138         default:
139                 snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
140                     ss->ss_family);
141                 break;
142         }
143         ret = __printf_out(io, pi, buf, strlen(buf));
144         __printf_flush(io);
145         return (ret);
146 }
147
148 void
149 pjdlog_init(int mode)
150 {
151         int saved_errno;
152
153         assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
154             pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
155         assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
156
157         saved_errno = errno;
158
159         if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
160                 __use_xprintf = 1;
161                 register_printf_render_std("T");
162                 register_printf_render('N',
163                     pjdlog_printf_render_humanized_number,
164                     pjdlog_printf_arginfo_humanized_number);
165                 register_printf_render('S',
166                     pjdlog_printf_render_sockaddr,
167                     pjdlog_printf_arginfo_sockaddr);
168         }
169
170         if (mode == PJDLOG_MODE_SYSLOG)
171                 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
172         pjdlog_mode = mode;
173         pjdlog_debug_level = 0;
174         bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
175
176         pjdlog_initialized = PJDLOG_INITIALIZED;
177
178         errno = saved_errno;
179 }
180
181 void
182 pjdlog_fini(void)
183 {
184         int saved_errno;
185
186         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
187
188         saved_errno = errno;
189
190         if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
191                 closelog();
192
193         pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
194
195         errno = saved_errno;
196 }
197
198 /*
199  * Configure where the logs should go.
200  * By default they are send to stdout/stderr, but after going into background
201  * (eg. by calling daemon(3)) application is responsible for changing mode to
202  * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
203  */
204 void
205 pjdlog_mode_set(int mode)
206 {
207         int saved_errno;
208
209         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
210         assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
211
212         if (pjdlog_mode == mode)
213                 return;
214
215         saved_errno = errno;
216
217         if (mode == PJDLOG_MODE_SYSLOG)
218                 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
219         else /* if (mode == PJDLOG_MODE_STD) */
220                 closelog();
221
222         pjdlog_mode = mode;
223
224         errno = saved_errno;
225 }
226
227 /*
228  * Return current mode.
229  */
230 int
231 pjdlog_mode_get(void)
232 {
233
234         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
235
236         return (pjdlog_mode);
237 }
238
239 /*
240  * Set debug level. All the logs above the level specified here will be
241  * ignored.
242  */
243 void
244 pjdlog_debug_set(int level)
245 {
246
247         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
248         assert(level >= 0);
249
250         pjdlog_debug_level = level;
251 }
252
253 /*
254  * Return current debug level.
255  */
256 int
257 pjdlog_debug_get(void)
258 {
259
260         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
261
262         return (pjdlog_debug_level);
263 }
264
265 /*
266  * Set prefix that will be used before each log.
267  * Setting prefix to NULL will remove it.
268  */
269 void
270 pjdlog_prefix_set(const char *fmt, ...)
271 {
272         va_list ap;
273
274         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
275
276         va_start(ap, fmt);
277         pjdlogv_prefix_set(fmt, ap);
278         va_end(ap);
279 }
280
281 /*
282  * Set prefix that will be used before each log.
283  * Setting prefix to NULL will remove it.
284  */
285 void
286 pjdlogv_prefix_set(const char *fmt, va_list ap)
287 {
288         int saved_errno;
289
290         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
291         assert(fmt != NULL);
292
293         saved_errno = errno;
294
295         vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
296
297         errno = saved_errno;
298 }
299
300 /*
301  * Convert log level into string.
302  */
303 static const char *
304 pjdlog_level_string(int loglevel)
305 {
306
307         switch (loglevel) {
308         case LOG_EMERG:
309                 return ("EMERG");
310         case LOG_ALERT:
311                 return ("ALERT");
312         case LOG_CRIT:
313                 return ("CRIT");
314         case LOG_ERR:
315                 return ("ERROR");
316         case LOG_WARNING:
317                 return ("WARNING");
318         case LOG_NOTICE:
319                 return ("NOTICE");
320         case LOG_INFO:
321                 return ("INFO");
322         case LOG_DEBUG:
323                 return ("DEBUG");
324         }
325         assert(!"Invalid log level.");
326         abort();        /* XXX: gcc */
327 }
328
329 /*
330  * Common log routine.
331  */
332 void
333 pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
334 {
335         va_list ap;
336
337         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
338
339         va_start(ap, fmt);
340         pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
341         va_end(ap);
342 }
343
344 /*
345  * Common log routine, which can handle regular log level as well as debug
346  * level. We decide here where to send the logs (stdout/stderr or syslog).
347  */
348 void
349 pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
350     va_list ap)
351 {
352         int saved_errno;
353
354         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
355         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
356             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
357             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
358             loglevel == LOG_INFO || loglevel == LOG_DEBUG);
359         assert(loglevel != LOG_DEBUG || debuglevel > 0);
360         assert(error >= -1);
361
362         /* Ignore debug above configured level. */
363         if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
364                 return;
365
366         saved_errno = errno;
367
368         switch (pjdlog_mode) {
369         case PJDLOG_MODE_STD:
370             {
371                 FILE *out;
372
373                 /*
374                  * We send errors and warning to stderr and the rest to stdout.
375                  */
376                 switch (loglevel) {
377                 case LOG_EMERG:
378                 case LOG_ALERT:
379                 case LOG_CRIT:
380                 case LOG_ERR:
381                 case LOG_WARNING:
382                         out = stderr;
383                         break;
384                 case LOG_NOTICE:
385                 case LOG_INFO:
386                 case LOG_DEBUG:
387                         out = stdout;
388                         break;
389                 default:
390                         assert(!"Invalid loglevel.");
391                         abort();        /* XXX: gcc */
392                 }
393
394                 fprintf(out, "[%s]", pjdlog_level_string(loglevel));
395                 /* Attach debuglevel if this is debug log. */
396                 if (loglevel == LOG_DEBUG)
397                         fprintf(out, "[%d]", debuglevel);
398                 fprintf(out, " %s", pjdlog_prefix);
399                 vfprintf(out, fmt, ap);
400                 if (error != -1)
401                         fprintf(out, ": %s.", strerror(error));
402                 fprintf(out, "\n");
403                 fflush(out);
404                 break;
405             }
406         case PJDLOG_MODE_SYSLOG:
407             {
408                 char log[1024];
409                 int len;
410
411                 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
412                 if ((size_t)len < sizeof(log))
413                         len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
414                 if (error != -1 && (size_t)len < sizeof(log)) {
415                         (void)snprintf(log + len, sizeof(log) - len, ": %s.",
416                             strerror(error));
417                 }
418                 syslog(loglevel, "%s", log);
419                 break;
420             }
421         default:
422                 assert(!"Invalid mode.");
423         }
424
425         errno = saved_errno;
426 }
427
428 /*
429  * Regular logs.
430  */
431 void
432 pjdlogv(int loglevel, const char *fmt, va_list ap)
433 {
434
435         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
436
437         /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
438         assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
439             loglevel == LOG_CRIT || loglevel == LOG_ERR ||
440             loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
441             loglevel == LOG_INFO);
442
443         pjdlogv_common(loglevel, 0, -1, fmt, ap);
444 }
445
446 /*
447  * Regular logs.
448  */
449 void
450 pjdlog(int loglevel, const char *fmt, ...)
451 {
452         va_list ap;
453
454         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
455
456         va_start(ap, fmt);
457         pjdlogv(loglevel, fmt, ap);
458         va_end(ap);
459 }
460
461 /*
462  * Debug logs.
463  */
464 void
465 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
466 {
467
468         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
469
470         pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
471 }
472
473 /*
474  * Debug logs.
475  */
476 void
477 pjdlog_debug(int debuglevel, const char *fmt, ...)
478 {
479         va_list ap;
480
481         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
482
483         va_start(ap, fmt);
484         pjdlogv_debug(debuglevel, fmt, ap);
485         va_end(ap);
486 }
487
488 /*
489  * Error logs with errno logging.
490  */
491 void
492 pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
493 {
494
495         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
496
497         pjdlogv_common(loglevel, 0, errno, fmt, ap);
498 }
499
500 /*
501  * Error logs with errno logging.
502  */
503 void
504 pjdlog_errno(int loglevel, const char *fmt, ...)
505 {
506         va_list ap;
507
508         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
509
510         va_start(ap, fmt);
511         pjdlogv_errno(loglevel, fmt, ap);
512         va_end(ap);
513 }
514
515 /*
516  * Log error, errno and exit.
517  */
518 void
519 pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
520 {
521
522         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
523
524         pjdlogv_errno(LOG_ERR, fmt, ap);
525         exit(exitcode);
526         /* NOTREACHED */
527 }
528
529 /*
530  * Log error, errno and exit.
531  */
532 void
533 pjdlog_exit(int exitcode, const char *fmt, ...)
534 {
535         va_list ap;
536
537         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
538
539         va_start(ap, fmt);
540         pjdlogv_exit(exitcode, fmt, ap);
541         /* NOTREACHED */
542         va_end(ap);
543 }
544
545 /*
546  * Log error and exit.
547  */
548 void
549 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
550 {
551
552         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
553
554         pjdlogv(LOG_ERR, fmt, ap);
555         exit(exitcode);
556         /* NOTREACHED */
557 }
558
559 /*
560  * Log error and exit.
561  */
562 void
563 pjdlog_exitx(int exitcode, const char *fmt, ...)
564 {
565         va_list ap;
566
567         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
568
569         va_start(ap, fmt);
570         pjdlogv_exitx(exitcode, fmt, ap);
571         /* NOTREACHED */
572         va_end(ap);
573 }
574
575 /*
576  * Log failure message and exit.
577  */
578 void
579 pjdlog_abort(const char *func, const char *file, int line,
580     const char *failedexpr, const char *fmt, ...)
581 {
582         va_list ap;
583
584         assert(pjdlog_initialized == PJDLOG_INITIALIZED);
585
586         /*
587          * When there is no message we pass __func__ as 'fmt'.
588          * It would be cleaner to pass NULL or "", but gcc generates a warning
589          * for both of those.
590          */
591         if (fmt != func) {
592                 va_start(ap, fmt);
593                 pjdlogv_critical(fmt, ap);
594                 va_end(ap);
595         }
596         if (failedexpr == NULL) {
597                 if (func == NULL) {
598                         pjdlog_critical("Aborted at file %s, line %d.", file,
599                             line);
600                 } else {
601                         pjdlog_critical("Aborted at function %s, file %s, line %d.",
602                             func, file, line);
603                 }
604         } else {
605                 if (func == NULL) {
606                         pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
607                             failedexpr, file, line);
608                 } else {
609                         pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
610                             failedexpr, func, file, line);
611                 }
612         }
613         abort();
614 }