diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c6fd4e195c..977449fd92 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -136,6 +136,32 @@ jobs: run: | make static + build-musl: + name: musl libc build on Debian + runs-on: ubuntu-latest + container: + image: ghcr.io/linux-nvme/debian:latest + steps: + - uses: actions/checkout@v5 + - name: Mark repo as safe for git + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: build + run: | + CC=musl-gcc scripts/build.sh musl + + build-alpine: + name: musl libc build on Alpine + runs-on: ubuntu-latest + container: + image: ghcr.io/linux-nvme/alpine:next + steps: + - uses: actions/checkout@v5 + - name: Mark repo as safe for git + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: build + run: | + scripts/build.sh musl + build-distro: name: build libnvme and nvme-cli separately runs-on: ubuntu-latest diff --git a/libnvme/src/nvme/lib.c b/libnvme/src/nvme/lib.c index b7865da5a3..bccb06f094 100644 --- a/libnvme/src/nvme/lib.c +++ b/libnvme/src/nvme/lib.c @@ -125,15 +125,11 @@ static int __nvme_transport_handle_open_direct( { struct nvme_passthru_cmd dummy = { 0 }; _cleanup_free_ char *path = NULL; - _cleanup_free_ char *_devname = NULL; char *name; int ret, id, ns; bool c = true; - _devname = strdup(devname); - if (!_devname) - return -ENOMEM; - name = basename(_devname); + name = nvme_basename(devname); hdl->type = NVME_TRANSPORT_HANDLE_TYPE_DIRECT; diff --git a/libnvme/src/nvme/linux.c b/libnvme/src/nvme/linux.c index a9f83a0fd8..6dfaf10d43 100644 --- a/libnvme/src/nvme/linux.c +++ b/libnvme/src/nvme/linux.c @@ -12,6 +12,10 @@ #include #include +#ifndef _GNU_SOURCE +#include +#endif + #include #include #include diff --git a/libnvme/src/nvme/util.c b/libnvme/src/nvme/util.c index 74c940ddb8..ed2e239648 100644 --- a/libnvme/src/nvme/util.c +++ b/libnvme/src/nvme/util.c @@ -981,3 +981,12 @@ const struct ifaddrs *nvme_getifaddrs(struct nvme_global_ctx *ctx) return ctx->ifaddrs_cache; } + +/* This used instead of basename() due to behavioral differences between + * the POSIX and the GNU version. This is the glibc implementation. + * Original source: https://github.com/bminor/glibc/blob/master/string/basename.c */ +char *nvme_basename(const char *path) +{ + char *p = (char *) strrchr(path, '/'); + return p ? p + 1 : (char *) path; +} diff --git a/libnvme/src/nvme/util.h b/libnvme/src/nvme/util.h index dad8a0e1fb..0a9e2625e2 100644 --- a/libnvme/src/nvme/util.h +++ b/libnvme/src/nvme/util.h @@ -218,3 +218,10 @@ int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN]); */ int nvme_uuid_find(struct nvme_id_uuid_list *uuid_list, const unsigned char uuid[NVME_UUID_LEN]); +/** + * nvme_basename - Return the final path component (the one after the last '/') + * @path: A string containing a filesystem path + * + * Return: A pointer into the original null-terminated path string. + */ +char *nvme_basename(const char *path); diff --git a/libnvme/test/ioctl/mock.c b/libnvme/test/ioctl/mock.c index 0333b53b01..baa87de4e7 100644 --- a/libnvme/test/ioctl/mock.c +++ b/libnvme/test/ioctl/mock.c @@ -157,9 +157,12 @@ int ioctl(int fd, int request, ...) real_ioctl = dlsym(RTLD_NEXT, "ioctl"); if (!real_ioctl) fail("Error: dlsym failed to find original ioctl\n"); -#else +#elif defined(HAVE_GLIBC_IOCTL) && HAVE_GLIBC_IOCTL == 1 fprintf(stderr, "Warning: unhandled ioctl %lx\n", request); return -ENOTTY; +#else + fprintf(stderr, "Warning: unhandled ioctl %x\n", request); + return -ENOTTY; #endif } diff --git a/libnvme/test/nbft/nbft-dump-diff.sh.in b/libnvme/test/nbft/nbft-dump-diff.sh.in index f697bce033..46de39d21d 100755 --- a/libnvme/test/nbft/nbft-dump-diff.sh.in +++ b/libnvme/test/nbft/nbft-dump-diff.sh.in @@ -5,4 +5,4 @@ if [ $# -ne 2 ]; then exit 255 fi -"@NBFT_DUMP_PATH@" "$1" | diff --unified "$2" - +"@NBFT_DUMP_PATH@" "$1" | diff -u "$2" - diff --git a/scripts/build.sh b/scripts/build.sh index 2109a6bbdc..e8defd4caf 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -82,6 +82,23 @@ config_meson_default() { "${BUILDDIR}" } +config_meson_musl() { + local c_args="-U_GNU_SOURCE \ +-idirafter /usr/include -idirafter \ +/usr/include/x86_64-linux-gnu" + + CC="${CC}" "${MESON}" setup \ + --werror \ + --buildtype="${BUILDTYPE}" \ + -Dc_args="${c_args}" \ + -Ddefault_library=static \ + -Djson-c=disabled \ + -Dopenssl=disabled \ + -Dkeyutils=disabled \ + -Dpython=disabled \ + "${BUILDDIR}" +} + config_meson_libdbus() { CC="${CC}" "${MESON}" setup \ --werror \ diff --git a/unit/test-uint128.c b/unit/test-uint128.c index f8478ef57d..f7bc6f6445 100644 --- a/unit/test-uint128.c +++ b/unit/test-uint128.c @@ -49,16 +49,30 @@ static struct tostr_test tostr_tests[] = { void tostr_test(struct tostr_test *test) { char *str; + const char *exp = test->exp; if (!setlocale(LC_NUMERIC, test->locale)) return; - if (test->locale) + if (test->locale) { + /* For locale tests, adapt to what the system provides. + * musl libc may not support thousands_sep for all locales. */ + struct lconv *lc = localeconv(); + const char *sep = lc->thousands_sep; + + if (!sep || !*sep) { + /* No separator available, skip test */ + fprintf(stderr, "WARNING: thousands_sep is empty for " + "this system's %s locale! Skipping test...\n", + test->locale); + return; + } str = uint128_t_to_l10n_string(test->val); - else + } else { str = uint128_t_to_string(test->val); + } - check_str(test->val, test->exp, str); + check_str(test->val, exp, str); } int main(void)