@@ -171,6 +171,44 @@ fn test_initgroups() {
171171 setgroups ( & old_groups) . unwrap ( ) ;
172172}
173173
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+
174212macro_rules! execve_test_factory(
175213 ( $test_name: ident, $syscall: ident, $exe: expr) => (
176214 #[ test]
0 commit comments