use std::ffi::{CStr,CString};
use std::ptr;
use crate::errno::{Error,Result};
use crate::stdlib::realloc;
use crate::util::*;
pub use libc::gid_t;
pub struct Group {
grp: libc::group,
buf: *mut libc::c_void
}
impl Group {
pub fn gr_name(&self) -> &CStr {
unsafe { CStr::from_ptr(self.grp.gr_name) }
}
pub fn gr_passwd(&self) -> &CStr {
unsafe { CStr::from_ptr(self.grp.gr_passwd) }
}
pub fn gr_gid(&self) -> gid_t {
self.grp.gr_gid
}
pub fn gr_mem(&self) -> Option<Vec<&CStr>> {
unsafe {
if (*self.grp.gr_mem).is_null() {
return None;
}
let mut vec = Vec::new();
let mut p = self.grp.gr_mem;
while !(*p).is_null() {
vec.push(CStr::from_ptr(*p));
p = p.add(1);
}
Some(vec)
}
}
}
impl Drop for Group {
fn drop(&mut self) {
unsafe { libc::free(self.buf); }
}
}
pub fn getgid() -> gid_t {
unsafe { libc::getgid() }
}
pub fn getegid() -> gid_t {
unsafe { libc::getegid() }
}
pub fn getgrnam<T: Into<Vec<u8>>>(name: T) -> Result<Option<Group>> {
let cstring = CString::new(name)?;
let cstr = cstring.as_c_str();
unsafe {
let mut grp: libc::group = zeroed();
let mut result: *mut libc::group = ptr::null_mut();
let mut bufsize = get_bufsize(BufType::Group);
let mut buf = ptr::null_mut();
loop {
buf = realloc(buf, bufsize)?;
let buf_i8 = buf as *mut i8;
let rv = libc::getgrnam_r(cstr.as_ptr(), &mut grp,
buf_i8, bufsize, &mut result);
if !result.is_null() {
break;
}
match rv {
0 => return Ok(None),
_ => {
if rv != libc::ERANGE {
return Err(Error::new(rv));
}
bufsize *= 2;
}
}
}
Ok(Some(Group { grp, buf }))
}
}
pub fn getgrgid(gid: gid_t) -> Result<Option<Group>> {
unsafe {
let mut grp: libc::group = zeroed();
let mut result: *mut libc::group = ptr::null_mut();
let mut bufsize = get_bufsize(BufType::Group);
let mut buf = ptr::null_mut();
loop {
buf = realloc(buf, bufsize)?;
let buf_i8 = buf as *mut i8;
let rv = libc::getgrgid_r(gid, &mut grp, buf_i8, bufsize, &mut result);
if !result.is_null() {
break;
}
match rv {
0 => return Ok(None),
_ => {
if rv != libc::ERANGE {
return Err(Error::new(rv));
}
bufsize *= 2;
}
}
}
Ok(Some(Group { grp, buf }))
}
}
pub fn setregid(rgid: gid_t, egid: gid_t) -> Result<()> {
unsafe {
if libc::setregid(rgid, egid) == 0 {
Ok(())
} else {
Err(Error::errno())
}
}
}