summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-04-01 12:26:20 +0200
committerThomas Haller <thaller@redhat.com>2020-04-01 17:18:00 +0200
commitf4446e34c689d6bd81deb8bbab01387716db801f (patch)
treede60250fc94a728cfd5e2f5ffa63c4a298e1500a
parent659ac9cc1299399b34b4677a492c9943458e1b52 (diff)
downloadNetworkManager-f4446e34c689d6bd81deb8bbab01387716db801f.tar.gz
shared: add nm_g_ascii_strtoll() to workaround bug
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.c66
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.h4
2 files changed, 70 insertions, 0 deletions
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
index 74abfb933f..96c966f16f 100644
--- a/shared/nm-glib-aux/nm-shared-utils.c
+++ b/shared/nm-glib-aux/nm-shared-utils.c
@@ -955,6 +955,72 @@ nm_utils_ipaddr_is_normalized (int addr_family,
/*****************************************************************************/
+/**
+ * nm_g_ascii_strtoll()
+ * @nptr: the string to parse
+ * @endptr: the pointer on the first invalid chars
+ * @base: the base.
+ *
+ * This wraps g_ascii_strtoll() and should in almost all cases behave identical
+ * to it.
+ *
+ * However, it seems there are situations where g_ascii_strtoll() might set
+ * errno to some unexpected value EAGAIN. Possibly this is related to creating
+ * the C locale during
+ *
+ * #ifdef USE_XLOCALE
+ * return strtoll_l (nptr, endptr, base, get_C_locale ());
+ *
+ * This wrapper tries to workaround that condition.
+ */
+gint64
+nm_g_ascii_strtoll (const char *nptr,
+ char **endptr,
+ guint base)
+{
+ int try_count = 2;
+ gint64 v;
+ const int errsv_orig = errno;
+ int errsv;
+
+ nm_assert (nptr);
+ nm_assert (base == 0u || (base >= 2u && base <= 36u));
+
+again:
+ errno = 0;
+ v = g_ascii_strtoll (nptr, endptr, base);
+ errsv = errno;
+
+ if (errsv == 0) {
+ if (errsv_orig != 0)
+ errno = errsv_orig;
+ return v;
+ }
+
+ if ( errsv == ERANGE
+ && NM_IN_SET (v, G_MININT64, G_MAXINT64))
+ return v;
+
+ if ( errsv == EINVAL
+ && v == 0
+ && nptr
+ && nptr[0] == '\0')
+ return v;
+
+ if (try_count-- > 0)
+ goto again;
+
+#if NM_MORE_ASSERTS
+ g_critical ("g_ascii_strtoll() for \"%s\" failed with errno=%d (%s) and v=%"G_GINT64_FORMAT,
+ nptr,
+ errsv,
+ nm_strerror_native (errsv),
+ v);
+#endif
+
+ return v;
+}
+
/* _nm_utils_ascii_str_to_int64:
*
* A wrapper for g_ascii_strtoll, that checks whether the whole string
diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h
index bba60954b1..7ee024550b 100644
--- a/shared/nm-glib-aux/nm-shared-utils.h
+++ b/shared/nm-glib-aux/nm-shared-utils.h
@@ -657,6 +657,10 @@ gboolean nm_utils_parse_inaddr_prefix (int addr_family,
char **out_addr,
int *out_prefix);
+gint64 nm_g_ascii_strtoll (const char *nptr,
+ char **endptr,
+ guint base);
+
gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback);
guint64 _nm_utils_ascii_str_to_uint64 (const char *str, guint base, guint64 min, guint64 max, guint64 fallback);