@@ -171,6 +171,44 @@ fn test_initgroups() {
171
171
setgroups ( & old_groups) . unwrap ( ) ;
172
172
}
173
173
174
+ /// `initgroups()` test specific to Apple platforms.
175
+ ///
176
+ /// `getgroups()` and `setgroups()` do not behave as expected on Apple
177
+ /// platforms and the use of `setgroups()` is highly discouraged. The only
178
+ /// thing we have to work on is this note in the `getgroups(2)` manpage:
179
+ /// _"Calling initgroups(3) to opt-in for supplementary groups will cause
180
+ /// getgroups() to return a single entry, the GID that was passed to
181
+ /// initgroups(3)"_
182
+ /// This tests that behaviour.
183
+ #[ test]
184
+ #[ cfg( any( target_os = "ios" , target_os = "macos" ) ) ]
185
+ fn test_initgroups ( ) {
186
+ // Skip this test when not run as root as `initgroups()` and `setgroups()`
187
+ // require root.
188
+ if !Uid :: current ( ) . is_root ( ) {
189
+ let stderr = std:: io:: stderr ( ) ;
190
+ let mut handle = stderr. lock ( ) ;
191
+ writeln ! ( handle, "test_initgroups requires root privileges. Skipping test." ) . unwrap ( ) ;
192
+ return ;
193
+ }
194
+
195
+ #[ allow( unused_variables) ]
196
+ let m = :: GROUPS_MTX . lock ( ) . expect ( "Mutex got poisoned by another test" ) ;
197
+
198
+ // It doesn't matter if the root user is not called "root" or if a user
199
+ // called "root" doesn't exist. We are just checking that the extra,
200
+ // made-up group, `123`, is set.
201
+ // FIXME: Test the other half of initgroups' functionality: whether the
202
+ // groups that the user belongs to are also set.
203
+ let user = CString :: new ( "root" ) . unwrap ( ) ;
204
+ let group = Gid :: from_raw ( 123 ) ;
205
+
206
+ initgroups ( & user, group) . unwrap ( ) ;
207
+
208
+ let new_groups = getgroups ( ) . unwrap ( ) ;
209
+ assert ! ( new_groups. contains( & group) ) ;
210
+ }
211
+
174
212
macro_rules! execve_test_factory(
175
213
( $test_name: ident, $syscall: ident, $exe: expr) => (
176
214
#[ test]
0 commit comments