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