2 * Copyright (c) 2009-2010 The FreeBSD Foundation
3 * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
6 * This software was developed by Pawel Jakub Dawidek under sponsorship from
7 * the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
30 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/pjdlog.c#1 $
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
54 #define PJDLOG_NEVER_INITIALIZED 0
55 #define PJDLOG_NOT_INITIALIZED 1
56 #define PJDLOG_INITIALIZED 2
58 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
59 static int pjdlog_mode, pjdlog_debug_level;
60 static char pjdlog_prefix[128];
64 pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
69 argt[0] = PA_INT | PA_FLAG_INTMAX;
74 pjdlog_printf_render_humanized_number(struct __printf_io *io,
75 const struct printf_info *pi, const void * const *arg)
81 num = *(const intmax_t *)arg[0];
82 humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
83 HN_NOSPACE | HN_DECIMAL);
84 ret = __printf_out(io, pi, buf, strlen(buf));
90 pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
100 pjdlog_printf_render_sockaddr(struct __printf_io *io,
101 const struct printf_info *pi, const void * const *arg)
103 const struct sockaddr_storage *ss;
107 ss = *(const struct sockaddr_storage * const *)arg[0];
108 switch (ss->ss_family) {
111 char addr[INET_ADDRSTRLEN];
112 const struct sockaddr_in *sin;
115 sin = (const struct sockaddr_in *)ss;
116 port = ntohs(sin->sin_port);
117 if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
118 sizeof(addr)) == NULL) {
119 PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
122 snprintf(buf, sizeof(buf), "%s:%u", addr, port);
127 char addr[INET6_ADDRSTRLEN];
128 const struct sockaddr_in6 *sin;
131 sin = (const struct sockaddr_in6 *)ss;
132 port = ntohs(sin->sin6_port);
133 if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
134 sizeof(addr)) == NULL) {
135 PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
138 snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
142 snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
146 ret = __printf_out(io, pi, buf, strlen(buf));
150 #endif /* __FreeBSD__ */
153 pjdlog_init(int mode)
157 assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
158 pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
159 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
163 if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
166 register_printf_render_std("T");
167 register_printf_render('N',
168 pjdlog_printf_render_humanized_number,
169 pjdlog_printf_arginfo_humanized_number);
170 register_printf_render('S',
171 pjdlog_printf_render_sockaddr,
172 pjdlog_printf_arginfo_sockaddr);
176 if (mode == PJDLOG_MODE_SYSLOG)
177 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
179 pjdlog_debug_level = 0;
180 bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
182 pjdlog_initialized = PJDLOG_INITIALIZED;
192 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
196 if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
199 pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
205 * Configure where the logs should go.
206 * By default they are send to stdout/stderr, but after going into background
207 * (eg. by calling daemon(3)) application is responsible for changing mode to
208 * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
211 pjdlog_mode_set(int mode)
215 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
216 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
218 if (pjdlog_mode == mode)
223 if (mode == PJDLOG_MODE_SYSLOG)
224 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
225 else /* if (mode == PJDLOG_MODE_STD) */
234 * Return current mode.
237 pjdlog_mode_get(void)
240 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
242 return (pjdlog_mode);
246 * Set debug level. All the logs above the level specified here will be
250 pjdlog_debug_set(int level)
253 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
256 pjdlog_debug_level = level;
260 * Return current debug level.
263 pjdlog_debug_get(void)
266 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
268 return (pjdlog_debug_level);
272 * Set prefix that will be used before each log.
273 * Setting prefix to NULL will remove it.
276 pjdlog_prefix_set(const char *fmt, ...)
280 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
283 pjdlogv_prefix_set(fmt, ap);
288 * Set prefix that will be used before each log.
289 * Setting prefix to NULL will remove it.
292 pjdlogv_prefix_set(const char *fmt, va_list ap)
296 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
301 vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
307 * Convert log level into string.
310 pjdlog_level_string(int loglevel)
331 assert(!"Invalid log level.");
332 abort(); /* XXX: gcc */
336 * Common log routine.
339 pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
343 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
346 pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
351 * Common log routine, which can handle regular log level as well as debug
352 * level. We decide here where to send the logs (stdout/stderr or syslog).
355 pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
360 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
361 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
362 loglevel == LOG_CRIT || loglevel == LOG_ERR ||
363 loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
364 loglevel == LOG_INFO || loglevel == LOG_DEBUG);
365 assert(loglevel != LOG_DEBUG || debuglevel > 0);
368 /* Ignore debug above configured level. */
369 if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
374 switch (pjdlog_mode) {
375 case PJDLOG_MODE_STD:
380 * We send errors and warning to stderr and the rest to stdout.
396 assert(!"Invalid loglevel.");
397 abort(); /* XXX: gcc */
400 fprintf(out, "(%d) ", getpid());
401 fprintf(out, "[%s]", pjdlog_level_string(loglevel));
402 /* Attach debuglevel if this is debug log. */
403 if (loglevel == LOG_DEBUG)
404 fprintf(out, "[%d]", debuglevel);
405 fprintf(out, " %s", pjdlog_prefix);
406 vfprintf(out, fmt, ap);
408 fprintf(out, ": %s.", strerror(error));
413 case PJDLOG_MODE_SYSLOG:
418 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
419 if ((size_t)len < sizeof(log))
420 len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
421 if (error != -1 && (size_t)len < sizeof(log)) {
422 (void)snprintf(log + len, sizeof(log) - len, ": %s.",
425 syslog(loglevel, "%s", log);
429 assert(!"Invalid mode.");
439 pjdlogv(int loglevel, const char *fmt, va_list ap)
442 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
444 /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
445 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
446 loglevel == LOG_CRIT || loglevel == LOG_ERR ||
447 loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
448 loglevel == LOG_INFO);
450 pjdlogv_common(loglevel, 0, -1, fmt, ap);
457 pjdlog(int loglevel, const char *fmt, ...)
461 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
464 pjdlogv(loglevel, fmt, ap);
472 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
475 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
477 pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
484 pjdlog_debug(int debuglevel, const char *fmt, ...)
488 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
491 pjdlogv_debug(debuglevel, fmt, ap);
496 * Error logs with errno logging.
499 pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
502 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
504 pjdlogv_common(loglevel, 0, errno, fmt, ap);
508 * Error logs with errno logging.
511 pjdlog_errno(int loglevel, const char *fmt, ...)
515 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
518 pjdlogv_errno(loglevel, fmt, ap);
523 * Log error, errno and exit.
526 pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
529 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
531 pjdlogv_errno(LOG_ERR, fmt, ap);
537 * Log error, errno and exit.
540 pjdlog_exit(int exitcode, const char *fmt, ...)
544 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
547 pjdlogv_exit(exitcode, fmt, ap);
553 * Log error and exit.
556 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
559 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
561 pjdlogv(LOG_ERR, fmt, ap);
567 * Log error and exit.
570 pjdlog_exitx(int exitcode, const char *fmt, ...)
574 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
577 pjdlogv_exitx(exitcode, fmt, ap);
583 * Log failure message and exit.
586 pjdlog_abort(const char *func, const char *file, int line,
587 const char *failedexpr, const char *fmt, ...)
591 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
594 * When there is no message we pass __func__ as 'fmt'.
595 * It would be cleaner to pass NULL or "", but gcc generates a warning
600 pjdlogv_critical(fmt, ap);
603 if (failedexpr == NULL) {
605 pjdlog_critical("Aborted at file %s, line %d.", file,
608 pjdlog_critical("Aborted at function %s, file %s, line %d.",
613 pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
614 failedexpr, file, line);
616 pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
617 failedexpr, func, file, line);