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