Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/libntp/msyslog.c
Line
Count
Source (jump to first uncovered line)
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
0
#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
0
{
105
0
# if defined(STRERROR_R_CHAR_P) || !HAVE_DECL_STRERROR_R
106
0
  char *  pstatic;
107
108
0
  buf[0] = '\0';
109
0
#  ifdef STRERROR_R_CHAR_P
110
0
  pstatic = strerror_r(err, buf, bufsiz);
111
#  else
112
  pstatic = strerror(err);
113
#  endif
114
0
  if (NULL == pstatic && '\0' == buf[0])
115
0
    snprintf(buf, bufsiz, "%s(%d): errno %d",
116
0
#  ifdef STRERROR_R_CHAR_P
117
0
       "strerror_r",
118
#  else
119
       "strerror",
120
#  endif
121
0
       err, errno);
122
  /* protect against believing an int return is a pointer */
123
0
  else if (pstatic != buf && pstatic > (char *)bufsiz)
124
0
    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
0
}
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
96
{
148
96
  static char const * prevcall_progname;
149
96
  static char const * prog;
150
96
  const char  nl[] = "\n";
151
96
  const char  empty[] = "";
152
96
  FILE *    term_file;
153
96
  int   log_to_term;
154
96
  int   log_to_file;
155
96
  int   pid;
156
96
  const char *  nl_or_empty;
157
96
  const char *  human_time;
158
159
  /* setup program basename static var prog if needed */
160
96
  if (progname != prevcall_progname) {
161
1
    prevcall_progname = progname;
162
1
    prog = strrchr(progname, DIR_SEP);
163
1
    if (prog != NULL)
164
0
      prog++;
165
1
    else
166
1
      prog = progname;
167
1
  }
168
169
96
  log_to_term = msyslog_term;
170
96
  log_to_file = FALSE;
171
96
#if !defined(VMS) && !defined(SYS_VXWORKS)
172
96
  if (syslogit)
173
96
    syslog(level, "%s", msg);
174
0
  else
175
0
#endif
176
0
    if (syslog_file != NULL)
177
0
      log_to_file = TRUE;
178
0
    else
179
0
      log_to_term = TRUE;
180
96
#if DEBUG
181
96
  if (debug > 0)
182
0
    log_to_term = TRUE;
183
96
#endif
184
96
  if (!(log_to_file || log_to_term))
185
96
    return;
186
187
  /* syslog() adds the timestamp, name, and pid */
188
0
  if (msyslog_include_timestamp)
189
0
    human_time = humanlogtime();
190
0
  else  /* suppress gcc pot. uninit. warning */
191
0
    human_time = NULL;
192
0
  if (msyslog_term_pid || log_to_file)
193
0
    pid = getpid();
194
0
  else  /* suppress gcc pot. uninit. warning */
195
0
    pid = -1;
196
197
  /* syslog() adds trailing \n if not present */
198
0
  if ('\n' != msg[strlen(msg) - 1])
199
0
    nl_or_empty = nl;
200
0
  else
201
0
    nl_or_empty = empty;
202
203
0
  if (log_to_term) {
204
0
    term_file = (level <= LOG_ERR)
205
0
        ? stderr
206
0
        : stdout;
207
0
    if (msyslog_include_timestamp)
208
0
      fprintf(term_file, "%s ", human_time);
209
0
    if (msyslog_term_pid)
210
0
      fprintf(term_file, "%s[%d]: ", prog, pid);
211
0
    fprintf(term_file, "%s%s", msg, nl_or_empty);
212
0
    fflush(term_file);
213
0
  }
214
215
0
  if (log_to_file) {
216
0
    if (msyslog_include_timestamp)
217
0
      fprintf(syslog_file, "%s ", human_time);
218
0
    fprintf(syslog_file, "%s[%d]: %s%s", prog, pid, msg,
219
0
      nl_or_empty);
220
0
    fflush(syslog_file);
221
0
  }
222
0
}
223
224
225
int
226
mvsnprintf(
227
  char *    buf,
228
  size_t    bufsiz,
229
  const char *  fmt,
230
  va_list   ap
231
  )
