8bd513c0591f8731802d058d7c888b968b73dc8d
[strongswan.git] / src / libstrongswan / printf_hook.c
1 /*
2 * Copyright (C) 2009 Tobias Brunner
3 * Copyright (C) 2006-2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "printf_hook.h"
18
19 #include "utils.h"
20 #include "debug.h"
21
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <string.h>
25
26 typedef struct private_printf_hook_t private_printf_hook_t;
27 typedef struct printf_hook_handler_t printf_hook_handler_t;
28
29 #define PRINTF_BUF_LEN 8192
30 #define ARGS_MAX 3
31
32 /**
33 * private data of printf_hook
34 */
35 struct private_printf_hook_t {
36
37 /**
38 * public functions
39 */
40 printf_hook_t public;
41 };
42
43 /**
44 * struct with information about a registered handler
45 */
46 struct printf_hook_handler_t {
47
48 /**
49 * callback function
50 */
51 printf_hook_function_t hook;
52
53 /**
54 * number of arguments
55 */
56 int numargs;
57
58 /**
59 * types of the arguments
60 */
61 int argtypes[ARGS_MAX];
62
63 #ifdef USE_VSTR
64 /**
65 * name required for Vstr
66 */
67 char *name;
68 #endif
69 };
70
71 /* A-Z | 6 other chars | a-z */
72 #define NUM_HANDLERS 58
73 static printf_hook_handler_t *printf_hooks[NUM_HANDLERS];
74
75 #define SPEC_TO_INDEX(spec) ((int)(spec) - (int)'A')
76 #define IS_VALID_SPEC(spec) (SPEC_TO_INDEX(spec) > -1 && SPEC_TO_INDEX(spec) < NUM_HANDLERS)
77
78 #if !defined(USE_VSTR) && \
79 (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER))
80
81 /**
82 * Printf hook print function. This is actually of type "printf_function",
83 * however glibc does it typedef to function, but uclibc to a pointer.
84 * So we redefine it here.
85 */
86 static int custom_print(FILE *stream, const struct printf_info *info,
87 const void *const *args)
88 {
89 printf_hook_spec_t spec;
90 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)];
91 printf_hook_data_t data = {
92 .stream = stream,
93 };
94
95 spec.hash = info->alt;
96 spec.plus = info->showsign;
97 spec.minus = info->left;
98 spec.width = info->width;
99
100 return handler->hook(&data, &spec, args);
101 }
102
103 /**
104 * Printf hook arginfo function, which is actually of type
105 * "printf_arginfo_[size_]function".
106 */
107 static int custom_arginfo(const struct printf_info *info, size_t n, int *argtypes
108 #ifdef HAVE_PRINTF_SPECIFIER
109 , int *size
110 #endif
111 )
112 {
113 int i;
114 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)];
115
116 if (handler->numargs <= n)
117 {
118 for (i = 0; i < handler->numargs; ++i)
119 {
120 argtypes[i] = handler->argtypes[i];
121 }
122 }
123 /* we never set "size", as we have no user defined types */
124 return handler->numargs;
125 }
126
127 #else
128
129 #include <errno.h>
130 #include <unistd.h> /* for STDOUT_FILENO */
131
132 /**
133 * These are used below, whenever the public wrapper functions are called before
134 * initialization or after destruction.
135 */
136 #undef vprintf
137 #undef vfprintf
138 #undef vsnprintf
139
140 /**
141 * Vstr custom format specifier callback function.
142 */
143 static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec)
144 {
145 int i;
146 const void *args[ARGS_MAX];
147 printf_hook_spec_t spec;
148 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(fmt_spec->name[0])];
149 printf_hook_data_t data = {
150 .base = base,
151 .pos = pos,
152 };
153
154 for (i = 0; i < handler->numargs; i++)
155 {
156 switch(handler->argtypes[i])
157 {
158 case PRINTF_HOOK_ARGTYPE_INT:
159 args[i] = VSTR_FMT_CB_ARG_PTR(fmt_spec, i);
160 break;
161 case PRINTF_HOOK_ARGTYPE_POINTER:
162 args[i] = &VSTR_FMT_CB_ARG_PTR(fmt_spec, i);
163 break;
164 }
165 }
166
167 spec.hash = fmt_spec->fmt_hash;
168 spec.plus = fmt_spec->fmt_plus;
169 spec.minus = fmt_spec->fmt_minus;
170 spec.width = fmt_spec->fmt_field_width;
171
172 handler->hook(&data, &spec, args);
173 return 1;
174 }
175
176 /**
177 * Add a custom format handler to the given Vstr_conf object
178 */
179 static void vstr_fmt_add_handler(Vstr_conf *conf, printf_hook_handler_t *handler)
180 {
181 int *at = handler->argtypes;
182 switch(handler->numargs)
183 {
184 case 1:
185 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
186 VSTR_TYPE_FMT_END);
187 break;
188 case 2:
189 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
190 at[1], VSTR_TYPE_FMT_END);
191 break;
192 case 3:
193 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
194 at[1], at[2], VSTR_TYPE_FMT_END);
195 break;
196 }
197 }
198
199 /**
200 * Management of thread-specific Vstr_conf objects
201 */
202 #include <threading/thread_value.h>
203
204 static thread_value_t *vstr_conf = NULL;
205
206 static Vstr_conf *create_vstr_conf()
207 {
208 int i;
209 Vstr_conf *conf = vstr_make_conf();
210 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '%');
211 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_TYPE_GRPALLOC_CACHE,
212 VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR);
213 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, PRINTF_BUF_LEN);
214 for (i = 0; i < NUM_HANDLERS; ++i)
215 {
216 printf_hook_handler_t *handler = printf_hooks[i];
217 if (handler)
218 {
219 vstr_fmt_add_handler(conf, handler);
220 }
221 }
222 return conf;
223 }
224
225 static inline Vstr_conf *get_vstr_conf()
226 {
227 Vstr_conf *conf = NULL;
228 if (vstr_conf)
229 {
230 conf = (Vstr_conf*)vstr_conf->get(vstr_conf);
231 if (!conf)
232 {
233 conf = create_vstr_conf();
234 vstr_conf->set(vstr_conf, conf);
235 }
236 }
237 return conf;
238 }
239
240 /**
241 * Wrapper functions for printf and alike
242 */
243 int vstr_wrapper_printf(const char *format, ...)
244 {
245 int written;
246 va_list args;
247 va_start(args, format);
248 written = vstr_wrapper_vprintf(format, args);
249 va_end(args);
250 return written;
251 }
252 int vstr_wrapper_fprintf(FILE *stream, const char *format, ...)
253 {
254 int written;
255 va_list args;
256 va_start(args, format);
257 written = vstr_wrapper_vfprintf(stream, format, args);
258 va_end(args);
259 return written;
260 }
261 int vstr_wrapper_sprintf(char *str, const char *format, ...)
262 {
263 int written;
264 va_list args;
265 va_start(args, format);
266 written = vstr_wrapper_vsprintf(str, format, args);
267 va_end(args);
268 return written;
269 }
270 int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...)
271 {
272 int written;
273 va_list args;
274 va_start(args, format);
275 written = vstr_wrapper_vsnprintf(str, size, format, args);
276 va_end(args);
277 return written;
278 }
279 int vstr_wrapper_asprintf(char **str, const char *format, ...)
280 {
281 int written;
282 va_list args;
283 va_start(args, format);
284 written = vstr_wrapper_vasprintf(str, format, args);
285 va_end(args);
286 return written;
287 }
288 static inline int vstr_wrapper_vprintf_internal(Vstr_conf *conf, int fd,
289 const char *format,
290 va_list args)
291 {
292 int written;
293 Vstr_base *s = vstr_make_base(conf);
294 vstr_add_vfmt(s, 0, format, args);
295 written = s->len;
296 while (s->len)
297 {
298 if (!vstr_sc_write_fd(s, 1, s->len, fd, NULL))
299 {
300 if (errno != EAGAIN && errno != EINTR)
301 {
302 written -= s->len;
303 break;
304 }
305 }
306 }
307 vstr_free_base(s);
308 return written;
309 }
310 int vstr_wrapper_vprintf(const char *format, va_list args)
311 {
312 Vstr_conf *conf = get_vstr_conf();
313 if (conf)
314 {
315 return vstr_wrapper_vprintf_internal(conf, STDOUT_FILENO, format, args);
316 }
317 return vprintf(format, args);
318 }
319 int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list args)
320 {
321 Vstr_conf *conf = get_vstr_conf();
322 if (conf)
323 {
324 return vstr_wrapper_vprintf_internal(conf, fileno(stream), format,
325 args);
326 }
327 return vfprintf(stream, format, args);
328 }
329 static inline int vstr_wrapper_vsnprintf_internal(char *str, size_t size,
330 const char *format,
331 va_list args)
332 {
333 Vstr_conf *conf = get_vstr_conf();
334 if (conf)
335 {
336 int written;
337 Vstr_base *s = vstr_make_base(conf);
338 vstr_add_vfmt(s, 0, format, args);
339 written = s->len;
340 vstr_export_cstr_buf(s, 1, s->len, str, (size > 0) ? size : s->len + 1);
341 vstr_free_base(s);
342 return written;
343 }
344 return vsnprintf(str, size, format, args);
345 }
346 int vstr_wrapper_vsprintf(char *str, const char *format, va_list args)
347 {
348 return vstr_wrapper_vsnprintf_internal(str, 0, format, args);
349 }
350 int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format,
351 va_list args)
352 {
353 return (size > 0) ? vstr_wrapper_vsnprintf_internal(str, size, format, args) : 0;
354 }
355 int vstr_wrapper_vasprintf(char **str, const char *format, va_list args)
356 {
357 size_t len = 100;
358 int written;
359 *str = malloc(len);
360 while (TRUE)
361 {
362 va_list ac;
363 va_copy(ac, args);
364 written = vstr_wrapper_vsnprintf_internal(*str, len, format, ac);
365 va_end(ac);
366 if (written < len)
367 {
368 break;
369 }
370 len = written + 1;
371 *str = realloc(*str, len);
372 }
373 return written;
374 }
375 #endif
376
377 METHOD(printf_hook_t, add_handler, void,
378 private_printf_hook_t *this, char spec,
379 printf_hook_function_t hook, ...)
380 {
381 int i = -1;
382 printf_hook_handler_t *handler;
383 printf_hook_argtype_t argtype;
384 va_list args;
385
386 if (!IS_VALID_SPEC(spec))
387 {
388 DBG1(DBG_LIB, "'%c' is not a valid printf hook specifier, "
389 "not registered!", spec);
390 return;
391 }
392
393 handler = malloc_thing(printf_hook_handler_t);
394 handler->hook = hook;
395
396 va_start(args, hook);
397 while ((argtype = va_arg(args, printf_hook_argtype_t)) != PRINTF_HOOK_ARGTYPE_END)
398 {
399 if (++i >= ARGS_MAX)
400 {
401 DBG1(DBG_LIB, "Too many arguments for printf hook with "
402 "specifier '%c', not registered!", spec);
403 va_end(args);
404 free(handler);
405 return;
406 }
407 handler->argtypes[i] = argtype;
408 }
409 va_end(args);
410
411 handler->numargs = i + 1;
412
413 if (handler->numargs > 0)
414 {
415 #if !defined(USE_VSTR) && \
416 (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER))
417 # ifdef HAVE_PRINTF_SPECIFIER
418 register_printf_specifier(spec, custom_print, custom_arginfo);
419 # else
420 register_printf_function(spec, custom_print, custom_arginfo);
421 # endif
422 #else
423 Vstr_conf *conf = get_vstr_conf();
424 handler->name = malloc(2);
425 handler->name[0] = spec;
426 handler->name[1] = '\0';
427 vstr_fmt_add_handler(conf, handler);
428 #endif
429 printf_hooks[SPEC_TO_INDEX(spec)] = handler;
430 }
431 else
432 {
433 free(handler);
434 }
435 }
436
437 METHOD(printf_hook_t, destroy, void,
438 private_printf_hook_t *this)
439 {
440 int i;
441 #ifdef USE_VSTR
442 Vstr_conf *conf = get_vstr_conf();
443 #endif
444
445 for (i = 0; i < NUM_HANDLERS; ++i)
446 {
447 printf_hook_handler_t *handler = printf_hooks[i];
448 if (handler)
449 {
450 #ifdef USE_VSTR
451 vstr_fmt_del(conf, handler->name);
452 free(handler->name);
453 #endif
454 free(handler);
455 }
456 }
457
458 #ifdef USE_VSTR
459 /* freeing the Vstr_conf of the main thread */
460 vstr_conf->destroy(vstr_conf);
461 vstr_conf = NULL;
462 vstr_free_conf(conf);
463 vstr_exit();
464 #endif
465 free(this);
466 }
467
468 /*
469 * see header file
470 */
471 printf_hook_t *printf_hook_create()
472 {
473 private_printf_hook_t *this;
474
475 INIT(this,
476 .public = {
477 .add_handler = _add_handler,
478 .destroy = _destroy,
479 },
480 );
481
482 memset(printf_hooks, 0, sizeof(printf_hooks));
483
484 #ifdef USE_VSTR
485 if (!vstr_init())
486 {
487 DBG1(DBG_LIB, "failed to initialize Vstr library!");
488 free(this);
489 return NULL;
490 }
491 vstr_conf = thread_value_create((thread_cleanup_t)vstr_free_conf);
492 #endif
493
494 return &this->public;
495 }
496