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