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