use crate::ErrorWithHint;
use log::debug;
use std::io::ErrorKind;
use std::os::unix::prelude::CommandExt;
use std::path::Path;
use std::process::{Command, Output};
use std::{env, io};
pub fn sd_booted() -> bool {
Path::new("/run/systemd/system").exists()
}
pub fn have_command<P: AsRef<Path>>(exe_name: P) -> bool {
env::var_os("PATH").map_or(false, |paths| {
env::split_paths(&paths).any(|dir| dir.join(&exe_name).is_file())
})
}
fn report_command_error(err: io::Error, program: &str, args: &[String]) -> ErrorWithHint {
ErrorWithHint::new(
format!("Failed to run {}: {}", program, err),
if err.kind() == ErrorKind::NotFound {
format!("Try installing package that contains command '{}'", program)
} else {
format!("Complete command: {} {}", program, shell_words::join(args))
},
)
}
pub fn exec_command(program: &str, args: &[String]) -> Result<(), ErrorWithHint> {
debug!("Executing: {} {}", program, shell_words::join(args));
let err: io::Error = Command::new(program).args(args).exec();
Err(report_command_error(err, program, args))
}
pub fn run_command(program: &str, args: &[String]) -> Result<Output, ErrorWithHint> {
debug!("Running: {} {}", program, shell_words::join(args));
let ret = Command::new(program)
.args(args)
.output()
.map_err(|err| report_command_error(err, program, args))?;
if !ret.status.success() {
return Err(ErrorWithHint::new(
format!(
"{} returned {}:\n{}",
program,
ret.status.code().unwrap_or(999),
String::from_utf8_lossy(&ret.stderr).trim()
),
format!("Complete command: {} {}", program, shell_words::join(args)),
));
}
Ok(ret)
}