]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
musl: introduce GNU specific version of strerror_r()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 24 Jan 2023 07:39:46 +0000 (23:39 -0800)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 14 Nov 2025 18:37:30 +0000 (03:37 +0900)
musl provides XSI compliant strerror_r(), and it is slightly different
from the one by glibc.
Let's introduce a tiny wrapper to convert XSI strerror_r() to GNU one.

The wrapper also patches musl's spurious catchall error message.

src/include/musl/string.h [new file with mode: 0644]
src/libc/musl/meson.build
src/libc/musl/string.c [new file with mode: 0644]

diff --git a/src/include/musl/string.h b/src/include/musl/string.h
new file mode 100644 (file)
index 0000000..cc3da63
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include_next <string.h>
+
+char* strerror_r_gnu(int errnum, char *buf, size_t buflen);
+#define strerror_r strerror_r_gnu
index 8d06d919ef9ce87c678890c9d2360643f519f130..78f93c35421a6cc548119527757fcfbfdc651ac8 100644 (file)
@@ -6,4 +6,5 @@ endif
 
 libc_wrapper_sources += files(
         'stdio.c',
+        'string.c',
 )
diff --git a/src/libc/musl/string.c b/src/libc/musl/string.c
new file mode 100644 (file)
index 0000000..13fa778
--- /dev/null
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+/* MAX_ERRNO is defined as 4095 in linux/err.h. We use the same value here. */
+#define ERRNO_MAX               4095
+
+/* strerror(3) says that glibc uses a maximum length of 1024 bytes. */
+#define ERRNO_BUF_LEN           1024
+
+/* The header string.h overrides strerror_r with strerror_r_gnu, hence we need to undef it here. */
+#undef strerror_r
+
+char* strerror_r_gnu(int errnum, char *buf, size_t buflen) {
+        /* musl provides spurious catchall error message "No error information" for unknown errno
+         * (including errno == 0). Let's patch it to glibc style. */
+
+        if (errnum == 0)
+                return (char*) "Success";
+
+        if (buflen == 0)
+                return (char*) "Unknown error";
+
+        if (errnum < 0 || errnum > ERRNO_MAX)
+                goto fallback;
+
+        if (strerror_r(errnum, buf, buflen) != 0)
+                goto fallback;
+
+        char buf_0[ERRNO_BUF_LEN];
+        if (strerror_r(0, buf_0, sizeof buf_0) != 0) /* Wut?? */
+                goto fallback;
+
+        /* strerror_r() may truncate the result. In that case, let's not compare the trailing NUL. */
+        size_t n = (buflen < ERRNO_BUF_LEN ? buflen : ERRNO_BUF_LEN) - 1;
+        if (strncmp(buf, buf_0, n) != 0)
+                return buf;
+
+fallback:
+        snprintf(buf, buflen, "Unknown error %i", errnum);
+        return buf;
+}