Merge "bionic: Implement getpwent and getgrent"
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index d75b94d..332b2b8 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -54,6 +54,8 @@
group group_;
char* group_members_[2];
char group_name_buffer_[32];
+ // Must be last so init_group_state can run a simple memset for the above
+ ssize_t getgrent_idx;
};
struct passwd_state_t {
@@ -61,13 +63,14 @@
char name_buffer_[32];
char dir_buffer_[32];
char sh_buffer_[32];
+ ssize_t getpwent_idx;
};
static ThreadLocalBuffer<group_state_t> g_group_tls_buffer;
static ThreadLocalBuffer<passwd_state_t> g_passwd_tls_buffer;
static void init_group_state(group_state_t* state) {
- memset(state, 0, sizeof(group_state_t));
+ memset(state, 0, sizeof(group_state_t) - sizeof(state->getgrent_idx));
state->group_.gr_mem = state->group_members_;
}
@@ -467,6 +470,60 @@
return (pw != NULL) ? pw->pw_name : NULL;
}
+void setpwent() {
+ passwd_state_t* state = g_passwd_tls_buffer.get();
+ if (state) {
+ state->getpwent_idx = 0;
+ }
+}
+
+void endpwent() {
+ setpwent();
+}
+
+passwd* getpwent() {
+ passwd_state_t* state = g_passwd_tls_buffer.get();
+ if (state == NULL) {
+ return NULL;
+ }
+ if (state->getpwent_idx < 0) {
+ return NULL;
+ }
+
+ size_t start = 0;
+ ssize_t end = android_id_count;
+ if (state->getpwent_idx < end) {
+ return android_iinfo_to_passwd(state, android_ids + state->getpwent_idx++);
+ }
+
+ start = end;
+ end += AID_OEM_RESERVED_END - AID_OEM_RESERVED_START + 1;
+
+ if (state->getpwent_idx < end) {
+ return oem_id_to_passwd(
+ state->getpwent_idx++ - start + AID_OEM_RESERVED_START, state);
+ }
+
+ start = end;
+ end += AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START + 1;
+
+ if (state->getpwent_idx < end) {
+ return oem_id_to_passwd(
+ state->getpwent_idx++ - start + AID_OEM_RESERVED_2_START, state);
+ }
+
+ start = end;
+ end += AID_USER - AID_APP; // Do not expose higher users
+
+ if (state->getpwent_idx < end) {
+ return app_id_to_passwd(state->getpwent_idx++ - start + AID_APP, state);
+ }
+
+ // We are not reporting u1_a* and higher or we will be here forever
+ state->getpwent_idx = -1;
+ return NULL;
+}
+
static group* getgrgid_internal(gid_t gid, group_state_t* state) {
group* grp = android_id_to_group(state, gid);
if (grp != NULL) {
@@ -537,3 +594,61 @@
struct group **result) {
return getgroup_r(true, name, 0, grp, buf, buflen, result);
}
+
+void setgrent() {
+ group_state_t* state = g_group_tls_buffer.get();
+ if (state) {
+ state->getgrent_idx = 0;
+ }
+}
+
+void endgrent() {
+ setgrent();
+}
+
+group* getgrent() {
+ group_state_t* state = g_group_tls_buffer.get();
+ if (state == NULL) {
+ return NULL;
+ }
+ if (state->getgrent_idx < 0) {
+ return NULL;
+ }
+
+ size_t start = 0;
+ ssize_t end = android_id_count;
+ if (state->getgrent_idx < end) {
+ init_group_state(state);
+ return android_iinfo_to_group(state, android_ids + state->getgrent_idx++);
+ }
+
+ start = end;
+ end += AID_OEM_RESERVED_END - AID_OEM_RESERVED_START + 1;
+
+ if (state->getgrent_idx < end) {
+ init_group_state(state);
+ return oem_id_to_group(
+ state->getgrent_idx++ - start + AID_OEM_RESERVED_START, state);
+ }
+
+ start = end;
+ end += AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START + 1;
+
+ if (state->getgrent_idx < end) {
+ init_group_state(state);
+ return oem_id_to_group(
+ state->getgrent_idx++ - start + AID_OEM_RESERVED_2_START, state);
+ }
+
+ start = end;
+ end += AID_USER - AID_APP; // Do not expose higher groups
+
+ if (state->getgrent_idx < end) {
+ init_group_state(state);
+ return app_id_to_group(state->getgrent_idx++ - start + AID_APP, state);
+ }
+
+ // We are not reporting u1_a* and higher or we will be here forever
+ state->getgrent_idx = -1;
+ return NULL;
+}
diff --git a/libc/bionic/ndk_cruft.cpp b/libc/bionic/ndk_cruft.cpp
index 95abc20..224cd41 100644
--- a/libc/bionic/ndk_cruft.cpp
+++ b/libc/bionic/ndk_cruft.cpp
@@ -366,10 +366,6 @@
return __set_errno_internal(n);
}
-// This was never implemented in bionic, only needed for ABI compatibility with the NDK.
-// In the M time frame, over 1000 apps have a reference to this!
-void endpwent() { }
-
// Since dlmalloc_inspect_all and dlmalloc_trim are exported for systems
// that use dlmalloc, be consistent and export them everywhere.
void dlmalloc_inspect_all(void (*)(void*, void*, size_t, void*), void*) {
diff --git a/libc/include/grp.h b/libc/include/grp.h
index df7a613..3ae0d6e 100644
--- a/libc/include/grp.h
+++ b/libc/include/grp.h
@@ -1,9 +1,9 @@
-/* $OpenBSD: grp.h,v 1.8 2005/12/13 00:35:22 millert Exp $ */
-/* $NetBSD: grp.h,v 1.7 1995/04/29 05:30:40 cgd Exp $ */
+/* $OpenBSD: grp.h,v 1.8 2005/12/13 00:35:22 millert Exp $ */
+/* $NetBSD: grp.h,v 1.7 1995/04/29 05:30:40 cgd Exp $ */
/*-
* Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
@@ -34,39 +34,37 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)grp.h 8.2 (Berkeley) 1/21/94
+ * @(#)grp.h 8.2 (Berkeley) 1/21/94
*/
#ifndef _GRP_H_
-#define _GRP_H_
+#define _GRP_H_
#include <sys/cdefs.h>
#include <sys/types.h>
struct group {
- char *gr_name; /* group name */
- char *gr_passwd; /* group password */
- gid_t gr_gid; /* group id */
- char **gr_mem; /* group members */
+ char* gr_name; /* group name */
+ char* gr_passwd; /* group password */
+ gid_t gr_gid; /* group id */
+ char** gr_mem; /* group members */
};
__BEGIN_DECLS
-struct group *getgrgid(gid_t);
-struct group *getgrnam(const char *);
+struct group* getgrgid(gid_t);
+struct group* getgrnam(const char *);
#if __POSIX_VISIBLE >= 200112 || __XPG_VISIBLE
-struct group *getgrent(void) __attribute__((deprecated("getgrent is meaningless on Android")));
-void setgrent(void) __attribute__((deprecated("setgrent is meaningless on Android")));
-void endgrent(void) __attribute__((deprecated("endgrent is meaningless on Android")));
-int getgrgid_r(gid_t, struct group *, char *,
- size_t, struct group **);
-int getgrnam_r(const char *, struct group *, char *,
- size_t, struct group **);
+/* Android has thousands and thousands of ids to iterate through */
+struct group* getgrent(void) __attribute__((warning("getgrent is inefficient on Android")));
+void setgrent(void);
+void endgrent(void);
+int getgrgid_r(gid_t, struct group *, char *, size_t, struct group **);
+int getgrnam_r(const char *, struct group *, char *, size_t, struct group **);
#endif
-int getgrouplist (const char *user, gid_t group,
- gid_t *groups, int *ngroups);
+int getgrouplist (const char *user, gid_t group, gid_t *groups, int *ngroups);
-int initgroups (const char *user, gid_t group);
+int initgroups (const char *user, gid_t group);
__END_DECLS
diff --git a/libc/include/pwd.h b/libc/include/pwd.h
index 905bc75..e32825e 100644
--- a/libc/include/pwd.h
+++ b/libc/include/pwd.h
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
@@ -31,7 +31,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)pwd.h 8.2 (Berkeley) 1/21/94
+ * @(#)pwd.h 8.2 (Berkeley) 1/21/94
*/
/*-
@@ -118,6 +118,10 @@
struct passwd* getpwnam(const char*);
struct passwd* getpwuid(uid_t);
+/* Android has thousands and thousands of ids to iterate through */
+struct passwd* getpwent(void) __attribute__((warning("getpwent is inefficient on Android")));
+void setpwent(void);
+void endpwent(void);
int getpwnam_r(const char*, struct passwd*, char*, size_t, struct passwd**);
int getpwuid_r(uid_t, struct passwd*, char*, size_t, struct passwd**);
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index b0c8299..ae41430 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1276,12 +1276,18 @@
catclose;
catgets;
catopen;
+ endgrent;
+ endpwent;
getdomainname;
+ getgrent;
+ getpwent;
getsubopt;
hasmntopt;
pthread_getname_np;
quotactl;
setdomainname;
+ setgrent;
+ setpwent;
sighold;
sigignore;
sigpause;
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 7a3b8bd..019a880 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1276,12 +1276,18 @@
catclose;
catgets;
catopen;
+ endgrent;
+ endpwent;
getdomainname;
+ getgrent;
+ getpwent;
getsubopt;
hasmntopt;
pthread_getname_np;
quotactl;
setdomainname;
+ setgrent;
+ setpwent;
sighold;
sigignore;
sigpause;
@@ -1480,7 +1486,6 @@
dlmalloc_inspect_all; # arm x86 mips nobrillo
dlmalloc_trim; # arm x86 mips nobrillo
dlmalloc_usable_size; # arm x86 mips nobrillo
- endpwent; # arm x86 mips nobrillo
fdprintf; # arm x86 mips nobrillo
free_malloc_leak_info;
ftime; # arm x86 mips nobrillo
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 217d95e..b1a50ae 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1198,12 +1198,18 @@
catclose;
catgets;
catopen;
+ endgrent;
+ endpwent;
getdomainname;
+ getgrent;
+ getpwent;
getsubopt;
hasmntopt;
pthread_getname_np;
quotactl;
setdomainname;
+ setgrent;
+ setpwent;
sighold;
sigignore;
sigpause;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index c7f9058..8881485 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1301,12 +1301,18 @@
catclose;
catgets;
catopen;
+ endgrent;
+ endpwent;
getdomainname;
+ getgrent;
+ getpwent;
getsubopt;
hasmntopt;
pthread_getname_np;
quotactl;
setdomainname;
+ setgrent;
+ setpwent;
sighold;
sigignore;
sigpause;
@@ -1506,7 +1512,6 @@
dlmalloc_inspect_all; # arm x86 mips nobrillo
dlmalloc_trim; # arm x86 mips nobrillo
dlmalloc_usable_size; # arm x86 mips nobrillo
- endpwent; # arm x86 mips nobrillo
fdprintf; # arm x86 mips nobrillo
free_malloc_leak_info;
ftime; # arm x86 mips nobrillo
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index 2b92162..c281104 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1260,12 +1260,18 @@
catclose;
catgets;
catopen;
+ endgrent;
+ endpwent;
getdomainname;
+ getgrent;
+ getpwent;
getsubopt;
hasmntopt;
pthread_getname_np;
quotactl;
setdomainname;
+ setgrent;
+ setpwent;
sighold;
sigignore;
sigpause;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 934b23b..47a1ba2 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1260,12 +1260,18 @@
catclose;
catgets;
catopen;
+ endgrent;
+ endpwent;
getdomainname;
+ getgrent;
+ getpwent;
getsubopt;
hasmntopt;
pthread_getname_np;
quotactl;
setdomainname;
+ setgrent;
+ setpwent;
sighold;
sigignore;
sigpause;
@@ -1322,7 +1328,6 @@
dlmalloc_inspect_all; # arm x86 mips nobrillo
dlmalloc_trim; # arm x86 mips nobrillo
dlmalloc_usable_size; # arm x86 mips nobrillo
- endpwent; # arm x86 mips nobrillo
fdprintf; # arm x86 mips nobrillo
free_malloc_leak_info;
ftime; # arm x86 mips nobrillo
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 217d95e..b1a50ae 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1198,12 +1198,18 @@
catclose;
catgets;
catopen;
+ endgrent;
+ endpwent;
getdomainname;
+ getgrent;
+ getpwent;
getsubopt;
hasmntopt;
pthread_getname_np;
quotactl;
setdomainname;
+ setgrent;
+ setpwent;
sighold;
sigignore;
sigpause;
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index d973ac1..30eaf94 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -1258,12 +1258,18 @@
catclose;
catgets;
catopen;
+ endgrent;
+ endpwent;
getdomainname;
+ getgrent;
+ getpwent;
getsubopt;
hasmntopt;
pthread_getname_np;
quotactl;
setdomainname;
+ setgrent;
+ setpwent;
sighold;
sigignore;
sigpause;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index b3f9394..b98f865 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1258,12 +1258,18 @@
catclose;
catgets;
catopen;
+ endgrent;
+ endpwent;
getdomainname;
+ getgrent;
+ getpwent;
getsubopt;
hasmntopt;
pthread_getname_np;
quotactl;
setdomainname;
+ setgrent;
+ setpwent;
sighold;
sigignore;
sigpause;
@@ -1321,7 +1327,6 @@
dlmalloc_inspect_all; # arm x86 mips nobrillo
dlmalloc_trim; # arm x86 mips nobrillo
dlmalloc_usable_size; # arm x86 mips nobrillo
- endpwent; # arm x86 mips nobrillo
fdprintf; # arm x86 mips nobrillo
free_malloc_leak_info;
ftime; # arm x86 mips nobrillo
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 217d95e..b1a50ae 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1198,12 +1198,18 @@
catclose;
catgets;
catopen;
+ endgrent;
+ endpwent;
getdomainname;
+ getgrent;
+ getpwent;
getsubopt;
hasmntopt;
pthread_getname_np;
quotactl;
setdomainname;
+ setgrent;
+ setpwent;
sighold;
sigignore;
sigpause;
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index 29cd907..a684780 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -26,6 +26,10 @@
#include <sys/types.h>
#include <unistd.h>
+#include <bitset>
+
+#include <private/android_filesystem_config.h>
+
enum uid_type_t {
TYPE_SYSTEM,
TYPE_APP
@@ -179,6 +183,46 @@
check_get_passwd("u1_i0", 199000, TYPE_APP);
}
+TEST(getpwent, iterate) {
+ passwd* pwd;
+ std::bitset<10000> exist;
+ bool application = false;
+
+ exist.reset();
+
+ setpwent();
+ while ((pwd = getpwent()) != NULL) {
+ ASSERT_TRUE(NULL != pwd->pw_name);
+ ASSERT_EQ(pwd->pw_gid, pwd->pw_uid);
+ ASSERT_EQ(NULL, pwd->pw_passwd);
+#ifdef __LP64__
+ ASSERT_TRUE(NULL == pwd->pw_gecos);
+#endif
+ ASSERT_TRUE(NULL != pwd->pw_shell);
+ if (pwd->pw_uid >= exist.size()) {
+ ASSERT_STREQ("/data", pwd->pw_dir);
+ application = true;
+ } else {
+ ASSERT_STREQ("/", pwd->pw_dir);
+ ASSERT_FALSE(exist[pwd->pw_uid]);
+ exist[pwd->pw_uid] = true;
+ }
+ }
+ endpwent();
+
+ // Required content
+ for (size_t n = 0; n < android_id_count; ++n) {
+ ASSERT_TRUE(exist[android_ids[n].aid]);
+ }
+ for (size_t n = 2900; n < 2999; ++n) {
+ ASSERT_TRUE(exist[n]);
+ }
+ for (size_t n = 5000; n < 5999; ++n) {
+ ASSERT_TRUE(exist[n]);
+ }
+ ASSERT_TRUE(application);
+}
+
static void check_group(const group* grp, const char* group_name, gid_t gid) {
ASSERT_TRUE(grp != NULL);
ASSERT_STREQ(group_name, grp->gr_name);
@@ -373,3 +417,38 @@
ASSERT_EQ(0, getgrnam_r("root", &grp_storage, buf, size, &grp));
check_group(grp, "root", 0);
}
+
+TEST(getgrent, iterate) {
+ group* grp;
+ std::bitset<10000> exist;
+ bool application = false;
+
+ exist.reset();
+
+ setgrent();
+ while ((grp = getgrent()) != NULL) {
+ ASSERT_TRUE(grp->gr_name != NULL);
+ ASSERT_TRUE(grp->gr_mem != NULL);
+ ASSERT_STREQ(grp->gr_name, grp->gr_mem[0]);
+ ASSERT_TRUE(grp->gr_mem[1] == NULL);
+ if (grp->gr_gid >= exist.size()) {
+ application = true;
+ } else {
+ ASSERT_FALSE(exist[grp->gr_gid]);
+ exist[grp->gr_gid] = true;
+ }
+ }
+ endgrent();
+
+ // Required content
+ for (size_t n = 0; n < android_id_count; ++n) {
+ ASSERT_TRUE(exist[android_ids[n].aid]);
+ }
+ for (size_t n = 2900; n < 2999; ++n) {
+ ASSERT_TRUE(exist[n]);
+ }
+ for (size_t n = 5000; n < 5999; ++n) {
+ ASSERT_TRUE(exist[n]);
+ }
+ ASSERT_TRUE(application);
+}