pjdlog.c revision 222087
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: head/sbin/hastd/pjdlog.c 222087 2011-05-18 22:43:56Z pjd $");
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{
151217965Spjd
152219369Spjd	assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
153219369Spjd	    pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
154217965Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
155217965Spjd
156219370Spjd	if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
157219370Spjd		__use_xprintf = 1;
158219370Spjd		register_printf_render_std("T");
159219370Spjd		register_printf_render('N',
160219370Spjd		    pjdlog_printf_render_humanized_number,
161219370Spjd		    pjdlog_printf_arginfo_humanized_number);
162219370Spjd		register_printf_render('S',
163219370Spjd		    pjdlog_printf_render_sockaddr,
164219370Spjd		    pjdlog_printf_arginfo_sockaddr);
165219370Spjd	}
166219370Spjd
167217965Spjd	if (mode == PJDLOG_MODE_SYSLOG)
168217965Spjd		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
169217965Spjd	pjdlog_mode = mode;
170218040Spjd	pjdlog_debug_level = 0;
171218040Spjd	bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
172217965Spjd
173219369Spjd	pjdlog_initialized = PJDLOG_INITIALIZED;
174217965Spjd}
175217965Spjd
176217965Spjdvoid
177217965Spjdpjdlog_fini(void)
178217965Spjd{
179217965Spjd
180219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
181217965Spjd
182217965Spjd	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
183217965Spjd		closelog();
184217965Spjd
185219369Spjd	pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
186217965Spjd}
187217965Spjd
188204076Spjd/*
189204076Spjd * Configure where the logs should go.
190204076Spjd * By default they are send to stdout/stderr, but after going into background
191204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to
192204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
193204076Spjd */
194204076Spjdvoid
195204076Spjdpjdlog_mode_set(int mode)
196204076Spjd{
197204076Spjd
198219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
199204076Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
200204076Spjd
201217965Spjd	if (pjdlog_mode == mode)
202217965Spjd		return;
203212052Spjd
204212052Spjd	if (mode == PJDLOG_MODE_SYSLOG)
205217962Spjd		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
206217965Spjd	else /* if (mode == PJDLOG_MODE_STD) */
207217965Spjd		closelog();
208217965Spjd
209217965Spjd	pjdlog_mode = mode;
210204076Spjd}
211204076Spjd
212204076Spjd/*
213204076Spjd * Return current mode.
214204076Spjd */
215204076Spjdint
216204076Spjdpjdlog_mode_get(void)
217204076Spjd{
218204076Spjd
219219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
220217965Spjd
221204076Spjd	return (pjdlog_mode);
222204076Spjd}
223204076Spjd
224204076Spjd/*
225204076Spjd * Set debug level. All the logs above the level specified here will be
226204076Spjd * ignored.
227204076Spjd */
228204076Spjdvoid
229204076Spjdpjdlog_debug_set(int level)
230204076Spjd{
231204076Spjd
232219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
233204076Spjd	assert(level >= 0);
234204076Spjd
235204076Spjd	pjdlog_debug_level = level;
236204076Spjd}
237204076Spjd
238204076Spjd/*
239204076Spjd * Return current debug level.
240204076Spjd */
241204076Spjdint
242204076Spjdpjdlog_debug_get(void)
243204076Spjd{
244204076Spjd
245219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
246217965Spjd
247204076Spjd	return (pjdlog_debug_level);
248204076Spjd}
249204076Spjd
250204076Spjd/*
251204076Spjd * Set prefix that will be used before each log.
252204076Spjd * Setting prefix to NULL will remove it.
253204076Spjd */
254204076Spjdvoid
255204076Spjdpjdlog_prefix_set(const char *fmt, ...)
256204076Spjd{
257204076Spjd	va_list ap;
258204076Spjd
259219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
260217965Spjd
261204076Spjd	va_start(ap, fmt);
262217731Spjd	pjdlogv_prefix_set(fmt, ap);
263204076Spjd	va_end(ap);
264204076Spjd}
265204076Spjd
266204076Spjd/*
267204076Spjd * Set prefix that will be used before each log.
268204076Spjd * Setting prefix to NULL will remove it.
269204076Spjd */
270204076Spjdvoid
271217731Spjdpjdlogv_prefix_set(const char *fmt, va_list ap)
272204076Spjd{
273204076Spjd
274219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
275204076Spjd	assert(fmt != NULL);
276204076Spjd
277204076Spjd	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
278204076Spjd}
279204076Spjd
280204076Spjd/*
281204076Spjd * Convert log level into string.
282204076Spjd */
283204076Spjdstatic const char *
284204076Spjdpjdlog_level_string(int loglevel)
285204076Spjd{
286204076Spjd
287204076Spjd	switch (loglevel) {
288204076Spjd	case LOG_EMERG:
289204076Spjd		return ("EMERG");
290204076Spjd	case LOG_ALERT:
291204076Spjd		return ("ALERT");
292204076Spjd	case LOG_CRIT:
293204076Spjd		return ("CRIT");
294204076Spjd	case LOG_ERR:
295204076Spjd		return ("ERROR");
296204076Spjd	case LOG_WARNING:
297204076Spjd		return ("WARNING");
298204076Spjd	case LOG_NOTICE:
299204076Spjd		return ("NOTICE");
300204076Spjd	case LOG_INFO:
301204076Spjd		return ("INFO");
302204076Spjd	case LOG_DEBUG:
303204076Spjd		return ("DEBUG");
304204076Spjd	}
305204076Spjd	assert(!"Invalid log level.");
306204076Spjd	abort();	/* XXX: gcc */
307204076Spjd}
308204076Spjd
309204076Spjd/*
310204076Spjd * Common log routine.
311204076Spjd */
312204076Spjdvoid
313204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
314204076Spjd{
315204076Spjd	va_list ap;
316204076Spjd
317219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
318217965Spjd
319204076Spjd	va_start(ap, fmt);
320204076Spjd	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
321204076Spjd	va_end(ap);
322204076Spjd}
323204076Spjd
324204076Spjd/*
325204076Spjd * Common log routine, which can handle regular log level as well as debug
326204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog).
327204076Spjd */
328204076Spjdvoid
329204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
330204076Spjd    va_list ap)
331204076Spjd{
332204076Spjd
333219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
334204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
335204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
336204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
337204076Spjd	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
338204076Spjd	assert(loglevel != LOG_DEBUG || debuglevel > 0);
339204076Spjd	assert(error >= -1);
340204076Spjd
341204076Spjd	/* Ignore debug above configured level. */
342204076Spjd	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
343204076Spjd		return;
344204076Spjd
345204076Spjd	switch (pjdlog_mode) {
346204076Spjd	case PJDLOG_MODE_STD:
347204076Spjd	    {
348204076Spjd		FILE *out;
349204076Spjd
350204076Spjd		/*
351204076Spjd		 * We send errors and warning to stderr and the rest to stdout.
352204076Spjd		 */
353204076Spjd		switch (loglevel) {
354204076Spjd		case LOG_EMERG:
355204076Spjd		case LOG_ALERT:
356204076Spjd		case LOG_CRIT:
357204076Spjd		case LOG_ERR:
358204076Spjd		case LOG_WARNING:
359204076Spjd			out = stderr;
360204076Spjd			break;
361204076Spjd		case LOG_NOTICE:
362204076Spjd		case LOG_INFO:
363204076Spjd		case LOG_DEBUG:
364204076Spjd			out = stdout;
365204076Spjd			break;
366204076Spjd		default:
367204076Spjd			assert(!"Invalid loglevel.");
368204076Spjd			abort();	/* XXX: gcc */
369204076Spjd		}
370204076Spjd
371204076Spjd		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
372204076Spjd		/* Attach debuglevel if this is debug log. */
373204076Spjd		if (loglevel == LOG_DEBUG)
374204076Spjd			fprintf(out, "[%d]", debuglevel);
375213939Spjd		fprintf(out, " %s", pjdlog_prefix);
376204076Spjd		vfprintf(out, fmt, ap);
377204076Spjd		if (error != -1)
378204076Spjd			fprintf(out, ": %s.", strerror(error));
379204076Spjd		fprintf(out, "\n");
380211898Spjd		fflush(out);
381204076Spjd		break;
382204076Spjd	    }
383204076Spjd	case PJDLOG_MODE_SYSLOG:
384204076Spjd	    {
385204076Spjd		char log[1024];
386204076Spjd		int len;
387204076Spjd
388204076Spjd		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
389204076Spjd		if ((size_t)len < sizeof(log))
390206697Spjd			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
391204076Spjd		if (error != -1 && (size_t)len < sizeof(log)) {
392204076Spjd			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
393204076Spjd			    strerror(error));
394204076Spjd		}
395204076Spjd		syslog(loglevel, "%s", log);
396204076Spjd		break;
397204076Spjd	    }
398204076Spjd	default:
399204076Spjd		assert(!"Invalid mode.");
400204076Spjd	}
401204076Spjd}
402204076Spjd
403204076Spjd/*
404204076Spjd * Regular logs.
405204076Spjd */
406204076Spjdvoid
407204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap)
408204076Spjd{
409204076Spjd
410219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
411217965Spjd
412204076Spjd	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
413204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
414204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
415204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
416204076Spjd	    loglevel == LOG_INFO);
417204076Spjd
418204076Spjd	pjdlogv_common(loglevel, 0, -1, fmt, ap);
419204076Spjd}
420204076Spjd
421204076Spjd/*
422204076Spjd * Regular logs.
423204076Spjd */
424204076Spjdvoid
425204076Spjdpjdlog(int loglevel, const char *fmt, ...)
426204076Spjd{
427204076Spjd	va_list ap;
428204076Spjd
429219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
430217965Spjd
431204076Spjd	va_start(ap, fmt);
432204076Spjd	pjdlogv(loglevel, fmt, ap);
433204076Spjd	va_end(ap);
434204076Spjd}
435204076Spjd
436204076Spjd/*
437204076Spjd * Debug logs.
438204076Spjd */
439204076Spjdvoid
440204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
441204076Spjd{
442204076Spjd
443219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
444217965Spjd
445204076Spjd	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
446204076Spjd}
447204076Spjd
448204076Spjd/*
449204076Spjd * Debug logs.
450204076Spjd */
451204076Spjdvoid
452204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...)
453204076Spjd{
454204076Spjd	va_list ap;
455204076Spjd
456219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
457217965Spjd
458204076Spjd	va_start(ap, fmt);
459204076Spjd	pjdlogv_debug(debuglevel, fmt, ap);
460204076Spjd	va_end(ap);
461204076Spjd}
462204076Spjd
463204076Spjd/*
464204076Spjd * Error logs with errno logging.
465204076Spjd */
466204076Spjdvoid
467204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap)
468204076Spjd{
469204076Spjd
470219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
471217965Spjd
472204076Spjd	pjdlogv_common(loglevel, 0, errno, fmt, ap);
473204076Spjd}
474204076Spjd
475204076Spjd/*
476204076Spjd * Error logs with errno logging.
477204076Spjd */
478204076Spjdvoid
479204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...)
480204076Spjd{
481204076Spjd	va_list ap;
482204076Spjd
483219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
484217965Spjd
485204076Spjd	va_start(ap, fmt);
486204076Spjd	pjdlogv_errno(loglevel, fmt, ap);
487204076Spjd	va_end(ap);
488204076Spjd}
489204076Spjd
490204076Spjd/*
491204076Spjd * Log error, errno and exit.
492204076Spjd */
493204076Spjdvoid
494204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap)
495204076Spjd{
496204076Spjd
497219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
498217965Spjd
499204076Spjd	pjdlogv_errno(LOG_ERR, fmt, ap);
500204076Spjd	exit(exitcode);
501210872Spjd	/* NOTREACHED */
502204076Spjd}
503204076Spjd
504204076Spjd/*
505204076Spjd * Log error, errno and exit.
506204076Spjd */
507204076Spjdvoid
508204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...)
509204076Spjd{
510204076Spjd	va_list ap;
511204076Spjd
512219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
513217965Spjd
514204076Spjd	va_start(ap, fmt);
515204076Spjd	pjdlogv_exit(exitcode, fmt, ap);
516204076Spjd	/* NOTREACHED */
517204076Spjd	va_end(ap);
518204076Spjd}
519204076Spjd
520204076Spjd/*
521204076Spjd * Log error and exit.
522204076Spjd */
523204076Spjdvoid
524204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
525204076Spjd{
526204076Spjd
527219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
528217965Spjd
529204076Spjd	pjdlogv(LOG_ERR, fmt, ap);
530204076Spjd	exit(exitcode);
531210872Spjd	/* NOTREACHED */
532204076Spjd}
533204076Spjd
534204076Spjd/*
535204076Spjd * Log error and exit.
536204076Spjd */
537204076Spjdvoid
538204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...)
539204076Spjd{
540204076Spjd	va_list ap;
541204076Spjd
542219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
543217965Spjd
544204076Spjd	va_start(ap, fmt);
545204076Spjd	pjdlogv_exitx(exitcode, fmt, ap);
546204076Spjd	/* NOTREACHED */
547204076Spjd	va_end(ap);
548204076Spjd}
549210875Spjd
550210875Spjd/*
551218132Spjd * Log failure message and exit.
552210875Spjd */
553210875Spjdvoid
554218132Spjdpjdlog_abort(const char *func, const char *file, int line,
555217966Spjd    const char *failedexpr, const char *fmt, ...)
556210875Spjd{
557217966Spjd	va_list ap;
558210875Spjd
559219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
560217966Spjd
561217966Spjd	/*
562217966Spjd	 * When there is no message we pass __func__ as 'fmt'.
563217966Spjd	 * It would be cleaner to pass NULL or "", but gcc generates a warning
564217966Spjd	 * for both of those.
565217966Spjd	 */
566217966Spjd	if (fmt != func) {
567217966Spjd		va_start(ap, fmt);
568217966Spjd		pjdlogv_critical(fmt, ap);
569217966Spjd		va_end(ap);
570217966Spjd	}
571217966Spjd	if (failedexpr == NULL) {
572217966Spjd		if (func == NULL) {
573217966Spjd			pjdlog_critical("Aborted at file %s, line %d.", file,
574217966Spjd			    line);
575217966Spjd		} else {
576217966Spjd			pjdlog_critical("Aborted at function %s, file %s, line %d.",
577217966Spjd			    func, file, line);
578217966Spjd		}
579210875Spjd	} else {
580217966Spjd		if (func == NULL) {
581217966Spjd			pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
582217966Spjd			    failedexpr, file, line);
583217966Spjd		} else {
584217966Spjd			pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
585217966Spjd			    failedexpr, func, file, line);
586217966Spjd		}
587210875Spjd	}
588210875Spjd	abort();
589210875Spjd}
590