Code

Even though POSIX/XSI requires "strerror_r" to return an "int", some systems
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Fri, 6 Mar 2009 05:39:37 +0000 (05:39 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Fri, 6 Mar 2009 05:39:37 +0000 (05:39 +0000)
(e.g. the GNU libc) return a "char *" _and_ ignore the second argument (user
provided buffer). The configure script now checks for that behavior using
AC_FUNC_STRERROR_R. rrd_strerror() in rrd_thread_safe.c has been updated to
(hopefully) handle all possible cases.

Previously, rrd_strerror() would have returned "strerror_r failed. sorry!" in
mostly any cases when using glibc, since "if (strerror_r())" had been used to
check for errors which evaluates to true if a (non-NULL) pointer was returned.

Now, we, at least, return the error number in case anything else fails.

Thanks to Alessandro Iurlano for reporting this issue after spotting it in
collectd <http://collectd.org>.

patch by Sebastian Harl

git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@1752 a5681a0c-68f1-0310-ab6d-d61299d08faa

configure.ac
src/rrd_thread_safe.c

index 6cc2767edc21c4eed095f2e3f4541eec6919abf6..843e5b249da49ecd04c00b129174251754d50971 100644 (file)
@@ -203,7 +203,9 @@ AC_C_BIGENDIAN
 dnl for each function found we get a definition in config.h 
 dnl of the form HAVE_FUNCTION
 
-AC_CHECK_FUNCS(tzset fsync mbstowcs opendir readdir chdir chroot getuid setlocale strerror strerror_r snprintf vsnprintf fpclass class fp_class isnan memmove strchr mktime getrusage gettimeofday)
+AC_CHECK_FUNCS(tzset fsync mbstowcs opendir readdir chdir chroot getuid setlocale strerror snprintf vsnprintf fpclass class fp_class isnan memmove strchr mktime getrusage gettimeofday)
+
+AC_FUNC_STRERROR_R
 
 CONFIGURE_PART(Map/Fadvis/Madvise checking)
 
index c910b988227c5968db5b59f92570c2b04f796c75..6e30115bf7ea61a30a66435015f33adacf7269b3 100644 (file)
@@ -59,11 +59,38 @@ const char *rrd_strerror(
     int err)
 {
     rrd_context_t *ctx = rrd_get_context();
+    char *ret = "unknown error";
 
-    if (strerror_r(err, ctx->lib_errstr, sizeof(ctx->lib_errstr)))
-        return "strerror_r failed. sorry!";
-    else
-        return ctx->lib_errstr;
+    *ctx->lib_errstr = '\0';
+
+    /* Even though POSIX/XSI requires "strerror_r" to return an "int", some
+     * systems (e.g. the GNU libc) return a "char *" _and_ ignore the second
+     * argument ... -tokkee */
+#if STRERROR_R_CHAR_P
+    ret = strerror_r(err, ctx->lib_errstr, sizeof(ctx->lib_errstr));
+    if ((! ret) || (*ret == '\0')) {
+        if (*ctx->lib_errstr != '\0')
+            ret = ctx->lib_errstr;
+        else {
+            /* according to the manpage this should not happen -
+               let's handle it somehow sanely anyway */
+            snprintf(ctx->lib_errstr, sizeof(ctx->lib_errstr),
+                    "unknown error %i - strerror_r did not return anything",
+                    err);
+            ctx->lib_errstr[sizeof(ctx->lib_errstr) - 1] = '\0';
+            ret = ctx->lib_errstr;
+        }
+    }
+#else /* ! STRERROR_R_CHAR_P */
+    if (strerror_r(err, ctx->lib_errstr, sizeof(ctx->lib_errstr))) {
+        snprintf(ctx->lib_errstr, sizeof(ctx->lib_errstr),
+                "unknown error %i - strerror_r returned with errno = %i",
+                err, errno);
+        ctx->lib_errstr[sizeof(ctx->lib_errstr) - 1] = '\0';
+    }
+    ret = ctx->lib_errstr;
+#endif
+    return ret;
 }
 #else
 #undef strerror