Skip to content

Commit d04d0cd

Browse files
sylvestrecakebaker
andauthored
ls: fix the GNU test tests/ls/selinux.sh (#8281)
* ls: fix the GNU test tests/ls/selinux.sh * Remove old comment Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> * simpli Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com> --------- Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
1 parent 0923b92 commit d04d0cd

3 files changed

Lines changed: 114 additions & 9 deletions

File tree

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: 108 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,113 @@ fn test_ls_context_format() {
42984297
}
42994298
}
43004299

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

0 commit comments

Comments
 (0)