Skip to content

Commit d9c72dc

Browse files
committed
install -C: also the manage the ignore case
1 parent bdcd2ef commit d9c72dc

File tree

4 files changed

+98
-9
lines changed

4 files changed

+98
-9
lines changed

src/uu/install/locales/en-US.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ install-error-missing-file-operand = missing file operand
4848
install-error-missing-destination-operand = missing destination file operand after '{ $path }'
4949
install-error-failed-to-remove = Failed to remove existing file { $path }. Error: { $error }
5050
51+
# Warning messages
52+
install-warning-compare-ignored = the --compare (-C) option is ignored when you specify a mode with non-permission bits
53+
5154
# Verbose output
5255
install-verbose-creating-directory = creating directory { $path }
5356
install-verbose-creating-directory-step = install: creating directory { $path }

src/uu/install/locales/fr-FR.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ install-error-missing-file-operand = opérande de fichier manquant
4848
install-error-missing-destination-operand = opérande de fichier de destination manquant après '{ $path }'
4949
install-error-failed-to-remove = Échec de la suppression du fichier existant { $path }. Erreur : { $error }
5050
51+
# Messages d'avertissement
52+
install-warning-compare-ignored = l'option --compare (-C) est ignorée quand un mode est indiqué avec des bits non liés à des droits
53+
5154
# Sortie détaillée
5255
install-verbose-creating-directory = création du répertoire { $path }
5356
install-verbose-creating-directory-step = install : création du répertoire { $path }

src/uu/install/src/install.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,15 @@ fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
365365
return Err(1.into());
366366
}
367367

368+
// Check if compare is used with non-permission mode bits
369+
if compare && specified_mode.is_some() {
370+
let mode = specified_mode.unwrap();
371+
let non_permission_bits = 0o7000; // setuid, setgid, sticky bits
372+
if mode & non_permission_bits != 0 {
373+
show_error!("{}", get_message("install-warning-compare-ignored"));
374+
}
375+
}
376+
368377
let owner = matches
369378
.get_one::<String>(OPT_OWNER)
370379
.map(|s| s.as_str())

tests/by-util/test_install.rs

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,9 @@ fn test_install_copy_then_compare_file_with_extra_mode() {
643643
.arg("-m")
644644
.arg("1644")
645645
.succeeds()
646-
.no_stderr();
646+
.stderr_contains(
647+
"the --compare (-C) option is ignored when you specify a mode with non-permission bits",
648+
);
647649

648650
file2_meta = at.metadata(file2);
649651
let after_install_sticky = FileTime::from_last_modification_time(&file2_meta);
@@ -2222,20 +2224,37 @@ fn test_selinux() {
22222224

22232225
let args = ["-Z", "--context=unconfined_u:object_r:user_tmp_t:s0"];
22242226
for arg in args {
2225-
new_ucmd!()
2227+
let result = new_ucmd!()
22262228
.arg(arg)
22272229
.arg("-v")
22282230
.arg(at.plus_as_string(src))
22292231
.arg(at.plus_as_string(dest))
2230-
.succeeds()
2231-
.stdout_contains("orig' -> '");
2232+
.run();
2233+
2234+
// Skip test if SELinux is not enabled
2235+
if result
2236+
.stderr_str()
2237+
.contains("SELinux is not enabled on this system")
2238+
{
2239+
println!("Skipping SELinux test: SELinux is not enabled");
2240+
at.remove(&at.plus_as_string(dest));
2241+
continue;
2242+
}
2243+
2244+
result.success().stdout_contains("orig' -> '");
22322245

22332246
let getfattr_output = Command::new("getfattr")
22342247
.arg(at.plus_as_string(dest))
22352248
.arg("-n")
22362249
.arg("security.selinux")
2237-
.output()
2238-
.expect("Failed to run `getfattr` on the destination file");
2250+
.output();
2251+
2252+
// Skip test if getfattr is not available
2253+
let Ok(getfattr_output) = getfattr_output else {
2254+
println!("Skipping SELinux test: getfattr not available");
2255+
at.remove(&at.plus_as_string(dest));
2256+
continue;
2257+
};
22392258
println!("{:?}", getfattr_output);
22402259
assert!(
22412260
getfattr_output.status.success(),
@@ -2267,14 +2286,69 @@ fn test_selinux_invalid_args() {
22672286
"--context=nconfined_u:object_r:user_tmp_t:s0",
22682287
];
22692288
for arg in args {
2270-
new_ucmd!()
2289+
let result = new_ucmd!()
22712290
.arg(arg)
22722291
.arg("-v")
22732292
.arg(at.plus_as_string(src))
22742293
.arg(at.plus_as_string(dest))
2275-
.fails()
2276-
.stderr_contains("failed to set default file creation");
2294+
.fails();
2295+
2296+
let stderr = result.stderr_str();
2297+
assert!(
2298+
stderr.contains("failed to set default file creation")
2299+
|| stderr.contains("SELinux is not enabled on this system"),
2300+
"Expected stderr to contain either 'failed to set default file creation' or 'SELinux is not enabled on this system', but got: '{}'",
2301+
stderr
2302+
);
22772303

22782304
at.remove(&at.plus_as_string(dest));
22792305
}
22802306
}
2307+
2308+
#[test]
2309+
#[cfg(not(any(target_os = "openbsd", target_os = "freebsd")))]
2310+
fn test_install_compare_with_mode_bits() {
2311+
let test_cases = [
2312+
("4755", "setuid bit", true),
2313+
("2755", "setgid bit", true),
2314+
("1755", "sticky bit", true),
2315+
("7755", "setuid + setgid + sticky bits", true),
2316+
("755", "permission-only mode", false),
2317+
];
2318+
2319+
for (mode, description, should_warn) in test_cases {
2320+
let scene = TestScenario::new(util_name!());
2321+
let at = &scene.fixtures;
2322+
let source = format!("source_file_{}", mode);
2323+
let dest = format!("dest_file_{}", mode);
2324+
2325+
at.write(&source, "test content");
2326+
2327+
let mode_arg = format!("--mode={}", mode);
2328+
2329+
if should_warn {
2330+
scene.ucmd().args(&["-C", &mode_arg, &source, &dest])
2331+
.succeeds()
2332+
.stderr_contains("the --compare (-C) option is ignored when you specify a mode with non-permission bits");
2333+
} else {
2334+
scene
2335+
.ucmd()
2336+
.args(&["-C", &mode_arg, &source, &dest])
2337+
.succeeds()
2338+
.no_stderr();
2339+
2340+
// Test second install should be no-op due to -C
2341+
scene
2342+
.ucmd()
2343+
.args(&["-C", &mode_arg, &source, &dest])
2344+
.succeeds()
2345+
.no_stderr();
2346+
}
2347+
2348+
assert!(
2349+
at.file_exists(&dest),
2350+
"Failed to create dest file for {}",
2351+
description
2352+
);
2353+
}
2354+
}

0 commit comments

Comments
 (0)