2005-11-06 Zoltan Varga <vargaz@freemail.hu>
[mono-project.git] / support / grp.c
blob8e2a3f790cf38e37bea281b8d548e77d56d737d2
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 "mph.h"
21 G_BEGIN_DECLS
23 struct Mono_Posix_Syscall__Group {
24 /* string */ char *gr_name;
25 /* string */ char *gr_passwd;
26 /* gid_t */ mph_gid_t gr_gid;
27 /* int */ int _gr_nmem_;
28 /* string */ char **gr_mem;
29 /* string */ char *_gr_buf_; /* holds all but gr_mem */
32 static void
33 count_members (char **gr_mem, int *count, size_t *mem)
35 char *cur;
36 *count = 0;
38 // ensure that later (*mem)+1 doesn't result in integer overflow
39 if (*mem > INT_MAX - 1)
40 return;
42 for (cur = *gr_mem; cur != NULL; cur = *++gr_mem) {
43 size_t len;
44 len = strlen (cur);
46 if (!(len < INT_MAX - ((*mem) + 1)))
47 break;
49 ++(*count);
50 *mem += (len + 1);
54 static int
55 copy_group (struct Mono_Posix_Syscall__Group *to, struct group *from)
57 size_t nlen, plen, buflen;
58 int i, count;
59 char *cur;
61 to->gr_gid = from->gr_gid;
63 to->gr_name = NULL;
64 to->gr_passwd = NULL;
65 to->gr_mem = NULL;
66 to->_gr_buf_ = NULL;
68 nlen = strlen (from->gr_name);
69 plen = strlen (from->gr_passwd);
71 buflen = 2;
73 if (!(nlen < INT_MAX - buflen))
74 return -1;
75 buflen += nlen;
77 if (!(plen < INT_MAX - buflen))
78 return -1;
79 buflen += plen;
81 count = 0;
82 count_members (from->gr_mem, &count, &buflen);
84 to->_gr_nmem_ = count;
85 cur = to->_gr_buf_ = (char*) malloc (buflen);
86 to->gr_mem = (char **) malloc (sizeof(char*)*(count+1));
87 if (to->_gr_buf_ == NULL || to->gr_mem == NULL) {
88 free (to->_gr_buf_);
89 free (to->gr_mem);
90 return -1;
93 to->gr_name = strcpy (cur, from->gr_name);
94 cur += (nlen + 1);
95 to->gr_passwd = strcpy (cur, from->gr_passwd);
96 cur += (plen + 1);
98 for (i = 0; i != count; ++i) {
99 to->gr_mem[i] = strcpy (cur, from->gr_mem[i]);
100 cur += (strlen (from->gr_mem[i])+1);
102 to->gr_mem[i] = NULL;
104 return 0;
107 gint32
108 Mono_Posix_Syscall_getgrnam (const char *name, struct Mono_Posix_Syscall__Group *gbuf)
110 struct group *_gbuf;
112 if (gbuf == NULL) {
113 errno = EFAULT;
114 return -1;
117 errno = 0;
118 _gbuf = getgrnam (name);
119 if (_gbuf == NULL)
120 return -1;
122 if (copy_group (gbuf, _gbuf) == -1) {
123 errno = ENOMEM;
124 return -1;
126 return 0;
129 gint32
130 Mono_Posix_Syscall_getgrgid (mph_gid_t gid, struct Mono_Posix_Syscall__Group *gbuf)
132 struct group *_gbuf;
134 if (gbuf == NULL) {
135 errno = EFAULT;
136 return -1;
139 errno = 0;
140 _gbuf = getgrgid (gid);
141 if (_gbuf == NULL)
142 return -1;
144 if (copy_group (gbuf, _gbuf) == -1) {
145 errno = ENOMEM;
146 return -1;
148 return 0;
151 #ifdef HAVE_GETGRNAM_R
152 gint32
153 Mono_Posix_Syscall_getgrnam_r (const char *name,
154 struct Mono_Posix_Syscall__Group *gbuf,
155 void **gbufp)
157 char *buf, *buf2;
158 size_t buflen;
159 int r;
160 struct group _grbuf;
162 if (gbuf == NULL) {
163 errno = EFAULT;
164 return -1;
167 buf = buf2 = NULL;
168 buflen = 2;
170 do {
171 buf2 = realloc (buf, buflen *= 2);
172 if (buf2 == NULL) {
173 free (buf);
174 errno = ENOMEM;
175 return -1;
177 buf = buf2;
178 errno = 0;
179 } while ((r = getgrnam_r (name, &_grbuf, buf, buflen, (struct group**) gbufp)) &&
180 recheck_range (r));
182 /* On Solaris, this function returns 0 even if the entry was not found */
183 if (r == 0 && !(*gbufp))
184 r = errno = ENOENT;
186 if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
187 r = errno = ENOMEM;
188 free (buf);
190 return r;
192 #endif /* ndef HAVE_GETGRNAM_R */
194 #ifdef HAVE_GETGRGID_R
195 gint32
196 Mono_Posix_Syscall_getgrgid_r (mph_gid_t gid,
197 struct Mono_Posix_Syscall__Group *gbuf,
198 void **gbufp)
200 char *buf, *buf2;
201 size_t buflen;
202 int r;
203 struct group _grbuf;
205 if (gbuf == NULL) {
206 errno = EFAULT;
207 return -1;
210 buf = buf2 = NULL;
211 buflen = 2;
213 do {
214 buf2 = realloc (buf, buflen *= 2);
215 if (buf2 == NULL) {
216 free (buf);
217 errno = ENOMEM;
218 return -1;
220 buf = buf2;
221 errno = 0;
222 } while ((r = getgrgid_r (gid, &_grbuf, buf, buflen, (struct group**) gbufp)) &&
223 recheck_range (r));
225 /* On Solaris, this function returns 0 even if the entry was not found */
226 if (r == 0 && !(*gbufp))
227 r = errno = ENOENT;
229 if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
230 r = errno = ENOMEM;
231 free (buf);
233 return r;
235 #endif /* ndef HAVE_GETGRGID_R */
237 gint32
238 Mono_Posix_Syscall_getgrent (struct Mono_Posix_Syscall__Group *grbuf)
240 struct group *gr;
242 if (grbuf == NULL) {
243 errno = EFAULT;
244 return -1;
247 errno = 0;
248 gr = getgrent ();
249 if (gr == NULL)
250 return -1;
252 if (copy_group (grbuf, gr) == -1) {
253 errno = ENOMEM;
254 return -1;
256 return 0;
259 #ifdef HAVE_FGETGRENT
260 gint32
261 Mono_Posix_Syscall_fgetgrent (void *stream, struct Mono_Posix_Syscall__Group *grbuf)
263 struct group *gr;
265 if (grbuf == NULL) {
266 errno = EFAULT;
267 return -1;
270 errno = 0;
271 gr = fgetgrent ((FILE*) stream);
272 if (gr == NULL)
273 return -1;
275 if (copy_group (grbuf, gr) == -1) {
276 errno = ENOMEM;
277 return -1;
279 return 0;
281 #endif /* ndef HAVE_FGETGRENT */
283 gint32
284 Mono_Posix_Syscall_setgroups (mph_size_t size, mph_gid_t *list)
286 mph_return_if_size_t_overflow (size);
287 return setgroups ((size_t) size, list);
291 Mono_Posix_Syscall_setgrent (void)
293 errno = 0;
294 setgrent ();
295 return errno == 0 ? 0 : -1;
299 Mono_Posix_Syscall_endgrent (void)
301 errno = 0;
302 endgrent();
303 return errno == 0 ? 0 : -1;
307 G_END_DECLS
310 * vim: noexpandtab