2 This file is part of PulseAudio.
4 Copyright 2009 Ted Percival
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 #include <sys/types.h>
37 #include <pulse/xmalloc.h>
38 #include <pulsecore/macro.h>
40 #include "usergroup.h"
44 /* Returns a suitable starting size for a getgrnam_r() or getgrgid_r() buffer,
45 plus the size of a struct group.
47 static size_t starting_getgr_buflen(void) {
50 #ifdef _SC_GETGR_R_SIZE_MAX
51 n = sysconf(_SC_GETGR_R_SIZE_MAX);
58 full_size = (size_t) n + sizeof(struct group);
60 if (full_size < (size_t) n) /* check for integer overflow */
66 /* Returns a suitable starting size for a getpwnam_r() or getpwuid_r() buffer,
67 plus the size of a struct passwd.
69 static size_t starting_getpw_buflen(void) {
73 #ifdef _SC_GETPW_R_SIZE_MAX
74 n = sysconf(_SC_GETPW_R_SIZE_MAX);
81 full_size = (size_t) n + sizeof(struct passwd);
83 if (full_size < (size_t) n) /* check for integer overflow */
89 /* Given a memory allocation (*bufptr) and its length (*buflenptr),
90 double the size of the allocation, updating the given buffer and length
91 arguments. This function should be used in conjunction with the pa_*alloc
92 and pa_xfree functions.
94 Unlike realloc(), this function does *not* retain the original buffer's
97 Returns 0 on success, nonzero on error. The error cause is indicated by
100 static int expand_buffer_trashcontents(void **bufptr, size_t *buflenptr) {
103 if (!bufptr || !*bufptr || !buflenptr) {
108 newlen = *buflenptr * 2;
110 if (newlen < *buflenptr) {
115 /* Don't bother retaining memory contents; free & alloc anew */
118 *bufptr = pa_xmalloc(newlen);
124 #ifdef HAVE_GETGRGID_R
125 /* Thread-safe getgrgid() replacement.
126 Returned value should be freed using pa_getgrgid_free() when the caller is
127 finished with the returned group data.
129 API is the same as getgrgid(), errors are indicated by a NULL return;
130 consult errno for the error cause (zero it before calling).
132 struct group *pa_getgrgid_malloc(gid_t gid) {
133 size_t buflen, getgr_buflen;
137 struct group *result = NULL;
139 buflen = starting_getgr_buflen();
140 buf = pa_xmalloc(buflen);
142 getgr_buflen = buflen - sizeof(struct group);
143 getgr_buf = (char *)buf + sizeof(struct group);
145 while ((err = getgrgid_r(gid, (struct group *)buf, getgr_buf, getgr_buflen, &result)) == ERANGE) {
146 if (expand_buffer_trashcontents(&buf, &buflen))
149 getgr_buflen = buflen - sizeof(struct group);
150 getgr_buf = (char *)buf + sizeof(struct group);
153 if (err || !result) {
161 pa_assert(result == buf || result == NULL);
166 void pa_getgrgid_free(struct group *grp) {
170 #else /* !HAVE_GETGRGID_R */
172 struct group *pa_getgrgid_malloc(gid_t gid) {
173 return getgrgid(gid);
176 void pa_getgrgid_free(struct group *grp) {
181 #endif /* !HAVE_GETGRGID_R */
183 #ifdef HAVE_GETGRNAM_R
184 /* Thread-safe getgrnam() function.
185 Returned value should be freed using pa_getgrnam_free() when the caller is
186 finished with the returned group data.
188 API is the same as getgrnam(), errors are indicated by a NULL return;
189 consult errno for the error cause (zero it before calling).
191 struct group *pa_getgrnam_malloc(const char *name) {
192 size_t buflen, getgr_buflen;
196 struct group *result = NULL;
198 buflen = starting_getgr_buflen();
199 buf = pa_xmalloc(buflen);
201 getgr_buflen = buflen - sizeof(struct group);
202 getgr_buf = (char *)buf + sizeof(struct group);
204 while ((err = getgrnam_r(name, (struct group *)buf, getgr_buf, getgr_buflen, &result)) == ERANGE) {
205 if (expand_buffer_trashcontents(&buf, &buflen))
208 getgr_buflen = buflen - sizeof(struct group);
209 getgr_buf = (char *)buf + sizeof(struct group);
212 if (err || !result) {
220 pa_assert(result == buf || result == NULL);
225 void pa_getgrnam_free(struct group *group) {
229 #else /* !HAVE_GETGRNAM_R */
231 struct group *pa_getgrnam_malloc(const char *name) {
232 return getgrnam(name);
235 void pa_getgrnam_free(struct group *group) {
240 #endif /* HAVE_GETGRNAM_R */
242 #endif /* HAVE_GRP_H */
246 #ifdef HAVE_GETPWNAM_R
247 /* Thread-safe getpwnam() function.
248 Returned value should be freed using pa_getpwnam_free() when the caller is
249 finished with the returned passwd data.
251 API is the same as getpwnam(), errors are indicated by a NULL return;
252 consult errno for the error cause (zero it before calling).
254 struct passwd *pa_getpwnam_malloc(const char *name) {
255 size_t buflen, getpw_buflen;
259 struct passwd *result = NULL;
261 buflen = starting_getpw_buflen();
262 buf = pa_xmalloc(buflen);
264 getpw_buflen = buflen - sizeof(struct passwd);
265 getpw_buf = (char *)buf + sizeof(struct passwd);
267 while ((err = getpwnam_r(name, (struct passwd *)buf, getpw_buf, getpw_buflen, &result)) == ERANGE) {
268 if (expand_buffer_trashcontents(&buf, &buflen))
271 getpw_buflen = buflen - sizeof(struct passwd);
272 getpw_buf = (char *)buf + sizeof(struct passwd);
275 if (err || !result) {
283 pa_assert(result == buf || result == NULL);
288 void pa_getpwnam_free(struct passwd *passwd) {
292 #else /* !HAVE_GETPWNAM_R */
294 struct passwd *pa_getpwnam_malloc(const char *name) {
295 return getpwnam(name);
298 void pa_getpwnam_free(struct passwd *passwd) {
303 #endif /* !HAVE_GETPWNAM_R */
305 #ifdef HAVE_GETPWUID_R
306 /* Thread-safe getpwuid() function.
307 Returned value should be freed using pa_getpwuid_free() when the caller is
308 finished with the returned group data.
310 API is the same as getpwuid(), errors are indicated by a NULL return;
311 consult errno for the error cause (zero it before calling).
313 struct passwd *pa_getpwuid_malloc(uid_t uid) {
314 size_t buflen, getpw_buflen;
318 struct passwd *result = NULL;
320 buflen = starting_getpw_buflen();
321 buf = pa_xmalloc(buflen);
323 getpw_buflen = buflen - sizeof(struct passwd);
324 getpw_buf = (char *)buf + sizeof(struct passwd);
326 while ((err = getpwuid_r(uid, (struct passwd *)buf, getpw_buf, getpw_buflen, &result)) == ERANGE) {
327 if (expand_buffer_trashcontents(&buf, &buflen))
330 getpw_buflen = buflen - sizeof(struct passwd);
331 getpw_buf = (char *)buf + sizeof(struct passwd);
334 if (err || !result) {
342 pa_assert(result == buf || result == NULL);
347 void pa_getpwuid_free(struct passwd *passwd) {
351 #else /* !HAVE_GETPWUID_R */
353 struct passwd *pa_getpwuid_malloc(uid_t uid) {
354 return getpwuid(uid);
357 void pa_getpwuid_free(struct passwd *passwd) {
362 #endif /* !HAVE_GETPWUID_R */
364 #endif /* HAVE_PWD_H */