Merge branch 'master' of github.com:/mono/mono
[mono-project/dkf.git] / support / grp.c
blob09aff343270d79148b7d626d06724e7b6bdac232
1 /*
2 * <grp.h> wrapper functions.
4 * Authors:
5 * Jonathan Pryor (jonpryor@vt.edu)
7 * Copyright (C) 2004-2005 Jonathan Pryor
8 */
10 #include <sys/types.h>
11 #include <sys/param.h>
12 #include <grp.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <unistd.h> /* for setgroups on Mac OS X */
19 #include "map.h"
20 #include "mph.h"
22 G_BEGIN_DECLS
24 static void
25 count_members (char **gr_mem, int *count, size_t *mem)
27 char *cur;
28 *count = 0;
30 // ensure that later (*mem)+1 doesn't result in integer overflow
31 if (*mem > INT_MAX - 1)
32 return;
34 for (cur = *gr_mem; cur != NULL; cur = *++gr_mem) {
35 size_t len;
36 len = strlen (cur);
38 if (!(len < INT_MAX - ((*mem) + 1)))
39 break;
41 ++(*count);
42 *mem += (len + 1);
46 static int
47 copy_group (struct Mono_Posix_Syscall__Group *to, struct group *from)
49 size_t nlen, plen, buflen;
50 int i, count;
51 char *cur, **to_mem;
53 to->gr_gid = from->gr_gid;
55 to->gr_name = NULL;
56 to->gr_passwd = NULL;
57 to->gr_mem = NULL;
58 to->_gr_buf_ = NULL;
60 nlen = strlen (from->gr_name);
61 plen = strlen (from->gr_passwd);
63 buflen = 2;
65 if (!(nlen < INT_MAX - buflen))
66 return -1;
67 buflen += nlen;
69 if (!(plen < INT_MAX - buflen))
70 return -1;
71 buflen += plen;
73 count = 0;
74 count_members (from->gr_mem, &count, &buflen);
76 to->_gr_nmem_ = count;
77 cur = to->_gr_buf_ = (char*) malloc (buflen);
78 to_mem = to->gr_mem = malloc (sizeof(char*)*(count+1));
79 if (to->_gr_buf_ == NULL || to->gr_mem == NULL) {
80 free (to->_gr_buf_);
81 free (to->gr_mem);
82 return -1;
85 to->gr_name = strcpy (cur, from->gr_name);
86 cur += (nlen + 1);
87 to->gr_passwd = strcpy (cur, from->gr_passwd);
88 cur += (plen + 1);
90 for (i = 0; i != count; ++i) {
91 to_mem [i] = strcpy (cur, from->gr_mem[i]);
92 cur += (strlen (from->gr_mem[i])+1);
94 to_mem [i] = NULL;
96 return 0;
99 gint32
100 Mono_Posix_Syscall_getgrnam (const char *name, struct Mono_Posix_Syscall__Group *gbuf)
102 struct group *_gbuf;
104 if (gbuf == NULL) {
105 errno = EFAULT;
106 return -1;
109 errno = 0;
110 _gbuf = getgrnam (name);
111 if (_gbuf == NULL)
112 return -1;
114 if (copy_group (gbuf, _gbuf) == -1) {
115 errno = ENOMEM;
116 return -1;
118 return 0;
121 gint32
122 Mono_Posix_Syscall_getgrgid (mph_gid_t gid, struct Mono_Posix_Syscall__Group *gbuf)
124 struct group *_gbuf;
126 if (gbuf == NULL) {
127 errno = EFAULT;
128 return -1;
131 errno = 0;
132 _gbuf = getgrgid (gid);
133 if (_gbuf == NULL)
134 return -1;
136 if (copy_group (gbuf, _gbuf) == -1) {
137 errno = ENOMEM;
138 return -1;
140 return 0;
143 #ifdef HAVE_GETGRNAM_R
144 gint32
145 Mono_Posix_Syscall_getgrnam_r (const char *name,
146 struct Mono_Posix_Syscall__Group *gbuf,
147 void **gbufp)
149 char *buf, *buf2;
150 size_t buflen;
151 int r;
152 struct group _grbuf;
154 if (gbuf == NULL) {
155 errno = EFAULT;
156 return -1;
159 buf = buf2 = NULL;
160 buflen = 2;
162 do {
163 buf2 = realloc (buf, buflen *= 2);
164 if (buf2 == NULL) {
165 free (buf);
166 errno = ENOMEM;
167 return -1;
169 buf = buf2;
170 errno = 0;
171 } while ((r = getgrnam_r (name, &_grbuf, buf, buflen, (struct group**) gbufp)) &&
172 recheck_range (r));
174 /* On Solaris, this function returns 0 even if the entry was not found */
175 if (r == 0 && !(*gbufp))
176 r = errno = ENOENT;
178 if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
179 r = errno = ENOMEM;
180 free (buf);
182 return r;
184 #endif /* ndef HAVE_GETGRNAM_R */
186 #ifdef HAVE_GETGRGID_R
187 gint32
188 Mono_Posix_Syscall_getgrgid_r (mph_gid_t gid,
189 struct Mono_Posix_Syscall__Group *gbuf,
190 void **gbufp)
192 char *buf, *buf2;
193 size_t buflen;
194 int r;
195 struct group _grbuf;
197 if (gbuf == NULL) {
198 errno = EFAULT;
199 return -1;
202 buf = buf2 = NULL;
203 buflen = 2;
205 do {
206 buf2 = realloc (buf, buflen *= 2);
207 if (buf2 == NULL) {
208 free (buf);
209 errno = ENOMEM;
210 return -1;
212 buf = buf2;
213 errno = 0;
214 } while ((r = getgrgid_r (gid, &_grbuf, buf, buflen, (struct group**) gbufp)) &&
215 recheck_range (r));
217 /* On Solaris, this function returns 0 even if the entry was not found */
218 if (r == 0 && !(*gbufp))
219 r = errno = ENOENT;
221 if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
222 r = errno = ENOMEM;
223 free (buf);
225 return r;
227 #endif /* ndef HAVE_GETGRGID_R */
229 #if HAVE_GETGRENT
230 gint32
231 Mono_Posix_Syscall_getgrent (struct Mono_Posix_Syscall__Group *grbuf)
233 struct group *gr;
235 if (grbuf == NULL) {
236 errno = EFAULT;
237 return -1;
240 errno = 0;
241 gr = getgrent ();
242 if (gr == NULL)
243 return -1;
245 if (copy_group (grbuf, gr) == -1) {
246 errno = ENOMEM;
247 return -1;
249 return 0;
251 #endif /* def HAVE_GETGRENT */
253 #ifdef HAVE_FGETGRENT
254 gint32
255 Mono_Posix_Syscall_fgetgrent (void *stream, struct Mono_Posix_Syscall__Group *grbuf)
257 struct group *gr;
259 if (grbuf == NULL) {
260 errno = EFAULT;
261 return -1;
264 errno = 0;
265 gr = fgetgrent ((FILE*) stream);
266 if (gr == NULL)
267 return -1;
269 if (copy_group (grbuf, gr) == -1) {
270 errno = ENOMEM;
271 return -1;
273 return 0;
275 #endif /* ndef HAVE_FGETGRENT */
277 #if HAVE_SETGROUPS
278 gint32
279 Mono_Posix_Syscall_setgroups (mph_size_t size, mph_gid_t *list)
281 mph_return_if_size_t_overflow (size);
282 return setgroups ((size_t) size, list);
284 #endif /* def HAVE_SETGROUPS */
286 #if HAVE_SETGRENT
288 Mono_Posix_Syscall_setgrent (void)
290 errno = 0;
291 do {
292 setgrent ();
293 } while (errno == EINTR);
294 mph_return_if_val_in_list5(errno, EIO, EMFILE, ENFILE, ENOMEM, ERANGE);
295 return 0;
297 #endif /* def HAVE_SETGRENT */
299 #if HAVE_ENDGRENT
301 Mono_Posix_Syscall_endgrent (void)
303 endgrent();
304 return 0;
306 #endif /* def HAVE_ENDGRENT */
309 G_END_DECLS
312 * vim: noexpandtab