diff --git a/src/backend/libc/process/syscalls.rs b/src/backend/libc/process/syscalls.rs index 9822a151a..1b100e26b 100644 --- a/src/backend/libc/process/syscalls.rs +++ b/src/backend/libc/process/syscalls.rs @@ -145,6 +145,17 @@ pub(crate) fn getppid() -> Option { } } +#[cfg(not(target_os = "wasi"))] +#[inline] +#[must_use] +pub(crate) fn getpgid(pid: Option) -> Pid { + unsafe { + let pgid = c::getpgid(Pid::as_raw(pid) as _); + debug_assert_ne!(pgid, 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid)) + } +} + #[cfg(any( target_os = "android", target_os = "dragonfly", diff --git a/src/backend/linux_raw/process/syscalls.rs b/src/backend/linux_raw/process/syscalls.rs index 37284f803..d5bf60564 100644 --- a/src/backend/linux_raw/process/syscalls.rs +++ b/src/backend/linux_raw/process/syscalls.rs @@ -99,6 +99,17 @@ pub(crate) fn getppid() -> Option { } } +#[inline] +pub(crate) fn getpgid(pid: Option) -> Pid { + unsafe { + let pgid: i32 = + ret_usize_infallible(syscall_readonly!(__NR_getpgid, c_uint(Pid::as_raw(pid)))) + as __kernel_pid_t; + debug_assert!(pgid > 0); + Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid as u32)) + } +} + #[inline] pub(crate) fn getgid() -> Gid { #[cfg(any(target_arch = "x86", target_arch = "sparc", target_arch = "arm"))] diff --git a/src/process/id.rs b/src/process/id.rs index c8d2318bb..9e061bf9c 100644 --- a/src/process/id.rs +++ b/src/process/id.rs @@ -267,6 +267,20 @@ pub fn getppid() -> Option { backend::process::syscalls::getppid() } +/// `getpgid(pid)`—Returns the process group ID of the given process. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgid.html +/// [Linux]: https://man7.org/linux/man-pages/man2/getpgid.2.html +#[inline] +#[must_use] +pub fn getpgid(pid: Option) -> Pid { + backend::process::syscalls::getpgid(pid) +} + /// `setsid()`—Create a new session. /// /// # References diff --git a/src/process/mod.rs b/src/process/mod.rs index 45673c0ea..6d7a61623 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -39,8 +39,8 @@ pub use exit::{EXIT_FAILURE, EXIT_SUCCESS}; pub use id::Cpuid; #[cfg(not(target_os = "wasi"))] pub use id::{ - getegid, geteuid, getgid, getpid, getppid, getuid, setsid, Gid, Pid, RawGid, RawNonZeroPid, - RawPid, RawUid, Uid, + getegid, geteuid, getgid, getpgid, getpid, getppid, getuid, setsid, Gid, Pid, RawGid, + RawNonZeroPid, RawPid, RawUid, Uid, }; #[cfg(not(target_os = "wasi"))] pub use kill::{kill_current_process_group, kill_process, kill_process_group, Signal}; diff --git a/tests/process/id.rs b/tests/process/id.rs index 10095fa60..33c2fda53 100644 --- a/tests/process/id.rs +++ b/tests/process/id.rs @@ -63,3 +63,15 @@ fn test_getppid() { } } } + +#[test] +fn test_getpgid() { + assert_eq!(process::getpgid(None), process::getpgid(None)); + unsafe { + assert_eq!( + process::getpgid(None).as_raw_nonzero().get() as libc::pid_t, + libc::getpgid(0) + ); + assert_eq!(process::getpgid(None).is_init(), libc::getpgid(0) == 1); + } +}