55 lines
1.6 KiB
Rust
55 lines
1.6 KiB
Rust
//! One noninteractive SSH command with host-mediated authentication.
|
|
use clap::Parser;
|
|
use std::{
|
|
io::{self, Read, Write},
|
|
time::{Duration, Instant},
|
|
};
|
|
#[derive(Parser)]
|
|
struct Args {
|
|
#[arg(short = 'p', default_value_t = 22)]
|
|
port: u16,
|
|
#[arg(short = 'l')]
|
|
user: Option<String>,
|
|
#[arg(short = 'o')]
|
|
options: Vec<String>,
|
|
host: String,
|
|
#[arg(required = true, trailing_var_arg = true)]
|
|
command: Vec<String>,
|
|
}
|
|
fn run(args: Args) -> io::Result<u32> {
|
|
let mut accept_new = false;
|
|
for option in args.options {
|
|
match option.as_str() {
|
|
"StrictHostKeyChecking=accept-new" => accept_new = true,
|
|
"StrictHostKeyChecking=yes" => accept_new = false,
|
|
_ => return Err(io::Error::other("unsupported SSH option")),
|
|
}
|
|
}
|
|
let (user, host) = match args.host.split_once('@') {
|
|
Some((user, host)) => (Some(user), host),
|
|
None => (args.user.as_deref(), args.host.as_str()),
|
|
};
|
|
let session = sausage_ssh::identity::connect(host, args.port, user, accept_new)?;
|
|
let mut input = Vec::new();
|
|
io::stdin().read_to_end(&mut input)?;
|
|
let output = session.execute_input(
|
|
args.command.join(" ").as_bytes(),
|
|
&input,
|
|
usize::MAX,
|
|
Instant::now() + Duration::from_secs(300),
|
|
)?;
|
|
io::stdout().write_all(&output.stdout)?;
|
|
io::stderr().write_all(&output.stderr)?;
|
|
Ok(output.exit_code.unwrap_or(255))
|
|
}
|
|
fn main() {
|
|
let status = match run(Args::parse()) {
|
|
Ok(status) => status,
|
|
Err(error) => {
|
|
eprintln!("{error}");
|
|
255
|
|
}
|
|
};
|
|
std::process::exit(status.min(255) as i32);
|
|
}
|