pjdlog.c revision 218040
1237263Snp/*- 2237263Snp * Copyright (c) 2009-2010 The FreeBSD Foundation 3237263Snp * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org> 4237263Snp * All rights reserved. 5237263Snp * 6237263Snp * This software was developed by Pawel Jakub Dawidek under sponsorship from 7237263Snp * the FreeBSD Foundation. 8237263Snp * 9237263Snp * Redistribution and use in source and binary forms, with or without 10237263Snp * modification, are permitted provided that the following conditions 11237263Snp * are met: 12237263Snp * 1. Redistributions of source code must retain the above copyright 13237263Snp * notice, this list of conditions and the following disclaimer. 14237263Snp * 2. Redistributions in binary form must reproduce the above copyright 15237263Snp * notice, this list of conditions and the following disclaimer in the 16237263Snp * documentation and/or other materials provided with the distribution. 17237263Snp * 18237263Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19237263Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20237263Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21237263Snp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22237263Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23237263Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24237263Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25237263Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26237263Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27237263Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28237263Snp * SUCH DAMAGE. 29237263Snp */ 30237263Snp 31237263Snp#include <sys/cdefs.h> 32237263Snp__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 218040 2011-01-28 21:36:01Z pjd $"); 33237263Snp 34237263Snp#include <assert.h> 35237263Snp#include <errno.h> 36237263Snp#include <stdarg.h> 37237263Snp#include <stdbool.h> 38237263Snp#include <stdio.h> 39237263Snp#include <stdlib.h> 40237263Snp#include <string.h> 41237263Snp#include <syslog.h> 42237263Snp 43237263Snp#include "pjdlog.h" 44237263Snp 45237263Snpstatic bool pjdlog_initialized = false; 46237263Snpstatic int pjdlog_mode, pjdlog_debug_level; 47237263Snpstatic char pjdlog_prefix[128]; 48237263Snp 49237263Snpvoid 50237263Snppjdlog_init(int mode) 51237263Snp{ 52237263Snp 53237263Snp assert(!pjdlog_initialized); 54237263Snp assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 55237263Snp 56240169Snp if (mode == PJDLOG_MODE_SYSLOG) 57237263Snp openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 58237263Snp pjdlog_mode = mode; 59237263Snp pjdlog_debug_level = 0; 60237263Snp bzero(pjdlog_prefix, sizeof(pjdlog_prefix)); 61237263Snp 62237263Snp pjdlog_initialized = true; 63237263Snp} 64237263Snp 65237263Snpvoid 66237263Snppjdlog_fini(void) 67237263Snp{ 68237263Snp 69237263Snp assert(pjdlog_initialized); 70237263Snp 71237263Snp if (pjdlog_mode == PJDLOG_MODE_SYSLOG) 72237263Snp closelog(); 73237263Snp 74237263Snp pjdlog_initialized = false; 75237263Snp} 76241898Snp 77241898Snp/* 78241898Snp * Configure where the logs should go. 79237263Snp * By default they are send to stdout/stderr, but after going into background 80237263Snp * (eg. by calling daemon(3)) application is responsible for changing mode to 81237263Snp * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 82237263Snp */ 83237263Snpvoid 84240169Snppjdlog_mode_set(int mode) 85237263Snp{ 86237263Snp 87237263Snp assert(pjdlog_initialized); 88237263Snp assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 89237263Snp 90237263Snp if (pjdlog_mode == mode) 91252495Snp return; 92237263Snp 93237263Snp if (mode == PJDLOG_MODE_SYSLOG) 94237263Snp openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 95237263Snp else /* if (mode == PJDLOG_MODE_STD) */ 96237263Snp closelog(); 97237263Snp 98237263Snp pjdlog_mode = mode; 99237263Snp} 100237263Snp 101237263Snp/* 102237263Snp * Return current mode. 103237263Snp */ 104237263Snpint 105241898Snppjdlog_mode_get(void) 106241898Snp{ 107241898Snp 108241898Snp assert(pjdlog_initialized); 109241898Snp 110241898Snp return (pjdlog_mode); 111241898Snp} 112237263Snp 113237263Snp/* 114237263Snp * Set debug level. All the logs above the level specified here will be 115237263Snp * ignored. 116237263Snp */ 117237263Snpvoid 118237263Snppjdlog_debug_set(int level) 119237263Snp{ 120237263Snp 121237263Snp assert(pjdlog_initialized); 122237263Snp assert(level >= 0); 123241898Snp 124241898Snp pjdlog_debug_level = level; 125241898Snp} 126241898Snp 127241898Snp/* 128237263Snp * Return current debug level. 129237263Snp */ 130237263Snpint 131237263Snppjdlog_debug_get(void) 132237263Snp{ 133237263Snp 134237263Snp assert(pjdlog_initialized); 135237263Snp 136237263Snp return (pjdlog_debug_level); 137237263Snp} 138237263Snp 139240169Snp/* 140237263Snp * Set prefix that will be used before each log. 141237263Snp * Setting prefix to NULL will remove it. 142237263Snp */ 143237263Snpvoid 144237263Snppjdlog_prefix_set(const char *fmt, ...) 145237263Snp{ 146237263Snp va_list ap; 147237263Snp 148237263Snp assert(pjdlog_initialized); 149237263Snp 150237263Snp va_start(ap, fmt); 151237263Snp pjdlogv_prefix_set(fmt, ap); 152237263Snp va_end(ap); 153237263Snp} 154237263Snp 155237263Snp/* 156237263Snp * Set prefix that will be used before each log. 157237263Snp * Setting prefix to NULL will remove it. 158237263Snp */ 159240169Snpvoid 160237263Snppjdlogv_prefix_set(const char *fmt, va_list ap) 161237263Snp{ 162240169Snp 163237263Snp assert(pjdlog_initialized); 164237263Snp assert(fmt != NULL); 165240169Snp 166237263Snp vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 167240169Snp} 168237263Snp 169237263Snp/* 170237263Snp * Convert log level into string. 171237263Snp */ 172237263Snpstatic const char * 173237263Snppjdlog_level_string(int loglevel) 174237263Snp{ 175237263Snp 176237263Snp switch (loglevel) { 177237263Snp case LOG_EMERG: 178237263Snp return ("EMERG"); 179237263Snp case LOG_ALERT: 180237263Snp return ("ALERT"); 181237263Snp case LOG_CRIT: 182240169Snp return ("CRIT"); 183237263Snp case LOG_ERR: 184237263Snp return ("ERROR"); 185237263Snp case LOG_WARNING: 186237263Snp return ("WARNING"); 187237263Snp case LOG_NOTICE: 188237263Snp return ("NOTICE"); 189237263Snp case LOG_INFO: 190237263Snp return ("INFO"); 191237263Snp case LOG_DEBUG: 192237263Snp return ("DEBUG"); 193237263Snp } 194237263Snp assert(!"Invalid log level."); 195237263Snp abort(); /* XXX: gcc */ 196237263Snp} 197237263Snp 198237263Snp/* 199237263Snp * Common log routine. 200237263Snp */ 201237263Snpvoid 202237263Snppjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 203237263Snp{ 204237263Snp va_list ap; 205237263Snp 206237263Snp assert(pjdlog_initialized); 207237263Snp 208237263Snp va_start(ap, fmt); 209237263Snp pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 210237263Snp va_end(ap); 211237263Snp} 212237263Snp 213237263Snp/* 214237263Snp * Common log routine, which can handle regular log level as well as debug 215237263Snp * level. We decide here where to send the logs (stdout/stderr or syslog). 216237263Snp */ 217237263Snpvoid 218237263Snppjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 219237263Snp va_list ap) 220237263Snp{ 221237263Snp 222237263Snp assert(pjdlog_initialized); 223237263Snp assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 224237263Snp loglevel == LOG_CRIT || loglevel == LOG_ERR || 225237263Snp loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 226237263Snp loglevel == LOG_INFO || loglevel == LOG_DEBUG); 227237263Snp assert(loglevel != LOG_DEBUG || debuglevel > 0); 228237263Snp assert(error >= -1); 229237263Snp 230237263Snp /* Ignore debug above configured level. */ 231237263Snp if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 232237263Snp return; 233237263Snp 234237263Snp switch (pjdlog_mode) { 235237263Snp case PJDLOG_MODE_STD: 236237263Snp { 237237263Snp FILE *out; 238237263Snp 239237263Snp /* 240237263Snp * We send errors and warning to stderr and the rest to stdout. 241237263Snp */ 242237263Snp switch (loglevel) { 243237263Snp case LOG_EMERG: 244237263Snp case LOG_ALERT: 245237263Snp case LOG_CRIT: 246237263Snp case LOG_ERR: 247237263Snp case LOG_WARNING: 248237263Snp out = stderr; 249237263Snp break; 250237263Snp case LOG_NOTICE: 251237263Snp case LOG_INFO: 252237263Snp case LOG_DEBUG: 253237263Snp out = stdout; 254237263Snp break; 255237263Snp default: 256237263Snp assert(!"Invalid loglevel."); 257237263Snp abort(); /* XXX: gcc */ 258237263Snp } 259237263Snp 260237263Snp fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 261237263Snp /* Attach debuglevel if this is debug log. */ 262237263Snp if (loglevel == LOG_DEBUG) 263237263Snp fprintf(out, "[%d]", debuglevel); 264237263Snp fprintf(out, " %s", pjdlog_prefix); 265237263Snp vfprintf(out, fmt, ap); 266237263Snp if (error != -1) 267237263Snp fprintf(out, ": %s.", strerror(error)); 268237263Snp fprintf(out, "\n"); 269237263Snp fflush(out); 270237263Snp break; 271237263Snp } 272237263Snp case PJDLOG_MODE_SYSLOG: 273237263Snp { 274237263Snp char log[1024]; 275237263Snp int len; 276237263Snp 277237263Snp len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 278237263Snp if ((size_t)len < sizeof(log)) 279237263Snp len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 280237263Snp if (error != -1 && (size_t)len < sizeof(log)) { 281237263Snp (void)snprintf(log + len, sizeof(log) - len, ": %s.", 282237263Snp strerror(error)); 283237263Snp } 284237263Snp syslog(loglevel, "%s", log); 285237263Snp break; 286237263Snp } 287237263Snp default: 288237263Snp assert(!"Invalid mode."); 289237263Snp } 290237263Snp} 291237263Snp 292237263Snp/* 293237263Snp * Regular logs. 294237263Snp */ 295237263Snpvoid 296237263Snppjdlogv(int loglevel, const char *fmt, va_list ap) 297237263Snp{ 298237263Snp 299237263Snp assert(pjdlog_initialized); 300237263Snp 301237263Snp /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 302237263Snp assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 303237263Snp loglevel == LOG_CRIT || loglevel == LOG_ERR || 304237263Snp loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 305237263Snp loglevel == LOG_INFO); 306237263Snp 307237263Snp pjdlogv_common(loglevel, 0, -1, fmt, ap); 308240169Snp} 309237263Snp 310237263Snp/* 311237263Snp * Regular logs. 312237263Snp */ 313237263Snpvoid 314240169Snppjdlog(int loglevel, const char *fmt, ...) 315240169Snp{ 316237263Snp va_list ap; 317237263Snp 318237263Snp assert(pjdlog_initialized); 319237263Snp 320237263Snp va_start(ap, fmt); 321237263Snp pjdlogv(loglevel, fmt, ap); 322237263Snp va_end(ap); 323237263Snp} 324237263Snp 325237263Snp/* 326237263Snp * Debug logs. 327237263Snp */ 328237263Snpvoid 329237263Snppjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 330237263Snp{ 331237263Snp 332237263Snp assert(pjdlog_initialized); 333237263Snp 334240169Snp pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 335237263Snp} 336240169Snp 337237263Snp/* 338237263Snp * Debug logs. 339237263Snp */ 340240169Snpvoid 341240169Snppjdlog_debug(int debuglevel, const char *fmt, ...) 342240169Snp{ 343240169Snp va_list ap; 344240169Snp 345240169Snp assert(pjdlog_initialized); 346240169Snp 347240169Snp va_start(ap, fmt); 348237263Snp pjdlogv_debug(debuglevel, fmt, ap); 349240169Snp va_end(ap); 350240169Snp} 351237263Snp 352240169Snp/* 353240169Snp * Error logs with errno logging. 354237263Snp */ 355240169Snpvoid 356237263Snppjdlogv_errno(int loglevel, const char *fmt, va_list ap) 357237263Snp{ 358237263Snp 359237263Snp assert(pjdlog_initialized); 360237263Snp 361237263Snp pjdlogv_common(loglevel, 0, errno, fmt, ap); 362237263Snp} 363237263Snp 364237263Snp/* 365237263Snp * Error logs with errno logging. 366237263Snp */ 367237263Snpvoid 368237263Snppjdlog_errno(int loglevel, const char *fmt, ...) 369237263Snp{ 370237263Snp va_list ap; 371237263Snp 372240169Snp assert(pjdlog_initialized); 373237263Snp 374240169Snp va_start(ap, fmt); 375237263Snp pjdlogv_errno(loglevel, fmt, ap); 376237263Snp va_end(ap); 377240169Snp} 378237263Snp 379237263Snp/* 380237263Snp * Log error, errno and exit. 381237263Snp */ 382237263Snpvoid 383237263Snppjdlogv_exit(int exitcode, const char *fmt, va_list ap) 384237263Snp{ 385237263Snp 386237263Snp assert(pjdlog_initialized); 387237263Snp 388237263Snp pjdlogv_errno(LOG_ERR, fmt, ap); 389237263Snp exit(exitcode); 390237263Snp /* NOTREACHED */ 391237263Snp} 392237263Snp 393237263Snp/* 394237263Snp * Log error, errno and exit. 395240169Snp */ 396240169Snpvoid 397237263Snppjdlog_exit(int exitcode, const char *fmt, ...) 398237263Snp{ 399237263Snp va_list ap; 400237263Snp 401237263Snp assert(pjdlog_initialized); 402237263Snp 403237263Snp va_start(ap, fmt); 404237263Snp pjdlogv_exit(exitcode, fmt, ap); 405237263Snp /* NOTREACHED */ 406237263Snp va_end(ap); 407237263Snp} 408237263Snp 409237263Snp/* 410237263Snp * Log error and exit. 411237263Snp */ 412237263Snpvoid 413237263Snppjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 414237263Snp{ 415237263Snp 416237263Snp assert(pjdlog_initialized); 417237263Snp 418237263Snp pjdlogv(LOG_ERR, fmt, ap); 419237263Snp exit(exitcode); 420237263Snp /* NOTREACHED */ 421237263Snp} 422237263Snp 423237263Snp/* 424237263Snp * Log error and exit. 425237263Snp */ 426237263Snpvoid 427237263Snppjdlog_exitx(int exitcode, const char *fmt, ...) 428237263Snp{ 429237263Snp va_list ap; 430237263Snp 431237263Snp assert(pjdlog_initialized); 432237263Snp 433237263Snp va_start(ap, fmt); 434237263Snp pjdlogv_exitx(exitcode, fmt, ap); 435237263Snp /* NOTREACHED */ 436237263Snp va_end(ap); 437237263Snp} 438237263Snp 439237263Snp/* 440237263Snp * Log assertion and exit. 441237263Snp */ 442237263Snpvoid 443237263Snppjdlog_verify(const char *func, const char *file, int line, 444237263Snp const char *failedexpr, const char *fmt, ...) 445237263Snp{ 446237263Snp va_list ap; 447237263Snp 448237263Snp assert(pjdlog_initialized); 449237263Snp 450237263Snp /* 451237263Snp * When there is no message we pass __func__ as 'fmt'. 452237263Snp * It would be cleaner to pass NULL or "", but gcc generates a warning 453237263Snp * for both of those. 454237263Snp */ 455237263Snp if (fmt != func) { 456237263Snp va_start(ap, fmt); 457237263Snp pjdlogv_critical(fmt, ap); 458237263Snp va_end(ap); 459237263Snp } 460237263Snp if (failedexpr == NULL) { 461237263Snp if (func == NULL) { 462237263Snp pjdlog_critical("Aborted at file %s, line %d.", file, 463237263Snp line); 464237263Snp } else { 465237263Snp pjdlog_critical("Aborted at function %s, file %s, line %d.", 466237263Snp func, file, line); 467237263Snp } 468237263Snp } else { 469237263Snp if (func == NULL) { 470237263Snp pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 471237263Snp failedexpr, file, line); 472237263Snp } else { 473237263Snp pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 474237263Snp failedexpr, func, file, line); 475237263Snp } 476237263Snp } 477237263Snp abort(); 478237263Snp} 479237263Snp