pjdlog.c revision 218132
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 218132 2011-01-31 15:52:00Z pjd $"); 33204076Spjd 34204076Spjd#include <assert.h> 35204076Spjd#include <errno.h> 36204076Spjd#include <stdarg.h> 37217965Spjd#include <stdbool.h> 38204076Spjd#include <stdio.h> 39204076Spjd#include <stdlib.h> 40204076Spjd#include <string.h> 41204076Spjd#include <syslog.h> 42204076Spjd 43204076Spjd#include "pjdlog.h" 44204076Spjd 45217965Spjdstatic bool pjdlog_initialized = false; 46218040Spjdstatic int pjdlog_mode, pjdlog_debug_level; 47204076Spjdstatic char pjdlog_prefix[128]; 48204076Spjd 49217965Spjdvoid 50217965Spjdpjdlog_init(int mode) 51217965Spjd{ 52217965Spjd 53217965Spjd assert(!pjdlog_initialized); 54217965Spjd assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 55217965Spjd 56217965Spjd if (mode == PJDLOG_MODE_SYSLOG) 57217965Spjd openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 58217965Spjd pjdlog_mode = mode; 59218040Spjd pjdlog_debug_level = 0; 60218040Spjd bzero(pjdlog_prefix, sizeof(pjdlog_prefix)); 61217965Spjd 62217965Spjd pjdlog_initialized = true; 63217965Spjd} 64217965Spjd 65217965Spjdvoid 66217965Spjdpjdlog_fini(void) 67217965Spjd{ 68217965Spjd 69217965Spjd assert(pjdlog_initialized); 70217965Spjd 71217965Spjd if (pjdlog_mode == PJDLOG_MODE_SYSLOG) 72217965Spjd closelog(); 73217965Spjd 74217965Spjd pjdlog_initialized = false; 75217965Spjd} 76217965Spjd 77204076Spjd/* 78204076Spjd * Configure where the logs should go. 79204076Spjd * By default they are send to stdout/stderr, but after going into background 80204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to 81204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 82204076Spjd */ 83204076Spjdvoid 84204076Spjdpjdlog_mode_set(int mode) 85204076Spjd{ 86204076Spjd 87217965Spjd assert(pjdlog_initialized); 88204076Spjd assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 89204076Spjd 90217965Spjd if (pjdlog_mode == mode) 91217965Spjd return; 92212052Spjd 93212052Spjd if (mode == PJDLOG_MODE_SYSLOG) 94217962Spjd openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 95217965Spjd else /* if (mode == PJDLOG_MODE_STD) */ 96217965Spjd closelog(); 97217965Spjd 98217965Spjd pjdlog_mode = mode; 99204076Spjd} 100204076Spjd 101204076Spjd/* 102204076Spjd * Return current mode. 103204076Spjd */ 104204076Spjdint 105204076Spjdpjdlog_mode_get(void) 106204076Spjd{ 107204076Spjd 108217965Spjd assert(pjdlog_initialized); 109217965Spjd 110204076Spjd return (pjdlog_mode); 111204076Spjd} 112204076Spjd 113204076Spjd/* 114204076Spjd * Set debug level. All the logs above the level specified here will be 115204076Spjd * ignored. 116204076Spjd */ 117204076Spjdvoid 118204076Spjdpjdlog_debug_set(int level) 119204076Spjd{ 120204076Spjd 121217965Spjd assert(pjdlog_initialized); 122204076Spjd assert(level >= 0); 123204076Spjd 124204076Spjd pjdlog_debug_level = level; 125204076Spjd} 126204076Spjd 127204076Spjd/* 128204076Spjd * Return current debug level. 129204076Spjd */ 130204076Spjdint 131204076Spjdpjdlog_debug_get(void) 132204076Spjd{ 133204076Spjd 134217965Spjd assert(pjdlog_initialized); 135217965Spjd 136204076Spjd return (pjdlog_debug_level); 137204076Spjd} 138204076Spjd 139204076Spjd/* 140204076Spjd * Set prefix that will be used before each log. 141204076Spjd * Setting prefix to NULL will remove it. 142204076Spjd */ 143204076Spjdvoid 144204076Spjdpjdlog_prefix_set(const char *fmt, ...) 145204076Spjd{ 146204076Spjd va_list ap; 147204076Spjd 148217965Spjd assert(pjdlog_initialized); 149217965Spjd 150204076Spjd va_start(ap, fmt); 151217731Spjd pjdlogv_prefix_set(fmt, ap); 152204076Spjd va_end(ap); 153204076Spjd} 154204076Spjd 155204076Spjd/* 156204076Spjd * Set prefix that will be used before each log. 157204076Spjd * Setting prefix to NULL will remove it. 158204076Spjd */ 159204076Spjdvoid 160217731Spjdpjdlogv_prefix_set(const char *fmt, va_list ap) 161204076Spjd{ 162204076Spjd 163217965Spjd assert(pjdlog_initialized); 164204076Spjd assert(fmt != NULL); 165204076Spjd 166204076Spjd vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 167204076Spjd} 168204076Spjd 169204076Spjd/* 170204076Spjd * Convert log level into string. 171204076Spjd */ 172204076Spjdstatic const char * 173204076Spjdpjdlog_level_string(int loglevel) 174204076Spjd{ 175204076Spjd 176204076Spjd switch (loglevel) { 177204076Spjd case LOG_EMERG: 178204076Spjd return ("EMERG"); 179204076Spjd case LOG_ALERT: 180204076Spjd return ("ALERT"); 181204076Spjd case LOG_CRIT: 182204076Spjd return ("CRIT"); 183204076Spjd case LOG_ERR: 184204076Spjd return ("ERROR"); 185204076Spjd case LOG_WARNING: 186204076Spjd return ("WARNING"); 187204076Spjd case LOG_NOTICE: 188204076Spjd return ("NOTICE"); 189204076Spjd case LOG_INFO: 190204076Spjd return ("INFO"); 191204076Spjd case LOG_DEBUG: 192204076Spjd return ("DEBUG"); 193204076Spjd } 194204076Spjd assert(!"Invalid log level."); 195204076Spjd abort(); /* XXX: gcc */ 196204076Spjd} 197204076Spjd 198204076Spjd/* 199204076Spjd * Common log routine. 200204076Spjd */ 201204076Spjdvoid 202204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 203204076Spjd{ 204204076Spjd va_list ap; 205204076Spjd 206217965Spjd assert(pjdlog_initialized); 207217965Spjd 208204076Spjd va_start(ap, fmt); 209204076Spjd pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 210204076Spjd va_end(ap); 211204076Spjd} 212204076Spjd 213204076Spjd/* 214204076Spjd * Common log routine, which can handle regular log level as well as debug 215204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog). 216204076Spjd */ 217204076Spjdvoid 218204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 219204076Spjd va_list ap) 220204076Spjd{ 221204076Spjd 222217965Spjd assert(pjdlog_initialized); 223204076Spjd assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 224204076Spjd loglevel == LOG_CRIT || loglevel == LOG_ERR || 225204076Spjd loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 226204076Spjd loglevel == LOG_INFO || loglevel == LOG_DEBUG); 227204076Spjd assert(loglevel != LOG_DEBUG || debuglevel > 0); 228204076Spjd assert(error >= -1); 229204076Spjd 230204076Spjd /* Ignore debug above configured level. */ 231204076Spjd if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 232204076Spjd return; 233204076Spjd 234204076Spjd switch (pjdlog_mode) { 235204076Spjd case PJDLOG_MODE_STD: 236204076Spjd { 237204076Spjd FILE *out; 238204076Spjd 239204076Spjd /* 240204076Spjd * We send errors and warning to stderr and the rest to stdout. 241204076Spjd */ 242204076Spjd switch (loglevel) { 243204076Spjd case LOG_EMERG: 244204076Spjd case LOG_ALERT: 245204076Spjd case LOG_CRIT: 246204076Spjd case LOG_ERR: 247204076Spjd case LOG_WARNING: 248204076Spjd out = stderr; 249204076Spjd break; 250204076Spjd case LOG_NOTICE: 251204076Spjd case LOG_INFO: 252204076Spjd case LOG_DEBUG: 253204076Spjd out = stdout; 254204076Spjd break; 255204076Spjd default: 256204076Spjd assert(!"Invalid loglevel."); 257204076Spjd abort(); /* XXX: gcc */ 258204076Spjd } 259204076Spjd 260204076Spjd fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 261204076Spjd /* Attach debuglevel if this is debug log. */ 262204076Spjd if (loglevel == LOG_DEBUG) 263204076Spjd fprintf(out, "[%d]", debuglevel); 264213939Spjd fprintf(out, " %s", pjdlog_prefix); 265204076Spjd vfprintf(out, fmt, ap); 266204076Spjd if (error != -1) 267204076Spjd fprintf(out, ": %s.", strerror(error)); 268204076Spjd fprintf(out, "\n"); 269211898Spjd fflush(out); 270204076Spjd break; 271204076Spjd } 272204076Spjd case PJDLOG_MODE_SYSLOG: 273204076Spjd { 274204076Spjd char log[1024]; 275204076Spjd int len; 276204076Spjd 277204076Spjd len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 278204076Spjd if ((size_t)len < sizeof(log)) 279206697Spjd len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 280204076Spjd if (error != -1 && (size_t)len < sizeof(log)) { 281204076Spjd (void)snprintf(log + len, sizeof(log) - len, ": %s.", 282204076Spjd strerror(error)); 283204076Spjd } 284204076Spjd syslog(loglevel, "%s", log); 285204076Spjd break; 286204076Spjd } 287204076Spjd default: 288204076Spjd assert(!"Invalid mode."); 289204076Spjd } 290204076Spjd} 291204076Spjd 292204076Spjd/* 293204076Spjd * Regular logs. 294204076Spjd */ 295204076Spjdvoid 296204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap) 297204076Spjd{ 298204076Spjd 299217965Spjd assert(pjdlog_initialized); 300217965Spjd 301204076Spjd /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 302204076Spjd assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 303204076Spjd loglevel == LOG_CRIT || loglevel == LOG_ERR || 304204076Spjd loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 305204076Spjd loglevel == LOG_INFO); 306204076Spjd 307204076Spjd pjdlogv_common(loglevel, 0, -1, fmt, ap); 308204076Spjd} 309204076Spjd 310204076Spjd/* 311204076Spjd * Regular logs. 312204076Spjd */ 313204076Spjdvoid 314204076Spjdpjdlog(int loglevel, const char *fmt, ...) 315204076Spjd{ 316204076Spjd va_list ap; 317204076Spjd 318217965Spjd assert(pjdlog_initialized); 319217965Spjd 320204076Spjd va_start(ap, fmt); 321204076Spjd pjdlogv(loglevel, fmt, ap); 322204076Spjd va_end(ap); 323204076Spjd} 324204076Spjd 325204076Spjd/* 326204076Spjd * Debug logs. 327204076Spjd */ 328204076Spjdvoid 329204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 330204076Spjd{ 331204076Spjd 332217965Spjd assert(pjdlog_initialized); 333217965Spjd 334204076Spjd pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 335204076Spjd} 336204076Spjd 337204076Spjd/* 338204076Spjd * Debug logs. 339204076Spjd */ 340204076Spjdvoid 341204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...) 342204076Spjd{ 343204076Spjd va_list ap; 344204076Spjd 345217965Spjd assert(pjdlog_initialized); 346217965Spjd 347204076Spjd va_start(ap, fmt); 348204076Spjd pjdlogv_debug(debuglevel, fmt, ap); 349204076Spjd va_end(ap); 350204076Spjd} 351204076Spjd 352204076Spjd/* 353204076Spjd * Error logs with errno logging. 354204076Spjd */ 355204076Spjdvoid 356204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap) 357204076Spjd{ 358204076Spjd 359217965Spjd assert(pjdlog_initialized); 360217965Spjd 361204076Spjd pjdlogv_common(loglevel, 0, errno, fmt, ap); 362204076Spjd} 363204076Spjd 364204076Spjd/* 365204076Spjd * Error logs with errno logging. 366204076Spjd */ 367204076Spjdvoid 368204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...) 369204076Spjd{ 370204076Spjd va_list ap; 371204076Spjd 372217965Spjd assert(pjdlog_initialized); 373217965Spjd 374204076Spjd va_start(ap, fmt); 375204076Spjd pjdlogv_errno(loglevel, fmt, ap); 376204076Spjd va_end(ap); 377204076Spjd} 378204076Spjd 379204076Spjd/* 380204076Spjd * Log error, errno and exit. 381204076Spjd */ 382204076Spjdvoid 383204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap) 384204076Spjd{ 385204076Spjd 386217965Spjd assert(pjdlog_initialized); 387217965Spjd 388204076Spjd pjdlogv_errno(LOG_ERR, fmt, ap); 389204076Spjd exit(exitcode); 390210872Spjd /* NOTREACHED */ 391204076Spjd} 392204076Spjd 393204076Spjd/* 394204076Spjd * Log error, errno and exit. 395204076Spjd */ 396204076Spjdvoid 397204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...) 398204076Spjd{ 399204076Spjd va_list ap; 400204076Spjd 401217965Spjd assert(pjdlog_initialized); 402217965Spjd 403204076Spjd va_start(ap, fmt); 404204076Spjd pjdlogv_exit(exitcode, fmt, ap); 405204076Spjd /* NOTREACHED */ 406204076Spjd va_end(ap); 407204076Spjd} 408204076Spjd 409204076Spjd/* 410204076Spjd * Log error and exit. 411204076Spjd */ 412204076Spjdvoid 413204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 414204076Spjd{ 415204076Spjd 416217965Spjd assert(pjdlog_initialized); 417217965Spjd 418204076Spjd pjdlogv(LOG_ERR, fmt, ap); 419204076Spjd exit(exitcode); 420210872Spjd /* NOTREACHED */ 421204076Spjd} 422204076Spjd 423204076Spjd/* 424204076Spjd * Log error and exit. 425204076Spjd */ 426204076Spjdvoid 427204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...) 428204076Spjd{ 429204076Spjd va_list ap; 430204076Spjd 431217965Spjd assert(pjdlog_initialized); 432217965Spjd 433204076Spjd va_start(ap, fmt); 434204076Spjd pjdlogv_exitx(exitcode, fmt, ap); 435204076Spjd /* NOTREACHED */ 436204076Spjd va_end(ap); 437204076Spjd} 438210875Spjd 439210875Spjd/* 440218132Spjd * Log failure message and exit. 441210875Spjd */ 442210875Spjdvoid 443218132Spjdpjdlog_abort(const char *func, const char *file, int line, 444217966Spjd const char *failedexpr, const char *fmt, ...) 445210875Spjd{ 446217966Spjd va_list ap; 447210875Spjd 448217966Spjd assert(pjdlog_initialized); 449217966Spjd 450217966Spjd /* 451217966Spjd * When there is no message we pass __func__ as 'fmt'. 452217966Spjd * It would be cleaner to pass NULL or "", but gcc generates a warning 453217966Spjd * for both of those. 454217966Spjd */ 455217966Spjd if (fmt != func) { 456217966Spjd va_start(ap, fmt); 457217966Spjd pjdlogv_critical(fmt, ap); 458217966Spjd va_end(ap); 459217966Spjd } 460217966Spjd if (failedexpr == NULL) { 461217966Spjd if (func == NULL) { 462217966Spjd pjdlog_critical("Aborted at file %s, line %d.", file, 463217966Spjd line); 464217966Spjd } else { 465217966Spjd pjdlog_critical("Aborted at function %s, file %s, line %d.", 466217966Spjd func, file, line); 467217966Spjd } 468210875Spjd } else { 469217966Spjd if (func == NULL) { 470217966Spjd pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 471217966Spjd failedexpr, file, line); 472217966Spjd } else { 473217966Spjd pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 474217966Spjd failedexpr, func, file, line); 475217966Spjd } 476210875Spjd } 477210875Spjd abort(); 478210875Spjd} 479