Skip to content

Commit 029bd90

Browse files
committed
ls: fix the GNU test tests/ls/selinux.sh
1 parent 56ce0e2 commit 029bd90

File tree

3 files changed

+116
-9
lines changed

3 files changed

+116
-9
lines changed

src/uu/ls/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,4 @@ name = "ls"
5252
path = "src/main.rs"
5353

5454
[features]
55-
feat_selinux = ["selinux"]
55+
feat_selinux = ["selinux", "uucore/selinux"]

src/uu/ls/src/ls.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,11 +1900,7 @@ impl PathData {
19001900
None => OnceCell::new(),
19011901
};
19021902

1903-
let security_context = if config.context {
1904-
get_security_context(config, &p_buf, must_dereference)
1905-
} else {
1906-
String::new()
1907-
};
1903+
let security_context = get_security_context(config, &p_buf, must_dereference);
19081904

19091905
Self {
19101906
md: OnceCell::new(),
@@ -3339,7 +3335,10 @@ fn get_security_context(config: &Config, p_buf: &Path, must_dereference: bool) -
33393335
Err(err) => {
33403336
// The Path couldn't be dereferenced, so return early and set exit code 1
33413337
// to indicate a minor error
3342-
show!(LsError::IOErrorContext(p_buf.to_path_buf(), err, false));
3338+
// Only show error when context display is requested to avoid duplicate messages
3339+
if config.context {
3340+
show!(LsError::IOErrorContext(p_buf.to_path_buf(), err, false));
3341+
}
33433342
return substitute_string;
33443343
}
33453344
Ok(_md) => (),

tests/by-util/test_ls.rs

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4263,8 +4263,7 @@ fn test_ls_context_long() {
42634263
let line: Vec<_> = result.stdout_str().split(' ').collect();
42644264
assert!(line[0].ends_with('.'));
42654265
assert!(line[4].starts_with("unconfined_u"));
4266-
let s: Vec<_> = line[4].split(':').collect();
4267-
assert!(s.len() == 4);
4266+
validate_selinux_context(line[4]);
42684267
}
42694268
}
42704269

@@ -4298,6 +4297,115 @@ fn test_ls_context_format() {
42984297
}
42994298
}
43004299

4300+
/// Helper function to validate `SELinux` context format
4301+
/// Returns the context parts if valid, panics with descriptive message if invalid
4302+
#[cfg(feature = "feat_selinux")]
4303+
fn validate_selinux_context(context: &str) {
4304+
assert!(
4305+
context.contains(':'),
4306+
"Expected SELinux context format (user:role:type:level), got: {}",
4307+
context
4308+
);
4309+
4310+
let context_parts: Vec<&str> = context.split(':').collect();
4311+
assert_eq!(
4312+
context_parts.len(),
4313+
4,
4314+
"SELinux context should have 4 components separated by colons, got: {}",
4315+
context
4316+
);
4317+
}
4318+
4319+
#[test]
4320+
#[cfg(feature = "feat_selinux")]
4321+
fn test_ls_selinux_context_format() {
4322+
if !uucore::selinux::is_selinux_enabled() {
4323+
println!("test skipped: Kernel has no support for SElinux context");
4324+
return;
4325+
}
4326+
4327+
let scene = TestScenario::new(util_name!());
4328+
let at = &scene.fixtures;
4329+
4330+
at.touch("file");
4331+
at.symlink_file("file", "link");
4332+
4333+
// Test that ls -lnZ properly shows the context
4334+
for file in ["file", "link"] {
4335+
let result = scene.ucmd().args(&["-lnZ", file]).succeeds();
4336+
let output = result.stdout_str();
4337+
4338+
let lines: Vec<&str> = output.lines().collect();
4339+
assert!(!lines.is_empty(), "Output should contain at least one line");
4340+
4341+
let first_line = lines[0];
4342+
let parts: Vec<&str> = first_line.split_whitespace().collect();
4343+
assert!(parts.len() >= 6, "Line should have at least 6 fields");
4344+
4345+
// The 5th field (0-indexed position 4) should contain the SELinux context
4346+
// Format: permissions links owner group context size date time name
4347+
let context = parts[4];
4348+
validate_selinux_context(context);
4349+
}
4350+
}
4351+
4352+
#[test]
4353+
#[cfg(feature = "feat_selinux")]
4354+
fn test_ls_selinux_context_indicator() {
4355+
if !uucore::selinux::is_selinux_enabled() {
4356+
println!("test skipped: Kernel has no support for SElinux context");
4357+
return;
4358+
}
4359+
4360+
let scene = TestScenario::new(util_name!());
4361+
let at = &scene.fixtures;
4362+
4363+
at.touch("file");
4364+
at.symlink_file("file", "link");
4365+
4366+
// Test that ls -l shows "." indicator for files with SELinux contexts
4367+
for file in ["file", "link"] {
4368+
let result = scene.ucmd().args(&["-l", file]).succeeds();
4369+
let output = result.stdout_str();
4370+
4371+
// The 11th character should be "." indicating SELinux context
4372+
// -rw-rw-r--. (permissions + context indicator)
4373+
let lines: Vec<&str> = output.lines().collect();
4374+
assert!(!lines.is_empty(), "Output should contain at least one line");
4375+
4376+
let first_line = lines[0];
4377+
let chars: Vec<char> = first_line.chars().collect();
4378+
assert!(
4379+
chars.len() >= 11,
4380+
"Line should be at least 11 characters long"
4381+
);
4382+
4383+
// The 11th character (0-indexed position 10) should be "." for SELinux context
4384+
assert_eq!(
4385+
chars[10], '.',
4386+
"Expected '.' indicator for SELinux context in position 11, got '{}' in line: {}",
4387+
chars[10], first_line
4388+
);
4389+
}
4390+
4391+
// Test that ls -lnZ properly shows the context
4392+
for file in ["file", "link"] {
4393+
let result = scene.ucmd().args(&["-lnZ", file]).succeeds();
4394+
let output = result.stdout_str();
4395+
4396+
let lines: Vec<&str> = output.lines().collect();
4397+
assert!(!lines.is_empty(), "Output should contain at least one line");
4398+
4399+
let first_line = lines[0];
4400+
let parts: Vec<&str> = first_line.split_whitespace().collect();
4401+
assert!(parts.len() >= 6, "Line should have at least 6 fields");
4402+
4403+
// The 5th field (0-indexed position 4) should contain the SELinux context
4404+
// Format: permissions links owner group context size date time name
4405+
validate_selinux_context(parts[4]);
4406+
}
4407+
}
4408+
43014409
#[test]
43024410
#[allow(non_snake_case)]
43034411
fn test_ls_a_A() {

0 commit comments

Comments
 (0)