summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bfstd.c43
-rw-r--r--src/bfstd.h11
-rw-r--r--src/color.c2
-rw-r--r--src/eval.c2
-rw-r--r--src/parse.c4
-rw-r--r--src/printf.c2
-rw-r--r--src/thread.h3
-rw-r--r--src/xregex.c3
8 files changed, 63 insertions, 7 deletions
diff --git a/src/bfstd.c b/src/bfstd.c
index fcf4a6d..e9214d4 100644
--- a/src/bfstd.c
+++ b/src/bfstd.c
@@ -12,6 +12,7 @@
#include <errno.h>
#include <fcntl.h>
#include <langinfo.h>
+#include <locale.h>
#include <nl_types.h>
#include <stdint.h>
#include <stdio.h>
@@ -276,6 +277,48 @@ char *xstpencpy(char *dest, char *end, const char *src, size_t n) {
}
}
+const char *xstrerror(int errnum) {
+ int saved = errno;
+ const char *ret = NULL;
+ static thread_local char buf[256];
+
+#if __APPLE__
+ // No strerror_l() on macOS
+ if (strerror_r(errnum, buf, sizeof(buf)) == 0) {
+ ret = buf;
+ }
+#else
+# if __NetBSD__
+ // NetBSD has no thread-specific locales
+ locale_t loc = LC_GLOBAL_LOCALE;
+# else
+ locale_t loc = uselocale((locale_t)0);
+# endif
+
+ locale_t copy = loc;
+ if (copy == LC_GLOBAL_LOCALE) {
+ copy = duplocale(copy);
+ }
+
+ if (copy != (locale_t)0) {
+ ret = strerror_l(errnum, loc);
+ }
+
+ if (loc == LC_GLOBAL_LOCALE) {
+ freelocale(copy);
+ }
+#endif
+
+ if (!ret) {
+ // Fallback for strerror_[lr]() or duplocale() failures
+ snprintf(buf, sizeof(buf), "Unknown error %d", errnum);
+ ret = buf;
+ }
+
+ errno = saved;
+ return ret;
+}
+
void xstrmode(mode_t mode, char str[11]) {
strcpy(str, "----------");
diff --git a/src/bfstd.h b/src/bfstd.h
index fb77399..abde24e 100644
--- a/src/bfstd.h
+++ b/src/bfstd.h
@@ -167,6 +167,17 @@ char *xstpecpy(char *dest, char *end, const char *src);
char *xstpencpy(char *dest, char *end, const char *src, size_t n);
/**
+ * Thread-safe strerror().
+ *
+ * @param errnum
+ * An error number.
+ * @return
+ * A string describing that error, which remains valid until the next
+ * xstrerror() call in the same thread.
+ */
+const char *xstrerror(int errnum);
+
+/**
* Format a mode like ls -l (e.g. -rw-r--r--).
*
* @param mode
diff --git a/src/color.c b/src/color.c
index 788d35d..fbb5edf 100644
--- a/src/color.c
+++ b/src/color.c
@@ -1239,7 +1239,7 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) {
break;
case 'm':
- if (dstrcat(&cfile->buffer, strerror(error)) != 0) {
+ if (dstrcat(&cfile->buffer, xstrerror(error)) != 0) {
return -1;
}
break;
diff --git a/src/eval.c b/src/eval.c
index 9f4896a..e0dd97b 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1376,7 +1376,7 @@ static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) {
if (ftwbuf->type == BFS_ERROR) {
if (!eval_should_ignore(&state, ftwbuf->error)) {
- eval_error(&state, "%s.\n", strerror(ftwbuf->error));
+ eval_error(&state, "%s.\n", xstrerror(ftwbuf->error));
}
state.action = BFTW_PRUNE;
goto done;
diff --git a/src/parse.c b/src/parse.c
index 7766a7b..976f7cb 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1127,7 +1127,7 @@ static struct bfs_expr *parse_color(struct parser_state *state, int color, int a
if (color) {
if (!colors) {
- parse_expr_error(state, expr, "Error parsing $$LS_COLORS: %s.\n", strerror(ctx->colors_error));
+ parse_expr_error(state, expr, "Error parsing $$LS_COLORS: %s.\n", xstrerror(ctx->colors_error));
bfs_expr_free(expr);
return NULL;
}
@@ -3741,7 +3741,7 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) {
}
if (state.use_color == COLOR_AUTO && !ctx->colors) {
- bfs_warning(ctx, "Error parsing $$LS_COLORS: %s.\n\n", strerror(ctx->colors_error));
+ bfs_warning(ctx, "Error parsing $$LS_COLORS: %s.\n\n", xstrerror(ctx->colors_error));
}
if (bfs_optimize(ctx) != 0) {
diff --git a/src/printf.c b/src/printf.c
index 98bcb0f..704e26d 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -744,7 +744,7 @@ int bfs_printf_parse(const struct bfs_ctx *ctx, struct bfs_expr *expr, const cha
if (!directive.ptr) {
int error = errno;
bfs_expr_error(ctx, expr);
- bfs_error(ctx, "Couldn't parse the mount table: %s.\n", strerror(error));
+ bfs_error(ctx, "Couldn't parse the mount table: %s.\n", xstrerror(error));
goto directive_error;
}
break;
diff --git a/src/thread.h b/src/thread.h
index ab95a79..a59033c 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -8,6 +8,7 @@
#ifndef BFS_THREAD_H
#define BFS_THREAD_H
+#include "bfstd.h"
#include "config.h"
#include "diag.h"
#include <errno.h>
@@ -23,7 +24,7 @@
#endif
#define thread_verify(expr, cond) \
- bfs_verify((errno = (expr), (cond)), "%s: %s", #expr, strerror(errno))
+ bfs_verify((errno = (expr), (cond)), "%s: %s", #expr, xstrerror(errno))
/**
* Wrapper for pthread_create().
diff --git a/src/xregex.c b/src/xregex.c
index 87b692e..3df27f0 100644
--- a/src/xregex.c
+++ b/src/xregex.c
@@ -3,6 +3,7 @@
#include "xregex.h"
#include "alloc.h"
+#include "bfstd.h"
#include "config.h"
#include "diag.h"
#include "sanity.h"
@@ -274,7 +275,7 @@ void bfs_regfree(struct bfs_regex *regex) {
char *bfs_regerror(const struct bfs_regex *regex) {
if (!regex) {
- return strdup(strerror(ENOMEM));
+ return strdup(xstrerror(ENOMEM));
}
#if BFS_USE_ONIGURUMA