Skip to content

Commit 0fba0ae

Browse files
committed
unistd: Add getgroups()
1 parent e62b885 commit 0fba0ae

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

src/unistd.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,49 @@ pub fn setgid(gid: Gid) -> Result<()> {
982982
Errno::result(res).map(drop)
983983
}
984984

985+
/// Get the list of supplementary group IDs of the calling process.
986+
///
987+
/// *Note:* On macOS, `getgroups()` behavior differs somewhat from other Unix
988+
/// platforms. It returns the current group access list for the user associated
989+
/// with the effective user id of the process; the group access list may change
990+
/// over the lifetime of the process, and it is not affected by calls to
991+
/// `setgroups()`.
992+
///
993+
/// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
994+
pub fn getgroups() -> Result<Vec<Gid>> {
995+
// First get the number of groups so we can size our Vec
996+
use std::ptr;
997+
let ret = unsafe { libc::getgroups(0, ptr::null_mut()) };
998+
let mut size = Errno::result(ret)?;
999+
1000+
// Now actually get the groups. We try multiple times in case the number of
1001+
// groups has changed since the first call to getgroups() and the buffer is
1002+
// now too small
1003+
let mut groups = Vec::<Gid>::with_capacity(size as usize);
1004+
loop {
1005+
// FIXME: On the platforms we currently support, the `Gid` struct has
1006+
// the same representation in memory as a bare `gid_t`. This is not
1007+
// necessarily the case on all Rust platforms, though. See RFC 1785.
1008+
let ret = unsafe { libc::getgroups(size, groups.as_mut_ptr() as *mut gid_t) };
1009+
1010+
match Errno::result(ret) {
1011+
Ok(s) => {
1012+
unsafe { groups.set_len(s as usize) };
1013+
return Ok(groups);
1014+
},
1015+
Err(Error::Sys(Errno::EINVAL)) => {
1016+
// EINVAL indicates that size was too small, so trigger a
1017+
// resize of the groups Vec and try again...
1018+
let cap = groups.capacity();
1019+
unsafe { groups.set_len(cap) };
1020+
groups.reserve(1);
1021+
size = groups.capacity() as c_int;
1022+
},
1023+
Err(e) => return Err(e)
1024+
}
1025+
}
1026+
}
1027+
9851028
/// Set the list of supplementary group IDs for the calling process.
9861029
///
9871030
/// *Note:* On macOS, `getgroups()` may not return the same group list set by

0 commit comments

Comments
 (0)