pjdlog.c revision 219385
161452Sdfr/*- 261452Sdfr * Copyright (c) 2009-2010 The FreeBSD Foundation 361452Sdfr * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org> 461452Sdfr * All rights reserved. 561452Sdfr * 661452Sdfr * This software was developed by Pawel Jakub Dawidek under sponsorship from 761452Sdfr * the FreeBSD Foundation. 861452Sdfr * 961452Sdfr * Redistribution and use in source and binary forms, with or without 1061452Sdfr * modification, are permitted provided that the following conditions 1161452Sdfr * are met: 1261452Sdfr * 1. Redistributions of source code must retain the above copyright 1361452Sdfr * notice, this list of conditions and the following disclaimer. 1461452Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1561452Sdfr * notice, this list of conditions and the following disclaimer in the 1661452Sdfr * documentation and/or other materials provided with the distribution. 1761452Sdfr * 1861452Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1961452Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2061452Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2161452Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 2261452Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2361452Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2461452Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2561452Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2661452Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27116192Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28116192Sobrien * SUCH DAMAGE. 29116192Sobrien */ 3061452Sdfr 3161452Sdfr#include <sys/cdefs.h> 3261452Sdfr__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 219385 2011-03-07 19:54:51Z pjd $"); 3361452Sdfr 34129878Sphk#include <sys/socket.h> 3561452Sdfr#include <netinet/in.h> 3661452Sdfr 3776827Salfred#include <assert.h> 3879339Sjhb#include <errno.h> 3961452Sdfr#include <libutil.h> 40173573Sjhb#include <printf.h> 41173573Sjhb#include <stdarg.h> 42119288Simp#include <stdint.h> 43119288Simp#include <stdio.h> 4461452Sdfr#include <stdlib.h> 4561452Sdfr#include <string.h> 4661452Sdfr#include <syslog.h> 4761452Sdfr 4861452Sdfr#include "pjdlog.h" 4961452Sdfr 5061452Sdfr#define PJDLOG_NEVER_INITIALIZED 0 5161452Sdfr#define PJDLOG_NOT_INITIALIZED 1 5261452Sdfr#define PJDLOG_INITIALIZED 2 5361452Sdfr 5461452Sdfrstatic int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED; 5561452Sdfrstatic int pjdlog_mode, pjdlog_debug_level; 5661452Sdfrstatic char pjdlog_prefix[128]; 5761452Sdfr 5861452Sdfrstatic int 5961452Sdfrpjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused, 6061452Sdfr size_t n, int *argt) 6161452Sdfr{ 6261452Sdfr 6361452Sdfr assert(n >= 1); 6461452Sdfr argt[0] = PA_INT | PA_FLAG_INTMAX; 6561452Sdfr return (1); 66142646Scognet} 67142646Scognet 6861452Sdfrstatic int 6961452Sdfrpjdlog_printf_render_humanized_number(struct __printf_io *io, 70139431Sanholt const struct printf_info *pi, const void * const *arg) 71139431Sanholt{ 72244926Santoine char buf[5]; 7361452Sdfr intmax_t num; 7461452Sdfr int ret; 7561452Sdfr 7661452Sdfr num = *(const intmax_t *)arg[0]; 7761452Sdfr humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE, 7861452Sdfr HN_NOSPACE | HN_DECIMAL); 7961452Sdfr ret = __printf_out(io, pi, buf, strlen(buf)); 8061452Sdfr __printf_flush(io); 8161452Sdfr return (ret); 82241885Seadler} 83241885Seadler 8461452Sdfrstatic int 8561452Sdfrpjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused, 8661452Sdfr size_t n, int *argt) 87142398Simp{ 8861452Sdfr 8961452Sdfr assert(n >= 1); 9061452Sdfr argt[0] = PA_POINTER; 9161452Sdfr return (1); 9261452Sdfr} 9361452Sdfr 9461452Sdfrstatic int 9561452Sdfrpjdlog_printf_render_sockaddr(struct __printf_io *io, 9661452Sdfr const struct printf_info *pi, const void * const *arg) 9761452Sdfr{ 9861452Sdfr const struct sockaddr_storage *ss; 99134098Sanholt char buf[64]; 10061452Sdfr int ret; 10161452Sdfr 10261452Sdfr ss = *(const struct sockaddr_storage * const *)arg[0]; 10361452Sdfr switch (ss->ss_family) { 10461452Sdfr case AF_INET: 10561452Sdfr { 106122513Sanholt const struct sockaddr_in *sin; 107122513Sanholt in_addr_t ip; 108122513Sanholt unsigned int port; 109122513Sanholt 11061452Sdfr sin = (const struct sockaddr_in *)ss; 11161452Sdfr ip = ntohl(sin->sin_addr.s_addr); 11261452Sdfr port = ntohs(sin->sin_port); 11361452Sdfr 11461452Sdfr snprintf(buf, sizeof(buf), "%u.%u.%u.%u:%u", 11561452Sdfr ((ip >> 24) & 0xff), ((ip >> 16) & 0xff), 11661452Sdfr ((ip >> 8) & 0xff), (ip & 0xff), port); 11761452Sdfr break; 11861452Sdfr } 11961452Sdfr default: 12061452Sdfr snprintf(buf, sizeof(buf), "[unsupported family %u]", 12161452Sdfr (unsigned int)ss->ss_family); 12261452Sdfr break; 12361452Sdfr } 12461452Sdfr ret = __printf_out(io, pi, buf, strlen(buf)); 12561452Sdfr __printf_flush(io); 12661452Sdfr return (ret); 12761452Sdfr} 128134098Sanholt 129134098Sanholtvoid 130134099Sanholtpjdlog_init(int mode) 13161452Sdfr{ 13261452Sdfr 13361452Sdfr assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED || 13461452Sdfr pjdlog_initialized == PJDLOG_NOT_INITIALIZED); 13561452Sdfr assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 13661452Sdfr 13761452Sdfr if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) { 13861452Sdfr __use_xprintf = 1; 13961452Sdfr register_printf_render_std("T"); 14061452Sdfr register_printf_render('N', 14161452Sdfr pjdlog_printf_render_humanized_number, 142134098Sanholt pjdlog_printf_arginfo_humanized_number); 14361452Sdfr register_printf_render('S', 144173203Sjhb pjdlog_printf_render_sockaddr, 14561452Sdfr pjdlog_printf_arginfo_sockaddr); 14661452Sdfr } 14761452Sdfr 14861452Sdfr if (mode == PJDLOG_MODE_SYSLOG) 14961452Sdfr openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 15061452Sdfr pjdlog_mode = mode; 151134098Sanholt pjdlog_debug_level = 0; 152134099Sanholt bzero(pjdlog_prefix, sizeof(pjdlog_prefix)); 15361452Sdfr 15461452Sdfr pjdlog_initialized = PJDLOG_INITIALIZED; 155173203Sjhb} 15661452Sdfr 15761452Sdfrvoid 15861452Sdfrpjdlog_fini(void) 15961452Sdfr{ 16061452Sdfr 16161452Sdfr assert(pjdlog_initialized == PJDLOG_INITIALIZED); 16261452Sdfr 16361452Sdfr if (pjdlog_mode == PJDLOG_MODE_SYSLOG) 16461452Sdfr closelog(); 16561452Sdfr 16661452Sdfr pjdlog_initialized = PJDLOG_NOT_INITIALIZED; 16761452Sdfr} 16861452Sdfr 16961452Sdfr/* 17061452Sdfr * Configure where the logs should go. 17161452Sdfr * By default they are send to stdout/stderr, but after going into background 17261452Sdfr * (eg. by calling daemon(3)) application is responsible for changing mode to 17361452Sdfr * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 17461452Sdfr */ 17561452Sdfrvoid 17661452Sdfrpjdlog_mode_set(int mode) 17761452Sdfr{ 17861452Sdfr 17961452Sdfr assert(pjdlog_initialized == PJDLOG_INITIALIZED); 18061452Sdfr assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 18161452Sdfr 18261452Sdfr if (pjdlog_mode == mode) 183134099Sanholt return; 18461452Sdfr 18561452Sdfr if (mode == PJDLOG_MODE_SYSLOG) 18661452Sdfr openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 18761452Sdfr else /* if (mode == PJDLOG_MODE_STD) */ 18861452Sdfr closelog(); 18961452Sdfr 19061452Sdfr pjdlog_mode = mode; 19161452Sdfr} 19261452Sdfr 193134098Sanholt/* 19461452Sdfr * Return current mode. 19561452Sdfr */ 19661452Sdfrint 19761452Sdfrpjdlog_mode_get(void) 19861452Sdfr{ 19961452Sdfr 20061452Sdfr assert(pjdlog_initialized == PJDLOG_INITIALIZED); 201134098Sanholt 202134099Sanholt return (pjdlog_mode); 20361452Sdfr} 20461452Sdfr 20561452Sdfr/* 20661452Sdfr * Set debug level. All the logs above the level specified here will be 207194017Savg * ignored. 20861452Sdfr */ 20961452Sdfrvoid 21061452Sdfrpjdlog_debug_set(int level) 211194017Savg{ 21261452Sdfr 21361452Sdfr assert(pjdlog_initialized == PJDLOG_INITIALIZED); 21461452Sdfr assert(level >= 0); 21561452Sdfr 21661452Sdfr pjdlog_debug_level = level; 21761452Sdfr} 21861452Sdfr 219194017Savg/* 22061452Sdfr * Return current debug level. 22161452Sdfr */ 22261452Sdfrint 223194017Savgpjdlog_debug_get(void) 22461452Sdfr{ 22561452Sdfr 22661452Sdfr assert(pjdlog_initialized == PJDLOG_INITIALIZED); 22761452Sdfr 22861452Sdfr return (pjdlog_debug_level); 22961452Sdfr} 23061452Sdfr 23161452Sdfr/* 23261452Sdfr * Set prefix that will be used before each log. 23361452Sdfr * Setting prefix to NULL will remove it. 23461452Sdfr */ 23561452Sdfrvoid 23661452Sdfrpjdlog_prefix_set(const char *fmt, ...) 23761452Sdfr{ 23861452Sdfr va_list ap; 23961452Sdfr 24061452Sdfr assert(pjdlog_initialized == PJDLOG_INITIALIZED); 24161452Sdfr 24261452Sdfr va_start(ap, fmt); 24361452Sdfr pjdlogv_prefix_set(fmt, ap); 24461452Sdfr va_end(ap); 24561452Sdfr} 24661452Sdfr 24761452Sdfr/* 24861452Sdfr * Set prefix that will be used before each log. 24961452Sdfr * Setting prefix to NULL will remove it. 25061452Sdfr */ 25161452Sdfrvoid 25261452Sdfrpjdlogv_prefix_set(const char *fmt, va_list ap) 25361452Sdfr{ 25461452Sdfr 25561452Sdfr assert(pjdlog_initialized == PJDLOG_INITIALIZED); 25661452Sdfr assert(fmt != NULL); 25761452Sdfr 25861452Sdfr vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 25961452Sdfr} 26061452Sdfr 26161452Sdfr/* 26261452Sdfr * Convert log level into string. 26361452Sdfr */ 26461452Sdfrstatic const char * 26561452Sdfrpjdlog_level_string(int loglevel) 26661452Sdfr{ 26761452Sdfr 26861452Sdfr switch (loglevel) { 269153572Sjhb case LOG_EMERG: 270113506Smdodd return ("EMERG"); 271113506Smdodd case LOG_ALERT: 272 return ("ALERT"); 273 case LOG_CRIT: 274 return ("CRIT"); 275 case LOG_ERR: 276 return ("ERROR"); 277 case LOG_WARNING: 278 return ("WARNING"); 279 case LOG_NOTICE: 280 return ("NOTICE"); 281 case LOG_INFO: 282 return ("INFO"); 283 case LOG_DEBUG: 284 return ("DEBUG"); 285 } 286 assert(!"Invalid log level."); 287 abort(); /* XXX: gcc */ 288} 289 290/* 291 * Common log routine. 292 */ 293void 294pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 295{ 296 va_list ap; 297 298 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 299 300 va_start(ap, fmt); 301 pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 302 va_end(ap); 303} 304 305/* 306 * Common log routine, which can handle regular log level as well as debug 307 * level. We decide here where to send the logs (stdout/stderr or syslog). 308 */ 309void 310pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 311 va_list ap) 312{ 313 314 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 315 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 316 loglevel == LOG_CRIT || loglevel == LOG_ERR || 317 loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 318 loglevel == LOG_INFO || loglevel == LOG_DEBUG); 319 assert(loglevel != LOG_DEBUG || debuglevel > 0); 320 assert(error >= -1); 321 322 /* Ignore debug above configured level. */ 323 if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 324 return; 325 326 switch (pjdlog_mode) { 327 case PJDLOG_MODE_STD: 328 { 329 FILE *out; 330 331 /* 332 * We send errors and warning to stderr and the rest to stdout. 333 */ 334 switch (loglevel) { 335 case LOG_EMERG: 336 case LOG_ALERT: 337 case LOG_CRIT: 338 case LOG_ERR: 339 case LOG_WARNING: 340 out = stderr; 341 break; 342 case LOG_NOTICE: 343 case LOG_INFO: 344 case LOG_DEBUG: 345 out = stdout; 346 break; 347 default: 348 assert(!"Invalid loglevel."); 349 abort(); /* XXX: gcc */ 350 } 351 352 fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 353 /* Attach debuglevel if this is debug log. */ 354 if (loglevel == LOG_DEBUG) 355 fprintf(out, "[%d]", debuglevel); 356 fprintf(out, " %s", pjdlog_prefix); 357 vfprintf(out, fmt, ap); 358 if (error != -1) 359 fprintf(out, ": %s.", strerror(error)); 360 fprintf(out, "\n"); 361 fflush(out); 362 break; 363 } 364 case PJDLOG_MODE_SYSLOG: 365 { 366 char log[1024]; 367 int len; 368 369 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 370 if ((size_t)len < sizeof(log)) 371 len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 372 if (error != -1 && (size_t)len < sizeof(log)) { 373 (void)snprintf(log + len, sizeof(log) - len, ": %s.", 374 strerror(error)); 375 } 376 syslog(loglevel, "%s", log); 377 break; 378 } 379 default: 380 assert(!"Invalid mode."); 381 } 382} 383 384/* 385 * Regular logs. 386 */ 387void 388pjdlogv(int loglevel, const char *fmt, va_list ap) 389{ 390 391 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 392 393 /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 394 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 395 loglevel == LOG_CRIT || loglevel == LOG_ERR || 396 loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 397 loglevel == LOG_INFO); 398 399 pjdlogv_common(loglevel, 0, -1, fmt, ap); 400} 401 402/* 403 * Regular logs. 404 */ 405void 406pjdlog(int loglevel, const char *fmt, ...) 407{ 408 va_list ap; 409 410 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 411 412 va_start(ap, fmt); 413 pjdlogv(loglevel, fmt, ap); 414 va_end(ap); 415} 416 417/* 418 * Debug logs. 419 */ 420void 421pjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 422{ 423 424 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 425 426 pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 427} 428 429/* 430 * Debug logs. 431 */ 432void 433pjdlog_debug(int debuglevel, const char *fmt, ...) 434{ 435 va_list ap; 436 437 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 438 439 va_start(ap, fmt); 440 pjdlogv_debug(debuglevel, fmt, ap); 441 va_end(ap); 442} 443 444/* 445 * Error logs with errno logging. 446 */ 447void 448pjdlogv_errno(int loglevel, const char *fmt, va_list ap) 449{ 450 451 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 452 453 pjdlogv_common(loglevel, 0, errno, fmt, ap); 454} 455 456/* 457 * Error logs with errno logging. 458 */ 459void 460pjdlog_errno(int loglevel, const char *fmt, ...) 461{ 462 va_list ap; 463 464 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 465 466 va_start(ap, fmt); 467 pjdlogv_errno(loglevel, fmt, ap); 468 va_end(ap); 469} 470 471/* 472 * Log error, errno and exit. 473 */ 474void 475pjdlogv_exit(int exitcode, const char *fmt, va_list ap) 476{ 477 478 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 479 480 pjdlogv_errno(LOG_ERR, fmt, ap); 481 exit(exitcode); 482 /* NOTREACHED */ 483} 484 485/* 486 * Log error, errno and exit. 487 */ 488void 489pjdlog_exit(int exitcode, const char *fmt, ...) 490{ 491 va_list ap; 492 493 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 494 495 va_start(ap, fmt); 496 pjdlogv_exit(exitcode, fmt, ap); 497 /* NOTREACHED */ 498 va_end(ap); 499} 500 501/* 502 * Log error and exit. 503 */ 504void 505pjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 506{ 507 508 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 509 510 pjdlogv(LOG_ERR, fmt, ap); 511 exit(exitcode); 512 /* NOTREACHED */ 513} 514 515/* 516 * Log error and exit. 517 */ 518void 519pjdlog_exitx(int exitcode, const char *fmt, ...) 520{ 521 va_list ap; 522 523 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 524 525 va_start(ap, fmt); 526 pjdlogv_exitx(exitcode, fmt, ap); 527 /* NOTREACHED */ 528 va_end(ap); 529} 530 531/* 532 * Log failure message and exit. 533 */ 534void 535pjdlog_abort(const char *func, const char *file, int line, 536 const char *failedexpr, const char *fmt, ...) 537{ 538 va_list ap; 539 540 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 541 542 /* 543 * When there is no message we pass __func__ as 'fmt'. 544 * It would be cleaner to pass NULL or "", but gcc generates a warning 545 * for both of those. 546 */ 547 if (fmt != func) { 548 va_start(ap, fmt); 549 pjdlogv_critical(fmt, ap); 550 va_end(ap); 551 } 552 if (failedexpr == NULL) { 553 if (func == NULL) { 554 pjdlog_critical("Aborted at file %s, line %d.", file, 555 line); 556 } else { 557 pjdlog_critical("Aborted at function %s, file %s, line %d.", 558 func, file, line); 559 } 560 } else { 561 if (func == NULL) { 562 pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 563 failedexpr, file, line); 564 } else { 565 pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 566 failedexpr, func, file, line); 567 } 568 } 569 abort(); 570} 571