1 /*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org> 4 * All rights reserved. 5 * 6 * This software was developed by Pawel Jakub Dawidek under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 36 #include <assert.h> 37 #include <errno.h> 38 #ifdef __FreeBSD__ 39 #include <libutil.h> 40 #include <printf.h> 41 #endif 42 #include <stdarg.h> 43 #include <stdint.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <syslog.h> 48 #include <unistd.h> 49 50 #include "pjdlog.h" 51 52 #define PJDLOG_NEVER_INITIALIZED 0 53 #define PJDLOG_NOT_INITIALIZED 1 54 #define PJDLOG_INITIALIZED 2 55 56 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED; 57 static int pjdlog_mode, pjdlog_debug_level; 58 static char pjdlog_prefix[128]; 59 60 #ifdef __FreeBSD__ 61 static int 62 pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused, 63 size_t n, int *argt) 64 { 65 66 assert(n >= 1); 67 argt[0] = PA_INT | PA_FLAG_INTMAX; 68 return (1); 69 } 70 71 static int 72 pjdlog_printf_render_humanized_number(struct __printf_io *io, 73 const struct printf_info *pi, const void * const *arg) 74 { 75 char buf[5]; 76 intmax_t num; 77 int ret; 78 79 num = *(const intmax_t *)arg[0]; 80 humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE, 81 HN_NOSPACE | HN_DECIMAL); 82 ret = __printf_out(io, pi, buf, strlen(buf)); 83 __printf_flush(io); 84 return (ret); 85 } 86 87 static int 88 pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused, 89 size_t n, int *argt) 90 { 91 92 assert(n >= 1); 93 argt[0] = PA_POINTER; 94 return (1); 95 } 96 97 static int 98 pjdlog_printf_render_sockaddr(struct __printf_io *io, 99 const struct printf_info *pi, const void * const *arg) 100 { 101 const struct sockaddr_storage *ss; 102 char buf[64]; 103 int ret; 104 105 ss = *(const struct sockaddr_storage * const *)arg[0]; 106 switch (ss->ss_family) { 107 case AF_INET: 108 { 109 char addr[INET_ADDRSTRLEN]; 110 const struct sockaddr_in *sin; 111 unsigned int port; 112 113 sin = (const struct sockaddr_in *)ss; 114 port = ntohs(sin->sin_port); 115 if (inet_ntop(ss->ss_family, &sin->sin_addr, addr, 116 sizeof(addr)) == NULL) { 117 PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.", 118 strerror(errno)); 119 } 120 snprintf(buf, sizeof(buf), "%s:%u", addr, port); 121 break; 122 } 123 case AF_INET6: 124 { 125 char addr[INET6_ADDRSTRLEN]; 126 const struct sockaddr_in6 *sin; 127 unsigned int port; 128 129 sin = (const struct sockaddr_in6 *)ss; 130 port = ntohs(sin->sin6_port); 131 if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr, 132 sizeof(addr)) == NULL) { 133 PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.", 134 strerror(errno)); 135 } 136 snprintf(buf, sizeof(buf), "[%s]:%u", addr, port); 137 break; 138 } 139 default: 140 snprintf(buf, sizeof(buf), "[unsupported family %hhu]", 141 ss->ss_family); 142 break; 143 } 144 ret = __printf_out(io, pi, buf, strlen(buf)); 145 __printf_flush(io); 146 return (ret); 147 } 148 #endif /* __FreeBSD__ */ 149 150 void 151 pjdlog_init(int mode) 152 { 153 int saved_errno; 154 155 assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED || 156 pjdlog_initialized == PJDLOG_NOT_INITIALIZED); 157 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 158 159 saved_errno = errno; 160 161 if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) { 162 #ifdef __FreeBSD__ 163 __use_xprintf = 1; 164 register_printf_render_std("T"); 165 register_printf_render('N', 166 pjdlog_printf_render_humanized_number, 167 pjdlog_printf_arginfo_humanized_number); 168 register_printf_render('S', 169 pjdlog_printf_render_sockaddr, 170 pjdlog_printf_arginfo_sockaddr); 171 #endif 172 } 173 174 if (mode == PJDLOG_MODE_SYSLOG) 175 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 176 pjdlog_mode = mode; 177 pjdlog_debug_level = 0; 178 bzero(pjdlog_prefix, sizeof(pjdlog_prefix)); 179 180 pjdlog_initialized = PJDLOG_INITIALIZED; 181 182 errno = saved_errno; 183 } 184 185 void 186 pjdlog_fini(void) 187 { 188 int saved_errno; 189 190 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 191 192 saved_errno = errno; 193 194 if (pjdlog_mode == PJDLOG_MODE_SYSLOG) 195 closelog(); 196 197 pjdlog_initialized = PJDLOG_NOT_INITIALIZED; 198 199 errno = saved_errno; 200 } 201 202 /* 203 * Configure where the logs should go. 204 * By default they are send to stdout/stderr, but after going into background 205 * (eg. by calling daemon(3)) application is responsible for changing mode to 206 * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 207 */ 208 void 209 pjdlog_mode_set(int mode) 210 { 211 int saved_errno; 212 213 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 214 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 215 216 if (pjdlog_mode == mode) 217 return; 218 219 saved_errno = errno; 220 221 if (mode == PJDLOG_MODE_SYSLOG) 222 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 223 else /* if (mode == PJDLOG_MODE_STD) */ 224 closelog(); 225 226 pjdlog_mode = mode; 227 228 errno = saved_errno; 229 } 230 231 /* 232 * Return current mode. 233 */ 234 int 235 pjdlog_mode_get(void) 236 { 237 238 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 239 240 return (pjdlog_mode); 241 } 242 243 /* 244 * Set debug level. All the logs above the level specified here will be 245 * ignored. 246 */ 247 void 248 pjdlog_debug_set(int level) 249 { 250 251 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 252 assert(level >= 0); 253 254 pjdlog_debug_level = level; 255 } 256 257 /* 258 * Return current debug level. 259 */ 260 int 261 pjdlog_debug_get(void) 262 { 263 264 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 265 266 return (pjdlog_debug_level); 267 } 268 269 /* 270 * Set prefix that will be used before each log. 271 * Setting prefix to NULL will remove it. 272 */ 273 void 274 pjdlog_prefix_set(const char *fmt, ...) 275 { 276 va_list ap; 277 278 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 279 280 va_start(ap, fmt); 281 pjdlogv_prefix_set(fmt, ap); 282 va_end(ap); 283 } 284 285 /* 286 * Set prefix that will be used before each log. 287 * Setting prefix to NULL will remove it. 288 */ 289 void 290 pjdlogv_prefix_set(const char *fmt, va_list ap) 291 { 292 int saved_errno; 293 294 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 295 assert(fmt != NULL); 296 297 saved_errno = errno; 298 299 vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 300 301 errno = saved_errno; 302 } 303 304 /* 305 * Convert log level into string. 306 */ 307 static const char * 308 pjdlog_level_string(int loglevel) 309 { 310 311 switch (loglevel) { 312 case LOG_EMERG: 313 return ("EMERG"); 314 case LOG_ALERT: 315 return ("ALERT"); 316 case LOG_CRIT: 317 return ("CRIT"); 318 case LOG_ERR: 319 return ("ERROR"); 320 case LOG_WARNING: 321 return ("WARNING"); 322 case LOG_NOTICE: 323 return ("NOTICE"); 324 case LOG_INFO: 325 return ("INFO"); 326 case LOG_DEBUG: 327 return ("DEBUG"); 328 } 329 assert(!"Invalid log level."); 330 abort(); /* XXX: gcc */ 331 } 332 333 /* 334 * Common log routine. 335 */ 336 void 337 pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) 338 { 339 va_list ap; 340 341 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 342 343 va_start(ap, fmt); 344 pjdlogv_common(loglevel, debuglevel, error, fmt, ap); 345 va_end(ap); 346 } 347 348 /* 349 * Common log routine, which can handle regular log level as well as debug 350 * level. We decide here where to send the logs (stdout/stderr or syslog). 351 */ 352 void 353 pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, 354 va_list ap) 355 { 356 int saved_errno; 357 358 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 359 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 360 loglevel == LOG_CRIT || loglevel == LOG_ERR || 361 loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 362 loglevel == LOG_INFO || loglevel == LOG_DEBUG); 363 assert(loglevel != LOG_DEBUG || debuglevel > 0); 364 assert(error >= -1); 365 366 /* Ignore debug above configured level. */ 367 if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) 368 return; 369 370 saved_errno = errno; 371 372 switch (pjdlog_mode) { 373 case PJDLOG_MODE_STD: 374 { 375 FILE *out; 376 377 /* 378 * We send errors and warning to stderr and the rest to stdout. 379 */ 380 switch (loglevel) { 381 case LOG_EMERG: 382 case LOG_ALERT: 383 case LOG_CRIT: 384 case LOG_ERR: 385 case LOG_WARNING: 386 out = stderr; 387 break; 388 case LOG_NOTICE: 389 case LOG_INFO: 390 case LOG_DEBUG: 391 out = stdout; 392 break; 393 default: 394 assert(!"Invalid loglevel."); 395 abort(); /* XXX: gcc */ 396 } 397 398 fprintf(out, "(%d) ", getpid()); 399 fprintf(out, "[%s]", pjdlog_level_string(loglevel)); 400 /* Attach debuglevel if this is debug log. */ 401 if (loglevel == LOG_DEBUG) 402 fprintf(out, "[%d]", debuglevel); 403 fprintf(out, " %s", pjdlog_prefix); 404 vfprintf(out, fmt, ap); 405 if (error != -1) 406 fprintf(out, ": %s.", strerror(error)); 407 fprintf(out, "\n"); 408 fflush(out); 409 break; 410 } 411 case PJDLOG_MODE_SYSLOG: 412 { 413 char log[1024]; 414 int len; 415 416 len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); 417 if ((size_t)len < sizeof(log)) 418 len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); 419 if (error != -1 && (size_t)len < sizeof(log)) { 420 (void)snprintf(log + len, sizeof(log) - len, ": %s.", 421 strerror(error)); 422 } 423 syslog(loglevel, "%s", log); 424 break; 425 } 426 default: 427 assert(!"Invalid mode."); 428 } 429 430 errno = saved_errno; 431 } 432 433 /* 434 * Regular logs. 435 */ 436 void 437 pjdlogv(int loglevel, const char *fmt, va_list ap) 438 { 439 440 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 441 442 /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ 443 assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || 444 loglevel == LOG_CRIT || loglevel == LOG_ERR || 445 loglevel == LOG_WARNING || loglevel == LOG_NOTICE || 446 loglevel == LOG_INFO); 447 448 pjdlogv_common(loglevel, 0, -1, fmt, ap); 449 } 450 451 /* 452 * Regular logs. 453 */ 454 void 455 pjdlog(int loglevel, const char *fmt, ...) 456 { 457 va_list ap; 458 459 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 460 461 va_start(ap, fmt); 462 pjdlogv(loglevel, fmt, ap); 463 va_end(ap); 464 } 465 466 /* 467 * Debug logs. 468 */ 469 void 470 pjdlogv_debug(int debuglevel, const char *fmt, va_list ap) 471 { 472 473 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 474 475 pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); 476 } 477 478 /* 479 * Debug logs. 480 */ 481 void 482 pjdlog_debug(int debuglevel, const char *fmt, ...) 483 { 484 va_list ap; 485 486 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 487 488 va_start(ap, fmt); 489 pjdlogv_debug(debuglevel, fmt, ap); 490 va_end(ap); 491 } 492 493 /* 494 * Error logs with errno logging. 495 */ 496 void 497 pjdlogv_errno(int loglevel, const char *fmt, va_list ap) 498 { 499 500 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 501 502 pjdlogv_common(loglevel, 0, errno, fmt, ap); 503 } 504 505 /* 506 * Error logs with errno logging. 507 */ 508 void 509 pjdlog_errno(int loglevel, const char *fmt, ...) 510 { 511 va_list ap; 512 513 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 514 515 va_start(ap, fmt); 516 pjdlogv_errno(loglevel, fmt, ap); 517 va_end(ap); 518 } 519 520 /* 521 * Log error, errno and exit. 522 */ 523 void 524 pjdlogv_exit(int exitcode, const char *fmt, va_list ap) 525 { 526 527 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 528 529 pjdlogv_errno(LOG_ERR, fmt, ap); 530 exit(exitcode); 531 /* NOTREACHED */ 532 } 533 534 /* 535 * Log error, errno and exit. 536 */ 537 void 538 pjdlog_exit(int exitcode, const char *fmt, ...) 539 { 540 va_list ap; 541 542 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 543 544 va_start(ap, fmt); 545 pjdlogv_exit(exitcode, fmt, ap); 546 /* NOTREACHED */ 547 va_end(ap); 548 } 549 550 /* 551 * Log error and exit. 552 */ 553 void 554 pjdlogv_exitx(int exitcode, const char *fmt, va_list ap) 555 { 556 557 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 558 559 pjdlogv(LOG_ERR, fmt, ap); 560 exit(exitcode); 561 /* NOTREACHED */ 562 } 563 564 /* 565 * Log error and exit. 566 */ 567 void 568 pjdlog_exitx(int exitcode, const char *fmt, ...) 569 { 570 va_list ap; 571 572 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 573 574 va_start(ap, fmt); 575 pjdlogv_exitx(exitcode, fmt, ap); 576 /* NOTREACHED */ 577 va_end(ap); 578 } 579 580 /* 581 * Log failure message and exit. 582 */ 583 void 584 pjdlog_abort(const char *func, const char *file, int line, 585 const char *failedexpr, const char *fmt, ...) 586 { 587 va_list ap; 588 589 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 590 591 /* 592 * When there is no message we pass __func__ as 'fmt'. 593 * It would be cleaner to pass NULL or "", but gcc generates a warning 594 * for both of those. 595 */ 596 if (fmt != func) { 597 va_start(ap, fmt); 598 pjdlogv_critical(fmt, ap); 599 va_end(ap); 600 } 601 if (failedexpr == NULL) { 602 if (func == NULL) { 603 pjdlog_critical("Aborted at file %s, line %d.", file, 604 line); 605 } else { 606 pjdlog_critical("Aborted at function %s, file %s, line %d.", 607 func, file, line); 608 } 609 } else { 610 if (func == NULL) { 611 pjdlog_critical("Assertion failed: (%s), file %s, line %d.", 612 failedexpr, file, line); 613 } else { 614 pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", 615 failedexpr, func, file, line); 616 } 617 } 618 abort(); 619 } 620