12f02600aSPawel Jakub Dawidek /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni *
42f02600aSPawel Jakub Dawidek * Copyright (c) 2009-2010 The FreeBSD Foundation
52f02600aSPawel Jakub Dawidek * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
62f02600aSPawel Jakub Dawidek * All rights reserved.
72f02600aSPawel Jakub Dawidek *
82f02600aSPawel Jakub Dawidek * This software was developed by Pawel Jakub Dawidek under sponsorship from
92f02600aSPawel Jakub Dawidek * the FreeBSD Foundation.
102f02600aSPawel Jakub Dawidek *
112f02600aSPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without
122f02600aSPawel Jakub Dawidek * modification, are permitted provided that the following conditions
132f02600aSPawel Jakub Dawidek * are met:
142f02600aSPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright
152f02600aSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer.
162f02600aSPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright
172f02600aSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the
182f02600aSPawel Jakub Dawidek * documentation and/or other materials provided with the distribution.
192f02600aSPawel Jakub Dawidek *
202f02600aSPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
212f02600aSPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
222f02600aSPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
232f02600aSPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
242f02600aSPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
252f02600aSPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
262f02600aSPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
272f02600aSPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
282f02600aSPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
292f02600aSPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
302f02600aSPawel Jakub Dawidek * SUCH DAMAGE.
312f02600aSPawel Jakub Dawidek */
322f02600aSPawel Jakub Dawidek
332f02600aSPawel Jakub Dawidek #include <sys/types.h>
342f02600aSPawel Jakub Dawidek #include <sys/socket.h>
352f02600aSPawel Jakub Dawidek #include <sys/un.h>
362f02600aSPawel Jakub Dawidek #include <netinet/in.h>
372f02600aSPawel Jakub Dawidek #include <arpa/inet.h>
382f02600aSPawel Jakub Dawidek
392f02600aSPawel Jakub Dawidek #include <assert.h>
402f02600aSPawel Jakub Dawidek #include <errno.h>
412f02600aSPawel Jakub Dawidek #include <libutil.h>
422f02600aSPawel Jakub Dawidek #include <limits.h>
43ab40f58cSRuslan Bukin #include <printf.h>
447d729cedSRuslan Bukin #include <stdarg.h>
452f02600aSPawel Jakub Dawidek #include <stdint.h>
462f02600aSPawel Jakub Dawidek #include <stdio.h>
472f02600aSPawel Jakub Dawidek #include <stdlib.h>
482f02600aSPawel Jakub Dawidek #include <string.h>
492f02600aSPawel Jakub Dawidek #include <syslog.h>
502f02600aSPawel Jakub Dawidek #include <unistd.h>
512f02600aSPawel Jakub Dawidek
522f02600aSPawel Jakub Dawidek #ifdef notyet
532f02600aSPawel Jakub Dawidek #include <robustio.h>
542f02600aSPawel Jakub Dawidek #endif
552f02600aSPawel Jakub Dawidek
562f02600aSPawel Jakub Dawidek #include "pjdlog.h"
572f02600aSPawel Jakub Dawidek
582f02600aSPawel Jakub Dawidek #ifndef MAX
592f02600aSPawel Jakub Dawidek #define MAX(a, b) ((a) > (b) ? (a) : (b))
602f02600aSPawel Jakub Dawidek #endif
612f02600aSPawel Jakub Dawidek
622f02600aSPawel Jakub Dawidek #define PJDLOG_MAX_MSGSIZE 4096
632f02600aSPawel Jakub Dawidek
642f02600aSPawel Jakub Dawidek #define PJDLOG_PREFIX_STACK 4
652f02600aSPawel Jakub Dawidek #define PJDLOG_PREFIX_MAXSIZE 128
662f02600aSPawel Jakub Dawidek
672f02600aSPawel Jakub Dawidek #define PJDLOG_NEVER_INITIALIZED 0
682f02600aSPawel Jakub Dawidek #define PJDLOG_NOT_INITIALIZED 1
692f02600aSPawel Jakub Dawidek #define PJDLOG_INITIALIZED 2
702f02600aSPawel Jakub Dawidek
712f02600aSPawel Jakub Dawidek static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
722f02600aSPawel Jakub Dawidek static int pjdlog_mode, pjdlog_debug_level, pjdlog_sock;
732f02600aSPawel Jakub Dawidek static int pjdlog_prefix_current;
742f02600aSPawel Jakub Dawidek static char pjdlog_prefix[PJDLOG_PREFIX_STACK][PJDLOG_PREFIX_MAXSIZE];
752f02600aSPawel Jakub Dawidek
762f02600aSPawel Jakub Dawidek static int
pjdlog_printf_arginfo_humanized_number(const struct printf_info * pi __unused,size_t n,int * argt)772f02600aSPawel Jakub Dawidek pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
782f02600aSPawel Jakub Dawidek size_t n, int *argt)
792f02600aSPawel Jakub Dawidek {
802f02600aSPawel Jakub Dawidek
812f02600aSPawel Jakub Dawidek assert(n >= 1);
822f02600aSPawel Jakub Dawidek argt[0] = PA_INT | PA_FLAG_INTMAX;
832f02600aSPawel Jakub Dawidek return (1);
842f02600aSPawel Jakub Dawidek }
852f02600aSPawel Jakub Dawidek
862f02600aSPawel Jakub Dawidek static int
pjdlog_printf_render_humanized_number(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)872f02600aSPawel Jakub Dawidek pjdlog_printf_render_humanized_number(struct __printf_io *io,
882f02600aSPawel Jakub Dawidek const struct printf_info *pi, const void * const *arg)
892f02600aSPawel Jakub Dawidek {
902f02600aSPawel Jakub Dawidek char buf[5];
912f02600aSPawel Jakub Dawidek intmax_t num;
922f02600aSPawel Jakub Dawidek int ret;
932f02600aSPawel Jakub Dawidek
942f02600aSPawel Jakub Dawidek num = *(const intmax_t *)arg[0];
952f02600aSPawel Jakub Dawidek humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
962f02600aSPawel Jakub Dawidek HN_NOSPACE | HN_DECIMAL);
972f02600aSPawel Jakub Dawidek ret = __printf_out(io, pi, buf, strlen(buf));
982f02600aSPawel Jakub Dawidek __printf_flush(io);
992f02600aSPawel Jakub Dawidek return (ret);
1002f02600aSPawel Jakub Dawidek }
1012f02600aSPawel Jakub Dawidek
1022f02600aSPawel Jakub Dawidek static int
pjdlog_printf_arginfo_sockaddr(const struct printf_info * pi __unused,size_t n,int * argt)1032f02600aSPawel Jakub Dawidek pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
1042f02600aSPawel Jakub Dawidek size_t n, int *argt)
1052f02600aSPawel Jakub Dawidek {
1062f02600aSPawel Jakub Dawidek
1072f02600aSPawel Jakub Dawidek assert(n >= 1);
1082f02600aSPawel Jakub Dawidek argt[0] = PA_POINTER;
1092f02600aSPawel Jakub Dawidek return (1);
1102f02600aSPawel Jakub Dawidek }
1112f02600aSPawel Jakub Dawidek
1122f02600aSPawel Jakub Dawidek static int
pjdlog_printf_render_sockaddr_ip(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)1132f02600aSPawel Jakub Dawidek pjdlog_printf_render_sockaddr_ip(struct __printf_io *io,
1142f02600aSPawel Jakub Dawidek const struct printf_info *pi, const void * const *arg)
1152f02600aSPawel Jakub Dawidek {
1162f02600aSPawel Jakub Dawidek const struct sockaddr_storage *ss;
1172f02600aSPawel Jakub Dawidek char addr[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
1182f02600aSPawel Jakub Dawidek int ret;
1192f02600aSPawel Jakub Dawidek
1202f02600aSPawel Jakub Dawidek ss = *(const struct sockaddr_storage * const *)arg[0];
1212f02600aSPawel Jakub Dawidek switch (ss->ss_family) {
1222f02600aSPawel Jakub Dawidek case AF_INET:
1232f02600aSPawel Jakub Dawidek {
1242f02600aSPawel Jakub Dawidek const struct sockaddr_in *sin;
1252f02600aSPawel Jakub Dawidek
1262f02600aSPawel Jakub Dawidek sin = (const struct sockaddr_in *)ss;
1272f02600aSPawel Jakub Dawidek if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
1282f02600aSPawel Jakub Dawidek sizeof(addr)) == NULL) {
1292f02600aSPawel Jakub Dawidek PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
1302f02600aSPawel Jakub Dawidek strerror(errno));
1312f02600aSPawel Jakub Dawidek }
1322f02600aSPawel Jakub Dawidek break;
1332f02600aSPawel Jakub Dawidek }
1342f02600aSPawel Jakub Dawidek case AF_INET6:
1352f02600aSPawel Jakub Dawidek {
1362f02600aSPawel Jakub Dawidek const struct sockaddr_in6 *sin;
1372f02600aSPawel Jakub Dawidek
1382f02600aSPawel Jakub Dawidek sin = (const struct sockaddr_in6 *)ss;
1392f02600aSPawel Jakub Dawidek if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
1402f02600aSPawel Jakub Dawidek sizeof(addr)) == NULL) {
1412f02600aSPawel Jakub Dawidek PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
1422f02600aSPawel Jakub Dawidek strerror(errno));
1432f02600aSPawel Jakub Dawidek }
1442f02600aSPawel Jakub Dawidek break;
1452f02600aSPawel Jakub Dawidek }
1462f02600aSPawel Jakub Dawidek default:
1472f02600aSPawel Jakub Dawidek snprintf(addr, sizeof(addr), "[unsupported family %hhu]",
1482f02600aSPawel Jakub Dawidek ss->ss_family);
1492f02600aSPawel Jakub Dawidek break;
1502f02600aSPawel Jakub Dawidek }
1512f02600aSPawel Jakub Dawidek ret = __printf_out(io, pi, addr, strlen(addr));
1522f02600aSPawel Jakub Dawidek __printf_flush(io);
1532f02600aSPawel Jakub Dawidek return (ret);
1542f02600aSPawel Jakub Dawidek }
1552f02600aSPawel Jakub Dawidek
1562f02600aSPawel Jakub Dawidek static int
pjdlog_printf_render_sockaddr(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)1572f02600aSPawel Jakub Dawidek pjdlog_printf_render_sockaddr(struct __printf_io *io,
1582f02600aSPawel Jakub Dawidek const struct printf_info *pi, const void * const *arg)
1592f02600aSPawel Jakub Dawidek {
1602f02600aSPawel Jakub Dawidek const struct sockaddr_storage *ss;
1612f02600aSPawel Jakub Dawidek char buf[PATH_MAX];
1622f02600aSPawel Jakub Dawidek int ret;
1632f02600aSPawel Jakub Dawidek
1642f02600aSPawel Jakub Dawidek ss = *(const struct sockaddr_storage * const *)arg[0];
1652f02600aSPawel Jakub Dawidek switch (ss->ss_family) {
1662f02600aSPawel Jakub Dawidek case AF_UNIX:
1672f02600aSPawel Jakub Dawidek {
1682f02600aSPawel Jakub Dawidek const struct sockaddr_un *sun;
1692f02600aSPawel Jakub Dawidek
1702f02600aSPawel Jakub Dawidek sun = (const struct sockaddr_un *)ss;
1712f02600aSPawel Jakub Dawidek if (sun->sun_path[0] == '\0')
1722f02600aSPawel Jakub Dawidek snprintf(buf, sizeof(buf), "N/A");
1732f02600aSPawel Jakub Dawidek else
1742f02600aSPawel Jakub Dawidek snprintf(buf, sizeof(buf), "%s", sun->sun_path);
1752f02600aSPawel Jakub Dawidek break;
1762f02600aSPawel Jakub Dawidek }
1772f02600aSPawel Jakub Dawidek case AF_INET:
1782f02600aSPawel Jakub Dawidek {
1792f02600aSPawel Jakub Dawidek char addr[INET_ADDRSTRLEN];
1802f02600aSPawel Jakub Dawidek const struct sockaddr_in *sin;
1812f02600aSPawel Jakub Dawidek unsigned int port;
1822f02600aSPawel Jakub Dawidek
1832f02600aSPawel Jakub Dawidek sin = (const struct sockaddr_in *)ss;
1842f02600aSPawel Jakub Dawidek port = ntohs(sin->sin_port);
1852f02600aSPawel Jakub Dawidek if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
1862f02600aSPawel Jakub Dawidek sizeof(addr)) == NULL) {
1872f02600aSPawel Jakub Dawidek PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
1882f02600aSPawel Jakub Dawidek strerror(errno));
1892f02600aSPawel Jakub Dawidek }
1902f02600aSPawel Jakub Dawidek snprintf(buf, sizeof(buf), "%s:%u", addr, port);
1912f02600aSPawel Jakub Dawidek break;
1922f02600aSPawel Jakub Dawidek }
1932f02600aSPawel Jakub Dawidek case AF_INET6:
1942f02600aSPawel Jakub Dawidek {
1952f02600aSPawel Jakub Dawidek char addr[INET6_ADDRSTRLEN];
1962f02600aSPawel Jakub Dawidek const struct sockaddr_in6 *sin;
1972f02600aSPawel Jakub Dawidek unsigned int port;
1982f02600aSPawel Jakub Dawidek
1992f02600aSPawel Jakub Dawidek sin = (const struct sockaddr_in6 *)ss;
2002f02600aSPawel Jakub Dawidek port = ntohs(sin->sin6_port);
2012f02600aSPawel Jakub Dawidek if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
2022f02600aSPawel Jakub Dawidek sizeof(addr)) == NULL) {
2032f02600aSPawel Jakub Dawidek PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
2042f02600aSPawel Jakub Dawidek strerror(errno));
2052f02600aSPawel Jakub Dawidek }
2062f02600aSPawel Jakub Dawidek snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
2072f02600aSPawel Jakub Dawidek break;
2082f02600aSPawel Jakub Dawidek }
2092f02600aSPawel Jakub Dawidek default:
2102f02600aSPawel Jakub Dawidek snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
2112f02600aSPawel Jakub Dawidek ss->ss_family);
2122f02600aSPawel Jakub Dawidek break;
2132f02600aSPawel Jakub Dawidek }
2142f02600aSPawel Jakub Dawidek ret = __printf_out(io, pi, buf, strlen(buf));
2152f02600aSPawel Jakub Dawidek __printf_flush(io);
2162f02600aSPawel Jakub Dawidek return (ret);
2172f02600aSPawel Jakub Dawidek }
2182f02600aSPawel Jakub Dawidek
2192f02600aSPawel Jakub Dawidek void
pjdlog_init(int mode)2202f02600aSPawel Jakub Dawidek pjdlog_init(int mode)
2212f02600aSPawel Jakub Dawidek {
2222f02600aSPawel Jakub Dawidek int saved_errno;
2232f02600aSPawel Jakub Dawidek
2242f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
2252f02600aSPawel Jakub Dawidek pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
2262f02600aSPawel Jakub Dawidek #ifdef notyet
2272f02600aSPawel Jakub Dawidek assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG ||
2282f02600aSPawel Jakub Dawidek mode == PJDLOG_MODE_SOCK);
2292f02600aSPawel Jakub Dawidek #else
2302f02600aSPawel Jakub Dawidek assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
2312f02600aSPawel Jakub Dawidek #endif
2322f02600aSPawel Jakub Dawidek
2332f02600aSPawel Jakub Dawidek saved_errno = errno;
2342f02600aSPawel Jakub Dawidek
2352f02600aSPawel Jakub Dawidek if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
2362f02600aSPawel Jakub Dawidek __use_xprintf = 1;
2372f02600aSPawel Jakub Dawidek register_printf_render_std("T");
2382f02600aSPawel Jakub Dawidek register_printf_render('N',
2392f02600aSPawel Jakub Dawidek pjdlog_printf_render_humanized_number,
2402f02600aSPawel Jakub Dawidek pjdlog_printf_arginfo_humanized_number);
2412f02600aSPawel Jakub Dawidek register_printf_render('I',
2422f02600aSPawel Jakub Dawidek pjdlog_printf_render_sockaddr_ip,
2432f02600aSPawel Jakub Dawidek pjdlog_printf_arginfo_sockaddr);
2442f02600aSPawel Jakub Dawidek register_printf_render('S',
2452f02600aSPawel Jakub Dawidek pjdlog_printf_render_sockaddr,
2462f02600aSPawel Jakub Dawidek pjdlog_printf_arginfo_sockaddr);
2472f02600aSPawel Jakub Dawidek }
2482f02600aSPawel Jakub Dawidek
2492f02600aSPawel Jakub Dawidek if (mode == PJDLOG_MODE_SYSLOG)
2502f02600aSPawel Jakub Dawidek openlog(NULL, LOG_PID | LOG_NDELAY, LOG_LOCAL0);
2512f02600aSPawel Jakub Dawidek pjdlog_mode = mode;
2522f02600aSPawel Jakub Dawidek pjdlog_debug_level = 0;
2532f02600aSPawel Jakub Dawidek pjdlog_prefix_current = 0;
2542f02600aSPawel Jakub Dawidek pjdlog_prefix[0][0] = '\0';
2552f02600aSPawel Jakub Dawidek
2562f02600aSPawel Jakub Dawidek pjdlog_initialized = PJDLOG_INITIALIZED;
2572f02600aSPawel Jakub Dawidek pjdlog_sock = -1;
2582f02600aSPawel Jakub Dawidek
2592f02600aSPawel Jakub Dawidek errno = saved_errno;
2602f02600aSPawel Jakub Dawidek }
2612f02600aSPawel Jakub Dawidek
2622f02600aSPawel Jakub Dawidek void
pjdlog_fini(void)2632f02600aSPawel Jakub Dawidek pjdlog_fini(void)
2642f02600aSPawel Jakub Dawidek {
2652f02600aSPawel Jakub Dawidek int saved_errno;
2662f02600aSPawel Jakub Dawidek
2672f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
2682f02600aSPawel Jakub Dawidek
2692f02600aSPawel Jakub Dawidek saved_errno = errno;
2702f02600aSPawel Jakub Dawidek
2712f02600aSPawel Jakub Dawidek if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
2722f02600aSPawel Jakub Dawidek closelog();
2732f02600aSPawel Jakub Dawidek
2742f02600aSPawel Jakub Dawidek pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
2752f02600aSPawel Jakub Dawidek pjdlog_sock = -1;
2762f02600aSPawel Jakub Dawidek
2772f02600aSPawel Jakub Dawidek errno = saved_errno;
2782f02600aSPawel Jakub Dawidek }
2792f02600aSPawel Jakub Dawidek
2802f02600aSPawel Jakub Dawidek /*
2812f02600aSPawel Jakub Dawidek * Configure where the logs should go.
2822f02600aSPawel Jakub Dawidek * By default they are send to stdout/stderr, but after going into background
2832f02600aSPawel Jakub Dawidek * (eg. by calling daemon(3)) application is responsible for changing mode to
2842f02600aSPawel Jakub Dawidek * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
2852f02600aSPawel Jakub Dawidek */
2862f02600aSPawel Jakub Dawidek void
pjdlog_mode_set(int mode)2872f02600aSPawel Jakub Dawidek pjdlog_mode_set(int mode)
2882f02600aSPawel Jakub Dawidek {
2892f02600aSPawel Jakub Dawidek int saved_errno;
2902f02600aSPawel Jakub Dawidek
2912f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
2922f02600aSPawel Jakub Dawidek #ifdef notyet
2932f02600aSPawel Jakub Dawidek assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG ||
2942f02600aSPawel Jakub Dawidek mode == PJDLOG_MODE_SOCK);
2952f02600aSPawel Jakub Dawidek #else
2962f02600aSPawel Jakub Dawidek assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
2972f02600aSPawel Jakub Dawidek #endif
2982f02600aSPawel Jakub Dawidek
2992f02600aSPawel Jakub Dawidek if (pjdlog_mode == mode)
3002f02600aSPawel Jakub Dawidek return;
3012f02600aSPawel Jakub Dawidek
3022f02600aSPawel Jakub Dawidek saved_errno = errno;
3032f02600aSPawel Jakub Dawidek
3042f02600aSPawel Jakub Dawidek if (mode == PJDLOG_MODE_SYSLOG)
3052f02600aSPawel Jakub Dawidek openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
3062f02600aSPawel Jakub Dawidek else if (mode == PJDLOG_MODE_STD)
3072f02600aSPawel Jakub Dawidek closelog();
3082f02600aSPawel Jakub Dawidek
3092f02600aSPawel Jakub Dawidek if (mode != PJDLOG_MODE_SOCK)
3102f02600aSPawel Jakub Dawidek pjdlog_sock = -1;
3112f02600aSPawel Jakub Dawidek
3122f02600aSPawel Jakub Dawidek pjdlog_mode = mode;
3132f02600aSPawel Jakub Dawidek
3142f02600aSPawel Jakub Dawidek errno = saved_errno;
3152f02600aSPawel Jakub Dawidek }
3162f02600aSPawel Jakub Dawidek
3172f02600aSPawel Jakub Dawidek
3182f02600aSPawel Jakub Dawidek /*
3192f02600aSPawel Jakub Dawidek * Return current mode.
3202f02600aSPawel Jakub Dawidek */
3212f02600aSPawel Jakub Dawidek int
pjdlog_mode_get(void)3222f02600aSPawel Jakub Dawidek pjdlog_mode_get(void)
3232f02600aSPawel Jakub Dawidek {
3242f02600aSPawel Jakub Dawidek
3252f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
3262f02600aSPawel Jakub Dawidek
3272f02600aSPawel Jakub Dawidek return (pjdlog_mode);
3282f02600aSPawel Jakub Dawidek }
3292f02600aSPawel Jakub Dawidek
3302f02600aSPawel Jakub Dawidek #ifdef notyet
3312f02600aSPawel Jakub Dawidek /*
3322f02600aSPawel Jakub Dawidek * Sets socket number to use for PJDLOG_MODE_SOCK mode.
3332f02600aSPawel Jakub Dawidek */
3342f02600aSPawel Jakub Dawidek void
pjdlog_sock_set(int sock)3352f02600aSPawel Jakub Dawidek pjdlog_sock_set(int sock)
3362f02600aSPawel Jakub Dawidek {
3372f02600aSPawel Jakub Dawidek
3382f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
3392f02600aSPawel Jakub Dawidek assert(pjdlog_mode == PJDLOG_MODE_SOCK);
3402f02600aSPawel Jakub Dawidek assert(sock >= 0);
3412f02600aSPawel Jakub Dawidek
3422f02600aSPawel Jakub Dawidek pjdlog_sock = sock;
3432f02600aSPawel Jakub Dawidek }
3442f02600aSPawel Jakub Dawidek #endif
3452f02600aSPawel Jakub Dawidek
3462f02600aSPawel Jakub Dawidek #ifdef notyet
3472f02600aSPawel Jakub Dawidek /*
3482f02600aSPawel Jakub Dawidek * Returns socket number used for PJDLOG_MODE_SOCK mode.
3492f02600aSPawel Jakub Dawidek */
3502f02600aSPawel Jakub Dawidek int
pjdlog_sock_get(void)3512f02600aSPawel Jakub Dawidek pjdlog_sock_get(void)
3522f02600aSPawel Jakub Dawidek {
3532f02600aSPawel Jakub Dawidek
3542f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
3552f02600aSPawel Jakub Dawidek assert(pjdlog_mode == PJDLOG_MODE_SOCK);
3562f02600aSPawel Jakub Dawidek assert(pjdlog_sock >= 0);
3572f02600aSPawel Jakub Dawidek
3582f02600aSPawel Jakub Dawidek return (pjdlog_sock);
3592f02600aSPawel Jakub Dawidek }
3602f02600aSPawel Jakub Dawidek #endif
3612f02600aSPawel Jakub Dawidek
3622f02600aSPawel Jakub Dawidek /*
3632f02600aSPawel Jakub Dawidek * Set debug level. All the logs above the level specified here will be
3642f02600aSPawel Jakub Dawidek * ignored.
3652f02600aSPawel Jakub Dawidek */
3662f02600aSPawel Jakub Dawidek void
pjdlog_debug_set(int level)3672f02600aSPawel Jakub Dawidek pjdlog_debug_set(int level)
3682f02600aSPawel Jakub Dawidek {
3692f02600aSPawel Jakub Dawidek
3702f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
3712f02600aSPawel Jakub Dawidek assert(level >= 0);
3722f02600aSPawel Jakub Dawidek assert(level <= 127);
3732f02600aSPawel Jakub Dawidek
3742f02600aSPawel Jakub Dawidek pjdlog_debug_level = level;
3752f02600aSPawel Jakub Dawidek }
3762f02600aSPawel Jakub Dawidek
3772f02600aSPawel Jakub Dawidek /*
3782f02600aSPawel Jakub Dawidek * Return current debug level.
3792f02600aSPawel Jakub Dawidek */
3802f02600aSPawel Jakub Dawidek int
pjdlog_debug_get(void)3812f02600aSPawel Jakub Dawidek pjdlog_debug_get(void)
3822f02600aSPawel Jakub Dawidek {
3832f02600aSPawel Jakub Dawidek
3842f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
3852f02600aSPawel Jakub Dawidek
3862f02600aSPawel Jakub Dawidek return (pjdlog_debug_level);
3872f02600aSPawel Jakub Dawidek }
3882f02600aSPawel Jakub Dawidek
3892f02600aSPawel Jakub Dawidek /*
3902f02600aSPawel Jakub Dawidek * Set prefix that will be used before each log.
3912f02600aSPawel Jakub Dawidek */
3922f02600aSPawel Jakub Dawidek void
pjdlog_prefix_set(const char * fmt,...)3932f02600aSPawel Jakub Dawidek pjdlog_prefix_set(const char *fmt, ...)
3942f02600aSPawel Jakub Dawidek {
3952f02600aSPawel Jakub Dawidek va_list ap;
3962f02600aSPawel Jakub Dawidek
3972f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
3982f02600aSPawel Jakub Dawidek
3992f02600aSPawel Jakub Dawidek va_start(ap, fmt);
4002f02600aSPawel Jakub Dawidek pjdlogv_prefix_set(fmt, ap);
4012f02600aSPawel Jakub Dawidek va_end(ap);
4022f02600aSPawel Jakub Dawidek }
4032f02600aSPawel Jakub Dawidek
4042f02600aSPawel Jakub Dawidek /*
4052f02600aSPawel Jakub Dawidek * Set prefix that will be used before each log.
4062f02600aSPawel Jakub Dawidek */
4072f02600aSPawel Jakub Dawidek void
pjdlogv_prefix_set(const char * fmt,va_list ap)4082f02600aSPawel Jakub Dawidek pjdlogv_prefix_set(const char *fmt, va_list ap)
4092f02600aSPawel Jakub Dawidek {
4102f02600aSPawel Jakub Dawidek int saved_errno;
4112f02600aSPawel Jakub Dawidek
4122f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
4132f02600aSPawel Jakub Dawidek assert(fmt != NULL);
4142f02600aSPawel Jakub Dawidek
4152f02600aSPawel Jakub Dawidek saved_errno = errno;
4162f02600aSPawel Jakub Dawidek
4172f02600aSPawel Jakub Dawidek vsnprintf(pjdlog_prefix[pjdlog_prefix_current],
4182f02600aSPawel Jakub Dawidek sizeof(pjdlog_prefix[pjdlog_prefix_current]), fmt, ap);
4192f02600aSPawel Jakub Dawidek
4202f02600aSPawel Jakub Dawidek errno = saved_errno;
4212f02600aSPawel Jakub Dawidek }
4222f02600aSPawel Jakub Dawidek
4232f02600aSPawel Jakub Dawidek /*
4242f02600aSPawel Jakub Dawidek * Get current prefix.
4252f02600aSPawel Jakub Dawidek */
4262f02600aSPawel Jakub Dawidek const char *
pjdlog_prefix_get(void)4272f02600aSPawel Jakub Dawidek pjdlog_prefix_get(void)
4282f02600aSPawel Jakub Dawidek {
4292f02600aSPawel Jakub Dawidek
4302f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
4312f02600aSPawel Jakub Dawidek
4322f02600aSPawel Jakub Dawidek return (pjdlog_prefix[pjdlog_prefix_current]);
4332f02600aSPawel Jakub Dawidek }
4342f02600aSPawel Jakub Dawidek
4352f02600aSPawel Jakub Dawidek /*
4362f02600aSPawel Jakub Dawidek * Set new prefix and put the current one on the stack.
4372f02600aSPawel Jakub Dawidek */
4382f02600aSPawel Jakub Dawidek void
pjdlog_prefix_push(const char * fmt,...)4392f02600aSPawel Jakub Dawidek pjdlog_prefix_push(const char *fmt, ...)
4402f02600aSPawel Jakub Dawidek {
4412f02600aSPawel Jakub Dawidek va_list ap;
4422f02600aSPawel Jakub Dawidek
4432f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
4442f02600aSPawel Jakub Dawidek
4452f02600aSPawel Jakub Dawidek va_start(ap, fmt);
4462f02600aSPawel Jakub Dawidek pjdlogv_prefix_push(fmt, ap);
4472f02600aSPawel Jakub Dawidek va_end(ap);
4482f02600aSPawel Jakub Dawidek }
4492f02600aSPawel Jakub Dawidek
4502f02600aSPawel Jakub Dawidek /*
4512f02600aSPawel Jakub Dawidek * Set new prefix and put the current one on the stack.
4522f02600aSPawel Jakub Dawidek */
4532f02600aSPawel Jakub Dawidek void
pjdlogv_prefix_push(const char * fmt,va_list ap)4542f02600aSPawel Jakub Dawidek pjdlogv_prefix_push(const char *fmt, va_list ap)
4552f02600aSPawel Jakub Dawidek {
4562f02600aSPawel Jakub Dawidek
4572f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
4582f02600aSPawel Jakub Dawidek assert(pjdlog_prefix_current < PJDLOG_PREFIX_STACK - 1);
4592f02600aSPawel Jakub Dawidek
4602f02600aSPawel Jakub Dawidek pjdlog_prefix_current++;
4612f02600aSPawel Jakub Dawidek
4622f02600aSPawel Jakub Dawidek pjdlogv_prefix_set(fmt, ap);
4632f02600aSPawel Jakub Dawidek }
4642f02600aSPawel Jakub Dawidek
4652f02600aSPawel Jakub Dawidek /*
4662f02600aSPawel Jakub Dawidek * Removes current prefix and recovers previous one from the stack.
4672f02600aSPawel Jakub Dawidek */
4682f02600aSPawel Jakub Dawidek void
pjdlog_prefix_pop(void)4692f02600aSPawel Jakub Dawidek pjdlog_prefix_pop(void)
4702f02600aSPawel Jakub Dawidek {
4712f02600aSPawel Jakub Dawidek
4722f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
4732f02600aSPawel Jakub Dawidek assert(pjdlog_prefix_current > 0);
4742f02600aSPawel Jakub Dawidek
4752f02600aSPawel Jakub Dawidek pjdlog_prefix_current--;
4762f02600aSPawel Jakub Dawidek }
4772f02600aSPawel Jakub Dawidek
4782f02600aSPawel Jakub Dawidek /*
4792f02600aSPawel Jakub Dawidek * Convert log level into string.
4802f02600aSPawel Jakub Dawidek */
4812f02600aSPawel Jakub Dawidek static const char *
pjdlog_level_to_string(int loglevel)4822f02600aSPawel Jakub Dawidek pjdlog_level_to_string(int loglevel)
4832f02600aSPawel Jakub Dawidek {
4842f02600aSPawel Jakub Dawidek
4852f02600aSPawel Jakub Dawidek switch (loglevel) {
4862f02600aSPawel Jakub Dawidek case LOG_EMERG:
4872f02600aSPawel Jakub Dawidek return ("EMERG");
4882f02600aSPawel Jakub Dawidek case LOG_ALERT:
4892f02600aSPawel Jakub Dawidek return ("ALERT");
4902f02600aSPawel Jakub Dawidek case LOG_CRIT:
4912f02600aSPawel Jakub Dawidek return ("CRIT");
4922f02600aSPawel Jakub Dawidek case LOG_ERR:
4932f02600aSPawel Jakub Dawidek return ("ERROR");
4942f02600aSPawel Jakub Dawidek case LOG_WARNING:
4952f02600aSPawel Jakub Dawidek return ("WARNING");
4962f02600aSPawel Jakub Dawidek case LOG_NOTICE:
4972f02600aSPawel Jakub Dawidek return ("NOTICE");
4982f02600aSPawel Jakub Dawidek case LOG_INFO:
4992f02600aSPawel Jakub Dawidek return ("INFO");
5002f02600aSPawel Jakub Dawidek case LOG_DEBUG:
5012f02600aSPawel Jakub Dawidek return ("DEBUG");
5022f02600aSPawel Jakub Dawidek }
5032f02600aSPawel Jakub Dawidek assert(!"Invalid log level.");
5042f02600aSPawel Jakub Dawidek abort(); /* XXX: gcc */
5052f02600aSPawel Jakub Dawidek }
5062f02600aSPawel Jakub Dawidek
5072f02600aSPawel Jakub Dawidek static int
vsnprlcat(char * str,size_t size,const char * fmt,va_list ap)5082f02600aSPawel Jakub Dawidek vsnprlcat(char *str, size_t size, const char *fmt, va_list ap)
5092f02600aSPawel Jakub Dawidek {
5102f02600aSPawel Jakub Dawidek size_t len;
5112f02600aSPawel Jakub Dawidek
5122f02600aSPawel Jakub Dawidek len = strlen(str);
5132f02600aSPawel Jakub Dawidek assert(len < size);
5142f02600aSPawel Jakub Dawidek return (vsnprintf(str + len, size - len, fmt, ap));
5152f02600aSPawel Jakub Dawidek }
5162f02600aSPawel Jakub Dawidek
5172f02600aSPawel Jakub Dawidek static int
snprlcat(char * str,size_t size,const char * fmt,...)5182f02600aSPawel Jakub Dawidek snprlcat(char *str, size_t size, const char *fmt, ...)
5192f02600aSPawel Jakub Dawidek {
5202f02600aSPawel Jakub Dawidek va_list ap;
5212f02600aSPawel Jakub Dawidek int result;
5222f02600aSPawel Jakub Dawidek
5232f02600aSPawel Jakub Dawidek va_start(ap, fmt);
5242f02600aSPawel Jakub Dawidek result = vsnprlcat(str, size, fmt, ap);
5252f02600aSPawel Jakub Dawidek va_end(ap);
5262f02600aSPawel Jakub Dawidek return (result);
5272f02600aSPawel Jakub Dawidek }
5282f02600aSPawel Jakub Dawidek
5292f02600aSPawel Jakub Dawidek static void
pjdlogv_common_single_line(const char * func,const char * file,int line,int loglevel,int debuglevel,int error,const char * msg)5302f02600aSPawel Jakub Dawidek pjdlogv_common_single_line(const char *func, const char *file, int line,
5312f02600aSPawel Jakub Dawidek int loglevel, int debuglevel, int error, const char *msg)
5322f02600aSPawel Jakub Dawidek {
5332f02600aSPawel Jakub Dawidek static char log[2 * PJDLOG_MAX_MSGSIZE];
5342f02600aSPawel Jakub Dawidek char *logp;
5352f02600aSPawel Jakub Dawidek size_t logs;
5362f02600aSPawel Jakub Dawidek
5372f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
5382f02600aSPawel Jakub Dawidek #ifdef notyet
5392f02600aSPawel Jakub Dawidek assert(pjdlog_mode == PJDLOG_MODE_STD ||
5402f02600aSPawel Jakub Dawidek pjdlog_mode == PJDLOG_MODE_SYSLOG ||
5412f02600aSPawel Jakub Dawidek pjdlog_mode == PJDLOG_MODE_SOCK);
5422f02600aSPawel Jakub Dawidek #else
5432f02600aSPawel Jakub Dawidek assert(pjdlog_mode == PJDLOG_MODE_STD ||
5442f02600aSPawel Jakub Dawidek pjdlog_mode == PJDLOG_MODE_SYSLOG);
5452f02600aSPawel Jakub Dawidek #endif
5462f02600aSPawel Jakub Dawidek assert(pjdlog_mode != PJDLOG_MODE_SOCK || pjdlog_sock >= 0);
5472f02600aSPawel Jakub Dawidek assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
5482f02600aSPawel Jakub Dawidek loglevel == LOG_CRIT || loglevel == LOG_ERR ||
5492f02600aSPawel Jakub Dawidek loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
5502f02600aSPawel Jakub Dawidek loglevel == LOG_INFO || loglevel == LOG_DEBUG);
5512f02600aSPawel Jakub Dawidek assert(loglevel != LOG_DEBUG || debuglevel > 0);
5522f02600aSPawel Jakub Dawidek assert(loglevel != LOG_DEBUG || debuglevel <= pjdlog_debug_level);
5532f02600aSPawel Jakub Dawidek assert(debuglevel <= 127);
5542f02600aSPawel Jakub Dawidek assert(error >= -1);
5552f02600aSPawel Jakub Dawidek assert((file != NULL && line > 0) ||
5562f02600aSPawel Jakub Dawidek (func == NULL && file == NULL && line == 0));
5572f02600aSPawel Jakub Dawidek
5582f02600aSPawel Jakub Dawidek switch (pjdlog_mode) {
5592f02600aSPawel Jakub Dawidek case PJDLOG_MODE_STD:
5602f02600aSPawel Jakub Dawidek case PJDLOG_MODE_SYSLOG:
5612f02600aSPawel Jakub Dawidek logp = log;
5622f02600aSPawel Jakub Dawidek logs = sizeof(log);
5632f02600aSPawel Jakub Dawidek break;
5642f02600aSPawel Jakub Dawidek case PJDLOG_MODE_SOCK:
5652f02600aSPawel Jakub Dawidek logp = log + 4;
5662f02600aSPawel Jakub Dawidek logs = sizeof(log) - 4;
5672f02600aSPawel Jakub Dawidek break;
5682f02600aSPawel Jakub Dawidek default:
5692f02600aSPawel Jakub Dawidek assert(!"Invalid mode.");
5702f02600aSPawel Jakub Dawidek }
5712f02600aSPawel Jakub Dawidek
5722f02600aSPawel Jakub Dawidek *logp = '\0';
5732f02600aSPawel Jakub Dawidek
5742f02600aSPawel Jakub Dawidek if (pjdlog_mode != PJDLOG_MODE_SOCK) {
5752f02600aSPawel Jakub Dawidek if (loglevel == LOG_DEBUG) {
5762f02600aSPawel Jakub Dawidek /* Attach debuglevel if this is debug log. */
5772f02600aSPawel Jakub Dawidek snprlcat(logp, logs, "[%s%d] ",
5782f02600aSPawel Jakub Dawidek pjdlog_level_to_string(loglevel), debuglevel);
5792f02600aSPawel Jakub Dawidek } else {
5802f02600aSPawel Jakub Dawidek snprlcat(logp, logs, "[%s] ",
5812f02600aSPawel Jakub Dawidek pjdlog_level_to_string(loglevel));
5822f02600aSPawel Jakub Dawidek }
5832f02600aSPawel Jakub Dawidek if (pjdlog_mode != PJDLOG_MODE_SYSLOG &&
5842f02600aSPawel Jakub Dawidek pjdlog_debug_level >= 1) {
5852f02600aSPawel Jakub Dawidek snprlcat(logp, logs, "(pid=%d) ", getpid());
5862f02600aSPawel Jakub Dawidek }
5872f02600aSPawel Jakub Dawidek }
5882f02600aSPawel Jakub Dawidek /* Attach file, func, line if debuglevel is 2 or more. */
5892f02600aSPawel Jakub Dawidek if (pjdlog_debug_level >= 2 && file != NULL) {
5902f02600aSPawel Jakub Dawidek if (func == NULL)
5912f02600aSPawel Jakub Dawidek snprlcat(logp, logs, "(%s:%d) ", file, line);
5922f02600aSPawel Jakub Dawidek else
5932f02600aSPawel Jakub Dawidek snprlcat(logp, logs, "(%s:%d:%s) ", file, line, func);
5942f02600aSPawel Jakub Dawidek }
5952f02600aSPawel Jakub Dawidek
5962f02600aSPawel Jakub Dawidek if (pjdlog_mode != PJDLOG_MODE_SOCK) {
5972f02600aSPawel Jakub Dawidek snprlcat(logp, logs, "%s",
5982f02600aSPawel Jakub Dawidek pjdlog_prefix[pjdlog_prefix_current]);
5992f02600aSPawel Jakub Dawidek }
6002f02600aSPawel Jakub Dawidek
6012f02600aSPawel Jakub Dawidek strlcat(logp, msg, logs);
6022f02600aSPawel Jakub Dawidek
6032f02600aSPawel Jakub Dawidek /* Attach error description. */
6042f02600aSPawel Jakub Dawidek if (error != -1)
6052f02600aSPawel Jakub Dawidek snprlcat(logp, logs, ": %s.", strerror(error));
6062f02600aSPawel Jakub Dawidek
6072f02600aSPawel Jakub Dawidek switch (pjdlog_mode) {
6082f02600aSPawel Jakub Dawidek case PJDLOG_MODE_STD:
6092f02600aSPawel Jakub Dawidek fprintf(stderr, "%s\n", logp);
6102f02600aSPawel Jakub Dawidek fflush(stderr);
6112f02600aSPawel Jakub Dawidek break;
6122f02600aSPawel Jakub Dawidek case PJDLOG_MODE_SYSLOG:
6132f02600aSPawel Jakub Dawidek syslog(loglevel, "%s", logp);
6142f02600aSPawel Jakub Dawidek break;
6152f02600aSPawel Jakub Dawidek #ifdef notyet
6162f02600aSPawel Jakub Dawidek case PJDLOG_MODE_SOCK:
6172f02600aSPawel Jakub Dawidek {
6182f02600aSPawel Jakub Dawidek char ack[2];
6192f02600aSPawel Jakub Dawidek uint16_t dlen;
6202f02600aSPawel Jakub Dawidek
6212f02600aSPawel Jakub Dawidek log[2] = loglevel;
6222f02600aSPawel Jakub Dawidek log[3] = debuglevel;
6232f02600aSPawel Jakub Dawidek dlen = strlen(logp) + 3; /* +3 = loglevel, debuglevel and terminating \0 */
6242f02600aSPawel Jakub Dawidek bcopy(&dlen, log, sizeof(dlen));
6252f02600aSPawel Jakub Dawidek if (robust_send(pjdlog_sock, log, (size_t)dlen + 2) == -1) /* +2 for size */
6262f02600aSPawel Jakub Dawidek assert(!"Unable to send log.");
6272f02600aSPawel Jakub Dawidek if (robust_recv(pjdlog_sock, ack, sizeof(ack)) == -1)
6282f02600aSPawel Jakub Dawidek assert(!"Unable to send log.");
6292f02600aSPawel Jakub Dawidek break;
6302f02600aSPawel Jakub Dawidek }
6312f02600aSPawel Jakub Dawidek #endif
6322f02600aSPawel Jakub Dawidek default:
6332f02600aSPawel Jakub Dawidek assert(!"Invalid mode.");
6342f02600aSPawel Jakub Dawidek }
6352f02600aSPawel Jakub Dawidek }
6362f02600aSPawel Jakub Dawidek
6372f02600aSPawel Jakub Dawidek /*
6382f02600aSPawel Jakub Dawidek * Common log routine, which can handle regular log level as well as debug
6392f02600aSPawel Jakub Dawidek * level. We decide here where to send the logs (stdout/stderr or syslog).
6402f02600aSPawel Jakub Dawidek */
6412f02600aSPawel Jakub Dawidek void
_pjdlogv_common(const char * func,const char * file,int line,int loglevel,int debuglevel,int error,const char * fmt,va_list ap)6422f02600aSPawel Jakub Dawidek _pjdlogv_common(const char *func, const char *file, int line, int loglevel,
6432f02600aSPawel Jakub Dawidek int debuglevel, int error, const char *fmt, va_list ap)
6442f02600aSPawel Jakub Dawidek {
6452f02600aSPawel Jakub Dawidek char log[PJDLOG_MAX_MSGSIZE];
6462f02600aSPawel Jakub Dawidek char *logp, *curline;
6472f02600aSPawel Jakub Dawidek const char *prvline;
6482f02600aSPawel Jakub Dawidek int saved_errno;
6492f02600aSPawel Jakub Dawidek
6502f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
6512f02600aSPawel Jakub Dawidek assert(pjdlog_mode == PJDLOG_MODE_STD ||
6522f02600aSPawel Jakub Dawidek pjdlog_mode == PJDLOG_MODE_SYSLOG ||
6532f02600aSPawel Jakub Dawidek pjdlog_mode == PJDLOG_MODE_SOCK);
6542f02600aSPawel Jakub Dawidek assert(pjdlog_mode != PJDLOG_MODE_SOCK || pjdlog_sock >= 0);
6552f02600aSPawel Jakub Dawidek assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
6562f02600aSPawel Jakub Dawidek loglevel == LOG_CRIT || loglevel == LOG_ERR ||
6572f02600aSPawel Jakub Dawidek loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
6582f02600aSPawel Jakub Dawidek loglevel == LOG_INFO || loglevel == LOG_DEBUG);
6592f02600aSPawel Jakub Dawidek assert(loglevel != LOG_DEBUG || debuglevel > 0);
6602f02600aSPawel Jakub Dawidek assert(debuglevel <= 127);
6612f02600aSPawel Jakub Dawidek assert(error >= -1);
6622f02600aSPawel Jakub Dawidek
6632f02600aSPawel Jakub Dawidek /* Ignore debug above configured level. */
6642f02600aSPawel Jakub Dawidek if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
6652f02600aSPawel Jakub Dawidek return;
6662f02600aSPawel Jakub Dawidek
6672f02600aSPawel Jakub Dawidek saved_errno = errno;
6682f02600aSPawel Jakub Dawidek
6692f02600aSPawel Jakub Dawidek vsnprintf(log, sizeof(log), fmt, ap);
6702f02600aSPawel Jakub Dawidek logp = log;
6712f02600aSPawel Jakub Dawidek prvline = NULL;
6722f02600aSPawel Jakub Dawidek
6732f02600aSPawel Jakub Dawidek while ((curline = strsep(&logp, "\n")) != NULL) {
6742f02600aSPawel Jakub Dawidek if (*curline == '\0')
6752f02600aSPawel Jakub Dawidek continue;
6762f02600aSPawel Jakub Dawidek if (prvline != NULL) {
6772f02600aSPawel Jakub Dawidek pjdlogv_common_single_line(func, file, line, loglevel,
6782f02600aSPawel Jakub Dawidek debuglevel, -1, prvline);
6792f02600aSPawel Jakub Dawidek }
6802f02600aSPawel Jakub Dawidek prvline = curline;
6812f02600aSPawel Jakub Dawidek }
6822f02600aSPawel Jakub Dawidek if (prvline == NULL)
6832f02600aSPawel Jakub Dawidek prvline = "";
6842f02600aSPawel Jakub Dawidek pjdlogv_common_single_line(func, file, line, loglevel, debuglevel,
6852f02600aSPawel Jakub Dawidek error, prvline);
6862f02600aSPawel Jakub Dawidek
6872f02600aSPawel Jakub Dawidek errno = saved_errno;
6882f02600aSPawel Jakub Dawidek }
6892f02600aSPawel Jakub Dawidek
6902f02600aSPawel Jakub Dawidek /*
6912f02600aSPawel Jakub Dawidek * Common log routine.
6922f02600aSPawel Jakub Dawidek */
6932f02600aSPawel Jakub Dawidek void
_pjdlog_common(const char * func,const char * file,int line,int loglevel,int debuglevel,int error,const char * fmt,...)6942f02600aSPawel Jakub Dawidek _pjdlog_common(const char *func, const char *file, int line, int loglevel,
6952f02600aSPawel Jakub Dawidek int debuglevel, int error, const char *fmt, ...)
6962f02600aSPawel Jakub Dawidek {
6972f02600aSPawel Jakub Dawidek va_list ap;
6982f02600aSPawel Jakub Dawidek
6992f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
7002f02600aSPawel Jakub Dawidek
7012f02600aSPawel Jakub Dawidek va_start(ap, fmt);
7022f02600aSPawel Jakub Dawidek _pjdlogv_common(func, file, line, loglevel, debuglevel, error, fmt, ap);
7032f02600aSPawel Jakub Dawidek va_end(ap);
7042f02600aSPawel Jakub Dawidek }
7052f02600aSPawel Jakub Dawidek
7062f02600aSPawel Jakub Dawidek /*
7072f02600aSPawel Jakub Dawidek * Log error, errno and exit.
7082f02600aSPawel Jakub Dawidek */
7092f02600aSPawel Jakub Dawidek void
_pjdlogv_exit(const char * func,const char * file,int line,int exitcode,int error,const char * fmt,va_list ap)7102f02600aSPawel Jakub Dawidek _pjdlogv_exit(const char *func, const char *file, int line, int exitcode,
7112f02600aSPawel Jakub Dawidek int error, const char *fmt, va_list ap)
7122f02600aSPawel Jakub Dawidek {
7132f02600aSPawel Jakub Dawidek
7142f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
7152f02600aSPawel Jakub Dawidek
7162f02600aSPawel Jakub Dawidek _pjdlogv_common(func, file, line, exitcode == 0 ? LOG_INFO : LOG_ERR, 0,
7172f02600aSPawel Jakub Dawidek error, fmt, ap);
7182f02600aSPawel Jakub Dawidek exit(exitcode);
7192f02600aSPawel Jakub Dawidek /* NOTREACHED */
7202f02600aSPawel Jakub Dawidek }
7212f02600aSPawel Jakub Dawidek
7222f02600aSPawel Jakub Dawidek /*
7232f02600aSPawel Jakub Dawidek * Log error, errno and exit.
7242f02600aSPawel Jakub Dawidek */
7252f02600aSPawel Jakub Dawidek void
_pjdlog_exit(const char * func,const char * file,int line,int exitcode,int error,const char * fmt,...)7262f02600aSPawel Jakub Dawidek _pjdlog_exit(const char *func, const char *file, int line, int exitcode,
7272f02600aSPawel Jakub Dawidek int error, const char *fmt, ...)
7282f02600aSPawel Jakub Dawidek {
7292f02600aSPawel Jakub Dawidek va_list ap;
7302f02600aSPawel Jakub Dawidek
7312f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
7322f02600aSPawel Jakub Dawidek
7332f02600aSPawel Jakub Dawidek va_start(ap, fmt);
7342f02600aSPawel Jakub Dawidek _pjdlogv_exit(func, file, line, exitcode, error, fmt, ap);
7352f02600aSPawel Jakub Dawidek /* NOTREACHED */
7362f02600aSPawel Jakub Dawidek va_end(ap);
7372f02600aSPawel Jakub Dawidek }
7382f02600aSPawel Jakub Dawidek
7392f02600aSPawel Jakub Dawidek /*
7402f02600aSPawel Jakub Dawidek * Log failure message and exit.
7412f02600aSPawel Jakub Dawidek */
7422f02600aSPawel Jakub Dawidek void
_pjdlog_abort(const char * func,const char * file,int line,int error,const char * failedexpr,const char * fmt,...)7432f02600aSPawel Jakub Dawidek _pjdlog_abort(const char *func, const char *file, int line,
7442f02600aSPawel Jakub Dawidek int error, const char *failedexpr, const char *fmt, ...)
7452f02600aSPawel Jakub Dawidek {
7462f02600aSPawel Jakub Dawidek va_list ap;
7472f02600aSPawel Jakub Dawidek
7482f02600aSPawel Jakub Dawidek assert(pjdlog_initialized == PJDLOG_INITIALIZED);
7492f02600aSPawel Jakub Dawidek
7502f02600aSPawel Jakub Dawidek /*
7512f02600aSPawel Jakub Dawidek * Set pjdlog_debug_level to 2, so that file, line and func are
7522f02600aSPawel Jakub Dawidek * included in log. This is fine as we will exit anyway.
7532f02600aSPawel Jakub Dawidek */
7542f02600aSPawel Jakub Dawidek if (pjdlog_debug_level < 2)
7552f02600aSPawel Jakub Dawidek pjdlog_debug_level = 2;
7562f02600aSPawel Jakub Dawidek
7572f02600aSPawel Jakub Dawidek /*
7582f02600aSPawel Jakub Dawidek * When there is no message we pass __func__ as 'fmt'.
7592f02600aSPawel Jakub Dawidek * It would be cleaner to pass NULL or "", but gcc generates a warning
7602f02600aSPawel Jakub Dawidek * for both of those.
7612f02600aSPawel Jakub Dawidek */
7622f02600aSPawel Jakub Dawidek if (fmt != func) {
7632f02600aSPawel Jakub Dawidek va_start(ap, fmt);
7642f02600aSPawel Jakub Dawidek _pjdlogv_common(func, file, line, LOG_CRIT, 0, -1, fmt, ap);
7652f02600aSPawel Jakub Dawidek va_end(ap);
7662f02600aSPawel Jakub Dawidek }
7672f02600aSPawel Jakub Dawidek if (failedexpr == NULL) {
7682f02600aSPawel Jakub Dawidek _pjdlog_common(func, file, line, LOG_CRIT, 0, -1, "Aborted.");
7692f02600aSPawel Jakub Dawidek } else {
7702f02600aSPawel Jakub Dawidek _pjdlog_common(func, file, line, LOG_CRIT, 0, -1,
7712f02600aSPawel Jakub Dawidek "Assertion failed: (%s).", failedexpr);
7722f02600aSPawel Jakub Dawidek }
7732f02600aSPawel Jakub Dawidek if (error != -1)
7742f02600aSPawel Jakub Dawidek _pjdlog_common(func, file, line, LOG_CRIT, 0, error, "Errno");
7752f02600aSPawel Jakub Dawidek abort();
7762f02600aSPawel Jakub Dawidek }
7772f02600aSPawel Jakub Dawidek
7782f02600aSPawel Jakub Dawidek #ifdef notyet
7792f02600aSPawel Jakub Dawidek /*
7802f02600aSPawel Jakub Dawidek * Receive log from the given socket.
7812f02600aSPawel Jakub Dawidek */
7822f02600aSPawel Jakub Dawidek int
pjdlog_receive(int sock)7832f02600aSPawel Jakub Dawidek pjdlog_receive(int sock)
7842f02600aSPawel Jakub Dawidek {
7852f02600aSPawel Jakub Dawidek char log[PJDLOG_MAX_MSGSIZE];
7862f02600aSPawel Jakub Dawidek int loglevel, debuglevel;
7872f02600aSPawel Jakub Dawidek uint16_t dlen;
7882f02600aSPawel Jakub Dawidek
7892f02600aSPawel Jakub Dawidek if (robust_recv(sock, &dlen, sizeof(dlen)) == -1)
7902f02600aSPawel Jakub Dawidek return (-1);
7912f02600aSPawel Jakub Dawidek
7922f02600aSPawel Jakub Dawidek PJDLOG_ASSERT(dlen > 0);
7932f02600aSPawel Jakub Dawidek PJDLOG_ASSERT(dlen <= PJDLOG_MAX_MSGSIZE - 3);
7942f02600aSPawel Jakub Dawidek
7952f02600aSPawel Jakub Dawidek if (robust_recv(sock, log, (size_t)dlen) == -1)
7962f02600aSPawel Jakub Dawidek return (-1);
7972f02600aSPawel Jakub Dawidek
7982f02600aSPawel Jakub Dawidek log[dlen - 1] = '\0';
7992f02600aSPawel Jakub Dawidek loglevel = log[0];
8002f02600aSPawel Jakub Dawidek debuglevel = log[1];
8012f02600aSPawel Jakub Dawidek _pjdlog_common(NULL, NULL, 0, loglevel, debuglevel, -1, "%s", log + 2);
8022f02600aSPawel Jakub Dawidek
8032f02600aSPawel Jakub Dawidek if (robust_send(sock, "ok", 2) == -1)
8042f02600aSPawel Jakub Dawidek return (-1);
8052f02600aSPawel Jakub Dawidek
8062f02600aSPawel Jakub Dawidek return (0);
8072f02600aSPawel Jakub Dawidek }
8082f02600aSPawel Jakub Dawidek #endif
809