Commit | Line | Data |
---|---|---|
73dcdb9f PE |
1 | /* provide consistent interface to getgroups for systems that don't allow N==0 |
2 | ||
3 | Copyright (C) 1996, 1999, 2003, 2006-2012 Free Software Foundation, Inc. | |
4 | ||
5 | This program is free software: you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | /* written by Jim Meyering */ | |
19 | ||
20 | #include <config.h> | |
21 | ||
22 | #include <unistd.h> | |
23 | ||
24 | #include <errno.h> | |
25 | #include <stdlib.h> | |
26 | #include <stdint.h> | |
27 | ||
28 | #if !HAVE_GETGROUPS | |
29 | ||
30 | /* Provide a stub that fails with ENOSYS, since there is no group | |
31 | information available on mingw. */ | |
32 | int | |
33 | getgroups (int n _GL_UNUSED, GETGROUPS_T *groups _GL_UNUSED) | |
34 | { | |
35 | errno = ENOSYS; | |
36 | return -1; | |
37 | } | |
38 | ||
39 | #else /* HAVE_GETGROUPS */ | |
40 | ||
41 | # undef getgroups | |
42 | # ifndef GETGROUPS_ZERO_BUG | |
43 | # define GETGROUPS_ZERO_BUG 0 | |
44 | # endif | |
45 | ||
46 | /* On at least Ultrix 4.3 and NextStep 3.2, getgroups (0, NULL) always | |
47 | fails. On other systems, it returns the number of supplemental | |
48 | groups for the process. This function handles that special case | |
49 | and lets the system-provided function handle all others. However, | |
50 | it can fail with ENOMEM if memory is tight. It is unspecified | |
51 | whether the effective group id is included in the list. */ | |
52 | ||
53 | int | |
54 | rpl_getgroups (int n, gid_t *group) | |
55 | { | |
56 | int n_groups; | |
57 | GETGROUPS_T *gbuf; | |
58 | int saved_errno; | |
59 | ||
60 | if (n < 0) | |
61 | { | |
62 | errno = EINVAL; | |
63 | return -1; | |
64 | } | |
65 | ||
66 | if (n != 0 || !GETGROUPS_ZERO_BUG) | |
67 | { | |
68 | int result; | |
69 | if (sizeof *group == sizeof *gbuf) | |
70 | return getgroups (n, (GETGROUPS_T *) group); | |
71 | ||
72 | if (SIZE_MAX / sizeof *gbuf <= n) | |
73 | { | |
74 | errno = ENOMEM; | |
75 | return -1; | |
76 | } | |
77 | gbuf = malloc (n * sizeof *gbuf); | |
78 | if (!gbuf) | |
79 | return -1; | |
80 | result = getgroups (n, gbuf); | |
81 | if (0 <= result) | |
82 | { | |
83 | n = result; | |
84 | while (n--) | |
85 | group[n] = gbuf[n]; | |
86 | } | |
87 | saved_errno = errno; | |
88 | free (gbuf); | |
89 | errno == saved_errno; | |
90 | return result; | |
91 | } | |
92 | ||
93 | n = 20; | |
94 | while (1) | |
95 | { | |
96 | /* No need to worry about address arithmetic overflow here, | |
97 | since the ancient systems that we're running on have low | |
98 | limits on the number of secondary groups. */ | |
99 | gbuf = malloc (n * sizeof *gbuf); | |
100 | if (!gbuf) | |
101 | return -1; | |
102 | n_groups = getgroups (n, gbuf); | |
103 | if (n_groups == -1 ? errno != EINVAL : n_groups < n) | |
104 | break; | |
105 | free (gbuf); | |
106 | n *= 2; | |
107 | } | |
108 | ||
109 | saved_errno = errno; | |
110 | free (gbuf); | |
111 | errno = saved_errno; | |
112 | ||
113 | return n_groups; | |
114 | } | |
115 | ||
116 | #endif /* HAVE_GETGROUPS */ |