#include "util.h"
#include <errno.h>
#include <limits.h>
+#include <pthread.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
/* argv[0] without directory names. */
const char *program_name;
-/* Ordinarily "" but set to "monitor" for a monitor process or "worker" for a
- * worker process. */
-const char *subprogram_name = "";
+/* Name for the currently running thread or process, for log messages, process
+ * listings, and debuggers. */
+DEFINE_PER_THREAD_MALLOCED_DATA(char *, subprogram_name);
/* --version option output. */
static char *program_version;
+/* Buffer used by ovs_strerror(). */
+DEFINE_PER_THREAD_DATA(struct { char s[128]; }, strerror_buffer, { "" });
+
void
ovs_assert_failure(const char *where, const char *function,
const char *condition)
void
ovs_error_valist(int err_no, const char *format, va_list args)
{
+ const char *subprogram_name = get_subprogram_name();
int save_errno = errno;
if (subprogram_name[0]) {
const char *
ovs_retval_to_string(int retval)
{
- static char unknown[48];
+ return (!retval ? ""
+ : retval == EOF ? "End of file"
+ : ovs_strerror(retval));
+}
- if (!retval) {
- return "";
- }
- if (retval > 0) {
- return strerror(retval);
- }
- if (retval == EOF) {
- return "End of file";
+const char *
+ovs_strerror(int error)
+{
+ enum { BUFSIZE = sizeof strerror_buffer_get()->s };
+ int save_errno;
+ char *buffer;
+ char *s;
+
+ save_errno = errno;
+ buffer = strerror_buffer_get()->s;
+
+#if STRERROR_R_CHAR_P
+ /* GNU style strerror_r() might return an immutable static string, or it
+ * might write and return 'buffer', but in either case we can pass the
+ * returned string directly to the caller. */
+ s = strerror_r(error, buffer, BUFSIZE);
+#else /* strerror_r() returns an int. */
+ s = buffer;
+ if (strerror_r(error, buffer, BUFSIZE)) {
+ /* strerror_r() is only allowed to fail on ERANGE (because the buffer
+ * is too short). We don't check the actual failure reason because
+ * POSIX requires strerror_r() to return the error but old glibc
+ * (before 2.13) returns -1 and sets errno. */
+ snprintf(buffer, BUFSIZE, "Unknown error %d", error);
}
- snprintf(unknown, sizeof unknown, "***unknown return value: %d***", retval);
- return unknown;
+#endif
+
+ errno = save_errno;
+
+ return s;
}
/* Sets global "program_name" and "program_version" variables. Should
}
}
+/* Returns the name of the currently running thread or process. */
+const char *
+get_subprogram_name(void)
+{
+ const char *name = subprogram_name_get();
+ return name ? name : "";
+}
+
+/* Sets 'name' as the name of the currently running thread or process. (This
+ * appears in log messages.) */
+void
+set_subprogram_name(const char *name)
+{
+ free(subprogram_name_set(xstrdup(name)));
+}
+
/* Returns a pointer to a string describing the program version. The
* caller must not modify or free the returned string.
*/
int error = errno;
free(buf);
if (error != ERANGE) {
- VLOG_WARN("getcwd failed (%s)", strerror(error));
+ VLOG_WARN("getcwd failed (%s)", ovs_strerror(error));
return NULL;
}
size *= 2;
linkname = xreadlink(fn);
if (!linkname) {
- VLOG_WARN("%s: readlink failed (%s)", filename, strerror(errno));
+ VLOG_WARN("%s: readlink failed (%s)",
+ filename, ovs_strerror(errno));
return fn;
}