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