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/cdefs.h> 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 810