1aa772005SRobert Watson /*-
2aa772005SRobert Watson  * Copyright (c) 2009-2010 The FreeBSD Foundation
3aa772005SRobert Watson  * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4aa772005SRobert Watson  * All rights reserved.
5aa772005SRobert Watson  *
6aa772005SRobert Watson  * This software was developed by Pawel Jakub Dawidek under sponsorship from
7aa772005SRobert Watson  * the FreeBSD Foundation.
8aa772005SRobert Watson  *
9aa772005SRobert Watson  * Redistribution and use in source and binary forms, with or without
10aa772005SRobert Watson  * modification, are permitted provided that the following conditions
11aa772005SRobert Watson  * are met:
12aa772005SRobert Watson  * 1. Redistributions of source code must retain the above copyright
13aa772005SRobert Watson  *    notice, this list of conditions and the following disclaimer.
14aa772005SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
15aa772005SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
16aa772005SRobert Watson  *    documentation and/or other materials provided with the distribution.
17aa772005SRobert Watson  *
18aa772005SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19aa772005SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20aa772005SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21aa772005SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22aa772005SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23aa772005SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24aa772005SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25aa772005SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26aa772005SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27aa772005SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28aa772005SRobert Watson  * SUCH DAMAGE.
29aa772005SRobert Watson  */
30aa772005SRobert Watson 
31aa772005SRobert Watson #include <sys/types.h>
32aa772005SRobert Watson #include <sys/socket.h>
33aa772005SRobert Watson #include <netinet/in.h>
34aa772005SRobert Watson #include <arpa/inet.h>
35aa772005SRobert Watson 
36aa772005SRobert Watson #include <assert.h>
37aa772005SRobert Watson #include <errno.h>
38aa772005SRobert Watson #include <stdarg.h>
39aa772005SRobert Watson #include <stdint.h>
40aa772005SRobert Watson #include <stdio.h>
41aa772005SRobert Watson #include <stdlib.h>
42aa772005SRobert Watson #include <string.h>
43aa772005SRobert Watson #include <syslog.h>
44aa772005SRobert Watson #include <unistd.h>
45aa772005SRobert Watson 
46*5e386598SRobert Watson #ifdef __FreeBSD__
47*5e386598SRobert Watson #include <libutil.h>
48*5e386598SRobert Watson #include <printf.h>
49*5e386598SRobert Watson #endif
50*5e386598SRobert Watson 
51aa772005SRobert Watson #include "pjdlog.h"
52aa772005SRobert Watson 
53aa772005SRobert Watson #define	PJDLOG_NEVER_INITIALIZED	0
54aa772005SRobert Watson #define	PJDLOG_NOT_INITIALIZED		1
55aa772005SRobert Watson #define	PJDLOG_INITIALIZED		2
56aa772005SRobert Watson 
57aa772005SRobert Watson static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
58aa772005SRobert Watson static int pjdlog_mode, pjdlog_debug_level;
59aa772005SRobert Watson static char pjdlog_prefix[128];
60aa772005SRobert Watson 
61aa772005SRobert Watson #ifdef __FreeBSD__
62aa772005SRobert Watson static int
pjdlog_printf_arginfo_humanized_number(const struct printf_info * pi __unused,size_t n,int * argt)63aa772005SRobert Watson pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
64aa772005SRobert Watson     size_t n, int *argt)
65aa772005SRobert Watson {
66aa772005SRobert Watson 
67aa772005SRobert Watson 	assert(n >= 1);
68aa772005SRobert Watson 	argt[0] = PA_INT | PA_FLAG_INTMAX;
69aa772005SRobert Watson 	return (1);
70aa772005SRobert Watson }
71aa772005SRobert Watson 
72aa772005SRobert Watson static int
pjdlog_printf_render_humanized_number(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)73aa772005SRobert Watson pjdlog_printf_render_humanized_number(struct __printf_io *io,
74aa772005SRobert Watson     const struct printf_info *pi, const void * const *arg)
75aa772005SRobert Watson {
76aa772005SRobert Watson 	char buf[5];
77aa772005SRobert Watson 	intmax_t num;
78aa772005SRobert Watson 	int ret;
79aa772005SRobert Watson 
80aa772005SRobert Watson 	num = *(const intmax_t *)arg[0];
81aa772005SRobert Watson 	humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
82aa772005SRobert Watson 	    HN_NOSPACE | HN_DECIMAL);
83aa772005SRobert Watson 	ret = __printf_out(io, pi, buf, strlen(buf));
84aa772005SRobert Watson 	__printf_flush(io);
85aa772005SRobert Watson 	return (ret);
86aa772005SRobert Watson }
87aa772005SRobert Watson 
88aa772005SRobert Watson static int
pjdlog_printf_arginfo_sockaddr(const struct printf_info * pi __unused,size_t n,int * argt)89aa772005SRobert Watson pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
90aa772005SRobert Watson     size_t n, int *argt)
91aa772005SRobert Watson {
92aa772005SRobert Watson 
93aa772005SRobert Watson 	assert(n >= 1);
94aa772005SRobert Watson 	argt[0] = PA_POINTER;
95aa772005SRobert Watson 	return (1);
96aa772005SRobert Watson }
97aa772005SRobert Watson 
98aa772005SRobert Watson static int
pjdlog_printf_render_sockaddr(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)99aa772005SRobert Watson pjdlog_printf_render_sockaddr(struct __printf_io *io,
100aa772005SRobert Watson     const struct printf_info *pi, const void * const *arg)
101aa772005SRobert Watson {
102aa772005SRobert Watson 	const struct sockaddr_storage *ss;
103aa772005SRobert Watson 	char buf[64];
104aa772005SRobert Watson 	int ret;
105aa772005SRobert Watson 
106aa772005SRobert Watson 	ss = *(const struct sockaddr_storage * const *)arg[0];
107aa772005SRobert Watson 	switch (ss->ss_family) {
108aa772005SRobert Watson 	case AF_INET:
109aa772005SRobert Watson 	    {
110aa772005SRobert Watson 		char addr[INET_ADDRSTRLEN];
111aa772005SRobert Watson 		const struct sockaddr_in *sin;
112aa772005SRobert Watson 		unsigned int port;
113aa772005SRobert Watson 
114aa772005SRobert Watson 		sin = (const struct sockaddr_in *)ss;
115aa772005SRobert Watson 		port = ntohs(sin->sin_port);
116aa772005SRobert Watson 		if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
117aa772005SRobert Watson 		    sizeof(addr)) == NULL) {
118aa772005SRobert Watson 			PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
119aa772005SRobert Watson 			    strerror(errno));
120aa772005SRobert Watson 		}
121aa772005SRobert Watson 		snprintf(buf, sizeof(buf), "%s:%u", addr, port);
122aa772005SRobert Watson 		break;
123aa772005SRobert Watson 	    }
124aa772005SRobert Watson 	case AF_INET6:
125aa772005SRobert Watson 	    {
126aa772005SRobert Watson 		char addr[INET6_ADDRSTRLEN];
127aa772005SRobert Watson 		const struct sockaddr_in6 *sin;
128aa772005SRobert Watson 		unsigned int port;
129aa772005SRobert Watson 
130aa772005SRobert Watson 		sin = (const struct sockaddr_in6 *)ss;
131aa772005SRobert Watson 		port = ntohs(sin->sin6_port);
132aa772005SRobert Watson 		if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
133aa772005SRobert Watson 		    sizeof(addr)) == NULL) {
134aa772005SRobert Watson 			PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
135aa772005SRobert Watson 			    strerror(errno));
136aa772005SRobert Watson 		}
137aa772005SRobert Watson 		snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
138aa772005SRobert Watson 		break;
139aa772005SRobert Watson 	    }
140aa772005SRobert Watson 	default:
141aa772005SRobert Watson 		snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
142aa772005SRobert Watson 		    ss->ss_family);
143aa772005SRobert Watson 		break;
144aa772005SRobert Watson 	}
145aa772005SRobert Watson 	ret = __printf_out(io, pi, buf, strlen(buf));
146aa772005SRobert Watson 	__printf_flush(io);
147aa772005SRobert Watson 	return (ret);
148aa772005SRobert Watson }
149aa772005SRobert Watson #endif	/* __FreeBSD__ */
150aa772005SRobert Watson 
151aa772005SRobert Watson void
pjdlog_init(int mode)152aa772005SRobert Watson pjdlog_init(int mode)
153aa772005SRobert Watson {
154aa772005SRobert Watson 	int saved_errno;
155aa772005SRobert Watson 
156aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
157aa772005SRobert Watson 	    pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
158aa772005SRobert Watson 	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
159aa772005SRobert Watson 
160aa772005SRobert Watson 	saved_errno = errno;
161aa772005SRobert Watson 
162aa772005SRobert Watson 	if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
163aa772005SRobert Watson #ifdef __FreeBSD__
164aa772005SRobert Watson 		__use_xprintf = 1;
165aa772005SRobert Watson 		register_printf_render_std("T");
166aa772005SRobert Watson 		register_printf_render('N',
167aa772005SRobert Watson 		    pjdlog_printf_render_humanized_number,
168aa772005SRobert Watson 		    pjdlog_printf_arginfo_humanized_number);
169aa772005SRobert Watson 		register_printf_render('S',
170aa772005SRobert Watson 		    pjdlog_printf_render_sockaddr,
171aa772005SRobert Watson 		    pjdlog_printf_arginfo_sockaddr);
172aa772005SRobert Watson #endif
173aa772005SRobert Watson 	}
174aa772005SRobert Watson 
175aa772005SRobert Watson 	if (mode == PJDLOG_MODE_SYSLOG)
176aa772005SRobert Watson 		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
177aa772005SRobert Watson 	pjdlog_mode = mode;
178aa772005SRobert Watson 	pjdlog_debug_level = 0;
179aa772005SRobert Watson 	bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
180aa772005SRobert Watson 
181aa772005SRobert Watson 	pjdlog_initialized = PJDLOG_INITIALIZED;
182aa772005SRobert Watson 
183aa772005SRobert Watson 	errno = saved_errno;
184aa772005SRobert Watson }
185aa772005SRobert Watson 
186aa772005SRobert Watson void
pjdlog_fini(void)187aa772005SRobert Watson pjdlog_fini(void)
188aa772005SRobert Watson {
189aa772005SRobert Watson 	int saved_errno;
190aa772005SRobert Watson 
191aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
192aa772005SRobert Watson 
193aa772005SRobert Watson 	saved_errno = errno;
194aa772005SRobert Watson 
195aa772005SRobert Watson 	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
196aa772005SRobert Watson 		closelog();
197aa772005SRobert Watson 
198aa772005SRobert Watson 	pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
199aa772005SRobert Watson 
200aa772005SRobert Watson 	errno = saved_errno;
201aa772005SRobert Watson }
202aa772005SRobert Watson 
203aa772005SRobert Watson /*
204aa772005SRobert Watson  * Configure where the logs should go.
205aa772005SRobert Watson  * By default they are send to stdout/stderr, but after going into background
206aa772005SRobert Watson  * (eg. by calling daemon(3)) application is responsible for changing mode to
207aa772005SRobert Watson  * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
208aa772005SRobert Watson  */
209aa772005SRobert Watson void
pjdlog_mode_set(int mode)210aa772005SRobert Watson pjdlog_mode_set(int mode)
211aa772005SRobert Watson {
212aa772005SRobert Watson 	int saved_errno;
213aa772005SRobert Watson 
214aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
215aa772005SRobert Watson 	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
216aa772005SRobert Watson 
217aa772005SRobert Watson 	if (pjdlog_mode == mode)
218aa772005SRobert Watson 		return;
219aa772005SRobert Watson 
220aa772005SRobert Watson 	saved_errno = errno;
221aa772005SRobert Watson 
222aa772005SRobert Watson 	if (mode == PJDLOG_MODE_SYSLOG)
223aa772005SRobert Watson 		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
224aa772005SRobert Watson 	else /* if (mode == PJDLOG_MODE_STD) */
225aa772005SRobert Watson 		closelog();
226aa772005SRobert Watson 
227aa772005SRobert Watson 	pjdlog_mode = mode;
228aa772005SRobert Watson 
229aa772005SRobert Watson 	errno = saved_errno;
230aa772005SRobert Watson }
231aa772005SRobert Watson 
232aa772005SRobert Watson /*
233aa772005SRobert Watson  * Return current mode.
234aa772005SRobert Watson  */
235aa772005SRobert Watson int
pjdlog_mode_get(void)236aa772005SRobert Watson pjdlog_mode_get(void)
237aa772005SRobert Watson {
238aa772005SRobert Watson 
239aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
240aa772005SRobert Watson 
241aa772005SRobert Watson 	return (pjdlog_mode);
242aa772005SRobert Watson }
243aa772005SRobert Watson 
244aa772005SRobert Watson /*
245aa772005SRobert Watson  * Set debug level. All the logs above the level specified here will be
246aa772005SRobert Watson  * ignored.
247aa772005SRobert Watson  */
248aa772005SRobert Watson void
pjdlog_debug_set(int level)249aa772005SRobert Watson pjdlog_debug_set(int level)
250aa772005SRobert Watson {
251aa772005SRobert Watson 
252aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
253aa772005SRobert Watson 	assert(level >= 0);
254aa772005SRobert Watson 
255aa772005SRobert Watson 	pjdlog_debug_level = level;
256aa772005SRobert Watson }
257aa772005SRobert Watson 
258aa772005SRobert Watson /*
259aa772005SRobert Watson  * Return current debug level.
260aa772005SRobert Watson  */
261aa772005SRobert Watson int
pjdlog_debug_get(void)262aa772005SRobert Watson pjdlog_debug_get(void)
263aa772005SRobert Watson {
264aa772005SRobert Watson 
265aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
266aa772005SRobert Watson 
267aa772005SRobert Watson 	return (pjdlog_debug_level);
268aa772005SRobert Watson }
269aa772005SRobert Watson 
270aa772005SRobert Watson /*
271aa772005SRobert Watson  * Set prefix that will be used before each log.
272aa772005SRobert Watson  * Setting prefix to NULL will remove it.
273aa772005SRobert Watson  */
274aa772005SRobert Watson void
pjdlog_prefix_set(const char * fmt,...)275aa772005SRobert Watson pjdlog_prefix_set(const char *fmt, ...)
276aa772005SRobert Watson {
277aa772005SRobert Watson 	va_list ap;
278aa772005SRobert Watson 
279aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
280aa772005SRobert Watson 
281aa772005SRobert Watson 	va_start(ap, fmt);
282aa772005SRobert Watson 	pjdlogv_prefix_set(fmt, ap);
283aa772005SRobert Watson 	va_end(ap);
284aa772005SRobert Watson }
285aa772005SRobert Watson 
286aa772005SRobert Watson /*
287aa772005SRobert Watson  * Set prefix that will be used before each log.
288aa772005SRobert Watson  * Setting prefix to NULL will remove it.
289aa772005SRobert Watson  */
290aa772005SRobert Watson void
pjdlogv_prefix_set(const char * fmt,va_list ap)291aa772005SRobert Watson pjdlogv_prefix_set(const char *fmt, va_list ap)
292aa772005SRobert Watson {
293aa772005SRobert Watson 	int saved_errno;
294aa772005SRobert Watson 
295aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
296aa772005SRobert Watson 	assert(fmt != NULL);
297aa772005SRobert Watson 
298aa772005SRobert Watson 	saved_errno = errno;
299aa772005SRobert Watson 
300aa772005SRobert Watson 	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
301aa772005SRobert Watson 
302aa772005SRobert Watson 	errno = saved_errno;
303aa772005SRobert Watson }
304aa772005SRobert Watson 
305aa772005SRobert Watson /*
306aa772005SRobert Watson  * Convert log level into string.
307aa772005SRobert Watson  */
308aa772005SRobert Watson static const char *
pjdlog_level_string(int loglevel)309aa772005SRobert Watson pjdlog_level_string(int loglevel)
310aa772005SRobert Watson {
311aa772005SRobert Watson 
312aa772005SRobert Watson 	switch (loglevel) {
313aa772005SRobert Watson 	case LOG_EMERG:
314aa772005SRobert Watson 		return ("EMERG");
315aa772005SRobert Watson 	case LOG_ALERT:
316aa772005SRobert Watson 		return ("ALERT");
317aa772005SRobert Watson 	case LOG_CRIT:
318aa772005SRobert Watson 		return ("CRIT");
319aa772005SRobert Watson 	case LOG_ERR:
320aa772005SRobert Watson 		return ("ERROR");
321aa772005SRobert Watson 	case LOG_WARNING:
322aa772005SRobert Watson 		return ("WARNING");
323aa772005SRobert Watson 	case LOG_NOTICE:
324aa772005SRobert Watson 		return ("NOTICE");
325aa772005SRobert Watson 	case LOG_INFO:
326aa772005SRobert Watson 		return ("INFO");
327aa772005SRobert Watson 	case LOG_DEBUG:
328aa772005SRobert Watson 		return ("DEBUG");
329aa772005SRobert Watson 	}
330aa772005SRobert Watson 	assert(!"Invalid log level.");
331aa772005SRobert Watson 	abort();	/* XXX: gcc */
332aa772005SRobert Watson }
333aa772005SRobert Watson 
334aa772005SRobert Watson /*
335aa772005SRobert Watson  * Common log routine.
336aa772005SRobert Watson  */
337aa772005SRobert Watson void
pjdlog_common(int loglevel,int debuglevel,int error,const char * fmt,...)338aa772005SRobert Watson pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
339aa772005SRobert Watson {
340aa772005SRobert Watson 	va_list ap;
341aa772005SRobert Watson 
342aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
343aa772005SRobert Watson 
344aa772005SRobert Watson 	va_start(ap, fmt);
345aa772005SRobert Watson 	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
346aa772005SRobert Watson 	va_end(ap);
347aa772005SRobert Watson }
348aa772005SRobert Watson 
349aa772005SRobert Watson /*
350aa772005SRobert Watson  * Common log routine, which can handle regular log level as well as debug
351aa772005SRobert Watson  * level. We decide here where to send the logs (stdout/stderr or syslog).
352aa772005SRobert Watson  */
353aa772005SRobert Watson void
pjdlogv_common(int loglevel,int debuglevel,int error,const char * fmt,va_list ap)354aa772005SRobert Watson pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
355aa772005SRobert Watson     va_list ap)
356aa772005SRobert Watson {
357aa772005SRobert Watson 	int saved_errno;
358aa772005SRobert Watson 
359aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
360aa772005SRobert Watson 	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
361aa772005SRobert Watson 	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
362aa772005SRobert Watson 	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
363aa772005SRobert Watson 	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
364aa772005SRobert Watson 	assert(loglevel != LOG_DEBUG || debuglevel > 0);
365aa772005SRobert Watson 	assert(error >= -1);
366aa772005SRobert Watson 
367aa772005SRobert Watson 	/* Ignore debug above configured level. */
368aa772005SRobert Watson 	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
369aa772005SRobert Watson 		return;
370aa772005SRobert Watson 
371aa772005SRobert Watson 	saved_errno = errno;
372aa772005SRobert Watson 
373aa772005SRobert Watson 	switch (pjdlog_mode) {
374aa772005SRobert Watson 	case PJDLOG_MODE_STD:
375aa772005SRobert Watson 	    {
376aa772005SRobert Watson 		FILE *out;
377aa772005SRobert Watson 
378aa772005SRobert Watson 		/*
379aa772005SRobert Watson 		 * We send errors and warning to stderr and the rest to stdout.
380aa772005SRobert Watson 		 */
381aa772005SRobert Watson 		switch (loglevel) {
382aa772005SRobert Watson 		case LOG_EMERG:
383aa772005SRobert Watson 		case LOG_ALERT:
384aa772005SRobert Watson 		case LOG_CRIT:
385aa772005SRobert Watson 		case LOG_ERR:
386aa772005SRobert Watson 		case LOG_WARNING:
387aa772005SRobert Watson 			out = stderr;
388aa772005SRobert Watson 			break;
389aa772005SRobert Watson 		case LOG_NOTICE:
390aa772005SRobert Watson 		case LOG_INFO:
391aa772005SRobert Watson 		case LOG_DEBUG:
392aa772005SRobert Watson 			out = stdout;
393aa772005SRobert Watson 			break;
394aa772005SRobert Watson 		default:
395aa772005SRobert Watson 			assert(!"Invalid loglevel.");
396aa772005SRobert Watson 			abort();	/* XXX: gcc */
397aa772005SRobert Watson 		}
398aa772005SRobert Watson 
399aa772005SRobert Watson 		fprintf(out, "(%d) ", getpid());
400aa772005SRobert Watson 		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
401aa772005SRobert Watson 		/* Attach debuglevel if this is debug log. */
402aa772005SRobert Watson 		if (loglevel == LOG_DEBUG)
403aa772005SRobert Watson 			fprintf(out, "[%d]", debuglevel);
404aa772005SRobert Watson 		fprintf(out, " %s", pjdlog_prefix);
405aa772005SRobert Watson 		vfprintf(out, fmt, ap);
406aa772005SRobert Watson 		if (error != -1)
407aa772005SRobert Watson 			fprintf(out, ": %s.", strerror(error));
408aa772005SRobert Watson 		fprintf(out, "\n");
409aa772005SRobert Watson 		fflush(out);
410aa772005SRobert Watson 		break;
411aa772005SRobert Watson 	    }
412aa772005SRobert Watson 	case PJDLOG_MODE_SYSLOG:
413aa772005SRobert Watson 	    {
414aa772005SRobert Watson 		char log[1024];
415aa772005SRobert Watson 		int len;
416aa772005SRobert Watson 
417aa772005SRobert Watson 		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
418aa772005SRobert Watson 		if ((size_t)len < sizeof(log))
419aa772005SRobert Watson 			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
420aa772005SRobert Watson 		if (error != -1 && (size_t)len < sizeof(log)) {
421aa772005SRobert Watson 			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
422aa772005SRobert Watson 			    strerror(error));
423aa772005SRobert Watson 		}
424aa772005SRobert Watson 		syslog(loglevel, "%s", log);
425aa772005SRobert Watson 		break;
426aa772005SRobert Watson 	    }
427aa772005SRobert Watson 	default:
428aa772005SRobert Watson 		assert(!"Invalid mode.");
429aa772005SRobert Watson 	}
430aa772005SRobert Watson 
431aa772005SRobert Watson 	errno = saved_errno;
432aa772005SRobert Watson }
433aa772005SRobert Watson 
434aa772005SRobert Watson /*
435aa772005SRobert Watson  * Regular logs.
436aa772005SRobert Watson  */
437aa772005SRobert Watson void
pjdlogv(int loglevel,const char * fmt,va_list ap)438aa772005SRobert Watson pjdlogv(int loglevel, const char *fmt, va_list ap)
439aa772005SRobert Watson {
440aa772005SRobert Watson 
441aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
442aa772005SRobert Watson 
443aa772005SRobert Watson 	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
444aa772005SRobert Watson 	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
445aa772005SRobert Watson 	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
446aa772005SRobert Watson 	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
447aa772005SRobert Watson 	    loglevel == LOG_INFO);
448aa772005SRobert Watson 
449aa772005SRobert Watson 	pjdlogv_common(loglevel, 0, -1, fmt, ap);
450aa772005SRobert Watson }
451aa772005SRobert Watson 
452aa772005SRobert Watson /*
453aa772005SRobert Watson  * Regular logs.
454aa772005SRobert Watson  */
455aa772005SRobert Watson void
pjdlog(int loglevel,const char * fmt,...)456aa772005SRobert Watson pjdlog(int loglevel, const char *fmt, ...)
457aa772005SRobert Watson {
458aa772005SRobert Watson 	va_list ap;
459aa772005SRobert Watson 
460aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
461aa772005SRobert Watson 
462aa772005SRobert Watson 	va_start(ap, fmt);
463aa772005SRobert Watson 	pjdlogv(loglevel, fmt, ap);
464aa772005SRobert Watson 	va_end(ap);
465aa772005SRobert Watson }
466aa772005SRobert Watson 
467aa772005SRobert Watson /*
468aa772005SRobert Watson  * Debug logs.
469aa772005SRobert Watson  */
470aa772005SRobert Watson void
pjdlogv_debug(int debuglevel,const char * fmt,va_list ap)471aa772005SRobert Watson pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
472aa772005SRobert Watson {
473aa772005SRobert Watson 
474aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
475aa772005SRobert Watson 
476aa772005SRobert Watson 	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
477aa772005SRobert Watson }
478aa772005SRobert Watson 
479aa772005SRobert Watson /*
480aa772005SRobert Watson  * Debug logs.
481aa772005SRobert Watson  */
482aa772005SRobert Watson void
pjdlog_debug(int debuglevel,const char * fmt,...)483aa772005SRobert Watson pjdlog_debug(int debuglevel, const char *fmt, ...)
484aa772005SRobert Watson {
485aa772005SRobert Watson 	va_list ap;
486aa772005SRobert Watson 
487aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
488aa772005SRobert Watson 
489aa772005SRobert Watson 	va_start(ap, fmt);
490aa772005SRobert Watson 	pjdlogv_debug(debuglevel, fmt, ap);
491aa772005SRobert Watson 	va_end(ap);
492aa772005SRobert Watson }
493aa772005SRobert Watson 
494aa772005SRobert Watson /*
495aa772005SRobert Watson  * Error logs with errno logging.
496aa772005SRobert Watson  */
497aa772005SRobert Watson void
pjdlogv_errno(int loglevel,const char * fmt,va_list ap)498aa772005SRobert Watson pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
499aa772005SRobert Watson {
500aa772005SRobert Watson 
501aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
502aa772005SRobert Watson 
503aa772005SRobert Watson 	pjdlogv_common(loglevel, 0, errno, fmt, ap);
504aa772005SRobert Watson }
505aa772005SRobert Watson 
506aa772005SRobert Watson /*
507aa772005SRobert Watson  * Error logs with errno logging.
508aa772005SRobert Watson  */
509aa772005SRobert Watson void
pjdlog_errno(int loglevel,const char * fmt,...)510aa772005SRobert Watson pjdlog_errno(int loglevel, const char *fmt, ...)
511aa772005SRobert Watson {
512aa772005SRobert Watson 	va_list ap;
513aa772005SRobert Watson 
514aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
515aa772005SRobert Watson 
516aa772005SRobert Watson 	va_start(ap, fmt);
517aa772005SRobert Watson 	pjdlogv_errno(loglevel, fmt, ap);
518aa772005SRobert Watson 	va_end(ap);
519aa772005SRobert Watson }
520aa772005SRobert Watson 
521aa772005SRobert Watson /*
522aa772005SRobert Watson  * Log error, errno and exit.
523aa772005SRobert Watson  */
524aa772005SRobert Watson void
pjdlogv_exit(int exitcode,const char * fmt,va_list ap)525aa772005SRobert Watson pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
526aa772005SRobert Watson {
527aa772005SRobert Watson 
528aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
529aa772005SRobert Watson 
530aa772005SRobert Watson 	pjdlogv_errno(LOG_ERR, fmt, ap);
531aa772005SRobert Watson 	exit(exitcode);
532aa772005SRobert Watson 	/* NOTREACHED */
533aa772005SRobert Watson }
534aa772005SRobert Watson 
535aa772005SRobert Watson /*
536aa772005SRobert Watson  * Log error, errno and exit.
537aa772005SRobert Watson  */
538aa772005SRobert Watson void
pjdlog_exit(int exitcode,const char * fmt,...)539aa772005SRobert Watson pjdlog_exit(int exitcode, const char *fmt, ...)
540aa772005SRobert Watson {
541aa772005SRobert Watson 	va_list ap;
542aa772005SRobert Watson 
543aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
544aa772005SRobert Watson 
545aa772005SRobert Watson 	va_start(ap, fmt);
546aa772005SRobert Watson 	pjdlogv_exit(exitcode, fmt, ap);
547aa772005SRobert Watson 	/* NOTREACHED */
548aa772005SRobert Watson 	va_end(ap);
549aa772005SRobert Watson }
550aa772005SRobert Watson 
551aa772005SRobert Watson /*
552aa772005SRobert Watson  * Log error and exit.
553aa772005SRobert Watson  */
554aa772005SRobert Watson void
pjdlogv_exitx(int exitcode,const char * fmt,va_list ap)555aa772005SRobert Watson pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
556aa772005SRobert Watson {
557aa772005SRobert Watson 
558aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
559aa772005SRobert Watson 
560aa772005SRobert Watson 	pjdlogv(LOG_ERR, fmt, ap);
561aa772005SRobert Watson 	exit(exitcode);
562aa772005SRobert Watson 	/* NOTREACHED */
563aa772005SRobert Watson }
564aa772005SRobert Watson 
565aa772005SRobert Watson /*
566aa772005SRobert Watson  * Log error and exit.
567aa772005SRobert Watson  */
568aa772005SRobert Watson void
pjdlog_exitx(int exitcode,const char * fmt,...)569aa772005SRobert Watson pjdlog_exitx(int exitcode, const char *fmt, ...)
570aa772005SRobert Watson {
571aa772005SRobert Watson 	va_list ap;
572aa772005SRobert Watson 
573aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
574aa772005SRobert Watson 
575aa772005SRobert Watson 	va_start(ap, fmt);
576aa772005SRobert Watson 	pjdlogv_exitx(exitcode, fmt, ap);
577aa772005SRobert Watson 	/* NOTREACHED */
578aa772005SRobert Watson 	va_end(ap);
579aa772005SRobert Watson }
580aa772005SRobert Watson 
581aa772005SRobert Watson /*
582aa772005SRobert Watson  * Log failure message and exit.
583aa772005SRobert Watson  */
584aa772005SRobert Watson void
pjdlog_abort(const char * func,const char * file,int line,const char * failedexpr,const char * fmt,...)585aa772005SRobert Watson pjdlog_abort(const char *func, const char *file, int line,
586aa772005SRobert Watson     const char *failedexpr, const char *fmt, ...)
587aa772005SRobert Watson {
588aa772005SRobert Watson 	va_list ap;
589aa772005SRobert Watson 
590aa772005SRobert Watson 	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
591aa772005SRobert Watson 
592aa772005SRobert Watson 	/*
593aa772005SRobert Watson 	 * When there is no message we pass __func__ as 'fmt'.
594aa772005SRobert Watson 	 * It would be cleaner to pass NULL or "", but gcc generates a warning
595aa772005SRobert Watson 	 * for both of those.
596aa772005SRobert Watson 	 */
597aa772005SRobert Watson 	if (fmt != func) {
598aa772005SRobert Watson 		va_start(ap, fmt);
599aa772005SRobert Watson 		pjdlogv_critical(fmt, ap);
600aa772005SRobert Watson 		va_end(ap);
601aa772005SRobert Watson 	}
602aa772005SRobert Watson 	if (failedexpr == NULL) {
603aa772005SRobert Watson 		if (func == NULL) {
604aa772005SRobert Watson 			pjdlog_critical("Aborted at file %s, line %d.", file,
605aa772005SRobert Watson 			    line);
606aa772005SRobert Watson 		} else {
607aa772005SRobert Watson 			pjdlog_critical("Aborted at function %s, file %s, line %d.",
608aa772005SRobert Watson 			    func, file, line);
609aa772005SRobert Watson 		}
610aa772005SRobert Watson 	} else {
611aa772005SRobert Watson 		if (func == NULL) {
612aa772005SRobert Watson 			pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
613aa772005SRobert Watson 			    failedexpr, file, line);
614aa772005SRobert Watson 		} else {
615aa772005SRobert Watson 			pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
616aa772005SRobert Watson 			    failedexpr, func, file, line);
617aa772005SRobert Watson 		}
618aa772005SRobert Watson 	}
619aa772005SRobert Watson 	abort();
620aa772005SRobert Watson }
621