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 __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 812