pjdlog.c revision 303975
1/*-
2 * Copyright (c) 2009-2010 The FreeBSD Foundation
3 * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4 * All rights reserved.
5 *
6 * This software was developed by Pawel Jakub Dawidek under sponsorship from
7 * the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: releng/11.0/lib/libpjdlog/pjdlog.c 258791 2013-12-01 09:41:06Z pjd $");
33
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <sys/un.h>
37#include <netinet/in.h>
38#include <arpa/inet.h>
39
40#include <assert.h>
41#include <errno.h>
42#include <libutil.h>
43#include <limits.h>
44#include <printf.h>
45#include <stdarg.h>
46#include <stdint.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <syslog.h>
51#include <unistd.h>
52
53#ifdef notyet
54#include <robustio.h>
55#endif
56
57#include "pjdlog.h"
58
59#ifndef	MAX
60#define	MAX(a, b)	((a) > (b) ? (a) : (b))
61#endif
62
63#define	PJDLOG_MAX_MSGSIZE	4096
64
65#define	PJDLOG_PREFIX_STACK	4
66#define	PJDLOG_PREFIX_MAXSIZE	128
67
68#define	PJDLOG_NEVER_INITIALIZED	0
69#define	PJDLOG_NOT_INITIALIZED		1
70#define	PJDLOG_INITIALIZED		2
71
72static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
73static int pjdlog_mode, pjdlog_debug_level, pjdlog_sock;
74static int pjdlog_prefix_current;
75static char pjdlog_prefix[PJDLOG_PREFIX_STACK][PJDLOG_PREFIX_MAXSIZE];
76
77static int
78pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
79    size_t n, int *argt)
80{
81
82	assert(n >= 1);
83	argt[0] = PA_INT | PA_FLAG_INTMAX;
84	return (1);
85}
86
87static int
88pjdlog_printf_render_humanized_number(struct __printf_io *io,
89    const struct printf_info *pi, const void * const *arg)
90{
91	char buf[5];
92	intmax_t num;
93	int ret;
94
95	num = *(const intmax_t *)arg[0];
96	humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
97	    HN_NOSPACE | HN_DECIMAL);
98	ret = __printf_out(io, pi, buf, strlen(buf));
99	__printf_flush(io);
100	return (ret);
101}
102
103static int
104pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
105    size_t n, int *argt)
106{
107
108	assert(n >= 1);
109	argt[0] = PA_POINTER;
110	return (1);
111}
112
113static int
114pjdlog_printf_render_sockaddr_ip(struct __printf_io *io,
115    const struct printf_info *pi, const void * const *arg)
116{
117	const struct sockaddr_storage *ss;
118	char addr[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
119	int ret;
120
121	ss = *(const struct sockaddr_storage * const *)arg[0];
122	switch (ss->ss_family) {
123	case AF_INET:
124	    {
125		const struct sockaddr_in *sin;
126
127		sin = (const struct sockaddr_in *)ss;
128		if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
129		    sizeof(addr)) == NULL) {
130			PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
131			    strerror(errno));
132		}
133		break;
134	    }
135	case AF_INET6:
136	    {
137		const struct sockaddr_in6 *sin;
138
139		sin = (const struct sockaddr_in6 *)ss;
140		if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
141		    sizeof(addr)) == NULL) {
142			PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
143			    strerror(errno));
144		}
145		break;
146	    }
147	default:
148		snprintf(addr, sizeof(addr), "[unsupported family %hhu]",
149		    ss->ss_family);
150		break;
151	}
152	ret = __printf_out(io, pi, addr, strlen(addr));
153	__printf_flush(io);
154	return (ret);
155}
156
157static int
158pjdlog_printf_render_sockaddr(struct __printf_io *io,
159    const struct printf_info *pi, const void * const *arg)
160{
161	const struct sockaddr_storage *ss;
162	char buf[PATH_MAX];
163	int ret;
164
165	ss = *(const struct sockaddr_storage * const *)arg[0];
166	switch (ss->ss_family) {
167	case AF_UNIX:
168	    {
169		const struct sockaddr_un *sun;
170
171		sun = (const struct sockaddr_un *)ss;
172		if (sun->sun_path[0] == '\0')
173			snprintf(buf, sizeof(buf), "N/A");
174		else
175			snprintf(buf, sizeof(buf), "%s", sun->sun_path);
176		break;
177	    }
178	case AF_INET:
179	    {
180		char addr[INET_ADDRSTRLEN];
181		const struct sockaddr_in *sin;
182		unsigned int port;
183
184		sin = (const struct sockaddr_in *)ss;
185		port = ntohs(sin->sin_port);
186		if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
187		    sizeof(addr)) == NULL) {
188			PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
189			    strerror(errno));
190		}
191		snprintf(buf, sizeof(buf), "%s:%u", addr, port);
192		break;
193	    }
194	case AF_INET6:
195	    {
196		char addr[INET6_ADDRSTRLEN];
197		const struct sockaddr_in6 *sin;
198		unsigned int port;
199
200		sin = (const struct sockaddr_in6 *)ss;
201		port = ntohs(sin->sin6_port);
202		if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
203		    sizeof(addr)) == NULL) {
204			PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
205			    strerror(errno));
206		}
207		snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
208		break;
209	    }
210	default:
211		snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
212		    ss->ss_family);
213		break;
214	}
215	ret = __printf_out(io, pi, buf, strlen(buf));
216	__printf_flush(io);
217	return (ret);
218}
219
220void
221pjdlog_init(int mode)
222{
223	int saved_errno;
224
225	assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
226	    pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
227#ifdef notyet
228	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG ||
229	    mode == PJDLOG_MODE_SOCK);
230#else
231	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
232#endif
233
234	saved_errno = errno;
235
236	if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
237		__use_xprintf = 1;
238		register_printf_render_std("T");
239		register_printf_render('N',
240		    pjdlog_printf_render_humanized_number,
241		    pjdlog_printf_arginfo_humanized_number);
242		register_printf_render('I',
243		    pjdlog_printf_render_sockaddr_ip,
244		    pjdlog_printf_arginfo_sockaddr);
245		register_printf_render('S',
246		    pjdlog_printf_render_sockaddr,
247		    pjdlog_printf_arginfo_sockaddr);
248	}
249
250	if (mode == PJDLOG_MODE_SYSLOG)
251		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_LOCAL0);
252	pjdlog_mode = mode;
253	pjdlog_debug_level = 0;
254	pjdlog_prefix_current = 0;
255	pjdlog_prefix[0][0] = '\0';
256
257	pjdlog_initialized = PJDLOG_INITIALIZED;
258	pjdlog_sock = -1;
259
260	errno = saved_errno;
261}
262
263void
264pjdlog_fini(void)
265{
266	int saved_errno;
267
268	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
269
270	saved_errno = errno;
271
272	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
273		closelog();
274
275	pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
276	pjdlog_sock = -1;
277
278	errno = saved_errno;
279}
280
281/*
282 * Configure where the logs should go.
283 * By default they are send to stdout/stderr, but after going into background
284 * (eg. by calling daemon(3)) application is responsible for changing mode to
285 * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
286 */
287void
288pjdlog_mode_set(int mode)
289{
290	int saved_errno;
291
292	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
293#ifdef notyet
294	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG ||
295	    mode == PJDLOG_MODE_SOCK);
296#else
297	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
298#endif
299
300	if (pjdlog_mode == mode)
301		return;
302
303	saved_errno = errno;
304
305	if (mode == PJDLOG_MODE_SYSLOG)
306		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
307	else if (mode == PJDLOG_MODE_STD)
308		closelog();
309
310	if (mode != PJDLOG_MODE_SOCK)
311		pjdlog_sock = -1;
312
313	pjdlog_mode = mode;
314
315	errno = saved_errno;
316}
317
318
319/*
320 * Return current mode.
321 */
322int
323pjdlog_mode_get(void)
324{
325
326	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
327
328	return (pjdlog_mode);
329}
330
331#ifdef notyet
332/*
333 * Sets socket number to use for PJDLOG_MODE_SOCK mode.
334 */
335void
336pjdlog_sock_set(int sock)
337{
338
339	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
340	assert(pjdlog_mode == PJDLOG_MODE_SOCK);
341	assert(sock >= 0);
342
343	pjdlog_sock = sock;
344}
345#endif
346
347#ifdef notyet
348/*
349 * Returns socket number used for PJDLOG_MODE_SOCK mode.
350 */
351int
352pjdlog_sock_get(void)
353{
354
355	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
356	assert(pjdlog_mode == PJDLOG_MODE_SOCK);
357	assert(pjdlog_sock >= 0);
358
359	return (pjdlog_sock);
360}
361#endif
362
363/*
364 * Set debug level. All the logs above the level specified here will be
365 * ignored.
366 */
367void
368pjdlog_debug_set(int level)
369{
370
371	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
372	assert(level >= 0);
373	assert(level <= 127);
374
375	pjdlog_debug_level = level;
376}
377
378/*
379 * Return current debug level.
380 */
381int
382pjdlog_debug_get(void)
383{
384
385	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
386
387	return (pjdlog_debug_level);
388}
389
390/*
391 * Set prefix that will be used before each log.
392 */
393void
394pjdlog_prefix_set(const char *fmt, ...)
395{
396	va_list ap;
397
398	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
399
400	va_start(ap, fmt);
401	pjdlogv_prefix_set(fmt, ap);
402	va_end(ap);
403}
404
405/*
406 * Set prefix that will be used before each log.
407 */
408void
409pjdlogv_prefix_set(const char *fmt, va_list ap)
410{
411	int saved_errno;
412
413	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
414	assert(fmt != NULL);
415
416	saved_errno = errno;
417
418	vsnprintf(pjdlog_prefix[pjdlog_prefix_current],
419	    sizeof(pjdlog_prefix[pjdlog_prefix_current]), fmt, ap);
420
421	errno = saved_errno;
422}
423
424/*
425 * Get current prefix.
426 */
427const char *
428pjdlog_prefix_get(void)
429{
430
431	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
432
433	return (pjdlog_prefix[pjdlog_prefix_current]);
434}
435
436/*
437 * Set new prefix and put the current one on the stack.
438 */
439void
440pjdlog_prefix_push(const char *fmt, ...)
441{
442	va_list ap;
443
444	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
445
446	va_start(ap, fmt);
447	pjdlogv_prefix_push(fmt, ap);
448	va_end(ap);
449}
450
451/*
452 * Set new prefix and put the current one on the stack.
453 */
454void
455pjdlogv_prefix_push(const char *fmt, va_list ap)
456{
457
458	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
459	assert(pjdlog_prefix_current < PJDLOG_PREFIX_STACK - 1);
460
461	pjdlog_prefix_current++;
462
463	pjdlogv_prefix_set(fmt, ap);
464}
465
466/*
467 * Removes current prefix and recovers previous one from the stack.
468 */
469void
470pjdlog_prefix_pop(void)
471{
472
473	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
474	assert(pjdlog_prefix_current > 0);
475
476	pjdlog_prefix_current--;
477}
478
479/*
480 * Convert log level into string.
481 */
482static const char *
483pjdlog_level_to_string(int loglevel)
484{
485
486	switch (loglevel) {
487	case LOG_EMERG:
488		return ("EMERG");
489	case LOG_ALERT:
490		return ("ALERT");
491	case LOG_CRIT:
492		return ("CRIT");
493	case LOG_ERR:
494		return ("ERROR");
495	case LOG_WARNING:
496		return ("WARNING");
497	case LOG_NOTICE:
498		return ("NOTICE");
499	case LOG_INFO:
500		return ("INFO");
501	case LOG_DEBUG:
502		return ("DEBUG");
503	}
504	assert(!"Invalid log level.");
505	abort();	/* XXX: gcc */
506}
507
508static int
509vsnprlcat(char *str, size_t size, const char *fmt, va_list ap)
510{
511	size_t len;
512
513	len = strlen(str);
514	assert(len < size);
515	return (vsnprintf(str + len, size - len, fmt, ap));
516}
517
518static int
519snprlcat(char *str, size_t size, const char *fmt, ...)
520{
521	va_list ap;
522	int result;
523
524	va_start(ap, fmt);
525	result = vsnprlcat(str, size, fmt, ap);
526	va_end(ap);
527	return (result);
528}
529
530static void
531pjdlogv_common_single_line(const char *func, const char *file, int line,
532    int loglevel, int debuglevel, int error, const char *msg)
533{
534	static char log[2 * PJDLOG_MAX_MSGSIZE];
535	char *logp;
536	size_t logs;
537
538	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
539#ifdef notyet
540	assert(pjdlog_mode == PJDLOG_MODE_STD ||
541	    pjdlog_mode == PJDLOG_MODE_SYSLOG ||
542	    pjdlog_mode == PJDLOG_MODE_SOCK);
543#else
544	assert(pjdlog_mode == PJDLOG_MODE_STD ||
545	    pjdlog_mode == PJDLOG_MODE_SYSLOG);
546#endif
547	assert(pjdlog_mode != PJDLOG_MODE_SOCK || pjdlog_sock >= 0);
548	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
549	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
550	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
551	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
552	assert(loglevel != LOG_DEBUG || debuglevel > 0);
553	assert(loglevel != LOG_DEBUG || debuglevel <= pjdlog_debug_level);
554	assert(debuglevel <= 127);
555	assert(error >= -1);
556	assert((file != NULL && line > 0) ||
557	    (func == NULL && file == NULL && line == 0));
558
559	switch (pjdlog_mode) {
560	case PJDLOG_MODE_STD:
561	case PJDLOG_MODE_SYSLOG:
562		logp = log;
563		logs = sizeof(log);
564		break;
565	case PJDLOG_MODE_SOCK:
566		logp = log + 4;
567		logs = sizeof(log) - 4;
568		break;
569	default:
570		assert(!"Invalid mode.");
571	}
572
573	*logp = '\0';
574
575	if (pjdlog_mode != PJDLOG_MODE_SOCK) {
576		if (loglevel == LOG_DEBUG) {
577			/* Attach debuglevel if this is debug log. */
578			snprlcat(logp, logs, "[%s%d] ",
579			    pjdlog_level_to_string(loglevel), debuglevel);
580		} else {
581			snprlcat(logp, logs, "[%s] ",
582			    pjdlog_level_to_string(loglevel));
583		}
584		if (pjdlog_mode != PJDLOG_MODE_SYSLOG &&
585		    pjdlog_debug_level >= 1) {
586			snprlcat(logp, logs, "(pid=%d) ", getpid());
587		}
588	}
589	/* Attach file, func, line if debuglevel is 2 or more. */
590	if (pjdlog_debug_level >= 2 && file != NULL) {
591		if (func == NULL)
592			snprlcat(logp, logs, "(%s:%d) ", file, line);
593		else
594			snprlcat(logp, logs, "(%s:%d:%s) ", file, line, func);
595	}
596
597	if (pjdlog_mode != PJDLOG_MODE_SOCK) {
598		snprlcat(logp, logs, "%s",
599		    pjdlog_prefix[pjdlog_prefix_current]);
600	}
601
602	strlcat(logp, msg, logs);
603
604	/* Attach error description. */
605	if (error != -1)
606		snprlcat(logp, logs, ": %s.", strerror(error));
607
608	switch (pjdlog_mode) {
609	case PJDLOG_MODE_STD:
610		fprintf(stderr, "%s\n", logp);
611		fflush(stderr);
612		break;
613	case PJDLOG_MODE_SYSLOG:
614		syslog(loglevel, "%s", logp);
615		break;
616#ifdef notyet
617	case PJDLOG_MODE_SOCK:
618	    {
619		char ack[2];
620		uint16_t dlen;
621
622		log[2] = loglevel;
623		log[3] = debuglevel;
624		dlen = strlen(logp) + 3;	/* +3 = loglevel, debuglevel and terminating \0 */
625		bcopy(&dlen, log, sizeof(dlen));
626		if (robust_send(pjdlog_sock, log, (size_t)dlen + 2) == -1)	/* +2 for size */
627			assert(!"Unable to send log.");
628		if (robust_recv(pjdlog_sock, ack, sizeof(ack)) == -1)
629			assert(!"Unable to send log.");
630		break;
631	    }
632#endif
633	default:
634		assert(!"Invalid mode.");
635	}
636}
637
638/*
639 * Common log routine, which can handle regular log level as well as debug
640 * level. We decide here where to send the logs (stdout/stderr or syslog).
641 */
642void
643_pjdlogv_common(const char *func, const char *file, int line, int loglevel,
644    int debuglevel, int error, const char *fmt, va_list ap)
645{
646	char log[PJDLOG_MAX_MSGSIZE];
647	char *logp, *curline;
648	const char *prvline;
649	int saved_errno;
650
651	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
652	assert(pjdlog_mode == PJDLOG_MODE_STD ||
653	    pjdlog_mode == PJDLOG_MODE_SYSLOG ||
654	    pjdlog_mode == PJDLOG_MODE_SOCK);
655	assert(pjdlog_mode != PJDLOG_MODE_SOCK || pjdlog_sock >= 0);
656	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
657	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
658	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
659	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
660	assert(loglevel != LOG_DEBUG || debuglevel > 0);
661	assert(debuglevel <= 127);
662	assert(error >= -1);
663
664	/* Ignore debug above configured level. */
665	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
666		return;
667
668	saved_errno = errno;
669
670	vsnprintf(log, sizeof(log), fmt, ap);
671	logp = log;
672	prvline = NULL;
673
674	while ((curline = strsep(&logp, "\n")) != NULL) {
675		if (*curline == '\0')
676			continue;
677		if (prvline != NULL) {
678			pjdlogv_common_single_line(func, file, line, loglevel,
679			    debuglevel, -1, prvline);
680		}
681		prvline = curline;
682	}
683	if (prvline == NULL)
684		prvline = "";
685	pjdlogv_common_single_line(func, file, line, loglevel, debuglevel,
686	    error, prvline);
687
688	errno = saved_errno;
689}
690
691/*
692 * Common log routine.
693 */
694void
695_pjdlog_common(const char *func, const char *file, int line, int loglevel,
696    int debuglevel, int error, const char *fmt, ...)
697{
698	va_list ap;
699
700	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
701
702	va_start(ap, fmt);
703	_pjdlogv_common(func, file, line, loglevel, debuglevel, error, fmt, ap);
704	va_end(ap);
705}
706
707/*
708 * Log error, errno and exit.
709 */
710void
711_pjdlogv_exit(const char *func, const char *file, int line, int exitcode,
712    int error, const char *fmt, va_list ap)
713{
714
715	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
716
717	_pjdlogv_common(func, file, line, exitcode == 0 ? LOG_INFO : LOG_ERR, 0,
718	    error, fmt, ap);
719	exit(exitcode);
720	/* NOTREACHED */
721}
722
723/*
724 * Log error, errno and exit.
725 */
726void
727_pjdlog_exit(const char *func, const char *file, int line, int exitcode,
728    int error, const char *fmt, ...)
729{
730	va_list ap;
731
732	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
733
734	va_start(ap, fmt);
735	_pjdlogv_exit(func, file, line, exitcode, error, fmt, ap);
736	/* NOTREACHED */
737	va_end(ap);
738}
739
740/*
741 * Log failure message and exit.
742 */
743void
744_pjdlog_abort(const char *func, const char *file, int line,
745    int error, const char *failedexpr, const char *fmt, ...)
746{
747	va_list ap;
748
749	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
750
751	/*
752	 * Set pjdlog_debug_level to 2, so that file, line and func are
753	 * included in log. This is fine as we will exit anyway.
754	 */
755	if (pjdlog_debug_level < 2)
756		pjdlog_debug_level = 2;
757
758	/*
759	 * When there is no message we pass __func__ as 'fmt'.
760	 * It would be cleaner to pass NULL or "", but gcc generates a warning
761	 * for both of those.
762	 */
763	if (fmt != func) {
764		va_start(ap, fmt);
765		_pjdlogv_common(func, file, line, LOG_CRIT, 0, -1, fmt, ap);
766		va_end(ap);
767	}
768	if (failedexpr == NULL) {
769		_pjdlog_common(func, file, line, LOG_CRIT, 0, -1, "Aborted.");
770	} else {
771		_pjdlog_common(func, file, line, LOG_CRIT, 0, -1,
772		    "Assertion failed: (%s).", failedexpr);
773	}
774	if (error != -1)
775		_pjdlog_common(func, file, line, LOG_CRIT, 0, error, "Errno");
776	abort();
777}
778
779#ifdef notyet
780/*
781 * Receive log from the given socket.
782 */
783int
784pjdlog_receive(int sock)
785{
786	char log[PJDLOG_MAX_MSGSIZE];
787	int loglevel, debuglevel;
788	uint16_t dlen;
789
790	if (robust_recv(sock, &dlen, sizeof(dlen)) == -1)
791		return (-1);
792
793	PJDLOG_ASSERT(dlen > 0);
794	PJDLOG_ASSERT(dlen <= PJDLOG_MAX_MSGSIZE - 3);
795
796	if (robust_recv(sock, log, (size_t)dlen) == -1)
797		return (-1);
798
799	log[dlen - 1] = '\0';
800	loglevel = log[0];
801	debuglevel = log[1];
802	_pjdlog_common(NULL, NULL, 0, loglevel, debuglevel, -1, "%s", log + 2);
803
804	if (robust_send(sock, "ok", 2) == -1)
805		return (-1);
806
807	return (0);
808}
809#endif
810