1 /* -*- c-file-style: "java"; indent-tabs-mode: nil; tab-width: 4; fill-column: 78 -*-
2 *
3 * ecolog - Reusable application logging library.
4 *
5 * Copyright (C) 2000 - 2003 by Martin Pool <mbp@samba.org>
6 * Copyright 2007 Google Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /*
24 | Finality is death.
25 | Perfection is finality.
26 | Nothing is perfect.
27 | There are lumps in it.
28 */
29
30
31 #include <config.h>
32
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <sys/file.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <stdarg.h>
40 #include <syslog.h>
41
42 #include "distcc.h"
43 #include "trace.h"
44 #include "snprintf.h"
45 #include "va_copy.h"
46
47 struct rs_logger_list {
48 rs_logger_fn *fn;
49 void *private_ptr;
50 int private_int;
51 int max_level;
52 struct rs_logger_list *next;
53 };
54
55 static struct rs_logger_list *logger_list = NULL;
56
57 /* really bool */
58 int rs_trace_syslog = FALSE;
59 int rs_trace_level = RS_LOG_NOTICE;
60
61 #ifdef UNUSED
62 /* nothing */
63 #elif defined(__GNUC__)
64 # define UNUSED(x) x __attribute__((unused))
65 #elif defined(__LCLINT__)
66 # define UNUSED(x) /*@unused@*/ x
67 #else /* !__GNUC__ && !__LCLINT__ */
68 # define UNUSED(x) x
69 #endif /* !__GNUC__ && !__LCLINT__ */
70
71
72 static void rs_log_va(int level, char const *fn, char const *fmt, va_list va);
73
74 #if SIZEOF_SIZE_T > SIZEOF_LONG
75 # warning size_t is larger than a long integer, values in trace messages may be wrong
76 #endif
77
78
79 /**
80 * Log severity strings, if any. Must match ordering in
81 * ::rs_loglevel.
82 */
83 static const char *rs_severities[] = {
84 "EMERGENCY! ", "ALERT! ", "CRITICAL! ", "ERROR: ", "Warning: ",
85 "", "", ""
86 };
87
88
89 /**********************************************************************
90 * Functions for manipulating the list of loggers
91 **********************************************************************/
92
rs_remove_all_loggers(void)93 void rs_remove_all_loggers(void)
94 {
95 struct rs_logger_list *l, *next;
96
97 for (l = logger_list; l; l = next) {
98 next = l -> next; /* save before destruction */
99 free(l);
100 }
101 logger_list = NULL;
102 }
103
104
rs_add_logger(rs_logger_fn fn,int max_level,void * private_ptr,int private_int)105 void rs_add_logger(rs_logger_fn fn,
106 int max_level,
107 void *private_ptr,
108 int private_int)
109 {
110 struct rs_logger_list *l;
111
112 if ((l = malloc(sizeof *l)) == NULL)
113 return;
114
115 l->fn = fn;
116 l->max_level = max_level;
117 l->private_ptr = private_ptr;
118 l->private_int = private_int;
119
120 l->next = logger_list;
121 logger_list = l;
122 }
123
124
125 /**
126 * Remove only the logger that exactly matches the specified parameters
127 **/
rs_remove_logger(rs_logger_fn fn,int max_level,void * private_ptr,int private_int)128 void rs_remove_logger(rs_logger_fn fn,
129 int max_level,
130 void *private_ptr,
131 int private_int)
132 {
133 struct rs_logger_list *l, **pl;
134
135 for (pl = &logger_list; *pl; pl = &((*pl)->next)) {
136 l = *pl;
137 if (l->fn == fn
138 && l->max_level == max_level
139 && l->private_ptr == private_ptr
140 && l->private_int == private_int) {
141 /* unhook from list by adjusting whoever points to this. */
142 *pl = l->next;
143 free(l);
144 return;
145 }
146 }
147 }
148
149
150 /**
151 * Set the least important (i.e. largest) message severity that
152 * will be output.
153 */
154 void
rs_trace_set_level(rs_loglevel level)155 rs_trace_set_level(rs_loglevel level)
156 {
157 rs_trace_level = level;
158 }
159
160
161
162 /**
163 * Work out a log level from a string name.
164 *
165 * Returns -1 for invalid names.
166 */
167 int
rs_loglevel_from_name(const char * name)168 rs_loglevel_from_name(const char *name)
169 {
170 if (!strcmp(name, "emerg") || !strcmp(name, "emergency"))
171 return RS_LOG_EMERG;
172 else if (!strcmp(name, "alert"))
173 return RS_LOG_ALERT;
174 else if (!strcmp(name, "critical") || !strcmp(name, "crit"))
175 return RS_LOG_CRIT;
176 else if (!strcmp(name, "error") || !strcmp(name, "err"))
177 return RS_LOG_ERR;
178 else if (!strcmp(name, "warning") || !strcmp(name, "warn"))
179 return RS_LOG_WARNING;
180 else if (!strcmp(name, "notice") || !strcmp(name, "note"))
181 return RS_LOG_NOTICE;
182 else if (!strcmp(name, "info"))
183 return RS_LOG_INFO;
184 else if (!strcmp(name, "debug"))
185 return RS_LOG_DEBUG;
186
187 return -1;
188 }
189
190
191 /**
192 * If you don't initialize a logger before first logging, then we
193 * write to stderr by default.
194 **/
rs_lazy_default(void)195 static void rs_lazy_default(void)
196 {
197 static int called;
198
199 if (called)
200 return;
201
202 called = 1;
203 if (logger_list == NULL)
204 rs_add_logger(rs_logger_file, RS_LOG_WARNING, NULL, STDERR_FILENO);
205 }
206
207 /* Heart of the matter */
208 static void
rs_log_va(int flags,char const * caller_fn_name,char const * fmt,va_list va)209 rs_log_va(int flags, char const *caller_fn_name, char const *fmt, va_list va)
210
211
212 {
213 int level = flags & RS_LOG_PRIMASK;
214 struct rs_logger_list *l;
215
216 rs_lazy_default();
217
218 if (level <= rs_trace_level)
219 for (l = logger_list; l; l = l->next)
220 if (level <= l->max_level) {
221 /* We need to use va_copy() here, because functions like vsprintf
222 * may destructively modify their va_list argument, but we need
223 * to ensure that it's still valid next time around the loop. */
224 va_list copied_va;
225 VA_COPY(copied_va, va);
226 l->fn(flags, caller_fn_name,
227 fmt, copied_va, l->private_ptr, l->private_int);
228 VA_COPY_END(copied_va);
229 }
230 }
231
232
rs_format_msg(char * buf,size_t buf_len,int flags,const char * fn,const char * fmt,va_list va)233 void rs_format_msg(char *buf,
234 size_t buf_len,
235 int flags,
236 const char *fn,
237 const char *fmt,
238 va_list va)
239 {
240 unsigned level = flags & RS_LOG_PRIMASK;
241 int len;
242 const char *sv;
243
244 *buf = '\0';
245 len = 0;
246
247 if (!(flags & RS_LOG_NO_PROGRAM)) {
248 strcpy(buf, rs_program_name);
249 len = strlen(buf);
250 }
251
252 if (!(flags & RS_LOG_NO_PID)) {
253 /* You might like to cache the pid, but that would cause trouble when we fork. */
254 sprintf(buf+len, "[%d] ", (int) getpid());
255 } else if (~flags & RS_LOG_NO_PROGRAM) {
256 strcat(buf+len, ": ");
257 }
258 len = strlen(buf);
259
260 if (!(flags & RS_LOG_NONAME) && fn) {
261 sprintf(buf+len, "(%s) ", fn);
262 len = strlen(buf);
263 }
264
265 sv = rs_severities[level];
266 if (*sv) {
267 strcpy(buf + len, sv);
268 len = strlen(buf);
269 }
270
271 vsnprintf(buf + len, buf_len - len, fmt, va);
272 }
273
274
275
276 /**
277 * Called by a macro, used on platforms where we can't determine the
278 * calling function name.
279 */
280 void
rs_log0_nofn(int level,char const * fmt,...)281 rs_log0_nofn(int level, char const *fmt, ...)
282 {
283 va_list va;
284
285 va_start(va, fmt);
286 rs_log_va(level, NULL, fmt, va);
287 va_end(va);
288 }
289
290
rs_log0(int level,char const * fn,char const * fmt,...)291 void rs_log0(int level, char const *fn, char const *fmt, ...)
292 {
293 va_list va;
294
295 va_start(va, fmt);
296 rs_log_va(level, fn, fmt, va);
297 va_end(va);
298 }
299
300
301 void
rs_logger_syslog(int flags,const char * fn,char const * fmt,va_list va,void * UNUSED (private_ptr),int UNUSED (private_int))302 rs_logger_syslog(int flags, const char *fn, char const *fmt, va_list va,
303 void * UNUSED(private_ptr), int UNUSED(private_int))
304 {
305 /* NOTE NO TRAILING NUL */
306 char buf[4090];
307
308 /* you're never going to want program or pid in a syslog message,
309 * because it's redundant. */
310 rs_format_msg(buf, sizeof buf,
311 flags | RS_LOG_NO_PROGRAM | RS_LOG_NO_PID,
312 fn, fmt, va);
313 syslog(flags & RS_LOG_PRIMASK, "%s", buf);
314 }
315
316
317 void
rs_logger_file(int flags,const char * fn,char const * fmt,va_list va,void * UNUSED (private_ptr),int log_fd)318 rs_logger_file(int flags, const char *fn, char const *fmt, va_list va,
319 void * UNUSED(private_ptr), int log_fd)
320 {
321 /* NOTE NO TRAILING NUL */
322 char buf[4090];
323 size_t len;
324 ssize_t ret;
325
326 rs_format_msg(buf, sizeof buf, flags, fn, fmt, va);
327
328 len = strlen(buf);
329 if (len > (int) sizeof buf - 2)
330 len = (int) sizeof buf - 2;
331 strcpy(&buf[len], "\n");
332
333 ret = write(log_fd, buf, len + 1);
334 if (ret == -1) {
335 ret = write(/* stderr */ 2, buf, len + 1);
336 }
337 }
338
339
340
341 /* ======================================================================== */
342 /* functions for handling compilers without varargs macros */
343
344 /* This is called directly if the machine doesn't allow varargs
345 * macros. */
346 void
rs_log_error_nofn(char const * s,...)347 rs_log_error_nofn(char const *s, ...)
348 {
349 va_list va;
350
351 va_start(va, s);
352 rs_log_va(RS_LOG_ERR, NULL, s, va);
353 va_end(va);
354 }
355
356 /* This is called directly if the machine doesn't allow varargs
357 * macros. */
358 void
rs_log_warning_nofn(char const * s,...)359 rs_log_warning_nofn(char const *s, ...)
360 {
361 va_list va;
362
363 va_start(va, s);
364 rs_log_va(RS_LOG_WARNING, NULL, s, va);
365 va_end(va);
366 }
367
368
369 /* This is called directly if the machine doesn't allow varargs
370 * macros. */
371 void
rs_log_critical_nofn(char const * s,...)372 rs_log_critical_nofn(char const *s, ...)
373 {
374 va_list va;
375
376 va_start(va, s);
377 rs_log_va(RS_LOG_CRIT, NULL, s, va);
378 va_end(va);
379 }
380
381 /* This is called directly if the machine doesn't allow varargs
382 * macros. */
383 void
rs_log_info_nofn(char const * s,...)384 rs_log_info_nofn(char const *s, ...)
385 {
386 va_list va;
387
388 va_start(va, s);
389 rs_log_va(RS_LOG_INFO, NULL, s, va);
390 va_end(va);
391 }
392
393
394 /* This is called directly if the machine doesn't allow varargs
395 * macros. */
396 void
rs_log_notice_nofn(char const * s,...)397 rs_log_notice_nofn(char const *s, ...)
398 {
399 va_list va;
400
401 va_start(va, s);
402 rs_log_va(RS_LOG_NOTICE, NULL, s, va);
403 va_end(va);
404 }
405
406
407 /* This is called directly if the machine doesn't allow varargs
408 * macros. */
409 void
rs_log_trace_nofn(char const * s,...)410 rs_log_trace_nofn(char const *s, ...)
411 {
412 va_list va;
413
414 va_start(va, s);
415 rs_log_va(RS_LOG_DEBUG, NULL, s, va);
416 va_end(va);
417 }
418
419
420 /**
421 * Return true if the library contains trace code; otherwise false.
422 * If this returns false, then trying to turn trace on will achieve
423 * nothing.
424 */
425 int
rs_supports_trace(void)426 rs_supports_trace(void)
427 {
428 #ifdef DO_RS_TRACE
429 return 1;
430 #else
431 return 0;
432 #endif /* !DO_RS_TRACE */
433 }
434
435
436 static char job_summary[4096*4];
dcc_job_summary_clear(void)437 void dcc_job_summary_clear(void) {
438 job_summary[0] = 0;
439 job_summary[sizeof(job_summary) - 1] = '\0';
440 }
441
dcc_job_summary(void)442 void dcc_job_summary(void) {
443 rs_log_notice("%s", job_summary);
444 }
445
dcc_job_summary_append(const char * s)446 void dcc_job_summary_append(const char *s) {
447 int64_t len = (4096 * 4 - 1) - strlen(job_summary);
448 if (len > 0)
449 strncat(job_summary, s, len);
450 }
451