cosmetics
[radsecproxy.git] / debug.c
1 /*
2  * Copyright (C) 2007 Stig Venaas <venaas@uninett.no>
3  * Copyright (C) 2010 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 != FTICKS_LOG) {
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 == FTICKS_LOG) {
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 == FTICKS_LOG)
111                 fticks_syslogfacility = facvals[i];
112             else
113                 debug_syslogfacility = facvals[i];
114         } else {
115             if (log_type == FTICKS_LOG)
116                 fticks_syslogfacility = 0;
117             else
118                 debug_syslogfacility = LOG_DAEMON;
119         }
120         if (log_type == FTICKS_LOG) {
121             if (fticks_syslogfacility && !debug_syslogfacility) {
122                 openlog(debug_ident, LOG_PID, fticks_syslogfacility);
123             }
124         } else {
125             openlog(debug_ident, LOG_PID, debug_syslogfacility);
126         }
127         return 1;
128     }
129     debug(DBG_ERR, "Unknown log destination, exiting %s", dest);
130     exit(1);
131 }
132
133 void debug_reopen_log() {
134     extern int errno;
135
136     /* not a file, noop, return success */
137     if (!debug_filepath) {
138         debug(DBG_ERR, "skipping reopen");
139         return;
140     }
141
142     if (debug_file != stderr)
143         fclose(debug_file);
144
145     debug_file = fopen(debug_filepath, "a");
146     if (debug_file)
147         debug(DBG_ERR, "Reopened logfile %s", debug_filepath);
148     else {
149         debug_file = stderr;
150         debug(DBG_ERR, "Failed to open logfile %s, using stderr\n%s",
151               debug_filepath, strerror(errno));
152     }
153     setvbuf(debug_file, NULL, _IONBF, 0);
154 }
155
156 void debug_logit(uint8_t level, const char *format, va_list ap) {
157     struct timeval now;
158     char *timebuf;
159     int priority;
160
161     if (debug_syslogfacility) {
162         switch (level) {
163         case DBG_DBG:
164             priority = LOG_DEBUG;
165             break;
166         case DBG_INFO:
167             priority = LOG_INFO;
168             break;
169         case DBG_NOTICE:
170             priority = LOG_NOTICE;
171             break;
172         case DBG_WARN:
173             priority = LOG_WARNING;
174             break;
175         case DBG_ERR:
176             priority = LOG_ERR;
177             break;
178         default:
179             priority = LOG_DEBUG;
180         }
181         vsyslog(priority, format, ap);
182     } else {
183         if (debug_timestamp && (timebuf = malloc(256))) {
184             gettimeofday(&now, NULL);
185             ctime_r(&now.tv_sec, timebuf);
186             timebuf[strlen(timebuf) - 1] = '\0';
187             fprintf(debug_file, "%s: ", timebuf + 4);
188             free(timebuf);
189         }
190         vfprintf(debug_file, format, ap);
191         fprintf(debug_file, "\n");
192     }
193 }
194
195 void debug(uint8_t level, char *format, ...) {
196     va_list ap;
197     if (level < debug_level)
198         return;
199     va_start(ap, format);
200     debug_logit(level, format, ap);
201     va_end(ap);
202 }
203
204 void debugx(int status, uint8_t level, char *format, ...) {
205     if (level >= debug_level) {
206         va_list ap;
207         va_start(ap, format);
208         debug_logit(level, format, ap);
209         va_end(ap);
210     }
211     exit(status);
212 }
213
214 void debugerrno(int err, uint8_t level, char *format, ...) {
215     if (level >= debug_level) {
216         va_list ap;
217         size_t len = strlen(format);
218         char *tmp = malloc(len + 1024 + 2);
219         assert(tmp);
220         strcpy(tmp, format);
221         tmp[len++] = ':';
222         tmp[len++] = ' ';
223         if (strerror_r(err, tmp + len, 1024))
224             tmp = format;
225         va_start(ap, format);
226         debug_logit(level, tmp, ap);
227         va_end(ap);
228     }
229 }
230
231 void debugerrnox(int err, uint8_t level, char *format, ...) {
232     if (level >= debug_level) {
233         va_list ap;
234         va_start(ap, format);
235         debugerrno(err, level, format, ap);
236         va_end(ap);
237     }
238     exit(err);
239 }
240
241 #if defined(WANT_FTICKS)
242 void fticks_debug(const char *format, ...) {
243     int priority;
244     va_list ap;
245     va_start(ap, format);
246     if (!debug_syslogfacility && !fticks_syslogfacility)
247         debug_logit(0xff, format, ap);
248     else {
249         priority = LOG_DEBUG | fticks_syslogfacility;
250         vsyslog(priority, format, ap);
251         va_end(ap);
252     }
253 }
254 #endif
255 /* Local Variables: */
256 /* c-file-style: "stroustrup" */
257 /* End: */