From 43bfa23e6f968be9a8c134a4b5c3cfb6da3816d9 Mon Sep 17 00:00:00 2001 From: Martin Kletzander Date: Sat, 11 Aug 2012 21:13:00 +0200 Subject: [PATCH] json: fix interface locale dependency libvirt creates invalid commands if wrong locale is selected. For example with locale that uses comma as a decimal point, JSON commands created with decimal numbers are invalid because comma separates the entries in JSON. Fortunately even when decimal point is affected, thousands grouping is not, because for grouping to be enabled with *printf, there has to be an apostrophe flag specified (and supported). This patch adds specific internal function for converting doubles to strings with C locale. --- bootstrap.conf | 1 + configure.ac | 4 +-- src/libvirt_private.syms | 1 + src/util/json.c | 2 +- src/util/util.c | 63 ++++++++++++++++++++++++++++++++++++++++ src/util/util.h | 3 ++ 6 files changed, 71 insertions(+), 3 deletions(-) diff --git a/bootstrap.conf b/bootstrap.conf index c112ccd8a8..a4e1c2fa1b 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -62,6 +62,7 @@ ioctl isatty largefile listen +localeconv maintainer-makefile manywarnings mkstemp diff --git a/configure.ac b/configure.ac index 8a04d912c7..3951012051 100644 --- a/configure.ac +++ b/configure.ac @@ -132,8 +132,8 @@ AC_CHECK_SIZEOF([long]) dnl Availability of various common functions (non-fatal if missing), dnl and various less common threadsafe functions AC_CHECK_FUNCS_ONCE([cfmakeraw geteuid getgid getgrnam_r getmntent_r \ - getpwuid_r getuid initgroups kill mmap posix_fallocate posix_memalign \ - regexec sched_getaffinity]) + getpwuid_r getuid initgroups kill mmap newlocale posix_fallocate \ + posix_memalign regexec sched_getaffinity]) dnl Availability of pthread functions (if missing, win32 threading is dnl assumed). Because of $LIB_PTHREAD, we cannot use AC_CHECK_FUNCS_ONCE. diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c023dbf4cc..018d3a9329 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1140,6 +1140,7 @@ virArgvToString; virAsprintf; virBuildPathInternal; virDirCreate; +virDoubleToStr; virEnumFromString; virEnumToString; virEventAddHandle; diff --git a/src/util/json.c b/src/util/json.c index 51329897bc..40d50a1db3 100644 --- a/src/util/json.c +++ b/src/util/json.c @@ -201,7 +201,7 @@ virJSONValuePtr virJSONValueNewNumberDouble(double data) { virJSONValuePtr val = NULL; char *str; - if (virAsprintf(&str, "%lf", data) < 0) + if (virDoubleToStr(&str, data) < 0) return NULL; val = virJSONValueNewNumber(str); VIR_FREE(str); diff --git a/src/util/util.c b/src/util/util.c index e5bb27b358..4a720d8584 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -44,6 +44,7 @@ #include #include #include +#include #if HAVE_LIBDEVMAPPER_H # include @@ -2060,6 +2061,68 @@ int virEnumFromString(const char *const*types, return -1; } +/* In case thread-safe locales are available */ +#if HAVE_NEWLOCALE + +static locale_t virLocale; + +static int +virLocaleOnceInit(void) +{ + virLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0); + if (!virLocale) + return -1; + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virLocale) +#endif + +/** + * virDoubleToStr + * + * converts double to string with C locale (thread-safe). + * + * Returns -1 on error, size of the string otherwise. + */ +int +virDoubleToStr(char **strp, double number) +{ + int ret = -1; + +#if HAVE_NEWLOCALE + + locale_t old_loc; + + if (virLocaleInitialize() < 0) + goto error; + + old_loc = uselocale(virLocale); + ret = virAsprintf(strp, "%lf", number); + uselocale(old_loc); + +#else + + char *radix, *tmp; + struct lconv *lc; + + if ((ret = virVasprintf(strp, "%lf", number) < 0) + goto error; + + lc = localeconv(); + radix = lc->decimal_point; + tmp = strstr(*strp, radix); + if (tmp) { + *tmp = '.'; + if (strlen(radix) > 1) + memmove(tmp + 1, tmp + strlen(radix), strlen(*strp) - (tmp - str)); + } + +#endif /* HAVE_NEWLOCALE */ + error: + return ret; +} + const char *virEnumToString(const char *const*types, unsigned int ntypes, int type) diff --git a/src/util/util.h b/src/util/util.h index d151c27405..a5d892dd4c 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -209,6 +209,9 @@ char *virStrcpy(char *dest, const char *src, size_t destbytes) ATTRIBUTE_RETURN_CHECK; # define virStrcpyStatic(dest, src) virStrcpy((dest), (src), sizeof(dest)) +int virDoubleToStr(char **strp, double number) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + int virDiskNameToIndex(const char* str); char *virIndexToDiskName(int idx, const char *prefix);