]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/libntp/msyslog.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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 *  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 }