@@ -982,6 +982,51 @@ pub fn setgid(gid: Gid) -> Result<()> {
982982 Errno :: result ( res) . map ( drop)
983983}
984984
985+ /// Set the list of supplementary group IDs for the calling process.
986+ ///
987+ /// *Note:* On macOS, `getgroups()` may not return the same group list set by
988+ /// calling `setgroups()`. The use of `setgroups()` on macOS is 'highly
989+ /// discouraged' by Apple. Developers are referred to the `opendirectoryd`
990+ /// daemon and its set of APIs.
991+ ///
992+ /// [Further reading](http://man7.org/linux/man-pages/man2/getgroups.2.html)
993+ ///
994+ /// # Examples
995+ ///
996+ /// `setgroups` can be used when dropping privileges from the root user to a
997+ /// specific user and group. For example, given the user `www-data` with UID
998+ /// `33` and the group `backup` with the GID `34`, one could switch user as
999+ /// follows:
1000+ /// ```
1001+ /// let uid = Uid::from_raw(33);
1002+ /// let gid = Gid::from_raw(34);
1003+ /// setgroups(&[gid])?;
1004+ /// setgid(gid)?;
1005+ /// setuid(uid)?;
1006+ /// ```
1007+ pub fn setgroups ( groups : & [ Gid ] ) -> Result < ( ) > {
1008+ cfg_if ! {
1009+ if #[ cfg( any( target_os = "dragonfly" ,
1010+ target_os = "freebsd" ,
1011+ target_os = "ios" ,
1012+ target_os = "macos" ,
1013+ target_os = "netbsd" ,
1014+ target_os = "openbsd" ) ) ] {
1015+ type setgroups_ngroups_t = c_int;
1016+ } else {
1017+ type setgroups_ngroups_t = size_t;
1018+ }
1019+ }
1020+ // FIXME: On the platforms we currently support, the `Gid` struct has the
1021+ // same representation in memory as a bare `gid_t`. This is not necessarily
1022+ // the case on all Rust platforms, though. See RFC 1785.
1023+ let res = unsafe {
1024+ libc:: setgroups ( groups. len ( ) as setgroups_ngroups_t , groups. as_ptr ( ) as * const gid_t )
1025+ } ;
1026+
1027+ Errno :: result ( res) . map ( |_| ( ) )
1028+ }
1029+
9851030#[ inline]
9861031pub fn pause ( ) -> Result < ( ) > {
9871032 let res = unsafe { libc:: pause ( ) } ;
0 commit comments