Hagia
log in
morj / wzmach
overview
files
history
wiki
Viewing at
use std::os::unix::prelude::CommandExt;

use super::{Action, ActionError};

pub struct CommandAction {
pub path: String,
pub args: Vec<String>,
}

pub struct ShellCommandAction {
pub command: String,
}

impl Action for CommandAction {
fn execute(&mut self) -> Result<(), ActionError> {
log::debug!("Execute command {} {:?}", self.path, self.args);

std::process::Command::new(&self.path)
.args(self.args.iter())
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::inherit())
.stderr(std::process::Stdio::inherit())
.detach()?;
log::trace!("Spawned the command");

Ok(())
}
}

impl Action for ShellCommandAction {
fn execute(&mut self) -> Result<(), ActionError> {
log::debug!("Execute command {:?}", self.command);

std::process::Command::new("/bin/sh")
.arg("-c")
.arg(&self.command)
.stdout(std::process::Stdio::inherit())
.stderr(std::process::Stdio::inherit())
.detach()?;
log::trace!("Spawned the command");

Ok(())
}
}

/// Extension to be able to detach child processes without creating zombies
trait DetachExt {
fn detach(&mut self) -> std::io::Result<()>;
}
impl DetachExt for std::process::Command {
fn detach(&mut self) -> std::io::Result<()> {
// Safety: usual daemonization stuff. Parent exits immediately before
// exec, child goes on to exec what it wants
use nix::unistd::ForkResult;
unsafe {
self.pre_exec(|| {
match nix::unistd::fork().unwrap() {
ForkResult::Parent { child: _ } => std::process::exit(0),
ForkResult::Child => (),
}
Ok(())
})
}
.status()
.map(|_| ())
}
}

impl From<std::io::Error> for ActionError {
fn from(err: std::io::Error) -> ActionError {
ActionError(format!("{}", err))
}
}