]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libpjdlog/pjdlog.c
Merge branch 'releng/11.3' into releng-CDN/11.3
[FreeBSD/FreeBSD.git] / lib / libpjdlog / pjdlog.c
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$");
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
72 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
73 static int pjdlog_mode, pjdlog_debug_level, pjdlog_sock;
74 static int pjdlog_prefix_current;
75 static char pjdlog_prefix[PJDLOG_PREFIX_STACK][PJDLOG_PREFIX_MAXSIZE];
76
77 static int
78 pjdlog_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
87 static int
88 pjdlog_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
103 static int
104 pjdlog_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
113 static int
114 pjdlog_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
157 static int
158 pjdlog_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
220 void
221 pjdlog_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
263 void
264 pjdlog_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  */
287 void
288 pjdlog_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  */
322 int
323 pjdlog_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  */
335 void
336 pjdlog_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  */
351 int
352 pjdlog_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  */
367 void
368 pjdlog_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  */
381 int
382 pjdlog_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  */
393 void
394 pjdlog_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  */
408 void
409 pjdlogv_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  */
427 const char *
428 pjdlog_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  */
439 void
440 pjdlog_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  */
454 void
455 pjdlogv_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  */
469 void
470 pjdlog_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  */
482 static const char *
483 pjdlog_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
508 static int
509 vsnprlcat(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
518 static int
519 snprlcat(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
530 static void
531 pjdlogv_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  */
642 void
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  */
694 void
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  */
710 void
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  */
726 void
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  */
743 void
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  */
783 int
784 pjdlog_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