]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libpjdlog/pjdlog.c
Make linux_ptrace() use linux_msg() instead of printf().
[FreeBSD/FreeBSD.git] / lib / libpjdlog / pjdlog.c
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$");
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
74 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
75 static int pjdlog_mode, pjdlog_debug_level, pjdlog_sock;
76 static int pjdlog_prefix_current;
77 static char pjdlog_prefix[PJDLOG_PREFIX_STACK][PJDLOG_PREFIX_MAXSIZE];
78
79 static int
80 pjdlog_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
89 static int
90 pjdlog_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
105 static int
106 pjdlog_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
115 static int
116 pjdlog_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
159 static int
160 pjdlog_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
222 void
223 pjdlog_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
265 void
266 pjdlog_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  */
289 void
290 pjdlog_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  */
324 int
325 pjdlog_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  */
337 void
338 pjdlog_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  */
353 int
354 pjdlog_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  */
369 void
370 pjdlog_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  */
383 int
384 pjdlog_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  */
395 void
396 pjdlog_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  */
410 void
411 pjdlogv_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  */
429 const char *
430 pjdlog_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  */
441 void
442 pjdlog_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  */
456 void
457 pjdlogv_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  */
471 void
472 pjdlog_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  */
484 static const char *
485 pjdlog_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
510 static int
511 vsnprlcat(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
520 static int
521 snprlcat(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
532 static void
533 pjdlogv_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  */
644 void
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  */
696 void
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  */
712 void
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  */
728 void
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  */
745 void
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  */
785 int
786 pjdlog_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