1 /*
2  * log.c: Miscellaneous logging functions
3  *
4  * Copyright (C) 2001, 2002  Juha Yrjölä <juha.yrjola@iki.fi>
5  * Copyright (C) 2003  Antti Tapaninen <aet@cc.hut.fi>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 #if HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <time.h>
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #ifdef HAVE_SYS_TIME_H
36 #include <sys/time.h>
37 #endif
38 #ifdef HAVE_IO_H
39 #include <io.h>
40 #endif
41 #ifdef HAVE_PTHREAD
42 #include <pthread.h>
43 #endif
44 #ifdef _WIN32
45 #include <windows.h>
46 #endif
47 
48 #include "internal.h"
49 
50 static void sc_do_log_va(sc_context_t *ctx, int level, const char *file, int line, const char *func, int color, const char *format, va_list args);
51 static int sc_color_fprintf_va(int colors, struct sc_context *ctx, FILE * stream, const char *format, va_list args);
52 
sc_do_log(sc_context_t * ctx,int level,const char * file,int line,const char * func,const char * format,...)53 void sc_do_log(sc_context_t *ctx, int level, const char *file, int line, const char *func, const char *format, ...)
54 {
55 	va_list ap;
56 
57 	va_start(ap, format);
58 	sc_do_log_va(ctx, level, file, line, func, 0, format, ap);
59 	va_end(ap);
60 }
61 
sc_do_log_color(sc_context_t * ctx,int level,const char * file,int line,const char * func,int color,const char * format,...)62 void sc_do_log_color(sc_context_t *ctx, int level, const char *file, int line, const char *func, int color, const char *format, ...)
63 {
64 	va_list ap;
65 
66 	va_start(ap, format);
67 	sc_do_log_va(ctx, level, file, line, func, color, format, ap);
68 	va_end(ap);
69 }
70 
sc_do_log_noframe(sc_context_t * ctx,int level,const char * format,va_list args)71 void sc_do_log_noframe(sc_context_t *ctx, int level, const char *format, va_list args)
72 {
73 	sc_do_log_va(ctx, level, NULL, 0, NULL, 0, format, args);
74 }
75 
sc_do_log_va(sc_context_t * ctx,int level,const char * file,int line,const char * func,int color,const char * format,va_list args)76 static void sc_do_log_va(sc_context_t *ctx, int level, const char *file, int line, const char *func, int color, const char *format, va_list args)
77 {
78 #ifdef _WIN32
79 	SYSTEMTIME st;
80 #else
81 	struct tm *tm;
82 	struct timeval tv;
83 	char time_string[40];
84 #endif
85 
86 	if (!ctx || ctx->debug < level)
87 		return;
88 
89 #ifdef _WIN32
90 	/* In Windows, file handles can not be shared between DLL-s, each DLL has a
91 	 * separate file handle table. Make sure we always have a valid file
92 	 * descriptor. */
93 	if (sc_ctx_log_to_file(ctx, ctx->debug_filename) < 0)
94 		return;
95 #endif
96 	if (ctx->debug_file == NULL)
97 		return;
98 
99 #ifdef _WIN32
100 	GetLocalTime(&st);
101 	sc_color_fprintf(SC_COLOR_FG_GREEN|SC_COLOR_BOLD,
102 			ctx, ctx->debug_file,
103 			"P:%lu; T:%lu",
104 			(unsigned long)GetCurrentProcessId(),
105 			(unsigned long)GetCurrentThreadId());
106 	sc_color_fprintf(SC_COLOR_FG_GREEN,
107 			ctx, ctx->debug_file,
108 			" %i-%02i-%02i %02i:%02i:%02i.%03i",
109 			st.wYear, st.wMonth, st.wDay,
110 			st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
111 #else
112 	sc_color_fprintf(SC_COLOR_FG_GREEN|SC_COLOR_BOLD,
113 			ctx, ctx->debug_file,
114 			"P:%lu; T:0x%lu",
115 			(unsigned long)getpid(),
116 			(unsigned long)pthread_self());
117 	gettimeofday (&tv, NULL);
118 	tm = localtime (&tv.tv_sec);
119 	strftime (time_string, sizeof(time_string), "%H:%M:%S", tm);
120 	sc_color_fprintf(SC_COLOR_FG_GREEN,
121 			ctx, ctx->debug_file,
122 			" %s.%03ld",
123 			time_string,
124 			(long)tv.tv_usec / 1000);
125 #endif
126 
127 	sc_color_fprintf(SC_COLOR_FG_YELLOW,
128 			ctx, ctx->debug_file,
129 			" [");
130 	sc_color_fprintf(SC_COLOR_FG_YELLOW|SC_COLOR_BOLD,
131 			ctx, ctx->debug_file,
132 			"%s",
133 			ctx->app_name);
134 	sc_color_fprintf(SC_COLOR_FG_YELLOW,
135 			ctx, ctx->debug_file,
136 			"] ");
137 
138 	if (file != NULL) {
139 		sc_color_fprintf(SC_COLOR_FG_YELLOW,
140 				ctx, ctx->debug_file,
141 				"%s:%d:%s: ",
142 				file, line, func ? func : "");
143 	}
144 
145 	sc_color_fprintf_va(color, ctx, ctx->debug_file, format, args);
146 	if (strlen(format) == 0 || format[strlen(format) - 1] != '\n')
147 		sc_color_fprintf(color, ctx, ctx->debug_file, "\n");
148 	fflush(ctx->debug_file);
149 
150 #ifdef _WIN32
151 	if (ctx->debug_file && (ctx->debug_file != stderr && ctx->debug_file != stdout))
152 		fclose(ctx->debug_file);
153 	ctx->debug_file = NULL;
154 #endif
155 }
156 
_sc_debug(struct sc_context * ctx,int level,const char * format,...)157 void _sc_debug(struct sc_context *ctx, int level, const char *format, ...)
158 {
159 	va_list ap;
160 
161 	va_start(ap, format);
162 	sc_do_log_va(ctx, level, NULL, 0, NULL, 0, format, ap);
163 	va_end(ap);
164 }
165 
_sc_log(struct sc_context * ctx,const char * format,...)166 void _sc_log(struct sc_context *ctx, const char *format, ...)
167 {
168 	va_list ap;
169 
170 	va_start(ap, format);
171 	sc_do_log_va(ctx, SC_LOG_DEBUG_NORMAL, NULL, 0, NULL, 0, format, ap);
172 	va_end(ap);
173 }
174 
is_a_tty(FILE * fp)175 static int is_a_tty(FILE *fp)
176 {
177 	if (fp != NULL) {
178 		int fd = fileno(fp);
179 		if (fd >= 0) {
180 #ifdef _WIN32
181 			HANDLE h = (HANDLE)_get_osfhandle(fd);
182 			if (h != INVALID_HANDLE_VALUE) {
183 				return GetFileType(h) == FILE_TYPE_CHAR;
184 			}
185 #else
186 			return isatty(fd);
187 #endif
188 		}
189 	}
190 	return 0;
191 }
192 
193 #ifdef _WIN32
194 #define set_color(sc_color, win_color, vt100_color) \
195 	do { if (colors & sc_color) { attr |= win_color; } } while (0)
196 #else
197 #define set_color(sc_color, win_color, vt100_color) \
198 	do { if (colors & sc_color) { fprintf(stream, vt100_color); } } while (0)
199 #endif
200 
sc_color_fprintf(int colors,struct sc_context * ctx,FILE * stream,const char * format,...)201 int sc_color_fprintf(int colors, struct sc_context *ctx, FILE * stream, const char * format, ...)
202 {
203 	int r;
204 	va_list ap;
205 
206 	va_start(ap, format);
207 	r = sc_color_fprintf_va(colors, ctx, stream, format, ap);
208 	va_end(ap);
209 
210 	return r;
211 }
212 
sc_color_fprintf_va(int colors,struct sc_context * ctx,FILE * stream,const char * format,va_list args)213 int sc_color_fprintf_va(int colors, struct sc_context *ctx, FILE * stream, const char *format, va_list args)
214 {
215 	int r;
216 #ifdef _WIN32
217 	WORD old_attr = 0;
218 	int fd = stream ? fileno(stream) : -1;
219 	HANDLE handle = fd >= 0 ? (HANDLE) _get_osfhandle(fd) : INVALID_HANDLE_VALUE;
220 #endif
221 
222 	if (!is_a_tty(stream))
223 		colors = 0;
224 
225 	if (colors && (!ctx || (!(ctx->flags & SC_CTX_FLAG_DISABLE_COLORS)))) {
226 #ifdef _WIN32
227 		WORD attr = 0;
228 		CONSOLE_SCREEN_BUFFER_INFO csbi;
229 		GetConsoleScreenBufferInfo(handle, &csbi);
230 		old_attr = csbi.wAttributes;
231 #endif
232 		set_color(SC_COLOR_FG_RED,
233 				FOREGROUND_RED,
234 				"\x1b[31m");
235 		set_color(SC_COLOR_FG_GREEN,
236 				FOREGROUND_GREEN,
237 				"\x1b[32m");
238 		set_color(SC_COLOR_FG_YELLOW,
239 				FOREGROUND_GREEN|FOREGROUND_RED,
240 				"\x1b[33m");
241 		set_color(SC_COLOR_FG_BLUE,
242 				FOREGROUND_BLUE,
243 				"\x1b[34m");
244 		set_color(SC_COLOR_FG_MAGENTA,
245 				FOREGROUND_BLUE|FOREGROUND_RED,
246 				"\x1b[35m");
247 		set_color(SC_COLOR_FG_CYAN,
248 				FOREGROUND_BLUE|FOREGROUND_GREEN,
249 				"\x1b[36m");
250 		set_color(SC_COLOR_BG_RED,
251 				FOREGROUND_RED,
252 				"\x1b[41m");
253 		set_color(SC_COLOR_BG_GREEN,
254 				BACKGROUND_GREEN,
255 				"\x1b[42m");
256 		set_color(SC_COLOR_BG_YELLOW,
257 				BACKGROUND_GREEN|BACKGROUND_RED,
258 				"\x1b[43m");
259 		set_color(SC_COLOR_BG_BLUE,
260 				BACKGROUND_BLUE,
261 				"\x1b[44m");
262 		set_color(SC_COLOR_BG_MAGENTA,
263 				BACKGROUND_BLUE|BACKGROUND_RED,
264 				"\x1b[45m");
265 		set_color(SC_COLOR_BG_CYAN,
266 				BACKGROUND_BLUE|BACKGROUND_GREEN,
267 				"\x1b[46m");
268 		set_color(SC_COLOR_BOLD,
269 				FOREGROUND_INTENSITY,
270 				"\x1b[1m");
271 #ifdef _WIN32
272 		SetConsoleTextAttribute(handle, attr);
273 #endif
274 	}
275 
276 	r = vfprintf(stream, format, args);
277 
278 	if (colors && (!ctx || (!(ctx->flags & SC_CTX_FLAG_DISABLE_COLORS)))) {
279 #ifdef _WIN32
280 		SetConsoleTextAttribute(handle, old_attr);
281 #else
282 		fprintf(stream, "\x1b[0m");
283 #endif
284 	}
285 
286 	return r;
287 }
288 
_sc_debug_hex(sc_context_t * ctx,int type,const char * file,int line,const char * func,const char * label,const u8 * data,size_t len)289 void _sc_debug_hex(sc_context_t *ctx, int type, const char *file, int line,
290 		const char *func, const char *label, const u8 *data, size_t len)
291 {
292 	size_t blen = len * 5 + 128;
293 	char *buf = malloc(blen);
294 	if (buf == NULL)
295 		return;
296 
297 	sc_hex_dump(data, len, buf, blen);
298 
299 	if (label)
300 		sc_do_log(ctx, type, file, line, func,
301 			"\n%s (%"SC_FORMAT_LEN_SIZE_T"u byte%s):\n%s",
302 			label, len, len==1?"":"s", buf);
303 	else
304 		sc_do_log(ctx, type, file, line, func,
305 			"%"SC_FORMAT_LEN_SIZE_T"u byte%s:\n%s",
306 			len, len==1?"":"s", buf);
307 
308 	free(buf);
309 }
310 
sc_hex_dump(const u8 * in,size_t count,char * buf,size_t len)311 void sc_hex_dump(const u8 * in, size_t count, char *buf, size_t len)
312 {
313 	char *p = buf;
314 	int lines = 0;
315 
316 	if (buf == NULL || (in == NULL && count != 0)) {
317 		return;
318 	}
319 	buf[0] = 0;
320 	if ((count * 5) > len)
321 		return;
322 	while (count) {
323 		char ascbuf[17];
324 		size_t i;
325 
326 		for (i = 0; i < count && i < 16; i++) {
327 			sprintf(p, "%02X ", *in);
328 			if (isprint(*in))
329 				ascbuf[i] = *in;
330 			else
331 				ascbuf[i] = '.';
332 			p += 3;
333 			in++;
334 		}
335 		count -= i;
336 		ascbuf[i] = 0;
337 		for (; i < 16 && lines; i++) {
338 			strcat(p, "   ");
339 			p += 3;
340 		}
341 		strcat(p, ascbuf);
342 		p += strlen(p);
343 		sprintf(p, "\n");
344 		p++;
345 		lines++;
346 	}
347 }
348 
349 const char *
sc_dump_hex(const u8 * in,size_t count)350 sc_dump_hex(const u8 * in, size_t count)
351 {
352 	static char dump_buf[0x1000];
353 	size_t ii, size = sizeof(dump_buf) - 0x10;
354 	size_t offs = 0;
355 
356 	memset(dump_buf, 0, sizeof(dump_buf));
357 	if (in == NULL)
358 		return dump_buf;
359 
360 	for (ii=0; ii<count; ii++) {
361 		if (ii && !(ii%16))   {
362 			if (!(ii%48))
363 				snprintf(dump_buf + offs, size - offs, "\n");
364 			else
365 				snprintf(dump_buf + offs, size - offs, " ");
366 			offs = strlen(dump_buf);
367 		}
368 
369 		snprintf(dump_buf + offs, size - offs, "%02X", *(in + ii));
370 		offs += 2;
371 
372 		if (offs > size)
373 			break;
374 	}
375 
376 	if (ii<count)
377 		snprintf(dump_buf + offs, sizeof(dump_buf) - offs, "....\n");
378 
379 	return dump_buf;
380 }
381 
382 const char *
sc_dump_oid(const struct sc_object_id * oid)383 sc_dump_oid(const struct sc_object_id *oid)
384 {
385 	static char dump_buf[SC_MAX_OBJECT_ID_OCTETS * 20];
386         size_t ii;
387 
388 	memset(dump_buf, 0, sizeof(dump_buf));
389 	if (oid)
390 		for (ii=0; ii<SC_MAX_OBJECT_ID_OCTETS && oid->value[ii] != -1; ii++)
391 			snprintf(dump_buf + strlen(dump_buf), sizeof(dump_buf) - strlen(dump_buf), "%s%i", (ii ? "." : ""), oid->value[ii]);
392 
393 	return dump_buf;
394 }
395