+ return start;
+}
+
+/* Store at most *NGROUPS members of the group set for USER into
+ *GROUPS. Also include GROUP. The actual number of groups found is
+ returned in *NGROUPS. Return -1 if the if *NGROUPS is too small. */
+int
+getgrouplist (const char *user, gid_t group, gid_t *groups, int *ngroups)
+{
+ gid_t *newgroups;
+ long int size = *ngroups;
+ int result;
+
+ newgroups = (gid_t *) malloc (size * sizeof (gid_t));
+ if (__builtin_expect (newgroups == NULL, 0))
+ /* No more memory. */
+ return -1;
+
+ result = internal_getgrouplist (user, group, &size, &newgroups, -1);
+ if (result > *ngroups)
+ {
+ *ngroups = result;
+ result = -1;
+ }
+ else
+ *ngroups = result;
+
+ memcpy (groups, newgroups, *ngroups * sizeof (gid_t));
+
+ free (newgroups);
+ return result;
+}
+
+/* Initialize the group set for the current user
+ by reading the group database and using all groups
+ of which USER is a member. Also include GROUP. */
+int
+initgroups (const char *user, gid_t group)
+{
+#if defined NGROUPS_MAX && NGROUPS_MAX == 0
+
+ /* No extra groups allowed. */
+ return 0;
+
+#else
+
+ long int size;
+ gid_t *groups;
+ int ngroups;
+ int result;
+
+ /* We always use sysconf even if NGROUPS_MAX is defined. That way, the
+ limit can be raised in the kernel configuration without having to
+ recompile libc. */
+ long int limit = __sysconf (_SC_NGROUPS_MAX);
+
+ if (limit > 0)
+ size = limit;
+ else
+ {
+ /* No fixed limit on groups. Pick a starting buffer size. */
+ size = 16;
+ }
+
+ groups = (gid_t *) malloc (size * sizeof (gid_t));
+ if (__builtin_expect (groups == NULL, 0))
+ /* No more memory. */
+ return -1;
+
+ ngroups = internal_getgrouplist (user, group, &size, &groups, limit);
+