From 37dd6d09102bdb77584449d85daec2e96fef7d64 Mon Sep 17 00:00:00 2001 From: Tom Forbes Date: Mon, 16 Dec 2024 18:24:09 +0000 Subject: [PATCH] Support generic ping arguments. Closes #491 and #393 --- gping.1 | 13 ++++--- gping/src/main.rs | 87 +++++++++++++++++++++------------------------ pinger/src/bsd.rs | 3 ++ pinger/src/lib.rs | 15 ++++++++ pinger/src/linux.rs | 10 +++++- pinger/src/macos.rs | 4 +++ 6 files changed, 79 insertions(+), 53 deletions(-) diff --git a/gping.1 b/gping.1 index 9329e0a4c..c5ecba5f2 100644 --- a/gping.1 +++ b/gping.1 @@ -4,7 +4,7 @@ .SH NAME gping \- Ping, but with a graph. .SH SYNOPSIS -\fBgping\fR [\fB\-\-cmd\fR] [\fB\-n\fR|\fB\-\-watch\-interval\fR] [\fB\-b\fR|\fB\-\-buffer\fR] [\fB\-4 \fR] [\fB\-6 \fR] [\fB\-i\fR|\fB\-\-interface\fR] [\fB\-s\fR|\fB\-\-simple\-graphics\fR] [\fB\-\-vertical\-margin\fR] [\fB\-\-horizontal\-margin\fR] [\fB\-c\fR|\fB\-\-color\fR] [\fB\-\-clear\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fIHOSTS_OR_COMMANDS\fR] +\fBgping\fR [\fB\-\-cmd\fR] [\fB\-n\fR|\fB\-\-watch\-interval\fR] [\fB\-b\fR|\fB\-\-buffer\fR] [\fB\-4 \fR] [\fB\-6 \fR] [\fB\-i\fR|\fB\-\-interface\fR] [\fB\-s\fR|\fB\-\-simple\-graphics\fR] [\fB\-\-vertical\-margin\fR] [\fB\-\-horizontal\-margin\fR] [\fB\-c\fR|\fB\-\-color\fR] [\fB\-\-clear\fR] [\fB\-\-ping\-args\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fIHOSTS_OR_COMMANDS\fR] .SH DESCRIPTION Ping, but with a graph. .SH OPTIONS @@ -13,10 +13,10 @@ Ping, but with a graph. Graph the execution time for a list of commands rather than pinging hosts .TP \fB\-n\fR, \fB\-\-watch\-interval\fR=\fIWATCH_INTERVAL\fR -Watch interval seconds (provide partial seconds like \*(Aq0.5\*(Aq). Default for ping is 0.2, default for cmd is 0.5. +Watch interval seconds (provide partial seconds like \*(Aq0.5\*(Aq). Default for ping is 0.2, default for cmd is 0.5 .TP \fB\-b\fR, \fB\-\-buffer\fR=\fIBUFFER\fR [default: 30] -Determines the number of seconds to display in the graph. +Determines the number of seconds to display in the graph .TP \fB\-4\fR Resolve ping targets to IPv4 address @@ -28,7 +28,7 @@ Resolve ping targets to IPv6 address Interface to use when pinging .TP \fB\-s\fR, \fB\-\-simple\-graphics\fR -Uses dot characters instead of braille + .TP \fB\-\-vertical\-margin\fR=\fIVERTICAL_MARGIN\fR [default: 1] Vertical margin around the graph (top and bottom) @@ -51,10 +51,13 @@ following color names: \*(Aqblack\*(Aq, \*(Aqred\*(Aq, \*(Aqgreen\*(Aq, \*(Aqyel \fB\-\-clear\fR Clear the graph from the terminal after closing the program .TP +\fB\-\-ping\-args\fR=\fIPING_ARGS\fR +Extra arguments to pass to `ping`. These are platform dependent +.TP \fB\-h\fR, \fB\-\-help\fR Print help .TP [\fIHOSTS_OR_COMMANDS\fR] -Hosts or IPs to ping, or commands to run if \-\-cmd is provided. Can use cloud shorthands like aws:eu\-west\-1. +Hosts or IPs to ping, or commands to run if \-\-cmd is provided. Can use cloud shorthands like aws:eu\-west\-1 .SH AUTHORS Tom Forbes diff --git a/gping/src/main.rs b/gping/src/main.rs index 72441c099..3cdceb5a4 100644 --- a/gping/src/main.rs +++ b/gping/src/main.rs @@ -55,29 +55,23 @@ build_env: {},{}"#, ); #[derive(Parser, Debug)] -#[command(author, version=build::PKG_VERSION, name = "gping", about = "Ping, but with a graph.", long_version = VERSION_INFO)] +#[command(author, version=build::PKG_VERSION, name = "gping", about = "Ping, but with a graph.", long_version = VERSION_INFO +)] struct Args { - #[arg( - long, - help = "Graph the execution time for a list of commands rather than pinging hosts" - )] + /// Graph the execution time for a list of commands rather than pinging hosts + #[arg(long)] cmd: bool, - #[arg( - short = 'n', - long, - help = "Watch interval seconds (provide partial seconds like '0.5'). Default for ping is 0.2, default for cmd is 0.5." - )] + + /// Watch interval seconds (provide partial seconds like '0.5'). Default for ping is 0.2, default for cmd is 0.5. + #[arg(short = 'n', long)] watch_interval: Option, - #[arg( - help = "Hosts or IPs to ping, or commands to run if --cmd is provided. Can use cloud shorthands like aws:eu-west-1." - )] + + /// Hosts or IPs to ping, or commands to run if --cmd is provided. Can use cloud shorthands like aws:eu-west-1. + #[arg(allow_hyphen_values = false)] hosts_or_commands: Vec, - #[arg( - short, - long, - default_value = "30", - help = "Determines the number of seconds to display in the graph." - )] + + /// Determines the number of seconds to display in the graph. + #[arg(short, long, default_value = "30")] buffer: u64, /// Resolve ping targets to IPv4 address #[arg(short = '4', conflicts_with = "ipv6")] @@ -88,20 +82,19 @@ struct Args { /// Interface to use when pinging. #[arg(short = 'i', long)] interface: Option, - #[arg(short = 's', long, help = "Uses dot characters instead of braille")] + + /// Uses dot characters instead of braille + #[arg(short = 's', long, help = "")] simple_graphics: bool, - #[arg( - long, - help = "Vertical margin around the graph (top and bottom)", - default_value = "1" - )] + + /// Vertical margin around the graph (top and bottom) + #[arg(long, default_value = "1")] vertical_margin: u16, - #[arg( - long, - help = "Horizontal margin around the graph (left and right)", - default_value = "0" - )] + + /// Horizontal margin around the graph (left and right) + #[arg(long, default_value = "0")] horizontal_margin: u16, + #[arg( name = "color", short = 'c', @@ -120,15 +113,14 @@ following color names: 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'light-blue', 'light-magenta', 'light-cyan', and 'white'"# )] color_codes_or_names: Vec, - #[arg( - name = "clear", - long = "clear", - help = "\ - Clear the graph from the terminal after closing the program\ - ", - action - )] + + /// Clear the graph from the terminal after closing the program + #[arg(name = "clear", long = "clear", action)] clear: bool, + + /// Extra arguments to pass to `ping`. These are platform dependent. + #[arg(long, allow_hyphen_values = true, num_args = 0.., conflicts_with="cmd")] + ping_args: Option>, } struct App { @@ -302,17 +294,13 @@ fn start_cmd_thread( } fn start_ping_thread( - host: String, + options: PingOptions, host_id: usize, - watch_interval: Option, ping_tx: Sender, kill_event: Arc, - interface: Option, ) -> Result>> { - let interval = Duration::from_millis((watch_interval.unwrap_or(0.2) * 1000.0) as u64); + let stream = ping(options)?; // Pump ping messages into the queue - let ping_opts = PingOptions::new(host, interval, interface); - let stream = ping(ping_opts)?; Ok(thread::spawn(move || -> Result<()> { while !kill_event.load(Ordering::Acquire) { match stream.recv() { @@ -419,13 +407,18 @@ fn main() -> Result<()> { ); threads.push(cmd_thread); } else { + let interval = + Duration::from_millis((args.watch_interval.unwrap_or(0.2) * 1000.0) as u64); + let mut ping_opts = PingOptions::new(host_or_cmd, interval, args.interface.clone()); + if let Some(ping_args) = &args.ping_args { + ping_opts = ping_opts.with_raw_arguments(ping_args.clone()); + } + threads.push(start_ping_thread( - host_or_cmd, + ping_opts, host_id, - args.watch_interval, key_tx.clone(), std::sync::Arc::clone(&killed), - args.interface.clone(), )?); } } diff --git a/pinger/src/bsd.rs b/pinger/src/bsd.rs index 41f99b93e..724070991 100644 --- a/pinger/src/bsd.rs +++ b/pinger/src/bsd.rs @@ -38,6 +38,9 @@ impl Pinger for BSDPinger { args.push("-I".into()); args.push(interface.clone()); } + if let Some(raw_args) = &self.options.raw_arguments { + args.extend(raw_args.iter().cloned()); + } args.push(self.options.target.to_string()); ("ping", args) } diff --git a/pinger/src/lib.rs b/pinger/src/lib.rs index 04397fd57..be377e14d 100644 --- a/pinger/src/lib.rs +++ b/pinger/src/lib.rs @@ -45,6 +45,19 @@ pub struct PingOptions { pub target: Target, pub interval: Duration, pub interface: Option, + pub raw_arguments: Option>, +} + +impl PingOptions { + pub fn with_raw_arguments(mut self, raw_arguments: Vec) -> Self { + self.raw_arguments = Some( + raw_arguments + .into_iter() + .map(|item| item.to_string()) + .collect(), + ); + self + } } impl PingOptions { @@ -53,6 +66,7 @@ impl PingOptions { target, interval, interface, + raw_arguments: None, } } pub fn new(target: impl ToString, interval: Duration, interface: Option) -> Self { @@ -116,6 +130,7 @@ pub trait Pinger: Send + Sync { fn start(&self) -> Result, PingCreationError> { let (tx, rx) = mpsc::channel(); let (cmd, args) = self.ping_args(); + let mut child = run_ping(cmd, args)?; let stdout = child.stdout.take().expect("child did not have a stdout"); diff --git a/pinger/src/linux.rs b/pinger/src/linux.rs index 1640337b6..9d18519b2 100644 --- a/pinger/src/linux.rs +++ b/pinger/src/linux.rs @@ -70,11 +70,15 @@ impl Pinger for LinuxPinger { "ping" }; - let args = vec![ + let mut args = vec![ options.target.to_string(), format!("-i{:.1}", options.interval.as_millis() as f32 / 1_000_f32), ]; + if let Some(raw_args) = &options.raw_arguments { + args.extend(raw_args.iter().cloned()); + } + (cmd, args) } LinuxPinger::IPTools(options) => { @@ -94,6 +98,10 @@ impl Pinger for LinuxPinger { args.push("-I".into()); args.push(interface.clone()); } + if let Some(raw_args) = &options.raw_arguments { + args.extend(raw_args.iter().cloned()); + } + args.push(options.target.to_string()); (cmd, args) } diff --git a/pinger/src/macos.rs b/pinger/src/macos.rs index 1ff57aeed..c12128111 100644 --- a/pinger/src/macos.rs +++ b/pinger/src/macos.rs @@ -38,6 +38,10 @@ impl Pinger for MacOSPinger { args.push(interface.clone()); } + if let Some(raw_args) = &self.options.raw_arguments { + args.extend(raw_args.iter().cloned()); + } + (cmd, args) } }