This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: NSS error reporting (bug 20532)
On 08/04/2017 04:38 PM, Carlos O'Donell wrote:
> We stop setting errno in nss/getXXbyYY_r.c, because none of the reentrant
> versions are supposed to set errno, they are supposed to return the error
> as their result. This might not work easily if other more complex APIs use
> the *_r versions and need errno set.
>
> nss/getXXbyYY_r.c
> * save errno.
> * set errno to zero
> * resolve service to nss_files
> * call nss_files low-level functions: e.g. _nss_files_getpwnam_r (nss_files/files-pwd.c)
> ... and get back NSS_STATUS_TRYAGAIN/ERANGE.
> * save result.
> * restore errno.
> * return result.
>
> nss/getXXbyYY.c
> * call reentrant version
> * save result
> * if (result == ERANGE) then try again with larger buffer.
> Note: errno remains 0 the whole time (except within the *_r function impl)
> * if result != 0 then errno = result
I'm afraid this is not possible. A pre-POSIX version of getpwnam_r set
errno and returned a flag (just like most non-pthread functions). Here
is an excerpt from nscd:
static int
lookup (int type, union keytype key, struct passwd *resultbufp, char
*buffer,
size_t buflen, struct passwd **pwd)
{
if (type == GETPWBYNAME)
return __getpwnam_r (key.v, resultbufp, buffer, buflen, pwd);
else
return __getpwuid_r (key.u, resultbufp, buffer, buflen, pwd);
}
…
while (lookup (req->type, key, &resultbuf, buffer, buflen, &pwd) != 0
&& (errval = errno) == ERANGE)
Here is another excerpt from glob:
while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
!= 0)
{
if (errno != ERANGE)
{
p = NULL;
break;
}
wordexp has the same issue:
while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
&& errno == ERANGE)
Here's an example from OpenJDK:
errno = 0;
#ifdef __solaris__
RESTARTABLE_RETURN_PTR(getgrgid_r((gid_t)gid, &grent, grbuf,
(size_t)buflen), g);
#else
RESTARTABLE(getgrgid_r((gid_t)gid, &grent, grbuf,
(size_t)buflen, &g), res);
#endif
retry = 0;
if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name)
== '\0') {
/* not found or error */
if (errno == ERANGE) {
In short, if we made this change, way too much code would break.
Thanks,
Florian