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