Skip to content

Commit f760287

Browse files
committed
unistd::getgroups: Retry on EINVAL
1 parent 25512e9 commit f760287

File tree

1 file changed

+23
-12
lines changed

1 file changed

+23
-12
lines changed

src/unistd.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -943,26 +943,37 @@ pub fn setgid(gid: Gid) -> Result<()> {
943943

944944
/// Get the list of supplementary group IDs of the calling process.
945945
///
946-
/// Note that if the user is added to more group(s) while this call is in
947-
/// progress then an error (EINVAL) will be returned.
948-
///
949946
/// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
950947
pub fn getgroups() -> Result<Vec<Gid>> {
951948
// First get the number of groups so we can size our Vec
952949
use std::ptr;
953950
let ret = unsafe { libc::getgroups(0, ptr::null_mut()) };
954-
let size = try!(Errno::result(ret));
951+
let mut size = try!(Errno::result(ret));
955952

956953
// Now actually get the groups
957954
let mut groups = Vec::<Gid>::with_capacity(size as usize);
958-
// We can coerce a pointer to some `Gid`s as a pointer to some `gid_t`s as
959-
// they have the same representation in memory.
960-
let ret = unsafe { libc::getgroups(size, groups.as_mut_ptr() as *mut gid_t) };
961-
962-
Errno::result(ret).map(|s| {
963-
unsafe { groups.set_len(s as usize) };
964-
groups
965-
})
955+
loop {
956+
// We can coerce a pointer to some `Gid`s as a pointer to some `gid_t`s
957+
// as they have the same representation in memory.
958+
let ret = unsafe { libc::getgroups(size, groups.as_mut_ptr() as *mut gid_t) };
959+
960+
match Errno::result(ret) {
961+
Ok(s) => {
962+
unsafe { groups.set_len(s as usize) };
963+
break
964+
},
965+
Err(Error::Sys(Errno::EINVAL)) => {
966+
// EINVAL indicates that size was too small, so trigger a
967+
// resize of the groups Vec and try again...
968+
let cap = groups.capacity();
969+
unsafe { groups.set_len(cap) };
970+
groups.reserve(1);
971+
size = groups.capacity() as c_int;
972+
},
973+
Err(e) => return Err(e)
974+
}
975+
}
976+
Ok(groups)
966977
}
967978

968979
/// Set the list of supplementary group IDs for the calling process.

0 commit comments

Comments
 (0)