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 | } |