allow --remote-exe argument

This commit is contained in:
2026-08-25 09:10:03 -04:00
parent 9fbef46c9a
commit 3fd6ba3bd0
3 changed files with 27 additions and 10 deletions
+4
View File
@@ -28,6 +28,10 @@ pub struct ClientCli {
/// Suffix identifying a still-growing file. /// Suffix identifying a still-growing file.
#[arg(long, default_value = "partial")] #[arg(long, default_value = "partial")]
pub extension: String, pub extension: String,
/// Path to the scpcap executable on the remote host, e.g. `~/bin/scpcap`.
#[arg(long, default_value = "scpcap")]
pub remote_exe: String,
} }
/// Remote helper mode, ssh-spawned by the client (like `rsync --server`). /// Remote helper mode, ssh-spawned by the client (like `rsync --server`).
+2 -2
View File
@@ -61,7 +61,7 @@ pub fn run(cli: ClientCli) -> Result<()> {
"--dest-temp".to_string(), "--dest-temp".to_string(),
dest.temp_path.clone(), dest.temp_path.clone(),
]; ];
let remote_cmd = build_server_command(&server_args); let remote_cmd = build_server_command(&cli.remote_exe, &server_args);
let mut child = spawn_remote_server(host, &remote_cmd)?; let mut child = spawn_remote_server(host, &remote_cmd)?;
let stdin = child.stdin.take().expect("piped stdin"); let stdin = child.stdin.take().expect("piped stdin");
@@ -103,7 +103,7 @@ pub fn run(cli: ClientCli) -> Result<()> {
server_args.push("--compress".to_string()); server_args.push("--compress".to_string());
server_args.push("zstd".to_string()); server_args.push("zstd".to_string());
} }
let remote_cmd = build_server_command(&server_args); let remote_cmd = build_server_command(&cli.remote_exe, &server_args);
let mut child = spawn_remote_server(host, &remote_cmd)?; let mut child = spawn_remote_server(host, &remote_cmd)?;
let stdout = child.stdout.take().expect("piped stdout"); let stdout = child.stdout.take().expect("piped stdout");
+18 -5
View File
@@ -4,9 +4,13 @@ use std::process::{Child, Command, Stdio};
/// Builds the argv for the remote `scpcap --server` invocation, run as a /// Builds the argv for the remote `scpcap --server` invocation, run as a
/// single ssh remote-command argument (so it goes through the remote shell, /// single ssh remote-command argument (so it goes through the remote shell,
/// same as rsync's `ssh host rsync --server ...`). /// same as rsync's `ssh host rsync --server ...`). `remote_exe` is the path
pub fn build_server_command(args: &[String]) -> String { /// (or bare name, resolved via remote `PATH`) to the scpcap executable on
let mut parts = vec!["scpcap".to_string(), "--server".to_string()]; /// the remote host, e.g. `~/bin/scpcap`. Like rsync's `--rsync-path`, it's
/// passed through unquoted so `~` and `$HOME`-style remote shell expansions
/// work; it's a trusted, locally-supplied flag, not remote-controlled data.
pub fn build_server_command(remote_exe: &str, args: &[String]) -> String {
let mut parts = vec![remote_exe.to_string(), "--server".to_string()];
parts.extend(args.iter().map(|a| shell_quote(a))); parts.extend(args.iter().map(|a| shell_quote(a)));
parts.join(" ") parts.join(" ")
} }
@@ -31,14 +35,23 @@ mod tests {
#[test] #[test]
fn builds_quoted_command() { fn builds_quoted_command() {
let cmd = build_server_command(&[ let cmd = build_server_command(
"scpcap",
&[
"--recv".to_string(), "--recv".to_string(),
"--dest-final".to_string(), "--dest-final".to_string(),
"/a b/c.pcap".to_string(), "/a b/c.pcap".to_string(),
]); ],
);
assert_eq!( assert_eq!(
cmd, cmd,
"scpcap --server '--recv' '--dest-final' '/a b/c.pcap'" "scpcap --server '--recv' '--dest-final' '/a b/c.pcap'"
); );
} }
#[test]
fn builds_command_with_custom_remote_exe() {
let cmd = build_server_command("~/bin/scpcap", &["--recv".to_string()]);
assert_eq!(cmd, "~/bin/scpcap --server '--recv'");
}
} }