From 876924f5d5b6b6c6846d4234326655c06f5aa7f1 Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 5 Apr 2022 14:21:32 +0200 Subject: [PATCH] df: show error if same type is included & excluded Fixes #3302 --- src/uu/df/src/df.rs | 53 ++++++++++++++++++++++++++-------------- tests/by-util/test_df.rs | 15 ++++++++++++ 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index d125e73d0..97f1a2e6e 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -111,6 +111,8 @@ enum OptionsError { /// An error getting the columns to display in the output table. ColumnError(ColumnError), + + FilesystemTypeBothSelectedAndExcluded(Vec), } impl fmt::Display for OptionsError { @@ -126,6 +128,16 @@ impl fmt::Display for OptionsError { "option --output: field {} used more than once", s.quote() ), + Self::FilesystemTypeBothSelectedAndExcluded(types) => { + for t in types { + eprintln!( + "{}: file system type {} both selected and excluded", + uucore::util_name(), + t.quote() + ); + } + Ok(()) + } } } } @@ -133,18 +145,39 @@ impl fmt::Display for OptionsError { impl Options { /// Convert command-line arguments into [`Options`]. fn from(matches: &ArgMatches) -> Result { + let include = matches.values_of_lossy(OPT_TYPE); + let exclude = matches.values_of_lossy(OPT_EXCLUDE_TYPE); + + if let (Some(include), Some(exclude)) = (&include, &exclude) { + if let Some(types) = Self::get_intersected_types(include, exclude) { + return Err(OptionsError::FilesystemTypeBothSelectedAndExcluded(types)); + } + } + Ok(Self { show_local_fs: matches.is_present(OPT_LOCAL), show_all_fs: matches.is_present(OPT_ALL), show_listed_fs: false, block_size: block_size_from_matches(matches) .map_err(|_| OptionsError::InvalidBlockSize)?, - include: matches.values_of_lossy(OPT_TYPE), - exclude: matches.values_of_lossy(OPT_EXCLUDE_TYPE), + include, + exclude, show_total: matches.is_present(OPT_TOTAL), columns: Column::from_matches(matches).map_err(OptionsError::ColumnError)?, }) } + + fn get_intersected_types(include: &[String], exclude: &[String]) -> Option> { + let mut intersected_types = Vec::new(); + + for t in include { + if exclude.contains(t) { + intersected_types.push(t.clone()); + } + } + + (!intersected_types.is_empty()).then(|| intersected_types) + } } /// Whether to display the mount info given the inclusion settings. @@ -708,22 +741,6 @@ mod tests { let m = mount_info("ext4", "/mnt/foo", false, false); assert!(is_included(&m, &opt)); } - - #[test] - fn test_include_and_exclude_match_both() { - // TODO The same filesystem type in both `include` and - // `exclude` should cause an error, but currently does - // not. - let include = Some(vec![String::from("ext4")]); - let exclude = Some(vec![String::from("ext4")]); - let opt = Options { - include, - exclude, - ..Default::default() - }; - let m = mount_info("ext4", "/mnt/foo", false, false); - assert!(!is_included(&m, &opt)); - } } mod filter_mount_list { diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index b0ee8a2b3..fa77a8096 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -95,6 +95,21 @@ fn test_exclude_type_option() { new_ucmd!().args(&["-x", "ext4", "-x", "ext3"]).succeeds(); } +#[test] +fn test_include_exclude_same_type() { + new_ucmd!() + .args(&["-t", "ext4", "-x", "ext4"]) + .fails() + .stderr_is("df: file system type 'ext4' both selected and excluded"); + new_ucmd!() + .args(&["-t", "ext4", "-x", "ext4", "-t", "ext3", "-x", "ext3"]) + .fails() + .stderr_is( + "df: file system type 'ext4' both selected and excluded\n\ + df: file system type 'ext3' both selected and excluded", + ); +} + #[test] fn test_total() { // Example output: