diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 4001688001..33508c2d24 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -611,10 +611,52 @@ impl Pal for Sys { redox_rt::sys::posix_getresugid().rgid as gid_t } - fn getgroups(list: Out<[gid_t]>) -> Result { - // TODO - todo_skip!(0, "getgroups({}, {:p}): not implemented", list.len(), list); - Err(Errno(ENOSYS)) + fn getgroups(mut list: Out<[gid_t]>) -> Result { + // FIXME: this operation doesn't scale when group/passwd file grows + + let uid = Self::geteuid(); + let pwd = crate::header::pwd::getpwuid(uid); + + if pwd.is_null() { + return Err(Errno(ENOENT)); + } + + let username = unsafe { CStr::from_ptr((*pwd).pw_name) }; + let username = username.to_bytes_with_nul(); + let mut count = 0; + + unsafe { + use crate::header::grp; + grp::setgrent(); + + while let Some(grp) = grp::getgrent().as_ref() { + let mut i = 0; + let mut found = false; + + while !(*grp.gr_mem.offset(i)).is_null() { + let member = CStr::from_ptr(*grp.gr_mem.offset(i)); + if member.to_bytes_with_nul() == username { + found = true; + break; + } + i += 1; + } + + if found { + if !list.is_empty() && (count as usize) < list.len() { + list.index(count).write(grp.gr_gid); + } + count += 1; + } + } + grp::endgrent(); + } + + if !list.is_empty() && (count as usize) > list.len() { + return Err(Errno(EINVAL)); + } + + Ok(count as i32) } fn getpagesize() -> usize { diff --git a/tests/Makefile b/tests/Makefile index c7d4d70e1d..4fe21f3a1c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -305,6 +305,7 @@ VARIED_NAMES=\ pthread/timeout \ pthread/tls \ grp/getgrouplist \ + grp/getgroups \ grp/getgrgid_r \ grp/getgrnam_r \ grp/gr_iter \ diff --git a/tests/grp/getgroups.c b/tests/grp/getgroups.c new file mode 100644 index 0000000000..7b06f293e2 --- /dev/null +++ b/tests/grp/getgroups.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +int main() { + gid_t primary_gid = getegid(); + struct group *pg = getgrgid(primary_gid); + + printf("getegid: %u (%s)\n", primary_gid, pg ? pg->gr_name : "?"); + + int count = getgroups(0, NULL); + gid_t *list = malloc(sizeof(gid_t) * count); + getgroups(count, list); + + printf("getgroups: %d\n", count); + for (int i = 0; i < count; i++) { + struct group *sg = getgrgid(list[i]); + + printf(" - %u (%s)\n", list[i], sg ? sg->gr_name : "?"); + } + + free(list); + return 0; +} \ No newline at end of file