summaryrefslogtreecommitdiffstats
path: root/lib/pthread_safe.c
diff options
context:
space:
mode:
authorChris Hall <GMCH@hestia.halldom.com>2010-04-08 19:51:10 +0100
committerChris Hall <GMCH@hestia.halldom.com>2010-04-08 19:51:10 +0100
commit83447a051fbcc88b33fcea6670520687668d3ba1 (patch)
treef3be10368d9fc6c605c1ec351bc7c1f2c0c61ff0 /lib/pthread_safe.c
parent17b711e6e4a4d5ce3728a07890434d890ebb76b4 (diff)
downloadquagga-83447a051fbcc88b33fcea6670520687668d3ba1.tar.bz2
quagga-83447a051fbcc88b33fcea6670520687668d3ba1.tar.xz
New functions for error numbers and addresses in messages.
Implemented less onerous ways of including descriptions of errors and IP addresses in logging and other messages. Implemented mapping of error numbers to error names, which is generally more meaningful.
Diffstat (limited to 'lib/pthread_safe.c')
-rw-r--r--lib/pthread_safe.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/lib/pthread_safe.c b/lib/pthread_safe.c
index f67e6b2a..b6c429e4 100644
--- a/lib/pthread_safe.c
+++ b/lib/pthread_safe.c
@@ -35,7 +35,10 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <errno.h>
+#include "qfstring.h"
+#include "errno_names.h"
/* prototypes */
static void destructor(void* data);
@@ -98,6 +101,226 @@ safe_strerror(int errnum)
}
}
+/*------------------------------------------------------------------------------
+ * Construct string to describe the given error of the form:
+ *
+ * ENAME '<strerror>'
+ *
+ * where <strerror> is given by strerror() or, if pthreads_enabled, strerror_r()
+ *
+ * Truncates the result to the given len (0 => no truncation). But silently
+ * imposes the maximum length allowed by the strerror_t.
+ *
+ * If has to truncate, places "..." at the end of the message to show this has
+ * happened.
+ *
+ * If a name is not known then (assuming strerror() won't know it either):
+ *
+ * ERRNO=999 *unknown error*
+ *
+ * For err==0 returns:
+ *
+ * EOK 'no error'
+ *
+ * Thread safe replacement for strerror. Never returns NULL.
+ */
+static void
+errtox(strerror_t* st, int err, int len, int want)
+{
+ qf_str_t qfs ;
+
+ const char* q ;
+ int ql ;
+
+ /* Prepare. */
+ int errno_saved = errno ;
+
+ if ((len <= 0) || (len >= (int)sizeof(st->str)))
+ len = sizeof(st->str) - 1 ;
+ qfs_init(&qfs, st->str, len + 1) ;
+
+ q = "" ;
+ ql = 0 ;
+
+ /* If want the error name, do that now. */
+ if (want & 1)
+ {
+ const char* name = errno_name_lookup(err) ;
+
+ if (name != NULL)
+ qfs_append(&qfs, name) ;
+ else
+ qfs_printf(&qfs, "ERRNO=%d", err) ;
+ } ;
+
+ /* name and string ? */
+ if (want == 3)
+ {
+ qfs_append(&qfs, " ") ;
+ q = "'" ;
+ ql = 2 ;
+ } ;
+
+ /* If want the error string, do that now */
+ if (want & 2)
+ {
+ char buf[400] ; /* impossibly vast */
+ int ret ;
+ const char* errm ;
+
+ if (err == 0)
+ errm = "no error" ;
+ else
+ {
+ if (qpthreads_enabled)
+ {
+ /* POSIX is not explicit about what happens if the buffer is not
+ * big enough to accommodate the message, except that an ERANGE
+ * error may be raised.
+ *
+ * By experiment: glibc-2.10.2-1.x86_64 returns -1, with errno
+ * set to ERANGE and no string at all if the buffer is too small.
+ *
+ * A huge buffer is used to get the message, and that is later
+ * truncated, if necessary, to fit in the strerror_t structure.
+ */
+
+ buf[0] = '\0' ; /* make sure starts empty */
+ ret = strerror_r(err, buf, sizeof(buf)) ;
+ errm = buf ;
+ if (ret != 0)
+ ret = errno ;
+ }
+ else
+ {
+ /* POSIX says that strerror *will* return something, but it is
+ * known that it may return NULL if the error number is not
+ * recognised.
+ */
+ errno = 0 ;
+ errm = strerror(err) ;
+ ret = errno ;
+ if ((ret == 0) && ((errm == NULL) || (*errm == '\0')))
+ ret = EINVAL ;
+ } ;
+
+ /* Deal with errors, however exotic. */
+ if (ret != 0)
+ {
+ q = "*" ;
+ ql = 2 ; /* force "*" "quotes" */
+ if (ret == EINVAL)
+ errm = "unknown error" ;
+ else if (ret == ERANGE)
+ {
+ if (*errm == '\0')
+ errm = "vast error message" ;
+ }
+ else
+ {
+ qf_str_t qfs_b ;
+ qfs_init(&qfs_b, buf, sizeof(buf)) ;
+ qfs_printf(&qfs_b, "strerror%s(%d) returned error %d",
+ qpthreads_enabled ? "_r" : "", err, ret) ;
+ errm = buf ;
+ } ;
+ } ;
+ } ;
+
+ /* Add strerror to the result... looking out for overflow. */
+ len = strlen(errm) ;
+
+ if ((len + ql) <= qfs_left(&qfs)) /* accounting for "quotes" */
+ qfs_printf(&qfs, "%s%s%s", q, errm, q) ;
+ else
+ qfs_printf(&qfs, "%s%.*s...%s", q, qfs_left(&qfs) - ql - 3, errm, q) ;
+ /* -ve precision is ignored ! */
+ } ;
+
+ /* Put back errno */
+ errno = errno_saved ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Construct string to describe the given error of the form:
+ *
+ * ENAME '<strerror>'
+ *
+ * where <strerror> is given by strerror() or, if pthreads_enabled, strerror_r()
+ *
+ * Truncates the result to the given len (0 => no truncation). But silently
+ * imposes the maximum length allowed by the strerror_t.
+ *
+ * If has to truncate, places "..." at the end of the message to show this has
+ * happened.
+ *
+ * If a name is not known then (assuming strerror() won't know it either):
+ *
+ * ERRNO=999 *unknown error*
+ *
+ * For err==0 returns:
+ *
+ * EOK 'no error'
+ *
+ * Thread safe replacement for strerror. Never returns NULL.
+ */
+extern strerror_t
+errtoa(int err, int len)
+{
+ strerror_t st ;
+
+ errtox(&st, err, len, 3) ; /* name and message */
+
+ return st ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Convert error number to its name
+
+ * If a name is not known then:
+ *
+ * ERRNO=999
+ *
+ * For err==0 returns:
+ *
+ * EOK
+ *
+ * Truncates the result to the given len (0 => no truncation). But silently
+ * imposes the maximum length allowed by the strerror_t.
+ *
+ * This is thread-safe.
+ */
+extern strerror_t
+errtoname(int err, int len)
+{
+ strerror_t st ;
+
+ errtox(&st, err, len, 1) ; /* name */
+
+ return st ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Alternative thread-safe safe_strerror()
+ *
+ * Truncates the result to the given len (0 => no truncation). But silently
+ * imposes the maximum length allowed by the strerror_t.
+ *
+ * If the <strerror> will not fit in the strerror_t, it is truncated and
+ * '...' placed at the end to show this has happened.
+ *
+ * Thread safe replacement for strerror. Never returns NULL.
+ */
+extern strerror_t
+errtostr(int err, int len)
+{
+ strerror_t st ;
+
+ errtox(&st, err, len, 2) ; /* message */
+
+ return st ;
+} ;
+
/* Thread safe version of inet_ntoa. Never returns NULL.
* Contents of result remains intact until another call of
* a safe_ function.
@@ -135,3 +358,10 @@ thread_buff(void)
return buff;
}
+
+
+
+
+
+
+