process_alive-0.2.0/.cargo_vcs_info.json0000644000000001360000000000100136710ustar { "git": { "sha1": "297fc56029efc4acd7bb0753e1d07dd9b38ab531" }, "path_in_vcs": "" }process_alive-0.2.0/.github/CODEOWNERS000064400000000000000000000000121046102023000154050ustar 00000000000000* @sytten process_alive-0.2.0/.github/workflows/ci.yaml000064400000000000000000000021241046102023000173340ustar 00000000000000name: Run CI on: pull_request: push: branches: - 'main' concurrency: group: test-${{ github.ref_name }} cancel-in-progress: true jobs: lint: runs-on: ubuntu-latest timeout-minutes: 5 steps: - name: Checkout project uses: actions/checkout@v4 - name: Setup Rust uses: caido/action-setup-rust@v1 with: cache: false - name: Run linter uses: giraffate/clippy-action@871cc4173f2594435c7ea6b0bce499cf6c2164a1 with: github_token: ${{ secrets.GITHUB_TOKEN }} clippy_flags: --all-features -- -D warnings reporter: github-pr-review - name: Run formatter run: cargo fmt --all -- --check test: needs: lint runs-on: ${{ matrix.os }} timeout-minutes: 10 strategy: matrix: os: [ubuntu-latest, windows-latest] steps: - name: Checkout project uses: actions/checkout@v4 - name: Setup Rust uses: caido/action-setup-rust@v1 with: cache: false - name: Run tests run: cargo test process_alive-0.2.0/.github/workflows/publish.yml000064400000000000000000000007141046102023000202510ustar 00000000000000 name: Publish on: push: branches: - 'main' jobs: publish: runs-on: ubuntu-latest timeout-minutes: 5 steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable override: true - uses: katyo/publish-crates@v1 with: registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} ignore-unpublished-changes: trueprocess_alive-0.2.0/.gitignore000064400000000000000000000000241046102023000144450ustar 00000000000000/target /Cargo.lock process_alive-0.2.0/Cargo.lock0000644000000014630000000000100116500ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "libc" version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "process_alive" version = "0.2.0" dependencies = [ "libc", "windows-sys", ] [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] process_alive-0.2.0/Cargo.toml0000644000000021440000000000100116700ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "process_alive" version = "0.2.0" authors = ["Caido Labs Inc. "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Cross platform library to verify if a process is alive" readme = "README.md" license = "MIT" repository = "https://github.com/caido/process_alive" [lib] name = "process_alive" path = "src/lib.rs" [dependencies] [target.'cfg(target_family = "unix")'.dependencies.libc] version = "0.2" [target."cfg(windows)".dependencies.windows-sys] version = "0.61" features = [ "Win32_Foundation", "Win32_System_Threading", ] process_alive-0.2.0/Cargo.toml.orig000064400000000000000000000007331046102023000153530ustar 00000000000000[package] name = "process_alive" authors = ["Caido Labs Inc. "] description = "Cross platform library to verify if a process is alive" repository = "https://github.com/caido/process_alive" license = "MIT" version = "0.2.0" edition = "2021" [dependencies] [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.61", features = [ "Win32_Foundation", "Win32_System_Threading", ] } [target.'cfg(target_family = "unix")'.dependencies] libc = "0.2" process_alive-0.2.0/LICENSE000064400000000000000000000020431046102023000134650ustar 00000000000000Copyright (c) 2022 Caido Labs Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. process_alive-0.2.0/README.md000064400000000000000000000015741046102023000137470ustar 00000000000000# Process Alive [github](https://github.com/caido/process_alive) [crates.io](https://crates.io/crates/process_alive) This is a small cross platform crate to check if a process is alive. Inspired by [sysinfo](https://github.com/GuillaumeGomez/sysinfo), but without the need to parse through all the processes to verify one. Since there can be some errors related to permissions, the state can be `Unknown` and you can decide how you want to handle it. ```rust use process_alive::{State, Pid}; pub fn main() { let pid = Pid::from(1234); let state = process_alive::state(pid); println("Process {} is {}", pid, state); } ``` process_alive-0.2.0/rust-toolchain.toml000064400000000000000000000001261046102023000163300ustar 00000000000000[toolchain] channel = "1.89.0" profile = "minimal" components = ["rustfmt", "clippy"] process_alive-0.2.0/src/lib.rs000064400000000000000000000015151046102023000143660ustar 00000000000000mod pid; pub use self::pid::*; mod state; pub use self::state::*; #[cfg(unix)] mod unix; #[cfg(unix)] pub use self::unix::*; #[cfg(windows)] mod windows; #[cfg(windows)] pub use self::windows::*; #[cfg(test)] mod tests { use super::*; use std::process::Command; #[test] fn test_alive() { let mut child = Command::new("sleep").arg("5").spawn().unwrap(); let pid = child.id().into(); let state = state(pid); child.kill().unwrap(); child.wait().unwrap(); assert_eq!(State::Alive, state); } #[test] fn test_dead() { let mut child = Command::new("sleep").arg("5").spawn().unwrap(); let pid = child.id().into(); child.kill().unwrap(); child.wait().unwrap(); let state = state(pid); assert_eq!(State::Dead, state); } } process_alive-0.2.0/src/pid.rs000064400000000000000000000010341046102023000143700ustar 00000000000000use std::fmt; use std::num::TryFromIntError; /// Used as a wrapper for the process ID #[derive(Clone, Copy, PartialEq, Eq)] pub struct Pid(pub(crate) u32); impl From for Pid { fn from(value: u32) -> Self { Self(value) } } impl TryFrom for Pid { type Error = TryFromIntError; fn try_from(value: i32) -> Result { Ok(Self(value.try_into()?)) } } impl fmt::Display for Pid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) } } process_alive-0.2.0/src/state.rs000064400000000000000000000007341046102023000147420ustar 00000000000000use std::fmt; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum State { Alive, Dead, Unknown, } impl State { pub fn is_alive(&self) -> bool { *self == Self::Alive } } impl fmt::Display for State { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self { Self::Alive => "alive", Self::Dead => "dead", Self::Unknown => "unknown", }; write!(f, "{}", s) } } process_alive-0.2.0/src/unix.rs000064400000000000000000000007231046102023000146030ustar 00000000000000use std::io::Error; use libc::kill; use crate::{Pid, State}; pub fn state(pid: Pid) -> State { let pid: i32 = match pid.0.try_into() { Ok(pid) => pid, Err(_) => return State::Unknown, }; unsafe { if kill(pid, 0) == 0 { return State::Alive; } } let errno = Error::last_os_error().raw_os_error().unwrap(); if errno == libc::ESRCH { State::Dead } else { State::Unknown } } process_alive-0.2.0/src/windows/handle.rs000064400000000000000000000013111046102023000165370ustar 00000000000000use std::ops::Deref; use windows_sys::Win32::{ Foundation::{CloseHandle, FALSE, HANDLE}, System::Threading::{OpenProcess, PROCESS_QUERY_LIMITED_INFORMATION}, }; use crate::Pid; pub struct Handle(HANDLE); impl Handle { pub fn open(pid: Pid) -> Option { let handle = unsafe { OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid.0) }; if handle.is_null() { None } else { Some(Self(handle)) } } } impl Deref for Handle { type Target = HANDLE; fn deref(&self) -> &Self::Target { &self.0 } } impl Drop for Handle { fn drop(&mut self) { unsafe { CloseHandle(self.0); } } } process_alive-0.2.0/src/windows/mod.rs000064400000000000000000000012571046102023000160740ustar 00000000000000use std::mem::MaybeUninit; use windows_sys::Win32::Foundation::{FALSE, STILL_ACTIVE}; use windows_sys::Win32::System::Threading::GetExitCodeProcess; use self::handle::Handle; use crate::{Pid, State}; mod handle; pub fn state(pid: Pid) -> State { let handle = match Handle::open(pid) { Some(handle) => handle, None => return State::Unknown, }; let mut status = MaybeUninit::uninit(); unsafe { if GetExitCodeProcess(*handle, status.as_mut_ptr()) == FALSE { return State::Unknown; } if status.assume_init() == STILL_ACTIVE as u32 { State::Alive } else { State::Dead } } }