Implement strerror_l().

Only for the arches that provide user-mode TLS.

PR: 251651
Requested by:	yuri
Discussed with:	emaste, jilles, tijl
Sponsored by:	The FreeBSD Foundation
Differential revision:	https://reviews.freebsd.org/D27495
MFC after:	2 weeks
This commit is contained in:
Konstantin Belousov 2020-12-16 09:02:09 +00:00
parent 3ab53b27e3
commit 675079b1ea
7 changed files with 96 additions and 22 deletions

View File

@ -46,6 +46,7 @@ typedef struct _xlocale *locale_t;
* 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 */

View File

@ -431,4 +431,9 @@ void ___pthread_cleanup_pop_imp(int);
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_ */

View File

@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#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 @@ SLIST_HEAD(listhead, catentry) cache =
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 @@ catopen(const char *name, int type)
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");

View File

@ -64,6 +64,7 @@ MLINKS+=strcpy.3 stpcpy.3 \
strcpy.3 strncpy.3
MLINKS+=strdup.3 strndup.3
MLINKS+=strerror.3 perror.3 \
strerror.3 strerror_l.3 \
strerror.3 strerror_r.3 \
strerror.3 sys_errlist.3 \
strerror.3 sys_nerr.3

View File

@ -110,6 +110,10 @@ FBSD_1.5 {
timingsafe_memcmp;
};
FBSD_1.6 {
strerror_l;
};
FBSDprivate_1.0 {
__strtok_r;
};

View File

@ -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,28 @@ The
.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.
.Fn strerror
is not thread-safe.
It returns a pointer to an internal static buffer that could be
overwritten by a
.Fn strerror
call from another thread.
.Pp
The
.Fn strerror_l
function accepts
.Fa errnum
error number and
.Fa locale
locale handle arguments and returns a pointer to a string
corresponding to the specified error in the given locale.
.Fn strerror_l
is thread-safe, its result can be only overwritten by
another call to
.Fn strerror_l
from the current thread.
.Pp
The
.Fn strerror_r
@ -141,7 +165,8 @@ The external value
contains a count of the messages in
.Va sys_errlist .
The use of these variables is deprecated;
.Fn strerror
.Fn strerror ,
.Fn strerror_l ,
or
.Fn strerror_r
should be used instead.
@ -160,6 +185,10 @@ The
.Fn strerror_r
function conforms to
.St -p1003.1-2001 .
The
.Fn strerror_l
function conforms to
.St -p1003.1-2008 .
.Sh HISTORY
The
.Fn strerror
@ -173,18 +202,21 @@ function was implemented in
.Fx 4.4
by
.An Wes Peters Aq Mt wes@FreeBSD.org .
The
.Fn strerror_l
function was added in
.Fx 13.0 .
.Sh BUGS
The
.Fn strerror
function returns its result in a static buffer which
will be overwritten by subsequent calls.
.Pp
The return type for
.Fn strerror
is missing a type-qualifier; it should actually be
.Vt const char * .
.Pp
Programs that use the deprecated
.Va sys_errlist
variable often fail to compile because they declare it
inconsistently.
Size of the
.Va sys_errlist
object might increase during FreeBSD lifetime,
breaking some ABI stability guarantees.

View File

@ -45,6 +45,8 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#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 @@ errstr(int num, const char *uprefix, char *buf, size_t len)
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 @@ strerror_r(int errnum, char *strerrbuf, size_t buflen)
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), 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);
}