diff --git a/lib/libzutil/zutil_nicenum.c b/lib/libzutil/zutil_nicenum.c index 44d68e85d0db..3d5e94fc738f 100644 --- a/lib/libzutil/zutil_nicenum.c +++ b/lib/libzutil/zutil_nicenum.c @@ -25,11 +25,39 @@ */ #include +#include #include #include #include #include +/* + * Replace the C locale decimal point ('.') with the locale-specific + * decimal separator in the formatted string. This ensures that + * commands like "zfs list" respect the user's LC_NUMERIC locale. + */ +static void +zfs_nicenum_locale_decimal(char *buf) +{ + const struct lconv *lc = localeconv(); + const char *dp = lc->decimal_point; + + /* + * If locale uses '.' or is empty, nothing to change. + * Skip multibyte separators (e.g. Arabic U+066B) since we can only + * safely replace a single-byte decimal point in the formatted string. + */ + if (dp == NULL || dp[0] == '.' || dp[0] == '\0' || strlen(dp) > 1) + return; + + for (char *p = buf; *p != '\0'; p++) { + if (*p == '.') { + *p = dp[0]; + return; + } + } +} + /* * Return B_TRUE if "str" is a number string, B_FALSE otherwise. * Works for integer and floating point numbers. @@ -140,8 +168,10 @@ zfs_nicenum_format(uint64_t num, char *buf, size_t buflen, } else { if (snprintf(buf, buflen, "%.*f%s", i, - val, u) <= 5) + val, u) <= 5) { + zfs_nicenum_locale_decimal(buf); break; + } } } }