Implement getpwnam_r(3) and getpwuid_r(3).

These functions were already declared in <pwd.h>, but hadn't been implemented
yet.

git cherry-pick --no-commit 081504af74826bad7035669ad34d457b4b439e8f

Change-Id: I316acf4cffb9f2c6788e8e342aa620f9a00886d5
This commit is contained in:
Brian Carlstrom 2011-05-27 00:52:21 -07:00
parent fe88a194a3
commit 1f8e2672a8

View File

@ -37,6 +37,78 @@
#include <errno.h>
#include <ctype.h>
static int do_getpw_r(int by_name, const char* name, uid_t uid,
struct passwd* dst, char* buf, size_t byte_count, struct passwd** result)
{
/*
* getpwnam_r and getpwuid_r don't modify errno, but library calls we
* make might.
*/
int old_errno = errno;
int rc = 0;
*result = NULL;
const struct passwd* src = by_name ? getpwnam(name) : getpwuid(uid);
/*
* POSIX allows failure to find a match to be considered a non-error.
* Reporting success (0) but with *result NULL is glibc's behavior.
*/
if (src == NULL) {
rc = (errno == ENOENT) ? 0 : errno;
goto failure;
}
/*
* Work out where our strings will go in 'buf', and whether we've got
* enough space.
*/
size_t required_byte_count = 0;
dst->pw_name = buf;
required_byte_count += strlen(src->pw_name) + 1;
dst->pw_dir = buf + required_byte_count;
required_byte_count += strlen(src->pw_dir) + 1;
dst->pw_shell = buf + required_byte_count;
required_byte_count += strlen(src->pw_shell) + 1;
if (byte_count < required_byte_count) {
rc = ERANGE;
goto failure;
}
/* Copy the strings. */
snprintf(buf, byte_count, "%s%c%s%c%s",
src->pw_name, 0, src->pw_dir, 0, src->pw_shell);
/*
* pw_passwd is non-POSIX and unused (always NULL) in bionic.
* pw_gecos is non-POSIX and missing in bionic.
*/
dst->pw_passwd = NULL;
/* Copy the integral fields. */
dst->pw_gid = src->pw_gid;
dst->pw_uid = src->pw_uid;
success:
rc = 0;
*result = dst;
failure:
errno = old_errno;
return rc;
}
int getpwnam_r(const char* name, struct passwd* pwd,
char* buf, size_t byte_count, struct passwd** result)
{
return do_getpw_r(1, name, -1, pwd, buf, byte_count, result);
}
int getpwuid_r(uid_t uid, struct passwd* pwd,
char* buf, size_t byte_count, struct passwd** result)
{
return do_getpw_r(0, NULL, uid, pwd, buf, byte_count, result);
}
/** Thread-specific state for the stubs functions
**/
@ -400,4 +472,3 @@ void endusershell(void)
{
fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
}