Index: include/xlocale/_string.h =================================================================== --- include/xlocale/_string.h +++ include/xlocale/_string.h @@ -46,6 +46,7 @@ * POSIX2008 functions */ int strcoll_l(const char *, const char *, locale_t); +char *strerror_l(int num, locale_t); size_t strxfrm_l(char *, const char *, size_t, locale_t); #endif /* _XLOCALE_STRING1_H */ Index: lib/libc/include/libc_private.h =================================================================== --- lib/libc/include/libc_private.h +++ lib/libc/include/libc_private.h @@ -431,4 +431,9 @@ void __throw_constraint_handler_s(const char * restrict msg, int error); +struct __nl_cat_d; +struct _xlocale; +struct __nl_cat_d *__catopen_l(const char *name, int type, + struct _xlocale *locale); + #endif /* _LIBC_PRIVATE_H_ */ Index: lib/libc/nls/msgcat.c =================================================================== --- lib/libc/nls/msgcat.c +++ lib/libc/nls/msgcat.c @@ -58,6 +58,7 @@ #include "un-namespace.h" #include "../locale/xlocale_private.h" +#include "libc_private.h" #define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:" \ _PATH_LOCALBASE "/share/nls/%L/%N.cat:" \ @@ -121,6 +122,12 @@ nl_catd catopen(const char *name, int type) +{ + return (__catopen_l(name, type, __get_locale())); +} + +nl_catd +__catopen_l(const char *name, int type, locale_t locale) { struct stat sbuf; struct catentry *np; @@ -139,7 +146,7 @@ lang = NULL; else { if (type == NL_CAT_LOCALE) - lang = querylocale(LC_MESSAGES_MASK, __get_locale()); + lang = querylocale(LC_MESSAGES_MASK, locale); else lang = getenv("LANG"); Index: lib/libc/string/Symbol.map =================================================================== --- lib/libc/string/Symbol.map +++ lib/libc/string/Symbol.map @@ -110,6 +110,10 @@ timingsafe_memcmp; }; +FBSD_1.6 { + strerror_l; +}; + FBSDprivate_1.0 { __strtok_r; }; Index: lib/libc/string/strerror.3 =================================================================== --- lib/libc/string/strerror.3 +++ lib/libc/string/strerror.3 @@ -32,12 +32,13 @@ .\" @(#)strerror.3 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd April 5, 2011 +.Dd December 7, 2020 .Dt STRERROR 3 .Os .Sh NAME .Nm perror , .Nm strerror , +.Nm strerror_l , .Nm strerror_r , .Nm sys_errlist , .Nm sys_nerr @@ -53,12 +54,15 @@ .In string.h .Ft "char *" .Fn strerror "int errnum" +.Ft "char *" +.Fn strerror_l "int errnum" "locale_t" .Ft int .Fn strerror_r "int errnum" "char *strerrbuf" "size_t buflen" .Sh DESCRIPTION The .Fn strerror , -.Fn strerror_r +.Fn strerror_l , +.Fn strerror_r , and .Fn perror functions look up the error message string corresponding to an @@ -68,8 +72,17 @@ .Fn strerror function accepts an error number argument .Fa errnum -and returns a pointer to the corresponding -message string. +and returns a pointer to the corresponding message string in the current locale. +The function is not thread-safe, it returns pointer to the buffer the could +be overwritten by a call to +.Fn strerror +from other thread. +.Pp +The +.Fn strerror_l +takes an error number and locale arguments and return string, +corresponding to specified error, in the requested locale. +The function is thread-safe. .Pp The .Fn strerror_r Index: lib/libc/string/strerror.c =================================================================== --- lib/libc/string/strerror.c +++ lib/libc/string/strerror.c @@ -45,6 +45,8 @@ #include #include "errlst.h" +#include "../locale/xlocale_private.h" +#include "libc_private.h" /* * Define buffer big enough to contain delimiter (": ", 2 bytes), @@ -78,34 +80,35 @@ strlcat(buf, t, len); } -int -strerror_r(int errnum, char *strerrbuf, size_t buflen) +static int +strerror_rl(int errnum, char *strerrbuf, size_t buflen, locale_t locale) { int retval = 0; #if defined(NLS) int saved_errno = errno; nl_catd catd; - catd = catopen("libc", NL_CAT_LOCALE); + + catd = __catopen_l("libc", NL_CAT_LOCALE, locale); #endif if (errnum < 0 || errnum >= __hidden_sys_nerr) { errstr(errnum, #if defined(NLS) - catgets(catd, 1, 0xffff, __uprefix), + catgets(catd, 1, 0xffff, __uprefix), #else - __uprefix, + __uprefix, #endif - strerrbuf, buflen); + strerrbuf, buflen); retval = EINVAL; } else { if (strlcpy(strerrbuf, #if defined(NLS) - catgets(catd, 1, errnum, __hidden_sys_errlist[errnum]), + catgets(catd, 1, errnum, __hidden_sys_errlist[errnum]), #else - __hidden_sys_errlist[errnum], + __hidden_sys_errlist[errnum], #endif - buflen) >= buflen) - retval = ERANGE; + buflen) >= buflen) + retval = ERANGE; } #if defined(NLS) @@ -116,12 +119,33 @@ return (retval); } +int +strerror_r(int errnum, char *strerrbuf, size_t buflen) +{ + return (strerror_rl(errnum, strerrbuf, buflen, __get_locale())); +} + +char * +strerror_l(int num, locale_t locale) +{ +#ifndef __NO_TLS + static _Thread_local char ebuf[NL_TEXTMAX]; + + if (strerror_rl(num, ebuf, sizeof(ebuf), __get_locale()) != 0) + errno = EINVAL; + return (ebuf); +#else + errno = ENOTSUP; + return (NULL); +#endif +} + char * strerror(int num) { static char ebuf[NL_TEXTMAX]; - if (strerror_r(num, ebuf, sizeof(ebuf)) != 0) + if (strerror_rl(num, ebuf, sizeof(ebuf), __get_locale()) != 0) errno = EINVAL; return (ebuf); }