Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / log.c @ 4a591d4b

History | View | Annotate | Download (6.78 KB)

1 6032aa6a Martin Mares
/*
2
 *        BIRD Library -- Logging Functions
3
 *
4 73275d85 Martin Mares
 *        (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 6032aa6a Martin Mares
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8
9 73275d85 Martin Mares
/**
10
 * DOC: Logging
11
 *
12
 * The Logging module offers a simple set of functions for writing
13 725270cb Martin Mares
 * messages to system logs and to the debug output. Message classes
14
 * used by this module are described in |birdlib.h| and also in the
15
 * user's manual.
16 73275d85 Martin Mares
 */
17
18 6032aa6a Martin Mares
#include <stdio.h>
19
#include <stdlib.h>
20
#include <stdarg.h>
21 01b776e1 Martin Mares
#include <time.h>
22 e81b440f Ondrej Zajicek
#include <unistd.h>
23 6032aa6a Martin Mares
24
#include "nest/bird.h"
25 34350a52 Martin Mares
#include "nest/cli.h"
26 cf31112f Ondrej Zajicek
#include "nest/mrtdump.h"
27 9556f225 Martin Mares
#include "lib/string.h"
28 a0c37b45 Martin Mares
#include "lib/lists.h"
29
#include "lib/unix.h"
30 6032aa6a Martin Mares
31 44d4ab7a Ondrej Zajicek
static FILE *dbgf;
32 a0c37b45 Martin Mares
static list *current_log_list;
33 44d4ab7a Ondrej Zajicek
static char *current_syslog_name; /* NULL -> syslog closed */
34 6032aa6a Martin Mares
35 0e175f9f Ondrej Zajicek
36 1ec52253 Ondrej Zajicek
#ifdef USE_PTHREADS
37 0e175f9f Ondrej Zajicek
38
#include <pthread.h>
39 4e398e34 Ondrej Zajicek
40 0e175f9f Ondrej Zajicek
static pthread_mutex_t log_mutex;
41
static inline void log_lock(void) { pthread_mutex_lock(&log_mutex); }
42
static inline void log_unlock(void) { pthread_mutex_unlock(&log_mutex); }
43
44 4e398e34 Ondrej Zajicek
static pthread_t main_thread;
45
void main_thread_init(void) { main_thread = pthread_self(); }
46
static int main_thread_self(void) { return pthread_equal(pthread_self(), main_thread); }
47
48 1ec52253 Ondrej Zajicek
#else
49
50
static inline void log_lock(void) {  }
51
static inline void log_unlock(void) {  }
52 4e398e34 Ondrej Zajicek
void main_thread_init(void) { }
53
static int main_thread_self(void) { return 1; }
54 1ec52253 Ondrej Zajicek
55
#endif
56
57 cb530392 Ondrej Zajicek
58 6032aa6a Martin Mares
#ifdef HAVE_SYSLOG
59
#include <sys/syslog.h>
60
61
static int syslog_priorities[] = {
62 a0c37b45 Martin Mares
  LOG_DEBUG,
63
  LOG_DEBUG,
64 6032aa6a Martin Mares
  LOG_DEBUG,
65
  LOG_INFO,
66 a0c37b45 Martin Mares
  LOG_ERR,
67 6032aa6a Martin Mares
  LOG_WARNING,
68
  LOG_ERR,
69 a0c37b45 Martin Mares
  LOG_ERR,
70
  LOG_CRIT,
71 6032aa6a Martin Mares
  LOG_CRIT
72
};
73
#endif
74
75
static char *class_names[] = {
76
  "???",
77
  "DBG",
78 a0c37b45 Martin Mares
  "TRACE",
79 6032aa6a Martin Mares
  "INFO",
80 a0c37b45 Martin Mares
  "RMT",
81 6032aa6a Martin Mares
  "WARN",
82
  "ERR",
83
  "AUTH",
84 a0c37b45 Martin Mares
  "FATAL",
85
  "BUG"
86 6032aa6a Martin Mares
};
87
88 9556f225 Martin Mares
89 0d1b3c4c Ondrej Zajicek
/**
90
 * log_commit - commit a log message
91
 * @class: message class information (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
92
 *
93
 * This function writes a message prepared in the log buffer to the
94
 * log file (as specified in the configuration). The log buffer is
95
 * reset after that. The log message is a full line, log_commit()
96
 * terminates it.
97
 *
98
 * The message class is an integer, not a first char of a string like
99
 * in log(), so it should be written like *L_INFO.
100
 */
101
void
102 0e175f9f Ondrej Zajicek
log_commit(int class, buffer *buf)
103 0d1b3c4c Ondrej Zajicek
{
104
  struct log_config *l;
105 9556f225 Martin Mares
106 0e175f9f Ondrej Zajicek
  if (buf->pos == buf->end)
107
    strcpy(buf->end - 100, " ... <too long>");
108
109
  log_lock();
110 a0c37b45 Martin Mares
  WALK_LIST(l, *current_log_list)
111 6032aa6a Martin Mares
    {
112 a0c37b45 Martin Mares
      if (!(l->mask & (1 << class)))
113
        continue;
114
      if (l->fh)
115
        {
116
          if (l->terminal_flag)
117
            fputs("bird: ", l->fh);
118
          else
119
            {
120 c37e7851 Ondrej Zajicek
              byte tbuf[TM_DATETIME_BUFFER_SIZE];
121
              tm_format_datetime(tbuf, &config->tf_log, now);
122
              fprintf(l->fh, "%s <%s> ", tbuf, class_names[class]);
123 a0c37b45 Martin Mares
            }
124 0e175f9f Ondrej Zajicek
          fputs(buf->start, l->fh);
125 a0c37b45 Martin Mares
          fputc('\n', l->fh);
126
          fflush(l->fh);
127
        }
128 6032aa6a Martin Mares
#ifdef HAVE_SYSLOG
129 a0c37b45 Martin Mares
      else
130 0e175f9f Ondrej Zajicek
        syslog(syslog_priorities[class], "%s", buf->start);
131 6032aa6a Martin Mares
#endif
132
    }
133 0e175f9f Ondrej Zajicek
  log_unlock();
134 0d1b3c4c Ondrej Zajicek
135 4e398e34 Ondrej Zajicek
  /* cli_echo is not thread-safe, so call it just from the main thread */
136
  if (main_thread_self())
137
    cli_echo(class, buf->start);
138 56027b5c Ondrej Zajicek
139
  buf->pos = buf->start;
140 0d1b3c4c Ondrej Zajicek
}
141
142 0e175f9f Ondrej Zajicek
int buffer_vprint(buffer *buf, const char *fmt, va_list args);
143 0d1b3c4c Ondrej Zajicek
144
static void
145
vlog(int class, const char *msg, va_list args)
146
{
147 0e175f9f Ondrej Zajicek
  buffer buf;
148
  LOG_BUFFER_INIT(buf);
149
  buffer_vprint(&buf, msg, args);
150
  log_commit(class, &buf);
151 0d1b3c4c Ondrej Zajicek
}
152
153
154 73275d85 Martin Mares
/**
155
 * log - log a message
156
 * @msg: printf-like formatting string with message class information
157
 * prepended (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
158
 *
159
 * This function formats a message according to the format string @msg
160 2e9b2421 Martin Mares
 * and writes it to the corresponding log file (as specified in the
161 73275d85 Martin Mares
 * configuration). Please note that the message is automatically
162
 * formatted as a full line, no need to include |\n| inside.
163 0d1b3c4c Ondrej Zajicek
 * It is essentially a sequence of log_reset(), logn() and log_commit().
164 73275d85 Martin Mares
 */
165 6032aa6a Martin Mares
void
166 e98bc2ea Martin Mares
log_msg(char *msg, ...)
167 6032aa6a Martin Mares
{
168
  int class = 1;
169
  va_list args;
170
171
  va_start(args, msg);
172 98e87c86 Martin Mares
  if (*msg >= 1 && *msg <= 8)
173 6032aa6a Martin Mares
    class = *msg++;
174
  vlog(class, msg, args);
175
  va_end(args);
176
}
177
178 cb530392 Ondrej Zajicek
void
179 1123e707 Ondrej Zajicek
log_rl(struct tbf *f, char *msg, ...)
180 cb530392 Ondrej Zajicek
{
181 1123e707 Ondrej Zajicek
  int last_hit = f->mark;
182 cb530392 Ondrej Zajicek
  int class = 1;
183
  va_list args;
184
185 1123e707 Ondrej Zajicek
  /* Rate limiting is a bit tricky here as it also logs '...' during the first hit */
186
  if (tbf_limit(f) && last_hit)
187 cb530392 Ondrej Zajicek
    return;
188
189
  if (*msg >= 1 && *msg <= 8)
190
    class = *msg++;
191 1123e707 Ondrej Zajicek
192
  va_start(args, msg);
193
  vlog(class, (f->mark ? "..." : msg), args);
194 cb530392 Ondrej Zajicek
  va_end(args);
195
}
196
197 73275d85 Martin Mares
/**
198
 * bug - report an internal error
199
 * @msg: a printf-like error message
200
 *
201
 * This function logs an internal error and aborts execution
202
 * of the program.
203
 */
204 6032aa6a Martin Mares
void
205 98e87c86 Martin Mares
bug(char *msg, ...)
206
{
207
  va_list args;
208
209
  va_start(args, msg);
210
  vlog(L_BUG[0], msg, args);
211 818ff1e2 Martin Mares
  abort();
212 98e87c86 Martin Mares
}
213
214 73275d85 Martin Mares
/**
215
 * bug - report a fatal error
216
 * @msg: a printf-like error message
217
 *
218
 * This function logs a fatal error and aborts execution
219
 * of the program.
220
 */
221 98e87c86 Martin Mares
void
222 6032aa6a Martin Mares
die(char *msg, ...)
223
{
224
  va_list args;
225
226
  va_start(args, msg);
227 98e87c86 Martin Mares
  vlog(L_FATAL[0], msg, args);
228 6032aa6a Martin Mares
  exit(1);
229
}
230
231 73275d85 Martin Mares
/**
232
 * debug - write to debug output
233
 * @msg: a printf-like message
234
 *
235
 * This function formats the message @msg and prints it out
236
 * to the debugging output. No newline character is appended.
237
 */
238 6032aa6a Martin Mares
void
239
debug(char *msg, ...)
240
{
241
  va_list args;
242 34350a52 Martin Mares
  char buf[1024];
243 6032aa6a Martin Mares
244
  va_start(args, msg);
245
  if (dbgf)
246 a0c37b45 Martin Mares
    {
247
      if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
248
        bsprintf(buf + sizeof(buf) - 100, " ... <too long>\n");
249
      fputs(buf, dbgf);
250
    }
251 6032aa6a Martin Mares
  va_end(args);
252
}
253
254 44d4ab7a Ondrej Zajicek
static list *
255
default_log_list(int debug, int init, char **syslog_name)
256 6032aa6a Martin Mares
{
257 44d4ab7a Ondrej Zajicek
  static list init_log_list;
258 a0c37b45 Martin Mares
  init_list(&init_log_list);
259 44d4ab7a Ondrej Zajicek
  *syslog_name = NULL;
260 6032aa6a Martin Mares
261
#ifdef HAVE_SYSLOG
262 a0c37b45 Martin Mares
  if (!debug)
263 6032aa6a Martin Mares
    {
264 4a591d4b Pavel Tvrdik
      static struct log_config lc_syslog = { .mask = ~0 };
265 44d4ab7a Ondrej Zajicek
      add_tail(&init_log_list, &lc_syslog.n);
266
      *syslog_name = bird_name;
267 5ddf4a58 Martin Mares
      if (!init)
268 44d4ab7a Ondrej Zajicek
        return &init_log_list;
269 6032aa6a Martin Mares
    }
270 a0c37b45 Martin Mares
#endif
271
272 4a591d4b Pavel Tvrdik
  static struct log_config lc_stderr = { .mask = ~0, .terminal_flag = 1 };
273 a0c37b45 Martin Mares
  lc_stderr.fh = stderr;
274 44d4ab7a Ondrej Zajicek
  add_tail(&init_log_list, &lc_stderr.n);
275
  return &init_log_list;
276 a0c37b45 Martin Mares
}
277
278
void
279 44d4ab7a Ondrej Zajicek
log_switch(int debug, list *l, char *new_syslog_name)
280 a0c37b45 Martin Mares
{
281 44d4ab7a Ondrej Zajicek
  if (!l || EMPTY_LIST(*l))
282
    l = default_log_list(debug, !l, &new_syslog_name);
283
284
  current_log_list = l;
285
286
#ifdef HAVE_SYSLOG
287
  if (current_syslog_name && new_syslog_name &&
288
      !strcmp(current_syslog_name, new_syslog_name))
289
    return;
290
291
  if (current_syslog_name)
292
    closelog();
293
294
  if (new_syslog_name)
295
    openlog(new_syslog_name, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
296
297
  current_syslog_name = new_syslog_name;
298
#endif
299 6032aa6a Martin Mares
}
300
301 44d4ab7a Ondrej Zajicek
302
303 6032aa6a Martin Mares
void
304
log_init_debug(char *f)
305
{
306
  if (dbgf && dbgf != stderr)
307
    fclose(dbgf);
308
  if (!f)
309
    dbgf = NULL;
310 a0c37b45 Martin Mares
  else if (!*f)
311
    dbgf = stderr;
312 6032aa6a Martin Mares
  else if (!(dbgf = fopen(f, "a")))
313
    log(L_ERR "Error opening debug file `%s': %m", f);
314 f098e072 Martin Mares
  if (dbgf)
315
    setvbuf(dbgf, NULL, _IONBF, 0);
316 6032aa6a Martin Mares
}
317 cf31112f Ondrej Zajicek
318
void
319
mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len)
320
{
321
  /* Prepare header */
322
  put_u32(buf+0, now_real);
323
  put_u16(buf+4, type);
324
  put_u16(buf+6, subtype);
325
  put_u32(buf+8, len - MRTDUMP_HDR_LENGTH);
326
327
  if (p->cf->global->mrtdump_file != -1)
328
    write(p->cf->global->mrtdump_file, buf, len);
329
}