Move ports/ChangeLog* files to ChangeLog.old-ports*, remove ports/ directory.
[glibc.git] / grp / compat-initgroups.c
blobff10e247f4c776e942fb855bd75cec820d0f0d87
1 /* Prototype for the setgrent functions we use here. */
2 typedef enum nss_status (*set_function) (void);
4 /* Prototype for the endgrent functions we use here. */
5 typedef enum nss_status (*end_function) (void);
7 /* Prototype for the setgrent functions we use here. */
8 typedef enum nss_status (*get_function) (struct group *, char *,
9 size_t, int *);
12 static enum nss_status
13 compat_call (service_user *nip, const char *user, gid_t group, long int *start,
14 long int *size, gid_t **groupsp, long int limit, int *errnop)
16 struct group grpbuf;
17 size_t buflen = __sysconf (_SC_GETGR_R_SIZE_MAX);
18 enum nss_status status;
19 set_function setgrent_fct;
20 get_function getgrent_fct;
21 end_function endgrent_fct;
22 gid_t *groups = *groupsp;
24 getgrent_fct = __nss_lookup_function (nip, "getgrent_r");
25 if (getgrent_fct == NULL)
26 return NSS_STATUS_UNAVAIL;
28 setgrent_fct = __nss_lookup_function (nip, "setgrent");
29 if (setgrent_fct)
31 status = DL_CALL_FCT (setgrent_fct, ());
32 if (status != NSS_STATUS_SUCCESS)
33 return status;
36 endgrent_fct = __nss_lookup_function (nip, "endgrent");
38 char *tmpbuf = __alloca (buflen);
39 bool use_malloc = false;
40 enum nss_status result = NSS_STATUS_SUCCESS;
44 while ((status = DL_CALL_FCT (getgrent_fct,
45 (&grpbuf, tmpbuf, buflen, errnop)),
46 status == NSS_STATUS_TRYAGAIN)
47 && *errnop == ERANGE)
49 if (__libc_use_alloca (buflen * 2))
50 tmpbuf = extend_alloca (tmpbuf, buflen, buflen * 2);
51 else
53 buflen *= 2;
54 char *newbuf = realloc (use_malloc ? tmpbuf : NULL, buflen);
55 if (newbuf == NULL)
57 result = NSS_STATUS_TRYAGAIN;
58 goto done;
60 use_malloc = true;
61 tmpbuf = newbuf;
65 if (status != NSS_STATUS_SUCCESS)
66 goto done;
68 if (grpbuf.gr_gid != group)
70 char **m;
72 for (m = grpbuf.gr_mem; *m != NULL; ++m)
73 if (strcmp (*m, user) == 0)
75 /* Check whether the group is already on the list. */
76 long int cnt;
77 for (cnt = 0; cnt < *start; ++cnt)
78 if (groups[cnt] == grpbuf.gr_gid)
79 break;
81 if (cnt == *start)
83 /* Matches user and not yet on the list. Insert
84 this group. */
85 if (__glibc_unlikely (*start == *size))
87 /* Need a bigger buffer. */
88 gid_t *newgroups;
89 long int newsize;
91 if (limit > 0 && *size == limit)
92 /* We reached the maximum. */
93 goto done;
95 if (limit <= 0)
96 newsize = 2 * *size;
97 else
98 newsize = MIN (limit, 2 * *size);
100 newgroups = realloc (groups,
101 newsize * sizeof (*groups));
102 if (newgroups == NULL)
103 goto done;
104 *groupsp = groups = newgroups;
105 *size = newsize;
108 groups[*start] = grpbuf.gr_gid;
109 *start += 1;
112 break;
116 while (status == NSS_STATUS_SUCCESS);
118 done:
119 if (use_malloc)
120 free (tmpbuf);
122 if (endgrent_fct)
123 DL_CALL_FCT (endgrent_fct, ());
125 return result;