]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/printf_hook.c
Use register_printf_specifier instead of deprecated register_printf_function, if...
[thirdparty/strongswan.git] / src / libstrongswan / printf_hook.c
CommitLineData
db7ef624 1/*
d25ce370 2 * Copyright (C) 2009 Tobias Brunner
552cc11b 3 * Copyright (C) 2006-2008 Martin Willi
db7ef624
MW
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
552cc11b 19#include <utils.h>
d25ce370
TB
20#include <debug.h>
21
22#include <stdio.h>
23#include <stdarg.h>
24#include <string.h>
db7ef624 25
552cc11b 26typedef struct private_printf_hook_t private_printf_hook_t;
d25ce370
TB
27typedef struct printf_hook_handler_t printf_hook_handler_t;
28
29#define PRINTF_BUF_LEN 8192
30#define ARGS_MAX 3
2f5914a3 31
db7ef624 32/**
552cc11b 33 * private data of printf_hook
db7ef624 34 */
552cc11b 35struct private_printf_hook_t {
db7ef624 36
552cc11b
MW
37 /**
38 * public functions
39 */
40 printf_hook_t public;
41};
db7ef624 42
d25ce370
TB
43/**
44 * struct with information about a registered handler
45 */
46struct printf_hook_handler_t {
7daf5226 47
d25ce370
TB
48 /**
49 * callback function
50 */
51 printf_hook_function_t hook;
7daf5226 52
d25ce370
TB
53 /**
54 * number of arguments
55 */
56 int numargs;
7daf5226 57
d25ce370
TB
58 /**
59 * types of the arguments
60 */
61 int argtypes[ARGS_MAX];
62
bf45d6dd 63#ifdef USE_VSTR
d25ce370
TB
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
73static 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
f6bbcec3
MW
78#if !defined(USE_VSTR) && \
79 (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER))
d25ce370
TB
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 */
86static 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)];
7daf5226 93
d25ce370
TB
94 spec.hash = info->alt;
95 spec.minus = info->left;
96 spec.width = info->width;
7daf5226 97
d25ce370
TB
98 written = handler->hook(buf, sizeof(buf), &spec, args);
99 if (written > 0)
100 {
c5c96963 101 ignore_result(fwrite(buf, 1, written, stream));
d25ce370
TB
102 }
103 return written;
104}
105
106/**
107 * Printf hook arginfo function, which is actually of type
f6bbcec3 108 * "printf_arginfo_[size_]function".
d25ce370 109 */
f6bbcec3
MW
110static int custom_arginfo(const struct printf_info *info, size_t n, int *argtypes
111#ifdef HAVE_PRINTF_SPECIFIER
112 , int *size
113#endif
114 )
d25ce370
TB
115{
116 int i;
117 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)];
7daf5226 118
d25ce370
TB
119 if (handler->numargs <= n)
120 {
121 for (i = 0; i < handler->numargs; ++i)
122 {
123 argtypes[i] = handler->argtypes[i];
124 }
125 }
f6bbcec3 126 /* we never set "size", as we have no user defined types */
d25ce370
TB
127 return handler->numargs;
128}
129
130#else
131
132#include <errno.h>
133#include <unistd.h> /* for STDOUT_FILENO */
134
135/**
136 * Vstr custom format specifier callback function.
137 */
138static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec)
139{
140 int i, written;
141 char buf[PRINTF_BUF_LEN];
142 const void *args[ARGS_MAX];
143 printf_hook_spec_t spec;
144 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(fmt_spec->name[0])];
7daf5226 145
d25ce370
TB
146 for (i = 0; i < handler->numargs; i++)
147 {
148 switch(handler->argtypes[i])
149 {
150 case PRINTF_HOOK_ARGTYPE_INT:
151 args[i] = VSTR_FMT_CB_ARG_PTR(fmt_spec, i);
152 break;
153 case PRINTF_HOOK_ARGTYPE_POINTER:
154 args[i] = &VSTR_FMT_CB_ARG_PTR(fmt_spec, i);
155 break;
156 }
157 }
7daf5226 158
d25ce370
TB
159 spec.hash = fmt_spec->fmt_hash;
160 spec.minus = fmt_spec->fmt_minus;
161 spec.width = fmt_spec->fmt_field_width;
7daf5226 162
d25ce370
TB
163 written = handler->hook(buf, sizeof(buf), &spec, args);
164 if (written > 0)
165 {
166 vstr_add_buf(base, pos, buf, written);
167 }
168 return TRUE;
169}
170
171/**
d24a74c5 172 * Add a custom format handler to the given Vstr_conf object
d25ce370
TB
173 */
174static void vstr_fmt_add_handler(Vstr_conf *conf, printf_hook_handler_t *handler)
175{
176 int *at = handler->argtypes;
177 switch(handler->numargs)
178 {
179 case 1:
180 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0], VSTR_TYPE_FMT_END);
181 break;
182 case 2:
183 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0], at[1], VSTR_TYPE_FMT_END);
184 break;
185 case 3:
186 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0], at[1], at[2], VSTR_TYPE_FMT_END);
187 break;
188 }
189}
190
191/**
192 * Management of thread-specific Vstr_conf objects
193 */
194#include <pthread.h>
195
196static pthread_key_t vstr_conf_key;
197static pthread_once_t vstr_conf_key_once = PTHREAD_ONCE_INIT;
198
199static void init_vstr_conf_key(void)
200{
201 pthread_key_create(&vstr_conf_key, (void*)vstr_free_conf);
202}
203
204static Vstr_conf *create_vstr_conf()
205{
206 int i;
207 Vstr_conf *conf = vstr_make_conf();
208 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '%');
209 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_TYPE_GRPALLOC_CACHE,
210 VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR);
211 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, PRINTF_BUF_LEN);
212 for (i = 0; i < NUM_HANDLERS; ++i)
213 {
214 printf_hook_handler_t *handler = printf_hooks[i];
215 if (handler)
216 {
217 vstr_fmt_add_handler(conf, handler);
218 }
219 }
220 return conf;
221}
222
223static inline Vstr_conf *get_vstr_conf()
224{
225 Vstr_conf *conf;
226 pthread_once(&vstr_conf_key_once, init_vstr_conf_key);
227 conf = (Vstr_conf*)pthread_getspecific(vstr_conf_key);
228 if (!conf)
229 {
230 conf = create_vstr_conf();
231 pthread_setspecific(vstr_conf_key, conf);
232 }
233 return conf;
234}
235
236/**
237 * Wrapper functions for printf and alike
238 */
239int vstr_wrapper_printf(const char *format, ...)
240{
241 int written;
242 va_list args;
243 va_start(args, format);
244 written = vstr_wrapper_vprintf(format, args);
245 va_end(args);
246 return written;
247}
248int vstr_wrapper_fprintf(FILE *stream, const char *format, ...)
249{
250 int written;
251 va_list args;
252 va_start(args, format);
253 written = vstr_wrapper_vfprintf(stream, format, args);
254 va_end(args);
255 return written;
256}
257int vstr_wrapper_sprintf(char *str, const char *format, ...)
258{
259 int written;
260 va_list args;
261 va_start(args, format);
262 written = vstr_wrapper_vsprintf(str, format, args);
263 va_end(args);
264 return written;
265}
266int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...)
267{
268 int written;
269 va_list args;
270 va_start(args, format);
271 written = vstr_wrapper_vsnprintf(str, size, format, args);
272 va_end(args);
273 return written;
274}
275static inline int vstr_wrapper_vprintf_internal(int fd, const char *format,
276 va_list args)
277{
278 int written;
279 Vstr_conf *conf = get_vstr_conf();
280 Vstr_base *s = vstr_make_base(conf);
281 vstr_add_vfmt(s, 0, format, args);
282 written = s->len;
283 while (s->len)
284 {
285 if (!vstr_sc_write_fd(s, 1, s->len, fd, NULL))
286 {
287 if (errno != EAGAIN && errno != EINTR)
288 {
289 written -= s->len;
290 break;
291 }
292 }
293 }
294 vstr_free_base(s);
295 return written;
296}
297int vstr_wrapper_vprintf(const char *format, va_list args)
298{
299 return vstr_wrapper_vprintf_internal(STDOUT_FILENO, format, args);
300}
301int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list args)
302{
303 return vstr_wrapper_vprintf_internal(fileno(stream), format, args);
304}
305static inline int vstr_wrapper_vsnprintf_internal(char *str, size_t size,
306 const char *format,
307 va_list args)
308{
309 int written;
310 Vstr_conf *conf = get_vstr_conf();
311 Vstr_base *s = vstr_make_base(conf);
312 vstr_add_vfmt(s, 0, format, args);
313 written = s->len;
314 vstr_export_cstr_buf(s, 1, s->len, str, (size > 0) ? size : s->len + 1);
315 vstr_free_base(s);
316 return written;
317}
318int vstr_wrapper_vsprintf(char *str, const char *format, va_list args)
319{
320 return vstr_wrapper_vsnprintf_internal(str, 0, format, args);
321}
322int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format,
323 va_list args)
324{
325 return (size > 0) ? vstr_wrapper_vsnprintf_internal(str, size, format, args) : 0;
326}
327
328#endif
329
db7ef624 330/**
552cc11b 331 * Implementation of printf_hook_t.add_handler.
db7ef624 332 */
d25ce370
TB
333static void add_handler(private_printf_hook_t *this, char spec,
334 printf_hook_function_t hook, ...)
db7ef624 335{
d25ce370
TB
336 int i = -1;
337 printf_hook_handler_t *handler;
338 printf_hook_argtype_t argtype;
339 va_list args;
7daf5226 340
d25ce370
TB
341 if (!IS_VALID_SPEC(spec))
342 {
343 DBG1("'%c' is not a valid printf hook specifier, not registered!", spec);
344 return;
345 }
7daf5226 346
d24a74c5 347 handler = malloc_thing(printf_hook_handler_t);
d25ce370 348 handler->hook = hook;
7daf5226 349
d25ce370
TB
350 va_start(args, hook);
351 while ((argtype = va_arg(args, printf_hook_argtype_t)) != PRINTF_HOOK_ARGTYPE_END)
352 {
353 if (++i >= ARGS_MAX)
354 {
355 DBG1("Too many arguments for printf hook with specifier '%c', not registered!", spec);
356 va_end(args);
357 free(handler);
358 return;
359 }
360 handler->argtypes[i] = argtype;
361 }
362 va_end(args);
7daf5226 363
d25ce370 364 handler->numargs = i + 1;
7daf5226 365
d25ce370
TB
366 if (handler->numargs > 0)
367 {
f6bbcec3
MW
368#if !defined(USE_VSTR) && \
369 (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER))
370# ifdef HAVE_PRINTF_SPECIFIER
371 register_printf_specifier(spec, custom_print, custom_arginfo);
372# else
d25ce370 373 register_printf_function(spec, custom_print, custom_arginfo);
f6bbcec3 374# endif
d25ce370
TB
375#else
376 Vstr_conf *conf = get_vstr_conf();
377 handler->name = malloc(2);
378 handler->name[0] = spec;
379 handler->name[1] = '\0';
380 vstr_fmt_add_handler(conf, handler);
381#endif
382 printf_hooks[SPEC_TO_INDEX(spec)] = handler;
383 }
384 else
385 {
386 free(handler);
387 }
db7ef624
MW
388}
389
390/**
552cc11b 391 * Implementation of printf_hook_t.destroy
db7ef624 392 */
552cc11b 393static void destroy(private_printf_hook_t *this)
db7ef624 394{
d25ce370 395 int i;
bf45d6dd 396#ifdef USE_VSTR
d25ce370
TB
397 Vstr_conf *conf = get_vstr_conf();
398#endif
7daf5226 399
d25ce370
TB
400 for (i = 0; i < NUM_HANDLERS; ++i)
401 {
402 printf_hook_handler_t *handler = printf_hooks[i];
403 if (handler)
404 {
bf45d6dd 405#ifdef USE_VSTR
d25ce370
TB
406 vstr_fmt_del(conf, handler->name);
407 free(handler->name);
408#endif
409 free(handler);
410 }
411 }
7daf5226 412
bf45d6dd 413#ifdef USE_VSTR
d25ce370
TB
414 /* freeing the Vstr_conf of the main thread */
415 pthread_key_delete(vstr_conf_key);
416 vstr_free_conf(conf);
417 vstr_exit();
418#endif
552cc11b 419 free(this);
db7ef624 420}
ee614711 421
552cc11b
MW
422/*
423 * see header file
ee614711 424 */
552cc11b 425printf_hook_t *printf_hook_create()
ee614711 426{
552cc11b 427 private_printf_hook_t *this = malloc_thing(private_printf_hook_t);
7daf5226 428
d25ce370 429 this->public.add_handler = (void(*)(printf_hook_t*, char, printf_hook_function_t, ...))add_handler;
552cc11b 430 this->public.destroy = (void(*)(printf_hook_t*))destroy;
7daf5226 431
d25ce370 432 memset(printf_hooks, 0, sizeof(printf_hooks));
7daf5226 433
bf45d6dd 434#ifdef USE_VSTR
d25ce370
TB
435 if (!vstr_init())
436 {
437 DBG1("failed to initialize Vstr library!");
438 free(this);
439 return NULL;
440 }
441#endif
7daf5226 442
552cc11b 443 return &this->public;
ee614711
MW
444}
445