2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
8 * This software was developed by Pawel Jakub Dawidek under sponsorship from
9 * the FreeBSD Foundation.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/types.h>
37 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
62 #define MAX(a, b) ((a) > (b) ? (a) : (b))
65 #define PJDLOG_MAX_MSGSIZE 4096
67 #define PJDLOG_PREFIX_STACK 4
68 #define PJDLOG_PREFIX_MAXSIZE 128
70 #define PJDLOG_NEVER_INITIALIZED 0
71 #define PJDLOG_NOT_INITIALIZED 1
72 #define PJDLOG_INITIALIZED 2
74 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
75 static int pjdlog_mode, pjdlog_debug_level, pjdlog_sock;
76 static int pjdlog_prefix_current;
77 static char pjdlog_prefix[PJDLOG_PREFIX_STACK][PJDLOG_PREFIX_MAXSIZE];
80 pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
85 argt[0] = PA_INT | PA_FLAG_INTMAX;
90 pjdlog_printf_render_humanized_number(struct __printf_io *io,
91 const struct printf_info *pi, const void * const *arg)
97 num = *(const intmax_t *)arg[0];
98 humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
99 HN_NOSPACE | HN_DECIMAL);
100 ret = __printf_out(io, pi, buf, strlen(buf));
106 pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
111 argt[0] = PA_POINTER;
116 pjdlog_printf_render_sockaddr_ip(struct __printf_io *io,
117 const struct printf_info *pi, const void * const *arg)
119 const struct sockaddr_storage *ss;
120 char addr[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
123 ss = *(const struct sockaddr_storage * const *)arg[0];
124 switch (ss->ss_family) {
127 const struct sockaddr_in *sin;
129 sin = (const struct sockaddr_in *)ss;
130 if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
131 sizeof(addr)) == NULL) {
132 PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
139 const struct sockaddr_in6 *sin;
141 sin = (const struct sockaddr_in6 *)ss;
142 if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
143 sizeof(addr)) == NULL) {
144 PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
150 snprintf(addr, sizeof(addr), "[unsupported family %hhu]",
154 ret = __printf_out(io, pi, addr, strlen(addr));
160 pjdlog_printf_render_sockaddr(struct __printf_io *io,
161 const struct printf_info *pi, const void * const *arg)
163 const struct sockaddr_storage *ss;
167 ss = *(const struct sockaddr_storage * const *)arg[0];
168 switch (ss->ss_family) {
171 const struct sockaddr_un *sun;
173 sun = (const struct sockaddr_un *)ss;
174 if (sun->sun_path[0] == '\0')
175 snprintf(buf, sizeof(buf), "N/A");
177 snprintf(buf, sizeof(buf), "%s", sun->sun_path);
182 char addr[INET_ADDRSTRLEN];
183 const struct sockaddr_in *sin;
186 sin = (const struct sockaddr_in *)ss;
187 port = ntohs(sin->sin_port);
188 if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
189 sizeof(addr)) == NULL) {
190 PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
193 snprintf(buf, sizeof(buf), "%s:%u", addr, port);
198 char addr[INET6_ADDRSTRLEN];
199 const struct sockaddr_in6 *sin;
202 sin = (const struct sockaddr_in6 *)ss;
203 port = ntohs(sin->sin6_port);
204 if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
205 sizeof(addr)) == NULL) {
206 PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
209 snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
213 snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
217 ret = __printf_out(io, pi, buf, strlen(buf));
223 pjdlog_init(int mode)
227 assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
228 pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
230 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG ||
231 mode == PJDLOG_MODE_SOCK);
233 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
238 if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
240 register_printf_render_std("T");
241 register_printf_render('N',
242 pjdlog_printf_render_humanized_number,
243 pjdlog_printf_arginfo_humanized_number);
244 register_printf_render('I',
245 pjdlog_printf_render_sockaddr_ip,
246 pjdlog_printf_arginfo_sockaddr);
247 register_printf_render('S',
248 pjdlog_printf_render_sockaddr,
249 pjdlog_printf_arginfo_sockaddr);
252 if (mode == PJDLOG_MODE_SYSLOG)
253 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_LOCAL0);
255 pjdlog_debug_level = 0;
256 pjdlog_prefix_current = 0;
257 pjdlog_prefix[0][0] = '\0';
259 pjdlog_initialized = PJDLOG_INITIALIZED;
270 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
274 if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
277 pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
284 * Configure where the logs should go.
285 * By default they are send to stdout/stderr, but after going into background
286 * (eg. by calling daemon(3)) application is responsible for changing mode to
287 * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
290 pjdlog_mode_set(int mode)
294 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
296 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG ||
297 mode == PJDLOG_MODE_SOCK);
299 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
302 if (pjdlog_mode == mode)
307 if (mode == PJDLOG_MODE_SYSLOG)
308 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
309 else if (mode == PJDLOG_MODE_STD)
312 if (mode != PJDLOG_MODE_SOCK)
322 * Return current mode.
325 pjdlog_mode_get(void)
328 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
330 return (pjdlog_mode);
335 * Sets socket number to use for PJDLOG_MODE_SOCK mode.
338 pjdlog_sock_set(int sock)
341 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
342 assert(pjdlog_mode == PJDLOG_MODE_SOCK);
351 * Returns socket number used for PJDLOG_MODE_SOCK mode.
354 pjdlog_sock_get(void)
357 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
358 assert(pjdlog_mode == PJDLOG_MODE_SOCK);
359 assert(pjdlog_sock >= 0);
361 return (pjdlog_sock);
366 * Set debug level. All the logs above the level specified here will be
370 pjdlog_debug_set(int level)
373 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
375 assert(level <= 127);
377 pjdlog_debug_level = level;
381 * Return current debug level.
384 pjdlog_debug_get(void)
387 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
389 return (pjdlog_debug_level);
393 * Set prefix that will be used before each log.
396 pjdlog_prefix_set(const char *fmt, ...)
400 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
403 pjdlogv_prefix_set(fmt, ap);
408 * Set prefix that will be used before each log.
411 pjdlogv_prefix_set(const char *fmt, va_list ap)
415 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
420 vsnprintf(pjdlog_prefix[pjdlog_prefix_current],
421 sizeof(pjdlog_prefix[pjdlog_prefix_current]), fmt, ap);
427 * Get current prefix.
430 pjdlog_prefix_get(void)
433 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
435 return (pjdlog_prefix[pjdlog_prefix_current]);
439 * Set new prefix and put the current one on the stack.
442 pjdlog_prefix_push(const char *fmt, ...)
446 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
449 pjdlogv_prefix_push(fmt, ap);
454 * Set new prefix and put the current one on the stack.
457 pjdlogv_prefix_push(const char *fmt, va_list ap)
460 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
461 assert(pjdlog_prefix_current < PJDLOG_PREFIX_STACK - 1);
463 pjdlog_prefix_current++;
465 pjdlogv_prefix_set(fmt, ap);
469 * Removes current prefix and recovers previous one from the stack.
472 pjdlog_prefix_pop(void)
475 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
476 assert(pjdlog_prefix_current > 0);
478 pjdlog_prefix_current--;
482 * Convert log level into string.
485 pjdlog_level_to_string(int loglevel)
506 assert(!"Invalid log level.");
507 abort(); /* XXX: gcc */
511 vsnprlcat(char *str, size_t size, const char *fmt, va_list ap)
517 return (vsnprintf(str + len, size - len, fmt, ap));
521 snprlcat(char *str, size_t size, const char *fmt, ...)
527 result = vsnprlcat(str, size, fmt, ap);
533 pjdlogv_common_single_line(const char *func, const char *file, int line,
534 int loglevel, int debuglevel, int error, const char *msg)
536 static char log[2 * PJDLOG_MAX_MSGSIZE];
540 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
542 assert(pjdlog_mode == PJDLOG_MODE_STD ||
543 pjdlog_mode == PJDLOG_MODE_SYSLOG ||
544 pjdlog_mode == PJDLOG_MODE_SOCK);
546 assert(pjdlog_mode == PJDLOG_MODE_STD ||
547 pjdlog_mode == PJDLOG_MODE_SYSLOG);
549 assert(pjdlog_mode != PJDLOG_MODE_SOCK || pjdlog_sock >= 0);
550 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
551 loglevel == LOG_CRIT || loglevel == LOG_ERR ||
552 loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
553 loglevel == LOG_INFO || loglevel == LOG_DEBUG);
554 assert(loglevel != LOG_DEBUG || debuglevel > 0);
555 assert(loglevel != LOG_DEBUG || debuglevel <= pjdlog_debug_level);
556 assert(debuglevel <= 127);
558 assert((file != NULL && line > 0) ||
559 (func == NULL && file == NULL && line == 0));
561 switch (pjdlog_mode) {
562 case PJDLOG_MODE_STD:
563 case PJDLOG_MODE_SYSLOG:
567 case PJDLOG_MODE_SOCK:
569 logs = sizeof(log) - 4;
572 assert(!"Invalid mode.");
577 if (pjdlog_mode != PJDLOG_MODE_SOCK) {
578 if (loglevel == LOG_DEBUG) {
579 /* Attach debuglevel if this is debug log. */
580 snprlcat(logp, logs, "[%s%d] ",
581 pjdlog_level_to_string(loglevel), debuglevel);
583 snprlcat(logp, logs, "[%s] ",
584 pjdlog_level_to_string(loglevel));
586 if (pjdlog_mode != PJDLOG_MODE_SYSLOG &&
587 pjdlog_debug_level >= 1) {
588 snprlcat(logp, logs, "(pid=%d) ", getpid());
591 /* Attach file, func, line if debuglevel is 2 or more. */
592 if (pjdlog_debug_level >= 2 && file != NULL) {
594 snprlcat(logp, logs, "(%s:%d) ", file, line);
596 snprlcat(logp, logs, "(%s:%d:%s) ", file, line, func);
599 if (pjdlog_mode != PJDLOG_MODE_SOCK) {
600 snprlcat(logp, logs, "%s",
601 pjdlog_prefix[pjdlog_prefix_current]);
604 strlcat(logp, msg, logs);
606 /* Attach error description. */
608 snprlcat(logp, logs, ": %s.", strerror(error));
610 switch (pjdlog_mode) {
611 case PJDLOG_MODE_STD:
612 fprintf(stderr, "%s\n", logp);
615 case PJDLOG_MODE_SYSLOG:
616 syslog(loglevel, "%s", logp);
619 case PJDLOG_MODE_SOCK:
626 dlen = strlen(logp) + 3; /* +3 = loglevel, debuglevel and terminating \0 */
627 bcopy(&dlen, log, sizeof(dlen));
628 if (robust_send(pjdlog_sock, log, (size_t)dlen + 2) == -1) /* +2 for size */
629 assert(!"Unable to send log.");
630 if (robust_recv(pjdlog_sock, ack, sizeof(ack)) == -1)
631 assert(!"Unable to send log.");
636 assert(!"Invalid mode.");
641 * Common log routine, which can handle regular log level as well as debug
642 * level. We decide here where to send the logs (stdout/stderr or syslog).
645 _pjdlogv_common(const char *func, const char *file, int line, int loglevel,
646 int debuglevel, int error, const char *fmt, va_list ap)
648 char log[PJDLOG_MAX_MSGSIZE];
649 char *logp, *curline;
653 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
654 assert(pjdlog_mode == PJDLOG_MODE_STD ||
655 pjdlog_mode == PJDLOG_MODE_SYSLOG ||
656 pjdlog_mode == PJDLOG_MODE_SOCK);
657 assert(pjdlog_mode != PJDLOG_MODE_SOCK || pjdlog_sock >= 0);
658 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
659 loglevel == LOG_CRIT || loglevel == LOG_ERR ||
660 loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
661 loglevel == LOG_INFO || loglevel == LOG_DEBUG);
662 assert(loglevel != LOG_DEBUG || debuglevel > 0);
663 assert(debuglevel <= 127);
666 /* Ignore debug above configured level. */
667 if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
672 vsnprintf(log, sizeof(log), fmt, ap);
676 while ((curline = strsep(&logp, "\n")) != NULL) {
677 if (*curline == '\0')
679 if (prvline != NULL) {
680 pjdlogv_common_single_line(func, file, line, loglevel,
681 debuglevel, -1, prvline);
687 pjdlogv_common_single_line(func, file, line, loglevel, debuglevel,
694 * Common log routine.
697 _pjdlog_common(const char *func, const char *file, int line, int loglevel,
698 int debuglevel, int error, const char *fmt, ...)
702 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
705 _pjdlogv_common(func, file, line, loglevel, debuglevel, error, fmt, ap);
710 * Log error, errno and exit.
713 _pjdlogv_exit(const char *func, const char *file, int line, int exitcode,
714 int error, const char *fmt, va_list ap)
717 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
719 _pjdlogv_common(func, file, line, exitcode == 0 ? LOG_INFO : LOG_ERR, 0,
726 * Log error, errno and exit.
729 _pjdlog_exit(const char *func, const char *file, int line, int exitcode,
730 int error, const char *fmt, ...)
734 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
737 _pjdlogv_exit(func, file, line, exitcode, error, fmt, ap);
743 * Log failure message and exit.
746 _pjdlog_abort(const char *func, const char *file, int line,
747 int error, const char *failedexpr, const char *fmt, ...)
751 assert(pjdlog_initialized == PJDLOG_INITIALIZED);
754 * Set pjdlog_debug_level to 2, so that file, line and func are
755 * included in log. This is fine as we will exit anyway.
757 if (pjdlog_debug_level < 2)
758 pjdlog_debug_level = 2;
761 * When there is no message we pass __func__ as 'fmt'.
762 * It would be cleaner to pass NULL or "", but gcc generates a warning
767 _pjdlogv_common(func, file, line, LOG_CRIT, 0, -1, fmt, ap);
770 if (failedexpr == NULL) {
771 _pjdlog_common(func, file, line, LOG_CRIT, 0, -1, "Aborted.");
773 _pjdlog_common(func, file, line, LOG_CRIT, 0, -1,
774 "Assertion failed: (%s).", failedexpr);
777 _pjdlog_common(func, file, line, LOG_CRIT, 0, error, "Errno");
783 * Receive log from the given socket.
786 pjdlog_receive(int sock)
788 char log[PJDLOG_MAX_MSGSIZE];
789 int loglevel, debuglevel;
792 if (robust_recv(sock, &dlen, sizeof(dlen)) == -1)
795 PJDLOG_ASSERT(dlen > 0);
796 PJDLOG_ASSERT(dlen <= PJDLOG_MAX_MSGSIZE - 3);
798 if (robust_recv(sock, log, (size_t)dlen) == -1)
801 log[dlen - 1] = '\0';
804 _pjdlog_common(NULL, NULL, 0, loglevel, debuglevel, -1, "%s", log + 2);
806 if (robust_send(sock, "ok", 2) == -1)