Skip to content

Commit

Permalink
Add a Result to getpgid, and add getpgrp. (#386)
Browse files Browse the repository at this point in the history
* Add a `Result` to `getpgid`, and add `getpgrp`.

Add a `Result` return type to `getpgid`, as it can fail if there's no
process with the given pid.

And, add a a `getpgrp` function, which is similar to `getpgid`, but
doesn't take a pid argument and always operates on the current process,
which means it doesn't need a `Result` return type.

* Use `getpgid` on platforms which don't have a `getpgrp` syscall.
  • Loading branch information
sunfishcode committed Jul 26, 2022
1 parent 677c8af commit 7dd900a
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 9 deletions.
7 changes: 7 additions & 0 deletions examples/process.rs
Expand Up @@ -10,6 +10,13 @@ fn main() -> io::Result<()> {

println!("Pid: {}", getpid().as_raw_nonzero());
println!("Parent Pid: {}", Pid::as_raw(getppid()));
println!("Group Pid: {}", getpgrp().as_raw_nonzero());
if let Some(ppid) = getppid() {
println!(
"Parent Group Pid: {}",
getpgid(Some(ppid)).unwrap().as_raw_nonzero()
);
}
println!("Uid: {}", getuid().as_raw());
println!("Gid: {}", getgid().as_raw());
#[cfg(any(
Expand Down
17 changes: 15 additions & 2 deletions src/backend/libc/process/syscalls.rs
Expand Up @@ -3,6 +3,8 @@
use super::super::c;
#[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))]
use super::super::conv::borrowed_fd;
#[cfg(not(target_os = "wasi"))]
use super::super::conv::ret_pid_t;
use super::super::conv::{c_str, ret, ret_c_int, ret_discarded_char_ptr};
#[cfg(any(target_os = "android", target_os = "linux"))]
use super::super::conv::{syscall_ret, syscall_ret_u32};
Expand Down Expand Up @@ -148,9 +150,20 @@ pub(crate) fn getppid() -> Option<Pid> {
#[cfg(not(target_os = "wasi"))]
#[inline]
#[must_use]
pub(crate) fn getpgid(pid: Option<Pid>) -> Pid {
pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> {
unsafe {
let pgid = ret_pid_t(c::getpgid(Pid::as_raw(pid) as _))?;
debug_assert_ne!(pgid, 0);
Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid)))
}
}

#[cfg(not(target_os = "wasi"))]
#[inline]
#[must_use]
pub(crate) fn getpgrp() -> Pid {
unsafe {
let pgid = c::getpgid(Pid::as_raw(pid) as _);
let pgid = c::getpgrp();
debug_assert_ne!(pgid, 0);
Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid))
}
Expand Down
27 changes: 24 additions & 3 deletions src/backend/linux_raw/process/syscalls.rs
Expand Up @@ -21,6 +21,7 @@ use crate::process::{
};
use core::convert::TryInto;
use core::mem::MaybeUninit;
use core::num::NonZeroU32;
use core::ptr::{null, null_mut};
use linux_raw_sys::general::{
__kernel_gid_t, __kernel_pid_t, __kernel_uid_t, membarrier_cmd, membarrier_cmd_flag, rlimit,
Expand Down Expand Up @@ -100,11 +101,31 @@ pub(crate) fn getppid() -> Option<Pid> {
}

#[inline]
pub(crate) fn getpgid(pid: Option<Pid>) -> Pid {
pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> {
unsafe {
let pgid: i32 =
ret_usize_infallible(syscall_readonly!(__NR_getpgid, c_uint(Pid::as_raw(pid))))
as __kernel_pid_t;
ret_usize(syscall_readonly!(__NR_getpgid, c_uint(Pid::as_raw(pid))))? as __kernel_pid_t;
Ok(Pid::from_raw_nonzero(NonZeroU32::new_unchecked(
pgid as u32,
)))
}
}

#[inline]
pub(crate) fn getpgrp() -> Pid {
// Use the `getpgrp` syscall if available.
#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
unsafe {
let pgid: i32 = ret_usize_infallible(syscall_readonly!(__NR_getpgrp)) as __kernel_pid_t;
debug_assert!(pgid > 0);
Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid as u32))
}

// Otherwise use `getpgrp` and pass it zero.
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
unsafe {
let pgid: i32 =
ret_usize_infallible(syscall_readonly!(__NR_getpgid, c_uint(0))) as __kernel_pid_t;
debug_assert!(pgid > 0);
Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid as u32))
}
Expand Down
16 changes: 15 additions & 1 deletion src/process/id.rs
Expand Up @@ -277,10 +277,24 @@ pub fn getppid() -> Option<Pid> {
/// [Linux]: https://man7.org/linux/man-pages/man2/getpgid.2.html
#[inline]
#[must_use]
pub fn getpgid(pid: Option<Pid>) -> Pid {
pub fn getpgid(pid: Option<Pid>) -> io::Result<Pid> {
backend::process::syscalls::getpgid(pid)
}

/// `getpgrp()`—Returns the process' group ID.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html
/// [Linux]: https://man7.org/linux/man-pages/man2/getpgrp.2.html
#[inline]
#[must_use]
pub fn getpgrp() -> Pid {
backend::process::syscalls::getpgrp()
}

/// `setsid()`—Create a new session.
///
/// # References
Expand Down
2 changes: 1 addition & 1 deletion src/process/mod.rs
Expand Up @@ -39,7 +39,7 @@ pub use exit::{EXIT_FAILURE, EXIT_SUCCESS};
pub use id::Cpuid;
#[cfg(not(target_os = "wasi"))]
pub use id::{
getegid, geteuid, getgid, getpgid, getpid, getppid, getuid, setsid, Gid, Pid, RawGid,
getegid, geteuid, getgid, getpgid, getpgrp, getpid, getppid, getuid, setsid, Gid, Pid, RawGid,
RawNonZeroPid, RawPid, RawUid, Uid,
};
#[cfg(not(target_os = "wasi"))]
Expand Down
29 changes: 27 additions & 2 deletions tests/process/id.rs
Expand Up @@ -67,11 +67,36 @@ fn test_getppid() {
#[test]
fn test_getpgid() {
assert_eq!(process::getpgid(None), process::getpgid(None));
assert_eq!(
process::getpgid(Some(process::getpid())),
process::getpgid(Some(process::getpid()))
);
unsafe {
assert_eq!(
process::getpgid(None).as_raw_nonzero().get() as libc::pid_t,
process::getpgid(None).unwrap().as_raw_nonzero().get() as libc::pid_t,
libc::getpgid(0)
);
assert_eq!(process::getpgid(None).is_init(), libc::getpgid(0) == 1);
assert_eq!(
process::getpgid(None).unwrap().is_init(),
libc::getpgid(0) == 1
);
assert_eq!(
process::getpgid(Some(process::getpid()))
.unwrap()
.as_raw_nonzero()
.get() as libc::pid_t,
libc::getpgid(libc::getpid())
);
}
}

#[test]
fn test_getpgrp() {
assert_eq!(process::getpgrp(), process::getpgrp());
unsafe {
assert_eq!(
process::getpgrp().as_raw_nonzero().get() as libc::pid_t,
libc::getpgrp()
);
}
}

0 comments on commit 7dd900a

Please sign in to comment.