diff --git a/Cargo.toml b/Cargo.toml index e44167877..9371f365a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ feat_selinux = [ "id/selinux", "ls/selinux", "mkdir/selinux", + "stat/selinux", "selinux", "feat_require_selinux", ] diff --git a/src/uu/stat/Cargo.toml b/src/uu/stat/Cargo.toml index 3e59da516..940a3ddbf 100644 --- a/src/uu/stat/Cargo.toml +++ b/src/uu/stat/Cargo.toml @@ -22,6 +22,9 @@ clap = { workspace = true } uucore = { workspace = true, features = ["entries", "libc", "fs", "fsext"] } chrono = { workspace = true } +[features] +selinux = ["uucore/selinux"] + [[bin]] name = "stat" path = "src/main.rs" diff --git a/src/uu/stat/src/stat.rs b/src/uu/stat/src/stat.rs index 6f721cf1d..22d58a9af 100644 --- a/src/uu/stat/src/stat.rs +++ b/src/uu/stat/src/stat.rs @@ -902,7 +902,27 @@ impl Stater { // FIXME: blocksize differs on various platform // See coreutils/gnulib/lib/stat-size.h ST_NBLOCKSIZE // spell-checker:disable-line 'B' => OutputType::Unsigned(512), - + // SELinux security context string + 'C' => { + #[cfg(feature = "selinux")] + { + if uucore::selinux::check_selinux_enabled().is_ok() { + match uucore::selinux::get_selinux_security_context(Path::new(file)) + { + Ok(ctx) => OutputType::Str(ctx), + Err(_) => OutputType::Str( + "failed to get security context".to_string(), + ), + } + } else { + OutputType::Str("unsupported on this system".to_string()) + } + } + #[cfg(not(feature = "selinux"))] + { + OutputType::Str("unsupported for this operating system".to_string()) + } + } // device number in decimal 'd' => OutputType::Unsigned(meta.dev()), // device number in hex diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index 8fbf62906..9587367e8 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -490,3 +490,27 @@ fn test_printf_invalid_directive() { .fails_with_code(1) .stderr_contains("'%9%': invalid directive"); } + +#[test] +#[cfg(feature = "feat_selinux")] +fn test_stat_selinux() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + at.touch("f"); + ts.ucmd() + .arg("--printf='%C'") + .arg("f") + .succeeds() + .no_stderr() + .stdout_contains("unconfined_u"); + ts.ucmd() + .arg("--printf='%C'") + .arg("/bin/") + .succeeds() + .no_stderr() + .stdout_contains("system_u"); + // Count that we have 4 fields + let result = ts.ucmd().arg("--printf='%C'").arg("/bin/").succeeds(); + let s: Vec<_> = result.stdout_str().split(":").collect(); + assert!(s.len() == 4); +}