Coverage Report

Created: 2026-02-26 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/lldpd/src/log.c
Line
Count
Source
1
/* -*- mode: c; c-file-style: "openbsd" -*- */
2
/*  $OpenBSD: log.c,v 1.11 2007/12/07 17:17:00 reyk Exp $ */
3
4
/*
5
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6
 *
7
 * Permission to use, copy, modify, and/or distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <unistd.h>
21
#include <stdio.h>
22
#include <stdlib.h>
23
#include <stdarg.h>
24
#include <syslog.h>
25
#include <sys/types.h>
26
#include <string.h>
27
#include <errno.h>
28
#include <time.h>
29
#include "log.h"
30
31
/* By default, logging is done on stderr. */
32
static int use_syslog = 0;
33
/* Default debug level */
34
static int debug = 0;
35
36
/* Logging can be modified by providing an appropriate log handler. */
37
static void (*logh)(int severity, const char *msg) = NULL;
38
39
static void vlog(int, const char *, const char *, va_list);
40
static void logit(int, const char *, const char *, ...);
41
42
0
#define MAX_DBG_TOKENS 40
43
static const char *tokens[MAX_DBG_TOKENS + 1] = { NULL };
44
45
void
46
log_init(int n_syslog, int n_debug, const char *progname)
47
0
{
48
0
  use_syslog = n_syslog;
49
0
  debug = n_debug;
50
51
0
  if (use_syslog) openlog(progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
52
53
0
  tzset();
54
0
}
55
56
void
57
log_level(int n_debug)
58
0
{
59
0
  if (n_debug >= 0) debug = n_debug;
60
0
}
61
62
void
63
log_register(void (*cb)(int, const char *))
64
133
{
65
133
  logh = cb;
66
133
}
67
68
void
69
log_accept(const char *token)
70
0
{
71
0
  int i;
72
0
  for (i = 0; i < MAX_DBG_TOKENS; i++) {
73
0
    if (tokens[i] == NULL) {
74
0
      tokens[i + 1] = NULL;
75
0
      tokens[i] = token;
76
0
      return;
77
0
    }
78
0
  }
79
0
}
80
81
static void
82
logit(int pri, const char *token, const char *fmt, ...)
83
0
{
84
0
  va_list ap;
85
86
0
  va_start(ap, fmt);
87
0
  vlog(pri, token, fmt, ap);
88
0
  va_end(ap);
89
0
}
90
91
static char *
92
date()
93
0
{
94
  /* Return the current date as incomplete ISO 8601 (2012-12-12T16:13:30) */
95
0
  static char date[] = "2012-12-12T16:13:30";
96
0
  time_t t = time(NULL);
97
0
  struct tm *tmp = localtime(&t);
98
0
  strftime(date, sizeof(date), "%Y-%m-%dT%H:%M:%S", tmp);
99
0
  return date;
100
0
}
101
102
static const char *
103
translate(int fd, int priority)
104
0
{
105
  /* Translate a syslog priority to a string. With colors if the output is a
106
   * terminal. */
107
0
  int tty = isatty(fd);
108
0
  switch (tty) {
109
0
  case 1:
110
0
    switch (priority) {
111
0
    case LOG_EMERG:
112
0
      return "\033[1;37;41m[EMRG";
113
0
    case LOG_ALERT:
114
0
      return "\033[1;37;41m[ALRT";
115
0
    case LOG_CRIT:
116
0
      return "\033[1;37;41m[CRIT";
117
0
    case LOG_ERR:
118
0
      return "\033[1;31m[ ERR";
119
0
    case LOG_WARNING:
120
0
      return "\033[1;33m[WARN";
121
0
    case LOG_NOTICE:
122
0
      return "\033[1;34m[NOTI";
123
0
    case LOG_INFO:
124
0
      return "\033[1;34m[INFO";
125
0
    case LOG_DEBUG:
126
0
      return "\033[36m[ DBG";
127
0
    }
128
0
    break;
129
0
  default:
130
0
    switch (priority) {
131
0
    case LOG_EMERG:
132
0
      return "[EMRG";
133
0
    case LOG_ALERT:
134
0
      return "[ALRT";
135
0
    case LOG_CRIT:
136
0
      return "[CRIT";
137
0
    case LOG_ERR:
138
0
      return "[ ERR";
139
0
    case LOG_WARNING:
140
0
      return "[WARN";
141
0
    case LOG_NOTICE:
142
0
      return "[NOTI";
143
0
    case LOG_INFO:
144
0
      return "[INFO";
145
0
    case LOG_DEBUG:
146
0
      return "[ DBG";
147
0
    }
148
0
  }
149
0
  return "[UNKN]";
150
0
}
151
152
static void
153
vlog(int pri, const char *token, const char *fmt, va_list ap)
154
483
{
155
483
  if (logh) {
156
483
    char *result = NULL;
157
483
    if (vasprintf(&result, fmt, ap) != -1) {
158
483
      logh(pri, result);
159
483
      free(result);
160
483
      return;
161
483
    }
162
    /* Otherwise, abort. We don't know if "ap" is still OK. We could
163
     * have made a copy, but this is too much overhead for a
164
     * situation that shouldn't happen. */
165
0
    return;
166
483
  }
167
168
  /* Log to syslog if requested */
169
0
  if (use_syslog) {
170
0
    va_list ap2;
171
0
    va_copy(ap2, ap);
172
0
    vsyslog(pri, fmt, ap2);
173
0
    va_end(ap2);
174
0
  }
175
176
  /* Log to standard error in all cases */
177
0
  char *nfmt;
178
  /* best effort in out of mem situations */
179
0
  if (asprintf(&nfmt, "%s %s%s%s]%s %s\n", date(), translate(STDERR_FILENO, pri),
180
0
    token ? "/" : "", token ? token : "",
181
0
    isatty(STDERR_FILENO) ? "\033[0m" : "", fmt) == -1) {
182
0
    vfprintf(stderr, fmt, ap);
183
0
    fprintf(stderr, "\n");
184
0
  } else {
185
0
    vfprintf(stderr, nfmt, ap);
186
0
    free(nfmt);
187
0
  }
188
0
  fflush(stderr);
189
0
}
190
191
void
192
log_warn(const char *token, const char *emsg, ...)
193
0
{
194
0
  char *nfmt = NULL;
195
0
  va_list ap;
196
197
  /* best effort to even work in out of memory situations */
198
0
  if (emsg == NULL)
199
0
    logit(LOG_WARNING, "%s", strerror(errno));
200
0
  else {
201
0
    va_start(ap, emsg);
202
203
0
    if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) {
204
      /* we tried it... */
205
0
      vlog(LOG_WARNING, token, emsg, ap);
206
0
      logit(LOG_WARNING, "%s", strerror(errno));
207
0
    } else {
208
0
      vlog(LOG_WARNING, token, nfmt, ap);
209
0
      free(nfmt);
210
0
    }
211
0
    va_end(ap);
212
0
  }
213
0
}
214
215
void
216
log_warnx(const char *token, const char *emsg, ...)
217
12
{
218
12
  va_list ap;
219
220
12
  va_start(ap, emsg);
221
12
  vlog(LOG_WARNING, token, emsg, ap);
222
12
  va_end(ap);
223
12
}
224
225
void
226
log_info(const char *token, const char *emsg, ...)
227
0
{
228
0
  va_list ap;
229
230
0
  if (use_syslog || debug > 0 || logh) {
231
0
    va_start(ap, emsg);
232
0
    vlog(LOG_INFO, token, emsg, ap);
233
0
    va_end(ap);
234
0
  }
235
0
}
236
237
static int
238
log_debug_accept_token(const char *token)
239
0
{
240
0
  int i;
241
0
  if (tokens[0] == NULL) return 1;
242
0
  for (i = 0; (i < MAX_DBG_TOKENS) && (tokens[i] != NULL); i++) {
243
0
    if (!strcmp(tokens[i], token)) return 1;
244
0
  }
245
0
  return 0;
246
0
}
247
248
void
249
log_debug(const char *token, const char *emsg, ...)
250
471
{
251
471
  va_list ap;
252
253
471
  if ((debug > 1 && log_debug_accept_token(token)) || logh) {
254
471
    va_start(ap, emsg);
255
471
    vlog(LOG_DEBUG, token, emsg, ap);
256
471
    va_end(ap);
257
471
  }
258
471
}
259
260
void
261
fatal(const char *token, const char *emsg)
262
0
{
263
0
  if (emsg == NULL)
264
0
    logit(LOG_CRIT, token ? token : "fatal", "%s", strerror(errno));
265
0
  else if (errno)
266
0
    logit(LOG_CRIT, token ? token : "fatal", "%s: %s", emsg,
267
0
        strerror(errno));
268
0
  else
269
0
    logit(LOG_CRIT, token ? token : "fatal", "%s", emsg);
270
271
0
  exit(1);
272
0
}
273
274
void
275
fatalx(const char *token, const char *emsg)
276
0
{
277
  errno = 0;
278
0
  fatal(token, emsg);
279
0
}