Repository: uutils/coreutils (language: rust)

Issue:
kill: fails to use only least significant bits to identify signal with -l
Environment: Ubuntu 24.04, uutils `main` branch (git commit 2430e2a396d5f5ae29413081b065a4503245839b), GNU coreutils v9.6.8-fbfd88-dirty

Steps to reproduce:
```
# 143 is 15 + 128, and signal number 15 is SIGTERM.
kill -l 143
```

What happens now: uutils `kill` displays an error message that the signal 143 is unknown:
```
kill: unknown signal name '143'
```

What I expected to happen: GNU `kill` lists the name of the signal `TERM`:
```
TERM
```

Notes: This is causing a failure in the GNU test file `tests/misc/kill.sh`. It seems that only some number of the least significant bits are used to identify the signal.


Discussion / hints:

Fix patch:
diff --git a/src/uu/kill/src/kill.rs b/src/uu/kill/src/kill.rs
index 7638dcc4488..18b45e2eff6 100644
--- a/src/uu/kill/src/kill.rs
+++ b/src/uu/kill/src/kill.rs
@@ -17,6 +17,11 @@ use uucore::{format_usage, help_about, help_usage, show};
 static ABOUT: &str = help_about!("kill.md");
 const USAGE: &str = help_usage!("kill.md");
 
+// When the -l option is selected, the program displays the type of signal related to a certain
+// value or string. In case of a value, the program should control the lower 8 bits, but there is
+// a particular case in which if the value is in range [128, 159], it is translated to a signal
+const OFFSET: usize = 128;
+
 pub mod options {
     pub static PIDS_OR_SIGNALS: &str = "pids_or_signals";
     pub static LIST: &str = "list";
@@ -164,13 +169,24 @@ fn table() {
 }
 
 fn print_signal(signal_name_or_value: &str) -> UResult<()> {
+    // Closure used to track the last 8 bits of the signal value
+    // when the -l option is passed only the lower 8 bits are important
+    // or the value is in range [128, 159]
+    // Example: kill -l 143 => TERM because 143 = 15 + 128
+    // Example: kill -l 2304 => EXIT
+    let lower_8_bits = |x: usize| x & 0xff;
+    let option_num_parse = signal_name_or_value.parse::<usize>().ok();
+
     for (value, &signal) in ALL_SIGNALS.iter().enumerate() {
         if signal.eq_ignore_ascii_case(signal_name_or_value)
             || format!("SIG{signal}").eq_ignore_ascii_case(signal_name_or_value)
         {
             println!("{value}");
             return Ok(());
-        } else if signal_name_or_value == value.to_string() {
+        } else if signal_name_or_value == value.to_string()
+            || option_num_parse.is_some_and(|signal_value| lower_8_bits(signal_value) == value)
+            || option_num_parse.is_some_and(|signal_value| signal_value == value + OFFSET)
+        {
             println!("{signal}");
             return Ok(());
         }
diff --git a/util/why-error.md b/util/why-error.md
index 6c7865e430a..b387bf3310c 100644
--- a/util/why-error.md
+++ b/util/why-error.md
@@ -27,7 +27,6 @@ This file documents why some tests are failing:
 * gnu/tests/ls/stat-free-symlinks.sh
 * gnu/tests/misc/close-stdout.sh
 * gnu/tests/misc/comm.pl
-* gnu/tests/misc/kill.sh - https://github.com/uutils/coreutils/issues/7218
 * gnu/tests/misc/nohup.sh
 * gnu/tests/misc/numfmt.pl - https://github.com/uutils/coreutils/issues/7219 / https://github.com/uutils/coreutils/issues/7221
 * gnu/tests/misc/stdbuf.sh - https://github.com/uutils/coreutils/issues/7072


Test patch:
diff --git a/tests/by-util/test_kill.rs b/tests/by-util/test_kill.rs
index b42e34828f6..0cdfd9aae4f 100644
--- a/tests/by-util/test_kill.rs
+++ b/tests/by-util/test_kill.rs
@@ -334,6 +334,39 @@ fn test_kill_with_signal_and_list() {
         .fails();
 }
 
+#[test]
+fn test_kill_with_list_lower_bits() {
+    new_ucmd!()
+        .arg("-l")
+        .arg("128")
+        .succeeds()
+        .stdout_contains("EXIT");
+
+    new_ucmd!()
+        .arg("-l")
+        .arg("143")
+        .succeeds()
+        .stdout_contains("TERM");
+
+    new_ucmd!()
+        .arg("-l")
+        .arg("256")
+        .succeeds()
+        .stdout_contains("EXIT");
+
+    new_ucmd!()
+        .arg("-l")
+        .arg("2304")
+        .succeeds()
+        .stdout_contains("EXIT");
+}
+
+#[test]
+fn test_kill_with_list_lower_bits_unrecognized() {
+    new_ucmd!().arg("-l").arg("111").fails();
+    new_ucmd!().arg("-l").arg("384").fails();
+}
+
 #[test]
 fn test_kill_with_signal_and_table() {
     let target = Target::new();