pjdlog.c revision 219369
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 219369 2011-03-07 10:33:52Z pjd $"); 33204076Spjd 34204076Spjd#include <assert.h> 35204076Spjd#include <errno.h> 36204076Spjd#include <stdarg.h> 37204076Spjd#include <stdio.h> 38204076Spjd#include <stdlib.h> 39204076Spjd#include <string.h> 40204076Spjd#include <syslog.h> 41204076Spjd 42204076Spjd#include "pjdlog.h" 43204076Spjd 44219369Spjd#define PJDLOG_NEVER_INITIALIZED 0 45219369Spjd#define PJDLOG_NOT_INITIALIZED 1 46219369Spjd#define PJDLOG_INITIALIZED 2 47219369Spjd 48219369Spjdstatic int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED; 49218040Spjdstatic int pjdlog_mode, pjdlog_debug_level; 50204076Spjdstatic char pjdlog_prefix[128]; 51204076Spjd 52217965Spjdvoid 53217965Spjdpjdlog_init(int mode) 54217965Spjd{ 55217965Spjd 56219369Spjd assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED || 57219369Spjd pjdlog_initialized == PJDLOG_NOT_INITIALIZED); 58217965Spjd assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 59217965Spjd 60217965Spjd if (mode == PJDLOG_MODE_SYSLOG) 61217965Spjd openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 62217965Spjd pjdlog_mode = mode; 63218040Spjd pjdlog_debug_level = 0; 64218040Spjd bzero(pjdlog_prefix, sizeof(pjdlog_prefix)); 65217965Spjd 66219369Spjd pjdlog_initialized = PJDLOG_INITIALIZED; 67217965Spjd} 68217965Spjd 69217965Spjdvoid 70217965Spjdpjdlog_fini(void) 71217965Spjd{ 72217965Spjd 73219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 74217965Spjd 75217965Spjd if (pjdlog_mode == PJDLOG_MODE_SYSLOG) 76217965Spjd closelog(); 77217965Spjd 78219369Spjd pjdlog_initialized = PJDLOG_NOT_INITIALIZED; 79217965Spjd} 80217965Spjd 81204076Spjd/* 82204076Spjd * Configure where the logs should go. 83204076Spjd * By default they are send to stdout/stderr, but after going into background 84204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to 85204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 86204076Spjd */ 87204076Spjdvoid 88204076Spjdpjdlog_mode_set(int mode) 89204076Spjd{ 90204076Spjd 91219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 92204076Spjd assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 93204076Spjd 94217965Spjd if (pjdlog_mode == mode) 95217965Spjd return; 96212052Spjd 97212052Spjd if (mode == PJDLOG_MODE_SYSLOG) 98217962Spjd openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 99217965Spjd else /* if (mode == PJDLOG_MODE_STD) */ 100217965Spjd closelog(); 101217965Spjd 102217965Spjd pjdlog_mode = mode; 103204076Spjd} 104204076Spjd 105204076Spjd/* 106204076Spjd * Return current mode. 107204076Spjd */ 108204076Spjdint 109204076Spjdpjdlog_mode_get(void) 110204076Spjd{ 111204076Spjd 112219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 113217965Spjd 114204076Spjd return (pjdlog_mode); 115204076Spjd} 116204076Spjd 117204076Spjd/* 118204076Spjd * Set debug level. All the logs above the level specified here will be 119204076Spjd * ignored. 120204076Spjd */ 121204076Spjdvoid 122204076Spjdpjdlog_debug_set(int level) 123204076Spjd{ 124204076Spjd 125219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 126204076Spjd assert(level >= 0); 127204076Spjd 128204076Spjd pjdlog_debug_level = level; 129204076Spjd} 130204076Spjd 131204076Spjd/* 132204076Spjd * Return current debug level. 133204076Spjd */ 134204076Spjdint 135204076Spjdpjdlog_debug_get(void) 136204076Spjd{ 137204076Spjd 138219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 139217965Spjd 140204076Spjd return (pjdlog_debug_level); 141204076Spjd} 142204076Spjd 143204076Spjd/* 144204076Spjd * Set prefix that will be used before each log. 145204076Spjd * Setting prefix to NULL will remove it. 146204076Spjd */ 147204076Spjdvoid 148204076Spjdpjdlog_prefix_set(const char *fmt, ...) 149204076Spjd{ 150204076Spjd va_list ap; 151204076Spjd 152219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 153217965Spjd 154204076Spjd va_start(ap, fmt); 155217731Spjd pjdlogv_prefix_set(fmt, ap); 156204076Spjd va_end(ap); 157204076Spjd} 158204076Spjd 159204076Spjd/* 160204076Spjd * Set prefix that will be used before each log. 161204076Spjd * Setting prefix to NULL will remove it. 162204076Spjd */ 163204076Spjdvoid 164217731Spjdpjdlogv_prefix_set(const char *fmt, va_list ap) 165204076Spjd{ 166204076Spjd 167219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 168204076Spjd assert(fmt != NULL); 169204076Spjd 170204076Spjd vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 171204076Spjd} 172204076Spjd 173204076Spjd/* 174204076Spjd * Convert log level into string. 175204076Spjd */ 176204076Spjdstatic const char * 177204076Spjdpjdlog_level_string(int loglevel) 178204076Spjd{ 179204076Spjd 180204076Spjd switch (loglevel) { 181204076Spjd case LOG_EMERG: 182204076Spjd return ("EMERG"); 183204076Spjd case LOG_ALERT: 184204076Spjd return ("ALERT"); 185204076Spjd case LOG_CRIT: 186204076Spjd return ("CRIT"); 187204076Spjd case LOG_ERR: 188204076Spjd return ("ERROR"); 189204076Spjd case LOG_WARNING: 190204076Spjd return ("WARNING"); 191204076Spjd case LOG_NOTICE: 192204076Spjd return ("NOTICE"); 193204076Spjd case LOG_INFO: 194204076Spjd return ("INFO"); 195204076Spjd case LOG_DEBUG: 196204076Spjd return ("DEBUG"); 197204076Spjd } 198204076Spjd assert(!"Invalid log level."); 199204076Spjd abort(); /* XXX: gcc */ 200204076Spjd} 201204076Spjd 202204076Spjd/* 203204076Spjd * Common log routine. 204204076Spjd */ 205204076Spjdvoid 206204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 207204076Spjd{ 208204076Spjd va_list ap; 209204076Spjd 210219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 211217965Spjd 212204076Spjd va_start(ap, fmt); 213204076Spjd pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 214204076Spjd va_end(ap); 215204076Spjd} 216204076Spjd 217204076Spjd/* 218204076Spjd * Common log routine, which can handle regular log level as well as debug 219204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog). 220204076Spjd */ 221204076Spjdvoid 222204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 223204076Spjd va_list ap) 224204076Spjd{ 225204076Spjd 226219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 227204076Spjd assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 228204076Spjd loglevel == LOG_CRIT || loglevel == LOG_ERR || 229204076Spjd loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 230204076Spjd loglevel == LOG_INFO || loglevel == LOG_DEBUG); 231204076Spjd assert(loglevel != LOG_DEBUG || debuglevel > 0); 232204076Spjd assert(error >= -1); 233204076Spjd 234204076Spjd /* Ignore debug above configured level. */ 235204076Spjd if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 236204076Spjd return; 237204076Spjd 238204076Spjd switch (pjdlog_mode) { 239204076Spjd case PJDLOG_MODE_STD: 240204076Spjd { 241204076Spjd FILE *out; 242204076Spjd 243204076Spjd /* 244204076Spjd * We send errors and warning to stderr and the rest to stdout. 245204076Spjd */ 246204076Spjd switch (loglevel) { 247204076Spjd case LOG_EMERG: 248204076Spjd case LOG_ALERT: 249204076Spjd case LOG_CRIT: 250204076Spjd case LOG_ERR: 251204076Spjd case LOG_WARNING: 252204076Spjd out = stderr; 253204076Spjd break; 254204076Spjd case LOG_NOTICE: 255204076Spjd case LOG_INFO: 256204076Spjd case LOG_DEBUG: 257204076Spjd out = stdout; 258204076Spjd break; 259204076Spjd default: 260204076Spjd assert(!"Invalid loglevel."); 261204076Spjd abort(); /* XXX: gcc */ 262204076Spjd } 263204076Spjd 264204076Spjd fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 265204076Spjd /* Attach debuglevel if this is debug log. */ 266204076Spjd if (loglevel == LOG_DEBUG) 267204076Spjd fprintf(out, "[%d]", debuglevel); 268213939Spjd fprintf(out, " %s", pjdlog_prefix); 269204076Spjd vfprintf(out, fmt, ap); 270204076Spjd if (error != -1) 271204076Spjd fprintf(out, ": %s.", strerror(error)); 272204076Spjd fprintf(out, "\n"); 273211898Spjd fflush(out); 274204076Spjd break; 275204076Spjd } 276204076Spjd case PJDLOG_MODE_SYSLOG: 277204076Spjd { 278204076Spjd char log[1024]; 279204076Spjd int len; 280204076Spjd 281204076Spjd len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 282204076Spjd if ((size_t)len < sizeof(log)) 283206697Spjd len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 284204076Spjd if (error != -1 && (size_t)len < sizeof(log)) { 285204076Spjd (void)snprintf(log + len, sizeof(log) - len, ": %s.", 286204076Spjd strerror(error)); 287204076Spjd } 288204076Spjd syslog(loglevel, "%s", log); 289204076Spjd break; 290204076Spjd } 291204076Spjd default: 292204076Spjd assert(!"Invalid mode."); 293204076Spjd } 294204076Spjd} 295204076Spjd 296204076Spjd/* 297204076Spjd * Regular logs. 298204076Spjd */ 299204076Spjdvoid 300204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap) 301204076Spjd{ 302204076Spjd 303219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 304217965Spjd 305204076Spjd /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 306204076Spjd assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 307204076Spjd loglevel == LOG_CRIT || loglevel == LOG_ERR || 308204076Spjd loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 309204076Spjd loglevel == LOG_INFO); 310204076Spjd 311204076Spjd pjdlogv_common(loglevel, 0, -1, fmt, ap); 312204076Spjd} 313204076Spjd 314204076Spjd/* 315204076Spjd * Regular logs. 316204076Spjd */ 317204076Spjdvoid 318204076Spjdpjdlog(int loglevel, const char *fmt, ...) 319204076Spjd{ 320204076Spjd va_list ap; 321204076Spjd 322219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 323217965Spjd 324204076Spjd va_start(ap, fmt); 325204076Spjd pjdlogv(loglevel, fmt, ap); 326204076Spjd va_end(ap); 327204076Spjd} 328204076Spjd 329204076Spjd/* 330204076Spjd * Debug logs. 331204076Spjd */ 332204076Spjdvoid 333204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 334204076Spjd{ 335204076Spjd 336219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 337217965Spjd 338204076Spjd pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 339204076Spjd} 340204076Spjd 341204076Spjd/* 342204076Spjd * Debug logs. 343204076Spjd */ 344204076Spjdvoid 345204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...) 346204076Spjd{ 347204076Spjd va_list ap; 348204076Spjd 349219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 350217965Spjd 351204076Spjd va_start(ap, fmt); 352204076Spjd pjdlogv_debug(debuglevel, fmt, ap); 353204076Spjd va_end(ap); 354204076Spjd} 355204076Spjd 356204076Spjd/* 357204076Spjd * Error logs with errno logging. 358204076Spjd */ 359204076Spjdvoid 360204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap) 361204076Spjd{ 362204076Spjd 363219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 364217965Spjd 365204076Spjd pjdlogv_common(loglevel, 0, errno, fmt, ap); 366204076Spjd} 367204076Spjd 368204076Spjd/* 369204076Spjd * Error logs with errno logging. 370204076Spjd */ 371204076Spjdvoid 372204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...) 373204076Spjd{ 374204076Spjd va_list ap; 375204076Spjd 376219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 377217965Spjd 378204076Spjd va_start(ap, fmt); 379204076Spjd pjdlogv_errno(loglevel, fmt, ap); 380204076Spjd va_end(ap); 381204076Spjd} 382204076Spjd 383204076Spjd/* 384204076Spjd * Log error, errno and exit. 385204076Spjd */ 386204076Spjdvoid 387204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap) 388204076Spjd{ 389204076Spjd 390219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 391217965Spjd 392204076Spjd pjdlogv_errno(LOG_ERR, fmt, ap); 393204076Spjd exit(exitcode); 394210872Spjd /* NOTREACHED */ 395204076Spjd} 396204076Spjd 397204076Spjd/* 398204076Spjd * Log error, errno and exit. 399204076Spjd */ 400204076Spjdvoid 401204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...) 402204076Spjd{ 403204076Spjd va_list ap; 404204076Spjd 405219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 406217965Spjd 407204076Spjd va_start(ap, fmt); 408204076Spjd pjdlogv_exit(exitcode, fmt, ap); 409204076Spjd /* NOTREACHED */ 410204076Spjd va_end(ap); 411204076Spjd} 412204076Spjd 413204076Spjd/* 414204076Spjd * Log error and exit. 415204076Spjd */ 416204076Spjdvoid 417204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 418204076Spjd{ 419204076Spjd 420219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 421217965Spjd 422204076Spjd pjdlogv(LOG_ERR, fmt, ap); 423204076Spjd exit(exitcode); 424210872Spjd /* NOTREACHED */ 425204076Spjd} 426204076Spjd 427204076Spjd/* 428204076Spjd * Log error and exit. 429204076Spjd */ 430204076Spjdvoid 431204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...) 432204076Spjd{ 433204076Spjd va_list ap; 434204076Spjd 435219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 436217965Spjd 437204076Spjd va_start(ap, fmt); 438204076Spjd pjdlogv_exitx(exitcode, fmt, ap); 439204076Spjd /* NOTREACHED */ 440204076Spjd va_end(ap); 441204076Spjd} 442210875Spjd 443210875Spjd/* 444218132Spjd * Log failure message and exit. 445210875Spjd */ 446210875Spjdvoid 447218132Spjdpjdlog_abort(const char *func, const char *file, int line, 448217966Spjd const char *failedexpr, const char *fmt, ...) 449210875Spjd{ 450217966Spjd va_list ap; 451210875Spjd 452219369Spjd assert(pjdlog_initialized == PJDLOG_INITIALIZED); 453217966Spjd 454217966Spjd /* 455217966Spjd * When there is no message we pass __func__ as 'fmt'. 456217966Spjd * It would be cleaner to pass NULL or "", but gcc generates a warning 457217966Spjd * for both of those. 458217966Spjd */ 459217966Spjd if (fmt != func) { 460217966Spjd va_start(ap, fmt); 461217966Spjd pjdlogv_critical(fmt, ap); 462217966Spjd va_end(ap); 463217966Spjd } 464217966Spjd if (failedexpr == NULL) { 465217966Spjd if (func == NULL) { 466217966Spjd pjdlog_critical("Aborted at file %s, line %d.", file, 467217966Spjd line); 468217966Spjd } else { 469217966Spjd pjdlog_critical("Aborted at function %s, file %s, line %d.", 470217966Spjd func, file, line); 471217966Spjd } 472210875Spjd } else { 473217966Spjd if (func == NULL) { 474217966Spjd pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 475217966Spjd failedexpr, file, line); 476217966Spjd } else { 477217966Spjd pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 478217966Spjd failedexpr, func, file, line); 479217966Spjd } 480210875Spjd } 481210875Spjd abort(); 482210875Spjd} 483