From ebb422dd2b3695de3abfb2dc4874bda432ca0c57 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 23 Jan 2023 23:39:46 -0800 Subject: [PATCH 1/3] musl: introduce GNU specific version of strerror_r() 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 | 7 +++++++ src/libc/musl/meson.build | 1 + src/libc/musl/string.c | 44 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 src/include/musl/string.h create mode 100644 src/libc/musl/string.c diff --git a/src/include/musl/string.h b/src/include/musl/string.h new file mode 100644 index 0000000000..cc3da63012 --- /dev/null +++ b/src/include/musl/string.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include_next + +char* strerror_r_gnu(int errnum, char *buf, size_t buflen); +#define strerror_r strerror_r_gnu diff --git a/src/libc/musl/meson.build b/src/libc/musl/meson.build index 8d06d919ef..78f93c3542 100644 --- a/src/libc/musl/meson.build +++ b/src/libc/musl/meson.build @@ -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 index 0000000000..13fa778a20 --- /dev/null +++ b/src/libc/musl/string.c @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include + +/* 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; +} From bb7d5e52a2a89d48a3e8194c824def9effdf7436 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 14 Nov 2025 08:26:47 +0900 Subject: [PATCH 2/3] musl: test-bus-error: drop ._need_free flag checks Its value depends on how strerror_r() implemented, and the implementations of the function in glibc and musl are actually different. Let's drop the checks. --- src/libsystemd/sd-bus/test-bus-error.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c index 3679f30457..db41141811 100644 --- a/src/libsystemd/sd-bus/test-bus-error.c +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -230,7 +230,6 @@ TEST(sd_bus_error_set_errnof) { assert_se(sd_bus_error_set_errnof(&error, EACCES, NULL) == -EACCES); assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_ACCESS_DENIED)); ASSERT_STREQ(error.message, STRERROR(EACCES)); - assert_se(error._need_free == 0); str = mfree(str); sd_bus_error_free(&error); @@ -238,7 +237,6 @@ TEST(sd_bus_error_set_errnof) { assert_se(sd_bus_error_set_errnof(&error, ENOANO, NULL) == -ENOANO); assert_se(sd_bus_error_has_name(&error, "System.Error.ENOANO")); ASSERT_STREQ(error.message, STRERROR(ENOANO)); - assert_se(error._need_free == 1); str = mfree(str); sd_bus_error_free(&error); @@ -246,7 +244,6 @@ TEST(sd_bus_error_set_errnof) { assert_se(sd_bus_error_set_errnof(&error, 100000, NULL) == -100000); assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_FAILED)); ASSERT_STREQ(error.message, STRERROR(100000)); - assert_se(error._need_free == 1); str = mfree(str); sd_bus_error_free(&error); @@ -262,7 +259,6 @@ TEST(sd_bus_error_set_errnof) { errno = EACCES; assert_se(asprintf(&str, "hoge %s: %m", "foo") >= 0); assert_se(streq(error.message, str)); - assert_se(error._need_free == 1); str = mfree(str); sd_bus_error_free(&error); @@ -272,7 +268,6 @@ TEST(sd_bus_error_set_errnof) { errno = ENOANO; assert_se(asprintf(&str, "hoge %s: %m", "foo") >= 0); assert_se(streq(error.message, str)); - assert_se(error._need_free == 1); str = mfree(str); sd_bus_error_free(&error); @@ -282,7 +277,6 @@ TEST(sd_bus_error_set_errnof) { errno = 100000; assert_se(asprintf(&str, "hoge %s: %m", "foo") >= 0); assert_se(streq(error.message, str)); - assert_se(error._need_free == 1); } DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, dump_mapping_table); From 46ea7c3e3289fd6704f5fb4cfbb1421523ca1c7a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 9 Sep 2025 09:10:44 +0900 Subject: [PATCH 3/3] musl: make strtoll() accept strings start with dot glibc accepts strings start with '.' and returns 0, but musl refuses them. Let's accept them, as our code assumes the function accept such strings. --- src/include/musl/stdlib.h | 7 +++++++ src/libc/musl/meson.build | 1 + src/libc/musl/stdlib.c | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 src/include/musl/stdlib.h create mode 100644 src/libc/musl/stdlib.c diff --git a/src/include/musl/stdlib.h b/src/include/musl/stdlib.h new file mode 100644 index 0000000000..ecfd6ccb43 --- /dev/null +++ b/src/include/musl/stdlib.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include_next + +long long strtoll_fallback(const char *nptr, char **endptr, int base); +#define strtoll strtoll_fallback diff --git a/src/libc/musl/meson.build b/src/libc/musl/meson.build index 78f93c3542..54866a8b61 100644 --- a/src/libc/musl/meson.build +++ b/src/libc/musl/meson.build @@ -6,5 +6,6 @@ endif libc_wrapper_sources += files( 'stdio.c', + 'stdlib.c', 'string.c', ) diff --git a/src/libc/musl/stdlib.c b/src/libc/musl/stdlib.c new file mode 100644 index 0000000000..1106fec9d0 --- /dev/null +++ b/src/libc/musl/stdlib.c @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +/* The header stdlib.h overrides strtoll with strtoll_fallback, hence we need to undef it here. */ +#undef strtoll + +long long strtoll_fallback(const char *nptr, char **endptr, int base) { + /* glibc returns 0 if the first character is '.' without error, but musl returns as an error. + * As our code assumes the glibc behavior, let's accept strings start with '.'. */ + if (nptr && *nptr == '.') { + if (endptr) + *endptr = (char*) nptr; + return 0; + } + + /* Otherwise, use the native strtoll(). */ + return strtoll(nptr, endptr, base); +}