From 20ff36381973c1b09dc83697a355c17dfa00768c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20R=C3=A1bek?= Date: Fri, 6 Mar 2026 10:10:11 +0100 Subject: [PATCH 1/7] lib: save one strdup by using GNU basename() implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit POSIX states that basename(3) may modify its input string. For this reason, strdup(3) is used in__nvme_transport_handle_open_direct() so that it is safe to call basename(3) on a const char*. This patch introduces an nvme_basename() function that is guaranteed to never modify its input and is thus safe to be used on string literals. It is a copy of basename(3) implementation from glibc. This change allows us to avoid one needless dynamic allocation. Signed-off-by: Michal Rábek --- libnvme/src/nvme/lib.c | 6 +----- libnvme/src/nvme/util.c | 9 +++++++++ libnvme/src/nvme/util.h | 7 +++++++ 3 files changed, 17 insertions(+), 5 deletions(-) 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/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); From e8cdb46e19df824f475dacb078f6d64edeb1047e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20R=C3=A1bek?= Date: Fri, 6 Mar 2026 10:16:16 +0100 Subject: [PATCH 2/7] build: fix musl build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Rábek --- libnvme/src/nvme/linux.c | 4 ++++ libnvme/test/ioctl/mock.c | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) 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/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 } From 6899e9569788081801e6ea2419b16b0d73331f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20R=C3=A1bek?= Date: Fri, 6 Mar 2026 10:17:56 +0100 Subject: [PATCH 3/7] build: add a musl build configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Rábek --- scripts/build.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 \ From 4d5f9b6c01e93123cf7a344d2e22b03aaae0c62b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20R=C3=A1bek?= Date: Thu, 26 Feb 2026 13:41:51 +0100 Subject: [PATCH 4/7] ci: add a musl build job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds with musl libc get broken too often. This patch suggests a new GitHub CI build job to help maintain them being functional. Closes: #2565 Link: https://github.com/linux-nvme/nvme-cli/issues/2565 Signed-off-by: Michal Rábek --- .github/workflows/build.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c6fd4e195c..95422b8535 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -136,6 +136,19 @@ jobs: run: | make static + build-musl: + name: build with musl standard C library + 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-distro: name: build libnvme and nvme-cli separately runs-on: ubuntu-latest From 872ec5e11d6fcbdb6572be3600c773179911b6dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20R=C3=A1bek?= Date: Fri, 27 Feb 2026 23:15:02 +0100 Subject: [PATCH 5/7] test: fix musl libc test fail due to locale differences MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'nvme-cli - uint128' test was failing when build with musl libc. The reason was that musl libc leaves the thousands separator from LC_NUMERIC empty with the fr_FR.utf-8. This patch offers a solution by skipping the test with a warning if the thousands separator cannot be obtained. Signed-off-by: Michal Rábek --- unit/test-uint128.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) 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) From af8d4c1afd2971abaed06a1bebc83b031f67db66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20R=C3=A1bek?= Date: Mon, 2 Mar 2026 15:12:44 +0100 Subject: [PATCH 6/7] test: fix 'diff --unified' failing on Alpine Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The long '--unified' flag of the 'diff' command is GNU specific. Although it is recognized by the Alpine Linux version of 'diff', it is expecting a numeric argument N (number of lines). This difference caused test cases using 'diff' to fail on Alpine. This patch changes that to '-u' which implies N=3 by default on both GNU-based distros and Alpine Linux. Signed-off-by: Michal Rábek --- libnvme/test/nbft/nbft-dump-diff.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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" - From 2148c390a1d9005a41d0687d3ed8e3d465fa9e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20R=C3=A1bek?= Date: Fri, 6 Mar 2026 09:09:18 +0100 Subject: [PATCH 7/7] ci: add build job in an Alpine container with musl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces a new CI job that builds the project with musl standard C library in the environment in which it is most commonly used - Alpine Linux. Signed-off-by: Michal Rábek --- .github/workflows/build.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 95422b8535..977449fd92 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -137,7 +137,7 @@ jobs: make static build-musl: - name: build with musl standard C library + name: musl libc build on Debian runs-on: ubuntu-latest container: image: ghcr.io/linux-nvme/debian:latest @@ -149,6 +149,19 @@ jobs: 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