glibc/nss/initgroups-fallback.c
Arjun Shankar b121fdc552 Remove 'grp' and merge into 'nss' and 'posix'
The majority of grp routines are entry points for nss functionality.
This commit removes the 'grp' subdirectory and moves all nss-relevant
functionality and all tests to 'nss', and the 'setgroups' stub into
'posix' (alongside the 'getgroups' stub).  References to grp/ are
accordingly changed.  In addition, compat-initgroups.c, a fallback
implementation of initgroups is renamed to initgroups-fallback.c so that
the build system does not confuse it for nss_compat/compat-initgroups.c.

Build time improves very slightly; e.g. down from an average of 45.5s to
44.5s on an 8-thread mobile x86_64 CPU.
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2023-10-24 12:30:59 +02:00

117 lines
2.7 KiB
C

/* Prototype for the setgrent functions we use here. */
typedef enum nss_status (*set_function) (void);
/* Prototype for the endgrent functions we use here. */
typedef enum nss_status (*end_function) (void);
/* Prototype for the setgrent functions we use here. */
typedef enum nss_status (*get_function) (struct group *, char *,
size_t, int *);
static enum nss_status
compat_call (nss_action_list nip, const char *user, gid_t group, long int *start,
long int *size, gid_t **groupsp, long int limit, int *errnop)
{
struct group grpbuf;
enum nss_status status;
set_function setgrent_fct;
get_function getgrent_fct;
end_function endgrent_fct;
gid_t *groups = *groupsp;
getgrent_fct = __nss_lookup_function (nip, "getgrent_r");
if (getgrent_fct == NULL)
return NSS_STATUS_UNAVAIL;
setgrent_fct = __nss_lookup_function (nip, "setgrent");
if (setgrent_fct)
{
status = DL_CALL_FCT (setgrent_fct, ());
if (status != NSS_STATUS_SUCCESS)
return status;
}
endgrent_fct = __nss_lookup_function (nip, "endgrent");
struct scratch_buffer tmpbuf;
scratch_buffer_init (&tmpbuf);
enum nss_status result = NSS_STATUS_SUCCESS;
do
{
while ((status = DL_CALL_FCT (getgrent_fct,
(&grpbuf, tmpbuf.data, tmpbuf.length,
errnop)),
status == NSS_STATUS_TRYAGAIN)
&& *errnop == ERANGE)
{
if (!scratch_buffer_grow (&tmpbuf))
{
result = NSS_STATUS_TRYAGAIN;
goto done;
}
}
if (status != NSS_STATUS_SUCCESS)
goto done;
if (grpbuf.gr_gid != group)
{
char **m;
for (m = grpbuf.gr_mem; *m != NULL; ++m)
if (strcmp (*m, user) == 0)
{
/* Check whether the group is already on the list. */
long int cnt;
for (cnt = 0; cnt < *start; ++cnt)
if (groups[cnt] == grpbuf.gr_gid)
break;
if (cnt == *start)
{
/* Matches user and not yet on the list. Insert
this group. */
if (__glibc_unlikely (*start == *size))
{
/* Need a bigger buffer. */
gid_t *newgroups;
long int newsize;
if (limit > 0 && *size == limit)
/* We reached the maximum. */
goto done;
if (limit <= 0)
newsize = 2 * *size;
else
newsize = MIN (limit, 2 * *size);
newgroups = realloc (groups,
newsize * sizeof (*groups));
if (newgroups == NULL)
goto done;
*groupsp = groups = newgroups;
*size = newsize;
}
groups[*start] = grpbuf.gr_gid;
*start += 1;
}
break;
}
}
}
while (status == NSS_STATUS_SUCCESS);
done:
scratch_buffer_free (&tmpbuf);
if (endgrent_fct)
DL_CALL_FCT (endgrent_fct, ());
return result;
}