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/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..54866a8b61 100644 --- a/src/libc/musl/meson.build +++ b/src/libc/musl/meson.build @@ -6,4 +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); +} 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; +} 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);