Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / log.c @ 8e433d6a

History | View | Annotate | Download (6.87 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 8e433d6a Pavel Tvrdik
 * @buf: message to write
93 0d1b3c4c Ondrej Zajicek
 *
94
 * This function writes a message prepared in the log buffer to the
95
 * log file (as specified in the configuration). The log buffer is
96
 * reset after that. The log message is a full line, log_commit()
97
 * terminates it.
98
 *
99
 * The message class is an integer, not a first char of a string like
100
 * in log(), so it should be written like *L_INFO.
101
 */
102
void
103 0e175f9f Ondrej Zajicek
log_commit(int class, buffer *buf)
104 0d1b3c4c Ondrej Zajicek
{
105
  struct log_config *l;
106 9556f225 Martin Mares
107 0e175f9f Ondrej Zajicek
  if (buf->pos == buf->end)
108
    strcpy(buf->end - 100, " ... <too long>");
109
110
  log_lock();
111 a0c37b45 Martin Mares
  WALK_LIST(l, *current_log_list)
112 6032aa6a Martin Mares
    {
113 a0c37b45 Martin Mares
      if (!(l->mask & (1 << class)))
114
        continue;
115
      if (l->fh)
116
        {
117
          if (l->terminal_flag)
118
            fputs("bird: ", l->fh);
119
          else
120
            {
121 c37e7851 Ondrej Zajicek
              byte tbuf[TM_DATETIME_BUFFER_SIZE];
122
              tm_format_datetime(tbuf, &config->tf_log, now);
123
              fprintf(l->fh, "%s <%s> ", tbuf, class_names[class]);
124 a0c37b45 Martin Mares
            }
125 0e175f9f Ondrej Zajicek
          fputs(buf->start, l->fh);
126 a0c37b45 Martin Mares
          fputc('\n', l->fh);
127
          fflush(l->fh);
128
        }
129 6032aa6a Martin Mares
#ifdef HAVE_SYSLOG
130 a0c37b45 Martin Mares
      else
131 0e175f9f Ondrej Zajicek
        syslog(syslog_priorities[class], "%s", buf->start);
132 6032aa6a Martin Mares
#endif
133
    }
134 0e175f9f Ondrej Zajicek
  log_unlock();
135 0d1b3c4c Ondrej Zajicek
136 4e398e34 Ondrej Zajicek
  /* cli_echo is not thread-safe, so call it just from the main thread */
137
  if (main_thread_self())
138
    cli_echo(class, buf->start);
139 56027b5c Ondrej Zajicek
140
  buf->pos = buf->start;
141 0d1b3c4c Ondrej Zajicek
}
142
143 0e175f9f Ondrej Zajicek
int buffer_vprint(buffer *buf, const char *fmt, va_list args);
144 0d1b3c4c Ondrej Zajicek
145
static void
146
vlog(int class, const char *msg, va_list args)
147
{
148 0e175f9f Ondrej Zajicek
  buffer buf;
149
  LOG_BUFFER_INIT(buf);
150
  buffer_vprint(&buf, msg, args);
151
  log_commit(class, &buf);
152 0d1b3c4c Ondrej Zajicek
}
153
154
155 73275d85 Martin Mares
/**
156
 * log - log a message
157
 * @msg: printf-like formatting string with message class information
158
 * prepended (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
159
 *
160
 * This function formats a message according to the format string @msg
161 2e9b2421 Martin Mares
 * and writes it to the corresponding log file (as specified in the
162 73275d85 Martin Mares
 * configuration). Please note that the message is automatically
163
 * formatted as a full line, no need to include |\n| inside.
164 0d1b3c4c Ondrej Zajicek
 * It is essentially a sequence of log_reset(), logn() and log_commit().
165 73275d85 Martin Mares
 */
166 6032aa6a Martin Mares
void
167 e598853e Pavel Tvrdik
log_msg(const char *msg, ...)
168 6032aa6a Martin Mares
{
169
  int class = 1;
170
  va_list args;
171
172
  va_start(args, msg);
173 98e87c86 Martin Mares
  if (*msg >= 1 && *msg <= 8)
174 6032aa6a Martin Mares
    class = *msg++;
175
  vlog(class, msg, args);
176
  va_end(args);
177
}
178
179 cb530392 Ondrej Zajicek
void
180 e598853e Pavel Tvrdik
log_rl(struct tbf *f, const char *msg, ...)
181 cb530392 Ondrej Zajicek
{
182 1123e707 Ondrej Zajicek
  int last_hit = f->mark;
183 cb530392 Ondrej Zajicek
  int class = 1;
184
  va_list args;
185
186 1123e707 Ondrej Zajicek
  /* Rate limiting is a bit tricky here as it also logs '...' during the first hit */
187
  if (tbf_limit(f) && last_hit)
188 cb530392 Ondrej Zajicek
    return;
189
190
  if (*msg >= 1 && *msg <= 8)
191
    class = *msg++;
192 1123e707 Ondrej Zajicek
193
  va_start(args, msg);
194
  vlog(class, (f->mark ? "..." : msg), args);
195 cb530392 Ondrej Zajicek
  va_end(args);
196
}
197
198 73275d85 Martin Mares
/**
199
 * bug - report an internal error
200
 * @msg: a printf-like error message
201
 *
202
 * This function logs an internal error and aborts execution
203
 * of the program.
204
 */
205 6032aa6a Martin Mares
void
206 e598853e Pavel Tvrdik
bug(const char *msg, ...)
207 98e87c86 Martin Mares
{
208
  va_list args;
209
210
  va_start(args, msg);
211
  vlog(L_BUG[0], msg, args);
212 818ff1e2 Martin Mares
  abort();
213 98e87c86 Martin Mares
}
214
215 73275d85 Martin Mares
/**
216
 * bug - report a fatal error
217
 * @msg: a printf-like error message
218
 *
219
 * This function logs a fatal error and aborts execution
220
 * of the program.
221
 */
222 98e87c86 Martin Mares
void
223 e598853e Pavel Tvrdik
die(const char *msg, ...)
224 6032aa6a Martin Mares
{
225
  va_list args;
226
227
  va_start(args, msg);
228 98e87c86 Martin Mares
  vlog(L_FATAL[0], msg, args);
229 6032aa6a Martin Mares
  exit(1);
230
}
231
232 73275d85 Martin Mares
/**
233
 * debug - write to debug output
234
 * @msg: a printf-like message
235
 *
236
 * This function formats the message @msg and prints it out
237
 * to the debugging output. No newline character is appended.
238
 */
239 6032aa6a Martin Mares
void
240 e598853e Pavel Tvrdik
debug(const char *msg, ...)
241 6032aa6a Martin Mares
{
242
  va_list args;
243 34350a52 Martin Mares
  char buf[1024];
244 6032aa6a Martin Mares
245
  va_start(args, msg);
246
  if (dbgf)
247 a0c37b45 Martin Mares
    {
248
      if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
249
        bsprintf(buf + sizeof(buf) - 100, " ... <too long>\n");
250
      fputs(buf, dbgf);
251
    }
252 6032aa6a Martin Mares
  va_end(args);
253
}
254
255 44d4ab7a Ondrej Zajicek
static list *
256
default_log_list(int debug, int init, char **syslog_name)
257 6032aa6a Martin Mares
{
258 44d4ab7a Ondrej Zajicek
  static list init_log_list;
259 a0c37b45 Martin Mares
  init_list(&init_log_list);
260 44d4ab7a Ondrej Zajicek
  *syslog_name = NULL;
261 6032aa6a Martin Mares
262
#ifdef HAVE_SYSLOG
263 a0c37b45 Martin Mares
  if (!debug)
264 6032aa6a Martin Mares
    {
265 4a591d4b Pavel Tvrdik
      static struct log_config lc_syslog = { .mask = ~0 };
266 44d4ab7a Ondrej Zajicek
      add_tail(&init_log_list, &lc_syslog.n);
267
      *syslog_name = bird_name;
268 5ddf4a58 Martin Mares
      if (!init)
269 44d4ab7a Ondrej Zajicek
        return &init_log_list;
270 6032aa6a Martin Mares
    }
271 a0c37b45 Martin Mares
#endif
272
273 4a591d4b Pavel Tvrdik
  static struct log_config lc_stderr = { .mask = ~0, .terminal_flag = 1 };
274 a0c37b45 Martin Mares
  lc_stderr.fh = stderr;
275 44d4ab7a Ondrej Zajicek
  add_tail(&init_log_list, &lc_stderr.n);
276
  return &init_log_list;
277 a0c37b45 Martin Mares
}
278
279
void
280 44d4ab7a Ondrej Zajicek
log_switch(int debug, list *l, char *new_syslog_name)
281 a0c37b45 Martin Mares
{
282 44d4ab7a Ondrej Zajicek
  if (!l || EMPTY_LIST(*l))
283
    l = default_log_list(debug, !l, &new_syslog_name);
284
285
  current_log_list = l;
286
287
#ifdef HAVE_SYSLOG
288 c2106b67 Ondrej Zajicek (work)
  char *old_syslog_name = current_syslog_name;
289
  current_syslog_name = new_syslog_name;
290
291
  if (old_syslog_name && new_syslog_name &&
292
      !strcmp(old_syslog_name, new_syslog_name))
293 44d4ab7a Ondrej Zajicek
    return;
294
295 c2106b67 Ondrej Zajicek (work)
  if (old_syslog_name)
296 44d4ab7a Ondrej Zajicek
    closelog();
297
298
  if (new_syslog_name)
299
    openlog(new_syslog_name, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
300
#endif
301 6032aa6a Martin Mares
}
302
303 44d4ab7a Ondrej Zajicek
304
305 6032aa6a Martin Mares
void
306
log_init_debug(char *f)
307
{
308
  if (dbgf && dbgf != stderr)
309
    fclose(dbgf);
310
  if (!f)
311
    dbgf = NULL;
312 a0c37b45 Martin Mares
  else if (!*f)
313
    dbgf = stderr;
314 6032aa6a Martin Mares
  else if (!(dbgf = fopen(f, "a")))
315
    log(L_ERR "Error opening debug file `%s': %m", f);
316 f098e072 Martin Mares
  if (dbgf)
317
    setvbuf(dbgf, NULL, _IONBF, 0);
318 6032aa6a Martin Mares
}
319 cf31112f Ondrej Zajicek
320
void
321
mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len)
322
{
323
  /* Prepare header */
324
  put_u32(buf+0, now_real);
325
  put_u16(buf+4, type);
326
  put_u16(buf+6, subtype);
327
  put_u32(buf+8, len - MRTDUMP_HDR_LENGTH);
328
329
  if (p->cf->global->mrtdump_file != -1)
330
    write(p->cf->global->mrtdump_file, buf, len);
331
}