make IMC/IMV pairs independent of libcharon
[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 int written;
90 char buf[PRINTF_BUF_LEN];
91 printf_hook_spec_t spec;
92 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)];
93
94 spec.hash = info->alt;
95 spec.minus = info->left;
96 spec.width = info->width;
97
98 written = handler->hook(buf, sizeof(buf), &spec, args);
99 if (written > 0)
100 {
101 ignore_result(fwrite(buf, 1, written, stream));
102 }
103 return written;
104 }
105
106 /**
107 * Printf hook arginfo function, which is actually of type
108 * "printf_arginfo_[size_]function".
109 */
110 static int custom_arginfo(const struct printf_info *info, size_t n, int *argtypes
111 #ifdef HAVE_PRINTF_SPECIFIER
112 , int *size
113 #endif
114 )
115 {
116 int i;
117 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)];
118
119 if (handler->numargs <= n)
120 {
121 for (i = 0; i < handler->numargs; ++i)
122 {
123 argtypes[i] = handler->argtypes[i];
124 }
125 }
126 /* we never set "size", as we have no user defined types */
127 return handler->numargs;
128 }
129
130 #else
131
132 #include <errno.h>
133 #include <unistd.h> /* for STDOUT_FILENO */
134
135 /**
136 * These are used below, whenever the public wrapper functions are called before
137 * initialization or after destruction.
138 */
139 #undef vprintf
140 #undef vfprintf
141 #undef vsnprintf
142
143 /**
144 * Vstr custom format specifier callback function.
145 */
146 static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec)
147 {
148 int i, written;
149 char buf[PRINTF_BUF_LEN];
150 const void *args[ARGS_MAX];
151 printf_hook_spec_t spec;
152 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(fmt_spec->name[0])];
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.minus = fmt_spec->fmt_minus;
169 spec.width = fmt_spec->fmt_field_width;
170
171 written = handler->hook(buf, sizeof(buf), &spec, args);
172 if (written > 0)
173 {
174 vstr_add_buf(base, pos, buf, written);
175 }
176 return TRUE;
177 }
178
179 /**
180 * Add a custom format handler to the given Vstr_conf object
181 */
182 static void vstr_fmt_add_handler(Vstr_conf *conf, printf_hook_handler_t *handler)
183 {
184 int *at = handler->argtypes;
185 switch(handler->numargs)
186 {
187 case 1:
188 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
189 VSTR_TYPE_FMT_END);
190 break;
191 case 2:
192 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
193 at[1], VSTR_TYPE_FMT_END);
194 break;
195 case 3:
196 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
197 at[1], at[2], VSTR_TYPE_FMT_END);
198 break;
199 }
200 }
201
202 /**
203 * Management of thread-specific Vstr_conf objects
204 */
205 #include <threading/thread_value.h>
206
207 static thread_value_t *vstr_conf = NULL;
208
209 static Vstr_conf *create_vstr_conf()
210 {
211 int i;
212 Vstr_conf *conf = vstr_make_conf();
213 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '%');
214 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_TYPE_GRPALLOC_CACHE,
215 VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR);
216 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, PRINTF_BUF_LEN);
217 for (i = 0; i < NUM_HANDLERS; ++i)
218 {
219 printf_hook_handler_t *handler = printf_hooks[i];
220 if (handler)
221 {
222 vstr_fmt_add_handler(conf, handler);
223 }
224 }
225 return conf;
226 }
227
228 static inline Vstr_conf *get_vstr_conf()
229 {
230 Vstr_conf *conf = NULL;
231 if (vstr_conf)
232 {
233 conf = (Vstr_conf*)vstr_conf->get(vstr_conf);
234 if (!conf)
235 {
236 conf = create_vstr_conf();
237 vstr_conf->set(vstr_conf, conf);
238 }
239 }
240 return conf;
241 }
242
243 /**
244 * Wrapper functions for printf and alike
245 */
246 int vstr_wrapper_printf(const char *format, ...)
247 {
248 int written;
249 va_list args;
250 va_start(args, format);
251 written = vstr_wrapper_vprintf(format, args);
252 va_end(args);
253 return written;
254 }
255 int vstr_wrapper_fprintf(FILE *stream, const char *format, ...)
256 {
257 int written;
258 va_list args;
259 va_start(args, format);
260 written = vstr_wrapper_vfprintf(stream, format, args);
261 va_end(args);
262 return written;
263 }
264 int vstr_wrapper_sprintf(char *str, const char *format, ...)
265 {
266 int written;
267 va_list args;
268 va_start(args, format);
269 written = vstr_wrapper_vsprintf(str, format, args);
270 va_end(args);
271 return written;
272 }
273 int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...)
274 {
275 int written;
276 va_list args;
277 va_start(args, format);
278 written = vstr_wrapper_vsnprintf(str, size, format, args);
279 va_end(args);
280 return written;
281 }
282 int vstr_wrapper_asprintf(char **str, const char *format, ...)
283 {
284 int written;
285 va_list args;
286 va_start(args, format);
287 written = vstr_wrapper_vasprintf(str, format, args);
288 va_end(args);
289 return written;
290 }
291 static inline int vstr_wrapper_vprintf_internal(Vstr_conf *conf, int fd,
292 const char *format,
293 va_list args)
294 {
295 int written;
296 Vstr_base *s = vstr_make_base(conf);
297 vstr_add_vfmt(s, 0, format, args);
298 written = s->len;
299 while (s->len)
300 {
301 if (!vstr_sc_write_fd(s, 1, s->len, fd, NULL))
302 {
303 if (errno != EAGAIN && errno != EINTR)
304 {
305 written -= s->len;
306 break;
307 }
308 }
309 }
310 vstr_free_base(s);
311 return written;
312 }
313 int vstr_wrapper_vprintf(const char *format, va_list args)
314 {
315 Vstr_conf *conf = get_vstr_conf();
316 if (conf)
317 {
318 return vstr_wrapper_vprintf_internal(conf, STDOUT_FILENO, format, args);
319 }
320 return vprintf(format, args);
321 }
322 int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list args)
323 {
324 Vstr_conf *conf = get_vstr_conf();
325 if (conf)
326 {
327 return vstr_wrapper_vprintf_internal(conf, fileno(stream), format,
328 args);
329 }
330 return vfprintf(stream, format, args);
331 }
332 static inline int vstr_wrapper_vsnprintf_internal(char *str, size_t size,
333 const char *format,
334 va_list args)
335 {
336 Vstr_conf *conf = get_vstr_conf();
337 if (conf)
338 {
339 int written;
340 Vstr_base *s = vstr_make_base(conf);
341 vstr_add_vfmt(s, 0, format, args);
342 written = s->len;
343 vstr_export_cstr_buf(s, 1, s->len, str, (size > 0) ? size : s->len + 1);
344 vstr_free_base(s);
345 return written;
346 }
347 return vsnprintf(str, size, format, args);
348 }
349 int vstr_wrapper_vsprintf(char *str, const char *format, va_list args)
350 {
351 return vstr_wrapper_vsnprintf_internal(str, 0, format, args);
352 }
353 int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format,
354 va_list args)
355 {
356 return (size > 0) ? vstr_wrapper_vsnprintf_internal(str, size, format, args) : 0;
357 }
358 int vstr_wrapper_vasprintf(char **str, const char *format, va_list args)
359 {
360 size_t len = 100;
361 int written;
362 *str = malloc(len);
363 while (TRUE)
364 {
365 va_list ac;
366 va_copy(ac, args);
367 written = vstr_wrapper_vsnprintf_internal(*str, len, format, ac);
368 va_end(ac);
369 if (written < len)
370 {
371 break;
372 }
373 len = written + 1;
374 *str = realloc(*str, len);
375 }
376 return written;
377 }
378 #endif
379
380 METHOD(printf_hook_t, add_handler, void,
381 private_printf_hook_t *this, char spec,
382 printf_hook_function_t hook, ...)
383 {
384 int i = -1;
385 printf_hook_handler_t *handler;
386 printf_hook_argtype_t argtype;
387 va_list args;
388
389 if (!IS_VALID_SPEC(spec))
390 {
391 DBG1(DBG_LIB, "'%c' is not a valid printf hook specifier, "
392 "not registered!", spec);
393 return;
394 }
395
396 handler = malloc_thing(printf_hook_handler_t);
397 handler->hook = hook;
398
399 va_start(args, hook);
400 while ((argtype = va_arg(args, printf_hook_argtype_t)) != PRINTF_HOOK_ARGTYPE_END)
401 {
402 if (++i >= ARGS_MAX)
403 {
404 DBG1(DBG_LIB, "Too many arguments for printf hook with "
405 "specifier '%c', not registered!", spec);
406 va_end(args);
407 free(handler);
408 return;
409 }
410 handler->argtypes[i] = argtype;
411 }
412 va_end(args);
413
414 handler->numargs = i + 1;
415
416 if (handler->numargs > 0)
417 {
418 #if !defined(USE_VSTR) && \
419 (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER))
420 # ifdef HAVE_PRINTF_SPECIFIER
421 register_printf_specifier(spec, custom_print, custom_arginfo);
422 # else
423 register_printf_function(spec, custom_print, custom_arginfo);
424 # endif
425 #else
426 Vstr_conf *conf = get_vstr_conf();
427 handler->name = malloc(2);
428 handler->name[0] = spec;
429 handler->name[1] = '\0';
430 vstr_fmt_add_handler(conf, handler);
431 #endif
432 printf_hooks[SPEC_TO_INDEX(spec)] = handler;
433 }
434 else
435 {
436 free(handler);
437 }
438 }
439
440 METHOD(printf_hook_t, destroy, void,
441 private_printf_hook_t *this)
442 {
443 int i;
444 #ifdef USE_VSTR
445 Vstr_conf *conf = get_vstr_conf();
446 #endif
447
448 for (i = 0; i < NUM_HANDLERS; ++i)
449 {
450 printf_hook_handler_t *handler = printf_hooks[i];
451 if (handler)
452 {
453 #ifdef USE_VSTR
454 vstr_fmt_del(conf, handler->name);
455 free(handler->name);
456 #endif
457 free(handler);
458 }
459 }
460
461 #ifdef USE_VSTR
462 /* freeing the Vstr_conf of the main thread */
463 vstr_conf->destroy(vstr_conf);
464 vstr_conf = NULL;
465 vstr_free_conf(conf);
466 vstr_exit();
467 #endif
468 free(this);
469 }
470
471 /*
472 * see header file
473 */
474 printf_hook_t *printf_hook_create()
475 {
476 private_printf_hook_t *this;
477
478 INIT(this,
479 .public = {
480 .add_handler = _add_handler,
481 .destroy = _destroy,
482 },
483 );
484
485 memset(printf_hooks, 0, sizeof(printf_hooks));
486
487 #ifdef USE_VSTR
488 if (!vstr_init())
489 {
490 DBG1(DBG_LIB, "failed to initialize Vstr library!");
491 free(this);
492 return NULL;
493 }
494 vstr_conf = thread_value_create((thread_cleanup_t)vstr_free_conf);
495 #endif
496
497 return &this->public;
498 }
499