chj_unix_util/
signal.rs

1use anyhow::{anyhow, bail, Result};
2use nix::{
3    sys::signal::{kill, Signal},
4    unistd::{getsid, Pid},
5};
6
7use crate::processes::Processes;
8
9pub fn send_signal_to_pid(pid: Pid, signal: Option<Signal>) -> anyhow::Result<bool> {
10    match kill(pid, signal) {
11        Ok(()) => Ok(true),
12        Err(e) => match e {
13            nix::errno::Errno::EPERM => {
14                // Can't happen because there's "no way"
15                // that between us checking is_running()
16                // and reading the pid and signalling
17                // another process group would be there
18                // than ours.  XX except, what if a member
19                // of the process group exec's a setuid
20                // binary?
21                bail!("don't have permission to send signal to pid {pid}")
22            }
23            nix::errno::Errno::ESRCH => {
24                // Process does not exist
25                Ok(false)
26            }
27            _ => unreachable!(),
28        },
29    }
30}
31
32pub fn send_signal_to_process_group(pid: Pid, signal: Option<Signal>) -> Result<bool> {
33    let process_group_id: i32 = pid
34        .as_raw()
35        .checked_neg()
36        .ok_or_else(|| anyhow!("pid {pid} can't be negated"))?;
37    send_signal_to_pid(Pid::from_raw(process_group_id), signal)
38}
39
40pub fn send_signal_to_all_processes_of_session(
41    session_pid: Pid,
42    signal: Option<Signal>,
43) -> anyhow::Result<bool> {
44    // Kill the whole process group (but that doesn't include
45    // everything in the session)
46    let mut reached_a_process = send_signal_to_process_group(session_pid, signal)?;
47
48    // Iterate all processes to find ones in the given session
49    let pids = Processes::default().get_list()?;
50    for pid in pids {
51        if let Ok(sid) = getsid(Some(pid)) {
52            if sid == session_pid {
53                if send_signal_to_pid(pid, signal)? {
54                    reached_a_process = true;
55                }
56            }
57        }
58    }
59    Ok(reached_a_process)
60}