diff options
Diffstat (limited to 'src/libstrongswan/utils')
-rw-r--r-- | src/libstrongswan/utils/backtrace.c | 4 | ||||
-rw-r--r-- | src/libstrongswan/utils/chunk.c | 36 | ||||
-rw-r--r-- | src/libstrongswan/utils/chunk.h | 9 | ||||
-rw-r--r-- | src/libstrongswan/utils/enum.h | 2 | ||||
-rw-r--r-- | src/libstrongswan/utils/identification.c | 2 | ||||
-rw-r--r-- | src/libstrongswan/utils/leak_detective.c | 1 | ||||
-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 | 1168 | ||||
-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) | 283 | ||||
-rw-r--r-- | src/libstrongswan/utils/printf_hook/printf_hook_vstr.h | 83 | ||||
-rw-r--r-- | src/libstrongswan/utils/utils.c | 46 | ||||
-rw-r--r-- | src/libstrongswan/utils/utils.h | 53 |
15 files changed, 1973 insertions, 408 deletions
diff --git a/src/libstrongswan/utils/backtrace.c b/src/libstrongswan/utils/backtrace.c index 93031908a..fb2c4d1e8 100644 --- a/src/libstrongswan/utils/backtrace.c +++ b/src/libstrongswan/utils/backtrace.c @@ -536,7 +536,7 @@ METHOD(backtrace_t, create_frame_enumerator, enumerator_t*, return &enumerator->public; } -METHOD(backtrace_t, clone, backtrace_t*, +METHOD(backtrace_t, clone_, backtrace_t*, private_backtrace_t *this) { private_backtrace_t *clone; @@ -593,7 +593,7 @@ static backtrace_t get_methods() .log = _log_, .contains_function = _contains_function, .equals = _equals, - .clone = _clone, + .clone = _clone_, .create_frame_enumerator = _create_frame_enumerator, .destroy = _destroy, }; diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c index 04f3eea7d..644b8060f 100644 --- a/src/libstrongswan/utils/chunk.c +++ b/src/libstrongswan/utils/chunk.c @@ -243,6 +243,38 @@ bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force return good; } +/** + * Described in header. + */ +chunk_t chunk_from_fd(int fd) +{ + char buf[8096]; + char *pos = buf; + ssize_t len, total = 0; + + while (TRUE) + { + len = read(fd, pos, buf + sizeof(buf) - pos); + if (len < 0) + { + DBG1(DBG_LIB, "reading from file descriptor failed: %s", + strerror(errno)); + return chunk_empty; + } + if (len == 0) + { + break; + } + total += len; + if (total == sizeof(buf)) + { + DBG1(DBG_LIB, "buffer too small to read from file descriptor"); + return chunk_empty; + } + } + return chunk_clone(chunk_create(buf, total)); +} + /** hex conversion digits */ static char hexdig_upper[] = "0123456789ABCDEF"; @@ -797,7 +829,7 @@ int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, chunk_t copy = *chunk; int written = 0; - if (!spec->hash) + if (!spec->hash && !spec->plus) { u_int chunk_len = chunk->len; const void *new_args[] = {&chunk->ptr, &chunk_len}; @@ -810,7 +842,7 @@ int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, { first = FALSE; } - else + else if (!spec->plus) { written += print_in_hook(data, ":"); } diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h index 34ba77357..d3751da70 100644 --- a/src/libstrongswan/utils/chunk.h +++ b/src/libstrongswan/utils/chunk.h @@ -100,6 +100,14 @@ void chunk_split(chunk_t chunk, const char *mode, ...); bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force); /** + * Store data read from FD into a chunk + * + * @param fd file descriptor to read from + * @return chunk or chunk_empty on failure + */ +chunk_t chunk_from_fd(int fd); + +/** * Convert a chunk of data to hex encoding. * * The resulting string is '\\0' terminated, but the chunk does not include @@ -368,6 +376,7 @@ u_int64_t chunk_mac(chunk_t chunk, u_char *key); * Arguments are: * chunk_t *chunk * Use #-modifier to print a compact version + * Use +-modifier to print a compact version without separator */ int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args); 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/identification.c b/src/libstrongswan/utils/identification.c index 5df3e5fe2..9c43ad570 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -602,7 +602,7 @@ static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc) } } /* try a binary compare */ - if (memeq(t_dn.ptr, o_dn.ptr, t_dn.len)) + if (chunk_equals(t_dn, o_dn)) { return TRUE; } diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index ffbc62085..725e04f7c 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -511,6 +511,7 @@ char *whitelist[] = { "getspnam_r", "getpwuid_r", "initgroups", + "tzset", /* ignore dlopen, as we do not dlclose to get proper leak reports */ "dlopen", "dlerror", 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..d00abef20 --- /dev/null +++ b/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c @@ -0,0 +1,1168 @@ +/* + * 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)) + { + if (isgreater(dval, 0.0)) + { + sarg = flags & FL_UPPER ? "INF" : "inf"; + } + else + { + 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 f030f45c8..ab93b24ba 100644 --- a/src/libstrongswan/utils/printf_hook.c +++ b/src/libstrongswan/utils/printf_hook/printf_hook_vstr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2009-2013 Tobias Brunner * Copyright (C) 2006-2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -16,12 +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 <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; @@ -56,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 @@ -138,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) @@ -145,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; } @@ -167,9 +144,10 @@ static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec) 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; + spec.width = fmt_spec->obj_field_width; handler->hook(&data, &spec, args); + return 1; } @@ -178,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], @@ -197,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); @@ -238,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, ...) @@ -264,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; @@ -273,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; @@ -282,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; @@ -291,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; @@ -300,56 +276,68 @@ int vstr_wrapper_asprintf(char **str, const char *format, ...) va_end(args); return written; } -static inline int vstr_wrapper_vprintf_internal(Vstr_conf *conf, int fd, + +static inline int vstr_wrapper_vprintf_internal(Vstr_conf *conf, FILE *stream, const char *format, va_list args) { - int written; - Vstr_base *s = vstr_make_base(conf); + struct iovec *iov; + int iovcnt, written = 0; + Vstr_base *s; + + s = vstr_make_base(conf); vstr_add_vfmt(s, 0, format, args); - written = s->len; - while (s->len) + if (vstr_export_iovec_ptr_all(s, &iov, &iovcnt)) { - if (!vstr_sc_write_fd(s, 1, s->len, fd, NULL)) + while (iovcnt--) { - if (errno != EAGAIN && errno != EINTR) + if (iov->iov_base) { - written -= s->len; - break; + 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 = get_vstr_conf(); + Vstr_conf *conf; + + conf = get_vstr_conf(); if (conf) { - return vstr_wrapper_vprintf_internal(conf, STDOUT_FILENO, format, args); + 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, fileno(stream), format, - args); + 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_ @}*/ diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c index 30084cd81..266fb4357 100644 --- a/src/libstrongswan/utils/utils.c +++ b/src/libstrongswan/utils/utils.c @@ -29,6 +29,7 @@ #include "collections/enumerator.h" #include "utils/debug.h" +#include "utils/chunk.h" ENUM(status_names, SUCCESS, NEED_MORE, "SUCCESS", @@ -513,6 +514,51 @@ _cas_impl(ptr, void*) #endif /* HAVE_GCC_ATOMIC_OPERATIONS */ + +#ifdef HAVE_FMEMOPEN_FALLBACK + +static int fmemread(chunk_t *cookie, char *buf, int size) +{ + int len; + + len = min(size, cookie->len); + memcpy(buf, cookie->ptr, len); + *cookie = chunk_skip(*cookie, len); + + return len; +} + +static int fmemwrite(chunk_t *cookie, const char *buf, int size) +{ + int len; + + len = min(size, cookie->len); + memcpy(cookie->ptr, buf, len); + *cookie = chunk_skip(*cookie, len); + + return len; +} + +static int fmemclose(void *cookie) +{ + free(cookie); + return 0; +} + +FILE *fmemopen(void *buf, size_t size, const char *mode) +{ + chunk_t *cookie; + + INIT(cookie, + .ptr = buf, + .len = size, + ); + + return funopen(cookie, (void*)fmemread, (void*)fmemwrite, NULL, fmemclose); +} + +#endif /* FMEMOPEN fallback*/ + /** * Described in header. */ diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h index d055f712d..cda7edf08 100644 --- a/src/libstrongswan/utils/utils.h +++ b/src/libstrongswan/utils/utils.h @@ -113,6 +113,14 @@ static inline bool strncaseeq(const char *x, const char *y, size_t len) } /** + * Helper function that checks if a string starts with a given prefix + */ +static inline bool strcasepfx(const char *x, const char *prefix) +{ + return strncaseeq(x, prefix, strlen(prefix)); +} + +/** * NULL-safe strdup variant */ static inline char *strdupnull(const char *s) @@ -671,26 +679,30 @@ static inline u_int64_t untoh64(void *network) } /** - * Round up size to be multiple of alignement + * Get the padding required to make size a multiple of alignment */ -static inline size_t round_up(size_t size, int alignement) +static inline size_t pad_len(size_t size, size_t alignment) { - int remainder; + size_t remainder; - remainder = size % alignement; - if (remainder) - { - size += alignement - remainder; - } - return size; + remainder = size % alignment; + return remainder ? alignment - remainder : 0; +} + +/** + * Round up size to be multiple of alignment + */ +static inline size_t round_up(size_t size, size_t alignment) +{ + return size + pad_len(size, alignment); } /** - * Round down size to be a multiple of alignement + * Round down size to be a multiple of alignment */ -static inline size_t round_down(size_t size, int alignement) +static inline size_t round_down(size_t size, size_t alignment) { - return size - (size % alignement); + return size - (size % alignment); } /** @@ -753,6 +765,23 @@ bool cas_ptr(void **ptr, void *oldval, void *newval); #endif /* HAVE_GCC_ATOMIC_OPERATIONS */ +#ifndef HAVE_FMEMOPEN +# ifdef HAVE_FUNOPEN +# define HAVE_FMEMOPEN +# define HAVE_FMEMOPEN_FALLBACK +# include <stdio.h> +/** + * fmemopen(3) fallback using BSD funopen. + * + * We could also provide one using fopencookie(), but should we have it we + * most likely have fmemopen(). + * + * fseek() is currently not supported. + */ +FILE *fmemopen(void *buf, size_t size, const char *mode); +# endif /* FUNOPEN */ +#endif /* FMEMOPEN */ + /** * printf hook for time_t. * |