pjdlog.c revision 303975
1/*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org> 4 * All rights reserved. 5 * 6 * This software was developed by Pawel Jakub Dawidek under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: releng/11.0/lib/libpjdlog/pjdlog.c 258791 2013-12-01 09:41:06Z pjd $"); 33 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 72static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED; 73static int pjdlog_mode, pjdlog_debug_level, pjdlog_sock; 74static int pjdlog_prefix_current; 75static char pjdlog_prefix[PJDLOG_PREFIX_STACK][PJDLOG_PREFIX_MAXSIZE]; 76 77static int 78pjdlog_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 87static int 88pjdlog_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 103static int 104pjdlog_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 113static int 114pjdlog_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 157static int 158pjdlog_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 220void 221pjdlog_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 263void 264pjdlog_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 */ 287void 288pjdlog_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 */ 322int 323pjdlog_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 */ 335void 336pjdlog_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 */ 351int 352pjdlog_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 */ 367void 368pjdlog_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 */ 381int 382pjdlog_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 */ 393void 394pjdlog_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 */ 408void 409pjdlogv_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 */ 427const char * 428pjdlog_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 */ 439void 440pjdlog_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 */ 454void 455pjdlogv_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 */ 469void 470pjdlog_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 */ 482static const char * 483pjdlog_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 508static int 509vsnprlcat(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 518static int 519snprlcat(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 530static void 531pjdlogv_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 */ 642void 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 */ 694void 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 */ 710void 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 */ 726void 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 */ 743void 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 */ 783int 784pjdlog_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