232
96
{
233
#ifndef VSNPRINTF_PERCENT_M
234
  char    nfmt[256];
235
#else
236
96
  const char *  nfmt = fmt;
237
96
#endif
238
96
  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
96
    errval = errno;
248
249
#ifndef VSNPRINTF_PERCENT_M
250
  format_errmsg(nfmt, sizeof(nfmt), fmt, errval);
251
#else
252
96
  errno = errval;
253
96
#endif
254
96
  return vsnprintf(buf, bufsiz, nfmt, ap);
255
96
}
256
257
258
int
259
mvfprintf(
260
  FILE *    fp,
261
  const char *  fmt,
262
  va_list   ap
263
  )
264
0
{
265
#ifndef VSNPRINTF_PERCENT_M
266
  char    nfmt[256];
267
#else
268
0
  const char *  nfmt = fmt;
269
0
#endif
270
0
  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
0
    errval = errno;
280
281
#ifndef VSNPRINTF_PERCENT_M
282
  format_errmsg(nfmt, sizeof(nfmt), fmt, errval);
283
#else
284
0
  errno = errval;
285
0
#endif
286
0
  return vfprintf(fp, nfmt, ap);
287
0
}
288
289
290
int
291
mfprintf(
292
  FILE *    fp,
293
  const char *  fmt,
294
  ...
295
  )
296
0
{
297
0
  va_list   ap;
298
0
  int   rc;
299
300
0
  va_start(ap, fmt);
301
0
  rc = mvfprintf(fp, fmt, ap);
302
0
  va_end(ap);
303
304
0
  return rc;
305
0
}
306
307
308
int
309
mprintf(
310
  const char *  fmt,
311
  ...
312
  )
313
0
{
314
0
  va_list   ap;
315
0
  int   rc;
316
317
0
  va_start(ap, fmt);
318
0
  rc = mvfprintf(stdout, fmt, ap);
319
0
  va_end(ap);
320
321
0
  return rc;
322
0
}
323
324
325
int
326
msnprintf(
327
  char *    buf,
328
  size_t    bufsiz,
329
  const char *  fmt,
330
  ...
331
  )
332
0
{
333
0
  va_list ap;
334
0
  int rc;
335
336
0
  va_start(ap, fmt);
337
0
  rc = mvsnprintf(buf, bufsiz, fmt, ap);
338
0
  va_end(ap);
339
340
0
  return rc;
341
0
}
342
343
344
void
345
msyslog(
346
  int   level,
347
  const char *  fmt,
348
  ...
349
  )
350
96
{
351
96
  char  buf[1024];
352
96
  va_list ap;
353
354
96
  va_start(ap, fmt);
355
96
  mvsnprintf(buf, sizeof(buf), fmt, ap);
356
96
  va_end(ap);
357
96
  addto_syslog(level, buf);
358
96
}
359
360
void
361
mvsyslog(
362
  int   level,
363
  const char *  fmt,
364
  va_list   ap
365
  )
