[libvirt] [PATCH v3.1] json: fix interface locale dependency

Martin Kletzander mkletzan at redhat.com
Sun Aug 12 07:55:25 UTC 2012


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             |    2 +-
 src/libvirt_private.syms |    1 +
 src/util/json.c          |    2 +-
 src/util/util.c          |   63 ++++++++++++++++++++++++++++++++++++++++++++++
 src/util/util.h          |    2 +
 6 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/bootstrap.conf b/bootstrap.conf
index c112ccd..a4e1c2f 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 8a04d91..e614b48 100644
--- a/configure.ac
+++ b/configure.ac
@@ -133,7 +133,7 @@ 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])
+  regexec sched_getaffinity newlocale])

 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 c023dbf..018d3a9 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 5132989..40d50a1 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 e5bb27b..c318153 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -44,6 +44,7 @@
 #include <signal.h>
 #include <termios.h>
 #include <pty.h>
+#include <locale.h>

 #if HAVE_LIBDEVMAPPER_H
 # include <libdevmapper.h>
@@ -2060,6 +2061,68 @@ int virEnumFromString(const char *const*types,
     return -1;
 }

+/* In case thread-safe locales are available */
+#if HAVE_NEWLOCALE
+
+locale_t virLocale;
+
+static int
+virLocaleOnceInit(void)
+{
+    virLocale = newlocale(LC_ALL_MASK, "C", NULL);
+    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 d151c27..a4e34c6 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -209,6 +209,8 @@ 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);
+
 int virDiskNameToIndex(const char* str);
 char *virIndexToDiskName(int idx, const char *prefix);

--
1.7.8.6




More information about the libvir-list mailing list