pjdlog.c revision 217962
1219820Sjeff/*- 2219820Sjeff * Copyright (c) 2009-2011 The FreeBSD Foundation 3219820Sjeff * All rights reserved. 4219820Sjeff * 5328653Shselasky * This software was developed by Pawel Jakub Dawidek under sponsorship from 6219820Sjeff * the FreeBSD Foundation. 7219820Sjeff * 8219820Sjeff * Redistribution and use in source and binary forms, with or without 9219820Sjeff * modification, are permitted provided that the following conditions 10219820Sjeff * are met: 11219820Sjeff * 1. Redistributions of source code must retain the above copyright 12219820Sjeff * notice, this list of conditions and the following disclaimer. 13219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 14219820Sjeff * notice, this list of conditions and the following disclaimer in the 15219820Sjeff * documentation and/or other materials provided with the distribution. 16219820Sjeff * 17219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219820Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21219820Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219820Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219820Sjeff * SUCH DAMAGE. 28289644Shselasky */ 29289644Shselasky 30219820Sjeff#include <sys/cdefs.h> 31219820Sjeff__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 217962 2011-01-27 19:15:25Z pjd $"); 32219820Sjeff 33219820Sjeff#include <assert.h> 34280764Shselasky#include <errno.h> 35280764Shselasky#include <stdarg.h> 36219820Sjeff#include <stdio.h> 37219820Sjeff#include <stdlib.h> 38219820Sjeff#include <string.h> 39219820Sjeff#include <syslog.h> 40219820Sjeff 41219820Sjeff#include "pjdlog.h" 42219820Sjeff 43219820Sjeffstatic int pjdlog_mode = PJDLOG_MODE_STD; 44328653Shselaskystatic int pjdlog_debug_level = 0; 45329966Shselaskystatic char pjdlog_prefix[128]; 46219820Sjeff 47219820Sjeff/* 48219820Sjeff * Configure where the logs should go. 49219820Sjeff * By default they are send to stdout/stderr, but after going into background 50219820Sjeff * (eg. by calling daemon(3)) application is responsible for changing mode to 51219820Sjeff * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 52219820Sjeff */ 53219820Sjeffvoid 54219820Sjeffpjdlog_mode_set(int mode) 55219820Sjeff{ 56219820Sjeff 57328653Shselasky assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 58219820Sjeff 59219820Sjeff pjdlog_mode = mode; 60219820Sjeff 61328653Shselasky if (mode == PJDLOG_MODE_SYSLOG) 62219820Sjeff openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 63219820Sjeff} 64219820Sjeff 65219820Sjeff/* 66219820Sjeff * Return current mode. 67219820Sjeff */ 68219820Sjeffint 69219820Sjeffpjdlog_mode_get(void) 70219820Sjeff{ 71328653Shselasky 72328653Shselasky return (pjdlog_mode); 73328653Shselasky} 74328653Shselasky 75328653Shselasky/* 76328653Shselasky * Set debug level. All the logs above the level specified here will be 77328653Shselasky * ignored. 78328653Shselasky */ 79328653Shselaskyvoid 80328653Shselaskypjdlog_debug_set(int level) 81328653Shselasky{ 82219820Sjeff 83219820Sjeff assert(level >= 0); 84219820Sjeff 85331756Semaste pjdlog_debug_level = level; 86219820Sjeff} 87219820Sjeff 88219820Sjeff/* 89219820Sjeff * Return current debug level. 90219820Sjeff */ 91219820Sjeffint 92251617Sjhbpjdlog_debug_get(void) 93328653Shselasky{ 94328653Shselasky 95328653Shselasky return (pjdlog_debug_level); 96328653Shselasky} 97328653Shselasky 98328653Shselasky/* 99328653Shselasky * Set prefix that will be used before each log. 100328653Shselasky * Setting prefix to NULL will remove it. 101328653Shselasky */ 102328653Shselaskyvoid 103328653Shselaskypjdlog_prefix_set(const char *fmt, ...) 104328653Shselasky{ 105328653Shselasky va_list ap; 106328653Shselasky 107328653Shselasky va_start(ap, fmt); 108219820Sjeff pjdlogv_prefix_set(fmt, ap); 109219820Sjeff va_end(ap); 110219820Sjeff} 111219820Sjeff 112219820Sjeff/* 113219820Sjeff * Set prefix that will be used before each log. 114219820Sjeff * Setting prefix to NULL will remove it. 115219820Sjeff */ 116219820Sjeffvoid 117219820Sjeffpjdlogv_prefix_set(const char *fmt, va_list ap) 118219820Sjeff{ 119219820Sjeff 120219820Sjeff assert(fmt != NULL); 121219820Sjeff 122219820Sjeff vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 123219820Sjeff} 124219820Sjeff 125219820Sjeff/* 126219820Sjeff * Convert log level into string. 127219820Sjeff */ 128219820Sjeffstatic const char * 129219820Sjeffpjdlog_level_string(int loglevel) 130219820Sjeff{ 131219820Sjeff 132219820Sjeff switch (loglevel) { 133219820Sjeff case LOG_EMERG: 134219820Sjeff return ("EMERG"); 135219820Sjeff case LOG_ALERT: 136328653Shselasky return ("ALERT"); 137219820Sjeff case LOG_CRIT: 138219820Sjeff return ("CRIT"); 139219820Sjeff case LOG_ERR: 140219820Sjeff return ("ERROR"); 141270710Shselasky case LOG_WARNING: 142270710Shselasky return ("WARNING"); 143331756Semaste case LOG_NOTICE: 144270710Shselasky return ("NOTICE"); 145270710Shselasky case LOG_INFO: 146270710Shselasky return ("INFO"); 147219820Sjeff case LOG_DEBUG: 148219820Sjeff return ("DEBUG"); 149219820Sjeff } 150219820Sjeff assert(!"Invalid log level."); 151219820Sjeff abort(); /* XXX: gcc */ 152219820Sjeff} 153219820Sjeff 154219820Sjeff/* 155219820Sjeff * Common log routine. 156219820Sjeff */ 157219820Sjeffvoid 158219820Sjeffpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 159219820Sjeff{ 160219820Sjeff va_list ap; 161219820Sjeff 162219820Sjeff va_start(ap, fmt); 163219820Sjeff pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 164219820Sjeff va_end(ap); 165219820Sjeff} 166219820Sjeff 167219820Sjeff/* 168219820Sjeff * Common log routine, which can handle regular log level as well as debug 169219820Sjeff * level. We decide here where to send the logs (stdout/stderr or syslog). 170219820Sjeff */ 171219820Sjeffvoid 172219820Sjeffpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 173219820Sjeff va_list ap) 174328653Shselasky{ 175328653Shselasky 176219820Sjeff assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 177219820Sjeff loglevel == LOG_CRIT || loglevel == LOG_ERR || 178219820Sjeff loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 179219820Sjeff loglevel == LOG_INFO || loglevel == LOG_DEBUG); 180219820Sjeff assert(loglevel != LOG_DEBUG || debuglevel > 0); 181311803Shselasky assert(error >= -1); 182311803Shselasky 183311803Shselasky /* Ignore debug above configured level. */ 184311803Shselasky if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 185311803Shselasky return; 186311803Shselasky 187311803Shselasky switch (pjdlog_mode) { 188311803Shselasky case PJDLOG_MODE_STD: 189311803Shselasky { 190311803Shselasky FILE *out; 191311803Shselasky 192311803Shselasky /* 193311803Shselasky * We send errors and warning to stderr and the rest to stdout. 194311803Shselasky */ 195311803Shselasky switch (loglevel) { 196311803Shselasky case LOG_EMERG: 197311803Shselasky case LOG_ALERT: 198219820Sjeff case LOG_CRIT: 199311803Shselasky case LOG_ERR: 200311803Shselasky case LOG_WARNING: 201311803Shselasky out = stderr; 202311803Shselasky break; 203311803Shselasky case LOG_NOTICE: 204311803Shselasky case LOG_INFO: 205311803Shselasky case LOG_DEBUG: 206311803Shselasky out = stdout; 207311803Shselasky break; 208311803Shselasky default: 209311803Shselasky assert(!"Invalid loglevel."); 210311803Shselasky abort(); /* XXX: gcc */ 211311803Shselasky } 212311803Shselasky 213311803Shselasky fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 214311803Shselasky /* Attach debuglevel if this is debug log. */ 215219820Sjeff if (loglevel == LOG_DEBUG) 216219820Sjeff fprintf(out, "[%d]", debuglevel); 217219820Sjeff fprintf(out, " %s", pjdlog_prefix); 218219820Sjeff vfprintf(out, fmt, ap); 219219820Sjeff if (error != -1) 220219820Sjeff fprintf(out, ": %s.", strerror(error)); 221219820Sjeff fprintf(out, "\n"); 222219820Sjeff fflush(out); 223219820Sjeff break; 224219820Sjeff } 225219820Sjeff case PJDLOG_MODE_SYSLOG: 226219820Sjeff { 227219820Sjeff char log[1024]; 228270710Shselasky int len; 229270710Shselasky 230270710Shselasky len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 231270710Shselasky if ((size_t)len < sizeof(log)) 232270710Shselasky len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 233270710Shselasky if (error != -1 && (size_t)len < sizeof(log)) { 234270710Shselasky (void)snprintf(log + len, sizeof(log) - len, ": %s.", 235270710Shselasky strerror(error)); 236270710Shselasky } 237270710Shselasky syslog(loglevel, "%s", log); 238270710Shselasky break; 239270710Shselasky } 240270710Shselasky default: 241270710Shselasky assert(!"Invalid mode."); 242270710Shselasky } 243328653Shselasky} 244328653Shselasky 245328653Shselasky/* 246328653Shselasky * Regular logs. 247328653Shselasky */ 248219820Sjeffvoid 249219820Sjeffpjdlogv(int loglevel, const char *fmt, va_list ap) 250328653Shselasky{ 251328653Shselasky 252219820Sjeff /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 253219820Sjeff assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 254219820Sjeff loglevel == LOG_CRIT || loglevel == LOG_ERR || 255219820Sjeff loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 256219820Sjeff loglevel == LOG_INFO); 257219820Sjeff 258219820Sjeff pjdlogv_common(loglevel, 0, -1, fmt, ap); 259219820Sjeff} 260219820Sjeff 261219820Sjeff/* 262219820Sjeff * Regular logs. 263219820Sjeff */ 264219820Sjeffvoid 265219820Sjeffpjdlog(int loglevel, const char *fmt, ...) 266219820Sjeff{ 267219820Sjeff va_list ap; 268219820Sjeff 269219820Sjeff va_start(ap, fmt); 270219820Sjeff pjdlogv(loglevel, fmt, ap); 271219820Sjeff va_end(ap); 272219820Sjeff} 273331756Semaste 274270710Shselasky/* 275270710Shselasky * Debug logs. 276328653Shselasky */ 277328653Shselaskyvoid 278270710Shselaskypjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 279270710Shselasky{ 280328653Shselasky 281328653Shselasky pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 282328653Shselasky} 283328653Shselasky 284328653Shselasky/* 285328653Shselasky * Debug logs. 286328653Shselasky */ 287329967Shselaskyvoid 288329967Shselaskypjdlog_debug(int debuglevel, const char *fmt, ...) 289329967Shselasky{ 290329967Shselasky va_list ap; 291329967Shselasky 292329967Shselasky va_start(ap, fmt); 293329967Shselasky pjdlogv_debug(debuglevel, fmt, ap); 294329967Shselasky va_end(ap); 295329967Shselasky} 296329967Shselasky 297329967Shselasky/* 298329967Shselasky * Error logs with errno logging. 299329967Shselasky */ 300329967Shselaskyvoid 301328653Shselaskypjdlogv_errno(int loglevel, const char *fmt, va_list ap) 302328653Shselasky{ 303328653Shselasky 304328653Shselasky pjdlogv_common(loglevel, 0, errno, fmt, ap); 305328653Shselasky} 306328653Shselasky 307328653Shselasky/* 308328653Shselasky * Error logs with errno logging. 309328653Shselasky */ 310328653Shselaskyvoid 311328653Shselaskypjdlog_errno(int loglevel, const char *fmt, ...) 312328653Shselasky{ 313328653Shselasky va_list ap; 314328653Shselasky 315328653Shselasky va_start(ap, fmt); 316328653Shselasky pjdlogv_errno(loglevel, fmt, ap); 317328653Shselasky va_end(ap); 318328653Shselasky} 319328653Shselasky 320328653Shselasky/* 321328653Shselasky * Log error, errno and exit. 322270710Shselasky */ 323void 324pjdlogv_exit(int exitcode, const char *fmt, va_list ap) 325{ 326 327 pjdlogv_errno(LOG_ERR, fmt, ap); 328 exit(exitcode); 329 /* NOTREACHED */ 330} 331 332/* 333 * Log error, errno and exit. 334 */ 335void 336pjdlog_exit(int exitcode, const char *fmt, ...) 337{ 338 va_list ap; 339 340 va_start(ap, fmt); 341 pjdlogv_exit(exitcode, fmt, ap); 342 /* NOTREACHED */ 343 va_end(ap); 344} 345 346/* 347 * Log error and exit. 348 */ 349void 350pjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 351{ 352 353 pjdlogv(LOG_ERR, fmt, ap); 354 exit(exitcode); 355 /* NOTREACHED */ 356} 357 358/* 359 * Log error and exit. 360 */ 361void 362pjdlog_exitx(int exitcode, const char *fmt, ...) 363{ 364 va_list ap; 365 366 va_start(ap, fmt); 367 pjdlogv_exitx(exitcode, fmt, ap); 368 /* NOTREACHED */ 369 va_end(ap); 370} 371 372/* 373 * Log assertion and exit. 374 */ 375void 376pjdlog_verify(const char *func, const char *file, int line, 377 const char *failedexpr) 378{ 379 380 if (func == NULL) { 381 pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 382 failedexpr, file, line); 383 } else { 384 pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 385 failedexpr, func, file, line); 386 } 387 abort(); 388} 389