pjdlog.c revision 212052
160812Sps/*- 260786Sps * Copyright (c) 2009-2010 The FreeBSD Foundation 3221715Sdelphij * All rights reserved. 460786Sps * 560786Sps * This software was developed by Pawel Jakub Dawidek under sponsorship from 660786Sps * the FreeBSD Foundation. 760786Sps * 860786Sps * Redistribution and use in source and binary forms, with or without 960786Sps * modification, are permitted provided that the following conditions 1060786Sps * are met: 1160786Sps * 1. Redistributions of source code must retain the above copyright 1260786Sps * notice, this list of conditions and the following disclaimer. 1360786Sps * 2. Redistributions in binary form must reproduce the above copyright 1460786Sps * notice, this list of conditions and the following disclaimer in the 1560786Sps * documentation and/or other materials provided with the distribution. 1660786Sps * 1760786Sps * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18195941Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1960786Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20172471Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 2160786Sps * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2260786Sps * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2360786Sps * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2460786Sps * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2560786Sps * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2660786Sps * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2760786Sps * SUCH DAMAGE. 2860786Sps */ 2960786Sps 3060786Sps#include <sys/cdefs.h> 3160786Sps__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 212052 2010-08-31 12:05:13Z pjd $"); 32170259Sdelphij 33128348Stjr#include <assert.h> 3463131Sps#include <errno.h> 35170259Sdelphij#include <stdarg.h> 3660786Sps#include <stdio.h> 3760786Sps#include <stdlib.h> 38191930Sdelphij#include <string.h> 39191930Sdelphij#include <syslog.h> 4060786Sps 4160786Sps#include "pjdlog.h" 4260786Sps 4360786Spsstatic int pjdlog_mode = PJDLOG_MODE_STD; 4460786Spsstatic int pjdlog_debug_level = 0; 4560786Spsstatic char pjdlog_prefix[128]; 4660786Sps 4760786Sps/* 48195941Sdelphij * Configure where the logs should go. 49195941Sdelphij * By default they are send to stdout/stderr, but after going into background 5060786Sps * (eg. by calling daemon(3)) application is responsible for changing mode to 5160786Sps * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 5260786Sps */ 5360786Spsvoid 5460786Spspjdlog_mode_set(int mode) 5560786Sps{ 5660786Sps 5760786Sps assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 58191930Sdelphij 5960786Sps pjdlog_mode = mode; 6060786Sps 6160786Sps if (mode == PJDLOG_MODE_SYSLOG) 6260786Sps openlog(NULL, LOG_PID, LOG_DAEMON); 6360786Sps} 64195941Sdelphij 6560786Sps/* 66195941Sdelphij * Return current mode. 67195941Sdelphij */ 68195941Sdelphijint 69195941Sdelphijpjdlog_mode_get(void) 70195941Sdelphij{ 71195941Sdelphij 72195941Sdelphij return (pjdlog_mode); 73195941Sdelphij} 7460786Sps 75173685Sdelphij/* 76221715Sdelphij * Set debug level. All the logs above the level specified here will be 77221715Sdelphij * ignored. 78221715Sdelphij */ 79221715Sdelphijvoid 80221715Sdelphijpjdlog_debug_set(int level) 81221715Sdelphij{ 82221715Sdelphij 83221715Sdelphij assert(level >= 0); 84221715Sdelphij 85221715Sdelphij pjdlog_debug_level = level; 86221715Sdelphij} 87221715Sdelphij 88221715Sdelphij/* 89221715Sdelphij * Return current debug level. 90221715Sdelphij */ 91221715Sdelphijint 92221715Sdelphijpjdlog_debug_get(void) 93221715Sdelphij{ 94221715Sdelphij 95195941Sdelphij return (pjdlog_debug_level); 96173685Sdelphij} 97173685Sdelphij 98195941Sdelphij/* 99195941Sdelphij * Set prefix that will be used before each log. 100195941Sdelphij * Setting prefix to NULL will remove it. 101195941Sdelphij */ 102173685Sdelphijvoid 103195941Sdelphijpjdlog_prefix_set(const char *fmt, ...) 104195941Sdelphij{ 105195941Sdelphij va_list ap; 106195941Sdelphij 107195941Sdelphij va_start(ap, fmt); 108195941Sdelphij pjdlog_prefix_setv(fmt, ap); 109195941Sdelphij va_end(ap); 110195941Sdelphij} 111195941Sdelphij 112195941Sdelphij/* 113195941Sdelphij * Set prefix that will be used before each log. 114195941Sdelphij * Setting prefix to NULL will remove it. 115195941Sdelphij */ 116195941Sdelphijvoid 117221715Sdelphijpjdlog_prefix_setv(const char *fmt, va_list ap) 118221715Sdelphij{ 119221715Sdelphij 120221715Sdelphij assert(fmt != NULL); 121221715Sdelphij 122221715Sdelphij vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 123221715Sdelphij} 124221715Sdelphij 125221715Sdelphij/* 126221715Sdelphij * Convert log level into string. 127195941Sdelphij */ 128173685Sdelphijstatic const char * 129173685Sdelphijpjdlog_level_string(int loglevel) 130173685Sdelphij{ 131195941Sdelphij 132173685Sdelphij switch (loglevel) { 13360786Sps case LOG_EMERG: 134195941Sdelphij return ("EMERG"); 135195941Sdelphij case LOG_ALERT: 13660786Sps return ("ALERT"); 137195941Sdelphij case LOG_CRIT: 138195941Sdelphij return ("CRIT"); 139195941Sdelphij case LOG_ERR: 140195941Sdelphij return ("ERROR"); 141195941Sdelphij case LOG_WARNING: 14260786Sps return ("WARNING"); 143195941Sdelphij case LOG_NOTICE: 144195941Sdelphij return ("NOTICE"); 145195941Sdelphij case LOG_INFO: 146195941Sdelphij return ("INFO"); 147195941Sdelphij case LOG_DEBUG: 148195941Sdelphij return ("DEBUG"); 149195941Sdelphij } 150195941Sdelphij assert(!"Invalid log level."); 151195941Sdelphij abort(); /* XXX: gcc */ 152195941Sdelphij} 153195941Sdelphij 154170259Sdelphij/* 155195941Sdelphij * Common log routine. 156195941Sdelphij */ 157195941Sdelphijvoid 158195941Sdelphijpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 159195941Sdelphij{ 160195941Sdelphij va_list ap; 161195941Sdelphij 162195941Sdelphij va_start(ap, fmt); 16360786Sps pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 16460786Sps va_end(ap); 16560786Sps} 166195941Sdelphij 167128348Stjr/* 168128348Stjr * Common log routine, which can handle regular log level as well as debug 169128348Stjr * level. We decide here where to send the logs (stdout/stderr or syslog). 170128348Stjr */ 171128348Stjrvoid 172128348Stjrpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 173128348Stjr va_list ap) 174128348Stjr{ 175128348Stjr 176128348Stjr assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 177128348Stjr loglevel == LOG_CRIT || loglevel == LOG_ERR || 178128348Stjr loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 179128348Stjr loglevel == LOG_INFO || loglevel == LOG_DEBUG); 180128348Stjr assert(loglevel != LOG_DEBUG || debuglevel > 0); 181128348Stjr assert(error >= -1); 182128348Stjr 183128348Stjr /* Ignore debug above configured level. */ 184128348Stjr if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 185128348Stjr return; 186128348Stjr 187128348Stjr switch (pjdlog_mode) { 188128348Stjr case PJDLOG_MODE_STD: 189128348Stjr { 19060786Sps FILE *out; 19160786Sps 19260786Sps /* 193195941Sdelphij * We send errors and warning to stderr and the rest to stdout. 194195941Sdelphij */ 19560786Sps switch (loglevel) { 196195941Sdelphij case LOG_EMERG: 197195941Sdelphij case LOG_ALERT: 198195941Sdelphij case LOG_CRIT: 19960786Sps case LOG_ERR: 20060786Sps case LOG_WARNING: 20160786Sps out = stderr; 20260786Sps break; 20360786Sps case LOG_NOTICE: 20460786Sps case LOG_INFO: 20560786Sps case LOG_DEBUG: 20660786Sps out = stdout; 20760786Sps break; 20860786Sps default: 20960786Sps assert(!"Invalid loglevel."); 21060786Sps abort(); /* XXX: gcc */ 21160786Sps } 21260786Sps 21360786Sps fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 21460786Sps /* Attach debuglevel if this is debug log. */ 21560786Sps if (loglevel == LOG_DEBUG) 21660786Sps fprintf(out, "[%d]", debuglevel); 21760786Sps fprintf(out, " "); 21860786Sps fprintf(out, "%s", pjdlog_prefix); 21960786Sps vfprintf(out, fmt, ap); 22060786Sps if (error != -1) 22160786Sps fprintf(out, ": %s.", strerror(error)); 22260786Sps fprintf(out, "\n"); 22360786Sps fflush(out); 22460786Sps break; 22560786Sps } 22660786Sps case PJDLOG_MODE_SYSLOG: 22760786Sps { 22860786Sps char log[1024]; 22960786Sps int len; 23060786Sps 23160786Sps len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 23260786Sps if ((size_t)len < sizeof(log)) 23360786Sps len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 23460786Sps if (error != -1 && (size_t)len < sizeof(log)) { 23560786Sps (void)snprintf(log + len, sizeof(log) - len, ": %s.", 23660786Sps strerror(error)); 23760786Sps } 23860786Sps syslog(loglevel, "%s", log); 23960786Sps break; 240195941Sdelphij } 241195941Sdelphij default: 242195941Sdelphij assert(!"Invalid mode."); 24360786Sps } 244221715Sdelphij} 24560786Sps 24660786Sps/* 24760786Sps * Regular logs. 24860786Sps */ 24960786Spsvoid 25060786Spspjdlogv(int loglevel, const char *fmt, va_list ap) 25160786Sps{ 25260786Sps 25360786Sps /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 25460786Sps assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 25560786Sps loglevel == LOG_CRIT || loglevel == LOG_ERR || 25660786Sps loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 25760786Sps loglevel == LOG_INFO); 25860786Sps 259170898Sdelphij pjdlogv_common(loglevel, 0, -1, fmt, ap); 26060786Sps} 26160786Sps 26260786Sps/* 26360786Sps * Regular logs. 26460786Sps */ 26560786Spsvoid 26660786Spspjdlog(int loglevel, const char *fmt, ...) 26760786Sps{ 26860786Sps va_list ap; 26960786Sps 27060786Sps va_start(ap, fmt); 27160786Sps pjdlogv(loglevel, fmt, ap); 27260786Sps va_end(ap); 27360786Sps} 27460786Sps 27560786Sps/* 27660786Sps * Debug logs. 27760786Sps */ 27860786Spsvoid 27960786Spspjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 28060786Sps{ 28160786Sps 28260786Sps pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 28360786Sps} 28460786Sps 28560786Sps/* 28660786Sps * Debug logs. 287170898Sdelphij */ 28860786Spsvoid 28960786Spspjdlog_debug(int debuglevel, const char *fmt, ...) 290170898Sdelphij{ 291170898Sdelphij va_list ap; 29260786Sps 29360786Sps va_start(ap, fmt); 29460786Sps pjdlogv_debug(debuglevel, fmt, ap); 29560786Sps va_end(ap); 29660786Sps} 29760786Sps 29860786Sps/* 29960786Sps * Error logs with errno logging. 30060786Sps */ 301195941Sdelphijvoid 30260786Spspjdlogv_errno(int loglevel, const char *fmt, va_list ap) 30360786Sps{ 30460786Sps 30560786Sps pjdlogv_common(loglevel, 0, errno, fmt, ap); 30660786Sps} 30760786Sps 30860786Sps/* 30960786Sps * Error logs with errno logging. 31060786Sps */ 31160786Spsvoid 31260786Spspjdlog_errno(int loglevel, const char *fmt, ...) 31360786Sps{ 31460786Sps va_list ap; 31560786Sps 31660786Sps va_start(ap, fmt); 317191930Sdelphij pjdlogv_errno(loglevel, fmt, ap); 318191930Sdelphij va_end(ap); 31960786Sps} 32060786Sps 32160786Sps/* 32260786Sps * Log error, errno and exit. 323191930Sdelphij */ 32460786Spsvoid 32560786Spspjdlogv_exit(int exitcode, const char *fmt, va_list ap) 32660786Sps{ 32760786Sps 328191930Sdelphij pjdlogv_errno(LOG_ERR, fmt, ap); 32960786Sps exit(exitcode); 33060786Sps /* NOTREACHED */ 33160786Sps} 332191930Sdelphij 333191930Sdelphij/* 334191930Sdelphij * Log error, errno and exit. 335191930Sdelphij */ 336191930Sdelphijvoid 337191930Sdelphijpjdlog_exit(int exitcode, const char *fmt, ...) 338191930Sdelphij{ 339191930Sdelphij va_list ap; 340191930Sdelphij 341191930Sdelphij va_start(ap, fmt); 342191930Sdelphij pjdlogv_exit(exitcode, fmt, ap); 343191930Sdelphij /* NOTREACHED */ 34460786Sps va_end(ap); 34560786Sps} 346161478Sdelphij 347161478Sdelphij/* 348161478Sdelphij * Log error and exit. 349161478Sdelphij */ 350161478Sdelphijvoid 351161478Sdelphijpjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 352161478Sdelphij{ 353161478Sdelphij 354161478Sdelphij pjdlogv(LOG_ERR, fmt, ap); 355161478Sdelphij exit(exitcode); 356161478Sdelphij /* NOTREACHED */ 357161478Sdelphij} 358161478Sdelphij 359161478Sdelphij/* 360161478Sdelphij * Log error and exit. 361161478Sdelphij */ 362161478Sdelphijvoid 363161478Sdelphijpjdlog_exitx(int exitcode, const char *fmt, ...) 364161478Sdelphij{ 365161478Sdelphij va_list ap; 366191930Sdelphij 367191930Sdelphij va_start(ap, fmt); 368191930Sdelphij pjdlogv_exitx(exitcode, fmt, ap); 369191930Sdelphij /* NOTREACHED */ 370191930Sdelphij va_end(ap); 371191930Sdelphij} 372191930Sdelphij 373191930Sdelphij/* 374191930Sdelphij * Log assertion and exit. 375191930Sdelphij */ 376191930Sdelphijvoid 377191930Sdelphijpjdlog_verify(const char *func, const char *file, int line, 378191930Sdelphij const char *failedexpr) 379191930Sdelphij{ 380191930Sdelphij 381191930Sdelphij if (func == NULL) { 382191930Sdelphij pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 383191930Sdelphij failedexpr, file, line); 384191930Sdelphij } else { 385191930Sdelphij pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 386191930Sdelphij failedexpr, func, file, line); 387191930Sdelphij } 388191930Sdelphij abort(); 389191930Sdelphij /* NOTREACHED */ 390161478Sdelphij} 391161478Sdelphij 39260786Sps