mirror of
https://github.com/ClementTsang/bottom.git
synced 2026-05-04 05:50:42 +00:00
f7d070f944
* refactor: try bumping to rust 2024 edition * now run nightly fmt * fix some macos changes * only apply a few of these settings
87 lines
2.6 KiB
Rust
87 lines
2.6 KiB
Rust
//! This file is meant to house (OS specific) implementations on how to kill
|
|
//! processes.
|
|
|
|
use anyhow::bail;
|
|
#[cfg(target_os = "windows")]
|
|
use windows::Win32::{
|
|
Foundation::{CloseHandle, HANDLE},
|
|
System::Threading::{
|
|
OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, TerminateProcess,
|
|
},
|
|
};
|
|
|
|
use crate::collection::processes::Pid;
|
|
|
|
/// Based from [this SO answer](https://stackoverflow.com/a/55231715).
|
|
#[cfg(target_os = "windows")]
|
|
struct Process(HANDLE);
|
|
|
|
#[cfg(target_os = "windows")]
|
|
impl Process {
|
|
fn open(pid: u32) -> anyhow::Result<Process> {
|
|
// SAFETY: Windows API call, tread carefully with the args.
|
|
match unsafe { OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE, false, pid) } {
|
|
Ok(process) => Ok(Process(process)),
|
|
Err(_) => bail!("process may have already been terminated."),
|
|
}
|
|
}
|
|
|
|
fn kill(self) -> anyhow::Result<()> {
|
|
// SAFETY: Windows API call, this is safe as we are passing in the handle.
|
|
let result = unsafe { TerminateProcess(self.0, 1) };
|
|
if result.is_err() {
|
|
bail!("process may have already been terminated.");
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[cfg(target_os = "windows")]
|
|
impl Drop for Process {
|
|
fn drop(&mut self) {
|
|
// SAFETY: Windows API call, this is safe as we are passing in the handle.
|
|
unsafe {
|
|
let _ = CloseHandle(self.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Kills a process, given a PID, for windows.
|
|
#[cfg(target_os = "windows")]
|
|
pub fn kill_process_given_pid(pid: Pid) -> anyhow::Result<()> {
|
|
let process = Process::open(pid as u32)?;
|
|
process.kill()?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Kills a process, given a PID, for UNIX.
|
|
#[cfg(target_family = "unix")]
|
|
pub fn kill_process_given_pid(pid: Pid, signal: usize) -> anyhow::Result<()> {
|
|
// SAFETY: the signal should be valid, and we act properly on an error (exit
|
|
// code not 0).
|
|
let output = unsafe { libc::kill(pid, signal as i32) };
|
|
|
|
if output != 0 {
|
|
// We had an error...
|
|
let err_code = std::io::Error::last_os_error().raw_os_error();
|
|
let err = match err_code {
|
|
Some(libc::ESRCH) => "the target process did not exist.",
|
|
Some(libc::EPERM) => {
|
|
"the calling process does not have the permissions to terminate the target process(es)."
|
|
}
|
|
Some(libc::EINVAL) => "an invalid signal was specified.",
|
|
_ => "Unknown error occurred.",
|
|
};
|
|
|
|
if let Some(err_code) = err_code {
|
|
bail!(format!("Error code {err_code} - {err}"))
|
|
} else {
|
|
bail!(format!("Error code unknown - {err}"))
|
|
};
|
|
}
|
|
|
|
Ok(())
|
|
}
|