pjdlog.c revision 222087
1204076Spjd/*- 2217964Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 3217964Spjd * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org> 4204076Spjd * All rights reserved. 5204076Spjd * 6204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 7204076Spjd * the FreeBSD Foundation. 8204076Spjd * 9204076Spjd * Redistribution and use in source and binary forms, with or without 10204076Spjd * modification, are permitted provided that the following conditions 11204076Spjd * are met: 12204076Spjd * 1. Redistributions of source code must retain the above copyright 13204076Spjd * notice, this list of conditions and the following disclaimer. 14204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 15204076Spjd * notice, this list of conditions and the following disclaimer in the 16204076Spjd * documentation and/or other materials provided with the distribution. 17204076Spjd * 18204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28204076Spjd * SUCH DAMAGE. 29204076Spjd */ 30204076Spjd 31204076Spjd#include <sys/cdefs.h> 32204076Spjd__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 222087 2011-05-18 22:43:56Z pjd $"); 33204076Spjd 34222087Spjd#include <sys/types.h> 35219370Spjd#include <sys/socket.h> 36219370Spjd#include <netinet/in.h> 37222087Spjd#include <arpa/inet.h> 38219370Spjd 39204076Spjd#include <assert.h> 40204076Spjd#include <errno.h> 41219370Spjd#include <libutil.h> 42219370Spjd#include <printf.h> 43204076Spjd#include <stdarg.h> 44219370Spjd#include <stdint.h> 45204076Spjd#include <stdio.h> 46204076Spjd#include <stdlib.h> 47204076Spjd#include <string.h> 48204076Spjd#include <syslog.h> 49204076Spjd 50204076Spjd#include "pjdlog.h" 51204076Spjd 52219369Spjd#define PJDLOG_NEVER_INITIALIZED 0 53219369Spjd#define PJDLOG_NOT_INITIALIZED 1 54219369Spjd#define PJDLOG_INITIALIZED 2 55219369Spjd 56219369Spjdstatic int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED; 57218040Spjdstatic int pjdlog_mode, pjdlog_debug_level; 58204076Spjdstatic char pjdlog_prefix[128]; 59204076Spjd 60219370Spjdstatic int 61219370Spjdpjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused, 62219370Spjd size_t n, int *argt) 63219370Spjd{ 64219370Spjd 65219370Spjd assert(n >= 1); 66219370Spjd argt[0] = PA_INT | PA_FLAG_INTMAX; 67219370Spjd return (1); 68219370Spjd} 69219370Spjd 70219370Spjdstatic int 71219370Spjdpjdlog_printf_render_humanized_number(struct __printf_io *io, 72219370Spjd const struct printf_info *pi, const void * const *arg) 73219370Spjd{ 74219370Spjd char buf[5]; 75219370Spjd intmax_t num; 76219370Spjd int ret; 77219370Spjd 78219370Spjd num = *(const intmax_t *)arg[0]; 79219370Spjd humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE, 80219370Spjd HN_NOSPACE | HN_DECIMAL); 81219370Spjd ret = __printf_out(io, pi, buf, strlen(buf)); 82219370Spjd __printf_flush(io); 83219370Spjd return (ret); 84219370Spjd} 85219370Spjd 86219370Spjdstatic int 87219370Spjdpjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused, 88219370Spjd size_t n, int *argt) 89219370Spjd{ 90219370Spjd 91219370Spjd assert(n >= 1); 92219370Spjd argt[0] = PA_POINTER; 93219370Spjd return (1); 94219370Spjd} 95219370Spjd 96219370Spjdstatic int 97219370Spjdpjdlog_printf_render_sockaddr(struct __printf_io *io, 98219370Spjd const struct printf_info *pi, const void * const *arg) 99219370Spjd{ 100219385Spjd const struct sockaddr_storage *ss; 101219370Spjd char buf[64]; 102219370Spjd int ret; 103219370Spjd 104219385Spjd ss = *(const struct sockaddr_storage * const *)arg[0]; 105219385Spjd switch (ss->ss_family) { 106219370Spjd case AF_INET: 107219370Spjd { 108222087Spjd char addr[INET_ADDRSTRLEN]; 109219370Spjd const struct sockaddr_in *sin; 110219370Spjd unsigned int port; 111219370Spjd 112219385Spjd sin = (const struct sockaddr_in *)ss; 113219370Spjd port = ntohs(sin->sin_port); 114222087Spjd if (inet_ntop(ss->ss_family, &sin->sin_addr, addr, 115222087Spjd sizeof(addr)) == NULL) { 116222087Spjd PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.", 117222087Spjd strerror(errno)); 118222087Spjd } 119222087Spjd snprintf(buf, sizeof(buf), "%s:%u", addr, port); 120222087Spjd break; 121222087Spjd } 122222087Spjd case AF_INET6: 123222087Spjd { 124222087Spjd char addr[INET6_ADDRSTRLEN]; 125222087Spjd const struct sockaddr_in6 *sin; 126222087Spjd unsigned int port; 127219370Spjd 128222087Spjd sin = (const struct sockaddr_in6 *)ss; 129222087Spjd port = ntohs(sin->sin6_port); 130222087Spjd if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr, 131222087Spjd sizeof(addr)) == NULL) { 132222087Spjd PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.", 133222087Spjd strerror(errno)); 134222087Spjd } 135222087Spjd snprintf(buf, sizeof(buf), "[%s]:%u", addr, port); 136219370Spjd break; 137219370Spjd } 138219370Spjd default: 139222087Spjd snprintf(buf, sizeof(buf), "[unsupported family %hhu]", 140222087Spjd ss->ss_family); 141219370Spjd break; 142219370Spjd } 143219370Spjd ret = __printf_out(io, pi, buf, strlen(buf)); 144219370Spjd __printf_flush(io); 145219370Spjd return (ret); 146219370Spjd} 147219370Spjd 148217965Spjdvoid 149217965Spjdpjdlog_init(int mode) 150217965Spjd{ 151217965Spjd 152219369Spjd assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED || 153219369Spjd pjdlog_initialized == PJDLOG_NOT_INITIALIZED); 154217965Spjd assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 155217965Spjd 156219370Spjd if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) { 157219370Spjd __use_xprintf = 1; 158219370Spjd register_printf_render_std("T"); 159219370Spjd register_printf_render('N', 160219370Spjd pjdlog_printf_render_humanized_number, 161219370Spjd pjdlog_printf_arginfo_humanized_number); 162219370Spjd register_printf_render('S', 163219370Spjd pjdlog_printf_render_sockaddr, 164219370Spjd pjdlog_printf_arginfo_sockaddr); 165219370Spjd } 166219370Spjd 167217965Spjd if (mode == PJDLOG_MODE_SYSLOG) 168217965Spjd openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 169217965Spjd pjdlog_mode = mode; 170218040Spjd pjdlog_debug_level = 0; 171218040Spjd bzero(pjdlog_prefix, sizeof(pjdlog_prefix)); 172217965Spjd 173219369Spjd pjdlog_initialized = PJDLOG_INITIALIZED; 174217965Spjd} 175217965Spjd 176217965Spjdvoid 177217965Spjdpjdlog_fini(void) 178217965Spjd{ 179217965Spjd 180219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 181217965Spjd 182217965Spjd if (pjdlog_mode == PJDLOG_MODE_SYSLOG) 183217965Spjd closelog(); 184217965Spjd 185219369Spjd pjdlog_initialized = PJDLOG_NOT_INITIALIZED; 186217965Spjd} 187217965Spjd 188204076Spjd/* 189204076Spjd * Configure where the logs should go. 190204076Spjd * By default they are send to stdout/stderr, but after going into background 191204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to 192204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 193204076Spjd */ 194204076Spjdvoid 195204076Spjdpjdlog_mode_set(int mode) 196204076Spjd{ 197204076Spjd 198219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 199204076Spjd assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 200204076Spjd 201217965Spjd if (pjdlog_mode == mode) 202217965Spjd return; 203212052Spjd 204212052Spjd if (mode == PJDLOG_MODE_SYSLOG) 205217962Spjd openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 206217965Spjd else /* if (mode == PJDLOG_MODE_STD) */ 207217965Spjd closelog(); 208217965Spjd 209217965Spjd pjdlog_mode = mode; 210204076Spjd} 211204076Spjd 212204076Spjd/* 213204076Spjd * Return current mode. 214204076Spjd */ 215204076Spjdint 216204076Spjdpjdlog_mode_get(void) 217204076Spjd{ 218204076Spjd 219219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 220217965Spjd 221204076Spjd return (pjdlog_mode); 222204076Spjd} 223204076Spjd 224204076Spjd/* 225204076Spjd * Set debug level. All the logs above the level specified here will be 226204076Spjd * ignored. 227204076Spjd */ 228204076Spjdvoid 229204076Spjdpjdlog_debug_set(int level) 230204076Spjd{ 231204076Spjd 232219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 233204076Spjd assert(level >= 0); 234204076Spjd 235204076Spjd pjdlog_debug_level = level; 236204076Spjd} 237204076Spjd 238204076Spjd/* 239204076Spjd * Return current debug level. 240204076Spjd */ 241204076Spjdint 242204076Spjdpjdlog_debug_get(void) 243204076Spjd{ 244204076Spjd 245219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 246217965Spjd 247204076Spjd return (pjdlog_debug_level); 248204076Spjd} 249204076Spjd 250204076Spjd/* 251204076Spjd * Set prefix that will be used before each log. 252204076Spjd * Setting prefix to NULL will remove it. 253204076Spjd */ 254204076Spjdvoid 255204076Spjdpjdlog_prefix_set(const char *fmt, ...) 256204076Spjd{ 257204076Spjd va_list ap; 258204076Spjd 259219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 260217965Spjd 261204076Spjd va_start(ap, fmt); 262217731Spjd pjdlogv_prefix_set(fmt, ap); 263204076Spjd va_end(ap); 264204076Spjd} 265204076Spjd 266204076Spjd/* 267204076Spjd * Set prefix that will be used before each log. 268204076Spjd * Setting prefix to NULL will remove it. 269204076Spjd */ 270204076Spjdvoid 271217731Spjdpjdlogv_prefix_set(const char *fmt, va_list ap) 272204076Spjd{ 273204076Spjd 274219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 275204076Spjd assert(fmt != NULL); 276204076Spjd 277204076Spjd vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 278204076Spjd} 279204076Spjd 280204076Spjd/* 281204076Spjd * Convert log level into string. 282204076Spjd */ 283204076Spjdstatic const char * 284204076Spjdpjdlog_level_string(int loglevel) 285204076Spjd{ 286204076Spjd 287204076Spjd switch (loglevel) { 288204076Spjd case LOG_EMERG: 289204076Spjd return ("EMERG"); 290204076Spjd case LOG_ALERT: 291204076Spjd return ("ALERT"); 292204076Spjd case LOG_CRIT: 293204076Spjd return ("CRIT"); 294204076Spjd case LOG_ERR: 295204076Spjd return ("ERROR"); 296204076Spjd case LOG_WARNING: 297204076Spjd return ("WARNING"); 298204076Spjd case LOG_NOTICE: 299204076Spjd return ("NOTICE"); 300204076Spjd case LOG_INFO: 301204076Spjd return ("INFO"); 302204076Spjd case LOG_DEBUG: 303204076Spjd return ("DEBUG"); 304204076Spjd } 305204076Spjd assert(!"Invalid log level."); 306204076Spjd abort(); /* XXX: gcc */ 307204076Spjd} 308204076Spjd 309204076Spjd/* 310204076Spjd * Common log routine. 311204076Spjd */ 312204076Spjdvoid 313204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 314204076Spjd{ 315204076Spjd va_list ap; 316204076Spjd 317219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 318217965Spjd 319204076Spjd va_start(ap, fmt); 320204076Spjd pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 321204076Spjd va_end(ap); 322204076Spjd} 323204076Spjd 324204076Spjd/* 325204076Spjd * Common log routine, which can handle regular log level as well as debug 326204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog). 327204076Spjd */ 328204076Spjdvoid 329204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 330204076Spjd va_list ap) 331204076Spjd{ 332204076Spjd 333219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 334204076Spjd assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 335204076Spjd loglevel == LOG_CRIT || loglevel == LOG_ERR || 336204076Spjd loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 337204076Spjd loglevel == LOG_INFO || loglevel == LOG_DEBUG); 338204076Spjd assert(loglevel != LOG_DEBUG || debuglevel > 0); 339204076Spjd assert(error >= -1); 340204076Spjd 341204076Spjd /* Ignore debug above configured level. */ 342204076Spjd if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 343204076Spjd return; 344204076Spjd 345204076Spjd switch (pjdlog_mode) { 346204076Spjd case PJDLOG_MODE_STD: 347204076Spjd { 348204076Spjd FILE *out; 349204076Spjd 350204076Spjd /* 351204076Spjd * We send errors and warning to stderr and the rest to stdout. 352204076Spjd */ 353204076Spjd switch (loglevel) { 354204076Spjd case LOG_EMERG: 355204076Spjd case LOG_ALERT: 356204076Spjd case LOG_CRIT: 357204076Spjd case LOG_ERR: 358204076Spjd case LOG_WARNING: 359204076Spjd out = stderr; 360204076Spjd break; 361204076Spjd case LOG_NOTICE: 362204076Spjd case LOG_INFO: 363204076Spjd case LOG_DEBUG: 364204076Spjd out = stdout; 365204076Spjd break; 366204076Spjd default: 367204076Spjd assert(!"Invalid loglevel."); 368204076Spjd abort(); /* XXX: gcc */ 369204076Spjd } 370204076Spjd 371204076Spjd fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 372204076Spjd /* Attach debuglevel if this is debug log. */ 373204076Spjd if (loglevel == LOG_DEBUG) 374204076Spjd fprintf(out, "[%d]", debuglevel); 375213939Spjd fprintf(out, " %s", pjdlog_prefix); 376204076Spjd vfprintf(out, fmt, ap); 377204076Spjd if (error != -1) 378204076Spjd fprintf(out, ": %s.", strerror(error)); 379204076Spjd fprintf(out, "\n"); 380211898Spjd fflush(out); 381204076Spjd break; 382204076Spjd } 383204076Spjd case PJDLOG_MODE_SYSLOG: 384204076Spjd { 385204076Spjd char log[1024]; 386204076Spjd int len; 387204076Spjd 388204076Spjd len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 389204076Spjd if ((size_t)len < sizeof(log)) 390206697Spjd len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 391204076Spjd if (error != -1 && (size_t)len < sizeof(log)) { 392204076Spjd (void)snprintf(log + len, sizeof(log) - len, ": %s.", 393204076Spjd strerror(error)); 394204076Spjd } 395204076Spjd syslog(loglevel, "%s", log); 396204076Spjd break; 397204076Spjd } 398204076Spjd default: 399204076Spjd assert(!"Invalid mode."); 400204076Spjd } 401204076Spjd} 402204076Spjd 403204076Spjd/* 404204076Spjd * Regular logs. 405204076Spjd */ 406204076Spjdvoid 407204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap) 408204076Spjd{ 409204076Spjd 410219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 411217965Spjd 412204076Spjd /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 413204076Spjd assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 414204076Spjd loglevel == LOG_CRIT || loglevel == LOG_ERR || 415204076Spjd loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 416204076Spjd loglevel == LOG_INFO); 417204076Spjd 418204076Spjd pjdlogv_common(loglevel, 0, -1, fmt, ap); 419204076Spjd} 420204076Spjd 421204076Spjd/* 422204076Spjd * Regular logs. 423204076Spjd */ 424204076Spjdvoid 425204076Spjdpjdlog(int loglevel, const char *fmt, ...) 426204076Spjd{ 427204076Spjd va_list ap; 428204076Spjd 429219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 430217965Spjd 431204076Spjd va_start(ap, fmt); 432204076Spjd pjdlogv(loglevel, fmt, ap); 433204076Spjd va_end(ap); 434204076Spjd} 435204076Spjd 436204076Spjd/* 437204076Spjd * Debug logs. 438204076Spjd */ 439204076Spjdvoid 440204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 441204076Spjd{ 442204076Spjd 443219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 444217965Spjd 445204076Spjd pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 446204076Spjd} 447204076Spjd 448204076Spjd/* 449204076Spjd * Debug logs. 450204076Spjd */ 451204076Spjdvoid 452204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...) 453204076Spjd{ 454204076Spjd va_list ap; 455204076Spjd 456219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 457217965Spjd 458204076Spjd va_start(ap, fmt); 459204076Spjd pjdlogv_debug(debuglevel, fmt, ap); 460204076Spjd va_end(ap); 461204076Spjd} 462204076Spjd 463204076Spjd/* 464204076Spjd * Error logs with errno logging. 465204076Spjd */ 466204076Spjdvoid 467204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap) 468204076Spjd{ 469204076Spjd 470219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 471217965Spjd 472204076Spjd pjdlogv_common(loglevel, 0, errno, fmt, ap); 473204076Spjd} 474204076Spjd 475204076Spjd/* 476204076Spjd * Error logs with errno logging. 477204076Spjd */ 478204076Spjdvoid 479204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...) 480204076Spjd{ 481204076Spjd va_list ap; 482204076Spjd 483219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 484217965Spjd 485204076Spjd va_start(ap, fmt); 486204076Spjd pjdlogv_errno(loglevel, fmt, ap); 487204076Spjd va_end(ap); 488204076Spjd} 489204076Spjd 490204076Spjd/* 491204076Spjd * Log error, errno and exit. 492204076Spjd */ 493204076Spjdvoid 494204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap) 495204076Spjd{ 496204076Spjd 497219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 498217965Spjd 499204076Spjd pjdlogv_errno(LOG_ERR, fmt, ap); 500204076Spjd exit(exitcode); 501210872Spjd /* NOTREACHED */ 502204076Spjd} 503204076Spjd 504204076Spjd/* 505204076Spjd * Log error, errno and exit. 506204076Spjd */ 507204076Spjdvoid 508204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...) 509204076Spjd{ 510204076Spjd va_list ap; 511204076Spjd 512219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 513217965Spjd 514204076Spjd va_start(ap, fmt); 515204076Spjd pjdlogv_exit(exitcode, fmt, ap); 516204076Spjd /* NOTREACHED */ 517204076Spjd va_end(ap); 518204076Spjd} 519204076Spjd 520204076Spjd/* 521204076Spjd * Log error and exit. 522204076Spjd */ 523204076Spjdvoid 524204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 525204076Spjd{ 526204076Spjd 527219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 528217965Spjd 529204076Spjd pjdlogv(LOG_ERR, fmt, ap); 530204076Spjd exit(exitcode); 531210872Spjd /* NOTREACHED */ 532204076Spjd} 533204076Spjd 534204076Spjd/* 535204076Spjd * Log error and exit. 536204076Spjd */ 537204076Spjdvoid 538204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...) 539204076Spjd{ 540204076Spjd va_list ap; 541204076Spjd 542219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 543217965Spjd 544204076Spjd va_start(ap, fmt); 545204076Spjd pjdlogv_exitx(exitcode, fmt, ap); 546204076Spjd /* NOTREACHED */ 547204076Spjd va_end(ap); 548204076Spjd} 549210875Spjd 550210875Spjd/* 551218132Spjd * Log failure message and exit. 552210875Spjd */ 553210875Spjdvoid 554218132Spjdpjdlog_abort(const char *func, const char *file, int line, 555217966Spjd const char *failedexpr, const char *fmt, ...) 556210875Spjd{ 557217966Spjd va_list ap; 558210875Spjd 559219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 560217966Spjd 561217966Spjd /* 562217966Spjd * When there is no message we pass __func__ as 'fmt'. 563217966Spjd * It would be cleaner to pass NULL or "", but gcc generates a warning 564217966Spjd * for both of those. 565217966Spjd */ 566217966Spjd if (fmt != func) { 567217966Spjd va_start(ap, fmt); 568217966Spjd pjdlogv_critical(fmt, ap); 569217966Spjd va_end(ap); 570217966Spjd } 571217966Spjd if (failedexpr == NULL) { 572217966Spjd if (func == NULL) { 573217966Spjd pjdlog_critical("Aborted at file %s, line %d.", file, 574217966Spjd line); 575217966Spjd } else { 576217966Spjd pjdlog_critical("Aborted at function %s, file %s, line %d.", 577217966Spjd func, file, line); 578217966Spjd } 579210875Spjd } else { 580217966Spjd if (func == NULL) { 581217966Spjd pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 582217966Spjd failedexpr, file, line); 583217966Spjd } else { 584217966Spjd pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 585217966Spjd failedexpr, func, file, line); 586217966Spjd } 587210875Spjd } 588210875Spjd abort(); 589210875Spjd} 590