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/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/socket.h> 35 #include <netinet/in.h> 36 37 #include <assert.h> 38 #include <errno.h> 39 #include <libutil.h> 40 #include <printf.h> 41 #include <stdarg.h> 42 #include <stdint.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <syslog.h> 47 48 #include "pjdlog.h" 49 50 #define PJDLOG_NEVER_INITIALIZED 0 51 #define PJDLOG_NOT_INITIALIZED 1 52 #define PJDLOG_INITIALIZED 2 53 54 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED; 55 static int pjdlog_mode, pjdlog_debug_level; 56 static char pjdlog_prefix[128]; 57 58 static int 59 pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused, 60 size_t n, int *argt) 61 { 62 63 assert(n >= 1); 64 argt[0] = PA_INT | PA_FLAG_INTMAX; 65 return (1); 66 } 67 68 static int 69 pjdlog_printf_render_humanized_number(struct __printf_io *io, 70 const struct printf_info *pi, const void * const *arg) 71 { 72 char buf[5]; 73 intmax_t num; 74 int ret; 75 76 num = *(const intmax_t *)arg[0]; 77 humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE, 78 HN_NOSPACE | HN_DECIMAL); 79 ret = __printf_out(io, pi, buf, strlen(buf)); 80 __printf_flush(io); 81 return (ret); 82 } 83 84 static int 85 pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused, 86 size_t n, int *argt) 87 { 88 89 assert(n >= 1); 90 argt[0] = PA_POINTER; 91 return (1); 92 } 93 94 static int 95 pjdlog_printf_render_sockaddr(struct __printf_io *io, 96 const struct printf_info *pi, const void * const *arg) 97 { 98 const struct sockaddr_storage *ss; 99 char buf[64]; 100 int ret; 101 102 ss = *(const struct sockaddr_storage * const *)arg[0]; 103 switch (ss->ss_family) { 104 case AF_INET: 105 { 106 const struct sockaddr_in *sin; 107 in_addr_t ip; 108 unsigned int port; 109 110 sin = (const struct sockaddr_in *)ss; 111 ip = ntohl(sin->sin_addr.s_addr); 112 port = ntohs(sin->sin_port); 113 114 snprintf(buf, sizeof(buf), "%u.%u.%u.%u:%u", 115 ((ip >> 24) & 0xff), ((ip >> 16) & 0xff), 116 ((ip >> 8) & 0xff), (ip & 0xff), port); 117 break; 118 } 119 default: 120 snprintf(buf, sizeof(buf), "[unsupported family %u]", 121 (unsigned int)ss->ss_family); 122 break; 123 } 124 ret = __printf_out(io, pi, buf, strlen(buf)); 125 __printf_flush(io); 126 return (ret); 127 } 128 129 void 130 pjdlog_init(int mode) 131 { 132 133 assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED || 134 pjdlog_initialized == PJDLOG_NOT_INITIALIZED); 135 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 136 137 if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) { 138 __use_xprintf = 1; 139 register_printf_render_std("T"); 140 register_printf_render('N', 141 pjdlog_printf_render_humanized_number, 142 pjdlog_printf_arginfo_humanized_number); 143 register_printf_render('S', 144 pjdlog_printf_render_sockaddr, 145 pjdlog_printf_arginfo_sockaddr); 146 } 147 148 if (mode == PJDLOG_MODE_SYSLOG) 149 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 150 pjdlog_mode = mode; 151 pjdlog_debug_level = 0; 152 bzero(pjdlog_prefix, sizeof(pjdlog_prefix)); 153 154 pjdlog_initialized = PJDLOG_INITIALIZED; 155 } 156 157 void 158 pjdlog_fini(void) 159 { 160 161 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 162 163 if (pjdlog_mode == PJDLOG_MODE_SYSLOG) 164 closelog(); 165 166 pjdlog_initialized = PJDLOG_NOT_INITIALIZED; 167 } 168 169 /* 170 * Configure where the logs should go. 171 * By default they are send to stdout/stderr, but after going into background 172 * (eg. by calling daemon(3)) application is responsible for changing mode to 173 * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. 174 */ 175 void 176 pjdlog_mode_set(int mode) 177 { 178 179 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 180 assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); 181 182 if (pjdlog_mode == mode) 183 return; 184 185 if (mode == PJDLOG_MODE_SYSLOG) 186 openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); 187 else /* if (mode == PJDLOG_MODE_STD) */ 188 closelog(); 189 190 pjdlog_mode = mode; 191 } 192 193 /* 194 * Return current mode. 195 */ 196 int 197 pjdlog_mode_get(void) 198 { 199 200 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 201 202 return (pjdlog_mode); 203 } 204 205 /* 206 * Set debug level. All the logs above the level specified here will be 207 * ignored. 208 */ 209 void 210 pjdlog_debug_set(int level) 211 { 212 213 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 214 assert(level >= 0); 215 216 pjdlog_debug_level = level; 217 } 218 219 /* 220 * Return current debug level. 221 */ 222 int 223 pjdlog_debug_get(void) 224 { 225 226 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 227 228 return (pjdlog_debug_level); 229 } 230 231 /* 232 * Set prefix that will be used before each log. 233 * Setting prefix to NULL will remove it. 234 */ 235 void 236 pjdlog_prefix_set(const char *fmt, ...) 237 { 238 va_list ap; 239 240 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 241 242 va_start(ap, fmt); 243 pjdlogv_prefix_set(fmt, ap); 244 va_end(ap); 245 } 246 247 /* 248 * Set prefix that will be used before each log. 249 * Setting prefix to NULL will remove it. 250 */ 251 void 252 pjdlogv_prefix_set(const char *fmt, va_list ap) 253 { 254 255 assert(pjdlog_initialized == PJDLOG_INITIALIZED); 256 assert(fmt != NULL); 257 258 vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); 259 } 260 261 /* 262 * Convert log level into string. 263 */ 264 static const char * 265 pjdlog_level_string(int loglevel) 266 { 267 268 switch (loglevel) { 269 case LOG_EMERG: 270 return ("EMERG"); 271 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 */ 293 void 294 pjdlog_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 */ 309 void 310 pjdlogv_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 */ 387 void 388 pjdlogv(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 */ 405 void 406 pjdlog(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 */ 420 void 421 pjdlogv_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 */ 432 void 433 pjdlog_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 */ 447 void 448 pjdlogv_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 */ 459 void 460 pjdlog_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 */ 474 void 475 pjdlogv_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 */ 488 void 489 pjdlog_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 */ 504 void 505 pjdlogv_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 */ 518 void 519 pjdlog_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 */ 534 void 535 pjdlog_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