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