use std::ffi;
use std::io;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::ffi::OsStringExt;
use std::path::Path;
pub mod exec;
pub mod priority;
pub mod resource;
pub mod sigaction;
pub mod sigmask;
pub mod wait;
#[cfg(target_os = "linux")]
pub mod namespace;
#[cfg(target_os = "linux")]
pub mod prctl;
#[cfg(target_os = "linux")]
pub mod signalfd;
use super::externs;
use super::{Char, GidT, Int, PidT, UidT};
#[inline]
pub fn getpid() -> PidT {
unsafe { libc::getpid() }
}
#[cfg(target_os = "linux")]
#[inline]
pub fn gettid() -> PidT {
unsafe { libc::syscall(libc::SYS_gettid) as PidT }
}
#[inline]
pub fn getppid() -> PidT {
unsafe { libc::getppid() }
}
#[inline]
pub fn getuid() -> UidT {
unsafe { libc::getuid() }
}
#[inline]
pub fn geteuid() -> UidT {
unsafe { libc::geteuid() }
}
#[inline]
pub fn getgid() -> GidT {
unsafe { libc::getgid() }
}
#[inline]
pub fn getegid() -> GidT {
unsafe { libc::getegid() }
}
pub fn getgroups_raw(groups: &mut Vec<GidT>) -> io::Result<Int> {
super::error::convert_neg_ret(unsafe {
libc::getgroups(groups.len() as Int, groups.as_mut_ptr())
})
}
pub fn getgroups() -> io::Result<Vec<GidT>> {
let mut groups: Vec<GidT> = Vec::new();
let ngroups = getgroups_raw(&mut groups)?;
groups.resize(ngroups as usize, 0);
if getgroups_raw(&mut groups)? != ngroups {
return Err(io::Error::last_os_error());
}
Ok(groups)
}
pub fn getallgroups() -> io::Result<Vec<GidT>> {
let mut groups = getgroups()?;
let (rgid, egid) = getregid();
groups.retain(|&x| x != rgid && x != egid);
if rgid == egid {
groups.insert(0, egid);
} else {
groups.splice(0..0, [rgid, egid].iter().cloned());
}
Ok(groups)
}
pub fn getlogin() -> io::Result<ffi::OsString> {
let init_length = super::constrain(
super::sysconf(libc::_SC_LOGIN_NAME_MAX).unwrap_or(256),
64,
1024,
) as usize;
super::error::while_erange(
|i| {
let length = init_length * (i as usize + 1);
let mut buf: Vec<Char> = Vec::new();
super::error::convert_nzero(
unsafe {
buf.resize(length, 0);
externs::getlogin_r(buf.as_mut_ptr(), length)
},
buf,
)
.map(|buf| {
ffi::OsString::from_vec(
buf.iter()
.take_while(|x| **x > 0)
.map(|x| *x as u8)
.collect(),
)
})
},
10,
)
}
pub fn setuid(uid: UidT) -> io::Result<()> {
super::error::convert_nzero(unsafe { libc::setuid(uid) }, ())
}
pub fn seteuid(uid: UidT) -> io::Result<()> {
super::error::convert_nzero(unsafe { libc::seteuid(uid) }, ())
}
pub fn setreuid(ruid: UidT, euid: UidT) -> io::Result<()> {
super::error::convert_nzero(unsafe { externs::setreuid(ruid, euid) }, ())
}
pub fn setgid(gid: GidT) -> io::Result<()> {
super::error::convert_nzero(unsafe { libc::setgid(gid) }, ())
}
pub fn setegid(gid: GidT) -> io::Result<()> {
super::error::convert_nzero(unsafe { libc::setegid(gid) }, ())
}
pub fn setregid(rgid: GidT, egid: GidT) -> io::Result<()> {
super::error::convert_nzero(unsafe { externs::setregid(rgid, egid) }, ())
}
#[cfg(target_os = "linux")]
type SetGroupsSize = super::SizeT;
#[cfg(any(
target_os = "openbsd",
target_os = "netbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "macos",
))]
type SetGroupsSize = Int;
pub fn setgroups(groups: &[GidT]) -> io::Result<()> {
super::error::convert_nzero(
unsafe { libc::setgroups(groups.len() as SetGroupsSize, groups.as_ptr()) },
(),
)
}
cfg_if::cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd", target_os = "dragonfly"))] {
pub fn getresuid() -> (UidT, UidT, UidT) {
let mut ruid: UidT = 0;
let mut euid: UidT = 0;
let mut suid: UidT = 0;
unsafe { externs::getresuid(&mut ruid, &mut euid, &mut suid); }
(ruid, euid, suid)
}
pub fn getresgid() -> (GidT, GidT, GidT) {
let mut rgid: GidT = 0;
let mut egid: GidT = 0;
let mut sgid: GidT = 0;
unsafe { externs::getresgid(&mut rgid, &mut egid, &mut sgid); }
(rgid, egid, sgid)
}
pub fn setresuid(ruid: UidT, euid: UidT, suid: UidT) -> io::Result<()> {
super::error::convert_nzero(unsafe {
externs::setresuid(ruid, euid, suid)
}, ())
}
pub fn setresgid(rgid: GidT, egid: GidT, sgid: GidT) -> io::Result<()> {
super::error::convert_nzero(unsafe {
externs::setresgid(rgid, egid, sgid)
}, ())
}
fn getreuid_impl() -> (UidT, UidT) {
let (ruid, euid, _) = getresuid();
(ruid, euid)
}
fn getregid_impl() -> (GidT, GidT) {
let (rgid, egid, _) = getresgid();
(rgid, egid)
}
}
else {
fn getreuid_impl() -> (UidT, UidT) {
(getuid(), geteuid())
}
fn getregid_impl() -> (GidT, GidT) {
(getgid(), getegid())
}
}
}
#[inline]
pub fn getreuid() -> (UidT, UidT) {
getreuid_impl()
}
#[inline]
pub fn getregid() -> (GidT, GidT) {
getregid_impl()
}
pub fn chroot<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = ffi::CString::new(path.as_ref().as_os_str().as_bytes())?;
super::error::convert_nzero(unsafe { libc::chroot(path.as_ptr()) }, ())
}
#[inline]
pub fn chdir<P: AsRef<Path>>(path: P) -> io::Result<()> {
std::env::set_current_dir(path)
}
pub fn fork() -> io::Result<Int> {
super::error::convert_neg_ret(unsafe { libc::fork() })
}
pub fn setpgid(pid: PidT, pgid: PidT) -> io::Result<()> {
super::error::convert_nzero(unsafe { libc::setpgid(pid, pgid) }, ())
}
pub fn setsid() -> io::Result<PidT> {
super::error::convert_neg_ret(unsafe { libc::setsid() })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_getpids_tid() {
getpid();
getppid();
#[cfg(target_os = "linux")]
gettid();
}
#[test]
fn test_getuidgid() {
assert_eq!((getuid(), geteuid()), getreuid());
assert_eq!((getgid(), getegid()), getregid());
}
#[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly"
))]
#[test]
fn test_resuidgid() {
let (ruid, euid, _suid) = getresuid();
assert_eq!((getuid(), geteuid()), (ruid, euid));
let (rgid, egid, _sgid) = getresgid();
assert_eq!((getgid(), getegid()), (rgid, egid));
}
#[test]
fn test_getgroups() {
getgroups().unwrap();
getallgroups().unwrap();
}
#[test]
fn test_chdir() {
chdir("/").unwrap();
}
}