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
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/types.h>
35 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
60 #define MAX(a, b) ((a) > (b) ? (a) : (b))
63 #define PJDLOG_MAX_MSGSIZE 4096
65 #define PJDLOG_PREFIX_STACK 4
66 #define PJDLOG_PREFIX_MAXSIZE 128
68 #define PJDLOG_NEVER_INITIALIZED 0
69 #define PJDLOG_NOT_INITIALIZED 1
70 #define PJDLOG_INITIALIZED 2
72 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
73 static int pjdlog_mode, pjdlog_debug_level, pjdlog_sock;
74 static int pjdlog_prefix_current;
75 static char pjdlog_prefix[PJDLOG_PREFIX_STACK][PJDLOG_PREFIX_MAXSIZE];
78 pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
83 argt[0] = PA_INT | PA_FLAG_INTMAX;
88 pjdlog_printf_render_humanized_number(struct __printf_io *io,
89 const struct printf_info *pi, const void * const *arg)
95 num = *(const intmax_t *)arg[0];
96 humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
97 HN_NOSPACE | HN_DECIMAL);
98 ret = __printf_out(io, pi, buf, strlen(buf));
104 pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
109 argt[0] = PA_POINTER;
114 pjdlog_printf_render_sockaddr_ip(struct __printf_io *io,
115 const struct printf_info *pi, const void * const *arg)
117 const struct sockaddr_storage *ss;
118 char addr[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
121 ss = *(const struct sockaddr_storage * const *)arg[0];
122 switch (ss->ss_family) {
125 const struct sockaddr_in *sin;
127 sin = (const struct sockaddr_in *)ss;
128 if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
129 sizeof(addr)) == NULL) {
130 PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
137 const struct sockaddr_in6 *sin;
139 sin = (const struct sockaddr_in6 *)ss;
140 if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
141 sizeof(addr)) == NULL) {
142 PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
148 snprintf(addr, sizeof(addr), "[unsupported family %hhu]",
152 ret = __printf_out(io, pi, addr, strlen(addr));
158 pjdlog_printf_render_sockaddr(struct __printf_io *io,
159 const struct printf_info *pi, const void * const *arg)
161 const struct sockaddr_storage *ss;
165 ss = *(const struct sockaddr_storage * const *)arg[0];
166 switch (ss->ss_family) {
169 const struct sockaddr_un *sun;
171 sun = (const struct sockaddr_un *)ss;
172 if (sun->sun_path[0] == '\0')
173 snprintf(buf, sizeof(buf), "N/A");
175 snprintf(buf, sizeof(buf), "%s", sun->sun_path);
180 char addr[INET_ADDRSTRLEN];
181 const struct sockaddr_in *sin;
184 sin = (const struct sockaddr_in *)ss;
185 port = ntohs(sin->sin_port);
186 if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
187 sizeof(addr)) == NULL) {
188 PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
191 snprintf(buf, sizeof(buf), "%s:%u", addr, port);
196 char addr[INET6_ADDRSTRLEN];
197 const struct sockaddr_in6 *sin;
200 sin = (const struct sockaddr_in6 *)ss;
201 port = ntohs(sin->sin6_port);
202 if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
203 sizeof(addr)) == NULL) {
204 PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
207 snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
211 snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
215 ret = __printf_out(io, pi, buf, strlen(buf));
221 pjdlog_init(int mode)
225 assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
226 pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
228 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG ||
229 mode == PJDLOG_MODE_SOCK);
231 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
236 if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
238 register_printf_render_std("T");
239 register_printf_render('N',
240 pjdlog_printf_render_humanized_number,
241 pjdlog_printf_arginfo_humanized_number);
242 register_printf_render('I',
243 pjdlog_printf_render_sockaddr_ip,
244 pjdlog_printf_arginfo_sockaddr);
245 register_printf_render('S',
246 pjdlog_printf_render_sockaddr,
247 pjdlog_printf_arginfo_sockaddr);
250 if (mode == PJDLOG_MODE_SYSLOG)
251 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_LOCAL0);
253 pjdlog_debug_level = 0;
254 pjdlog_prefix_current = 0;
255 pjdlog_prefix[0][0] = '\0';
257 pjdlog_initialized = PJDLOG_INITIALIZED;
268 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
272 if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
275 pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
282 * Configure where the logs should go.
283 * By default they are send to stdout/stderr, but after going into background
284 * (eg. by calling daemon(3)) application is responsible for changing mode to
285 * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
288 pjdlog_mode_set(int mode)
292 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
294 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG ||
295 mode == PJDLOG_MODE_SOCK);
297 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
300 if (pjdlog_mode == mode)
305 if (mode == PJDLOG_MODE_SYSLOG)
306 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
307 else if (mode == PJDLOG_MODE_STD)
310 if (mode != PJDLOG_MODE_SOCK)
320 * Return current mode.
323 pjdlog_mode_get(void)
326 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
328 return (pjdlog_mode);
333 * Sets socket number to use for PJDLOG_MODE_SOCK mode.
336 pjdlog_sock_set(int sock)
339 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
340 assert(pjdlog_mode == PJDLOG_MODE_SOCK);
349 * Returns socket number used for PJDLOG_MODE_SOCK mode.
352 pjdlog_sock_get(void)
355 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
356 assert(pjdlog_mode == PJDLOG_MODE_SOCK);
357 assert(pjdlog_sock >= 0);
359 return (pjdlog_sock);
364 * Set debug level. All the logs above the level specified here will be
368 pjdlog_debug_set(int level)
371 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
373 assert(level <= 127);
375 pjdlog_debug_level = level;
379 * Return current debug level.
382 pjdlog_debug_get(void)
385 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
387 return (pjdlog_debug_level);
391 * Set prefix that will be used before each log.
394 pjdlog_prefix_set(const char *fmt, ...)
398 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
401 pjdlogv_prefix_set(fmt, ap);
406 * Set prefix that will be used before each log.
409 pjdlogv_prefix_set(const char *fmt, va_list ap)
413 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
418 vsnprintf(pjdlog_prefix[pjdlog_prefix_current],
419 sizeof(pjdlog_prefix[pjdlog_prefix_current]), fmt, ap);
425 * Get current prefix.
428 pjdlog_prefix_get(void)
431 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
433 return (pjdlog_prefix[pjdlog_prefix_current]);
437 * Set new prefix and put the current one on the stack.
440 pjdlog_prefix_push(const char *fmt, ...)
444 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
447 pjdlogv_prefix_push(fmt, ap);
452 * Set new prefix and put the current one on the stack.
455 pjdlogv_prefix_push(const char *fmt, va_list ap)
458 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
459 assert(pjdlog_prefix_current < PJDLOG_PREFIX_STACK - 1);
461 pjdlog_prefix_current++;
463 pjdlogv_prefix_set(fmt, ap);
467 * Removes current prefix and recovers previous one from the stack.
470 pjdlog_prefix_pop(void)
473 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
474 assert(pjdlog_prefix_current > 0);
476 pjdlog_prefix_current--;
480 * Convert log level into string.
483 pjdlog_level_to_string(int loglevel)
504 assert(!"Invalid log level.");
505 abort(); /* XXX: gcc */
509 vsnprlcat(char *str, size_t size, const char *fmt, va_list ap)
515 return (vsnprintf(str + len, size - len, fmt, ap));
519 snprlcat(char *str, size_t size, const char *fmt, ...)
525 result = vsnprlcat(str, size, fmt, ap);
531 pjdlogv_common_single_line(const char *func, const char *file, int line,
532 int loglevel, int debuglevel, int error, const char *msg)
534 static char log[2 * PJDLOG_MAX_MSGSIZE];
538 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
540 assert(pjdlog_mode == PJDLOG_MODE_STD ||
541 pjdlog_mode == PJDLOG_MODE_SYSLOG ||
542 pjdlog_mode == PJDLOG_MODE_SOCK);
544 assert(pjdlog_mode == PJDLOG_MODE_STD ||
545 pjdlog_mode == PJDLOG_MODE_SYSLOG);
547 assert(pjdlog_mode != PJDLOG_MODE_SOCK || pjdlog_sock >= 0);
548 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
549 loglevel == LOG_CRIT || loglevel == LOG_ERR ||
550 loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
551 loglevel == LOG_INFO || loglevel == LOG_DEBUG);
552 assert(loglevel != LOG_DEBUG || debuglevel > 0);
553 assert(loglevel != LOG_DEBUG || debuglevel <= pjdlog_debug_level);
554 assert(debuglevel <= 127);
556 assert((file != NULL && line > 0) ||
557 (func == NULL && file == NULL && line == 0));
559 switch (pjdlog_mode) {
560 case PJDLOG_MODE_STD:
561 case PJDLOG_MODE_SYSLOG:
565 case PJDLOG_MODE_SOCK:
567 logs = sizeof(log) - 4;
570 assert(!"Invalid mode.");
575 if (pjdlog_mode != PJDLOG_MODE_SOCK) {
576 if (loglevel == LOG_DEBUG) {
577 /* Attach debuglevel if this is debug log. */
578 snprlcat(logp, logs, "[%s%d] ",
579 pjdlog_level_to_string(loglevel), debuglevel);
581 snprlcat(logp, logs, "[%s] ",
582 pjdlog_level_to_string(loglevel));
584 if (pjdlog_mode != PJDLOG_MODE_SYSLOG &&
585 pjdlog_debug_level >= 1) {
586 snprlcat(logp, logs, "(pid=%d) ", getpid());
589 /* Attach file, func, line if debuglevel is 2 or more. */
590 if (pjdlog_debug_level >= 2 && file != NULL) {
592 snprlcat(logp, logs, "(%s:%d) ", file, line);
594 snprlcat(logp, logs, "(%s:%d:%s) ", file, line, func);
597 if (pjdlog_mode != PJDLOG_MODE_SOCK) {
598 snprlcat(logp, logs, "%s",
599 pjdlog_prefix[pjdlog_prefix_current]);
602 strlcat(logp, msg, logs);
604 /* Attach error description. */
606 snprlcat(logp, logs, ": %s.", strerror(error));
608 switch (pjdlog_mode) {
609 case PJDLOG_MODE_STD:
610 fprintf(stderr, "%s\n", logp);
613 case PJDLOG_MODE_SYSLOG:
614 syslog(loglevel, "%s", logp);
617 case PJDLOG_MODE_SOCK:
624 dlen = strlen(logp) + 3; /* +3 = loglevel, debuglevel and terminating \0 */
625 bcopy(&dlen, log, sizeof(dlen));
626 if (robust_send(pjdlog_sock, log, (size_t)dlen + 2) == -1) /* +2 for size */
627 assert(!"Unable to send log.");
628 if (robust_recv(pjdlog_sock, ack, sizeof(ack)) == -1)
629 assert(!"Unable to send log.");
634 assert(!"Invalid mode.");
639 * Common log routine, which can handle regular log level as well as debug
640 * level. We decide here where to send the logs (stdout/stderr or syslog).
643 _pjdlogv_common(const char *func, const char *file, int line, int loglevel,
644 int debuglevel, int error, const char *fmt, va_list ap)
646 char log[PJDLOG_MAX_MSGSIZE];
647 char *logp, *curline;
651 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
652 assert(pjdlog_mode == PJDLOG_MODE_STD ||
653 pjdlog_mode == PJDLOG_MODE_SYSLOG ||
654 pjdlog_mode == PJDLOG_MODE_SOCK);
655 assert(pjdlog_mode != PJDLOG_MODE_SOCK || pjdlog_sock >= 0);
656 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
657 loglevel == LOG_CRIT || loglevel == LOG_ERR ||
658 loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
659 loglevel == LOG_INFO || loglevel == LOG_DEBUG);
660 assert(loglevel != LOG_DEBUG || debuglevel > 0);
661 assert(debuglevel <= 127);
664 /* Ignore debug above configured level. */
665 if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
670 vsnprintf(log, sizeof(log), fmt, ap);
674 while ((curline = strsep(&logp, "\n")) != NULL) {
675 if (*curline == '\0')
677 if (prvline != NULL) {
678 pjdlogv_common_single_line(func, file, line, loglevel,
679 debuglevel, -1, prvline);
685 pjdlogv_common_single_line(func, file, line, loglevel, debuglevel,
692 * Common log routine.
695 _pjdlog_common(const char *func, const char *file, int line, int loglevel,
696 int debuglevel, int error, const char *fmt, ...)
700 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
703 _pjdlogv_common(func, file, line, loglevel, debuglevel, error, fmt, ap);
708 * Log error, errno and exit.
711 _pjdlogv_exit(const char *func, const char *file, int line, int exitcode,
712 int error, const char *fmt, va_list ap)
715 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
717 _pjdlogv_common(func, file, line, exitcode == 0 ? LOG_INFO : LOG_ERR, 0,
724 * Log error, errno and exit.
727 _pjdlog_exit(const char *func, const char *file, int line, int exitcode,
728 int error, const char *fmt, ...)
732 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
735 _pjdlogv_exit(func, file, line, exitcode, error, fmt, ap);
741 * Log failure message and exit.
744 _pjdlog_abort(const char *func, const char *file, int line,
745 int error, const char *failedexpr, const char *fmt, ...)
749 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
752 * Set pjdlog_debug_level to 2, so that file, line and func are
753 * included in log. This is fine as we will exit anyway.
755 if (pjdlog_debug_level < 2)
756 pjdlog_debug_level = 2;
759 * When there is no message we pass __func__ as 'fmt'.
760 * It would be cleaner to pass NULL or "", but gcc generates a warning
765 _pjdlogv_common(func, file, line, LOG_CRIT, 0, -1, fmt, ap);
768 if (failedexpr == NULL) {
769 _pjdlog_common(func, file, line, LOG_CRIT, 0, -1, "Aborted.");
771 _pjdlog_common(func, file, line, LOG_CRIT, 0, -1,
772 "Assertion failed: (%s).", failedexpr);
775 _pjdlog_common(func, file, line, LOG_CRIT, 0, error, "Errno");
781 * Receive log from the given socket.
784 pjdlog_receive(int sock)
786 char log[PJDLOG_MAX_MSGSIZE];
787 int loglevel, debuglevel;
790 if (robust_recv(sock, &dlen, sizeof(dlen)) == -1)
793 PJDLOG_ASSERT(dlen > 0);
794 PJDLOG_ASSERT(dlen <= PJDLOG_MAX_MSGSIZE - 3);
796 if (robust_recv(sock, log, (size_t)dlen) == -1)
799 log[dlen - 1] = '\0';
802 _pjdlog_common(NULL, NULL, 0, loglevel, debuglevel, -1, "%s", log + 2);
804 if (robust_send(sock, "ok", 2) == -1)