1 /* $NetBSD: msyslog.c,v 1.1.1.3 2013/12/27 23:30:48 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 * 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 * prevcall_progname; 151 static char * 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 size_t 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 363 /* 364 * Initialize the logging 365 * 366 * Called once per process, including forked children. 367 */ 368 void 369 init_logging( 370 const char * name, 371 u_int32 def_syslogmask, 372 int is_daemon 373 ) 374 { 375 static int was_daemon; 376 const char * cp; 377 const char * pname; 378 379 /* 380 * ntpd defaults to only logging sync-category events, when 381 * NLOG() is used to conditionalize. Other libntp clients 382 * leave it alone so that all NLOG() conditionals will fire. 383 * This presumes all bits lit in ntp_syslogmask can't be 384 * configured via logconfig and all lit is thereby a sentinel 385 * that ntp_syslogmask is still at its default from libntp, 386 * keeping in mind this function is called in forked children 387 * where it has already been called in the parent earlier. 388 * Forked children pass 0 for def_syslogmask. 389 */ 390 if (INIT_NTP_SYSLOGMASK == ntp_syslogmask && 391 0 != def_syslogmask) 392 ntp_syslogmask = def_syslogmask; /* set more via logconfig */ 393 394 /* 395 * Logging. This may actually work on the gizmo board. Find a name 396 * to log with by using the basename 397 */ 398 cp = strrchr(name, DIR_SEP); 399 if (NULL == cp) 400 pname = name; 401 else 402 pname = 1 + cp; /* skip DIR_SEP */ 403 progname = estrdup(pname); 404 #ifdef SYS_WINNT /* strip ".exe" */ 405 cp = strrchr(progname, '.'); 406 if (NULL != cp && !strcasecmp(cp, ".exe")) 407 progname[cp - progname] = '\0'; 408 #endif 409 410 #if !defined(VMS) 411 412 if (is_daemon) 413 was_daemon = TRUE; 414 # ifndef LOG_DAEMON 415 openlog(progname, LOG_PID); 416 # else /* LOG_DAEMON */ 417 418 # ifndef LOG_NTP 419 # define LOG_NTP LOG_DAEMON 420 # endif 421 openlog(progname, LOG_PID | LOG_NDELAY, (was_daemon) 422 ? LOG_NTP 423 : 0); 424 # ifdef DEBUG 425 if (debug) 426 setlogmask(LOG_UPTO(LOG_DEBUG)); 427 else 428 # endif /* DEBUG */ 429 setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */ 430 # endif /* LOG_DAEMON */ 431 #endif /* !VMS */ 432 } 433 434 435 /* 436 * change_logfile() 437 * 438 * Used to change from syslog to a logfile, or from one logfile to 439 * another, and to reopen logfiles after forking. On systems where 440 * ntpd forks, deals with converting relative logfile paths to 441 * absolute (root-based) because we reopen logfiles after the current 442 * directory has changed. 443 */ 444 int 445 change_logfile( 446 const char * fname, 447 int leave_crumbs 448 ) 449 { 450 FILE * new_file; 451 const char * log_fname; 452 char * abs_fname; 453 #if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS) 454 char curdir[512]; 455 size_t cd_octets; 456 size_t octets; 457 #endif /* POSIX */ 458 459 NTP_REQUIRE(fname != NULL); 460 log_fname = fname; 461 462 /* 463 * In a forked child of a parent which is logging to a file 464 * instead of syslog, syslog_file will be NULL and both 465 * syslog_fname and syslog_abs_fname will be non-NULL. 466 * If we are given the same filename previously opened 467 * and it's still open, there's nothing to do here. 468 */ 469 if (syslog_file != NULL && syslog_fname != NULL && 470 0 == strcmp(syslog_fname, log_fname)) 471 return 0; 472 473 if (0 == strcmp(log_fname, "stderr")) { 474 new_file = stderr; 475 abs_fname = estrdup(log_fname); 476 } else if (0 == strcmp(log_fname, "stdout")) { 477 new_file = stdout; 478 abs_fname = estrdup(log_fname); 479 } else { 480 if (syslog_fname != NULL && 481 0 == strcmp(log_fname, syslog_fname)) 482 log_fname = syslog_abs_fname; 483 #if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS) 484 if (log_fname != syslog_abs_fname && 485 DIR_SEP != log_fname[0] && 486 0 != strcmp(log_fname, "stderr") && 487 0 != strcmp(log_fname, "stdout") && 488 NULL != getcwd(curdir, sizeof(curdir))) { 489 cd_octets = strlen(curdir); 490 /* trim any trailing '/' */ 491 if (cd_octets > 1 && 492 DIR_SEP == curdir[cd_octets - 1]) 493 cd_octets--; 494 octets = cd_octets; 495 octets += 1; /* separator '/' */ 496 octets += strlen(log_fname); 497 octets += 1; /* NUL terminator */ 498 abs_fname = emalloc(octets); 499 snprintf(abs_fname, octets, "%.*s%c%s", 500 (int)cd_octets, curdir, DIR_SEP, 501 log_fname); 502 } else 503 #endif 504 abs_fname = estrdup(log_fname); 505 TRACE(1, ("attempting to open log %s\n", abs_fname)); 506 new_file = fopen(abs_fname, "a"); 507 } 508 509 if (NULL == new_file) { 510 free(abs_fname); 511 return -1; 512 } 513 514 /* leave a pointer in the old log */ 515 if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname)) 516 msyslog(LOG_NOTICE, "switching logging to file %s", 517 abs_fname); 518 519 if (syslog_file != NULL && 520 syslog_file != stderr && syslog_file != stdout && 521 fileno(syslog_file) != fileno(new_file)) 522 fclose(syslog_file); 523 syslog_file = new_file; 524 if (log_fname == syslog_abs_fname) { 525 free(abs_fname); 526 } else { 527 if (syslog_abs_fname != NULL && 528 syslog_abs_fname != syslog_fname) 529 free(syslog_abs_fname); 530 if (syslog_fname != NULL) 531 free(syslog_fname); 532 syslog_fname = estrdup(log_fname); 533 syslog_abs_fname = abs_fname; 534 } 535 syslogit = FALSE; 536 537 return 0; 538 } 539 540 541 /* 542 * setup_logfile() 543 * 544 * Redirect logging to a file if requested with -l/--logfile or via 545 * ntp.conf logfile directive. 546 * 547 * This routine is invoked three different times in the sequence of a 548 * typical daemon ntpd with DNS lookups to do. First it is invoked in 549 * the original ntpd process, then again in the daemon after closing 550 * all descriptors. In both of those cases, ntp.conf has not been 551 * processed, so only -l/--logfile will trigger logfile redirection in 552 * those invocations. Finally, if DNS names are resolved, the worker 553 * child invokes this routine after its fork and close of all 554 * descriptors. In this case, ntp.conf has been processed and any 555 * "logfile" directive needs to be honored in the child as well. 556 */ 557 void 558 setup_logfile( 559 const char * name 560 ) 561 { 562 if (NULL == syslog_fname && NULL != name) { 563 if (-1 == change_logfile(name, TRUE)) 564 msyslog(LOG_ERR, "Cannot open log file %s, %m", 565 name); 566 return ; 567 } 568 if (NULL == syslog_fname) 569 return; 570 571 if (-1 == change_logfile(syslog_fname, FALSE)) 572 msyslog(LOG_ERR, "Cannot reopen log file %s, %m", 573 syslog_fname); 574 } 575