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