use std::ffi::OsString;
use std::path::PathBuf;
use std::process::{Command, ExitCode};
const DENY: u8 = 2;
const USAGE: u8 = 64;
fn main() -> ExitCode {
let args: Vec<OsString> = std::env::args_os().skip(1).collect();
let failed = if args.first().is_some_and(|arg| arg == "guard") {
DENY
} else {
USAGE
};
let Some(openmoat) = beside() else {
eprintln!(
"moat: cannot find openmoat next to this moat; reinstall OpenMoat, which installs both"
);
return ExitCode::from(failed);
};
let mut command = Command::new(&openmoat);
command.args(&args);
let error = run(command, failed);
eprintln!("moat: cannot run {}: {error}", openmoat.display());
ExitCode::from(failed)
}
fn beside() -> Option<PathBuf> {
let exe = std::env::current_exe().ok()?;
let name = format!("openmoat{}", std::env::consts::EXE_SUFFIX);
cfg!(unix)
.then(|| std::fs::canonicalize(&exe).ok())
.flatten()
.into_iter()
.chain([exe])
.filter_map(|exe| exe.parent().map(|dir| dir.join(&name)))
.find(|path| path.is_file())
}
#[cfg(unix)]
fn run(mut command: Command, _failed: u8) -> std::io::Error {
use std::os::unix::process::CommandExt as _;
command.exec()
}
#[cfg(not(unix))]
fn run(mut command: Command, failed: u8) -> std::io::Error {
match command.status() {
Ok(status) => {
let code = status
.code()
.and_then(|c| u8::try_from(c).ok())
.unwrap_or(failed);
std::process::exit(i32::from(code))
}
Err(error) => error,
}
}