pub mod tar; use std::{ io::{Error, ErrorKind, Result}, process::ExitStatus, result, }; use ipc_channel::ipc; use nix::{sys::wait, unistd}; pub trait ToIOResult { fn to_io_result(self) -> Result; } impl ToIOResult for nix::Result { fn to_io_result(self) -> Result { self.map_err(|error| match error { nix::Error::Sys(code) => Error::from_raw_os_error(code as i32), _ => Error::new(ErrorKind::Other, error), }) } } pub trait Checkable { fn check(&self) -> Result<()>; } impl Checkable for ExitStatus { fn check(&self) -> Result<()> { if self.success() { Ok(()) } else { Err(Error::new( ErrorKind::Other, format!("process exited with status {}", self), )) } } } impl Checkable for wait::WaitStatus { fn check(&self) -> Result<()> { match self { wait::WaitStatus::Exited(_, 0) => Ok(()), _ => Err(Error::new( ErrorKind::Other, format!("process exited with status {:?}", self), )), } } } pub trait CheckDisconnect { type Output; fn check_disconnect(self) -> Result; } impl CheckDisconnect for result::Result { type Output = result::Result<(), T>; fn check_disconnect(self) -> Result { match self { Ok(v) => Ok(Err(v)), Err(ipc::IpcError::Disconnected) => Ok(Ok(())), Err(error) => Err(Error::new(ErrorKind::Other, error)), } } } pub struct SetEUID(unistd::Uid); impl Drop for SetEUID { fn drop(&mut self) { unistd::seteuid(self.0).expect("failed to reset effective UID"); } } pub fn seteuid(uid: unistd::Uid) -> Result { let old_uid = unistd::geteuid(); unistd::seteuid(uid).to_io_result()?; Ok(SetEUID(old_uid)) } pub struct SetEGID(unistd::Gid); impl Drop for SetEGID { fn drop(&mut self) { unistd::setegid(self.0).expect("failed to reset effective GID"); } } pub fn setegid(gid: unistd::Gid) -> Result { let old_gid = unistd::getegid(); unistd::setegid(gid).to_io_result()?; Ok(SetEGID(old_gid)) }