diff options
Diffstat (limited to 'contrib/ntp/libntp/msyslog.c')
-rw-r--r-- | contrib/ntp/libntp/msyslog.c | 616 |
1 files changed, 491 insertions, 125 deletions
diff --git a/contrib/ntp/libntp/msyslog.c b/contrib/ntp/libntp/msyslog.c index fe4d979e1267..283414d74423 100644 --- a/contrib/ntp/libntp/msyslog.c +++ b/contrib/ntp/libntp/msyslog.c @@ -9,198 +9,564 @@ # include <config.h> #endif -#ifdef HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif +#include <sys/types.h> #ifdef HAVE_UNISTD_H # include <unistd.h> #endif - #include <stdio.h> -#include "ntp_types.h" #include "ntp_string.h" +#include "ntp.h" +#include "ntp_debug.h" #include "ntp_syslog.h" -#include "ntp_stdlib.h" #ifdef SYS_WINNT # include <stdarg.h> # include "..\ports\winnt\libntp\messages.h" #endif -int syslogit = 1; -FILE *syslog_file = NULL; +int syslogit = TRUE; +int msyslog_term = FALSE; /* duplicate to stdout/err */ +int msyslog_term_pid = TRUE; +int msyslog_include_timestamp = TRUE; +FILE * syslog_file; +char * syslog_fname; +char * syslog_abs_fname; -u_long ntp_syslogmask = ~ (u_long) 0; +/* libntp default ntp_syslogmask is all bits lit */ +#define INIT_NTP_SYSLOGMASK ~(u_int32)0 +u_int32 ntp_syslogmask = INIT_NTP_SYSLOGMASK; -#ifdef SYS_WINNT -static char separator = '\\'; -#else -static char separator = '/'; -#endif /* SYS_WINNT */ -extern char *progname; +extern char * progname; /* Declare the local functions */ -void addto_syslog P((int, char *)); -void format_errmsg P((char *, int, const char *, int)); +void addto_syslog (int, const char *); +#ifndef VSNPRINTF_PERCENT_M +void format_errmsg (char *, size_t, const char *, int); - -/* - * This routine adds the contents of a buffer to the log - */ +/* format_errmsg() is under #ifndef VSNPRINTF_PERCENT_M above */ void -addto_syslog(int level, char * buf) +format_errmsg( + char * nfmt, + size_t lennfmt, + const char * fmt, + int errval + ) { - char *prog; - FILE *out_file = syslog_file; - -#if !defined(VMS) && !defined (SYS_VXWORKS) - if (syslogit) - syslog(level, "%s", buf); - else -#endif /* VMS && SYS_VXWORKS*/ - { - out_file = syslog_file ? syslog_file: level <= LOG_ERR ? stderr : stdout; - /* syslog() provides the timestamp, so if we're not using - syslog, we must provide it. */ - prog = strrchr(progname, separator); - if (prog == NULL) - prog = progname; - else - prog++; - (void) fprintf(out_file, "%s ", humanlogtime ()); - (void) fprintf(out_file, "%s[%d]: %s", prog, (int)getpid(), buf); - fflush (out_file); - } -#if DEBUG - if (debug && out_file != stdout && out_file != stderr) - printf("addto_syslog: %s\n", buf); -#endif -} -void -format_errmsg(char *nfmt, int lennfmt, const char *fmt, int errval) -{ - register char c; - register char *n; - register const char *f; - - char *err; + char errmsg[256]; + char c; + char *n; + const char *f; + size_t len; n = nfmt; f = fmt; - while ((c = *f++) != '\0' && n < (nfmt+lennfmt - 2)) { + while ((c = *f++) != '\0' && n < (nfmt + lennfmt - 1)) { if (c != '%') { *n++ = c; continue; } if ((c = *f++) != 'm') { *n++ = '%'; + if ('\0' == c) + break; *n++ = c; continue; } - err = 0; - err = strerror(errval); + errno_to_str(errval, errmsg, sizeof(errmsg)); + len = strlen(errmsg); + /* Make sure we have enough space for the error message */ - if ((n + strlen(err)) < (nfmt + lennfmt -2)) { - strcpy(n, err); - n += strlen(err); + if ((n + len) < (nfmt + lennfmt - 1)) { + memcpy(n, errmsg, len); + n += len; } } -#if !defined(VMS) - if (!syslogit) -#endif /* VMS */ - *n++ = '\n'; *n = '\0'; } +#endif /* VSNPRINTF_PERCENT_M */ + /* - * The externally called functions are defined here - * but share the internal function above to fetch - * any error message strings, This is done so that we can - * have two different functions to perform the logging - * since Windows gets it's error information from different - * places depending on whether or not it's network I/O. - * msyslog() is for general use while netsyslog() is for - * network I/O functions. They are virtually identical - * in implementation. + * errno_to_str() - a thread-safe strerror() replacement. + * Hides the varied signatures of strerror_r(). + * For Windows, we have: + * #define errno_to_str isc_strerror */ +#ifndef errno_to_str +void +errno_to_str( + int err, + char * buf, + size_t bufsiz + ) +{ +# if defined(STRERROR_R_CHAR_P) || !HAVE_DECL_STRERROR_R + char * pstatic; -#if defined(__STDC__) || defined(HAVE_STDARG_H) -void msyslog(int level, const char *fmt, ...) -#else /* defined(__STDC__) || defined(HAVE_STDARG_H) */ - /*VARARGS*/ - void msyslog(va_alist) - va_dcl -#endif /* defined(__STDC__) || defined(HAVE_STDARG_H) */ + buf[0] = '\0'; +# ifdef STRERROR_R_CHAR_P + pstatic = strerror_r(err, buf, bufsiz); +# else + pstatic = strerror(err); +# endif + if (NULL == pstatic && '\0' == buf[0]) + snprintf(buf, bufsiz, "%s(%d): errno %d", +# ifdef STRERROR_R_CHAR_P + "strerror_r", +# else + "strerror", +# endif + err, errno); + /* protect against believing an int return is a pointer */ + else if (pstatic != buf && pstatic > (char *)bufsiz) + strlcpy(buf, pstatic, bufsiz); +# else + int rc; + + rc = strerror_r(err, buf, bufsiz); + if (rc < 0) + snprintf(buf, bufsiz, "strerror_r(%d): errno %d", + err, errno); +# endif +} +#endif /* errno_to_str */ + + +/* + * addto_syslog() + * This routine adds the contents of a buffer to the syslog or an + * application-specific logfile. + */ +void +addto_syslog( + int level, + const char * msg + ) { -#if defined(__STDC__) || defined(HAVE_STDARG_H) + static char * prevcall_progname; + static char * prog; + const char nl[] = "\n"; + const char empty[] = ""; + FILE * term_file; + int log_to_term; + int log_to_file; + int pid; + const char * nl_or_empty; + const char * human_time; + + /* setup program basename static var prog if needed */ + if (progname != prevcall_progname) { + prevcall_progname = progname; + prog = strrchr(progname, DIR_SEP); + if (prog != NULL) + prog++; + else + prog = progname; + } + + log_to_term = msyslog_term; + log_to_file = FALSE; +#if !defined(VMS) && !defined(SYS_VXWORKS) + if (syslogit) + syslog(level, "%s", msg); + else +#endif + if (syslog_file != NULL) + log_to_file = TRUE; + else + log_to_term = TRUE; +#if DEBUG + if (debug > 0) + log_to_term = TRUE; +#endif + if (!(log_to_file || log_to_term)) + return; + + /* syslog() adds the timestamp, name, and pid */ + if (msyslog_include_timestamp) + human_time = humanlogtime(); + else /* suppress gcc pot. uninit. warning */ + human_time = NULL; + if (msyslog_term_pid || log_to_file) + pid = getpid(); + else /* suppress gcc pot. uninit. warning */ + pid = -1; + + /* syslog() adds trailing \n if not present */ + if ('\n' != msg[strlen(msg) - 1]) + nl_or_empty = nl; + else + nl_or_empty = empty; + + if (log_to_term) { + term_file = (level <= LOG_ERR) + ? stderr + : stdout; + if (msyslog_include_timestamp) + fprintf(term_file, "%s ", human_time); + if (msyslog_term_pid) + fprintf(term_file, "%s[%d]: ", prog, pid); + fprintf(term_file, "%s%s", msg, nl_or_empty); + fflush(term_file); + } + + if (log_to_file) { + if (msyslog_include_timestamp) + fprintf(syslog_file, "%s ", human_time); + fprintf(syslog_file, "%s[%d]: %s%s", prog, pid, msg, + nl_or_empty); + fflush(syslog_file); + } +} + + +int +mvsnprintf( + char * buf, + size_t bufsiz, + const char * fmt, + va_list ap + ) +{ +#ifndef VSNPRINTF_PERCENT_M + char nfmt[256]; #else - int level; - const char *fmt; + const char * nfmt = fmt; #endif - va_list ap; - char buf[1025], nfmt[256]; + int errval; /* * Save the error value as soon as possible */ #ifdef SYS_WINNT - int errval = GetLastError(); -#else - int errval = errno; -#endif + errval = GetLastError(); + if (NO_ERROR == errval) +#endif /* SYS_WINNT */ + errval = errno; -#if defined(__STDC__) || defined(HAVE_STDARG_H) - va_start(ap, fmt); +#ifndef VSNPRINTF_PERCENT_M + format_errmsg(nfmt, sizeof(nfmt), fmt, errval); #else - va_start(ap); - - level = va_arg(ap, int); - fmt = va_arg(ap, char *); + errno = errval; #endif - format_errmsg(nfmt, sizeof(nfmt), fmt, errval); - - vsnprintf(buf, sizeof(buf), nfmt, ap); - addto_syslog(level, buf); - va_end(ap); + return vsnprintf(buf, bufsiz, nfmt, ap); } -#if defined(__STDC__) || defined(HAVE_STDARG_H) -void netsyslog(int level, const char *fmt, ...) -#else /* defined(__STDC__) || defined(HAVE_STDARG_H) */ - /*VARARGS*/ - void netsyslog(va_alist) - va_dcl -#endif /* defined(__STDC__) || defined(HAVE_STDARG_H) */ + + +int +mvfprintf( + FILE * fp, + const char * fmt, + va_list ap + ) { -#if defined(__STDC__) || defined(HAVE_STDARG_H) +#ifndef VSNPRINTF_PERCENT_M + char nfmt[256]; #else - int level; - const char *fmt; + const char * nfmt = fmt; #endif - va_list ap; - char buf[1025], nfmt[256]; + int errval; /* * Save the error value as soon as possible */ #ifdef SYS_WINNT - int errval = WSAGetLastError(); + errval = GetLastError(); + if (NO_ERROR == errval) +#endif /* SYS_WINNT */ + errval = errno; + +#ifndef VSNPRINTF_PERCENT_M + format_errmsg(nfmt, sizeof(nfmt), fmt, errval); #else - int errval = errno; + errno = errval; #endif + return vfprintf(fp, nfmt, ap); +} + + +int +mfprintf( + FILE * fp, + const char * fmt, + ... + ) +{ + va_list ap; + int rc; -#if defined(__STDC__) || defined(HAVE_STDARG_H) va_start(ap, fmt); -#else - va_start(ap); + rc = mvfprintf(fp, fmt, ap); + va_end(ap); - level = va_arg(ap, int); - fmt = va_arg(ap, char *); -#endif - format_errmsg(nfmt, sizeof(nfmt), fmt, errval); + return rc; +} - vsnprintf(buf, sizeof(buf), nfmt, ap); - addto_syslog(level, buf); + +int +mprintf( + const char * fmt, + ... + ) +{ + va_list ap; + int rc; + + va_start(ap, fmt); + rc = mvfprintf(stdout, fmt, ap); + va_end(ap); + + return rc; +} + + +int +msnprintf( + char * buf, + size_t bufsiz, + const char * fmt, + ... + ) +{ + va_list ap; + size_t rc; + + va_start(ap, fmt); + rc = mvsnprintf(buf, bufsiz, fmt, ap); + va_end(ap); + + return rc; +} + + +void +msyslog( + int level, + const char * fmt, + ... + ) +{ + char buf[1024]; + va_list ap; + + va_start(ap, fmt); + mvsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); + addto_syslog(level, buf); +} + + +/* + * Initialize the logging + * + * Called once per process, including forked children. + */ +void +init_logging( + const char * name, + u_int32 def_syslogmask, + int is_daemon + ) +{ + static int was_daemon; + const char * cp; + const char * pname; + + /* + * ntpd defaults to only logging sync-category events, when + * NLOG() is used to conditionalize. Other libntp clients + * leave it alone so that all NLOG() conditionals will fire. + * This presumes all bits lit in ntp_syslogmask can't be + * configured via logconfig and all lit is thereby a sentinel + * that ntp_syslogmask is still at its default from libntp, + * keeping in mind this function is called in forked children + * where it has already been called in the parent earlier. + * Forked children pass 0 for def_syslogmask. + */ + if (INIT_NTP_SYSLOGMASK == ntp_syslogmask && + 0 != def_syslogmask) + ntp_syslogmask = def_syslogmask; /* set more via logconfig */ + + /* + * Logging. This may actually work on the gizmo board. Find a name + * to log with by using the basename + */ + cp = strrchr(name, DIR_SEP); + if (NULL == cp) + pname = name; + else + pname = 1 + cp; /* skip DIR_SEP */ + progname = estrdup(pname); +#ifdef SYS_WINNT /* strip ".exe" */ + cp = strrchr(progname, '.'); + if (NULL != cp && !strcasecmp(cp, ".exe")) + progname[cp - progname] = '\0'; +#endif + +#if !defined(VMS) + + if (is_daemon) + was_daemon = TRUE; +# ifndef LOG_DAEMON + openlog(progname, LOG_PID); +# else /* LOG_DAEMON */ + +# ifndef LOG_NTP +# define LOG_NTP LOG_DAEMON +# endif + openlog(progname, LOG_PID | LOG_NDELAY, (was_daemon) + ? LOG_NTP + : 0); +# ifdef DEBUG + if (debug) + setlogmask(LOG_UPTO(LOG_DEBUG)); + else +# endif /* DEBUG */ + setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */ +# endif /* LOG_DAEMON */ +#endif /* !VMS */ +} + + +/* + * change_logfile() + * + * Used to change from syslog to a logfile, or from one logfile to + * another, and to reopen logfiles after forking. On systems where + * ntpd forks, deals with converting relative logfile paths to + * absolute (root-based) because we reopen logfiles after the current + * directory has changed. + */ +int +change_logfile( + const char * fname, + int leave_crumbs + ) +{ + FILE * new_file; + const char * log_fname; + char * abs_fname; +#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS) + char curdir[512]; + size_t cd_octets; + size_t octets; +#endif /* POSIX */ + + NTP_REQUIRE(fname != NULL); + log_fname = fname; + + /* + * In a forked child of a parent which is logging to a file + * instead of syslog, syslog_file will be NULL and both + * syslog_fname and syslog_abs_fname will be non-NULL. + * If we are given the same filename previously opened + * and it's still open, there's nothing to do here. + */ + if (syslog_file != NULL && syslog_fname != NULL && + 0 == strcmp(syslog_fname, log_fname)) + return 0; + + if (0 == strcmp(log_fname, "stderr")) { + new_file = stderr; + abs_fname = estrdup(log_fname); + } else if (0 == strcmp(log_fname, "stdout")) { + new_file = stdout; + abs_fname = estrdup(log_fname); + } else { + if (syslog_fname != NULL && + 0 == strcmp(log_fname, syslog_fname)) + log_fname = syslog_abs_fname; +#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS) + if (log_fname != syslog_abs_fname && + DIR_SEP != log_fname[0] && + 0 != strcmp(log_fname, "stderr") && + 0 != strcmp(log_fname, "stdout") && + NULL != getcwd(curdir, sizeof(curdir))) { + cd_octets = strlen(curdir); + /* trim any trailing '/' */ + if (cd_octets > 1 && + DIR_SEP == curdir[cd_octets - 1]) + cd_octets--; + octets = cd_octets; + octets += 1; /* separator '/' */ + octets += strlen(log_fname); + octets += 1; /* NUL terminator */ + abs_fname = emalloc(octets); + snprintf(abs_fname, octets, "%.*s%c%s", + (int)cd_octets, curdir, DIR_SEP, + log_fname); + } else +#endif + abs_fname = estrdup(log_fname); + TRACE(1, ("attempting to open log %s\n", abs_fname)); + new_file = fopen(abs_fname, "a"); + } + + if (NULL == new_file) { + free(abs_fname); + return -1; + } + + /* leave a pointer in the old log */ + if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname)) + msyslog(LOG_NOTICE, "switching logging to file %s", + abs_fname); + + if (syslog_file != NULL && + syslog_file != stderr && syslog_file != stdout && + fileno(syslog_file) != fileno(new_file)) + fclose(syslog_file); + syslog_file = new_file; + if (log_fname == syslog_abs_fname) { + free(abs_fname); + } else { + if (syslog_abs_fname != NULL && + syslog_abs_fname != syslog_fname) + free(syslog_abs_fname); + if (syslog_fname != NULL) + free(syslog_fname); + syslog_fname = estrdup(log_fname); + syslog_abs_fname = abs_fname; + } + syslogit = FALSE; + + return 0; +} + + +/* + * setup_logfile() + * + * Redirect logging to a file if requested with -l/--logfile or via + * ntp.conf logfile directive. + * + * This routine is invoked three different times in the sequence of a + * typical daemon ntpd with DNS lookups to do. First it is invoked in + * the original ntpd process, then again in the daemon after closing + * all descriptors. In both of those cases, ntp.conf has not been + * processed, so only -l/--logfile will trigger logfile redirection in + * those invocations. Finally, if DNS names are resolved, the worker + * child invokes this routine after its fork and close of all + * descriptors. In this case, ntp.conf has been processed and any + * "logfile" directive needs to be honored in the child as well. + */ +void +setup_logfile( + const char * name + ) +{ + if (NULL == syslog_fname && NULL != name) { + if (-1 == change_logfile(name, TRUE)) + msyslog(LOG_ERR, "Cannot open log file %s, %m", + name); + return ; + } + if (NULL == syslog_fname) + return; + + if (-1 == change_logfile(syslog_fname, FALSE)) + msyslog(LOG_ERR, "Cannot reopen log file %s, %m", + syslog_fname); } |