mirror of https://github.com/sharkdp/fd.git
Add option to filter by SELinux context
Filter files by their SELinux security context. The matching uses the given context as a regular expressions for the pattern. Examples: --context unlabeled_t --context ^user_u:object_r:*
This commit is contained in:
parent
42244e5f32
commit
42269cd66e
|
@ -354,6 +354,7 @@ dependencies = [
|
|||
"test-case",
|
||||
"users",
|
||||
"version_check",
|
||||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1219,3 +1220,12 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea263437ca03c1522846a4ddafbca2542d0ad5ed9b784909d4b27b76f62bc34a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
|
|
@ -69,6 +69,7 @@ features = ["nu-ansi-term"]
|
|||
[target.'cfg(unix)'.dependencies]
|
||||
users = "0.11.0"
|
||||
nix = { version = "0.26.2", default-features = false, features = ["signal"] }
|
||||
xattr = "1.0.0"
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "redox")))'.dependencies]
|
||||
libc = "0.2"
|
||||
|
|
|
@ -320,6 +320,7 @@ Options:
|
|||
--changed-within <date|dur> Filter by file modification time (newer than)
|
||||
--changed-before <date|dur> Filter by file modification time (older than)
|
||||
-o, --owner <user:group> Filter by owning user and/or group
|
||||
--context Filter by SELinux context
|
||||
-x, --exec <cmd>... Execute a command for each search result
|
||||
-X, --exec-batch <cmd>... Execute a command with all search results at once
|
||||
-c, --color <when> When to use colors [default: auto] [possible values: auto,
|
||||
|
|
|
@ -334,6 +334,14 @@ Examples:
|
|||
\-\-owner :students
|
||||
\-\-owner "!john:students"
|
||||
.TP
|
||||
.BI "\-\-context " security_context
|
||||
Filter files by their SELinux security context. The matching uses \fIsecurity_context\fR as
|
||||
a regular expressions for the pattern.
|
||||
|
||||
Examples:
|
||||
\-\-context unlabeled_t
|
||||
\-\-context ^user_u:object_r:*
|
||||
.TP
|
||||
.BI "\-\-base\-directory " path
|
||||
Change the current working directory of fd to the provided path. This means that search results will
|
||||
be shown with respect to the given base path. Note that relative paths which are passed to fd via the
|
||||
|
|
15
src/cli.rs
15
src/cli.rs
|
@ -14,6 +14,8 @@ use crate::error::print_error;
|
|||
use crate::exec::CommandSet;
|
||||
use crate::filesystem;
|
||||
#[cfg(unix)]
|
||||
use crate::filter::ContextFilter;
|
||||
#[cfg(unix)]
|
||||
use crate::filter::OwnerFilter;
|
||||
use crate::filter::SizeFilter;
|
||||
|
||||
|
@ -445,6 +447,19 @@ pub struct Opts {
|
|||
)]
|
||||
pub owner: Option<OwnerFilter>,
|
||||
|
||||
/// Filter files by their SELinux context. The matching uses 'security_context' as
|
||||
/// a regular expressions for the pattern.
|
||||
///
|
||||
/// Examples:
|
||||
/// {n} --context unlabeled_t
|
||||
/// {n} --context ^user_u:object_r:*
|
||||
#[cfg(unix)]
|
||||
#[arg(long, value_parser = ContextFilter::from_string, value_name = "security_context",
|
||||
help = "Filter by SELinux context",
|
||||
long_help,
|
||||
)]
|
||||
pub context: Option<ContextFilter>,
|
||||
|
||||
#[command(flatten)]
|
||||
pub exec: Exec,
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ use regex::bytes::RegexSet;
|
|||
use crate::exec::CommandSet;
|
||||
use crate::filetypes::FileTypes;
|
||||
#[cfg(unix)]
|
||||
use crate::filter::ContextFilter;
|
||||
#[cfg(unix)]
|
||||
use crate::filter::OwnerFilter;
|
||||
use crate::filter::{SizeFilter, TimeFilter};
|
||||
|
||||
|
@ -108,6 +110,10 @@ pub struct Config {
|
|||
/// User/group ownership constraint
|
||||
pub owner_constraint: Option<OwnerFilter>,
|
||||
|
||||
#[cfg(unix)]
|
||||
/// SELinux context constraint
|
||||
pub context_constraint: Option<ContextFilter>,
|
||||
|
||||
/// Whether or not to display filesystem errors
|
||||
pub show_filesystem_errors: bool,
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
use anyhow::Result;
|
||||
use regex::{Regex, RegexBuilder};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ContextFilter {
|
||||
regex: Regex,
|
||||
}
|
||||
|
||||
impl ContextFilter {
|
||||
pub fn from_string(input: &str) -> Result<Self> {
|
||||
Ok(ContextFilter {
|
||||
regex: RegexBuilder::new(input).build()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn matches(&self, path: &Path) -> bool {
|
||||
let Some(raw_context) = xattr::get(path, "security.selinux").unwrap_or(None) else { return false };
|
||||
|
||||
let context = String::from_utf8_lossy(&raw_context);
|
||||
|
||||
self.regex.is_match(&context)
|
||||
}
|
||||
}
|
|
@ -1,11 +1,15 @@
|
|||
pub use self::size::SizeFilter;
|
||||
pub use self::time::TimeFilter;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub use self::context::ContextFilter;
|
||||
#[cfg(unix)]
|
||||
pub use self::owner::OwnerFilter;
|
||||
|
||||
mod size;
|
||||
mod time;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod context;
|
||||
#[cfg(unix)]
|
||||
mod owner;
|
||||
|
|
|
@ -303,6 +303,8 @@ fn construct_config(mut opts: Opts, pattern_regexps: &[String]) -> Result<Config
|
|||
time_constraints,
|
||||
#[cfg(unix)]
|
||||
owner_constraint,
|
||||
#[cfg(unix)]
|
||||
context_constraint: opts.context.take(),
|
||||
show_filesystem_errors: opts.show_errors,
|
||||
path_separator,
|
||||
actual_path_separator,
|
||||
|
|
|
@ -491,6 +491,12 @@ fn spawn_senders(
|
|||
return ignore::WalkState::Continue;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(context_constraint) = &config.context_constraint {
|
||||
if !context_constraint.matches(entry_path) {
|
||||
return ignore::WalkState::Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out unwanted sizes if it is a file and we have been given size constraints.
|
||||
|
|
Loading…
Reference in New Issue