Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / log.c @ 508d9360

History | View | Annotate | Download (7.42 KB)

1
/*
2
 *        BIRD Library -- Logging Functions
3
 *
4
 *        (c) 1998--2000 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
/**
10
 * DOC: Logging
11
 *
12
 * The Logging module offers a simple set of functions for writing
13
 * 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
 */
17

    
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <stdarg.h>
21
#include <time.h>
22
#include <unistd.h>
23

    
24
#include "nest/bird.h"
25
#include "nest/cli.h"
26
#include "nest/mrtdump.h"
27
#include "lib/string.h"
28
#include "lib/lists.h"
29
#include "lib/unix.h"
30

    
31
static FILE *dbgf;
32
static list *current_log_list;
33
static char *current_syslog_name; /* NULL -> syslog closed */
34

    
35
bird_clock_t rate_limit_time = 5;
36
int rate_limit_count = 5;
37

    
38
#ifdef HAVE_SYSLOG
39
#include <sys/syslog.h>
40

    
41
static int syslog_priorities[] = {
42
  LOG_DEBUG,
43
  LOG_DEBUG,
44
  LOG_DEBUG,
45
  LOG_INFO,
46
  LOG_ERR,
47
  LOG_WARNING,
48
  LOG_ERR,
49
  LOG_ERR,
50
  LOG_CRIT,
51
  LOG_CRIT
52
};
53
#endif
54

    
55
static char *class_names[] = {
56
  "???",
57
  "DBG",
58
  "TRACE",
59
  "INFO",
60
  "RMT",
61
  "WARN",
62
  "ERR",
63
  "AUTH",
64
  "FATAL",
65
  "BUG"
66
};
67

    
68
#define LOG_BUFFER_SIZE 1024
69
static char log_buffer[LOG_BUFFER_SIZE];
70
static char *log_buffer_pos;
71
static int log_buffer_remains;
72

    
73
const char *log_buffer_ptr = log_buffer;
74

    
75

    
76
/**
77
 * log_reset - reset the log buffer
78
 *
79
 * This function resets a log buffer and discards buffered
80
 * messages. Should be used before a log message is prepared
81
 * using logn().
82
 */
83
void
84
log_reset(void)
85
{
86
  log_buffer_pos = log_buffer;
87
  log_buffer_remains = LOG_BUFFER_SIZE;
88
  log_buffer[0] = 0;
89
}
90

    
91
/**
92
 * log_commit - commit a log message
93
 * @class: message class information (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
94
 *
95
 * This function writes a message prepared in the log buffer to the
96
 * log file (as specified in the configuration). The log buffer is
97
 * reset after that. The log message is a full line, log_commit()
98
 * terminates it.
99
 *
100
 * The message class is an integer, not a first char of a string like
101
 * in log(), so it should be written like *L_INFO.
102
 */
103
void
104
log_commit(int class)
105
{
106
  struct log_config *l;
107

    
108
  WALK_LIST(l, *current_log_list)
109
    {
110
      if (!(l->mask & (1 << class)))
111
        continue;
112
      if (l->fh)
113
        {
114
          if (l->terminal_flag)
115
            fputs("bird: ", l->fh);
116
          else
117
            {
118
              byte tbuf[TM_DATETIME_BUFFER_SIZE];
119
              tm_format_datetime(tbuf, &config->tf_log, now);
120
              fprintf(l->fh, "%s <%s> ", tbuf, class_names[class]);
121
            }
122
          fputs(log_buffer, l->fh);
123
          fputc('\n', l->fh);
124
          fflush(l->fh);
125
        }
126
#ifdef HAVE_SYSLOG
127
      else
128
        syslog(syslog_priorities[class], "%s", log_buffer);
129
#endif
130
    }
131
  cli_echo(class, log_buffer);
132

    
133
  log_reset();
134
}
135

    
136
static void
137
log_print(const char *msg, va_list args)
138
{
139
  int i;
140

    
141
  if (log_buffer_remains == 0)
142
    return;
143

    
144
  i=bvsnprintf(log_buffer_pos, log_buffer_remains, msg, args);
145
  if (i < 0)
146
    {
147
      bsprintf(log_buffer + LOG_BUFFER_SIZE - 100, " ... <too long>");
148
      log_buffer_remains = 0;
149
      return;
150
    }
151

    
152
  log_buffer_pos += i;
153
  log_buffer_remains -= i;
154
}
155

    
156

    
157
static void
158
vlog(int class, const char *msg, va_list args)
159
{
160
  log_reset();
161
  log_print(msg, args);
162
  log_commit(class);
163
}
164

    
165

    
166

    
167
/**
168
 * log - log a message
169
 * @msg: printf-like formatting string with message class information
170
 * prepended (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
171
 *
172
 * This function formats a message according to the format string @msg
173
 * and writes it to the corresponding log file (as specified in the
174
 * configuration). Please note that the message is automatically
175
 * formatted as a full line, no need to include |\n| inside.
176
 * It is essentially a sequence of log_reset(), logn() and log_commit().
177
 */
178
void
179
log_msg(char *msg, ...)
180
{
181
  int class = 1;
182
  va_list args;
183

    
184
  va_start(args, msg);
185
  if (*msg >= 1 && *msg <= 8)
186
    class = *msg++;
187
  vlog(class, msg, args);
188
  va_end(args);
189
}
190

    
191
/**
192
 * logn - prepare a partial message in the log buffer
193
 * @msg: printf-like formatting string (without message class information)
194
 *
195
 * This function formats a message according to the format string @msg
196
 * and adds it to the log buffer. Messages in the log buffer are
197
 * logged when the buffer is flushed using log_commit() function. The
198
 * message should not contain |\n|, log_commit() also terminates a
199
 * line.
200
 */
201
void
202
logn(char *msg, ...)
203
{
204
  va_list args;
205

    
206
  va_start(args, msg);
207
  log_print(msg, args);
208
  va_end(args);
209
}
210

    
211
void
212
log_rl(struct rate_limit *rl, char *msg, ...)
213
{
214
  int class = 1;
215
  va_list args;
216

    
217
  bird_clock_t delta = now - rl->timestamp;
218
  if ((0 <= delta) && (delta < rate_limit_time))
219
    {
220
      rl->count++;
221
    }
222
  else
223
    {
224
      rl->timestamp = now;
225
      rl->count = 1;
226
    }
227

    
228
  if (rl->count > rate_limit_count)
229
    return;
230

    
231
  va_start(args, msg);
232
  if (*msg >= 1 && *msg <= 8)
233
    class = *msg++;
234
  vlog(class, msg, args);
235
  if (rl->count == rate_limit_count)
236
    vlog(class, "...", args);
237
  va_end(args);
238
}
239

    
240
/**
241
 * bug - report an internal error
242
 * @msg: a printf-like error message
243
 *
244
 * This function logs an internal error and aborts execution
245
 * of the program.
246
 */
247
void
248
bug(char *msg, ...)
249
{
250
  va_list args;
251

    
252
  va_start(args, msg);
253
  vlog(L_BUG[0], msg, args);
254
  abort();
255
}
256

    
257
/**
258
 * bug - report a fatal error
259
 * @msg: a printf-like error message
260
 *
261
 * This function logs a fatal error and aborts execution
262
 * of the program.
263
 */
264
void
265
die(char *msg, ...)
266
{
267
  va_list args;
268

    
269
  va_start(args, msg);
270
  vlog(L_FATAL[0], msg, args);
271
  exit(1);
272
}
273

    
274
/**
275
 * debug - write to debug output
276
 * @msg: a printf-like message
277
 *
278
 * This function formats the message @msg and prints it out
279
 * to the debugging output. No newline character is appended.
280
 */
281
void
282
debug(char *msg, ...)
283
{
284
  va_list args;
285
  char buf[1024];
286

    
287
  va_start(args, msg);
288
  if (dbgf)
289
    {
290
      if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
291
        bsprintf(buf + sizeof(buf) - 100, " ... <too long>\n");
292
      fputs(buf, dbgf);
293
    }
294
  va_end(args);
295
}
296

    
297
static list *
298
default_log_list(int debug, int init, char **syslog_name)
299
{
300
  static list init_log_list;
301
  init_list(&init_log_list);
302
  *syslog_name = NULL;
303

    
304
#ifdef HAVE_SYSLOG
305
  if (!debug)
306
    {
307
      static struct log_config lc_syslog = { mask: ~0 };
308
      add_tail(&init_log_list, &lc_syslog.n);
309
      *syslog_name = bird_name;
310
      if (!init)
311
        return &init_log_list;
312
    }
313
#endif
314

    
315
  static struct log_config lc_stderr = { mask: ~0, terminal_flag: 1 };
316
  lc_stderr.fh = stderr;
317
  add_tail(&init_log_list, &lc_stderr.n);
318
  return &init_log_list;
319
}
320

    
321
void
322
log_switch(int debug, list *l, char *new_syslog_name)
323
{
324
  if (!l || EMPTY_LIST(*l))
325
    l = default_log_list(debug, !l, &new_syslog_name);
326

    
327
  current_log_list = l;
328

    
329
#ifdef HAVE_SYSLOG
330
  if (current_syslog_name && new_syslog_name &&
331
      !strcmp(current_syslog_name, new_syslog_name))
332
    return;
333

    
334
  if (current_syslog_name)
335
    closelog();
336

    
337
  if (new_syslog_name)
338
    openlog(new_syslog_name, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
339

    
340
  current_syslog_name = new_syslog_name;
341
#endif
342
}
343

    
344

    
345

    
346
void
347
log_init_debug(char *f)
348
{
349
  if (dbgf && dbgf != stderr)
350
    fclose(dbgf);
351
  if (!f)
352
    dbgf = NULL;
353
  else if (!*f)
354
    dbgf = stderr;
355
  else if (!(dbgf = fopen(f, "a")))
356
    log(L_ERR "Error opening debug file `%s': %m", f);
357
  if (dbgf)
358
    setvbuf(dbgf, NULL, _IONBF, 0);
359
}
360

    
361
void
362
mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len)
363
{
364
  /* Prepare header */
365
  put_u32(buf+0, now_real);
366
  put_u16(buf+4, type);
367
  put_u16(buf+6, subtype);
368
  put_u32(buf+8, len - MRTDUMP_HDR_LENGTH);
369

    
370
  if (p->cf->global->mrtdump_file != -1)
371
    write(p->cf->global->mrtdump_file, buf, len);
372
}