Coverage Report

Created: 2026-08-13 06:49

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
2.29k
{
65
2.29k
  logh = cb;
66
2.29k
}
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
19.6k
{
155
19.6k
  if (logh) {
156
19.6k
    char *result = NULL;
157
19.6k
    if (vasprintf(&result, fmt, ap) != -1) {
158
19.6k
      logh(pri, result);
159
19.6k
      free(result);
160
19.6k
      return;
161
19.6k
    }
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
19.6k
  }
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. Format the caller's message
177
   * first so it is not re-interpreted as a format string by the
178
   * surrounding fprintf. */
179
0
  char *body = NULL;
180
0
  if (vasprintf(&body, fmt, ap) == -1) body = NULL;
181
0
  fprintf(stderr, "%s %s%s%s]%s %s\n", date(), translate(STDERR_FILENO, pri),
182
0
      token ? "/" : "", token ? token : "",
183
0
      isatty(STDERR_FILENO) ? "\033[0m" : "", body ? body : fmt);
184
0
  free(body);
185
0
  fflush(stderr);
186
0
}
187
188
void
189
log_warn(const char *token, const char *emsg, ...)
190
124
{
191
124
  char *nfmt = NULL;
192
124
  va_list ap;
193
194
  /* best effort to even work in out of memory situations */
195
124
  if (emsg == NULL)
196
0
    logit(LOG_WARNING, "%s", strerror(errno));
197
124
  else {
198
124
    va_start(ap, emsg);
199
200
124
    if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) {
201
      /* we tried it... */
202
0
      vlog(LOG_WARNING, token, emsg, ap);
203
0
      logit(LOG_WARNING, "%s", strerror(errno));
204
124
    } else {
205
124
      vlog(LOG_WARNING, token, nfmt, ap);
206
124
      free(nfmt);
207
124
    }
208
124
    va_end(ap);
209
124
  }
210
124
}
211
212
void
213
log_warnx(const char *token, const char *emsg, ...)
214
2.18k
{
215
2.18k
  va_list ap;
216
217
2.18k
  va_start(ap, emsg);
218
2.18k
  vlog(LOG_WARNING, token, emsg, ap);
219
2.18k
  va_end(ap);
220
2.18k
}
221
222
void
223
log_info(const char *token, const char *emsg, ...)
224
1.00k
{
225
1.00k
  va_list ap;
226
227
1.00k
  if (use_syslog || debug > 0 || logh) {
228
1.00k
    va_start(ap, emsg);
229
1.00k
    vlog(LOG_INFO, token, emsg, ap);
230
1.00k
    va_end(ap);
231
1.00k
  }
232
1.00k
}
233
234
static int
235
log_debug_accept_token(const char *token)
236
0
{
237
0
  int i;
238
0
  if (tokens[0] == NULL) return 1;
239
0
  for (i = 0; (i < MAX_DBG_TOKENS) && (tokens[i] != NULL); i++) {
240
0
    if (!strcmp(tokens[i], token)) return 1;
241
0
  }
242
0
  return 0;
243
0
}
244
245
void
246
log_debug(const char *token, const char *emsg, ...)
247
16.3k
{
248
16.3k
  va_list ap;
249
250
16.3k
  if ((debug > 1 && log_debug_accept_token(token)) || logh) {
251
16.3k
    va_start(ap, emsg);
252
16.3k
    vlog(LOG_DEBUG, token, emsg, ap);
253
16.3k
    va_end(ap);
254
16.3k
  }
255
16.3k
}
256
257
void
258
fatal(const char *token, const char *emsg)
259
0
{
260
0
  if (emsg == NULL)
261
0
    logit(LOG_CRIT, token ? token : "fatal", "%s", strerror(errno));
262
0
  else if (errno)
263
0
    logit(LOG_CRIT, token ? token : "fatal", "%s: %s", emsg,
264
0
        strerror(errno));
265
0
  else
266
0
    logit(LOG_CRIT, token ? token : "fatal", "%s", emsg);
267
268
0
  exit(1);
269
0
}
270
271
void
272
fatalx(const char *token, const char *emsg)
273
0
{
274
  errno = 0;
275
0
  fatal(token, emsg);
276
0
}