pjdlog.c revision 218040
1166124Srafan/*- 2184989Srafan * Copyright (c) 2009-2010 The FreeBSD Foundation 3166124Srafan * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org> 4166124Srafan * All rights reserved. 5166124Srafan * 6166124Srafan * This software was developed by Pawel Jakub Dawidek under sponsorship from 7166124Srafan * the FreeBSD Foundation. 8166124Srafan * 9166124Srafan * Redistribution and use in source and binary forms, with or without 10166124Srafan * modification, are permitted provided that the following conditions 11166124Srafan * are met: 12166124Srafan * 1. Redistributions of source code must retain the above copyright 13166124Srafan * notice, this list of conditions and the following disclaimer. 14166124Srafan * 2. Redistributions in binary form must reproduce the above copyright 15166124Srafan * notice, this list of conditions and the following disclaimer in the 16166124Srafan * documentation and/or other materials provided with the distribution. 17166124Srafan * 18166124Srafan * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19166124Srafan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20166124Srafan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21166124Srafan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22166124Srafan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23166124Srafan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24166124Srafan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25166124Srafan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26166124Srafan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27166124Srafan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28184989Srafan * SUCH DAMAGE. 29166124Srafan */ 3050276Speter 3150276Speter#include <sys/cdefs.h> 3250276Speter__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 218040 2011-01-28 21:36:01Z pjd $"); 3350276Speter 3450276Speter#include <assert.h> 35166124Srafan#include <errno.h> 3650276Speter#include <stdarg.h> 37166124Srafan#include <stdbool.h> 3850276Speter#include <stdio.h> 3950276Speter#include <stdlib.h> 4050276Speter#include <string.h> 41166124Srafan#include <syslog.h> 42166124Srafan 43166124Srafan#include "pjdlog.h" 4450276Speter 45166124Srafanstatic bool pjdlog_initialized = false; 4650276Speterstatic int pjdlog_mode, pjdlog_debug_level; 4750276Speterstatic char pjdlog_prefix[128]; 48166124Srafan 4950276Spetervoid 5050276Speterpjdlog_init(int mode) 5150276Speter{ 5250276Speter 5350276Speter assert(!pjdlog_initialized); 54166124Srafan assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 55166124Srafan 56166124Srafan if (mode == PJDLOG_MODE_SYSLOG) 5750276Speter openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 58166124Srafan pjdlog_mode = mode; 59166124Srafan pjdlog_debug_level = 0; 6050276Speter bzero(pjdlog_prefix, sizeof(pjdlog_prefix)); 61166124Srafan 62166124Srafan pjdlog_initialized = true; 63166124Srafan} 64184989Srafan 65184989Srafanvoid 66184989Srafanpjdlog_fini(void) 67184989Srafan{ 68184989Srafan 69184989Srafan assert(pjdlog_initialized); 70184989Srafan 71184989Srafan if (pjdlog_mode == PJDLOG_MODE_SYSLOG) 72184989Srafan closelog(); 73184989Srafan 74184989Srafan pjdlog_initialized = false; 7550276Speter} 7650276Speter 77166124Srafan/* 78166124Srafan * Configure where the logs should go. 79166124Srafan * By default they are send to stdout/stderr, but after going into background 80166124Srafan * (eg. by calling daemon(3)) application is responsible for changing mode to 81166124Srafan * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 82166124Srafan */ 83166124Srafanvoid 8450276Speterpjdlog_mode_set(int mode) 85166124Srafan{ 86174993Srafan 87174993Srafan assert(pjdlog_initialized); 88174993Srafan assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 89174993Srafan 90174993Srafan if (pjdlog_mode == mode) 91174993Srafan return; 9250276Speter 93166124Srafan if (mode == PJDLOG_MODE_SYSLOG) 94166124Srafan openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 95166124Srafan else /* if (mode == PJDLOG_MODE_STD) */ 96166124Srafan closelog(); 9750276Speter 98174993Srafan pjdlog_mode = mode; 9950276Speter} 10050276Speter 101166124Srafan/* 102166124Srafan * Return current mode. 10350276Speter */ 10450276Speterint 10550276Speterpjdlog_mode_get(void) 106166124Srafan{ 10750276Speter 108166124Srafan assert(pjdlog_initialized); 10950276Speter 11050276Speter return (pjdlog_mode); 11150276Speter} 11250276Speter 11350276Speter/* 11450276Speter * Set debug level. All the logs above the level specified here will be 11550276Speter * ignored. 11650276Speter */ 117174993Srafanvoid 11850276Speterpjdlog_debug_set(int level) 11950276Speter{ 12050276Speter 12150276Speter assert(pjdlog_initialized); 12250276Speter assert(level >= 0); 12350276Speter 124166124Srafan pjdlog_debug_level = level; 12550276Speter} 12650276Speter 12750276Speter/* 12850276Speter * Return current debug level. 12950276Speter */ 13050276Speterint 13150276Speterpjdlog_debug_get(void) 13250276Speter{ 13350276Speter 13450276Speter assert(pjdlog_initialized); 13550276Speter 13650276Speter return (pjdlog_debug_level); 13750276Speter} 13850276Speter 13950276Speter/* 14050276Speter * Set prefix that will be used before each log. 14150276Speter * Setting prefix to NULL will remove it. 14250276Speter */ 14350276Spetervoid 14450276Speterpjdlog_prefix_set(const char *fmt, ...) 14550276Speter{ 14650276Speter va_list ap; 14750276Speter 14850276Speter assert(pjdlog_initialized); 14950276Speter 15050276Speter va_start(ap, fmt); 15150276Speter pjdlogv_prefix_set(fmt, ap); 15250276Speter va_end(ap); 15350276Speter} 15450276Speter 15550276Speter/* 15650276Speter * Set prefix that will be used before each log. 15750276Speter * Setting prefix to NULL will remove it. 15850276Speter */ 15950276Spetervoid 16050276Speterpjdlogv_prefix_set(const char *fmt, va_list ap) 16150276Speter{ 16250276Speter 16350276Speter assert(pjdlog_initialized); 16450276Speter assert(fmt != NULL); 16550276Speter 16650276Speter vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 16750276Speter} 16850276Speter 16950276Speter/* 17050276Speter * Convert log level into string. 17150276Speter */ 17250276Speterstatic const char * 17350276Speterpjdlog_level_string(int loglevel) 17450276Speter{ 17550276Speter 17650276Speter switch (loglevel) { 17750276Speter case LOG_EMERG: 17850276Speter return ("EMERG"); 17950276Speter case LOG_ALERT: 18050276Speter return ("ALERT"); 18150276Speter case LOG_CRIT: 18250276Speter return ("CRIT"); 18350276Speter case LOG_ERR: 18450276Speter return ("ERROR"); 18550276Speter case LOG_WARNING: 18650276Speter return ("WARNING"); 18750276Speter case LOG_NOTICE: 18850276Speter return ("NOTICE"); 18950276Speter case LOG_INFO: 19050276Speter return ("INFO"); 19150276Speter case LOG_DEBUG: 19250276Speter return ("DEBUG"); 19350276Speter } 19450276Speter assert(!"Invalid log level."); 19550276Speter abort(); /* XXX: gcc */ 19650276Speter} 19750276Speter 19850276Speter/* 19950276Speter * Common log routine. 20050276Speter */ 20150276Spetervoid 20250276Speterpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 20350276Speter{ 20450276Speter va_list ap; 20550276Speter 20650276Speter assert(pjdlog_initialized); 20750276Speter 20850276Speter va_start(ap, fmt); 20950276Speter pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 21050276Speter va_end(ap); 21150276Speter} 212166124Srafan 213/* 214 * Common log routine, which can handle regular log level as well as debug 215 * level. We decide here where to send the logs (stdout/stderr or syslog). 216 */ 217void 218pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 219 va_list ap) 220{ 221 222 assert(pjdlog_initialized); 223 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 224 loglevel == LOG_CRIT || loglevel == LOG_ERR || 225 loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 226 loglevel == LOG_INFO || loglevel == LOG_DEBUG); 227 assert(loglevel != LOG_DEBUG || debuglevel > 0); 228 assert(error >= -1); 229 230 /* Ignore debug above configured level. */ 231 if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 232 return; 233 234 switch (pjdlog_mode) { 235 case PJDLOG_MODE_STD: 236 { 237 FILE *out; 238 239 /* 240 * We send errors and warning to stderr and the rest to stdout. 241 */ 242 switch (loglevel) { 243 case LOG_EMERG: 244 case LOG_ALERT: 245 case LOG_CRIT: 246 case LOG_ERR: 247 case LOG_WARNING: 248 out = stderr; 249 break; 250 case LOG_NOTICE: 251 case LOG_INFO: 252 case LOG_DEBUG: 253 out = stdout; 254 break; 255 default: 256 assert(!"Invalid loglevel."); 257 abort(); /* XXX: gcc */ 258 } 259 260 fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 261 /* Attach debuglevel if this is debug log. */ 262 if (loglevel == LOG_DEBUG) 263 fprintf(out, "[%d]", debuglevel); 264 fprintf(out, " %s", pjdlog_prefix); 265 vfprintf(out, fmt, ap); 266 if (error != -1) 267 fprintf(out, ": %s.", strerror(error)); 268 fprintf(out, "\n"); 269 fflush(out); 270 break; 271 } 272 case PJDLOG_MODE_SYSLOG: 273 { 274 char log[1024]; 275 int len; 276 277 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 278 if ((size_t)len < sizeof(log)) 279 len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 280 if (error != -1 && (size_t)len < sizeof(log)) { 281 (void)snprintf(log + len, sizeof(log) - len, ": %s.", 282 strerror(error)); 283 } 284 syslog(loglevel, "%s", log); 285 break; 286 } 287 default: 288 assert(!"Invalid mode."); 289 } 290} 291 292/* 293 * Regular logs. 294 */ 295void 296pjdlogv(int loglevel, const char *fmt, va_list ap) 297{ 298 299 assert(pjdlog_initialized); 300 301 /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 302 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 303 loglevel == LOG_CRIT || loglevel == LOG_ERR || 304 loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 305 loglevel == LOG_INFO); 306 307 pjdlogv_common(loglevel, 0, -1, fmt, ap); 308} 309 310/* 311 * Regular logs. 312 */ 313void 314pjdlog(int loglevel, const char *fmt, ...) 315{ 316 va_list ap; 317 318 assert(pjdlog_initialized); 319 320 va_start(ap, fmt); 321 pjdlogv(loglevel, fmt, ap); 322 va_end(ap); 323} 324 325/* 326 * Debug logs. 327 */ 328void 329pjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 330{ 331 332 assert(pjdlog_initialized); 333 334 pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 335} 336 337/* 338 * Debug logs. 339 */ 340void 341pjdlog_debug(int debuglevel, const char *fmt, ...) 342{ 343 va_list ap; 344 345 assert(pjdlog_initialized); 346 347 va_start(ap, fmt); 348 pjdlogv_debug(debuglevel, fmt, ap); 349 va_end(ap); 350} 351 352/* 353 * Error logs with errno logging. 354 */ 355void 356pjdlogv_errno(int loglevel, const char *fmt, va_list ap) 357{ 358 359 assert(pjdlog_initialized); 360 361 pjdlogv_common(loglevel, 0, errno, fmt, ap); 362} 363 364/* 365 * Error logs with errno logging. 366 */ 367void 368pjdlog_errno(int loglevel, const char *fmt, ...) 369{ 370 va_list ap; 371 372 assert(pjdlog_initialized); 373 374 va_start(ap, fmt); 375 pjdlogv_errno(loglevel, fmt, ap); 376 va_end(ap); 377} 378 379/* 380 * Log error, errno and exit. 381 */ 382void 383pjdlogv_exit(int exitcode, const char *fmt, va_list ap) 384{ 385 386 assert(pjdlog_initialized); 387 388 pjdlogv_errno(LOG_ERR, fmt, ap); 389 exit(exitcode); 390 /* NOTREACHED */ 391} 392 393/* 394 * Log error, errno and exit. 395 */ 396void 397pjdlog_exit(int exitcode, const char *fmt, ...) 398{ 399 va_list ap; 400 401 assert(pjdlog_initialized); 402 403 va_start(ap, fmt); 404 pjdlogv_exit(exitcode, fmt, ap); 405 /* NOTREACHED */ 406 va_end(ap); 407} 408 409/* 410 * Log error and exit. 411 */ 412void 413pjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 414{ 415 416 assert(pjdlog_initialized); 417 418 pjdlogv(LOG_ERR, fmt, ap); 419 exit(exitcode); 420 /* NOTREACHED */ 421} 422 423/* 424 * Log error and exit. 425 */ 426void 427pjdlog_exitx(int exitcode, const char *fmt, ...) 428{ 429 va_list ap; 430 431 assert(pjdlog_initialized); 432 433 va_start(ap, fmt); 434 pjdlogv_exitx(exitcode, fmt, ap); 435 /* NOTREACHED */ 436 va_end(ap); 437} 438 439/* 440 * Log assertion and exit. 441 */ 442void 443pjdlog_verify(const char *func, const char *file, int line, 444 const char *failedexpr, const char *fmt, ...) 445{ 446 va_list ap; 447 448 assert(pjdlog_initialized); 449 450 /* 451 * When there is no message we pass __func__ as 'fmt'. 452 * It would be cleaner to pass NULL or "", but gcc generates a warning 453 * for both of those. 454 */ 455 if (fmt != func) { 456 va_start(ap, fmt); 457 pjdlogv_critical(fmt, ap); 458 va_end(ap); 459 } 460 if (failedexpr == NULL) { 461 if (func == NULL) { 462 pjdlog_critical("Aborted at file %s, line %d.", file, 463 line); 464 } else { 465 pjdlog_critical("Aborted at function %s, file %s, line %d.", 466 func, file, line); 467 } 468 } else { 469 if (func == NULL) { 470 pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 471 failedexpr, file, line); 472 } else { 473 pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 474 failedexpr, func, file, line); 475 } 476 } 477 abort(); 478} 479