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:
parent
fe88a194a3
commit
1f8e2672a8
@ -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__);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user