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
,
146 getgr_buflen
, &result
)) == ERANGE
)
148 if (expand_buffer_trashcontents(&buf
, &buflen
))
151 getgr_buflen
= buflen
- sizeof(struct group
);
152 getgr_buf
= (char *)buf
+ sizeof(struct group
);
155 if (err
|| !result
) {
163 pa_assert(result
== buf
|| result
== NULL
);
168 void pa_getgrgid_free(struct group
*grp
) {
172 #else /* !HAVE_GETGRGID_R */
174 struct group
*pa_getgrgid_malloc(gid_t gid
) {
175 return getgrgid(gid
);
178 void pa_getgrgid_free(struct group
*grp
) {
183 #endif /* !HAVE_GETGRGID_R */
185 #ifdef HAVE_GETGRNAM_R
186 /* Thread-safe getgrnam() function.
187 Returned value should be freed using pa_getgrnam_free() when the caller is
188 finished with the returned group data.
190 API is the same as getgrnam(), errors are indicated by a NULL return;
191 consult errno for the error cause (zero it before calling).
193 struct group
*pa_getgrnam_malloc(const char *name
) {
194 size_t buflen
, getgr_buflen
;
198 struct group
*result
= NULL
;
200 buflen
= starting_getgr_buflen();
201 buf
= pa_xmalloc(buflen
);
203 getgr_buflen
= buflen
- sizeof(struct group
);
204 getgr_buf
= (char *)buf
+ sizeof(struct group
);
206 while ((err
= getgrnam_r(name
, (struct group
*)buf
, getgr_buf
,
207 getgr_buflen
, &result
)) == ERANGE
)
209 if (expand_buffer_trashcontents(&buf
, &buflen
))
212 getgr_buflen
= buflen
- sizeof(struct group
);
213 getgr_buf
= (char *)buf
+ sizeof(struct group
);
216 if (err
|| !result
) {
224 pa_assert(result
== buf
|| result
== NULL
);
229 void pa_getgrnam_free(struct group
*group
) {
233 #else /* !HAVE_GETGRNAM_R */
235 struct group
*pa_getgrnam_malloc(const char *name
) {
236 return getgrnam(name
);
239 void pa_getgrnam_free(struct group
*group
) {
244 #endif /* HAVE_GETGRNAM_R */
246 #endif /* HAVE_GRP_H */
250 #ifdef HAVE_GETPWNAM_R
251 /* Thread-safe getpwnam() function.
252 Returned value should be freed using pa_getpwnam_free() when the caller is
253 finished with the returned passwd data.
255 API is the same as getpwnam(), errors are indicated by a NULL return;
256 consult errno for the error cause (zero it before calling).
258 struct passwd
*pa_getpwnam_malloc(const char *name
) {
259 size_t buflen
, getpw_buflen
;
263 struct passwd
*result
= NULL
;
265 buflen
= starting_getpw_buflen();
266 buf
= pa_xmalloc(buflen
);
268 getpw_buflen
= buflen
- sizeof(struct passwd
);
269 getpw_buf
= (char *)buf
+ sizeof(struct passwd
);
271 while ((err
= getpwnam_r(name
, (struct passwd
*)buf
, getpw_buf
,
272 getpw_buflen
, &result
)) == ERANGE
)
274 if (expand_buffer_trashcontents(&buf
, &buflen
))
277 getpw_buflen
= buflen
- sizeof(struct passwd
);
278 getpw_buf
= (char *)buf
+ sizeof(struct passwd
);
281 if (err
|| !result
) {
289 pa_assert(result
== buf
|| result
== NULL
);
294 void pa_getpwnam_free(struct passwd
*passwd
) {
298 #else /* !HAVE_GETPWNAM_R */
300 struct passwd
*pa_getpwnam_malloc(const char *name
) {
301 return getpwnam(name
);
304 void pa_getpwnam_free(struct passwd
*passwd
) {
309 #endif /* !HAVE_GETPWNAM_R */
311 #ifdef HAVE_GETPWUID_R
312 /* Thread-safe getpwuid() function.
313 Returned value should be freed using pa_getpwuid_free() when the caller is
314 finished with the returned group data.
316 API is the same as getpwuid(), errors are indicated by a NULL return;
317 consult errno for the error cause (zero it before calling).
319 struct passwd
*pa_getpwuid_malloc(uid_t uid
) {
320 size_t buflen
, getpw_buflen
;
324 struct passwd
*result
= NULL
;
326 buflen
= starting_getpw_buflen();
327 buf
= pa_xmalloc(buflen
);
329 getpw_buflen
= buflen
- sizeof(struct passwd
);
330 getpw_buf
= (char *)buf
+ sizeof(struct passwd
);
332 while ((err
= getpwuid_r(uid
, (struct passwd
*)buf
, getpw_buf
,
333 getpw_buflen
, &result
)) == ERANGE
)
335 if (expand_buffer_trashcontents(&buf
, &buflen
))
338 getpw_buflen
= buflen
- sizeof(struct passwd
);
339 getpw_buf
= (char *)buf
+ sizeof(struct passwd
);
342 if (err
|| !result
) {
350 pa_assert(result
== buf
|| result
== NULL
);
355 void pa_getpwuid_free(struct passwd
*passwd
) {
359 #else /* !HAVE_GETPWUID_R */
361 struct passwd
*pa_getpwuid_malloc(uid_t uid
) {
362 return getpwuid(uid
);
365 void pa_getpwuid_free(struct passwd
*passwd
) {
370 #endif /* !HAVE_GETPWUID_R */
372 #endif /* HAVE_PWD_H */