From 0f19a43339b67676ede9c1a1b819c7ceab3dcaea Mon Sep 17 00:00:00 2001 From: Jesse Rosenstock Date: Tue, 28 Apr 2026 13:34:44 +0200 Subject: [PATCH] Add --list flag to multicall binary Add a --list option that prints all registered utility names, one per line. This matches the existing convention in uutils/coreutils and enables scripts to dynamically discover available utilities without hardcoding lists. Update the usage text to document the new flag. --- src/bin/util-linux.rs | 10 +++++++++- tests/tests.rs | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/bin/util-linux.rs b/src/bin/util-linux.rs index 6a942ee8..6974b880 100644 --- a/src/bin/util-linux.rs +++ b/src/bin/util-linux.rs @@ -21,7 +21,10 @@ include!(concat!(env!("OUT_DIR"), "/uutils_map.rs")); fn usage(utils: &UtilityMap, name: &str) { println!("{name} {VERSION} (multi-call binary)\n"); - println!("Usage: {name} [function [arguments...]]\n"); + println!("Usage: {name} [function [arguments...]]"); + println!(" {name} --list\n"); + println!("Options:"); + println!(" --list lists all defined functions, one per row\n"); println!("Currently defined functions:\n"); #[allow(clippy::map_clone)] let mut utils: Vec<&str> = utils.keys().map(|&s| s).collect(); @@ -123,6 +126,11 @@ fn main() { } usage(&utils, binary_as_util); process::exit(0); + } else if util == "--list" { + for util_name in utils.keys() { + println!("{util_name}"); + } + process::exit(0); } else { not_found(&util_os); } diff --git a/tests/tests.rs b/tests/tests.rs index 8f94a09a..a1d8ccee 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -90,3 +90,20 @@ mod test_mcookie; #[cfg(feature = "uuidgen")] #[path = "by-util/test_uuidgen.rs"] mod test_uuidgen; + +#[test] +fn test_list() { + let out = std::process::Command::new(TESTS_BINARY) + .arg("--list") + .output() + .unwrap(); + assert!(out.status.success()); + let stdout = String::from_utf8(out.stdout).unwrap(); + let lines: Vec<&str> = stdout.lines().collect(); + assert!(!lines.is_empty()); + // Can be replaced with lines.is_sorted() starting with Rust 1.82. + assert!(lines.windows(2).all(|w| w[0] <= w[1])); + // Spot-check a few utilities that should always be present. + assert!(lines.contains(&"rev")); + assert!(lines.contains(&"dmesg")); +}