pjdlog.c revision 217731
1204076Spjd/*- 2204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 3204076Spjd * All rights reserved. 4204076Spjd * 5204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 6204076Spjd * the FreeBSD Foundation. 7204076Spjd * 8204076Spjd * Redistribution and use in source and binary forms, with or without 9204076Spjd * modification, are permitted provided that the following conditions 10204076Spjd * are met: 11204076Spjd * 1. Redistributions of source code must retain the above copyright 12204076Spjd * notice, this list of conditions and the following disclaimer. 13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 14204076Spjd * notice, this list of conditions and the following disclaimer in the 15204076Spjd * documentation and/or other materials provided with the distribution. 16204076Spjd * 17204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27204076Spjd * SUCH DAMAGE. 28204076Spjd */ 29204076Spjd 30204076Spjd#include <sys/cdefs.h> 31204076Spjd__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 217731 2011-01-22 22:35:08Z pjd $"); 32204076Spjd 33204076Spjd#include <assert.h> 34204076Spjd#include <errno.h> 35204076Spjd#include <stdarg.h> 36204076Spjd#include <stdio.h> 37204076Spjd#include <stdlib.h> 38204076Spjd#include <string.h> 39204076Spjd#include <syslog.h> 40204076Spjd 41204076Spjd#include "pjdlog.h" 42204076Spjd 43204076Spjdstatic int pjdlog_mode = PJDLOG_MODE_STD; 44204076Spjdstatic int pjdlog_debug_level = 0; 45204076Spjdstatic char pjdlog_prefix[128]; 46204076Spjd 47204076Spjd/* 48204076Spjd * Configure where the logs should go. 49204076Spjd * By default they are send to stdout/stderr, but after going into background 50204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to 51204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 52204076Spjd */ 53204076Spjdvoid 54204076Spjdpjdlog_mode_set(int mode) 55204076Spjd{ 56204076Spjd 57204076Spjd assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 58204076Spjd 59204076Spjd pjdlog_mode = mode; 60212052Spjd 61212052Spjd if (mode == PJDLOG_MODE_SYSLOG) 62212052Spjd openlog(NULL, LOG_PID, LOG_DAEMON); 63204076Spjd} 64204076Spjd 65204076Spjd/* 66204076Spjd * Return current mode. 67204076Spjd */ 68204076Spjdint 69204076Spjdpjdlog_mode_get(void) 70204076Spjd{ 71204076Spjd 72204076Spjd return (pjdlog_mode); 73204076Spjd} 74204076Spjd 75204076Spjd/* 76204076Spjd * Set debug level. All the logs above the level specified here will be 77204076Spjd * ignored. 78204076Spjd */ 79204076Spjdvoid 80204076Spjdpjdlog_debug_set(int level) 81204076Spjd{ 82204076Spjd 83204076Spjd assert(level >= 0); 84204076Spjd 85204076Spjd pjdlog_debug_level = level; 86204076Spjd} 87204076Spjd 88204076Spjd/* 89204076Spjd * Return current debug level. 90204076Spjd */ 91204076Spjdint 92204076Spjdpjdlog_debug_get(void) 93204076Spjd{ 94204076Spjd 95204076Spjd return (pjdlog_debug_level); 96204076Spjd} 97204076Spjd 98204076Spjd/* 99204076Spjd * Set prefix that will be used before each log. 100204076Spjd * Setting prefix to NULL will remove it. 101204076Spjd */ 102204076Spjdvoid 103204076Spjdpjdlog_prefix_set(const char *fmt, ...) 104204076Spjd{ 105204076Spjd va_list ap; 106204076Spjd 107204076Spjd va_start(ap, fmt); 108217731Spjd pjdlogv_prefix_set(fmt, ap); 109204076Spjd va_end(ap); 110204076Spjd} 111204076Spjd 112204076Spjd/* 113204076Spjd * Set prefix that will be used before each log. 114204076Spjd * Setting prefix to NULL will remove it. 115204076Spjd */ 116204076Spjdvoid 117217731Spjdpjdlogv_prefix_set(const char *fmt, va_list ap) 118204076Spjd{ 119204076Spjd 120204076Spjd assert(fmt != NULL); 121204076Spjd 122204076Spjd vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 123204076Spjd} 124204076Spjd 125204076Spjd/* 126204076Spjd * Convert log level into string. 127204076Spjd */ 128204076Spjdstatic const char * 129204076Spjdpjdlog_level_string(int loglevel) 130204076Spjd{ 131204076Spjd 132204076Spjd switch (loglevel) { 133204076Spjd case LOG_EMERG: 134204076Spjd return ("EMERG"); 135204076Spjd case LOG_ALERT: 136204076Spjd return ("ALERT"); 137204076Spjd case LOG_CRIT: 138204076Spjd return ("CRIT"); 139204076Spjd case LOG_ERR: 140204076Spjd return ("ERROR"); 141204076Spjd case LOG_WARNING: 142204076Spjd return ("WARNING"); 143204076Spjd case LOG_NOTICE: 144204076Spjd return ("NOTICE"); 145204076Spjd case LOG_INFO: 146204076Spjd return ("INFO"); 147204076Spjd case LOG_DEBUG: 148204076Spjd return ("DEBUG"); 149204076Spjd } 150204076Spjd assert(!"Invalid log level."); 151204076Spjd abort(); /* XXX: gcc */ 152204076Spjd} 153204076Spjd 154204076Spjd/* 155204076Spjd * Common log routine. 156204076Spjd */ 157204076Spjdvoid 158204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 159204076Spjd{ 160204076Spjd va_list ap; 161204076Spjd 162204076Spjd va_start(ap, fmt); 163204076Spjd pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 164204076Spjd va_end(ap); 165204076Spjd} 166204076Spjd 167204076Spjd/* 168204076Spjd * Common log routine, which can handle regular log level as well as debug 169204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog). 170204076Spjd */ 171204076Spjdvoid 172204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 173204076Spjd va_list ap) 174204076Spjd{ 175204076Spjd 176204076Spjd assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 177204076Spjd loglevel == LOG_CRIT || loglevel == LOG_ERR || 178204076Spjd loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 179204076Spjd loglevel == LOG_INFO || loglevel == LOG_DEBUG); 180204076Spjd assert(loglevel != LOG_DEBUG || debuglevel > 0); 181204076Spjd assert(error >= -1); 182204076Spjd 183204076Spjd /* Ignore debug above configured level. */ 184204076Spjd if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 185204076Spjd return; 186204076Spjd 187204076Spjd switch (pjdlog_mode) { 188204076Spjd case PJDLOG_MODE_STD: 189204076Spjd { 190204076Spjd FILE *out; 191204076Spjd 192204076Spjd /* 193204076Spjd * We send errors and warning to stderr and the rest to stdout. 194204076Spjd */ 195204076Spjd switch (loglevel) { 196204076Spjd case LOG_EMERG: 197204076Spjd case LOG_ALERT: 198204076Spjd case LOG_CRIT: 199204076Spjd case LOG_ERR: 200204076Spjd case LOG_WARNING: 201204076Spjd out = stderr; 202204076Spjd break; 203204076Spjd case LOG_NOTICE: 204204076Spjd case LOG_INFO: 205204076Spjd case LOG_DEBUG: 206204076Spjd out = stdout; 207204076Spjd break; 208204076Spjd default: 209204076Spjd assert(!"Invalid loglevel."); 210204076Spjd abort(); /* XXX: gcc */ 211204076Spjd } 212204076Spjd 213204076Spjd fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 214204076Spjd /* Attach debuglevel if this is debug log. */ 215204076Spjd if (loglevel == LOG_DEBUG) 216204076Spjd fprintf(out, "[%d]", debuglevel); 217213939Spjd fprintf(out, " %s", pjdlog_prefix); 218204076Spjd vfprintf(out, fmt, ap); 219204076Spjd if (error != -1) 220204076Spjd fprintf(out, ": %s.", strerror(error)); 221204076Spjd fprintf(out, "\n"); 222211898Spjd fflush(out); 223204076Spjd break; 224204076Spjd } 225204076Spjd case PJDLOG_MODE_SYSLOG: 226204076Spjd { 227204076Spjd char log[1024]; 228204076Spjd int len; 229204076Spjd 230204076Spjd len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 231204076Spjd if ((size_t)len < sizeof(log)) 232206697Spjd len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 233204076Spjd if (error != -1 && (size_t)len < sizeof(log)) { 234204076Spjd (void)snprintf(log + len, sizeof(log) - len, ": %s.", 235204076Spjd strerror(error)); 236204076Spjd } 237204076Spjd syslog(loglevel, "%s", log); 238204076Spjd break; 239204076Spjd } 240204076Spjd default: 241204076Spjd assert(!"Invalid mode."); 242204076Spjd } 243204076Spjd} 244204076Spjd 245204076Spjd/* 246204076Spjd * Regular logs. 247204076Spjd */ 248204076Spjdvoid 249204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap) 250204076Spjd{ 251204076Spjd 252204076Spjd /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 253204076Spjd assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 254204076Spjd loglevel == LOG_CRIT || loglevel == LOG_ERR || 255204076Spjd loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 256204076Spjd loglevel == LOG_INFO); 257204076Spjd 258204076Spjd pjdlogv_common(loglevel, 0, -1, fmt, ap); 259204076Spjd} 260204076Spjd 261204076Spjd/* 262204076Spjd * Regular logs. 263204076Spjd */ 264204076Spjdvoid 265204076Spjdpjdlog(int loglevel, const char *fmt, ...) 266204076Spjd{ 267204076Spjd va_list ap; 268204076Spjd 269204076Spjd va_start(ap, fmt); 270204076Spjd pjdlogv(loglevel, fmt, ap); 271204076Spjd va_end(ap); 272204076Spjd} 273204076Spjd 274204076Spjd/* 275204076Spjd * Debug logs. 276204076Spjd */ 277204076Spjdvoid 278204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 279204076Spjd{ 280204076Spjd 281204076Spjd pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 282204076Spjd} 283204076Spjd 284204076Spjd/* 285204076Spjd * Debug logs. 286204076Spjd */ 287204076Spjdvoid 288204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...) 289204076Spjd{ 290204076Spjd va_list ap; 291204076Spjd 292204076Spjd va_start(ap, fmt); 293204076Spjd pjdlogv_debug(debuglevel, fmt, ap); 294204076Spjd va_end(ap); 295204076Spjd} 296204076Spjd 297204076Spjd/* 298204076Spjd * Error logs with errno logging. 299204076Spjd */ 300204076Spjdvoid 301204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap) 302204076Spjd{ 303204076Spjd 304204076Spjd pjdlogv_common(loglevel, 0, errno, fmt, ap); 305204076Spjd} 306204076Spjd 307204076Spjd/* 308204076Spjd * Error logs with errno logging. 309204076Spjd */ 310204076Spjdvoid 311204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...) 312204076Spjd{ 313204076Spjd va_list ap; 314204076Spjd 315204076Spjd va_start(ap, fmt); 316204076Spjd pjdlogv_errno(loglevel, fmt, ap); 317204076Spjd va_end(ap); 318204076Spjd} 319204076Spjd 320204076Spjd/* 321204076Spjd * Log error, errno and exit. 322204076Spjd */ 323204076Spjdvoid 324204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap) 325204076Spjd{ 326204076Spjd 327204076Spjd pjdlogv_errno(LOG_ERR, fmt, ap); 328204076Spjd exit(exitcode); 329210872Spjd /* NOTREACHED */ 330204076Spjd} 331204076Spjd 332204076Spjd/* 333204076Spjd * Log error, errno and exit. 334204076Spjd */ 335204076Spjdvoid 336204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...) 337204076Spjd{ 338204076Spjd va_list ap; 339204076Spjd 340204076Spjd va_start(ap, fmt); 341204076Spjd pjdlogv_exit(exitcode, fmt, ap); 342204076Spjd /* NOTREACHED */ 343204076Spjd va_end(ap); 344204076Spjd} 345204076Spjd 346204076Spjd/* 347204076Spjd * Log error and exit. 348204076Spjd */ 349204076Spjdvoid 350204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 351204076Spjd{ 352204076Spjd 353204076Spjd pjdlogv(LOG_ERR, fmt, ap); 354204076Spjd exit(exitcode); 355210872Spjd /* NOTREACHED */ 356204076Spjd} 357204076Spjd 358204076Spjd/* 359204076Spjd * Log error and exit. 360204076Spjd */ 361204076Spjdvoid 362204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...) 363204076Spjd{ 364204076Spjd va_list ap; 365204076Spjd 366204076Spjd va_start(ap, fmt); 367204076Spjd pjdlogv_exitx(exitcode, fmt, ap); 368204076Spjd /* NOTREACHED */ 369204076Spjd va_end(ap); 370204076Spjd} 371210875Spjd 372210875Spjd/* 373210875Spjd * Log assertion and exit. 374210875Spjd */ 375210875Spjdvoid 376210875Spjdpjdlog_verify(const char *func, const char *file, int line, 377210875Spjd const char *failedexpr) 378210875Spjd{ 379210875Spjd 380210875Spjd if (func == NULL) { 381210875Spjd pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 382210875Spjd failedexpr, file, line); 383210875Spjd } else { 384210875Spjd pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 385210875Spjd failedexpr, func, file, line); 386210875Spjd } 387210875Spjd abort(); 388210875Spjd /* NOTREACHED */ 389210875Spjd} 390210875Spjd 391