1 /* $NetBSD: msyslog.c,v 1.5 2016/01/08 21:35:38 christos Exp $ */ 2 3 /* 4 * msyslog - either send a message to the terminal or print it on 5 * the standard output. 6 * 7 * Converted to use varargs, much better ... jks 8 */ 9 10 #ifdef HAVE_CONFIG_H 11 # include <config.h> 12 #endif 13 14 #include <sys/types.h> 15 #ifdef HAVE_UNISTD_H 16 # include <unistd.h> 17 #endif 18 #include <stdio.h> 19 20 #include "ntp_string.h" 21 #include "ntp.h" 22 #include "ntp_debug.h" 23 #include "ntp_syslog.h" 24 25 #ifdef SYS_WINNT 26 # include <stdarg.h> 27 # include "..\ports\winnt\libntp\messages.h" 28 #endif 29 30 31 int syslogit = TRUE; 32 int msyslog_term = FALSE; /* duplicate to stdout/err */ 33 int msyslog_term_pid = TRUE; 34 int msyslog_include_timestamp = TRUE; 35 FILE * syslog_file; 36 char * syslog_fname; 37 char * syslog_abs_fname; 38 39 /* libntp default ntp_syslogmask is all bits lit */ 40 #define INIT_NTP_SYSLOGMASK ~(u_int32)0 41 u_int32 ntp_syslogmask = INIT_NTP_SYSLOGMASK; 42 43 extern char const * progname; 44 45 /* Declare the local functions */ 46 void addto_syslog (int, const char *); 47 #ifndef VSNPRINTF_PERCENT_M 48 void format_errmsg (char *, size_t, const char *, int); 49 50 /* format_errmsg() is under #ifndef VSNPRINTF_PERCENT_M above */ 51 void 52 format_errmsg( 53 char * nfmt, 54 size_t lennfmt, 55 const char * fmt, 56 int errval 57 ) 58 { 59 char errmsg[256]; 60 char c; 61 char *n; 62 const char *f; 63 size_t len; 64 65 n = nfmt; 66 f = fmt; 67 while ((c = *f++) != '\0' && n < (nfmt + lennfmt - 1)) { 68 if (c != '%') { 69 *n++ = c; 70 continue; 71 } 72 if ((c = *f++) != 'm') { 73 *n++ = '%'; 74 if ('\0' == c) 75 break; 76 *n++ = c; 77 continue; 78 } 79 errno_to_str(errval, errmsg, sizeof(errmsg)); 80 len = strlen(errmsg); 81 82 /* Make sure we have enough space for the error message */ 83 if ((n + len) < (nfmt + lennfmt - 1)) { 84 memcpy(n, errmsg, len); 85 n += len; 86 } 87 } 88 *n = '\0'; 89 } 90 #endif /* VSNPRINTF_PERCENT_M */ 91 92 93 /* 94 * errno_to_str() - a thread-safe strerror() replacement. 95 * Hides the varied signatures of strerror_r(). 96 * For Windows, we have: 97 * #define errno_to_str isc_strerror 98 */ 99 #ifndef errno_to_str 100 void 101 errno_to_str( 102 int err, 103 char * buf, 104 size_t bufsiz 105 ) 106 { 107 # if defined(STRERROR_R_CHAR_P) || !HAVE_DECL_STRERROR_R 108 char * pstatic; 109 110 buf[0] = '\0'; 111 # ifdef STRERROR_R_CHAR_P 112 pstatic = strerror_r(err, buf, bufsiz); 113 # else 114 pstatic = strerror(err); 115 # endif 116 if (NULL == pstatic && '\0' == buf[0]) 117 snprintf(buf, bufsiz, "%s(%d): errno %d", 118 # ifdef STRERROR_R_CHAR_P 119 "strerror_r", 120 # else 121 "strerror", 122 # endif 123 err, errno); 124 /* protect against believing an int return is a pointer */ 125 else if (pstatic != buf && pstatic > (char *)bufsiz) 126 strlcpy(buf, pstatic, bufsiz); 127 # else 128 int rc; 129 130 rc = strerror_r(err, buf, bufsiz); 131 if (rc < 0) 132 snprintf(buf, bufsiz, "strerror_r(%d): errno %d", 133 err, errno); 134 # endif 135 } 136 #endif /* errno_to_str */ 137 138 139 /* 140 * addto_syslog() 141 * This routine adds the contents of a buffer to the syslog or an 142 * application-specific logfile. 143 */ 144 void 145 addto_syslog( 146 int level, 147 const char * msg 148 ) 149 { 150 static char const * prevcall_progname; 151 static char const * prog; 152 const char nl[] = "\n"; 153 const char empty[] = ""; 154 FILE * term_file; 155 int log_to_term; 156 int log_to_file; 157 int pid; 158 const char * nl_or_empty; 159 const char * human_time; 160 161 /* setup program basename static var prog if needed */ 162 if (progname != prevcall_progname) { 163 prevcall_progname = progname; 164 prog = strrchr(progname, DIR_SEP); 165 if (prog != NULL) 166 prog++; 167 else 168 prog = progname; 169 } 170 171 log_to_term = msyslog_term; 172 log_to_file = FALSE; 173 #if !defined(VMS) && !defined(SYS_VXWORKS) 174 if (syslogit) 175 syslog(level, "%s", msg); 176 else 177 #endif 178 if (syslog_file != NULL) 179 log_to_file = TRUE; 180 else 181 log_to_term = TRUE; 182 #if DEBUG 183 if (debug > 0) 184 log_to_term = TRUE; 185 #endif 186 if (!(log_to_file || log_to_term)) 187 return; 188 189 /* syslog() adds the timestamp, name, and pid */ 190 if (msyslog_include_timestamp) 191 human_time = humanlogtime(); 192 else /* suppress gcc pot. uninit. warning */ 193 human_time = NULL; 194 if (msyslog_term_pid || log_to_file) 195 pid = getpid(); 196 else /* suppress gcc pot. uninit. warning */ 197 pid = -1; 198 199 /* syslog() adds trailing \n if not present */ 200 if ('\n' != msg[strlen(msg) - 1]) 201 nl_or_empty = nl; 202 else 203 nl_or_empty = empty; 204 205 if (log_to_term) { 206 term_file = (level <= LOG_ERR) 207 ? stderr 208 : stdout; 209 if (msyslog_include_timestamp) 210 fprintf(term_file, "%s ", human_time); 211 if (msyslog_term_pid) 212 fprintf(term_file, "%s[%d]: ", prog, pid); 213 fprintf(term_file, "%s%s", msg, nl_or_empty); 214 fflush(term_file); 215 } 216 217 if (log_to_file) { 218 if (msyslog_include_timestamp) 219 fprintf(syslog_file, "%s ", human_time); 220 fprintf(syslog_file, "%s[%d]: %s%s", prog, pid, msg, 221 nl_or_empty); 222 fflush(syslog_file); 223 } 224 } 225 226 227 int 228 mvsnprintf( 229 char * buf, 230 size_t bufsiz, 231 const char * fmt, 232 va_list ap 233 ) 234 { 235 #ifndef VSNPRINTF_PERCENT_M 236 char nfmt[256]; 237 #else 238 const char * nfmt = fmt; 239 #endif 240 int errval; 241 242 /* 243 * Save the error value as soon as possible 244 */ 245 #ifdef SYS_WINNT 246 errval = GetLastError(); 247 if (NO_ERROR == errval) 248 #endif /* SYS_WINNT */ 249 errval = errno; 250 251 #ifndef VSNPRINTF_PERCENT_M 252 format_errmsg(nfmt, sizeof(nfmt), fmt, errval); 253 #else 254 errno = errval; 255 #endif 256 return vsnprintf(buf, bufsiz, nfmt, ap); 257 } 258 259 260 int 261 mvfprintf( 262 FILE * fp, 263 const char * fmt, 264 va_list ap 265 ) 266 { 267 #ifndef VSNPRINTF_PERCENT_M 268 char nfmt[256]; 269 #else 270 const char * nfmt = fmt; 271 #endif 272 int errval; 273 274 /* 275 * Save the error value as soon as possible 276 */ 277 #ifdef SYS_WINNT 278 errval = GetLastError(); 279 if (NO_ERROR == errval) 280 #endif /* SYS_WINNT */ 281 errval = errno; 282 283 #ifndef VSNPRINTF_PERCENT_M 284 format_errmsg(nfmt, sizeof(nfmt), fmt, errval); 285 #else 286 errno = errval; 287 #endif 288 return vfprintf(fp, nfmt, ap); 289 } 290 291 292 int 293 mfprintf( 294 FILE * fp, 295 const char * fmt, 296 ... 297 ) 298 { 299 va_list ap; 300 int rc; 301 302 va_start(ap, fmt); 303 rc = mvfprintf(fp, fmt, ap); 304 va_end(ap); 305 306 return rc; 307 } 308 309 310 int 311 mprintf( 312 const char * fmt, 313 ... 314 ) 315 { 316 va_list ap; 317 int rc; 318 319 va_start(ap, fmt); 320 rc = mvfprintf(stdout, fmt, ap); 321 va_end(ap); 322 323 return rc; 324 } 325 326 327 int 328 msnprintf( 329 char * buf, 330 size_t bufsiz, 331 const char * fmt, 332 ... 333 ) 334 { 335 va_list ap; 336 int rc; 337 338 va_start(ap, fmt); 339 rc = mvsnprintf(buf, bufsiz, fmt, ap); 340 va_end(ap); 341 342 return rc; 343 } 344 345 346 void 347 msyslog( 348 int level, 349 const char * fmt, 350 ... 351 ) 352 { 353 char buf[1024]; 354 va_list ap; 355 356 va_start(ap, fmt); 357 mvsnprintf(buf, sizeof(buf), fmt, ap); 358 va_end(ap); 359 addto_syslog(level, buf); 360 } 361 362 void 363 mvsyslog( 364 int level, 365 const char * fmt, 366 va_list ap 367 ) 368 { 369 char buf[1024]; 370 mvsnprintf(buf, sizeof(buf), fmt, ap); 371 addto_syslog(level, buf); 372 } 373 374 375 /* 376 * Initialize the logging 377 * 378 * Called once per process, including forked children. 379 */ 380 void 381 init_logging( 382 const char * name, 383 u_int32 def_syslogmask, 384 int is_daemon 385 ) 386 { 387 static int was_daemon; 388 char * cp; 389 const char * pname; 390 391 /* 392 * ntpd defaults to only logging sync-category events, when 393 * NLOG() is used to conditionalize. Other libntp clients 394 * leave it alone so that all NLOG() conditionals will fire. 395 * This presumes all bits lit in ntp_syslogmask can't be 396 * configured via logconfig and all lit is thereby a sentinel 397 * that ntp_syslogmask is still at its default from libntp, 398 * keeping in mind this function is called in forked children 399 * where it has already been called in the parent earlier. 400 * Forked children pass 0 for def_syslogmask. 401 */ 402 if (INIT_NTP_SYSLOGMASK == ntp_syslogmask && 403 0 != def_syslogmask) 404 ntp_syslogmask = def_syslogmask; /* set more via logconfig */ 405 406 /* 407 * Logging. This may actually work on the gizmo board. Find a name 408 * to log with by using the basename 409 */ 410 cp = strrchr(name, DIR_SEP); 411 if (NULL == cp) 412 pname = name; 413 else 414 pname = 1 + cp; /* skip DIR_SEP */ 415 progname = estrdup(pname); 416 #ifdef SYS_WINNT /* strip ".exe" */ 417 cp = strrchr(progname, '.'); 418 if (NULL != cp && !strcasecmp(cp, ".exe")) 419 *cp = '\0'; 420 #endif 421 422 #if !defined(VMS) 423 424 if (is_daemon) 425 was_daemon = TRUE; 426 # ifndef LOG_DAEMON 427 openlog(progname, LOG_PID); 428 # else /* LOG_DAEMON */ 429 430 # ifndef LOG_NTP 431 # define LOG_NTP LOG_DAEMON 432 # endif 433 openlog(progname, LOG_PID | LOG_NDELAY, (was_daemon) 434 ? LOG_NTP 435 : 0); 436 # ifdef DEBUG 437 if (debug) 438 setlogmask(LOG_UPTO(LOG_DEBUG)); 439 else 440 # endif /* DEBUG */ 441 setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */ 442 # endif /* LOG_DAEMON */ 443 #endif /* !VMS */ 444 } 445 446 447 /* 448 * change_logfile() 449 * 450 * Used to change from syslog to a logfile, or from one logfile to 451 * another, and to reopen logfiles after forking. On systems where 452 * ntpd forks, deals with converting relative logfile paths to 453 * absolute (root-based) because we reopen logfiles after the current 454 * directory has changed. 455 */ 456 int 457 change_logfile( 458 const char * fname, 459 int leave_crumbs 460 ) 461 { 462 FILE * new_file; 463 const char * log_fname; 464 char * abs_fname; 465 #if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS) 466 char curdir[512]; 467 size_t cd_octets; 468 size_t octets; 469 #endif /* POSIX */ 470 471 REQUIRE(fname != NULL); 472 log_fname = fname; 473 474 /* 475 * In a forked child of a parent which is logging to a file 476 * instead of syslog, syslog_file will be NULL and both 477 * syslog_fname and syslog_abs_fname will be non-NULL. 478 * If we are given the same filename previously opened 479 * and it's still open, there's nothing to do here. 480 */ 481 if (syslog_file != NULL && syslog_fname != NULL && 482 0 == strcmp(syslog_fname, log_fname)) 483 return 0; 484 485 if (0 == strcmp(log_fname, "stderr")) { 486 new_file = stderr; 487 abs_fname = estrdup(log_fname); 488 } else if (0 == strcmp(log_fname, "stdout")) { 489 new_file = stdout; 490 abs_fname = estrdup(log_fname); 491 } else { 492 if (syslog_fname != NULL && 493 0 == strcmp(log_fname, syslog_fname)) 494 log_fname = syslog_abs_fname; 495 #if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS) 496 if (log_fname != syslog_abs_fname && 497 DIR_SEP != log_fname[0] && 498 0 != strcmp(log_fname, "stderr") && 499 0 != strcmp(log_fname, "stdout") && 500 NULL != getcwd(curdir, sizeof(curdir))) { 501 cd_octets = strlen(curdir); 502 /* trim any trailing '/' */ 503 if (cd_octets > 1 && 504 DIR_SEP == curdir[cd_octets - 1]) 505 cd_octets--; 506 octets = cd_octets; 507 octets += 1; /* separator '/' */ 508 octets += strlen(log_fname); 509 octets += 1; /* NUL terminator */ 510 abs_fname = emalloc(octets); 511 snprintf(abs_fname, octets, "%.*s%c%s", 512 (int)cd_octets, curdir, DIR_SEP, 513 log_fname); 514 } else 515 #endif 516 abs_fname = estrdup(log_fname); 517 TRACE(1, ("attempting to open log %s\n", abs_fname)); 518 new_file = fopen(abs_fname, "a"); 519 } 520 521 if (NULL == new_file) { 522 free(abs_fname); 523 return -1; 524 } 525 526 /* leave a pointer in the old log */ 527 if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname)) 528 msyslog(LOG_NOTICE, "switching logging to file %s", 529 abs_fname); 530 531 if (syslog_file != NULL && 532 syslog_file != stderr && syslog_file != stdout && 533 fileno(syslog_file) != fileno(new_file)) 534 fclose(syslog_file); 535 syslog_file = new_file; 536 if (log_fname == syslog_abs_fname) { 537 free(abs_fname); 538 } else { 539 if (syslog_abs_fname != NULL && 540 syslog_abs_fname != syslog_fname) 541 free(syslog_abs_fname); 542 if (syslog_fname != NULL) 543 free(syslog_fname); 544 syslog_fname = estrdup(log_fname); 545 syslog_abs_fname = abs_fname; 546 } 547 syslogit = FALSE; 548 549 return 0; 550 } 551 552 553 /* 554 * setup_logfile() 555 * 556 * Redirect logging to a file if requested with -l/--logfile or via 557 * ntp.conf logfile directive. 558 * 559 * This routine is invoked three different times in the sequence of a 560 * typical daemon ntpd with DNS lookups to do. First it is invoked in 561 * the original ntpd process, then again in the daemon after closing 562 * all descriptors. In both of those cases, ntp.conf has not been 563 * processed, so only -l/--logfile will trigger logfile redirection in 564 * those invocations. Finally, if DNS names are resolved, the worker 565 * child invokes this routine after its fork and close of all 566 * descriptors. In this case, ntp.conf has been processed and any 567 * "logfile" directive needs to be honored in the child as well. 568 */ 569 void 570 setup_logfile( 571 const char * name 572 ) 573 { 574 if (NULL == syslog_fname && NULL != name) { 575 if (-1 == change_logfile(name, TRUE)) 576 msyslog(LOG_ERR, "Cannot open log file %s, %m", 577 name); 578 return ; 579 } 580 if (NULL == syslog_fname) 581 return; 582 583 if (-1 == change_logfile(syslog_fname, FALSE)) 584 msyslog(LOG_ERR, "Cannot reopen log file %s, %m", 585 syslog_fname); 586 } 587