xref: /freebsd/sbin/hastd/pjdlog.c (revision 32e86a82f54826f14ea381affa6674db3aa3b5ae)
132115b10SPawel Jakub Dawidek /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
46ef7ddd7SPawel Jakub Dawidek  * Copyright (c) 2009-2010 The FreeBSD Foundation
56ef7ddd7SPawel Jakub Dawidek  * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
632115b10SPawel Jakub Dawidek  * All rights reserved.
732115b10SPawel Jakub Dawidek  *
832115b10SPawel Jakub Dawidek  * This software was developed by Pawel Jakub Dawidek under sponsorship from
932115b10SPawel Jakub Dawidek  * the FreeBSD Foundation.
1032115b10SPawel Jakub Dawidek  *
1132115b10SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
1232115b10SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
1332115b10SPawel Jakub Dawidek  * are met:
1432115b10SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
1532115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
1632115b10SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
1732115b10SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
1832115b10SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
1932115b10SPawel Jakub Dawidek  *
2032115b10SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
2132115b10SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2232115b10SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2332115b10SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2432115b10SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2532115b10SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2632115b10SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2732115b10SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2832115b10SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2932115b10SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3032115b10SPawel Jakub Dawidek  * SUCH DAMAGE.
3132115b10SPawel Jakub Dawidek  */
3232115b10SPawel Jakub Dawidek 
330855e423SPawel Jakub Dawidek #include <sys/types.h>
349e5bdc9dSPawel Jakub Dawidek #include <sys/socket.h>
359e5bdc9dSPawel Jakub Dawidek #include <netinet/in.h>
360855e423SPawel Jakub Dawidek #include <arpa/inet.h>
379e5bdc9dSPawel Jakub Dawidek 
3832115b10SPawel Jakub Dawidek #include <assert.h>
3932115b10SPawel Jakub Dawidek #include <errno.h>
409e5bdc9dSPawel Jakub Dawidek #include <libutil.h>
41ab40f58cSRuslan Bukin #include <printf.h>
427d729cedSRuslan Bukin #include <stdarg.h>
439e5bdc9dSPawel Jakub Dawidek #include <stdint.h>
4432115b10SPawel Jakub Dawidek #include <stdio.h>
4532115b10SPawel Jakub Dawidek #include <stdlib.h>
4632115b10SPawel Jakub Dawidek #include <string.h>
4732115b10SPawel Jakub Dawidek #include <syslog.h>
4832115b10SPawel Jakub Dawidek 
4932115b10SPawel Jakub Dawidek #include "pjdlog.h"
5032115b10SPawel Jakub Dawidek 
51a61f5793SPawel Jakub Dawidek #define	PJDLOG_NEVER_INITIALIZED	0
52a61f5793SPawel Jakub Dawidek #define	PJDLOG_NOT_INITIALIZED		1
53a61f5793SPawel Jakub Dawidek #define	PJDLOG_INITIALIZED		2
54a61f5793SPawel Jakub Dawidek 
55a61f5793SPawel Jakub Dawidek static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
5670db96bfSPawel Jakub Dawidek static int pjdlog_mode, pjdlog_debug_level;
5732115b10SPawel Jakub Dawidek static char pjdlog_prefix[128];
5832115b10SPawel Jakub Dawidek 
599e5bdc9dSPawel Jakub Dawidek static int
pjdlog_printf_arginfo_humanized_number(const struct printf_info * pi __unused,size_t n,int * argt)609e5bdc9dSPawel Jakub Dawidek pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
619e5bdc9dSPawel Jakub Dawidek     size_t n, int *argt)
629e5bdc9dSPawel Jakub Dawidek {
639e5bdc9dSPawel Jakub Dawidek 
649e5bdc9dSPawel Jakub Dawidek 	assert(n >= 1);
659e5bdc9dSPawel Jakub Dawidek 	argt[0] = PA_INT | PA_FLAG_INTMAX;
669e5bdc9dSPawel Jakub Dawidek 	return (1);
679e5bdc9dSPawel Jakub Dawidek }
689e5bdc9dSPawel Jakub Dawidek 
699e5bdc9dSPawel Jakub Dawidek static int
pjdlog_printf_render_humanized_number(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)709e5bdc9dSPawel Jakub Dawidek pjdlog_printf_render_humanized_number(struct __printf_io *io,
719e5bdc9dSPawel Jakub Dawidek     const struct printf_info *pi, const void * const *arg)
729e5bdc9dSPawel Jakub Dawidek {
739e5bdc9dSPawel Jakub Dawidek 	char buf[5];
749e5bdc9dSPawel Jakub Dawidek 	intmax_t num;
759e5bdc9dSPawel Jakub Dawidek 	int ret;
769e5bdc9dSPawel Jakub Dawidek 
779e5bdc9dSPawel Jakub Dawidek 	num = *(const intmax_t *)arg[0];
789e5bdc9dSPawel Jakub Dawidek 	humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
799e5bdc9dSPawel Jakub Dawidek 	    HN_NOSPACE | HN_DECIMAL);
809e5bdc9dSPawel Jakub Dawidek 	ret = __printf_out(io, pi, buf, strlen(buf));
819e5bdc9dSPawel Jakub Dawidek 	__printf_flush(io);
829e5bdc9dSPawel Jakub Dawidek 	return (ret);
839e5bdc9dSPawel Jakub Dawidek }
849e5bdc9dSPawel Jakub Dawidek 
859e5bdc9dSPawel Jakub Dawidek static int
pjdlog_printf_arginfo_sockaddr(const struct printf_info * pi __unused,size_t n,int * argt)869e5bdc9dSPawel Jakub Dawidek pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
879e5bdc9dSPawel Jakub Dawidek     size_t n, int *argt)
889e5bdc9dSPawel Jakub Dawidek {
899e5bdc9dSPawel Jakub Dawidek 
909e5bdc9dSPawel Jakub Dawidek 	assert(n >= 1);
919e5bdc9dSPawel Jakub Dawidek 	argt[0] = PA_POINTER;
929e5bdc9dSPawel Jakub Dawidek 	return (1);
939e5bdc9dSPawel Jakub Dawidek }
949e5bdc9dSPawel Jakub Dawidek 
959e5bdc9dSPawel Jakub Dawidek static int
pjdlog_printf_render_sockaddr(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)969e5bdc9dSPawel Jakub Dawidek pjdlog_printf_render_sockaddr(struct __printf_io *io,
979e5bdc9dSPawel Jakub Dawidek     const struct printf_info *pi, const void * const *arg)
989e5bdc9dSPawel Jakub Dawidek {
99a98bce29SPawel Jakub Dawidek 	const struct sockaddr_storage *ss;
1009e5bdc9dSPawel Jakub Dawidek 	char buf[64];
1019e5bdc9dSPawel Jakub Dawidek 	int ret;
1029e5bdc9dSPawel Jakub Dawidek 
103a98bce29SPawel Jakub Dawidek 	ss = *(const struct sockaddr_storage * const *)arg[0];
104a98bce29SPawel Jakub Dawidek 	switch (ss->ss_family) {
1059e5bdc9dSPawel Jakub Dawidek 	case AF_INET:
1069e5bdc9dSPawel Jakub Dawidek 	    {
1070855e423SPawel Jakub Dawidek 		char addr[INET_ADDRSTRLEN];
1089e5bdc9dSPawel Jakub Dawidek 		const struct sockaddr_in *sin;
1099e5bdc9dSPawel Jakub Dawidek 		unsigned int port;
1109e5bdc9dSPawel Jakub Dawidek 
111a98bce29SPawel Jakub Dawidek 		sin = (const struct sockaddr_in *)ss;
1129e5bdc9dSPawel Jakub Dawidek 		port = ntohs(sin->sin_port);
1130855e423SPawel Jakub Dawidek 		if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
1140855e423SPawel Jakub Dawidek 		    sizeof(addr)) == NULL) {
1150855e423SPawel Jakub Dawidek 			PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
1160855e423SPawel Jakub Dawidek 			    strerror(errno));
1170855e423SPawel Jakub Dawidek 		}
1180855e423SPawel Jakub Dawidek 		snprintf(buf, sizeof(buf), "%s:%u", addr, port);
1190855e423SPawel Jakub Dawidek 		break;
1200855e423SPawel Jakub Dawidek 	    }
1210855e423SPawel Jakub Dawidek 	case AF_INET6:
1220855e423SPawel Jakub Dawidek 	    {
1230855e423SPawel Jakub Dawidek 		char addr[INET6_ADDRSTRLEN];
1240855e423SPawel Jakub Dawidek 		const struct sockaddr_in6 *sin;
1250855e423SPawel Jakub Dawidek 		unsigned int port;
1269e5bdc9dSPawel Jakub Dawidek 
1270855e423SPawel Jakub Dawidek 		sin = (const struct sockaddr_in6 *)ss;
1280855e423SPawel Jakub Dawidek 		port = ntohs(sin->sin6_port);
1290855e423SPawel Jakub Dawidek 		if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
1300855e423SPawel Jakub Dawidek 		    sizeof(addr)) == NULL) {
1310855e423SPawel Jakub Dawidek 			PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
1320855e423SPawel Jakub Dawidek 			    strerror(errno));
1330855e423SPawel Jakub Dawidek 		}
1340855e423SPawel Jakub Dawidek 		snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
1359e5bdc9dSPawel Jakub Dawidek 		break;
1369e5bdc9dSPawel Jakub Dawidek 	    }
1379e5bdc9dSPawel Jakub Dawidek 	default:
1380855e423SPawel Jakub Dawidek 		snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
1390855e423SPawel Jakub Dawidek 		    ss->ss_family);
1409e5bdc9dSPawel Jakub Dawidek 		break;
1419e5bdc9dSPawel Jakub Dawidek 	}
1429e5bdc9dSPawel Jakub Dawidek 	ret = __printf_out(io, pi, buf, strlen(buf));
1439e5bdc9dSPawel Jakub Dawidek 	__printf_flush(io);
1449e5bdc9dSPawel Jakub Dawidek 	return (ret);
1459e5bdc9dSPawel Jakub Dawidek }
1469e5bdc9dSPawel Jakub Dawidek 
147eeb3cd67SPawel Jakub Dawidek void
pjdlog_init(int mode)148eeb3cd67SPawel Jakub Dawidek pjdlog_init(int mode)
149eeb3cd67SPawel Jakub Dawidek {
15080c9ebc2SPawel Jakub Dawidek 	int saved_errno;
151eeb3cd67SPawel Jakub Dawidek 
152a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
153a61f5793SPawel Jakub Dawidek 	    pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
154eeb3cd67SPawel Jakub Dawidek 	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
155eeb3cd67SPawel Jakub Dawidek 
15680c9ebc2SPawel Jakub Dawidek 	saved_errno = errno;
15780c9ebc2SPawel Jakub Dawidek 
1589e5bdc9dSPawel Jakub Dawidek 	if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
1599e5bdc9dSPawel Jakub Dawidek 		__use_xprintf = 1;
1609e5bdc9dSPawel Jakub Dawidek 		register_printf_render_std("T");
1619e5bdc9dSPawel Jakub Dawidek 		register_printf_render('N',
1629e5bdc9dSPawel Jakub Dawidek 		    pjdlog_printf_render_humanized_number,
1639e5bdc9dSPawel Jakub Dawidek 		    pjdlog_printf_arginfo_humanized_number);
1649e5bdc9dSPawel Jakub Dawidek 		register_printf_render('S',
1659e5bdc9dSPawel Jakub Dawidek 		    pjdlog_printf_render_sockaddr,
1669e5bdc9dSPawel Jakub Dawidek 		    pjdlog_printf_arginfo_sockaddr);
1679e5bdc9dSPawel Jakub Dawidek 	}
1689e5bdc9dSPawel Jakub Dawidek 
169eeb3cd67SPawel Jakub Dawidek 	if (mode == PJDLOG_MODE_SYSLOG)
170eeb3cd67SPawel Jakub Dawidek 		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
171eeb3cd67SPawel Jakub Dawidek 	pjdlog_mode = mode;
17270db96bfSPawel Jakub Dawidek 	pjdlog_debug_level = 0;
17370db96bfSPawel Jakub Dawidek 	bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
174eeb3cd67SPawel Jakub Dawidek 
175a61f5793SPawel Jakub Dawidek 	pjdlog_initialized = PJDLOG_INITIALIZED;
17680c9ebc2SPawel Jakub Dawidek 
17780c9ebc2SPawel Jakub Dawidek 	errno = saved_errno;
178eeb3cd67SPawel Jakub Dawidek }
179eeb3cd67SPawel Jakub Dawidek 
180eeb3cd67SPawel Jakub Dawidek void
pjdlog_fini(void)181eeb3cd67SPawel Jakub Dawidek pjdlog_fini(void)
182eeb3cd67SPawel Jakub Dawidek {
18380c9ebc2SPawel Jakub Dawidek 	int saved_errno;
184eeb3cd67SPawel Jakub Dawidek 
185a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
186eeb3cd67SPawel Jakub Dawidek 
18780c9ebc2SPawel Jakub Dawidek 	saved_errno = errno;
18880c9ebc2SPawel Jakub Dawidek 
189eeb3cd67SPawel Jakub Dawidek 	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
190eeb3cd67SPawel Jakub Dawidek 		closelog();
191eeb3cd67SPawel Jakub Dawidek 
192a61f5793SPawel Jakub Dawidek 	pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
19380c9ebc2SPawel Jakub Dawidek 
19480c9ebc2SPawel Jakub Dawidek 	errno = saved_errno;
195eeb3cd67SPawel Jakub Dawidek }
196eeb3cd67SPawel Jakub Dawidek 
19732115b10SPawel Jakub Dawidek /*
19832115b10SPawel Jakub Dawidek  * Configure where the logs should go.
19932115b10SPawel Jakub Dawidek  * By default they are send to stdout/stderr, but after going into background
20032115b10SPawel Jakub Dawidek  * (eg. by calling daemon(3)) application is responsible for changing mode to
20132115b10SPawel Jakub Dawidek  * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
20232115b10SPawel Jakub Dawidek  */
20332115b10SPawel Jakub Dawidek void
pjdlog_mode_set(int mode)20432115b10SPawel Jakub Dawidek pjdlog_mode_set(int mode)
20532115b10SPawel Jakub Dawidek {
20680c9ebc2SPawel Jakub Dawidek 	int saved_errno;
20732115b10SPawel Jakub Dawidek 
208a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
20932115b10SPawel Jakub Dawidek 	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
21032115b10SPawel Jakub Dawidek 
211eeb3cd67SPawel Jakub Dawidek 	if (pjdlog_mode == mode)
212eeb3cd67SPawel Jakub Dawidek 		return;
2136d19256bSPawel Jakub Dawidek 
21480c9ebc2SPawel Jakub Dawidek 	saved_errno = errno;
21580c9ebc2SPawel Jakub Dawidek 
2166d19256bSPawel Jakub Dawidek 	if (mode == PJDLOG_MODE_SYSLOG)
217c6245737SPawel Jakub Dawidek 		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
218eeb3cd67SPawel Jakub Dawidek 	else /* if (mode == PJDLOG_MODE_STD) */
219eeb3cd67SPawel Jakub Dawidek 		closelog();
220eeb3cd67SPawel Jakub Dawidek 
221eeb3cd67SPawel Jakub Dawidek 	pjdlog_mode = mode;
22280c9ebc2SPawel Jakub Dawidek 
22380c9ebc2SPawel Jakub Dawidek 	errno = saved_errno;
22432115b10SPawel Jakub Dawidek }
22532115b10SPawel Jakub Dawidek 
22632115b10SPawel Jakub Dawidek /*
22732115b10SPawel Jakub Dawidek  * Return current mode.
22832115b10SPawel Jakub Dawidek  */
22932115b10SPawel Jakub Dawidek int
pjdlog_mode_get(void)23032115b10SPawel Jakub Dawidek pjdlog_mode_get(void)
23132115b10SPawel Jakub Dawidek {
23232115b10SPawel Jakub Dawidek 
233a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
234eeb3cd67SPawel Jakub Dawidek 
23532115b10SPawel Jakub Dawidek 	return (pjdlog_mode);
23632115b10SPawel Jakub Dawidek }
23732115b10SPawel Jakub Dawidek 
23832115b10SPawel Jakub Dawidek /*
23932115b10SPawel Jakub Dawidek  * Set debug level. All the logs above the level specified here will be
24032115b10SPawel Jakub Dawidek  * ignored.
24132115b10SPawel Jakub Dawidek  */
24232115b10SPawel Jakub Dawidek void
pjdlog_debug_set(int level)24332115b10SPawel Jakub Dawidek pjdlog_debug_set(int level)
24432115b10SPawel Jakub Dawidek {
24532115b10SPawel Jakub Dawidek 
246a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
24732115b10SPawel Jakub Dawidek 	assert(level >= 0);
24832115b10SPawel Jakub Dawidek 
24932115b10SPawel Jakub Dawidek 	pjdlog_debug_level = level;
25032115b10SPawel Jakub Dawidek }
25132115b10SPawel Jakub Dawidek 
25232115b10SPawel Jakub Dawidek /*
25332115b10SPawel Jakub Dawidek  * Return current debug level.
25432115b10SPawel Jakub Dawidek  */
25532115b10SPawel Jakub Dawidek int
pjdlog_debug_get(void)25632115b10SPawel Jakub Dawidek pjdlog_debug_get(void)
25732115b10SPawel Jakub Dawidek {
25832115b10SPawel Jakub Dawidek 
259a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
260eeb3cd67SPawel Jakub Dawidek 
26132115b10SPawel Jakub Dawidek 	return (pjdlog_debug_level);
26232115b10SPawel Jakub Dawidek }
26332115b10SPawel Jakub Dawidek 
26432115b10SPawel Jakub Dawidek /*
26532115b10SPawel Jakub Dawidek  * Set prefix that will be used before each log.
26632115b10SPawel Jakub Dawidek  * Setting prefix to NULL will remove it.
26732115b10SPawel Jakub Dawidek  */
26832115b10SPawel Jakub Dawidek void
pjdlog_prefix_set(const char * fmt,...)26932115b10SPawel Jakub Dawidek pjdlog_prefix_set(const char *fmt, ...)
27032115b10SPawel Jakub Dawidek {
27132115b10SPawel Jakub Dawidek 	va_list ap;
27232115b10SPawel Jakub Dawidek 
273a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
274eeb3cd67SPawel Jakub Dawidek 
27532115b10SPawel Jakub Dawidek 	va_start(ap, fmt);
27609d6ae1bSPawel Jakub Dawidek 	pjdlogv_prefix_set(fmt, ap);
27732115b10SPawel Jakub Dawidek 	va_end(ap);
27832115b10SPawel Jakub Dawidek }
27932115b10SPawel Jakub Dawidek 
28032115b10SPawel Jakub Dawidek /*
28132115b10SPawel Jakub Dawidek  * Set prefix that will be used before each log.
28232115b10SPawel Jakub Dawidek  * Setting prefix to NULL will remove it.
28332115b10SPawel Jakub Dawidek  */
28432115b10SPawel Jakub Dawidek void
pjdlogv_prefix_set(const char * fmt,va_list ap)28509d6ae1bSPawel Jakub Dawidek pjdlogv_prefix_set(const char *fmt, va_list ap)
28632115b10SPawel Jakub Dawidek {
28780c9ebc2SPawel Jakub Dawidek 	int saved_errno;
28832115b10SPawel Jakub Dawidek 
289a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
29032115b10SPawel Jakub Dawidek 	assert(fmt != NULL);
29132115b10SPawel Jakub Dawidek 
29280c9ebc2SPawel Jakub Dawidek 	saved_errno = errno;
29380c9ebc2SPawel Jakub Dawidek 
29432115b10SPawel Jakub Dawidek 	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
29580c9ebc2SPawel Jakub Dawidek 
29680c9ebc2SPawel Jakub Dawidek 	errno = saved_errno;
29732115b10SPawel Jakub Dawidek }
29832115b10SPawel Jakub Dawidek 
29932115b10SPawel Jakub Dawidek /*
30032115b10SPawel Jakub Dawidek  * Convert log level into string.
30132115b10SPawel Jakub Dawidek  */
30232115b10SPawel Jakub Dawidek static const char *
pjdlog_level_string(int loglevel)30332115b10SPawel Jakub Dawidek pjdlog_level_string(int loglevel)
30432115b10SPawel Jakub Dawidek {
30532115b10SPawel Jakub Dawidek 
30632115b10SPawel Jakub Dawidek 	switch (loglevel) {
30732115b10SPawel Jakub Dawidek 	case LOG_EMERG:
30832115b10SPawel Jakub Dawidek 		return ("EMERG");
30932115b10SPawel Jakub Dawidek 	case LOG_ALERT:
31032115b10SPawel Jakub Dawidek 		return ("ALERT");
31132115b10SPawel Jakub Dawidek 	case LOG_CRIT:
31232115b10SPawel Jakub Dawidek 		return ("CRIT");
31332115b10SPawel Jakub Dawidek 	case LOG_ERR:
31432115b10SPawel Jakub Dawidek 		return ("ERROR");
31532115b10SPawel Jakub Dawidek 	case LOG_WARNING:
31632115b10SPawel Jakub Dawidek 		return ("WARNING");
31732115b10SPawel Jakub Dawidek 	case LOG_NOTICE:
31832115b10SPawel Jakub Dawidek 		return ("NOTICE");
31932115b10SPawel Jakub Dawidek 	case LOG_INFO:
32032115b10SPawel Jakub Dawidek 		return ("INFO");
32132115b10SPawel Jakub Dawidek 	case LOG_DEBUG:
32232115b10SPawel Jakub Dawidek 		return ("DEBUG");
32332115b10SPawel Jakub Dawidek 	}
32432115b10SPawel Jakub Dawidek 	assert(!"Invalid log level.");
32532115b10SPawel Jakub Dawidek 	abort();	/* XXX: gcc */
32632115b10SPawel Jakub Dawidek }
32732115b10SPawel Jakub Dawidek 
32832115b10SPawel Jakub Dawidek /*
32932115b10SPawel Jakub Dawidek  * Common log routine.
33032115b10SPawel Jakub Dawidek  */
33132115b10SPawel Jakub Dawidek void
pjdlog_common(int loglevel,int debuglevel,int error,const char * fmt,...)33232115b10SPawel Jakub Dawidek pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
33332115b10SPawel Jakub Dawidek {
33432115b10SPawel Jakub Dawidek 	va_list ap;
33532115b10SPawel Jakub Dawidek 
336a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
337eeb3cd67SPawel Jakub Dawidek 
33832115b10SPawel Jakub Dawidek 	va_start(ap, fmt);
33932115b10SPawel Jakub Dawidek 	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
34032115b10SPawel Jakub Dawidek 	va_end(ap);
34132115b10SPawel Jakub Dawidek }
34232115b10SPawel Jakub Dawidek 
34332115b10SPawel Jakub Dawidek /*
34432115b10SPawel Jakub Dawidek  * Common log routine, which can handle regular log level as well as debug
34532115b10SPawel Jakub Dawidek  * level. We decide here where to send the logs (stdout/stderr or syslog).
34632115b10SPawel Jakub Dawidek  */
34732115b10SPawel Jakub Dawidek void
pjdlogv_common(int loglevel,int debuglevel,int error,const char * fmt,va_list ap)34832115b10SPawel Jakub Dawidek pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
34932115b10SPawel Jakub Dawidek     va_list ap)
35032115b10SPawel Jakub Dawidek {
35180c9ebc2SPawel Jakub Dawidek 	int saved_errno;
35232115b10SPawel Jakub Dawidek 
353a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
35432115b10SPawel Jakub Dawidek 	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
35532115b10SPawel Jakub Dawidek 	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
35632115b10SPawel Jakub Dawidek 	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
35732115b10SPawel Jakub Dawidek 	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
35832115b10SPawel Jakub Dawidek 	assert(loglevel != LOG_DEBUG || debuglevel > 0);
35932115b10SPawel Jakub Dawidek 	assert(error >= -1);
36032115b10SPawel Jakub Dawidek 
36132115b10SPawel Jakub Dawidek 	/* Ignore debug above configured level. */
36232115b10SPawel Jakub Dawidek 	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
36332115b10SPawel Jakub Dawidek 		return;
36432115b10SPawel Jakub Dawidek 
36580c9ebc2SPawel Jakub Dawidek 	saved_errno = errno;
36680c9ebc2SPawel Jakub Dawidek 
36732115b10SPawel Jakub Dawidek 	switch (pjdlog_mode) {
36832115b10SPawel Jakub Dawidek 	case PJDLOG_MODE_STD:
36932115b10SPawel Jakub Dawidek 	    {
37032115b10SPawel Jakub Dawidek 		FILE *out;
37132115b10SPawel Jakub Dawidek 
37232115b10SPawel Jakub Dawidek 		/*
37332115b10SPawel Jakub Dawidek 		 * We send errors and warning to stderr and the rest to stdout.
37432115b10SPawel Jakub Dawidek 		 */
37532115b10SPawel Jakub Dawidek 		switch (loglevel) {
37632115b10SPawel Jakub Dawidek 		case LOG_EMERG:
37732115b10SPawel Jakub Dawidek 		case LOG_ALERT:
37832115b10SPawel Jakub Dawidek 		case LOG_CRIT:
37932115b10SPawel Jakub Dawidek 		case LOG_ERR:
38032115b10SPawel Jakub Dawidek 		case LOG_WARNING:
38132115b10SPawel Jakub Dawidek 			out = stderr;
38232115b10SPawel Jakub Dawidek 			break;
38332115b10SPawel Jakub Dawidek 		case LOG_NOTICE:
38432115b10SPawel Jakub Dawidek 		case LOG_INFO:
38532115b10SPawel Jakub Dawidek 		case LOG_DEBUG:
38632115b10SPawel Jakub Dawidek 			out = stdout;
38732115b10SPawel Jakub Dawidek 			break;
38832115b10SPawel Jakub Dawidek 		default:
38932115b10SPawel Jakub Dawidek 			assert(!"Invalid loglevel.");
39032115b10SPawel Jakub Dawidek 			abort();	/* XXX: gcc */
39132115b10SPawel Jakub Dawidek 		}
39232115b10SPawel Jakub Dawidek 
39332115b10SPawel Jakub Dawidek 		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
39432115b10SPawel Jakub Dawidek 		/* Attach debuglevel if this is debug log. */
39532115b10SPawel Jakub Dawidek 		if (loglevel == LOG_DEBUG)
39632115b10SPawel Jakub Dawidek 			fprintf(out, "[%d]", debuglevel);
39732115b10SPawel Jakub Dawidek 		fprintf(out, " %s", pjdlog_prefix);
39832115b10SPawel Jakub Dawidek 		vfprintf(out, fmt, ap);
39932115b10SPawel Jakub Dawidek 		if (error != -1)
40032115b10SPawel Jakub Dawidek 			fprintf(out, ": %s.", strerror(error));
40132115b10SPawel Jakub Dawidek 		fprintf(out, "\n");
4024767ee29SPawel Jakub Dawidek 		fflush(out);
40332115b10SPawel Jakub Dawidek 		break;
40432115b10SPawel Jakub Dawidek 	    }
40532115b10SPawel Jakub Dawidek 	case PJDLOG_MODE_SYSLOG:
40632115b10SPawel Jakub Dawidek 	    {
40732115b10SPawel Jakub Dawidek 		char log[1024];
40832115b10SPawel Jakub Dawidek 		int len;
40932115b10SPawel Jakub Dawidek 
41032115b10SPawel Jakub Dawidek 		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
41132115b10SPawel Jakub Dawidek 		if ((size_t)len < sizeof(log))
41220ec52dcSPawel Jakub Dawidek 			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
41332115b10SPawel Jakub Dawidek 		if (error != -1 && (size_t)len < sizeof(log)) {
41432115b10SPawel Jakub Dawidek 			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
41532115b10SPawel Jakub Dawidek 			    strerror(error));
41632115b10SPawel Jakub Dawidek 		}
41732115b10SPawel Jakub Dawidek 		syslog(loglevel, "%s", log);
41832115b10SPawel Jakub Dawidek 		break;
41932115b10SPawel Jakub Dawidek 	    }
42032115b10SPawel Jakub Dawidek 	default:
42132115b10SPawel Jakub Dawidek 		assert(!"Invalid mode.");
42232115b10SPawel Jakub Dawidek 	}
42380c9ebc2SPawel Jakub Dawidek 
42480c9ebc2SPawel Jakub Dawidek 	errno = saved_errno;
42532115b10SPawel Jakub Dawidek }
42632115b10SPawel Jakub Dawidek 
42732115b10SPawel Jakub Dawidek /*
42832115b10SPawel Jakub Dawidek  * Regular logs.
42932115b10SPawel Jakub Dawidek  */
43032115b10SPawel Jakub Dawidek void
pjdlogv(int loglevel,const char * fmt,va_list ap)43132115b10SPawel Jakub Dawidek pjdlogv(int loglevel, const char *fmt, va_list ap)
43232115b10SPawel Jakub Dawidek {
43332115b10SPawel Jakub Dawidek 
434a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
435eeb3cd67SPawel Jakub Dawidek 
43632115b10SPawel Jakub Dawidek 	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
43732115b10SPawel Jakub Dawidek 	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
43832115b10SPawel Jakub Dawidek 	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
43932115b10SPawel Jakub Dawidek 	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
44032115b10SPawel Jakub Dawidek 	    loglevel == LOG_INFO);
44132115b10SPawel Jakub Dawidek 
44232115b10SPawel Jakub Dawidek 	pjdlogv_common(loglevel, 0, -1, fmt, ap);
44332115b10SPawel Jakub Dawidek }
44432115b10SPawel Jakub Dawidek 
44532115b10SPawel Jakub Dawidek /*
44632115b10SPawel Jakub Dawidek  * Regular logs.
44732115b10SPawel Jakub Dawidek  */
44832115b10SPawel Jakub Dawidek void
pjdlog(int loglevel,const char * fmt,...)44932115b10SPawel Jakub Dawidek pjdlog(int loglevel, const char *fmt, ...)
45032115b10SPawel Jakub Dawidek {
45132115b10SPawel Jakub Dawidek 	va_list ap;
45232115b10SPawel Jakub Dawidek 
453a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
454eeb3cd67SPawel Jakub Dawidek 
45532115b10SPawel Jakub Dawidek 	va_start(ap, fmt);
45632115b10SPawel Jakub Dawidek 	pjdlogv(loglevel, fmt, ap);
45732115b10SPawel Jakub Dawidek 	va_end(ap);
45832115b10SPawel Jakub Dawidek }
45932115b10SPawel Jakub Dawidek 
46032115b10SPawel Jakub Dawidek /*
46132115b10SPawel Jakub Dawidek  * Debug logs.
46232115b10SPawel Jakub Dawidek  */
46332115b10SPawel Jakub Dawidek void
pjdlogv_debug(int debuglevel,const char * fmt,va_list ap)46432115b10SPawel Jakub Dawidek pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
46532115b10SPawel Jakub Dawidek {
46632115b10SPawel Jakub Dawidek 
467a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
468eeb3cd67SPawel Jakub Dawidek 
46932115b10SPawel Jakub Dawidek 	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
47032115b10SPawel Jakub Dawidek }
47132115b10SPawel Jakub Dawidek 
47232115b10SPawel Jakub Dawidek /*
47332115b10SPawel Jakub Dawidek  * Debug logs.
47432115b10SPawel Jakub Dawidek  */
47532115b10SPawel Jakub Dawidek void
pjdlog_debug(int debuglevel,const char * fmt,...)47632115b10SPawel Jakub Dawidek pjdlog_debug(int debuglevel, const char *fmt, ...)
47732115b10SPawel Jakub Dawidek {
47832115b10SPawel Jakub Dawidek 	va_list ap;
47932115b10SPawel Jakub Dawidek 
480a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
481eeb3cd67SPawel Jakub Dawidek 
48232115b10SPawel Jakub Dawidek 	va_start(ap, fmt);
48332115b10SPawel Jakub Dawidek 	pjdlogv_debug(debuglevel, fmt, ap);
48432115b10SPawel Jakub Dawidek 	va_end(ap);
48532115b10SPawel Jakub Dawidek }
48632115b10SPawel Jakub Dawidek 
48732115b10SPawel Jakub Dawidek /*
48832115b10SPawel Jakub Dawidek  * Error logs with errno logging.
48932115b10SPawel Jakub Dawidek  */
49032115b10SPawel Jakub Dawidek void
pjdlogv_errno(int loglevel,const char * fmt,va_list ap)49132115b10SPawel Jakub Dawidek pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
49232115b10SPawel Jakub Dawidek {
49332115b10SPawel Jakub Dawidek 
494a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
495eeb3cd67SPawel Jakub Dawidek 
49632115b10SPawel Jakub Dawidek 	pjdlogv_common(loglevel, 0, errno, fmt, ap);
49732115b10SPawel Jakub Dawidek }
49832115b10SPawel Jakub Dawidek 
49932115b10SPawel Jakub Dawidek /*
50032115b10SPawel Jakub Dawidek  * Error logs with errno logging.
50132115b10SPawel Jakub Dawidek  */
50232115b10SPawel Jakub Dawidek void
pjdlog_errno(int loglevel,const char * fmt,...)50332115b10SPawel Jakub Dawidek pjdlog_errno(int loglevel, const char *fmt, ...)
50432115b10SPawel Jakub Dawidek {
50532115b10SPawel Jakub Dawidek 	va_list ap;
50632115b10SPawel Jakub Dawidek 
507a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
508eeb3cd67SPawel Jakub Dawidek 
50932115b10SPawel Jakub Dawidek 	va_start(ap, fmt);
51032115b10SPawel Jakub Dawidek 	pjdlogv_errno(loglevel, fmt, ap);
51132115b10SPawel Jakub Dawidek 	va_end(ap);
51232115b10SPawel Jakub Dawidek }
51332115b10SPawel Jakub Dawidek 
51432115b10SPawel Jakub Dawidek /*
51532115b10SPawel Jakub Dawidek  * Log error, errno and exit.
51632115b10SPawel Jakub Dawidek  */
51732115b10SPawel Jakub Dawidek void
pjdlogv_exit(int exitcode,const char * fmt,va_list ap)51832115b10SPawel Jakub Dawidek pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
51932115b10SPawel Jakub Dawidek {
52032115b10SPawel Jakub Dawidek 
521a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
522eeb3cd67SPawel Jakub Dawidek 
52332115b10SPawel Jakub Dawidek 	pjdlogv_errno(LOG_ERR, fmt, ap);
52432115b10SPawel Jakub Dawidek 	exit(exitcode);
525e3031161SPawel Jakub Dawidek 	/* NOTREACHED */
52632115b10SPawel Jakub Dawidek }
52732115b10SPawel Jakub Dawidek 
52832115b10SPawel Jakub Dawidek /*
52932115b10SPawel Jakub Dawidek  * Log error, errno and exit.
53032115b10SPawel Jakub Dawidek  */
53132115b10SPawel Jakub Dawidek void
pjdlog_exit(int exitcode,const char * fmt,...)53232115b10SPawel Jakub Dawidek pjdlog_exit(int exitcode, const char *fmt, ...)
53332115b10SPawel Jakub Dawidek {
53432115b10SPawel Jakub Dawidek 	va_list ap;
53532115b10SPawel Jakub Dawidek 
536a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
537eeb3cd67SPawel Jakub Dawidek 
53832115b10SPawel Jakub Dawidek 	va_start(ap, fmt);
53932115b10SPawel Jakub Dawidek 	pjdlogv_exit(exitcode, fmt, ap);
54032115b10SPawel Jakub Dawidek 	/* NOTREACHED */
54132115b10SPawel Jakub Dawidek 	va_end(ap);
54232115b10SPawel Jakub Dawidek }
54332115b10SPawel Jakub Dawidek 
54432115b10SPawel Jakub Dawidek /*
54532115b10SPawel Jakub Dawidek  * Log error and exit.
54632115b10SPawel Jakub Dawidek  */
54732115b10SPawel Jakub Dawidek void
pjdlogv_exitx(int exitcode,const char * fmt,va_list ap)54832115b10SPawel Jakub Dawidek pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
54932115b10SPawel Jakub Dawidek {
55032115b10SPawel Jakub Dawidek 
551a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
552eeb3cd67SPawel Jakub Dawidek 
55332115b10SPawel Jakub Dawidek 	pjdlogv(LOG_ERR, fmt, ap);
55432115b10SPawel Jakub Dawidek 	exit(exitcode);
555e3031161SPawel Jakub Dawidek 	/* NOTREACHED */
55632115b10SPawel Jakub Dawidek }
55732115b10SPawel Jakub Dawidek 
55832115b10SPawel Jakub Dawidek /*
55932115b10SPawel Jakub Dawidek  * Log error and exit.
56032115b10SPawel Jakub Dawidek  */
56132115b10SPawel Jakub Dawidek void
pjdlog_exitx(int exitcode,const char * fmt,...)56232115b10SPawel Jakub Dawidek pjdlog_exitx(int exitcode, const char *fmt, ...)
56332115b10SPawel Jakub Dawidek {
56432115b10SPawel Jakub Dawidek 	va_list ap;
56532115b10SPawel Jakub Dawidek 
566a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
567eeb3cd67SPawel Jakub Dawidek 
56832115b10SPawel Jakub Dawidek 	va_start(ap, fmt);
56932115b10SPawel Jakub Dawidek 	pjdlogv_exitx(exitcode, fmt, ap);
57032115b10SPawel Jakub Dawidek 	/* NOTREACHED */
57132115b10SPawel Jakub Dawidek 	va_end(ap);
57232115b10SPawel Jakub Dawidek }
573524840d8SPawel Jakub Dawidek 
574524840d8SPawel Jakub Dawidek /*
57505a6b8deSPawel Jakub Dawidek  * Log failure message and exit.
576524840d8SPawel Jakub Dawidek  */
577524840d8SPawel Jakub Dawidek void
pjdlog_abort(const char * func,const char * file,int line,const char * failedexpr,const char * fmt,...)57805a6b8deSPawel Jakub Dawidek pjdlog_abort(const char *func, const char *file, int line,
57994bf851dSPawel Jakub Dawidek     const char *failedexpr, const char *fmt, ...)
580524840d8SPawel Jakub Dawidek {
58194bf851dSPawel Jakub Dawidek 	va_list ap;
582524840d8SPawel Jakub Dawidek 
583a61f5793SPawel Jakub Dawidek 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
58494bf851dSPawel Jakub Dawidek 
58594bf851dSPawel Jakub Dawidek 	/*
58694bf851dSPawel Jakub Dawidek 	 * When there is no message we pass __func__ as 'fmt'.
58794bf851dSPawel Jakub Dawidek 	 * It would be cleaner to pass NULL or "", but gcc generates a warning
58894bf851dSPawel Jakub Dawidek 	 * for both of those.
58994bf851dSPawel Jakub Dawidek 	 */
59094bf851dSPawel Jakub Dawidek 	if (fmt != func) {
59194bf851dSPawel Jakub Dawidek 		va_start(ap, fmt);
59294bf851dSPawel Jakub Dawidek 		pjdlogv_critical(fmt, ap);
59394bf851dSPawel Jakub Dawidek 		va_end(ap);
59494bf851dSPawel Jakub Dawidek 	}
59594bf851dSPawel Jakub Dawidek 	if (failedexpr == NULL) {
59694bf851dSPawel Jakub Dawidek 		if (func == NULL) {
59794bf851dSPawel Jakub Dawidek 			pjdlog_critical("Aborted at file %s, line %d.", file,
59894bf851dSPawel Jakub Dawidek 			    line);
59994bf851dSPawel Jakub Dawidek 		} else {
60094bf851dSPawel Jakub Dawidek 			pjdlog_critical("Aborted at function %s, file %s, line %d.",
60194bf851dSPawel Jakub Dawidek 			    func, file, line);
60294bf851dSPawel Jakub Dawidek 		}
60394bf851dSPawel Jakub Dawidek 	} else {
604524840d8SPawel Jakub Dawidek 		if (func == NULL) {
605524840d8SPawel Jakub Dawidek 			pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
606524840d8SPawel Jakub Dawidek 			    failedexpr, file, line);
607524840d8SPawel Jakub Dawidek 		} else {
608524840d8SPawel Jakub Dawidek 			pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
609524840d8SPawel Jakub Dawidek 			    failedexpr, func, file, line);
610524840d8SPawel Jakub Dawidek 		}
61194bf851dSPawel Jakub Dawidek 	}
612524840d8SPawel Jakub Dawidek 	abort();
613524840d8SPawel Jakub Dawidek }
614