1204076Spjd/*-
2217964Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation
3217964Spjd * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4204076Spjd * All rights reserved.
5204076Spjd *
6204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
7204076Spjd * the FreeBSD Foundation.
8204076Spjd *
9204076Spjd * Redistribution and use in source and binary forms, with or without
10204076Spjd * modification, are permitted provided that the following conditions
11204076Spjd * are met:
12204076Spjd * 1. Redistributions of source code must retain the above copyright
13204076Spjd *    notice, this list of conditions and the following disclaimer.
14204076Spjd * 2. Redistributions in binary form must reproduce the above copyright
15204076Spjd *    notice, this list of conditions and the following disclaimer in the
16204076Spjd *    documentation and/or other materials provided with the distribution.
17204076Spjd *
18204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21204076Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28204076Spjd * SUCH DAMAGE.
29204076Spjd */
30204076Spjd
31204076Spjd#include <sys/cdefs.h>
32204076Spjd__FBSDID("$FreeBSD$");
33204076Spjd
34222087Spjd#include <sys/types.h>
35219370Spjd#include <sys/socket.h>
36219370Spjd#include <netinet/in.h>
37222087Spjd#include <arpa/inet.h>
38219370Spjd
39204076Spjd#include <assert.h>
40204076Spjd#include <errno.h>
41219370Spjd#include <libutil.h>
42219370Spjd#include <printf.h>
43204076Spjd#include <stdarg.h>
44219370Spjd#include <stdint.h>
45204076Spjd#include <stdio.h>
46204076Spjd#include <stdlib.h>
47204076Spjd#include <string.h>
48204076Spjd#include <syslog.h>
49204076Spjd
50204076Spjd#include "pjdlog.h"
51204076Spjd
52219369Spjd#define	PJDLOG_NEVER_INITIALIZED	0
53219369Spjd#define	PJDLOG_NOT_INITIALIZED		1
54219369Spjd#define	PJDLOG_INITIALIZED		2
55219369Spjd
56219369Spjdstatic int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
57218040Spjdstatic int pjdlog_mode, pjdlog_debug_level;
58204076Spjdstatic char pjdlog_prefix[128];
59204076Spjd
60219370Spjdstatic int
61219370Spjdpjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
62219370Spjd    size_t n, int *argt)
63219370Spjd{
64219370Spjd
65219370Spjd	assert(n >= 1);
66219370Spjd	argt[0] = PA_INT | PA_FLAG_INTMAX;
67219370Spjd	return (1);
68219370Spjd}
69219370Spjd
70219370Spjdstatic int
71219370Spjdpjdlog_printf_render_humanized_number(struct __printf_io *io,
72219370Spjd    const struct printf_info *pi, const void * const *arg)
73219370Spjd{
74219370Spjd	char buf[5];
75219370Spjd	intmax_t num;
76219370Spjd	int ret;
77219370Spjd
78219370Spjd	num = *(const intmax_t *)arg[0];
79219370Spjd	humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
80219370Spjd	    HN_NOSPACE | HN_DECIMAL);
81219370Spjd	ret = __printf_out(io, pi, buf, strlen(buf));
82219370Spjd	__printf_flush(io);
83219370Spjd	return (ret);
84219370Spjd}
85219370Spjd
86219370Spjdstatic int
87219370Spjdpjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
88219370Spjd    size_t n, int *argt)
89219370Spjd{
90219370Spjd
91219370Spjd	assert(n >= 1);
92219370Spjd	argt[0] = PA_POINTER;
93219370Spjd	return (1);
94219370Spjd}
95219370Spjd
96219370Spjdstatic int
97219370Spjdpjdlog_printf_render_sockaddr(struct __printf_io *io,
98219370Spjd    const struct printf_info *pi, const void * const *arg)
99219370Spjd{
100219385Spjd	const struct sockaddr_storage *ss;
101219370Spjd	char buf[64];
102219370Spjd	int ret;
103219370Spjd
104219385Spjd	ss = *(const struct sockaddr_storage * const *)arg[0];
105219385Spjd	switch (ss->ss_family) {
106219370Spjd	case AF_INET:
107219370Spjd	    {
108222087Spjd		char addr[INET_ADDRSTRLEN];
109219370Spjd		const struct sockaddr_in *sin;
110219370Spjd		unsigned int port;
111219370Spjd
112219385Spjd		sin = (const struct sockaddr_in *)ss;
113219370Spjd		port = ntohs(sin->sin_port);
114222087Spjd		if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
115222087Spjd		    sizeof(addr)) == NULL) {
116222087Spjd			PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
117222087Spjd			    strerror(errno));
118222087Spjd		}
119222087Spjd		snprintf(buf, sizeof(buf), "%s:%u", addr, port);
120222087Spjd		break;
121222087Spjd	    }
122222087Spjd	case AF_INET6:
123222087Spjd	    {
124222087Spjd		char addr[INET6_ADDRSTRLEN];
125222087Spjd		const struct sockaddr_in6 *sin;
126222087Spjd		unsigned int port;
127219370Spjd
128222087Spjd		sin = (const struct sockaddr_in6 *)ss;
129222087Spjd		port = ntohs(sin->sin6_port);
130222087Spjd		if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
131222087Spjd		    sizeof(addr)) == NULL) {
132222087Spjd			PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
133222087Spjd			    strerror(errno));
134222087Spjd		}
135222087Spjd		snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
136219370Spjd		break;
137219370Spjd	    }
138219370Spjd	default:
139222087Spjd		snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
140222087Spjd		    ss->ss_family);
141219370Spjd		break;
142219370Spjd	}
143219370Spjd	ret = __printf_out(io, pi, buf, strlen(buf));
144219370Spjd	__printf_flush(io);
145219370Spjd	return (ret);
146219370Spjd}
147219370Spjd
148217965Spjdvoid
149217965Spjdpjdlog_init(int mode)
150217965Spjd{
151229509Strociny	int saved_errno;
152217965Spjd
153219369Spjd	assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
154219369Spjd	    pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
155217965Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
156217965Spjd
157229509Strociny	saved_errno = errno;
158229509Strociny
159219370Spjd	if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
160219370Spjd		__use_xprintf = 1;
161219370Spjd		register_printf_render_std("T");
162219370Spjd		register_printf_render('N',
163219370Spjd		    pjdlog_printf_render_humanized_number,
164219370Spjd		    pjdlog_printf_arginfo_humanized_number);
165219370Spjd		register_printf_render('S',
166219370Spjd		    pjdlog_printf_render_sockaddr,
167219370Spjd		    pjdlog_printf_arginfo_sockaddr);
168219370Spjd	}
169219370Spjd
170217965Spjd	if (mode == PJDLOG_MODE_SYSLOG)
171217965Spjd		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
172217965Spjd	pjdlog_mode = mode;
173218040Spjd	pjdlog_debug_level = 0;
174218040Spjd	bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
175217965Spjd
176219369Spjd	pjdlog_initialized = PJDLOG_INITIALIZED;
177229509Strociny
178229509Strociny	errno = saved_errno;
179217965Spjd}
180217965Spjd
181217965Spjdvoid
182217965Spjdpjdlog_fini(void)
183217965Spjd{
184229509Strociny	int saved_errno;
185217965Spjd
186219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
187217965Spjd
188229509Strociny	saved_errno = errno;
189229509Strociny
190217965Spjd	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
191217965Spjd		closelog();
192217965Spjd
193219369Spjd	pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
194229509Strociny
195229509Strociny	errno = saved_errno;
196217965Spjd}
197217965Spjd
198204076Spjd/*
199204076Spjd * Configure where the logs should go.
200204076Spjd * By default they are send to stdout/stderr, but after going into background
201204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to
202204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
203204076Spjd */
204204076Spjdvoid
205204076Spjdpjdlog_mode_set(int mode)
206204076Spjd{
207229509Strociny	int saved_errno;
208204076Spjd
209219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
210204076Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
211204076Spjd
212217965Spjd	if (pjdlog_mode == mode)
213217965Spjd		return;
214212052Spjd
215229509Strociny	saved_errno = errno;
216229509Strociny
217212052Spjd	if (mode == PJDLOG_MODE_SYSLOG)
218217962Spjd		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
219217965Spjd	else /* if (mode == PJDLOG_MODE_STD) */
220217965Spjd		closelog();
221217965Spjd
222217965Spjd	pjdlog_mode = mode;
223229509Strociny
224229509Strociny	errno = saved_errno;
225204076Spjd}
226204076Spjd
227204076Spjd/*
228204076Spjd * Return current mode.
229204076Spjd */
230204076Spjdint
231204076Spjdpjdlog_mode_get(void)
232204076Spjd{
233204076Spjd
234219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
235217965Spjd
236204076Spjd	return (pjdlog_mode);
237204076Spjd}
238204076Spjd
239204076Spjd/*
240204076Spjd * Set debug level. All the logs above the level specified here will be
241204076Spjd * ignored.
242204076Spjd */
243204076Spjdvoid
244204076Spjdpjdlog_debug_set(int level)
245204076Spjd{
246204076Spjd
247219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
248204076Spjd	assert(level >= 0);
249204076Spjd
250204076Spjd	pjdlog_debug_level = level;
251204076Spjd}
252204076Spjd
253204076Spjd/*
254204076Spjd * Return current debug level.
255204076Spjd */
256204076Spjdint
257204076Spjdpjdlog_debug_get(void)
258204076Spjd{
259204076Spjd
260219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
261217965Spjd
262204076Spjd	return (pjdlog_debug_level);
263204076Spjd}
264204076Spjd
265204076Spjd/*
266204076Spjd * Set prefix that will be used before each log.
267204076Spjd * Setting prefix to NULL will remove it.
268204076Spjd */
269204076Spjdvoid
270204076Spjdpjdlog_prefix_set(const char *fmt, ...)
271204076Spjd{
272204076Spjd	va_list ap;
273204076Spjd
274219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
275217965Spjd
276204076Spjd	va_start(ap, fmt);
277217731Spjd	pjdlogv_prefix_set(fmt, ap);
278204076Spjd	va_end(ap);
279204076Spjd}
280204076Spjd
281204076Spjd/*
282204076Spjd * Set prefix that will be used before each log.
283204076Spjd * Setting prefix to NULL will remove it.
284204076Spjd */
285204076Spjdvoid
286217731Spjdpjdlogv_prefix_set(const char *fmt, va_list ap)
287204076Spjd{
288229509Strociny	int saved_errno;
289204076Spjd
290219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
291204076Spjd	assert(fmt != NULL);
292204076Spjd
293229509Strociny	saved_errno = errno;
294229509Strociny
295204076Spjd	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
296229509Strociny
297229509Strociny	errno = saved_errno;
298204076Spjd}
299204076Spjd
300204076Spjd/*
301204076Spjd * Convert log level into string.
302204076Spjd */
303204076Spjdstatic const char *
304204076Spjdpjdlog_level_string(int loglevel)
305204076Spjd{
306204076Spjd
307204076Spjd	switch (loglevel) {
308204076Spjd	case LOG_EMERG:
309204076Spjd		return ("EMERG");
310204076Spjd	case LOG_ALERT:
311204076Spjd		return ("ALERT");
312204076Spjd	case LOG_CRIT:
313204076Spjd		return ("CRIT");
314204076Spjd	case LOG_ERR:
315204076Spjd		return ("ERROR");
316204076Spjd	case LOG_WARNING:
317204076Spjd		return ("WARNING");
318204076Spjd	case LOG_NOTICE:
319204076Spjd		return ("NOTICE");
320204076Spjd	case LOG_INFO:
321204076Spjd		return ("INFO");
322204076Spjd	case LOG_DEBUG:
323204076Spjd		return ("DEBUG");
324204076Spjd	}
325204076Spjd	assert(!"Invalid log level.");
326204076Spjd	abort();	/* XXX: gcc */
327204076Spjd}
328204076Spjd
329204076Spjd/*
330204076Spjd * Common log routine.
331204076Spjd */
332204076Spjdvoid
333204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
334204076Spjd{
335204076Spjd	va_list ap;
336204076Spjd
337219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
338217965Spjd
339204076Spjd	va_start(ap, fmt);
340204076Spjd	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
341204076Spjd	va_end(ap);
342204076Spjd}
343204076Spjd
344204076Spjd/*
345204076Spjd * Common log routine, which can handle regular log level as well as debug
346204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog).
347204076Spjd */
348204076Spjdvoid
349204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
350204076Spjd    va_list ap)
351204076Spjd{
352229509Strociny	int saved_errno;
353204076Spjd
354219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
355204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
356204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
357204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
358204076Spjd	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
359204076Spjd	assert(loglevel != LOG_DEBUG || debuglevel > 0);
360204076Spjd	assert(error >= -1);
361204076Spjd
362204076Spjd	/* Ignore debug above configured level. */
363204076Spjd	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
364204076Spjd		return;
365204076Spjd
366229509Strociny	saved_errno = errno;
367229509Strociny
368204076Spjd	switch (pjdlog_mode) {
369204076Spjd	case PJDLOG_MODE_STD:
370204076Spjd	    {
371204076Spjd		FILE *out;
372204076Spjd
373204076Spjd		/*
374204076Spjd		 * We send errors and warning to stderr and the rest to stdout.
375204076Spjd		 */
376204076Spjd		switch (loglevel) {
377204076Spjd		case LOG_EMERG:
378204076Spjd		case LOG_ALERT:
379204076Spjd		case LOG_CRIT:
380204076Spjd		case LOG_ERR:
381204076Spjd		case LOG_WARNING:
382204076Spjd			out = stderr;
383204076Spjd			break;
384204076Spjd		case LOG_NOTICE:
385204076Spjd		case LOG_INFO:
386204076Spjd		case LOG_DEBUG:
387204076Spjd			out = stdout;
388204076Spjd			break;
389204076Spjd		default:
390204076Spjd			assert(!"Invalid loglevel.");
391204076Spjd			abort();	/* XXX: gcc */
392204076Spjd		}
393204076Spjd
394204076Spjd		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
395204076Spjd		/* Attach debuglevel if this is debug log. */
396204076Spjd		if (loglevel == LOG_DEBUG)
397204076Spjd			fprintf(out, "[%d]", debuglevel);
398213939Spjd		fprintf(out, " %s", pjdlog_prefix);
399204076Spjd		vfprintf(out, fmt, ap);
400204076Spjd		if (error != -1)
401204076Spjd			fprintf(out, ": %s.", strerror(error));
402204076Spjd		fprintf(out, "\n");
403211898Spjd		fflush(out);
404204076Spjd		break;
405204076Spjd	    }
406204076Spjd	case PJDLOG_MODE_SYSLOG:
407204076Spjd	    {
408204076Spjd		char log[1024];
409204076Spjd		int len;
410204076Spjd
411204076Spjd		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
412204076Spjd		if ((size_t)len < sizeof(log))
413206697Spjd			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
414204076Spjd		if (error != -1 && (size_t)len < sizeof(log)) {
415204076Spjd			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
416204076Spjd			    strerror(error));
417204076Spjd		}
418204076Spjd		syslog(loglevel, "%s", log);
419204076Spjd		break;
420204076Spjd	    }
421204076Spjd	default:
422204076Spjd		assert(!"Invalid mode.");
423204076Spjd	}
424229509Strociny
425229509Strociny	errno = saved_errno;
426204076Spjd}
427204076Spjd
428204076Spjd/*
429204076Spjd * Regular logs.
430204076Spjd */
431204076Spjdvoid
432204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap)
433204076Spjd{
434204076Spjd
435219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
436217965Spjd
437204076Spjd	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
438204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
439204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
440204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
441204076Spjd	    loglevel == LOG_INFO);
442204076Spjd
443204076Spjd	pjdlogv_common(loglevel, 0, -1, fmt, ap);
444204076Spjd}
445204076Spjd
446204076Spjd/*
447204076Spjd * Regular logs.
448204076Spjd */
449204076Spjdvoid
450204076Spjdpjdlog(int loglevel, const char *fmt, ...)
451204076Spjd{
452204076Spjd	va_list ap;
453204076Spjd
454219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
455217965Spjd
456204076Spjd	va_start(ap, fmt);
457204076Spjd	pjdlogv(loglevel, fmt, ap);
458204076Spjd	va_end(ap);
459204076Spjd}
460204076Spjd
461204076Spjd/*
462204076Spjd * Debug logs.
463204076Spjd */
464204076Spjdvoid
465204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
466204076Spjd{
467204076Spjd
468219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
469217965Spjd
470204076Spjd	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
471204076Spjd}
472204076Spjd
473204076Spjd/*
474204076Spjd * Debug logs.
475204076Spjd */
476204076Spjdvoid
477204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...)
478204076Spjd{
479204076Spjd	va_list ap;
480204076Spjd
481219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
482217965Spjd
483204076Spjd	va_start(ap, fmt);
484204076Spjd	pjdlogv_debug(debuglevel, fmt, ap);
485204076Spjd	va_end(ap);
486204076Spjd}
487204076Spjd
488204076Spjd/*
489204076Spjd * Error logs with errno logging.
490204076Spjd */
491204076Spjdvoid
492204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap)
493204076Spjd{
494204076Spjd
495219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
496217965Spjd
497204076Spjd	pjdlogv_common(loglevel, 0, errno, fmt, ap);
498204076Spjd}
499204076Spjd
500204076Spjd/*
501204076Spjd * Error logs with errno logging.
502204076Spjd */
503204076Spjdvoid
504204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...)
505204076Spjd{
506204076Spjd	va_list ap;
507204076Spjd
508219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
509217965Spjd
510204076Spjd	va_start(ap, fmt);
511204076Spjd	pjdlogv_errno(loglevel, fmt, ap);
512204076Spjd	va_end(ap);
513204076Spjd}
514204076Spjd
515204076Spjd/*
516204076Spjd * Log error, errno and exit.
517204076Spjd */
518204076Spjdvoid
519204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap)
520204076Spjd{
521204076Spjd
522219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
523217965Spjd
524204076Spjd	pjdlogv_errno(LOG_ERR, fmt, ap);
525204076Spjd	exit(exitcode);
526210872Spjd	/* NOTREACHED */
527204076Spjd}
528204076Spjd
529204076Spjd/*
530204076Spjd * Log error, errno and exit.
531204076Spjd */
532204076Spjdvoid
533204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...)
534204076Spjd{
535204076Spjd	va_list ap;
536204076Spjd
537219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
538217965Spjd
539204076Spjd	va_start(ap, fmt);
540204076Spjd	pjdlogv_exit(exitcode, fmt, ap);
541204076Spjd	/* NOTREACHED */
542204076Spjd	va_end(ap);
543204076Spjd}
544204076Spjd
545204076Spjd/*
546204076Spjd * Log error and exit.
547204076Spjd */
548204076Spjdvoid
549204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
550204076Spjd{
551204076Spjd
552219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
553217965Spjd
554204076Spjd	pjdlogv(LOG_ERR, fmt, ap);
555204076Spjd	exit(exitcode);
556210872Spjd	/* NOTREACHED */
557204076Spjd}
558204076Spjd
559204076Spjd/*
560204076Spjd * Log error and exit.
561204076Spjd */
562204076Spjdvoid
563204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...)
564204076Spjd{
565204076Spjd	va_list ap;
566204076Spjd
567219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
568217965Spjd
569204076Spjd	va_start(ap, fmt);
570204076Spjd	pjdlogv_exitx(exitcode, fmt, ap);
571204076Spjd	/* NOTREACHED */
572204076Spjd	va_end(ap);
573204076Spjd}
574210875Spjd
575210875Spjd/*
576218132Spjd * Log failure message and exit.
577210875Spjd */
578210875Spjdvoid
579218132Spjdpjdlog_abort(const char *func, const char *file, int line,
580217966Spjd    const char *failedexpr, const char *fmt, ...)
581210875Spjd{
582217966Spjd	va_list ap;
583210875Spjd
584219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
585217966Spjd
586217966Spjd	/*
587217966Spjd	 * When there is no message we pass __func__ as 'fmt'.
588217966Spjd	 * It would be cleaner to pass NULL or "", but gcc generates a warning
589217966Spjd	 * for both of those.
590217966Spjd	 */
591217966Spjd	if (fmt != func) {
592217966Spjd		va_start(ap, fmt);
593217966Spjd		pjdlogv_critical(fmt, ap);
594217966Spjd		va_end(ap);
595217966Spjd	}
596217966Spjd	if (failedexpr == NULL) {
597217966Spjd		if (func == NULL) {
598217966Spjd			pjdlog_critical("Aborted at file %s, line %d.", file,
599217966Spjd			    line);
600217966Spjd		} else {
601217966Spjd			pjdlog_critical("Aborted at function %s, file %s, line %d.",
602217966Spjd			    func, file, line);
603217966Spjd		}
604210875Spjd	} else {
605217966Spjd		if (func == NULL) {
606217966Spjd			pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
607217966Spjd			    failedexpr, file, line);
608217966Spjd		} else {
609217966Spjd			pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
610217966Spjd			    failedexpr, func, file, line);
611217966Spjd		}
612210875Spjd	}
613210875Spjd	abort();
614210875Spjd}
615