(afsrights2nnpfsrights): export
[arla.git] / util / log.c
blobaaa85d5ae34d0d3218eb6f14dee6a8bdfe662466
1 /*
2 * Copyright (c) 1995 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
35 * Logging functions
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 RCSID("$Id$");
41 #endif
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #include <sys/time.h>
46 #ifdef HAVE_SYS_RESOURCE_H
47 #include <sys/resource.h>
48 #endif
49 #include <stdio.h>
50 #include <stdarg.h>
51 #include <ctype.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <time.h>
56 #if HAVE_SYSLOG
57 #include <syslog.h>
58 #endif /* HAVE_SYSLOG */
60 #include <assert.h>
61 #include <roken.h>
62 #include <err.h>
63 #include "log.h"
66 * The structure for each logging method.
69 struct log_method;
71 struct log_unit {
72 struct log_method *method;
73 char *name;
74 const struct units *unit;
75 unsigned mask;
78 struct log_method {
79 char *name;
80 void (*open)(Log_method *, const char *progname, char *fname,
81 char *extra_args);
82 void (*vprint)(Log_method *, char *, va_list);
83 void (*print)(Log_method *, char *);
84 void (*close)(Log_method *);
85 union {
86 void *v;
87 int i;
88 } data;
89 log_flags flags;
90 int num_units;
91 struct log_unit **units;
94 struct log_method_file_data {
95 FILE *f;
96 int flags;
97 #define LOGFILE_NO_TIME 1
98 char *progname;
101 #if HAVE_SYSLOG
102 static void log_open_syslog (Log_method *lm, const char *progname,
103 char *fname, char *extra_args);
105 static void log_close_syslog (Log_method *lm);
106 #if HAVE_VSYSLOG
107 static void log_vprint_syslog (Log_method *lm, char *, va_list);
108 #endif /* HAVE_VSYSLOG */
109 static void log_print_syslog (Log_method *lm, char *);
110 #endif /* HAVE_SYSLOG */
112 static void
113 log_open_stderr (Log_method *lm, const char *progname, char *fname,
114 char *extra_args);
116 static void
117 log_open_file (Log_method *lm, const char *progname, char *fname,
118 char *extra_args);
120 static void
121 log_close_file (Log_method *lm);
123 static void
124 log_print_file (Log_method *lm, char *);
126 static void
127 log_vprint_file (Log_method *lm, char *, va_list);
130 * The names for which we do special handling in the logging routines.
133 static
134 Log_method special_names[] = {
135 #if HAVE_SYSLOG
136 {"syslog", log_open_syslog,
137 #if HAVE_VSYSLOG
138 log_vprint_syslog, log_print_syslog
139 #else
140 NULL, log_print_syslog
141 #endif /* HAVE_VSYSLOG */
142 , log_close_syslog},
143 #endif /* HAVE_SYSLOG */
144 {"/dev/stderr", log_open_stderr, log_vprint_file, log_print_file, NULL},
145 {NULL, log_open_file, log_vprint_file, log_print_file, log_close_file}
146 /* Should be last */
149 #if HAVE_SYSLOG
151 struct units syslog_opt_units[] = {
152 #ifdef LOG_PERROR
153 { "stderr", LOG_PERROR },
154 #endif
155 #ifdef LOG_NDELAY
156 { "no-delay", LOG_NDELAY },
157 #endif
158 #ifdef LOG_CONS
159 { "console", LOG_CONS },
160 #endif
161 #ifdef LOG_PID
162 { "pid", LOG_PID },
163 #endif
164 { NULL }
167 struct units syslog_facility_units[] = {
168 #ifdef LOG_AUTH
169 { "auth", LOG_AUTH },
170 #endif
171 #ifdef LOG_AUTHPRIV
172 { "authpriv", LOG_AUTHPRIV },
173 #endif
174 #ifdef LOG_CRON
175 { "cron", LOG_CRON },
176 #endif
177 #ifdef LOG_DAEMON
178 { "daemon", LOG_DAEMON },
179 #endif
180 #ifdef LOG_FTP
181 { "ftp", LOG_FTP },
182 #endif
183 #ifdef LOG_KERN
184 { "kern", LOG_KERN },
185 #endif
186 #ifdef LOG_LPR
187 { "lpr", LOG_LPR },
188 #endif
189 #ifdef LOG_MAIL
190 { "mail", LOG_MAIL },
191 #endif
192 #ifdef LOG_NEWS
193 { "news", LOG_NEWS },
194 #endif
195 #ifdef LOG_SYSLOG
196 { "syslog", LOG_SYSLOG },
197 #endif
198 #ifdef LOG_USER
199 { "user", LOG_USER },
200 #endif
201 #ifdef LOG_UUCP
202 { "uucp", LOG_UUCP },
203 #endif
204 #ifdef LOG_LOCAL0
205 { "local0", LOG_LOCAL0 },
206 #endif
207 #ifdef LOG_LOCAL1
208 { "local1", LOG_LOCAL1 },
209 #endif
210 #ifdef LOG_LOCAL2
211 { "local2", LOG_LOCAL2 },
212 #endif
213 #ifdef LOG_LOCAL3
214 { "local3", LOG_LOCAL3 },
215 #endif
216 #ifdef LOG_LOCAL4
217 { "local4", LOG_LOCAL4 },
218 #endif
219 #ifdef LOG_LOCAL5
220 { "local5", LOG_LOCAL5 },
221 #endif
222 #ifdef LOG_LOCAL6
223 { "local6", LOG_LOCAL6 },
224 #endif
225 #ifdef LOG_LOCAL7
226 { "local7", LOG_LOCAL7 },
227 #endif
228 { NULL }
231 static void
232 log_open_syslog (Log_method *lm, const char *progname, char *fname,
233 char *extra_args)
235 int logopt = LOG_PID | LOG_NDELAY;
236 int facility = LOG_DAEMON;
237 char *opt = NULL;
238 char *facility_str = NULL;
240 opt = extra_args;
241 if (opt) {
242 facility_str = opt;
243 strsep (&facility_str, ":");
245 logopt = parse_flags (opt, syslog_opt_units, logopt);
246 if (logopt < 0) {
247 fprintf (stderr, "log_open: error parsing syslog "
248 "optional flags: %s\n", opt);
249 print_flags_table (syslog_opt_units, stderr);
250 exit (1);
253 if (facility_str) {
254 struct units *best_match = NULL, *u = syslog_facility_units;
255 int len = strlen(facility_str);
257 while (u->name) {
258 if (strcasecmp(u->name, facility_str) == 0) {
259 best_match = u;
260 break;
262 if (strncasecmp(u->name, facility_str, len) == 0) {
263 if (best_match)
264 errx (1, "log_open: log facility %s is ambiguous",
265 facility_str);
266 best_match = u;
268 u++;
270 if (best_match == NULL)
271 errx (1, "log_open: unknown facility %s", facility_str);
272 facility = u->mult;
275 openlog (progname, logopt, facility);
278 #if HAVE_VSYSLOG
280 static void
281 log_vprint_syslog (Log_method *lm, char *fmt, va_list args)
283 vsyslog (LOG_NOTICE, fmt, args);
285 #endif /* HAVE_VSYSLOG */
287 static void
288 log_print_syslog (Log_method *lm, char *str)
290 syslog (LOG_NOTICE, "%s", str);
293 static void
294 log_close_syslog (Log_method *lm)
296 closelog ();
299 #endif /* HAVE_SYSLOG */
301 static int
302 file_parse_extra(FILE *f, char *extra_args)
304 int flags = 0;
305 char *str;
306 if (extra_args == NULL)
307 return 0;
308 do {
309 if (strlen(extra_args) == 0)
310 return flags;
312 str = strsep(&extra_args, ":");
313 if (extra_args) {
314 *extra_args = '\0';
315 extra_args++;
317 if (strncasecmp(str, "notime", 6) == 0)
318 flags |= LOGFILE_NO_TIME;
319 else
320 fprintf (f, "unknown flag: `%s'\n", str);
321 } while (extra_args != NULL);
323 return flags;
326 static void
327 log_open_file_common(struct log_method_file_data *data,
328 const char *progname, char *extra_args)
330 if (progname != NULL)
331 data->progname = strdup(progname);
332 else
333 progname = "unknown-program";
334 if (data->progname == NULL)
335 data->progname = "out of memory";
336 data->flags = file_parse_extra(data->f, extra_args);
339 static void
340 log_open_stderr (Log_method *lm, const char *progname, char *fname,
341 char *extra_args)
343 struct log_method_file_data *data;
344 data = malloc(sizeof(*data));
345 if (data == NULL)
346 errx (1, "log_open_stderr: failed to malloc");
347 lm->data.v = data;
349 data->f = stderr;
350 log_open_file_common(data, progname, extra_args);
353 static void
354 log_open_file (Log_method *lm, const char *progname, char *fname,
355 char *extra_args)
357 struct log_method_file_data *data;
358 data = malloc(sizeof(*data));
359 if (data == NULL)
360 errx (1, "log_open_stderr: failed to malloc");
361 lm->data.v = data;
363 data->f = fopen (fname, "a");
364 if (data->f == NULL)
365 data->f = stderr;
366 log_open_file_common(data, progname, extra_args);
369 static void
370 log_printf_file(Log_method *lm, char *fmt, ...)
372 va_list args;
374 va_start (args, fmt);
375 log_vprint_file(lm, fmt, args);
376 va_end (args);
379 static void
380 log_print_file(Log_method *lm, char *str)
382 log_printf_file(lm, "%s", str);
385 static void
386 log_vprint_file (Log_method *lm, char *fmt, va_list args)
388 struct timeval tv = { 0, 0 };
389 char time[128];
390 time_t t;
391 struct log_method_file_data *data = lm->data.v;
392 FILE *f = data->f;
394 if ((data->flags & LOGFILE_NO_TIME) == 0) {
395 struct tm tm;
396 gettimeofday(&tv, NULL);
397 t = tv.tv_sec;
398 strftime(time, sizeof(time), "%Y-%m-%d %H:%M:%S %Z",
399 localtime_r(&t, &tm));
400 time[sizeof(time)-1] = '\0';
401 fprintf (f, "%s: ", time);
404 fprintf (f, "%s: ", data->progname);
405 vfprintf (f, fmt, args);
406 putc ('\n', f);
407 fflush (f);
410 static void
411 log_close_file (Log_method *lm)
413 struct log_method_file_data *data = lm->data.v;
414 fclose(data->f);
415 free (data);
418 Log_method *
419 log_open (const char *progname, char *fname)
421 int i;
422 Log_method *logm;
423 char *name, *extra;
425 name = strdup(fname);
426 if (name == NULL)
427 return NULL;
429 logm = (Log_method *)malloc (sizeof(Log_method));
430 if (logm == NULL) {
431 free (name);
432 return logm;
434 for (i = 0; i < sizeof(special_names) / sizeof(*special_names);
435 ++i) {
436 int len = 0;
437 if (special_names[i].name)
438 len = strlen(special_names[i].name);
439 if (special_names[i].name == NULL
440 || (strncmp (special_names[i].name, fname, len) == 0 &&
441 (special_names[i].name[len] == '\0'
442 || special_names[i].name[len] == ':'))) {
443 *logm = special_names[i];
444 break;
447 extra = name;
448 strsep(&extra, ":");
449 logm->num_units = 0;
450 logm->units = NULL;
451 (*logm->open)(logm, progname, name, extra);
452 free (name);
453 return logm;
456 log_flags
457 log_setflags(Log_method *method, log_flags flags)
459 log_flags oldflags;
461 oldflags = method->flags;
462 method->flags = flags;
463 return oldflags;
466 log_flags
467 log_getflags(Log_method *method)
469 return method->flags;
472 void
473 log_set_mask (Log_unit *logu, unsigned m)
475 logu->mask = m;
478 unsigned
479 log_get_mask (Log_unit *unit)
481 return unit->mask;
484 static void
485 _internal_vlog (Log_method *method, const char *fmt, va_list args)
487 if (method->vprint && (method->flags & LOG_CPU_USAGE) == 0)
488 (*method->vprint)(method, (char *) fmt, args);
489 else {
490 char *buf;
492 vasprintf (&buf, fmt, args);
494 if (buf != NULL) {
495 #ifdef HAVE_GETRUSAGE
496 if (method->flags & LOG_CPU_USAGE) {
497 struct rusage usage;
498 int ret;
499 char *rbuf = NULL;
501 ret = getrusage(RUSAGE_SELF, &usage);
502 if (ret == 0) {
503 asprintf(&rbuf, "s: %d.%d u: %d.%d",
504 (int)usage.ru_stime.tv_sec,
505 (int)usage.ru_stime.tv_usec,
506 (int)usage.ru_utime.tv_sec,
507 (int)usage.ru_utime.tv_usec);
508 if (rbuf) {
509 char *buf2;
511 asprintf(&buf2, "%s %s", buf, rbuf);
512 if (buf2) {
513 free(buf);
514 buf = buf2;
516 free(rbuf);
520 #endif /* HAVE_GETRUSAGE */
521 (*method->print)(method, buf);
522 } else
523 (*method->print)(method, "not enough memory to print");
524 free(buf);
528 static void
529 _internal_log (Log_method *method, const char *fmt, ...)
531 va_list args;
533 va_start (args, fmt);
534 _internal_vlog(method, fmt, args);
535 va_end (args);
538 void
539 log_vlog(Log_unit *unit, unsigned level, const char *fmt, va_list args)
541 if (level & unit->mask)
542 _internal_vlog (unit->method, fmt, args);
546 void
547 log_log (Log_unit *logu, unsigned level, const char *fmt, ...)
549 va_list args;
551 va_start (args, fmt);
552 log_vlog(logu, level, fmt, args);
553 va_end (args);
556 void
557 log_close (Log_method *method)
559 int i;
560 if (method->close)
561 (*method->close)(method);
562 for (i = 0 ; i < method->num_units; i++)
563 log_unit_free (method, method->units[i]);
564 free (method->units);
565 method->units = NULL;
566 free (method);
569 Log_unit *
570 log_unit_init (Log_method *method, const char *name, struct units *unit,
571 unsigned long default_mask)
573 Log_unit *u, **list;
575 u = malloc (sizeof(Log_unit));
576 if (u == NULL)
577 return NULL;
578 list = realloc (method->units,
579 (method->num_units + 1) * sizeof(Log_unit *));
580 if (list == NULL) {
581 free (u);
582 return NULL;
584 method->units = list;
585 method->units[method->num_units] = u;
586 method->num_units += 1;
588 u->method = method;
589 u->name = estrdup (name);
590 u->unit = unit;
591 u->mask = default_mask;
592 return u;
595 void
596 log_unit_free (Log_method *method, Log_unit *logu)
598 Log_unit **list;
599 int i;
601 for (i = 0; i < method->num_units; i++)
602 if (logu == method->units[method->num_units])
603 break;
604 if (i < method->num_units - 1)
605 memmove (&method->units[i], &method->units[i+1],
606 method->num_units - i);
608 method->num_units -= 1;
609 list = realloc (method->units, method->num_units * sizeof(Log_unit *));
610 if (list == NULL)
611 abort();
612 method->units = list;
614 free (logu->name);
615 assert (logu->method == method);
616 logu->name = NULL;
617 logu->unit = NULL;
618 logu->mask = 0;
619 free (logu);
622 static int
623 parse_word (Log_method *m, char **str, Log_unit **u, char **log_str)
625 int j;
626 char *first;
628 if (**str == '\0') return 1;
629 while (**str != '\0' && (isspace((unsigned char)**str) || **str == ';'))
630 (*str)++;
631 if (**str == '\0') return 1;
633 first = *str;
634 while (**str != '\0' && !isspace((unsigned char)**str) && **str != ':')
635 (*str)++;
636 if (**str == ':') {
637 int best_fit = -1;
638 int str_len;
639 **str = '\0';
640 (*str)++;
641 str_len = strlen(first);
642 for (j = 0; j < m->num_units; j++) {
643 if (strcasecmp(m->units[j]->name, first) == 0)
644 break;
645 if (strncasecmp(m->units[j]->name, first, str_len) == 0) {
646 if (best_fit != -1)
647 return 1;
648 best_fit = j;
651 if (j == m->num_units) {
652 if (best_fit != -1)
653 *u = m->units[best_fit];
654 else
655 return 1;
656 } else
657 *u = m->units[j];
658 *log_str = *str;
659 } else {
660 *u = NULL;
661 *log_str = first;
663 while (**str != '\0' && **str != ';')
664 (*str)++;
665 if (**str == '\0')
666 return 0;
667 **str = '\0';
668 (*str)++;
669 return 0;
672 static int
673 unit_parse_flags (const char *log_str, struct log_unit *unit)
675 int ret;
676 ret = parse_flags (log_str, unit->unit, log_get_mask(unit));
677 if (ret < 0)
678 return ret;
679 log_set_mask (unit, ret);
680 return 0;
683 void
684 log_set_mask_str (Log_method *method, Log_unit *default_unit, const char *str)
686 char *log_str, *ptr, *str2;
687 Log_unit *unit = NULL;
688 int ret;
690 str2 = ptr = estrdup (str);
691 while (parse_word (method, &ptr, &unit, &log_str) == 0) {
692 if (unit || default_unit) {
693 if ((unit && default_unit) && unit != default_unit)
694 _internal_log (method,
695 "log_set_mask_str: default with unit string"
696 "%s:%s", unit->name, log_str);
697 if (unit == NULL)
698 unit = default_unit;
699 ret = unit_parse_flags (log_str, unit);
700 if (ret)
701 _internal_log (unit->method,
702 "log error parsing: %s:%s\n",
703 unit->name, log_str);
704 unit = NULL;
705 } else {
706 int i;
707 ret = 1;
708 /* If something matches, be merry */
709 for (i = 0; i < method->num_units; i++) {
710 if (unit_parse_flags (log_str, method->units[i]) != -1)
711 ret = 0;
713 if (ret)
714 _internal_log (method,
715 "log error parsing: %s\n",
716 log_str);
719 free (str2);
722 #define UPDATESZ(str,len,update) \
723 do { (str) += (update); (len) -= min((len),(update)); } while (0)
725 static size_t
726 _print_unit (Log_unit *unit, char *buf, size_t sz)
728 size_t ret, orig_sz = sz;
729 ret = snprintf (buf, sz, "%s:", unit->name);
730 if (ret == -1)
731 ret = 0;
732 else if (ret >= sz)
733 ret = sz - 1;
734 UPDATESZ(buf,sz,ret);
735 ret = unparse_flags (log_get_mask (unit), unit->unit, buf, sz);
736 UPDATESZ(buf,sz,ret);
737 return orig_sz - sz;
740 size_t
741 log_mask2str (Log_method *method, Log_unit *unit, char *buf, size_t sz)
743 size_t ret, orig_sz = sz;
744 int i, printed = 0;
746 if (sz) buf[0] = '\0';
748 if (unit)
749 return _print_unit (unit, buf, sz);
751 for (i = 0; i < method->num_units; i++) {
752 if (log_get_mask (method->units[i])) {
753 if (printed) {
754 ret = snprintf (buf, sz, ";");
755 if (ret == -1)
756 ret = 0;
757 else if (ret >= sz)
758 ret = sz - 1;
759 UPDATESZ(buf,sz,ret);
761 ret = _print_unit (method->units[i], buf, sz);
762 UPDATESZ(buf,sz,ret);
763 printed = 1;
766 return orig_sz - sz;
769 #undef UPDATESZ