From 35cc9ee0369ee5d314d8b543cc5981a2ddaf64b2 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sun, 21 Dec 2025 13:36:05 +0100 Subject: [PATCH] feat(client): add --port option to specify server port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow users to override the default TFTP port (69) when connecting to servers running on non-standard ports. The port can be specified via -p or --port flag. Examples: tftp -p 6969 get 192.168.1.1 config.txt tftp --port 1069 put myserver firmware.bin If a port is embedded in the host (host:port format), the --port option takes precedence. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- crates/pfs-tftp/src/bin/tftp.rs | 42 ++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/crates/pfs-tftp/src/bin/tftp.rs b/crates/pfs-tftp/src/bin/tftp.rs index 729e159..955add2 100644 --- a/crates/pfs-tftp/src/bin/tftp.rs +++ b/crates/pfs-tftp/src/bin/tftp.rs @@ -12,6 +12,7 @@ //! put [REMOTE_FILE] Upload a file //! //! Options: +//! -p, --port Server port (default: 69) //! -m, --mode Transfer mode: octet (default) or netascii //! -v, --verbose Enable verbose output //! -h, --help Print help @@ -23,8 +24,8 @@ //! # Download a file //! tftp get 192.168.1.1 config.txt //! -//! # Download to a specific local file -//! tftp get 192.168.1.1 config.txt local_config.txt +//! # Download from a custom port +//! tftp -p 6969 get 192.168.1.1 config.txt //! //! # Upload a file //! tftp put 192.168.1.1 firmware.bin @@ -48,14 +49,15 @@ fn print_usage(program: &str) { eprintln!(" put [REMOTE_FILE] Upload a file"); eprintln!(); eprintln!("Options:"); + eprintln!(" -p, --port Server port (default: 69)"); eprintln!(" -m, --mode Transfer mode: octet (default) or netascii"); eprintln!(" -v, --verbose Enable verbose output"); eprintln!(" -h, --help Print help"); eprintln!(); eprintln!("Examples:"); eprintln!(" {program} get 192.168.1.1 config.txt"); - eprintln!(" {program} put 192.168.1.1 firmware.bin"); - eprintln!(" {program} -m netascii get 192.168.1.1:69 readme.txt local.txt"); + eprintln!(" {program} -p 6969 get 192.168.1.1 config.txt"); + eprintln!(" {program} -m netascii put 192.168.1.1 readme.txt"); } /// Command to execute. @@ -75,6 +77,7 @@ enum Command { /// Parsed command-line arguments. struct Args { command: Command, + port: Option, mode: Mode, verbose: bool, } @@ -84,6 +87,7 @@ fn parse_args() -> Result { let args: Vec = env::args().collect(); let program = &args[0]; + let mut port: Option = None; let mut mode = Mode::Octet; let mut verbose = false; @@ -96,6 +100,17 @@ fn parse_args() -> Result { print_usage(program); std::process::exit(0); } + "-p" | "--port" => { + i += 1; + if i >= args.len() { + return Err("--port requires an argument".to_string()); + } + port = Some( + args[i] + .parse() + .map_err(|_| format!("invalid port: {}", args[i]))?, + ); + } "-m" | "--mode" => { i += 1; if i >= args.len() { @@ -172,14 +187,23 @@ fn parse_args() -> Result { Ok(Args { command, + port, mode, verbose, }) } -/// Format host for connection (add default port if needed). -fn format_host(host: &str) -> String { - if host.contains(':') { +/// Format host for connection. +/// +/// If a port override is provided, it is used. Otherwise, if the host already +/// contains a port (has ':'), it is used as-is. Otherwise, the default TFTP +/// port 69 is appended. +fn format_host(host: &str, port_override: Option) -> String { + if let Some(port) = port_override { + // Strip any existing port from host and use override + let host_part = host.split(':').next().unwrap_or(host); + format!("{host_part}:{port}") + } else if host.contains(':') { host.to_string() } else { format!("{host}:69") @@ -203,7 +227,7 @@ fn main() -> ExitCode { remote_file, local_file, } => { - let addr = format_host(&host); + let addr = format_host(&host, args.port); if args.verbose { eprintln!("Getting '{remote_file}' from {addr} -> '{local_file}'"); @@ -255,7 +279,7 @@ fn main() -> ExitCode { local_file, remote_file, } => { - let addr = format_host(&host); + let addr = format_host(&host, args.port); if args.verbose { eprintln!("Putting '{local_file}' -> {addr} as '{remote_file}'");