366
0
{
367
0
  char  buf[1024];
368
0
  mvsnprintf(buf, sizeof(buf), fmt, ap);
369
0
  addto_syslog(level, buf);
370
0
}
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
0
{
385
0
  static int  was_daemon;
386
0
  char *    cp;
387
0
  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
0
  if (INIT_NTP_SYSLOGMASK == ntp_syslogmask &&
401
0
      0 != def_syslogmask)
402
0
    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
0
  cp = strrchr(name, DIR_SEP);
409
0
  if (NULL == cp)
410
0
    pname = name;
411
0
  else
412
0
    pname = 1 + cp; /* skip DIR_SEP */
413
0
  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
0
#if !defined(VMS)
421
422
0
  if (is_daemon)
423
0
    was_daemon = TRUE;
424
# ifndef LOG_DAEMON
425
  openlog(progname, LOG_PID);
426
# else /* LOG_DAEMON */
427
428
0
#  ifndef LOG_NTP
429
0
# define  LOG_NTP LOG_DAEMON
430
0
#  endif
431
0
  openlog(progname, LOG_PID | LOG_NDELAY, (was_daemon) 
432
0
                ? LOG_NTP
433
0
                : 0);
434
0
#  ifdef DEBUG
435
0
  if (debug)
436
0
    setlogmask(LOG_UPTO(LOG_DEBUG));
437
0
  else
438
0
#  endif /* DEBUG */
439
0
    setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
440
0
# endif /* LOG_DAEMON */
441
0
#endif  /* !VMS */
442
0
}
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
0
{
460
0
  FILE *    new_file;
461
0
  const char *  log_fname;
462
0
  char *    abs_fname;
463
0
#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
464
0
  char    curdir[512];
465
0
  size_t    cd_octets;
466
0
  size_t    octets;
467
0
#endif  /* POSIX */
468
469
0
  REQUIRE(fname != NULL);
470
0
  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
0
  if (syslog_file != NULL && syslog_fname != NULL &&
480
0
      0 == strcmp(syslog_fname, log_fname))
481
0
    return 0;
482
483
0
  if (0 == strcmp(log_fname, "stderr")) {
484
0
    new_file = stderr;
485
0
    abs_fname = estrdup(log_fname);
486
0
  } else if (0 == strcmp(log_fname, "stdout")) {
487
0
    new_file = stdout;
488
0
    abs_fname = estrdup(log_fname);
489
0
  } else {
490
0
    if (syslog_fname != NULL &&
491
0
        0 == strcmp(log_fname, syslog_fname))
492
0
      log_fname = syslog_abs_fname;
493
0
#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
494
0
    if (log_fname != syslog_abs_fname &&
495
0
        DIR_SEP != log_fname[0] &&
496
0
        0 != strcmp(log_fname, "stderr") &&
497
0
        0 != strcmp(log_fname, "stdout") &&
498
0
        NULL != getcwd(curdir, sizeof(curdir))) {
499
0
      cd_octets = strlen(curdir);
500
      /* trim any trailing '/' */
501
0
      if (cd_octets > 1 &&
502
0
          DIR_SEP == curdir[cd_octets - 1])
503
0
        cd_octets--;
504
0
      octets = cd_octets;
505
0
      octets += 1;  /* separator '/' */
506
0
      octets += strlen(log_fname);
507
0
      octets += 1;  /* NUL terminator */
508
0
      abs_fname = emalloc(octets);
509
0
      snprintf(abs_fname, octets, "%.*s%c%s",
510
0
         (int)cd_octets, curdir, DIR_SEP,
511
0
         log_fname);
512
0
    } else
513
0
#endif
514
0
      abs_fname = estrdup(log_fname);
515
0
    TRACE(1, ("attempting to open log %s\n", abs_fname));
516
0
    new_file = fopen(abs_fname, "a");
517
0
  }
518
519
0
  if (NULL == new_file) {
520
0
    free(abs_fname);
521
0
    return -1;
522
0
  }
523
524
  /* leave a pointer in the old log */
525
0
  if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname))
526
0
    msyslog(LOG_NOTICE, "switching logging to file %s",
527
0
      abs_fname);
528
529
0
  if (syslog_file != NULL &&
530
0
      syslog_file != stderr && syslog_file != stdout &&
531
0
      fileno(syslog_file) != fileno(new_file))
532
0
    fclose(syslog_file);
533
0
  syslog_file = new_file;
534
0
  if (log_fname == syslog_abs_fname) {
535
0
    free(abs_fname);
536
0
  } else {
537
0
    if (syslog_abs_fname != NULL &&
538
0
        syslog_abs_fname != syslog_fname)
539
0
      free(syslog_abs_fname);
540
0
    if (syslog_fname != NULL)
541
0
      free(syslog_fname);
542
0
    syslog_fname = estrdup(log_fname);
543
0
    syslog_abs_fname = abs_fname;
544
0
  }
545
0
  syslogit = FALSE;
546
547
0
  return 0;
548
0
}
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
0
{
572
0
  if (NULL == syslog_fname && NULL != name) {
573
0
    if (-1 == change_logfile(name, TRUE))
574
0
      msyslog(LOG_ERR, "Cannot open log file %s, %m",
575
0
        name);
576
0
    return ;
577
0
  } 
578
0
  if (NULL == syslog_fname)
579
0
    return;
580
581
0
  if (-1 == change_logfile(syslog_fname, FALSE))
582
0
    msyslog(LOG_ERR, "Cannot reopen log file %s, %m",
583
0
      syslog_fname);
584
0
}