xref: /freebsd-src/lib/libpjdlog/pjdlog.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
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