diff options
author | Martin Willi <martin@revosec.ch> | 2013-09-27 17:30:17 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2013-10-11 11:05:30 +0200 |
commit | 243048248b7c885186201a112484378b43116f66 (patch) | |
tree | ffdb81423ff050897c959244f390d5cbe8442694 /src/libstrongswan/utils/printf_hook/printf_hook_vstr.c | |
parent | 11282d0054d8a51f184a6f726f7f180ccf60e456 (diff) | |
download | strongswan-243048248b7c885186201a112484378b43116f66.tar.bz2 strongswan-243048248b7c885186201a112484378b43116f66.tar.xz |
printf-hook: Move glibc/vstr printf hook backends to separate files
Diffstat (limited to 'src/libstrongswan/utils/printf_hook/printf_hook_vstr.c')
-rw-r--r-- | src/libstrongswan/utils/printf_hook/printf_hook_vstr.c | 507 |
1 files changed, 507 insertions, 0 deletions
diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_vstr.c b/src/libstrongswan/utils/printf_hook/printf_hook_vstr.c new file mode 100644 index 000000000..f1884f119 --- /dev/null +++ b/src/libstrongswan/utils/printf_hook/printf_hook_vstr.c @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2009-2013 Tobias Brunner + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "printf_hook.h" + +#include <utils/utils.h> +#include <utils/debug.h> +#include <threading/thread_value.h> + +#include <vstr.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +typedef struct private_printf_hook_t private_printf_hook_t; +typedef struct printf_hook_handler_t printf_hook_handler_t; + +#define PRINTF_BUF_LEN 8192 +#define ARGS_MAX 3 + +/** + * private data of printf_hook + */ +struct private_printf_hook_t { + + /** + * public functions + */ + printf_hook_t public; +}; + +/** + * struct with information about a registered handler + */ +struct printf_hook_handler_t { + + /** + * callback function + */ + printf_hook_function_t hook; + + /** + * number of arguments + */ + int numargs; + + /** + * types of the arguments, VSTR_TYPE_FMT_* + */ + int argtypes[ARGS_MAX]; + + /** + * name required for Vstr + */ + char *name; +}; + +/** + * Data to pass to a printf hook. + */ +struct printf_hook_data_t { + + /** + * Base to append printf to + */ + Vstr_base *base; + + /** + * Position in base to write to + */ + size_t pos; +}; + +/* A-Z | 6 other chars | a-z */ +static printf_hook_handler_t *printf_hooks[58]; + +#define SPEC_TO_INDEX(spec) ((int)(spec) - (int)'A') + +/** + * These are used below, whenever the public wrapper functions are called before + * initialization or after destruction. + */ +#undef vprintf +#undef vfprintf +#undef vsnprintf + +/** + * Vstr variant of print_in_hook() + */ +size_t print_in_hook(printf_hook_data_t *data, char *fmt, ...) +{ + size_t written; + va_list args; + + va_start(args, fmt); + written = vstr_add_vfmt(data->base, data->pos, fmt, args); + va_end(args); + + data->pos += written; + return written; +} + +/** + * Vstr custom format specifier callback function. + */ +static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec) +{ + int i; + const void *args[ARGS_MAX]; + printf_hook_spec_t spec; + printf_hook_handler_t *handler; + printf_hook_data_t data = { + .base = base, + .pos = pos, + }; + + handler = printf_hooks[SPEC_TO_INDEX(fmt_spec->name[0])]; + for (i = 0; i < handler->numargs; i++) + { + switch (handler->argtypes[i]) + { + case VSTR_TYPE_FMT_INT: + args[i] = VSTR_FMT_CB_ARG_PTR(fmt_spec, i); + break; + case VSTR_TYPE_FMT_PTR_VOID: + args[i] = &VSTR_FMT_CB_ARG_PTR(fmt_spec, i); + break; + } + } + + spec.hash = fmt_spec->fmt_hash; + spec.plus = fmt_spec->fmt_plus; + spec.minus = fmt_spec->fmt_minus; + spec.width = fmt_spec->fmt_field_width; + + handler->hook(&data, &spec, args); + + return 1; +} + +/** + * Add a custom format handler to the given Vstr_conf object + */ +static void vstr_fmt_add_handler(Vstr_conf *conf, printf_hook_handler_t *handler) +{ + int *at; + + at = handler->argtypes; + switch (handler->numargs) + { + case 1: + vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0], + VSTR_TYPE_FMT_END); + break; + case 2: + vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0], + at[1], VSTR_TYPE_FMT_END); + break; + case 3: + vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0], + at[1], at[2], VSTR_TYPE_FMT_END); + break; + } +} + +/** + * Thread specific vstr config + */ +static thread_value_t *vstr_conf = NULL; + +/** + * Create vstr config for current thread + */ +static Vstr_conf *create_vstr_conf() +{ + Vstr_conf *conf; + int i; + + conf = vstr_make_conf(); + vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '%'); + vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_TYPE_GRPALLOC_CACHE, + VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR); + vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, PRINTF_BUF_LEN); + + for (i = 0; i < countof(printf_hooks); i++) + { + if (printf_hooks[i]) + { + vstr_fmt_add_handler(conf, printf_hooks[i]); + } + } + return conf; +} + +/** + * Get vstr config of current thread + */ +static inline Vstr_conf *get_vstr_conf() +{ + Vstr_conf *conf = NULL; + + if (vstr_conf) + { + conf = (Vstr_conf*)vstr_conf->get(vstr_conf); + if (!conf) + { + conf = create_vstr_conf(); + vstr_conf->set(vstr_conf, conf); + } + } + return conf; +} + +/** + * Wrapper functions for printf and alike + */ +int vstr_wrapper_printf(const char *format, ...) +{ + int written; + va_list args; + va_start(args, format); + written = vstr_wrapper_vprintf(format, args); + va_end(args); + return written; +} + +int vstr_wrapper_fprintf(FILE *stream, const char *format, ...) +{ + int written; + va_list args; + va_start(args, format); + written = vstr_wrapper_vfprintf(stream, format, args); + va_end(args); + return written; +} + +int vstr_wrapper_sprintf(char *str, const char *format, ...) +{ + int written; + va_list args; + va_start(args, format); + written = vstr_wrapper_vsprintf(str, format, args); + va_end(args); + return written; +} + +int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...) +{ + int written; + va_list args; + va_start(args, format); + written = vstr_wrapper_vsnprintf(str, size, format, args); + va_end(args); + return written; +} + +int vstr_wrapper_asprintf(char **str, const char *format, ...) +{ + int written; + va_list args; + va_start(args, format); + written = vstr_wrapper_vasprintf(str, format, args); + va_end(args); + return written; +} + +static inline int vstr_wrapper_vprintf_internal(Vstr_conf *conf, FILE *stream, + const char *format, + va_list args) +{ + struct iovec *iov; + int iovcnt, written = 0; + Vstr_base *s; + + s = vstr_make_base(conf); + vstr_add_vfmt(s, 0, format, args); + if (vstr_export_iovec_ptr_all(s, &iov, &iovcnt)) + { + while (iovcnt--) + { + if (iov->iov_base) + { + written += fwrite(iov->iov_base, 1, iov->iov_len, stream); + } + iov++; + } + } + vstr_free_base(s); + return written; +} + +int vstr_wrapper_vprintf(const char *format, va_list args) +{ + Vstr_conf *conf; + + conf = get_vstr_conf(); + if (conf) + { + return vstr_wrapper_vprintf_internal(conf, stdout, format, args); + } + return vprintf(format, args); +} + +int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list args) +{ + Vstr_conf *conf; + + conf = get_vstr_conf(); + if (conf) + { + return vstr_wrapper_vprintf_internal(conf, stream, format, args); + } + return vfprintf(stream, format, args); +} + +static inline int vstr_wrapper_vsnprintf_internal(char *str, size_t size, + const char *format, + va_list args) +{ + Vstr_conf *conf; + Vstr_base *s; + int written; + + conf = get_vstr_conf(); + if (conf) + { + s = vstr_make_base(conf); + vstr_add_vfmt(s, 0, format, args); + written = s->len; + vstr_export_cstr_buf(s, 1, s->len, str, (size > 0) ? size : s->len + 1); + vstr_free_base(s); + return written; + } + return vsnprintf(str, size, format, args); +} + +int vstr_wrapper_vsprintf(char *str, const char *format, va_list args) +{ + return vstr_wrapper_vsnprintf_internal(str, 0, format, args); +} + +int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format, + va_list args) +{ + if (size > 0) + { + return vstr_wrapper_vsnprintf_internal(str, size, format, args); + } + return 0; +} + +int vstr_wrapper_vasprintf(char **str, const char *format, va_list args) +{ + size_t len = 100; + int written; + + *str = malloc(len); + while (TRUE) + { + va_list ac; + va_copy(ac, args); + written = vstr_wrapper_vsnprintf_internal(*str, len, format, ac); + va_end(ac); + if (written < len) + { + break; + } + len = written + 1; + *str = realloc(*str, len); + } + return written; +} + +METHOD(printf_hook_t, add_handler, void, + private_printf_hook_t *this, char spec, printf_hook_function_t hook, ...) +{ + int i = -1; + bool failed = FALSE; + printf_hook_handler_t *handler; + printf_hook_argtype_t argtype; + va_list args; + + if (SPEC_TO_INDEX(spec) <= -1 || + SPEC_TO_INDEX(spec) >= countof(printf_hooks)) + { + DBG1(DBG_LIB, "'%c' is not a valid printf hook specifier, " + "not registered!", spec); + return; + } + + INIT(handler, + .hook = hook, + ); + + va_start(args, hook); + while (!failed) + { + argtype = va_arg(args, printf_hook_argtype_t); + if (argtype == PRINTF_HOOK_ARGTYPE_END) + { + break; + } + if (++i >= ARGS_MAX) + { + DBG1(DBG_LIB, "Too many arguments for printf hook with " + "specifier '%c', not registered!", spec); + failed = TRUE; + break; + } + switch (argtype) + { + case PRINTF_HOOK_ARGTYPE_INT: + handler->argtypes[i] = VSTR_TYPE_FMT_INT; + break; + case PRINTF_HOOK_ARGTYPE_POINTER: + handler->argtypes[i] = VSTR_TYPE_FMT_PTR_VOID; + break; + default: + DBG1(DBG_LIB, "Invalid printf hook arg type for '%c'", spec); + failed = TRUE; + break; + } + } + va_end(args); + + handler->numargs = i + 1; + + if (!failed && handler->numargs > 0) + { + Vstr_conf *conf = get_vstr_conf(); + handler->name = malloc(2); + handler->name[0] = spec; + handler->name[1] = '\0'; + vstr_fmt_add_handler(conf, handler); + printf_hooks[SPEC_TO_INDEX(spec)] = handler; + } + else + { + free(handler); + } +} + +METHOD(printf_hook_t, destroy, void, + private_printf_hook_t *this) +{ + int i; + Vstr_conf *conf; + printf_hook_handler_t *handler; + + conf = get_vstr_conf(); + for (i = 0; i < countof(printf_hooks); ++i) + { + handler = printf_hooks[i]; + if (handler) + { + vstr_fmt_del(conf, handler->name); + free(handler->name); + free(handler); + } + } + + /* freeing the Vstr_conf of the main thread */ + vstr_conf->destroy(vstr_conf); + vstr_conf = NULL; + vstr_exit(); + free(this); +} + +/* + * see header file + */ +printf_hook_t *printf_hook_create() +{ + private_printf_hook_t *this; + + INIT(this, + .public = { + .add_handler = _add_handler, + .destroy = _destroy, + }, + ); + + memset(printf_hooks, 0, sizeof(printf_hooks)); + + if (!vstr_init()) + { + DBG1(DBG_LIB, "failed to initialize Vstr library!"); + free(this); + return NULL; + } + vstr_conf = thread_value_create((thread_cleanup_t)vstr_free_conf); + + return &this->public; +} |