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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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