Skip to content

Commit 5ff0c35

Browse files
committed
unistd: Add getgroups()
1 parent a154b26 commit 5ff0c35

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
@@ -1047,6 +1047,49 @@ pub fn setgid(gid: Gid) -> Result<()> {
10471047
Errno::result(res).map(drop)
10481048
}
10491049

1050+
/// Get the list of supplementary group IDs of the calling process.
1051+
///
1052+
/// *Note:* On macOS, `getgroups()` behavior differs somewhat from other Unix
1053+
/// platforms. It returns the current group access list for the user associated
1054+
/// with the effective user id of the process; the group access list may change
1055+
/// over the lifetime of the process, and it is not affected by calls to
1056+
/// `setgroups()`.
1057+
///
1058+
/// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
1059+
pub fn getgroups() -> Result<Vec<Gid>> {
1060+
// First get the number of groups so we can size our Vec
1061+
use std::ptr;
1062+
let ret = unsafe { libc::getgroups(0, ptr::null_mut()) };
1063+
let mut size = Errno::result(ret)?;
1064+
1065+
// Now actually get the groups. We try multiple times in case the number of
1066+
// groups has changed since the first call to getgroups() and the buffer is
1067+
// now too small
1068+
let mut groups = Vec::<Gid>::with_capacity(size as usize);
1069+
loop {
1070+
// FIXME: On the platforms we currently support, the `Gid` struct has
1071+
// the same representation in memory as a bare `gid_t`. This is not
1072+
// necessarily the case on all Rust platforms, though. See RFC 1785.
1073+
let ret = unsafe { libc::getgroups(size, groups.as_mut_ptr() as *mut gid_t) };
1074+
1075+
match Errno::result(ret) {
1076+
Ok(s) => {
1077+
unsafe { groups.set_len(s as usize) };
1078+
return Ok(groups);
1079+
},
1080+
Err(Error::Sys(Errno::EINVAL)) => {
1081+
// EINVAL indicates that size was too small, so trigger a
1082+
// resize of the groups Vec and try again...
1083+
let cap = groups.capacity();
1084+
unsafe { groups.set_len(cap) };
1085+
groups.reserve(1);
1086+
size = groups.capacity() as c_int;
1087+
},
1088+
Err(e) => return Err(e)
1089+
}
1090+
}
1091+
}
1092+
10501093
/// Set the list of supplementary group IDs for the calling process.
10511094
///
10521095
/// *Note:* On macOS, `getgroups()` may not return the same group list set by

0 commit comments

Comments
 (0)