diff options
author | Martin Willi <martin@revosec.ch> | 2013-10-11 11:12:38 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2013-10-11 11:12:38 +0200 |
commit | 5900d6d469d24faf7052ed24f013f02cb33a7095 (patch) | |
tree | 05fd3b8922ef17eadc2e16ca3f6f44f02d10fe87 /src | |
parent | 11282d0054d8a51f184a6f726f7f180ccf60e456 (diff) | |
parent | 795cbb98c6950d732f112063bd16de02ec54db67 (diff) | |
download | strongswan-5900d6d469d24faf7052ed24f013f02cb33a7095.tar.bz2 strongswan-5900d6d469d24faf7052ed24f013f02cb33a7095.tar.xz |
Merge branch 'printf-hook'
Adds a custom printf hook implementation as a fallback if neither the glibc
style hooks nor vstr is available. This can avoid the Vstr dependency on some
systems at the cost of slower and less complete printf functions.
Diffstat (limited to 'src')
-rw-r--r-- | src/libstrongswan/Android.mk | 2 | ||||
-rw-r--r-- | src/libstrongswan/Makefile.am | 18 | ||||
-rw-r--r-- | src/libstrongswan/library.h | 2 | ||||
-rw-r--r-- | src/libstrongswan/tests/Makefile.am | 2 | ||||
-rw-r--r-- | src/libstrongswan/tests/test_printf.c | 185 | ||||
-rw-r--r-- | src/libstrongswan/tests/test_runner.c | 1 | ||||
-rw-r--r-- | src/libstrongswan/tests/test_runner.h | 1 | ||||
-rw-r--r-- | src/libstrongswan/utils/enum.h | 2 | ||||
-rw-r--r-- | src/libstrongswan/utils/printf_hook.h | 247 | ||||
-rw-r--r-- | src/libstrongswan/utils/printf_hook/printf_hook.h | 121 | ||||
-rw-r--r-- | src/libstrongswan/utils/printf_hook/printf_hook_builtin.c | 1167 | ||||
-rw-r--r-- | src/libstrongswan/utils/printf_hook/printf_hook_builtin.h | 82 | ||||
-rw-r--r-- | src/libstrongswan/utils/printf_hook/printf_hook_glibc.c | 244 | ||||
-rw-r--r-- | src/libstrongswan/utils/printf_hook/printf_hook_vstr.c (renamed from src/libstrongswan/utils/printf_hook.c) | 259 | ||||
-rw-r--r-- | src/libstrongswan/utils/printf_hook/printf_hook_vstr.h | 83 |
15 files changed, 2032 insertions, 384 deletions
diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index 3811ed083..74b409608 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -35,7 +35,7 @@ selectors/traffic_selector.c threading/thread.c threading/thread_value.c \ threading/mutex.c threading/semaphore.c threading/rwlock.c threading/spinlock.c \ utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \ utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \ -utils/printf_hook.c utils/settings.c +utils/printf_hook/printf_hook_vstr.c utils/settings.c # adding the plugin source files diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 78e4ce2e1..54b19e139 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -33,7 +33,7 @@ selectors/traffic_selector.c threading/thread.c threading/thread_value.c \ threading/mutex.c threading/semaphore.c threading/rwlock.c threading/spinlock.c \ utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \ utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \ -utils/printf_hook.c utils/settings.c +utils/settings.c if USE_DEV_HEADERS strongswan_includedir = ${dev_headers} @@ -78,7 +78,9 @@ threading/mutex.h threading/condvar.h threading/spinlock.h threading/semaphore.h threading/rwlock.h threading/rwlock_condvar.h threading/lock_profiler.h \ utils/utils.h utils/chunk.h utils/debug.h utils/enum.h utils/identification.h \ utils/lexparser.h utils/optionsfrom.h utils/capabilities.h utils/backtrace.h \ -utils/leak_detective.h utils/printf_hook.h utils/settings.h utils/integrity_checker.h +utils/leak_detective.h utils/printf_hook/printf_hook.h \ +utils/printf_hook/printf_hook_vstr.h utils/printf_hook/printf_hook_builtin.h \ +utils/settings.h utils/integrity_checker.h endif library.lo : $(top_builddir)/config.status @@ -113,9 +115,21 @@ if USE_INTEGRITY_TEST endif if USE_VSTR + libstrongswan_la_SOURCES += utils/printf_hook/printf_hook_vstr.c libstrongswan_la_LIBADD += -lvstr endif +if USE_BUILTIN_PRINTF + libstrongswan_la_SOURCES += utils/printf_hook/printf_hook_builtin.c + libstrongswan_la_LIBADD += -lm +endif + +if !USE_BUILTIN_PRINTF +if !USE_VSTR + libstrongswan_la_SOURCES += utils/printf_hook/printf_hook_glibc.c +endif +endif + if USE_LIBCAP libstrongswan_la_LIBADD += -lcap endif diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h index 560da27f9..da2798014 100644 --- a/src/libstrongswan/library.h +++ b/src/libstrongswan/library.h @@ -90,7 +90,7 @@ #endif /* make sure we include printf_hook.h and utils.h first */ -#include "utils/printf_hook.h" +#include "utils/printf_hook/printf_hook.h" #include "utils/utils.h" #include "networking/host_resolver.h" #include "networking/streams/stream_manager.h" diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index 585f9c16e..c3d41a1cd 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -7,7 +7,7 @@ test_runner_SOURCES = \ test_linked_list.c test_enumerator.c test_linked_list_enumerator.c \ test_bio_reader.c test_bio_writer.c test_chunk.c test_enum.c test_hashtable.c \ test_identification.c test_threading.c test_utils.c test_vectors.c \ - test_array.c test_ecdsa.c test_rsa.c test_host.c + test_array.c test_ecdsa.c test_rsa.c test_host.c test_printf.c test_runner_CFLAGS = \ -I$(top_srcdir)/src/libstrongswan \ diff --git a/src/libstrongswan/tests/test_printf.c b/src/libstrongswan/tests/test_printf.c new file mode 100644 index 000000000..6c15fbea1 --- /dev/null +++ b/src/libstrongswan/tests/test_printf.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 "test_suite.h" + +#include <errno.h> +#include <math.h> + +static void verify(char *expected, char *format, ...) +{ + FILE *mem; + char buf[128]; + va_list args; + + va_start(args, format); + vsnprintf(buf, sizeof(buf), format, args); + ck_assert_str_eq(expected, buf); + va_end(args); + + mem = fmemopen(buf, sizeof(buf), "w"); + va_start(args, format); + vfprintf(mem, format, args); + va_end(args); + fclose(mem); + ck_assert_str_eq(expected, buf); +} + +START_TEST(test_printf_strings) +{ + verify("a bc def", "%s %s %s", "a", "bc", "def"); + verify("asd", "%.3s", "asdfg"); + verify("asdf", "%.*s", (int)4, "asdfg"); + verify(" asdf", "%6s", "asdf"); + verify(" asdf", "%+6s", "asdf"); + verify("asdf ", "%-6s", "asdf"); +} +END_TEST + +START_TEST(test_printf_err) +{ + errno = EINVAL; + verify((char*)strerror(errno), "%m"); +} +END_TEST + +START_TEST(test_printf_unsigned) +{ + verify("1 23 456", "%u %lu %llu", 1, (u_long)23, (u_int64_t)456); + verify("65535 255", "%hu %hhu", 0x1ffff, 0x1ff); + verify("123456789", "%zu", (size_t)123456789); + verify(" 12", "%5u", 12); + verify("12 ", "%-5u", 12); + verify("0012", "%04u", 12); + verify("0012", "%.4u", 12); +} +END_TEST + +START_TEST(test_printf_signed) +{ + verify("-1 -23 -456", "%d %ld %lld", -1, (long)-23, (int64_t)-456); + verify("-1 -1", "%hd %hhd", 0x1ffff, 0x1ff); + verify("123456789", "%zd", (ssize_t)123456789); + verify(" -12", "%5d", -12); + verify("-12 ", "%-5d", -12); + verify("-012", "%04d", -12); + verify("-0012", "%.4d", -12); +} +END_TEST + +START_TEST(test_printf_hex) +{ + verify("1 23 456", "%x %lx %llx", 1, (u_long)0x23, (u_int64_t)0x456); + verify("12abcdef 12ABCDEF", "%x %X", 0x12ABCDEF, 0x12ABCDEF); + verify("ffff ff", "%hx %hhx", 0x1ffff, 0x1ff); + verify("23456789", "%zx", (size_t)0x23456789); + verify(" ab", "%5x", 0xab); + verify("ab ", "%-5x", 0xab); + verify("00ab", "%04x", 0xab); + verify("00ab", "%.4x", 0xab); +} +END_TEST + +START_TEST(test_printf_float) +{ + verify("0.000000", "%f", 0.0); + verify("1.000000", "%f", 1.0); + verify("12345.1", "%.1f", 12345.123); + verify("1", "%.0f", 1.0); + verify("1.3", "%.1f", 1.346789); + verify("1.23", "%.2f", 1.23456789); + verify("1.123", "%.3f", 1.123456789); + verify("1.0123", "%.4f", 1.0123456789); + + verify("-1.000000", "%f", -1.0); + verify("-12345.1", "%.1f", -12345.123); + verify("-1", "%.0f", -1.0); + verify("-1.3", "%.1f", -1.3456789); + verify("-1.23", "%.2f", -1.23456789); + verify("-1.123", "%.3f", -1.123456789); + verify("-1.0123", "%.4f", -1.0123456789); + + verify(" 1.2", "%5.1f", 1.234); + verify("001.2", "%05.1f", 1.234); + verify("1.2 ", "%-5.1f", 1.234); + + verify("12346", "%.0f", 12345.6789); + verify("2", "%.0f", 1.5); + verify("1", "%.0f", 1.49); + verify("1.2", "%.1f", 1.151); + verify("1.1", "%.1f", 1.149); + verify("1.13", "%.2f", 1.1251); + verify("1.12", "%.2f", 1.1249); + verify("1.124", "%.3f", 1.12351); + verify("1.123", "%.3f", 1.12349); + + verify("-12346", "%.0f", -12345.6789); + verify("-2", "%.0f", -1.51); + verify("-1", "%.0f", -1.49); + verify("-1.2", "%.1f", -1.151); + verify("-1.1", "%.1f", -1.149); + verify("-1.13", "%.2f", -1.1251); + verify("-1.12", "%.2f", -1.1249); + verify("-1.124", "%.3f", -1.12351); + verify("-1.123", "%.3f", -1.12349); + +#ifdef NAN + verify("nan", "%.3f", NAN); + verify(" nan", "%5.3f", NAN); + verify("NAN", "%.3F", NAN); + verify("NAN ", "%-5.3F", NAN); +#endif +#ifdef INFINITY + verify("inf", "%.3f", INFINITY); + verify("-inf", "%.4f", -INFINITY); + verify("INF", "%.3F", INFINITY); + verify("-INF", "%.4F", -INFINITY); +#endif +} +END_TEST + +Suite *printf_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("printf"); + + tc = tcase_create("strings"); + tcase_add_test(tc, test_printf_strings); + suite_add_tcase(s, tc); + + tc = tcase_create("err"); + tcase_add_test(tc, test_printf_err); + suite_add_tcase(s, tc); + + tc = tcase_create("unsiged"); + tcase_add_test(tc, test_printf_unsigned); + suite_add_tcase(s, tc); + + tc = tcase_create("siged"); + tcase_add_test(tc, test_printf_signed); + suite_add_tcase(s, tc); + + tc = tcase_create("hex"); + tcase_add_test(tc, test_printf_hex); + suite_add_tcase(s, tc); + + tc = tcase_create("float"); + tcase_add_test(tc, test_printf_float); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index e7a04fd9a..f85858504 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -84,6 +84,7 @@ int main() srunner_add_suite(sr, utils_suite_create()); srunner_add_suite(sr, host_suite_create()); srunner_add_suite(sr, vectors_suite_create()); + srunner_add_suite(sr, printf_suite_create()); if (lib->plugins->has_feature(lib->plugins, PLUGIN_DEPENDS(PRIVKEY_GEN, KEY_RSA))) { diff --git a/src/libstrongswan/tests/test_runner.h b/src/libstrongswan/tests/test_runner.h index e9381756c..6315abba7 100644 --- a/src/libstrongswan/tests/test_runner.h +++ b/src/libstrongswan/tests/test_runner.h @@ -34,5 +34,6 @@ Suite *vectors_suite_create(); Suite *ecdsa_suite_create(); Suite *rsa_suite_create(); Suite *host_suite_create(); +Suite *printf_suite_create(); #endif /** TEST_RUNNER_H_ */ diff --git a/src/libstrongswan/utils/enum.h b/src/libstrongswan/utils/enum.h index df8dbf8c1..a2f97d05e 100644 --- a/src/libstrongswan/utils/enum.h +++ b/src/libstrongswan/utils/enum.h @@ -22,7 +22,7 @@ #ifndef ENUM_H_ #define ENUM_H_ -#include "printf_hook.h" +#include <utils/printf_hook/printf_hook.h> typedef struct enum_name_t enum_name_t; diff --git a/src/libstrongswan/utils/printf_hook.h b/src/libstrongswan/utils/printf_hook.h deleted file mode 100644 index 1425910be..000000000 --- a/src/libstrongswan/utils/printf_hook.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -/** - * @defgroup printf_hook printf_hook - * @{ @ingroup utils - */ - -#ifndef PRINTF_HOOK_H_ -#define PRINTF_HOOK_H_ - -typedef struct printf_hook_t printf_hook_t; -typedef struct printf_hook_spec_t printf_hook_spec_t; -typedef struct printf_hook_data_t printf_hook_data_t; -typedef enum printf_hook_argtype_t printf_hook_argtype_t; - -#if !defined(USE_VSTR) && \ - !defined(HAVE_PRINTF_FUNCTION) && \ - !defined(HAVE_PRINTF_SPECIFIER) -/* assume newer glibc register_printf_specifier if none given */ -#define HAVE_PRINTF_SPECIFIER -#endif - -#if !defined(USE_VSTR) && \ - (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER)) - -#include <stdio.h> -#include <printf.h> - -enum printf_hook_argtype_t { - PRINTF_HOOK_ARGTYPE_END = -1, - PRINTF_HOOK_ARGTYPE_INT = PA_INT, - PRINTF_HOOK_ARGTYPE_POINTER = PA_POINTER, -}; - -/** - * Data to pass to a printf hook. - */ -struct printf_hook_data_t { - - /** - * Output FILE stream - */ - FILE *stream;; -}; - -/** - * Helper macro to be used in printf hook callbacks. - */ -#define print_in_hook(data, fmt, ...) ({\ - ssize_t _written = fprintf(data->stream, fmt, ##__VA_ARGS__);\ - if (_written < 0)\ - {\ - _written = 0;\ - }\ - _written;\ -}) - -#else - -#include <vstr.h> - -enum printf_hook_argtype_t { - PRINTF_HOOK_ARGTYPE_END = VSTR_TYPE_FMT_END, - PRINTF_HOOK_ARGTYPE_INT = VSTR_TYPE_FMT_INT, - PRINTF_HOOK_ARGTYPE_POINTER = VSTR_TYPE_FMT_PTR_VOID, -}; - -/** - * Redefining printf and alike - */ -#include <stdio.h> -#include <stdarg.h> - -int vstr_wrapper_printf(const char *format, ...); -int vstr_wrapper_fprintf(FILE *stream, const char *format, ...); -int vstr_wrapper_sprintf(char *str, const char *format, ...); -int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...); -int vstr_wrapper_asprintf(char **str, const char *format, ...); - -int vstr_wrapper_vprintf(const char *format, va_list ap); -int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list ap); -int vstr_wrapper_vsprintf(char *str, const char *format, va_list ap); -int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format, va_list ap); -int vstr_wrapper_vasprintf(char **str, const char *format, va_list ap); - -#ifdef printf -#undef printf -#endif -#ifdef fprintf -#undef fprintf -#endif -#ifdef sprintf -#undef sprintf -#endif -#ifdef snprintf -#undef snprintf -#endif -#ifdef asprintf -#undef asprintf -#endif -#ifdef vprintf -#undef vprintf -#endif -#ifdef vfprintf -#undef vfprintf -#endif -#ifdef vsprintf -#undef vsprintf -#endif -#ifdef vsnprintf -#undef vsnprintf -#endif -#ifdef vasprintf -#undef vasprintf -#endif - -#define printf vstr_wrapper_printf -#define fprintf vstr_wrapper_fprintf -#define sprintf vstr_wrapper_sprintf -#define snprintf vstr_wrapper_snprintf -#define asprintf vstr_wrapper_asprintf - -#define vprintf vstr_wrapper_vprintf -#define vfprintf vstr_wrapper_vfprintf -#define vsprintf vstr_wrapper_vsprintf -#define vsnprintf vstr_wrapper_vsnprintf -#define vasprintf vstr_wrapper_vasprintf - -/** - * 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; -}; - -/** - * Wrapper around vstr_add_vfmt(), avoids having to link all users of - * print_in_hook() against libvstr. - * - * @param base Vstr_string to add string to - * @param pos position to write to - * @param fmt format string - * @param ... arguments - * @return number of characters written - */ -size_t vstr_print_in_hook(struct Vstr_base *base, size_t pos, const char *fmt, - ...); - -/** - * Helper macro to be used in printf hook callbacks. - */ -#define print_in_hook(data, fmt, ...) ({\ - size_t _written; \ - _written = vstr_print_in_hook(data->base, data->pos, fmt, ##__VA_ARGS__);\ - data->pos += _written;\ - _written;\ -}) - -#endif - -/** - * Callback function type for printf hooks. - * - * @param data hook data, to pass to print_in_hook() - * @param spec format specifier - * @param args arguments array - * @return number of characters written - */ -typedef int (*printf_hook_function_t)(printf_hook_data_t *data, - printf_hook_spec_t *spec, - const void *const *args); - -/** - * Properties of the format specifier - */ -struct printf_hook_spec_t { - /** - * TRUE if a '#' was used in the format specifier - */ - int hash; - - /** - * TRUE if a '-' was used in the format specifier - */ - int minus; - - /** - * TRUE if a '+' was used in the format specifier - */ - int plus; - - /** - * The width as given in the format specifier. - */ - int width; -}; - -/** - * Printf handler management. - */ -struct printf_hook_t { - - /** - * Register a printf handler. - * - * @param spec printf hook format character - * @param hook hook function - * @param ... list of PRINTF_HOOK_ARGTYPE_*, MUST end with PRINTF_HOOK_ARGTYPE_END - */ - void (*add_handler)(printf_hook_t *this, char spec, - printf_hook_function_t hook, ...); - - /** - * Destroy a printf_hook instance. - */ - void (*destroy)(printf_hook_t *this); -}; - -/** - * Create a printf_hook instance. - */ -printf_hook_t *printf_hook_create(); - -#endif /** PRINTF_HOOK_H_ @}*/ diff --git a/src/libstrongswan/utils/printf_hook/printf_hook.h b/src/libstrongswan/utils/printf_hook/printf_hook.h new file mode 100644 index 000000000..c1d6fa90d --- /dev/null +++ b/src/libstrongswan/utils/printf_hook/printf_hook.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2009 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. + */ + +/** + * @defgroup printf_hook printf_hook + * @{ @ingroup utils + */ + +#ifndef PRINTF_HOOK_H_ +#define PRINTF_HOOK_H_ + +#include <stdlib.h> + +typedef struct printf_hook_t printf_hook_t; +typedef struct printf_hook_spec_t printf_hook_spec_t; +typedef struct printf_hook_data_t printf_hook_data_t; +typedef enum printf_hook_argtype_t printf_hook_argtype_t; + +#if defined(USE_VSTR) +# include "printf_hook_vstr.h" +#elif defined(USE_BUILTIN_PRINTF) +# include "printf_hook_builtin.h" +#endif + +/** + * Argument types to pass to printf hook. + */ +enum printf_hook_argtype_t { + PRINTF_HOOK_ARGTYPE_END, + PRINTF_HOOK_ARGTYPE_INT, + PRINTF_HOOK_ARGTYPE_POINTER, +}; + +/** + * Callback function type for printf hooks. + * + * @param data hook data, to pass to print_in_hook() + * @param spec format specifier + * @param args arguments array + * @return number of characters written + */ +typedef int (*printf_hook_function_t)(printf_hook_data_t *data, + printf_hook_spec_t *spec, + const void *const *args); + +/** + * Properties of the format specifier + */ +struct printf_hook_spec_t { + + /** + * TRUE if a '#' was used in the format specifier + */ + int hash; + + /** + * TRUE if a '-' was used in the format specifier + */ + int minus; + + /** + * TRUE if a '+' was used in the format specifier + */ + int plus; + + /** + * The width as given in the format specifier. + */ + int width; +}; + +/** + * Printf handler management. + */ +struct printf_hook_t { + + /** + * Register a printf handler. + * + * @param spec printf hook format character + * @param hook hook function + * @param ... list of PRINTF_HOOK_ARGTYPE_*, MUST end with PRINTF_HOOK_ARGTYPE_END + */ + void (*add_handler)(printf_hook_t *this, char spec, + printf_hook_function_t hook, ...); + + /** + * Destroy a printf_hook instance. + */ + void (*destroy)(printf_hook_t *this); +}; + +/** + * Create a printf_hook instance. + */ +printf_hook_t *printf_hook_create(); + +/** + * Print with format string within a printf hook. + * + * @param data hook data, as passed to printf hook + * @param fmt printf format string + * @param ... arguments to format string + * @return number of characters written + */ +size_t print_in_hook(printf_hook_data_t *data, char *fmt, ...); + +#endif /** PRINTF_HOOK_H_ @}*/ diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c new file mode 100644 index 000000000..ec0a418d8 --- /dev/null +++ b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c @@ -0,0 +1,1167 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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. + */ + +/** + * Copyright (C) 2002-2006 H. Peter Anvin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "printf_hook.h" + +#include <utils/utils.h> +#include <utils/debug.h> +#include <collections/hashtable.h> + +#include <inttypes.h> +#include <limits.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <math.h> + +#define PRINTF_BUF_LEN 8192 +#define ARGS_MAX 3 + +typedef struct private_printf_hook_t private_printf_hook_t; +typedef struct printf_hook_handler_t printf_hook_handler_t; + +/** + * 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 + */ + int argtypes[ARGS_MAX]; +}; + +/** + * Data to pass to a printf hook. + */ +struct printf_hook_data_t { + + /** + * Output buffer + */ + char *q; + + /** + * Remaining bytes in q + */ + size_t n; +}; + +/** + * Registered hooks (char => printf_hook_handler_t) + */ +static hashtable_t *hooks; + +/** + * builtin-printf variant of print_in_hook() + */ +size_t print_in_hook(printf_hook_data_t *data, char *fmt, ...) +{ + int written; + va_list args; + + va_start(args, fmt); + written = builtin_vsnprintf(data->q, data->n, fmt, args); + va_end(args); + + if (written > data->n) + { + written = data->n; + } + data->q += written; + data->n += written; + 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; + + 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 >= countof(handler->argtypes)) + { + DBG1(DBG_LIB, "Too many arguments for printf hook with " + "specifier '%c', not registered!", spec); + failed = TRUE; + break; + } + handler->argtypes[i] = argtype; + } + va_end(args); + + handler->numargs = i + 1; + if (!failed && handler->numargs > 0) + { + free(hooks->put(hooks, (void*)(uintptr_t)spec, handler)); + } + else + { + free(handler); + } +} + +/** + * Printf format modifier flags + */ +typedef enum { + FL_ZERO = 0x01, + FL_MINUS = 0x02, + FL_PLUS = 0x04, + FL_TICK = 0x08, + FL_SPACE = 0x10, + FL_HASH = 0x20, + FL_SIGNED = 0x40, + FL_UPPER = 0x80, +} bpf_flag_t; + +/** + * Size of format string arguments + */ +typedef enum { + RNK_CHAR = -2, + RNK_SHORT = -1, + RNK_INT = 0, + RNK_LONG = 1, + RNK_LONGLONG = 2, + + RNK_INTMAX = RNK_LONGLONG, + RNK_SIZE_T = RNK_LONG, + RNK_PTRDIFF_T = RNK_LONG, + + RNK_MIN = RNK_CHAR, + RNK_MAX = RNK_LONGLONG, +} bpf_rank_t; + +/** + * Printf specifier Parser state + */ +typedef enum { + /* Ground state */ + ST_NORMAL, + /* Special flags */ + ST_FLAGS, + /* Field width */ + ST_WIDTH, + /* Field precision */ + ST_PREC, + /* Length or conversion modifiers */ + ST_MODIFIERS, +} bpf_state_t; + +#define EMIT(x) ({ if (o<n){*q++ = (x);} o++; }) + +static const char lcdigits[] = "0123456789abcdef"; +static const char ucdigits[] = "0123456789ABCDEF"; + +/** + * Write an integer argument to q, using flags, base, width and precision + */ +static size_t format_int(char *q, size_t n, uintmax_t val, bpf_flag_t flags, + int base, int width, int prec) +{ + char *qq; + size_t o = 0, oo; + const char *digits; + uintmax_t tmpval; + int minus = 0; + int ndigits = 0, nchars; + int tickskip, b4tick; + + /* Select type of digits */ + digits = (flags & FL_UPPER) ? ucdigits : lcdigits; + + /* If signed, separate out the minus */ + if (flags & FL_SIGNED && (intmax_t) val < 0) + { + minus = 1; + val = (uintmax_t) (-(intmax_t) val); + } + + /* Count the number of digits needed. This returns zero for 0. */ + tmpval = val; + while (tmpval) + { + tmpval /= base; + ndigits++; + } + + /* Adjust ndigits for size of output */ + if (flags & FL_HASH && base == 8) + { + if (prec < ndigits + 1) + { + prec = ndigits + 1; + } + } + + if (ndigits < prec) + { + /* Mandatory number padding */ + ndigits = prec; + } + else if (val == 0) + { + /* Zero still requires space */ + ndigits = 1; + } + + /* For ', figure out what the skip should be */ + if (flags & FL_TICK) + { + if (base == 16) + { + tickskip = 4; + } + else + { + tickskip = 3; + } + } + else + { + /* No tick marks */ + tickskip = ndigits; + } + + /* Tick marks aren't digits, but generated by the number converter */ + ndigits += (ndigits - 1) / tickskip; + + /* Now compute the number of nondigits */ + nchars = ndigits; + + if (minus || (flags & (FL_PLUS | FL_SPACE))) + { + /* Need space for sign */ + nchars++; + } + if ((flags & FL_HASH) && base == 16) + { + /* Add 0x for hex */ + nchars += 2; + } + + /* Emit early space padding */ + if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars) + { + while (width > nchars) + { + EMIT(' '); + width--; + } + } + + /* Emit nondigits */ + if (minus) + { + EMIT('-'); + } + else if (flags & FL_PLUS) + { + EMIT('+'); + } + else if (flags & FL_SPACE) + { + EMIT(' '); + } + + if ((flags & FL_HASH) && base == 16) + { + EMIT('0'); + EMIT((flags & FL_UPPER) ? 'X' : 'x'); + } + + /* Emit zero padding */ + if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits) + { + while (width > nchars) + { + EMIT('0'); + width--; + } + } + + /* Generate the number. This is done from right to left. */ + /* Advance the pointer to end of number */ + q += ndigits; + o += ndigits; + /* Temporary values */ + qq = q; + oo = o; + + b4tick = tickskip; + while (ndigits > 0) + { + if (!b4tick--) + { + qq--; + oo--; + ndigits--; + if (oo < n) + { + *qq = '_'; + } + b4tick = tickskip - 1; + } + qq--; + oo--; + ndigits--; + if (oo < n) + { + *qq = digits[val % base]; + } + val /= base; + } + + /* Emit late space padding */ + while ((flags & FL_MINUS) && width > nchars) + { + EMIT(' '); + width--; + } + + return o; +} + +/** + * Write an double argument to q, using flags, base, width and precision + */ +static size_t format_double(char *q, size_t n, double val, bpf_flag_t flags, + int base, int width, int prec) +{ + char *qq; + size_t o = 0, oo; + const char *digits; + uintmax_t tmpval; + int minus = 0; + int ndigits = 0, nchars; + + /* Select type of digits */ + digits = (flags & FL_UPPER) ? ucdigits : lcdigits; + + if (prec < 0) + { + /* default precision */ + prec = 6; + } + if (val < 0) + { + minus = 1; + } + + tmpval = (uintmax_t)fabs(val); + while (tmpval) + { + tmpval /= base; + ndigits++; + } + if (val == 0) + { + ndigits++; + } + + /* Now compute the number of nondigits */ + nchars = ndigits; + + if (prec) + { + /* Space for decimal-point and digits after that */ + nchars += prec + 1; + } + if (minus || (flags & (FL_PLUS | FL_SPACE))) + { + /* Need space for sign */ + nchars++; + } + if ((flags & FL_HASH) && base == 16) + { + /* Add 0x for hex */ + nchars += 2; + } + + /* Emit early space padding */ + if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars) + { + while (width > nchars) + { + EMIT(' '); + width--; + } + } + + /* Emit nondigits */ + if (minus) + { + EMIT('-'); + } + else if (flags & FL_PLUS) + { + EMIT('+'); + } + else if (flags & FL_SPACE) + { + EMIT(' '); + } + + if ((flags & FL_HASH) && base == 16) + { + EMIT('0'); + EMIT((flags & FL_UPPER) ? 'X' : 'x'); + } + + /* Emit zero padding */ + if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits) + { + while (width > nchars) + { + EMIT('0'); + width--; + } + } + + /* Generate the number. This is done from right to left. */ + /* Advance the pointer to end of number */ + q += ndigits; + o += ndigits; + /* Temporary values */ + qq = q; + oo = o; + + tmpval = (uintmax_t)fabs(val); + if (!prec) + { + /* round up if no additional digits */ + if (fabs(val) - tmpval >= 0.5) + { + tmpval++; + } + } + while (ndigits > 0) + { + qq--; + oo--; + ndigits--; + if (oo < n) + { + *qq = digits[tmpval % base]; + } + tmpval /= base; + } + + if (prec) + { + EMIT('.'); + + q += prec; + o += prec; + qq = q; + oo = o; + + tmpval = (uintmax_t)(fabs(val) * pow(base, prec)); + /* round up if required */ + if (fabs(val) * pow(base, prec) - tmpval >= 0.5) + { + tmpval++; + } + while (prec > 0) + { + qq--; + oo--; + prec--; + if (oo < n) + { + *qq = digits[tmpval % base]; + } + tmpval /= base; + } + } + + /* Emit late space padding */ + while ((flags & FL_MINUS) && width > nchars) + { + EMIT(' '); + width--; + } + + return o; +} + +int builtin_vsnprintf(char *buffer, size_t n, const char *format, va_list ap) +{ + const char *p = format; + char ch; + char *q = buffer; + /* Number of characters output */ + size_t o = 0; + uintmax_t val = 0; + /* Default rank */ + int rank = RNK_INT; + int width = 0; + int prec = -1; + int base; + size_t sz; + bpf_flag_t flags = 0; + bpf_state_t state = ST_NORMAL; + /* %s string argument */ + const char *sarg; + /* %c char argument */ + char carg; + /* String length */ + int slen; + + while ((ch = *p++)) + { + switch (state) + { + case ST_NORMAL: + { + if (ch == '%') + { + state = ST_FLAGS; + flags = 0; + rank = RNK_INT; + width = 0; + prec = -1; + } + else + { + EMIT(ch); + } + break; + } + case ST_FLAGS: + { + switch (ch) + { + case '-': + flags |= FL_MINUS; + break; + case '+': + flags |= FL_PLUS; + break; + case '\'': + flags |= FL_TICK; + break; + case ' ': + flags |= FL_SPACE; + break; + case '#': + flags |= FL_HASH; + break; + case '0': + flags |= FL_ZERO; + break; + default: + state = ST_WIDTH; + /* Process this character again */ + p--; + break; + } + break; + } + case ST_WIDTH: + { + if (ch >= '0' && ch <= '9') + { + width = width * 10 + (ch - '0'); + } + else if (ch == '*') + { + width = va_arg(ap, int); + if (width < 0) + { + width = -width; + flags |= FL_MINUS; + } + } + else if (ch == '.') + { + /* Precision given */ + prec = 0; + state = ST_PREC; + } + else + { + state = ST_MODIFIERS; + /* Process this character again */ + p--; + } + break; + } + case ST_PREC: + { + if (ch >= '0' && ch <= '9') + { + prec = prec * 10 + (ch - '0'); + } + else if (ch == '*') + { + prec = va_arg(ap, int); + if (prec < 0) + { + prec = -1; + } + } + else + { + state = ST_MODIFIERS; + /* Process this character again */ + p--; + } + break; + } + case ST_MODIFIERS: + { + switch (ch) + { + /* Length modifiers - nonterminal sequences */ + case 'h': + rank--; + break; + case 'l': + rank++; + break; + case 'j': + rank = RNK_INTMAX; + break; + case 'z': + rank = RNK_SIZE_T; + break; + case 't': + rank = RNK_PTRDIFF_T; + break; + case 'L': + case 'q': + rank += 2; + break; + default: + { + /* Output modifiers - terminal sequences */ + + /* Next state will be normal */ + state = ST_NORMAL; + + /* Canonicalize rank */ + if (rank < RNK_MIN) + { + rank = RNK_MIN; + } + else if (rank > RNK_MAX) + { + rank = RNK_MAX; + } + + switch (ch) + { + case 'P': + { + /* Upper case pointer */ + flags |= FL_UPPER; + /* fall through */ + } + case 'p': + { + /* Pointer */ + base = 16; + prec = (CHAR_BIT*sizeof(void *)+3)/4; + flags |= FL_HASH; + val = (uintmax_t)(uintptr_t) + va_arg(ap, void *); + goto is_integer; + } + case 'd': + case 'i': + { + /* Signed decimal output */ + base = 10; + flags |= FL_SIGNED; + switch (rank) + { + case RNK_CHAR: + /* Yes, all these casts are + needed... */ + val = (uintmax_t)(intmax_t)(signed char) + va_arg(ap, signed int); + break; + case RNK_SHORT: + val = (uintmax_t)(intmax_t)(signed short) + va_arg(ap, signed int); + break; + case RNK_INT: + val = (uintmax_t)(intmax_t) + va_arg(ap, signed int); + break; + case RNK_LONG: + val = (uintmax_t)(intmax_t) + va_arg(ap, signed long); + break; + case RNK_LONGLONG: + val = (uintmax_t)(intmax_t) + va_arg(ap, signed long long); + break; + } + goto is_integer; + } + case 'o': + { + /* Octal */ + base = 8; + goto is_unsigned; + } + case 'u': + { + /* Unsigned decimal */ + base = 10; + goto is_unsigned; + } + case 'X': + { + /* Upper case hexadecimal */ + flags |= FL_UPPER; + /* fall through */ + } + case 'x': + { + /* Hexadecimal */ + base = 16; + goto is_unsigned; + } + is_unsigned: + { + switch (rank) { + case RNK_CHAR: + val = (uintmax_t)(unsigned char) + va_arg(ap, unsigned int); + break; + case RNK_SHORT: + val = (uintmax_t)(unsigned short) + va_arg(ap, unsigned int); + break; + case RNK_INT: + val = (uintmax_t) + va_arg(ap, unsigned int); + break; + case RNK_LONG: + val = (uintmax_t) + va_arg(ap, unsigned long); + break; + case RNK_LONGLONG: + val = (uintmax_t) + va_arg(ap, unsigned long long); + break; + } + goto is_integer; + } + is_integer: + { + sz = format_int(q, (o < n) ? n - o : 0, + val, flags, base, width, prec); + q += sz; + o += sz; + break; + } + case 'c': + { + /* Character */ + carg = (char)va_arg(ap, int); + sarg = &carg; + slen = 1; + goto is_string; + } + case 's': + { + /* String */ + sarg = va_arg(ap, const char *); + sarg = sarg ? sarg : "(null)"; + slen = strlen(sarg); + goto is_string; + } + case 'm': + { + /* glibc error string */ + sarg = strerror(errno); + slen = strlen(sarg); + goto is_string; + } + is_string: + { + char sch; + int i; + + if (prec != -1 && slen > prec) + { + slen = prec; + } + + if (width > slen && !(flags & FL_MINUS)) + { + char pad = (flags & FL_ZERO) ? '0' : ' '; + while (width > slen) + { + EMIT(pad); + width--; + } + } + for (i = slen; i; i--) + { + sch = *sarg++; + EMIT(sch); + } + if (width > slen && (flags & FL_MINUS)) + { + while (width > slen) + { + EMIT(' '); + width--; + } + } + break; + } + case 'A': + { + base = 16; + flags |= FL_UPPER; + goto is_double; + } + case 'E': + case 'G': + { + /* currently not supported, fall */ + } + case 'F': + { + base = 10; + flags |= FL_UPPER; + goto is_double; + } + case 'a': + { + base = 16; + goto is_double; + } + case 'e': + case 'g': + { + /* currently not supported, fall */ + } + case 'f': + { + base = 10; + goto is_double; + } + is_double: + { + double dval; + + dval = va_arg(ap, double); + if (isinf(dval) == 1) + { + sarg = flags & FL_UPPER ? "INF" : "inf"; + slen = strlen(sarg); + goto is_string; + } + if (isinf(dval) == -1) + { + sarg = flags & FL_UPPER ? "-INF" : "-inf"; + slen = strlen(sarg); + goto is_string; + } + if (isnan(dval)) + { + sarg = flags & FL_UPPER ? "NAN" : "nan"; + slen = strlen(sarg); + goto is_string; + } + sz = format_double(q, (o < n) ? n - o : 0, + dval, flags, base, width, prec); + q += sz; + o += sz; + break; + } + case 'n': + { + /* Output the number of characters written */ + switch (rank) + { + case RNK_CHAR: + *va_arg(ap, signed char *) = o; + break; + case RNK_SHORT: + *va_arg(ap, signed short *) = o; + break; + case RNK_INT: + *va_arg(ap, signed int *) = o; + break; + case RNK_LONG: + *va_arg(ap, signed long *) = o; + break; + case RNK_LONGLONG: + *va_arg(ap, signed long long *) = o; + break; + } + break; + } + default: + { + printf_hook_handler_t *handler; + + handler = hooks->get(hooks, (void*)(uintptr_t)ch); + if (handler) + { + const void *args[ARGS_MAX]; + int i, iargs[ARGS_MAX]; + void *pargs[ARGS_MAX]; + printf_hook_spec_t spec = { + .hash = flags & FL_HASH, + .plus = flags & FL_PLUS, + .minus = flags & FL_MINUS, + .width = width, + }; + printf_hook_data_t data = { + .q = q, + .n = (o < n) ? n - o : 0, + }; + + for (i = 0; i < handler->numargs; i++) + { + switch (handler->argtypes[i]) + { + case PRINTF_HOOK_ARGTYPE_INT: + iargs[i] = va_arg(ap, int); + args[i] = &iargs[i]; + break; + case PRINTF_HOOK_ARGTYPE_POINTER: + pargs[i] = va_arg(ap, void*); + args[i] = &pargs[i]; + break; + } + } + sz = handler->hook(&data, &spec, args); + q += sz; + o += sz; + } + else + { + /* Anything else, including % */ + EMIT(ch); + } + break; + } + } + } + } + } + } + } + + /* Null-terminate the string */ + if (o < n) + { + /* No overflow */ + *q = '\0'; + } + else if (n > 0) + { + /* Overflow - terminate at end of buffer */ + buffer[n - 1] = '\0'; + } + return o; +} + +int builtin_printf(const char *format, ...) +{ + int written; + va_list args; + + va_start(args, format); + written = builtin_vprintf(format, args); + va_end(args); + + return written; +} + +int builtin_fprintf(FILE *stream, const char *format, ...) +{ + int written; + va_list args; + + va_start(args, format); + written = builtin_vfprintf(stream, format, args); + va_end(args); + + return written; +} + +int builtin_sprintf(char *str, const char *format, ...) +{ + int written; + va_list args; + + va_start(args, format); + written = builtin_vsnprintf(str, ~(size_t)0, format, args); + va_end(args); + + return written; +} + +int builtin_snprintf(char *str, size_t size, const char *format, ...) +{ + int written; + va_list args; + + va_start(args, format); + written = builtin_vsnprintf(str, size, format, args); + va_end(args); + + return written; +} + +int builtin_asprintf(char **str, const char *format, ...) +{ + int written; + va_list args; + + va_start(args, format); + written = builtin_vasprintf(str, format, args); + va_end(args); + + return written; +} + +int builtin_vprintf(const char *format, va_list ap) +{ + return builtin_vfprintf(stdout, format, ap); +} + +int builtin_vfprintf(FILE *stream, const char *format, va_list ap) +{ + char buf[PRINTF_BUF_LEN]; + int len; + + len = builtin_vsnprintf(buf, sizeof(buf), format, ap); + return fwrite(buf, 1, len, stream); +} + +int builtin_vsprintf(char *str, const char *format, va_list ap) +{ + return builtin_vsnprintf(str, ~(size_t)0, format, ap); +} + +int builtin_vasprintf(char **str, const char *format, va_list ap) +{ + char buf[PRINTF_BUF_LEN]; + int len; + + len = builtin_vsnprintf(buf, sizeof(buf), format, ap); + *str = strdup(buf); + return len; +} + +METHOD(printf_hook_t, destroy, void, + private_printf_hook_t *this) +{ + enumerator_t *enumerator; + printf_hook_handler_t *handler; + + enumerator = hooks->create_enumerator(hooks); + while (enumerator->enumerate(enumerator, NULL, &handler)) + { + free(handler); + } + enumerator->destroy(enumerator); + + hooks->destroy(hooks); + + 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, + }, + ); + + hooks = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 8); + + return &this->public; +} diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_builtin.h b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.h new file mode 100644 index 000000000..409b5bf3d --- /dev/null +++ b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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. + */ + +/** + * @defgroup printf_hook_builtin printf_hook_builtin + * @{ @ingroup utils + */ + +#ifndef PRINTF_HOOK_BUILTIN_H_ +#define PRINTF_HOOK_BUILTIN_H_ + +#include <stdarg.h> +#include <stdio.h> + +int builtin_printf(const char *format, ...); +int builtin_fprintf(FILE *stream, const char *format, ...); +int builtin_sprintf(char *str, const char *format, ...); +int builtin_snprintf(char *str, size_t size, const char *format, ...); +int builtin_asprintf(char **str, const char *format, ...); + +int builtin_vprintf(const char *format, va_list ap); +int builtin_vfprintf(FILE *stream, const char *format, va_list ap); +int builtin_vsprintf(char *str, const char *format, va_list ap); +int builtin_vsnprintf(char *str, size_t size, const char *format, va_list ap); +int builtin_vasprintf(char **str, const char *format, va_list ap); + +#ifdef printf +#undef printf +#endif +#ifdef fprintf +#undef fprintf +#endif +#ifdef sprintf +#undef sprintf +#endif +#ifdef snprintf +#undef snprintf +#endif +#ifdef asprintf +#undef asprintf +#endif +#ifdef vprintf +#undef vprintf +#endif +#ifdef vfprintf +#undef vfprintf +#endif +#ifdef vsprintf +#undef vsprintf +#endif +#ifdef vsnprintf +#undef vsnprintf +#endif +#ifdef vasprintf +#undef vasprintf +#endif + +#define printf builtin_printf +#define fprintf builtin_fprintf +#define sprintf builtin_sprintf +#define snprintf builtin_snprintf +#define asprintf builtin_asprintf + +#define vprintf builtin_vprintf +#define vfprintf builtin_vfprintf +#define vsprintf builtin_vsprintf +#define vsnprintf builtin_vsnprintf +#define vasprintf builtin_vasprintf + +#endif /** PRINTF_HOOK_BUILTIN_H_ @}*/ diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_glibc.c b/src/libstrongswan/utils/printf_hook/printf_hook_glibc.c new file mode 100644 index 000000000..8fd1aed4a --- /dev/null +++ b/src/libstrongswan/utils/printf_hook/printf_hook_glibc.c @@ -0,0 +1,244 @@ +/* + * 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 <printf.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +typedef struct private_printf_hook_t private_printf_hook_t; +typedef struct printf_hook_handler_t printf_hook_handler_t; + +/** + * 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, PA_* + */ + int argtypes[3]; +}; + +/** + * Data to pass to a printf hook. + */ +struct printf_hook_data_t { + + /** + * Output FILE stream + */ + FILE *stream;; +}; + +/* A-Z | 6 other chars | a-z */ +static printf_hook_handler_t *printf_hooks[58]; + +#define SPEC_TO_INDEX(spec) ((int)(spec) - (int)'A') + +/** + * Glibc variant of print_in_hook() + */ +size_t print_in_hook(printf_hook_data_t *data, char *fmt, ...) +{ + ssize_t written; + va_list args; + + va_start(args, fmt); + written = vfprintf(data->stream, fmt, args); + va_end(args); + + if (written < 0) + { + written = 0; + } + return written; +} + +/** + * Printf hook print function. This is actually of type "printf_function", + * however glibc does it typedef to function, but uclibc to a pointer. + * So we redefine it here. + */ +static int custom_print(FILE *stream, const struct printf_info *info, + const void *const *args) +{ + printf_hook_spec_t spec; + printf_hook_handler_t *handler; + printf_hook_data_t data = { + .stream = stream, + }; + + handler = printf_hooks[SPEC_TO_INDEX(info->spec)]; + spec.hash = info->alt; + spec.plus = info->showsign; + spec.minus = info->left; + spec.width = info->width; + + return handler->hook(&data, &spec, args); +} + +/** + * Printf hook arginfo function, which is actually of type + * "printf_arginfo_[size_]function". + */ +static int custom_arginfo(const struct printf_info *info, size_t n, int *argtypes +#ifdef HAVE_PRINTF_SPECIFIER + , int *size +#endif + ) +{ + int i; + printf_hook_handler_t *handler; + + handler = printf_hooks[SPEC_TO_INDEX(info->spec)]; + if (handler->numargs <= n) + { + for (i = 0; i < handler->numargs; ++i) + { + argtypes[i] = handler->argtypes[i]; + } + } + /* we never set "size", as we have no user defined types */ + return handler->numargs; +} + +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 >= countof(handler->argtypes)) + { + 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] = PA_INT; + break; + case PRINTF_HOOK_ARGTYPE_POINTER: + handler->argtypes[i] = PA_POINTER; + 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) + { +# ifdef HAVE_PRINTF_SPECIFIER + register_printf_specifier(spec, custom_print, custom_arginfo); +# else + register_printf_function(spec, custom_print, custom_arginfo); +# endif + printf_hooks[SPEC_TO_INDEX(spec)] = handler; + } + else + { + free(handler); + } +} + +METHOD(printf_hook_t, destroy, void, + private_printf_hook_t *this) +{ + int i; + + for (i = 0; i < countof(printf_hooks); i++) + { + free(printf_hooks[i]); + } + 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)); + + return &this->public; +} diff --git a/src/libstrongswan/utils/printf_hook.c b/src/libstrongswan/utils/printf_hook/printf_hook_vstr.c index aabfdc53f..f1884f119 100644 --- a/src/libstrongswan/utils/printf_hook.c +++ b/src/libstrongswan/utils/printf_hook/printf_hook_vstr.c @@ -16,13 +16,14 @@ #include "printf_hook.h" -#include "utils.h" -#include "debug.h" +#include <utils/utils.h> +#include <utils/debug.h> +#include <threading/thread_value.h> -#include <stdio.h> -#include <stdarg.h> +#include <vstr.h> #include <string.h> -#include <sys/uio.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; @@ -57,78 +58,36 @@ struct printf_hook_handler_t { int numargs; /** - * types of the arguments + * types of the arguments, VSTR_TYPE_FMT_* */ int argtypes[ARGS_MAX]; -#ifdef USE_VSTR /** * name required for Vstr */ char *name; -#endif }; -/* A-Z | 6 other chars | a-z */ -#define NUM_HANDLERS 58 -static printf_hook_handler_t *printf_hooks[NUM_HANDLERS]; - -#define SPEC_TO_INDEX(spec) ((int)(spec) - (int)'A') -#define IS_VALID_SPEC(spec) (SPEC_TO_INDEX(spec) > -1 && SPEC_TO_INDEX(spec) < NUM_HANDLERS) - -#if !defined(USE_VSTR) && \ - (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER)) - /** - * Printf hook print function. This is actually of type "printf_function", - * however glibc does it typedef to function, but uclibc to a pointer. - * So we redefine it here. + * Data to pass to a printf hook. */ -static int custom_print(FILE *stream, const struct printf_info *info, - const void *const *args) -{ - printf_hook_spec_t spec; - printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)]; - printf_hook_data_t data = { - .stream = stream, - }; - - spec.hash = info->alt; - spec.plus = info->showsign; - spec.minus = info->left; - spec.width = info->width; - - return handler->hook(&data, &spec, args); -} +struct printf_hook_data_t { -/** - * Printf hook arginfo function, which is actually of type - * "printf_arginfo_[size_]function". - */ -static int custom_arginfo(const struct printf_info *info, size_t n, int *argtypes -#ifdef HAVE_PRINTF_SPECIFIER - , int *size -#endif - ) -{ - int i; - printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)]; + /** + * Base to append printf to + */ + Vstr_base *base; - if (handler->numargs <= n) - { - for (i = 0; i < handler->numargs; ++i) - { - argtypes[i] = handler->argtypes[i]; - } - } - /* we never set "size", as we have no user defined types */ - return handler->numargs; -} + /** + * Position in base to write to + */ + size_t pos; +}; -#else +/* A-Z | 6 other chars | a-z */ +static printf_hook_handler_t *printf_hooks[58]; -#include <errno.h> -#include <unistd.h> /* for STDOUT_FILENO */ +#define SPEC_TO_INDEX(spec) ((int)(spec) - (int)'A') /** * These are used below, whenever the public wrapper functions are called before @@ -139,6 +98,22 @@ static int custom_arginfo(const struct printf_info *info, size_t n, int *argtype #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) @@ -146,20 +121,21 @@ 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_hooks[SPEC_TO_INDEX(fmt_spec->name[0])]; + 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]) + switch (handler->argtypes[i]) { - case PRINTF_HOOK_ARGTYPE_INT: + case VSTR_TYPE_FMT_INT: args[i] = VSTR_FMT_CB_ARG_PTR(fmt_spec, i); break; - case PRINTF_HOOK_ARGTYPE_POINTER: + case VSTR_TYPE_FMT_PTR_VOID: args[i] = &VSTR_FMT_CB_ARG_PTR(fmt_spec, i); break; } @@ -171,6 +147,7 @@ static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec) spec.width = fmt_spec->fmt_field_width; handler->hook(&data, &spec, args); + return 1; } @@ -179,8 +156,10 @@ static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec) */ static void vstr_fmt_add_handler(Vstr_conf *conf, printf_hook_handler_t *handler) { - int *at = handler->argtypes; - switch(handler->numargs) + int *at; + + at = handler->argtypes; + switch (handler->numargs) { case 1: vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0], @@ -198,34 +177,41 @@ static void vstr_fmt_add_handler(Vstr_conf *conf, printf_hook_handler_t *handler } /** - * Management of thread-specific Vstr_conf objects + * Thread specific vstr config */ -#include <threading/thread_value.h> - static thread_value_t *vstr_conf = NULL; +/** + * Create vstr config for current thread + */ static Vstr_conf *create_vstr_conf() { + Vstr_conf *conf; int i; - Vstr_conf *conf = vstr_make_conf(); + + 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 < NUM_HANDLERS; ++i) + + for (i = 0; i < countof(printf_hooks); i++) { - printf_hook_handler_t *handler = printf_hooks[i]; - if (handler) + if (printf_hooks[i]) { - vstr_fmt_add_handler(conf, handler); + 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); @@ -239,21 +225,6 @@ static inline Vstr_conf *get_vstr_conf() } /** - * Described in header - */ -size_t vstr_print_in_hook(struct Vstr_base *base, size_t pos, const char *fmt, - ...) -{ - va_list args; - int written; - - va_start(args, fmt); - written = vstr_add_vfmt(base, pos, fmt, args); - va_end(args); - return written; -} - -/** * Wrapper functions for printf and alike */ int vstr_wrapper_printf(const char *format, ...) @@ -265,6 +236,7 @@ int vstr_wrapper_printf(const char *format, ...) va_end(args); return written; } + int vstr_wrapper_fprintf(FILE *stream, const char *format, ...) { int written; @@ -274,6 +246,7 @@ int vstr_wrapper_fprintf(FILE *stream, const char *format, ...) va_end(args); return written; } + int vstr_wrapper_sprintf(char *str, const char *format, ...) { int written; @@ -283,6 +256,7 @@ int vstr_wrapper_sprintf(char *str, const char *format, ...) va_end(args); return written; } + int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...) { int written; @@ -292,6 +266,7 @@ int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...) va_end(args); return written; } + int vstr_wrapper_asprintf(char **str, const char *format, ...) { int written; @@ -301,13 +276,16 @@ int vstr_wrapper_asprintf(char **str, const char *format, ...) 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 = vstr_make_base(conf); + Vstr_base *s; + + s = vstr_make_base(conf); vstr_add_vfmt(s, 0, format, args); if (vstr_export_iovec_ptr_all(s, &iov, &iovcnt)) { @@ -323,33 +301,43 @@ static inline int vstr_wrapper_vprintf_internal(Vstr_conf *conf, FILE *stream, vstr_free_base(s); return written; } + int vstr_wrapper_vprintf(const char *format, va_list args) { - Vstr_conf *conf = get_vstr_conf(); + 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 = get_vstr_conf(); + 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 = get_vstr_conf(); + Vstr_conf *conf; + Vstr_base *s; + int written; + + conf = get_vstr_conf(); if (conf) { - int written; - Vstr_base *s = vstr_make_base(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); @@ -358,19 +346,27 @@ static inline int vstr_wrapper_vsnprintf_internal(char *str, size_t size, } 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) { - return (size > 0) ? vstr_wrapper_vsnprintf_internal(str, size, format, args) : 0; + 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) { @@ -387,60 +383,68 @@ int vstr_wrapper_vasprintf(char **str, const char *format, va_list args) } return written; } -#endif METHOD(printf_hook_t, add_handler, void, - private_printf_hook_t *this, char spec, - printf_hook_function_t hook, ...) + 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 (!IS_VALID_SPEC(spec)) + 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; } - handler = malloc_thing(printf_hook_handler_t); - handler->hook = hook; + INIT(handler, + .hook = hook, + ); va_start(args, hook); - while ((argtype = va_arg(args, printf_hook_argtype_t)) != PRINTF_HOOK_ARGTYPE_END) + 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); - va_end(args); - free(handler); - return; + 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; } - handler->argtypes[i] = argtype; } va_end(args); handler->numargs = i + 1; - if (handler->numargs > 0) + if (!failed && handler->numargs > 0) { -#if !defined(USE_VSTR) && \ - (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER)) -# ifdef HAVE_PRINTF_SPECIFIER - register_printf_specifier(spec, custom_print, custom_arginfo); -# else - register_printf_function(spec, custom_print, custom_arginfo); -# endif -#else Vstr_conf *conf = get_vstr_conf(); handler->name = malloc(2); handler->name[0] = spec; handler->name[1] = '\0'; vstr_fmt_add_handler(conf, handler); -#endif printf_hooks[SPEC_TO_INDEX(spec)] = handler; } else @@ -453,29 +457,25 @@ METHOD(printf_hook_t, destroy, void, private_printf_hook_t *this) { int i; -#ifdef USE_VSTR - Vstr_conf *conf = get_vstr_conf(); -#endif + Vstr_conf *conf; + printf_hook_handler_t *handler; - for (i = 0; i < NUM_HANDLERS; ++i) + conf = get_vstr_conf(); + for (i = 0; i < countof(printf_hooks); ++i) { - printf_hook_handler_t *handler = printf_hooks[i]; + handler = printf_hooks[i]; if (handler) { -#ifdef USE_VSTR vstr_fmt_del(conf, handler->name); free(handler->name); -#endif free(handler); } } -#ifdef USE_VSTR /* freeing the Vstr_conf of the main thread */ vstr_conf->destroy(vstr_conf); vstr_conf = NULL; vstr_exit(); -#endif free(this); } @@ -495,7 +495,6 @@ printf_hook_t *printf_hook_create() memset(printf_hooks, 0, sizeof(printf_hooks)); -#ifdef USE_VSTR if (!vstr_init()) { DBG1(DBG_LIB, "failed to initialize Vstr library!"); @@ -503,8 +502,6 @@ printf_hook_t *printf_hook_create() return NULL; } vstr_conf = thread_value_create((thread_cleanup_t)vstr_free_conf); -#endif return &this->public; } - diff --git a/src/libstrongswan/utils/printf_hook/printf_hook_vstr.h b/src/libstrongswan/utils/printf_hook/printf_hook_vstr.h new file mode 100644 index 000000000..2f9ee5983 --- /dev/null +++ b/src/libstrongswan/utils/printf_hook/printf_hook_vstr.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 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. + */ + +/** + * @defgroup printf_hook_vstr printf_hook_vstr + * @{ @ingroup utils + */ + +#ifndef PRINTF_HOOK_VSTR_H_ +#define PRINTF_HOOK_VSTR_H_ + +#include <stdarg.h> +#include <stdio.h> + +int vstr_wrapper_printf(const char *format, ...); +int vstr_wrapper_fprintf(FILE *stream, const char *format, ...); +int vstr_wrapper_sprintf(char *str, const char *format, ...); +int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...); +int vstr_wrapper_asprintf(char **str, const char *format, ...); + +int vstr_wrapper_vprintf(const char *format, va_list ap); +int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list ap); +int vstr_wrapper_vsprintf(char *str, const char *format, va_list ap); +int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format, va_list ap); +int vstr_wrapper_vasprintf(char **str, const char *format, va_list ap); + +#ifdef printf +#undef printf +#endif +#ifdef fprintf +#undef fprintf +#endif +#ifdef sprintf +#undef sprintf +#endif +#ifdef snprintf +#undef snprintf +#endif +#ifdef asprintf +#undef asprintf +#endif +#ifdef vprintf +#undef vprintf +#endif +#ifdef vfprintf +#undef vfprintf +#endif +#ifdef vsprintf +#undef vsprintf +#endif +#ifdef vsnprintf +#undef vsnprintf +#endif +#ifdef vasprintf +#undef vasprintf +#endif + +#define printf vstr_wrapper_printf +#define fprintf vstr_wrapper_fprintf +#define sprintf vstr_wrapper_sprintf +#define snprintf vstr_wrapper_snprintf +#define asprintf vstr_wrapper_asprintf + +#define vprintf vstr_wrapper_vprintf +#define vfprintf vstr_wrapper_vfprintf +#define vsprintf vstr_wrapper_vsprintf +#define vsnprintf vstr_wrapper_vsnprintf +#define vasprintf vstr_wrapper_vasprintf + +#endif /** PRINTF_HOOK_VSTR_H_ @}*/ |