radsecproxy-1.6.5.
[libradsec.git] / debug.c
1 /*
2  * Copyright (C) 2007 Stig Venaas <venaas@uninett.no>
3  * Copyright (C) 2010,2011 NORDUnet A/S
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  */
9
10 #ifndef SYS_SOLARIS9
11 #include <stdint.h>
12 #endif
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdarg.h>
16 #include <string.h>
17 #include <strings.h>
18 #include <time.h>
19 #include <sys/time.h>
20 #include <syslog.h>
21 #include <errno.h>
22 #include <assert.h>
23 #include "debug.h"
24 #include "util.h"
25
26 static char *debug_ident = NULL;
27 static uint8_t debug_level = DBG_INFO;
28 static char *debug_filepath = NULL;
29 static FILE *debug_file = NULL;
30 static int debug_syslogfacility = 0;
31 #if defined(WANT_FTICKS)
32 static int fticks_syslogfacility = 0;
33 #endif
34 static uint8_t debug_timestamp = 0;
35
36 void debug_init(char *ident) {
37     debug_file = stderr;
38     setvbuf(debug_file, NULL, _IONBF, 0);
39     debug_ident = ident;
40 }
41
42 void debug_set_level(uint8_t level) {
43     switch (level) {
44     case 1:
45         debug_level = DBG_ERR;
46         return;
47     case 2:
48         debug_level = DBG_WARN;
49         return;
50     case 3:
51         debug_level = DBG_NOTICE;
52         return;
53     case 4:
54         debug_level = DBG_INFO;
55         return;
56     case 5:
57         debug_level = DBG_DBG;
58         return;
59     }
60 }
61
62 void debug_timestamp_on() {
63     debug_timestamp = 1;
64 }
65
66 uint8_t debug_get_level() {
67     return debug_level;
68 }
69
70 int debug_set_destination(char *dest, int log_type) {
71     static const char *facstrings[] = {
72         "LOG_DAEMON", "LOG_MAIL", "LOG_USER", "LOG_LOCAL0",
73         "LOG_LOCAL1", "LOG_LOCAL2", "LOG_LOCAL3", "LOG_LOCAL4",
74         "LOG_LOCAL5", "LOG_LOCAL6", "LOG_LOCAL7", NULL };
75     static const int facvals[] = {
76         LOG_DAEMON, LOG_MAIL, LOG_USER, LOG_LOCAL0,
77         LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4,
78         LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 };
79     extern int errno;
80     int i;
81
82     if (!strncasecmp(dest, "file:///", 8)) {
83         if (log_type != LOG_TYPE_FTICKS) {
84             debug_filepath = stringcopy(dest + 7, 0);
85             debug_file = fopen(debug_filepath, "a");
86             if (!debug_file) {
87                 debug_file = stderr;
88                 debugx(1, DBG_ERR, "Failed to open logfile %s\n%s",
89                        debug_filepath, strerror(errno));
90             }
91             setvbuf(debug_file, NULL, _IONBF, 0);
92         } else {
93             debug(DBG_WARN, "FTicksSyslogFacility starting with file:/// not "
94                   "permitted, assuming default F-Ticks destination");
95         }
96         return 1;
97     }
98     if (!strncasecmp(dest, "x-syslog://", 11) || log_type == LOG_TYPE_FTICKS) {
99         if (!strncasecmp(dest, "x-syslog://", 11)) {
100             dest += 11;
101             if (*dest == '/')
102                 dest++;
103         }
104         if (*dest) {
105             for (i = 0; facstrings[i]; i++)
106                 if (!strcasecmp(dest, facstrings[i]))
107                     break;
108             if (!facstrings[i])
109                 debugx(1, DBG_ERR, "Unknown syslog facility %s", dest);
110             if (log_type != LOG_TYPE_FTICKS)
111                 debug_syslogfacility = facvals[i];
112 #if defined(WANT_FTICKS)
113             else if (log_type == LOG_TYPE_FTICKS)
114                 fticks_syslogfacility = facvals[i];
115 #endif
116         } else {
117             if (log_type != LOG_TYPE_FTICKS)
118                 debug_syslogfacility = LOG_DAEMON;
119 #if defined(WANT_FTICKS)
120             else if (log_type == LOG_TYPE_FTICKS)
121                 fticks_syslogfacility = 0;
122 #endif
123         }
124         openlog(debug_ident, LOG_PID, debug_syslogfacility);
125         return 1;
126     }
127     debug(DBG_ERR, "Unknown log destination, exiting %s", dest);
128     exit(1);
129 }
130
131 void debug_reopen_log() {
132     extern int errno;
133
134     /* not a file, noop, return success */
135     if (!debug_filepath) {
136         debug(DBG_ERR, "skipping reopen");
137         return;
138     }
139
140     if (debug_file != stderr)
141         fclose(debug_file);
142
143     debug_file = fopen(debug_filepath, "a");
144     if (debug_file)
145         debug(DBG_ERR, "Reopened logfile %s", debug_filepath);
146     else {
147         debug_file = stderr;
148         debug(DBG_ERR, "Failed to open logfile %s, using stderr\n%s",
149               debug_filepath, strerror(errno));
150     }
151     setvbuf(debug_file, NULL, _IONBF, 0);
152 }
153
154 void debug_logit(uint8_t level, const char *format, va_list ap) {
155     struct timeval now;
156     char *timebuf;
157     int priority;
158
159     if (debug_syslogfacility) {
160         switch (level) {
161         case DBG_DBG:
162             priority = LOG_DEBUG;
163             break;
164         case DBG_INFO:
165             priority = LOG_INFO;
166             break;
167         case DBG_NOTICE:
168             priority = LOG_NOTICE;
169             break;
170         case DBG_WARN:
171             priority = LOG_WARNING;
172             break;
173         case DBG_ERR:
174             priority = LOG_ERR;
175             break;
176         default:
177             priority = LOG_DEBUG;
178         }
179         vsyslog(priority, format, ap);
180     } else {
181         if (debug_timestamp && (timebuf = malloc(256))) {
182             gettimeofday(&now, NULL);
183             ctime_r(&now.tv_sec, timebuf);
184             timebuf[strlen(timebuf) - 1] = '\0';
185             fprintf(debug_file, "%s: ", timebuf + 4);
186             free(timebuf);
187         }
188         vfprintf(debug_file, format, ap);
189         fprintf(debug_file, "\n");
190     }
191 }
192
193 void debug(uint8_t level, char *format, ...) {
194     va_list ap;
195     if (level < debug_level)
196         return;
197     va_start(ap, format);
198     debug_logit(level, format, ap);
199     va_end(ap);
200 }
201
202 void debugx(int status, uint8_t level, char *format, ...) {
203     if (level >= debug_level) {
204         va_list ap;
205         va_start(ap, format);
206         debug_logit(level, format, ap);
207         va_end(ap);
208     }
209     exit(status);
210 }
211
212 void debugerrno(int err, uint8_t level, char *format, ...) {
213     if (level >= debug_level) {
214         va_list ap;
215         size_t len = strlen(format);
216         char *tmp = malloc(len + 1024 + 2);
217         assert(tmp);
218         strcpy(tmp, format);
219         tmp[len++] = ':';
220         tmp[len++] = ' ';
221         if (strerror_r(err, tmp + len, 1024))
222             tmp = format;
223         va_start(ap, format);
224         debug_logit(level, tmp, ap);
225         va_end(ap);
226     }
227 }
228
229 void debugerrnox(int err, uint8_t level, char *format, ...) {
230     if (level >= debug_level) {
231         va_list ap;
232         va_start(ap, format);
233         debugerrno(err, level, format, ap);
234         va_end(ap);
235     }
236     exit(err);
237 }
238
239 #if defined(WANT_FTICKS)
240 void fticks_debug(const char *format, ...) {
241     int priority;
242     va_list ap;
243     va_start(ap, format);
244     if (!debug_syslogfacility && !fticks_syslogfacility)
245         debug_logit(0xff, format, ap);
246     else {
247         priority = LOG_DEBUG | fticks_syslogfacility;
248         vsyslog(priority, format, ap);
249         va_end(ap);
250     }
251 }
252 #endif
253 /* Local Variables: */
254 /* c-file-style: "stroustrup" */
255 /* End: */