use std::io;
use std::ops::{Deref, DerefMut};
use std::os::fd::BorrowedFd;
use std::path::Path;
use crate::native::{Cage, Child, Grants, SpawnError};
use crate::unix::Proc;
use crate::{Audit, Receipt, Violation, ViolationStream, Violations};
impl Cage {
pub fn spawn_async(
&self,
command: &mut tokio::process::Command,
grants: &Grants,
) -> Result<AsyncChild, SpawnError> {
self.spawn_async_with_fds(command, grants, &[])
}
pub fn spawn_async_with_fds(
&self,
command: &mut tokio::process::Command,
grants: &Grants,
fds: &[BorrowedFd<'_>],
) -> Result<AsyncChild, SpawnError> {
if tokio::runtime::Handle::try_current().is_err() {
return Err(SpawnError::NoRuntime);
}
let launch = self.launch(command.as_std_mut(), grants, fds)?;
match command.spawn() {
Ok(inner) => Ok(AsyncChild(
self.adopt(launch, Proc::Tokio(std::panic::AssertUnwindSafe(inner))),
)),
Err(e) => Err(launch.abandon(e)),
}
}
}
#[derive(Debug)]
pub struct AsyncChild(Child);
impl AsyncChild {
pub async fn kill_all(&mut self) -> io::Result<()> {
self.0.signal()?;
let waited = self.deref_mut().wait().await.map(drop);
self.0.end(waited)
}
pub fn audit(&mut self) -> Option<Audit> {
self.0.audit()
}
pub fn receipt(&mut self) -> Option<Receipt> {
self.0.receipt()
}
pub fn violations(&mut self) -> Violations {
self.0.violations()
}
pub fn violation_stream(&mut self) -> Option<ViolationStream> {
self.0.violation_stream()
}
pub fn violation_receiver(&mut self) -> Option<std::sync::mpsc::Receiver<Violation>> {
self.0.violation_receiver()
}
pub fn detach(self) -> tokio::process::Child {
match self.0.release() {
Proc::Tokio(c) => c.0,
Proc::Std(_) => unreachable!("an async handle holds a tokio child"),
}
}
pub fn dropped_env(&self) -> &[String] {
self.0.dropped_env()
}
pub fn tmpdir(&self) -> Option<&Path> {
self.0.tmpdir()
}
}
impl Deref for AsyncChild {
type Target = tokio::process::Child;
fn deref(&self) -> &tokio::process::Child {
match self.0.inner() {
Proc::Tokio(c) => &c.0,
Proc::Std(_) => unreachable!("an async handle holds a tokio child"),
}
}
}
impl DerefMut for AsyncChild {
fn deref_mut(&mut self) -> &mut tokio::process::Child {
match self.0.inner_mut() {
Proc::Tokio(c) => &mut c.0,
Proc::Std(_) => unreachable!("an async handle holds a tokio child"),
}
}
}