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