### Example: kill() basic usage Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Example for the kill() method showing how to kill a process group. ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; let mut command = Command::new("yes"); if let Ok(mut child) = command.group_spawn() { child.kill().await.expect("command wasn't running"); } else { println!("yes command didn't start"); } ``` -------------------------------- ### Example: group_spawn and wait for /bin/cat Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Example from the struct documentation showing how to spawn a process group and wait for it to exit. ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; let mut child = Command::new("/bin/cat") .arg("file.txt") .group_spawn() .expect("failed to execute child"); let ecode = child.wait() .await .expect("failed to wait on child"); assert!(ecode.success()); ``` -------------------------------- ### Example: into_inner() writing to stdin Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Example for the into_inner() method showing how to write to the child's stdin. ```rust use std::process::Stdio; use tokio::{io::AsyncWriteExt, process::Command}; use command_group::AsyncCommandGroup; let mut child = Command::new("cat").stdin(Stdio::piped()).group_spawn().expect("cat command didn't start"); if let Some(mut din) = child.into_inner().stdin.take() { din.write_all(b"Woohoo!").await.expect("failed to write"); } ``` -------------------------------- ### Example: inner() reading from stdout Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Example for the inner() method showing how to read from the child's stdout. ```rust use std::process::Stdio; use tokio::{io::AsyncReadExt, process::Command}; use command_group::AsyncCommandGroup; let mut child = Command::new("ls").stdout(Stdio::piped()).group_spawn().expect("ls command didn't start"); let mut output = String::new(); if let Some(mut out) = child.inner().stdout.take() { out.read_to_string(&mut output).await.expect("failed to read from child"); } println!("output: {}", output); ``` -------------------------------- ### Getting exit status with group_status Source: https://docs.rs/command-group/latest/command_group/stdlib/trait.CommandGroup.html Example showing how to execute a command as a child process group and collect its exit status. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```rust use std::process::Command; use command_group::CommandGroup; let status = Command::new("/bin/cat") .arg("file.txt") .group_status() .expect("failed to execute process"); println!("process finished with: {}", status); assert!(status.success()); ``` -------------------------------- ### group_output Execution Source: https://docs.rs/command-group/latest/command_group/tokio/trait.AsyncCommandGroup.html Example of executing a command as a child process group and capturing its output. ```rust use tokio::process::Command; use std::io::{self, Write}; use command_group::AsyncCommandGroup; let output = Command::new("/bin/cat") .arg("file.txt") .group_output() .await .expect("failed to execute process"); println!("status: {}", output.status); io::stdout().write_all(&output.stdout).unwrap(); io::stderr().write_all(&output.stderr).unwrap(); assert!(output.status.success()); ``` -------------------------------- ### Using AsyncGroupChild::wait_with_output with tokio::process::Command Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Shows how to spawn a child process with group_spawn and then wait for it with wait_with_output, collecting stdout and stderr. The example uses tokio::process::Command and command_group::AsyncCommandGroup. The output status is asserted to be successful. ```rust /// use tokio::process::Command; /// use command_group::AsyncCommandGroup; /// /// let child = Command::new("/bin/cat") /// .arg("file.txt") /// .stdout(Stdio::piped()) /// .group_spawn() /// .expect("failed to execute child"); /// /// let output = child /// .wait_with_output() /// .await /// .expect("failed to wait on child"); /// /// assert!(output.status.success()); /// # } ``` -------------------------------- ### Basic usage of group_spawn Source: https://docs.rs/command-group/latest/command_group/stdlib/trait.CommandGroup.html Example showing how to spawn a command as a child process group using group_spawn(). By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```rust use std::process::Command; use command_group::CommandGroup; Command::new("ls") .group_spawn() .expect("ls command failed to start"); ``` -------------------------------- ### Collecting output with group_output Source: https://docs.rs/command-group/latest/command_group/stdlib/trait.CommandGroup.html Example showing how to execute a command as a child process group and collect its output. By default, stdout and stderr are captured, while stdin is not inherited and will close immediately if the child attempts to read from it. On Windows, this creates a job object instead of a POSIX process group. ```rust use std::process::Command; use std::io::{self, Write}; use command_group::CommandGroup; let output = Command::new("/bin/cat") .arg("file.txt") .group_output() .expect("failed to execute process"); println!("status: {}", output.status); io::stdout().write_all(&output.stdout).unwrap(); io::stderr().write_all(&output.stderr).unwrap(); assert!(output.status.success()); ``` -------------------------------- ### group_status Execution Source: https://docs.rs/command-group/latest/command_group/tokio/trait.AsyncCommandGroup.html Example of executing a command as a child process group and waiting for its exit status. ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; let status = Command::new("/bin/cat") .arg("file.txt") .group_status() .await .expect("failed to execute process"); println!("process finished with: {}", status); assert!(status.success()); ``` -------------------------------- ### CommandGroup trait group_output method with should_panic example Source: https://docs.rs/command-group/latest/src/command_group/stdlib.rs.html Defines the `group_output` method that executes the command as a child process group, waits, and collects all output. By default stdout/stderr are captured, stdin is not inherited and reads close immediately. On Windows it creates a job object. The `should_panic` example shows using group_output on `/bin/cat` and printing status and output. ```rust /// Executes the command as a child process group, waiting for it to finish and /// collecting all of its output. /// /// By default, stdout and stderr are captured (and used to provide the /// resulting output). Stdin is not inherited from the parent and any /// attempt by the child process to read from the stdin stream will result /// in the stream immediately closing. /// /// On Windows, this creates a job object instead of a POSIX process group. /// /// # Examples /// /// ```should_panic /// use std::process::Command; /// use std::io::{self, Write}; /// use command_group::CommandGroup; /// /// let output = Command::new("/bin/cat") /// .arg("file.txt") /// .group_output() /// .expect("failed to execute process"); /// /// println!("status: {}", output.status); /// io::stdout().write_all(&output.stdout).unwrap(); /// io::stderr().write_all(&output.stderr).unwrap(); /// /// assert!(output.status.success()); /// ``` fn group_output(&mut self) -> Result { self.group_spawn() .and_then(|child| child.wait_with_output()) } ``` -------------------------------- ### CommandGroup trait group_status method with should_panic example Source: https://docs.rs/command-group/latest/src/command_group/stdlib.rs.html Defines the `group_status` method that executes the command as a child process group and waits for it to finish, collecting its status. stdout/stderr are inherited by default. On Windows it creates a job object. The `should_panic` example shows how group_status handles `/bin/cat` and prints the status. ```rust /// Executes a command as a child process group, waiting for it to finish and /// collecting its status. /// /// By default, stdin, stdout and stderr are inherited from the parent. /// /// On Windows, this creates a job object instead of a POSIX process group. /// /// # Examples /// /// ```should_panic /// use std::process::Command; /// use command_group::CommandGroup; /// /// let status = Command::new("/bin/cat") /// .arg("file.txt") /// .group_status() /// .expect("failed to execute process"); /// /// println!("process finished with: {}", status); /// /// assert!(status.success()); /// ``` fn group_status(&mut self) -> Result { self.group_spawn().and_then(|mut child| child.wait()) } ``` -------------------------------- ### CommandGroup trait definition with group_spawn method and example Source: https://docs.rs/command-group/latest/src/command_group/stdlib.rs.html Defines the public `CommandGroup` trait. The `group_spawn` method executes the command as a child process group, inheriting stdin/stdout/stderr by default; on Windows it creates a job object instead of a POSIX process group. The `no_run` example shows basic usage with `Command::new("ls").group_spawn().expect(...)`. ```rust pub trait CommandGroup { /// Executes the command as a child process group, returning a handle to it. /// /// By default, stdin, stdout and stderr are inherited from the parent. /// /// On Windows, this creates a job object instead of a POSIX process group. /// /// # Examples /// /// Basic usage: /// /// ```no_run /// use std::process::Command; /// use command_group::CommandGroup; /// /// Command::new("ls") /// .group_spawn() /// .expect("ls command failed to start"); /// ``` fn group_spawn(&mut self) -> Result { self.group().spawn() } ``` -------------------------------- ### Get child group ID with tokio::process::Command Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Spawns a command as a process group and prints the group ID if available. Uses command_group::AsyncCommandGroup and tokio::process::Command. ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; let mut command = Command::new("ls"); if let Ok(child) = command.group_spawn() { if let Some(pgid) = child.id() { println!("Child group's ID is {}", pgid); } else { println!("Child group is gone"); } } else { println!("ls command didn't start"); } ``` -------------------------------- ### Spawn and wait for a process group Source: https://docs.rs/command-group/latest/command_group/struct.GroupChild.html Demonstrates spawning a command as a group and waiting for its completion. ```rust use std::process::Command; use command_group::CommandGroup; let mut child = Command::new("/bin/cat") .arg("file.txt") .group_spawn() .expect("failed to execute child"); let ecode = child.wait() .expect("failed to wait on child"); assert!(ecode.success()); ``` -------------------------------- ### Crate documentation summary line for stdlib.rs Source: https://docs.rs/command-group/latest/src/command_group/stdlib.rs.html The summary line at the top of the file describes the module as the implementation of process group extensions for the standard library's `Command` type. ```rust //! Implementation of process group extensions for the //! standard library’s [`Command` type](std::process::Command). ``` -------------------------------- ### Get process group ID Source: https://docs.rs/command-group/latest/command_group/struct.GroupChild.html Retrieves the OS-assigned process group identifier. ```rust use std::process::Command; use command_group::CommandGroup; let mut command = Command::new("ls"); if let Ok(child) = command.group_spawn() { println!("Child group's ID is {}", child.id()); } else { println!("ls command didn't start"); } ``` -------------------------------- ### Get child process group ID Source: https://docs.rs/command-group/latest/src/command_group/stdlib/child.rs.html Retrieves the OS-assigned process group identifier. ```rust use std::process::Command; use command_group::CommandGroup; let mut command = Command::new("ls"); if let Ok(child) = command.group_spawn() { ``` -------------------------------- ### Implementation of spawn for CommandGroupBuilder Source: https://docs.rs/command-group/latest/src/command_group/tokio/unix.rs.html The internal implementation of the spawn method, which configures process groups using either tokio_unstable features or nix system calls. ```rust use crate::builder::CommandGroupBuilder; use crate::AsyncGroupChild; impl CommandGroupBuilder<'_, tokio::process::Command> { /// Executes the command as a child process group, returning a handle to it. /// /// By default, stdin, stdout and stderr are inherited from the parent. /// /// On Windows, this creates a job object instead of a POSIX process group. /// /// # Examples /// /// Basic usage: /// /// ```no_run /// use tokio::process::Command; /// use command_group::AsyncCommandGroup; /// /// Command::new("ls") /// .group() /// .spawn() /// .expect("ls command failed to start"); /// ``` pub fn spawn(&mut self) -> std::io::Result { #[cfg(tokio_unstable)] { self.command.process_group(0); } #[cfg(not(tokio_unstable))] unsafe { use nix::unistd::{setpgid, Pid}; use std::io::Error; self.command.pre_exec(|| { setpgid(Pid::this(), Pid::from_raw(0)) .map_err(Error::from) .map(|_| ()) }); } self.command.spawn().map(AsyncGroupChild::new) } } ``` -------------------------------- ### CommandGroupBuilder::spawn (for tokio::process::Command) Source: https://docs.rs/command-group/latest/command_group/builder/struct.CommandGroupBuilder.html Executes the command as a child process group, returning a handle to it. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```APIDOC ## CommandGroupBuilder::spawn (for tokio::process::Command) ### Description Executes the command as a child process group, returning a handle to it. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ### Method spawn ### Signature pub fn spawn(&mut self) -> Result ### Parameters None ### Return Value Result - A handle to the spawned child process group. ### Example ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; Command::new("ls") .group() .spawn() .expect("ls command failed to start"); ``` ``` -------------------------------- ### start_kill Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Attempts to force the child process group to exit by sending a SIGKILL signal on Unix platforms. This method does not wait for the exit to take effect. ```APIDOC ## start_kill ### Description Attempts to force the child process group to exit by sending a SIGKILL signal on Unix platforms. This method does not wait for the exit to take effect. ### Method start_kill ### Signature pub fn start_kill(&mut self) -> Result<()> ### Parameters - **self** (&mut Self) - Required - Mutable reference to the child process group. ### Returns - **Result<()>** - Ok(()) if the signal was sent successfully, or an error otherwise. ### Notes - On Unix platforms, a zombie process may remain after a kill is sent. To avoid this, the caller should ensure that either `child.wait().await` or `child.try_wait()` is invoked successfully. - See the Tokio documentation for `Child::start_kill` for more details. ``` -------------------------------- ### fn group_output<'life0, 'async_trait>(&'life0 mut self) -> Pin> + Send + 'async_trait>> Source: https://docs.rs/command-group/latest/command_group/tokio/trait.AsyncCommandGroup.html Executes the command as a child process group, waiting for it to finish and collecting all of its output. By default, stdout and stderr are captured, and stdin is not inherited. On Windows, this creates a job object instead of a POSIX process group. ```APIDOC ## fn group_output<'life0, 'async_trait>(&'life0 mut self) -> Pin> + Send + 'async_trait>> ### Description Executes the command as a child process group, waiting for it to finish and collecting all of its output. By default, stdout and stderr are captured (and used to provide the resulting output). Stdin is not inherited from the parent and any attempt by the child process to read from the stdin stream will result in the stream immediately closing. On Windows, this creates a job object instead of a POSIX process group. ### Method `group_output` ### Signature ```rust fn group_output<'life0, 'async_trait>( &'life0 mut self, ) -> Pin> + Send + 'async_trait>> where Self: Send + 'async_trait, 'life0: 'async_trait, ``` ### Parameters - **self** (`&'life0 mut self`) - Required - The command to execute. ### Returns - **Pin> + Send + 'async_trait>>** - A future that resolves to the output of the command. ### Example ```rust use tokio::process::Command; use std::io::{self, Write}; use command_group::AsyncCommandGroup; let output = Command::new("/bin/cat") .arg("file.txt") .group_output() .await .expect("failed to execute process"); println!("status: {}", output.status); io::stdout().write_all(&output.stdout).unwrap(); io::stderr().write_all(&output.stderr).unwrap(); assert!(output.status.success()); ``` ``` -------------------------------- ### Unix spawn implementation for CommandGroupBuilder Source: https://docs.rs/command-group/latest/src/command_group/stdlib/unix.rs.html Implements the spawn method for CommandGroupBuilder on Unix. It calls process_group(0) on the command to create a new process group, then spawns and wraps the child in GroupChild. The doc comment notes that stdin, stdout, and stderr are inherited by default, and that on Windows a job object is used instead. ```rust use std::{os::unix::process::CommandExt, process::Command}; use crate::{builder::CommandGroupBuilder, GroupChild}; impl CommandGroupBuilder<'_, Command> { /// Executes the command as a child process group, returning a handle to it. /// /// By default, stdin, stdout and stderr are inherited from the parent. /// /// On Windows, this creates a job object instead of a POSIX process group. /// /// # Examples /// /// Basic usage: /// /// ```no_run /// use std::process::Command; /// use command_group::CommandGroup; /// /// Command::new("ls") /// .group() /// .spawn() /// .expect("ls command failed to start"); /// ``` pub fn spawn(&mut self) -> std::io::Result { self.command.process_group(0).spawn().map(GroupChild::new) } } ``` -------------------------------- ### UnixChildExt::signal implementation for AsyncGroupChild Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Unix-only implementation of the signal method from UnixChildExt for AsyncGroupChild. It delegates to the internal signal_imp method. ```rust #[cfg(unix)] impl crate::UnixChildExt for AsyncGroupChild { fn signal(&self, sig: Signal) -> Result<()> { self.imp.signal_imp(sig) } } ``` -------------------------------- ### fn group_spawn(&mut self) -> Result Source: https://docs.rs/command-group/latest/command_group/tokio/trait.AsyncCommandGroup.html Executes the command as a child process group, returning a handle to it. By default, stdin, stdout and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```APIDOC ## fn group_spawn(&mut self) -> Result ### Description Executes the command as a child process group, returning a handle to it. By default, stdin, stdout and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ### Method `group_spawn` ### Signature ```rust fn group_spawn(&mut self) -> Result ``` ### Parameters - **self** (`&mut self`) - Required - The command to execute. ### Returns - **Result** - A handle to the spawned child process group. ### Example ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; Command::new("ls") .group_spawn() .expect("ls command failed to start"); ``` ``` -------------------------------- ### AsyncCommandGroup::group_spawn Source: https://docs.rs/command-group/latest/src/command_group/tokio.rs.html Executes the command as a child process group, returning a handle to it. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```APIDOC ## AsyncCommandGroup::group_spawn ### Description Executes the command as a child process group, returning a handle to it. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ### Method fn group_spawn(&mut self) -> Result ### Parameters None ### Request Example ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; Command::new("ls") .group_spawn() .expect("ls command failed to start"); ``` ### Response #### Success Response Returns a Result which is a handle to the spawned child process group. #### Response Example ```rust let child = Command::new("ls").group_spawn().expect("ls command failed to start"); ``` ``` -------------------------------- ### Set non-blocking mode on Linux Source: https://docs.rs/command-group/latest/src/command_group/stdlib/child/unix.rs.html Configures a file descriptor to non-blocking mode using the FIONBIO ioctl on Linux systems. ```rust #[cfg(target_os = "linux")] fn set_nonblocking(fd: RawFd, nonblocking: bool) -> Result<()> { let v = nonblocking as libc::c_int; let res = unsafe { libc::ioctl(fd, libc::FIONBIO, &v) }; Errno::result(res).map_err(Error::from).map(drop) } ``` -------------------------------- ### fn group_spawn(&mut self) -> Result Source: https://docs.rs/command-group/latest/command_group/stdlib/trait.CommandGroup.html Executes the command as a child process group, returning a handle to it. By default, stdin, stdout and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```APIDOC ## fn group_spawn(&mut self) -> Result ### Description Executes the command as a child process group, returning a handle to it. By default, stdin, stdout and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ### Method Provided method ### Signature fn group_spawn(&mut self) -> Result ### Parameters - **self** (&mut self) - Required - The mutable reference to the command. ### Returns - **Result** - A result containing a handle to the child process group. ### Example ```rust use std::process::Command; use command_group::CommandGroup; Command::new("ls") .group_spawn() .expect("ls command failed to start"); ``` ``` -------------------------------- ### Spawn an asynchronous command group Source: https://docs.rs/command-group/latest/command_group/builder/struct.CommandGroupBuilder.html Basic usage of `CommandGroupBuilder::spawn` for an asynchronous `tokio::process::Command`. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; Command::new("ls") .group() .spawn() .expect("ls command failed to start"); ``` -------------------------------- ### fn group_status<'life0, 'async_trait>(&'life0 mut self) -> Pin> + Send + 'async_trait>> Source: https://docs.rs/command-group/latest/command_group/tokio/trait.AsyncCommandGroup.html Executes a command as a child process group, waiting for it to finish and collecting its status. By default, stdin, stdout and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```APIDOC ## fn group_status<'life0, 'async_trait>(&'life0 mut self) -> Pin> + Send + 'async_trait>> ### Description Executes a command as a child process group, waiting for it to finish and collecting its status. By default, stdin, stdout and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ### Method `group_status` ### Signature ```rust fn group_status<'life0, 'async_trait>( &'life0 mut self, ) -> Pin> + Send + 'async_trait>> where Self: Send + 'async_trait, 'life0: 'async_trait, ``` ### Parameters - **self** (`&'life0 mut self`) - Required - The command to execute. ### Returns - **Pin> + Send + 'async_trait>>** - A future that resolves to the exit status of the command. ### Example ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; let status = Command::new("/bin/cat") .arg("file.txt") .group_status() .await .expect("failed to execute process"); println!("process finished with: {}", status); assert!(status.success()); ``` ``` -------------------------------- ### Basic signal usage with Command::spawn Source: https://docs.rs/command-group/latest/command_group/trait.UnixChildExt.html Basic usage of signal on a spawned child process. Sends SIGTERM to the child; if the process has already exited, an InvalidInput error is returned. ```rust use std::process::Command; use command_group::{UnixChildExt, Signal}; let mut command = Command::new("yes"); if let Ok(mut child) = command.spawn() { child.signal(Signal::SIGTERM).expect("command wasn't running"); } else { println!("yes command didn't start"); } ``` -------------------------------- ### Unix ChildImp implementation for Tokio child process Source: https://docs.rs/command-group/latest/src/command_group/tokio/child/unix.rs.html Defines the `ChildImp` struct and its methods for managing a Unix process group. It wraps a `tokio::process::Child`, stores the process group ID, and provides methods to take stdin/stdout/stderr, send signals, wait for all processes in the group, and check exit status. The `wait` method retries reaping children and falls back to a blocking task if needed. ```rust use std::{ convert::TryInto, io::{Error, Result}, ops::ControlFlow, os::unix::process::ExitStatusExt, process::ExitStatus, }; use nix::{ errno::Errno, libc, sys::{ signal::{killpg, Signal}, wait::WaitPidFlag, }, unistd::Pid, }; use tokio::{ process::{Child, ChildStderr, ChildStdin, ChildStdout}, task::spawn_blocking, }; pub(super) struct ChildImp { pgid: Pid, inner: Child, } impl ChildImp { pub(super) fn new(inner: Child) -> Self { let pid = inner .id() .expect("Command was reaped before we could read its PID") .try_into() .expect("Command PID > i32::MAX"); Self { pgid: Pid::from_raw(pid), inner, } } pub(super) fn take_stdin(&mut self) -> Option { self.inner.stdin.take() } pub(super) fn take_stdout(&mut self) -> Option { self.inner.stdout.take() } pub(super) fn take_stderr(&mut self) -> Option { self.inner.stderr.take() } pub fn inner(&mut self) -> &mut Child { &mut self.inner } pub fn into_inner(self) -> Child { self.inner } pub(super) fn signal_imp(&self, sig: Signal) -> Result<()> { killpg(self.pgid, sig).map_err(Error::from) } pub fn start_kill(&mut self) -> Result<()> { self.signal_imp(Signal::SIGKILL) } pub fn id(&self) -> Option { self.inner.id() } fn wait_imp(pgid: i32, flag: WaitPidFlag) -> Result>> { // Wait for processes in a loop until every process in this // process group has exited (this ensures that we reap any // zombies that may have been created if the parent exited after // spawning children, but didn't wait for those children to // exit). let mut parent_exit_status: Option = None; loop { // we can't use the safe wrapper directly because it doesn't // return the raw status, and we need it to convert to the // std's ExitStatus. let mut status: i32 = 0; match unsafe { libc::waitpid(-pgid, &mut status as *mut libc::c_int, flag.bits()) } { 0 => { // Zero should only happen if WNOHANG was passed in, // and means that no processes have yet to exit. return Ok(ControlFlow::Continue(())); } -1 => { match Errno::last() { Errno::ECHILD => { // No more children to reap; this is a // graceful exit. return Ok(ControlFlow::Break(parent_exit_status)); } errno => { return Err(Error::from(errno)); } } } pid => { // *A* process exited. Was it the parent process // that we started? If so, collect the exit signal, // otherwise we reaped a zombie process and should // continue in the loop. if pgid == pid { parent_exit_status = Some(ExitStatus::from_raw(status)); } else { // Reaped a zombie child; keep looping. } } }; } } pub async fn wait(&mut self) -> Result { const MAX_RETRY_ATTEMPT: usize = 10; // Always wait for parent to exit first. // // It's likely that all its children has already exited and reaped by // the time the parent exits. let status = self.inner.wait().await?; let pgid = self.pgid.as_raw(); // Try reaping all children, if there are some that are still alive after // several attempts, then spawn a blocking task to reap them. for retry_attempt in 1..=MAX_RETRY_ATTEMPT { if Self::wait_imp(pgid, WaitPidFlag::WNOHANG)?.is_break() { break; } else if retry_attempt == MAX_RETRY_ATTEMPT { spawn_blocking(move || Self::wait_imp(pgid, WaitPidFlag::empty())).await??; } } Ok(status) } pub fn try_wait(&mut self) -> Result> { match Self::wait_imp(self.pgid.as_raw(), WaitPidFlag::WNOHANG)? { ControlFlow::Break(res) => Ok(res), ControlFlow::Continue(()) => self.inner.try_wait(), } } } impl crate::UnixChildExt for ChildImp { fn signal(&self, sig: Signal) -> Result<()> { self.signal_imp(sig) } } ``` -------------------------------- ### fn group_output(&mut self) -> Result Source: https://docs.rs/command-group/latest/command_group/stdlib/trait.CommandGroup.html Executes the command as a child process group, waiting for it to finish and collecting all of its output. By default, stdout and stderr are captured (and used to provide the resulting output). Stdin is not inherited from the parent and any attempt by the child process to read from the stdin stream will result in the stream immediately closing. On Windows, this creates a job object instead of a POSIX process group. ```APIDOC ## fn group_output(&mut self) -> Result ### Description Executes the command as a child process group, waiting for it to finish and collecting all of its output. By default, stdout and stderr are captured (and used to provide the resulting output). Stdin is not inherited from the parent and any attempt by the child process to read from the stdin stream will result in the stream immediately closing. On Windows, this creates a job object instead of a POSIX process group. ### Method Provided method ### Signature fn group_output(&mut self) -> Result ### Parameters - **self** (&mut self) - Required - The mutable reference to the command. ### Returns - **Result** - A result containing the output of the command. ### Example ```rust use std::process::Command; use std::io::{self, Write}; use command_group::CommandGroup; let output = Command::new("/bin/cat") .arg("file.txt") .group_output() .expect("failed to execute process"); println!("status: {}", output.status); io::stdout().write_all(&output.stdout).unwrap(); io::stderr().write_all(&output.stderr).unwrap(); assert!(output.status.success()); ``` ``` -------------------------------- ### CommandGroupBuilder::spawn (for std::process::Command) Source: https://docs.rs/command-group/latest/command_group/builder/struct.CommandGroupBuilder.html Executes the command as a child process group, returning a handle to it. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```APIDOC ## CommandGroupBuilder::spawn (for std::process::Command) ### Description Executes the command as a child process group, returning a handle to it. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ### Method spawn ### Signature pub fn spawn(&mut self) -> Result ### Parameters None ### Return Value Result - A handle to the spawned child process group. ### Example ```rust use std::process::Command; use command_group::CommandGroup; Command::new("ls") .group() .spawn() .expect("ls command failed to start"); ``` ``` -------------------------------- ### Try wait for process group Source: https://docs.rs/command-group/latest/command_group/struct.GroupChild.html Attempts to collect the exit status without blocking, falling back to wait if not ready. ```rust use std::process::Command; use command_group::CommandGroup; let mut child = Command::new("ls").group_spawn().unwrap(); match child.try_wait() { Ok(Some(status)) => println!("exited with: {}", status), Ok(None) => { println!("status not ready yet, let's really wait"); let res = child.wait(); println!("result: {:?}", res); } Err(e) => println!("error attempting to wait: {}", e), } ``` -------------------------------- ### Set non-blocking mode on non-Linux Unix systems Source: https://docs.rs/command-group/latest/src/command_group/stdlib/child/unix.rs.html Configures a file descriptor to non-blocking mode using fcntl for non-Linux Unix platforms. ```rust #[cfg(not(target_os = "linux"))] fn set_nonblocking(fd: RawFd, nonblocking: bool) -> Result<()> { use nix::fcntl::{fcntl, FcntlArg, OFlag}; let mut flags = OFlag::from_bits_truncate(fcntl(fd, FcntlArg::F_GETFL)?); flags.set(OFlag::O_NONBLOCK, nonblocking); fcntl(fd, FcntlArg::F_SETFL(flags)) .map_err(Error::from) .map(drop) } ``` -------------------------------- ### AsyncGroupChild::wait_with_output implementation Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Implementation of wait_with_output for AsyncGroupChild. It drops stdin, reads stdout and stderr concurrently using tokio::try_join!, and waits for the child process. Returns an Output containing status, stdout, and stderr. ```rust pub async fn wait_with_output(mut self) -> Result { drop(self.imp.take_stdin()); let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); match (self.imp.take_stdout(), self.imp.take_stderr()) { (None, None) => {} (Some(mut out), None) => { out.read_to_end(&mut stdout).await?; } (None, Some(mut err)) => { err.read_to_end(&mut stderr).await?; } (Some(mut out), Some(mut err)) => { // TODO: replace with futures crate usage // and drop macros feature from tokio tokio::try_join!(out.read_to_end(&mut stdout), err.read_to_end(&mut stderr),)?; } } let status = self.imp.wait().await?; Ok(Output { status, stdout, stderr, }) } ``` -------------------------------- ### Spawn a synchronous command group Source: https://docs.rs/command-group/latest/command_group/builder/struct.CommandGroupBuilder.html Basic usage of `CommandGroupBuilder::spawn` for a synchronous `std::process::Command`. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```rust use std::process::Command; use command_group::CommandGroup; Command::new("ls") .group() .spawn() .expect("ls command failed to start"); ``` -------------------------------- ### AsyncGroupChild::start_kill Source: https://docs.rs/command-group/latest/command_group/struct.AsyncGroupChild.html Attempts to force the child to exit without waiting for the request to take effect. Equivalent to sending SIGKILL on Unix platforms. On Unix, a zombie process may remain; callers should ensure wait or try_wait is invoked. ```APIDOC ## AsyncGroupChild::start_kill ### Description Attempts to force the child to exit, but does not wait for the request to take effect. This is equivalent to sending a SIGKILL on Unix platforms. Note that on Unix platforms it is possible for a zombie process to remain after a kill is sent; to avoid this, the caller should ensure that either `child.wait().await` or `child.try_wait()` is invoked successfully. ### Method start_kill(&mut self) -> Result<()> ### Parameters - **self** (&mut AsyncGroupChild) - Required - The mutable reference to the AsyncGroupChild instance. ### Returns - **Result<()>** - Ok(()) if the kill request was sent successfully, or an error if the process group has already exited. ``` -------------------------------- ### CommandGroup::group_spawn Source: https://docs.rs/command-group/latest/src/command_group/stdlib.rs.html Executes the command as a child process group, returning a handle to it. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```APIDOC ## CommandGroup::group_spawn ### Description Executes the command as a child process group, returning a handle to it. By default, stdin, stdout, and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ### Method fn group_spawn(&mut self) -> Result ### Parameters None. ### Return Value - Result - A result containing a handle to the spawned child process group, or an error. ### Example ```rust use std::process::Command; use command_group::CommandGroup; Command::new("ls") .group_spawn() .expect("ls command failed to start"); ``` ``` -------------------------------- ### Wait with output Source: https://docs.rs/command-group/latest/command_group/struct.GroupChild.html Waits for the child to exit and collects all output from stdout/stderr. ```rust use std::process::{Command, Stdio}; use command_group::CommandGroup; let child = Command::new("/bin/cat") .arg("file.txt") .stdout(Stdio::piped()) .group_spawn() .expect("failed to execute child"); let output = child .wait_with_output() .expect("failed to wait on child"); assert!(output.status.success()); ``` -------------------------------- ### Signal with process group using group_spawn Source: https://docs.rs/command-group/latest/command_group/trait.UnixChildExt.html Usage of signal with a process group created via group_spawn. Sends SIGTERM to the child process group. ```rust use std::process::Command; use command_group::{CommandGroup, UnixChildExt, Signal}; let mut command = Command::new("yes"); if let Ok(mut child) = command.group_spawn() { child.signal(Signal::SIGTERM).expect("command wasn't running"); } else { println!("yes command didn't start"); } ``` -------------------------------- ### CommandGroupBuilder::kill_on_drop Source: https://docs.rs/command-group/latest/command_group/builder/struct.CommandGroupBuilder.html Configures whether the process group is killed when the builder is dropped. See tokio::process::Command::kill_on_drop for more details. ```APIDOC ## CommandGroupBuilder::kill_on_drop ### Description Configures whether the process group is killed when the builder is dropped. See tokio::process::Command::kill_on_drop for more details. ### Method kill_on_drop ### Signature pub fn kill_on_drop(&mut self, kill_on_drop: bool) -> &mut Self ### Parameters - **kill_on_drop** (bool) - Required - Whether to kill the process group when the builder is dropped. ### Return Value &mut Self - A mutable reference to the builder for chaining. ### Example No example provided in the source. ``` -------------------------------- ### Wait for child group exit with tokio::process::Command Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Spawns a command as a process group and waits for it to exit, printing a message when finished. Uses command_group::AsyncCommandGroup and tokio::process::Command. ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; let mut command = Command::new("ls"); if let Ok(mut child) = command.group_spawn() { child.wait().await.expect("command wasn't running"); println!("Child has finished its execution!"); } else { println!("ls command didn't start"); } ``` -------------------------------- ### Try wait for child group exit with tokio::process::Command Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Attempts to collect the exit status of a child process group without blocking. If not ready, falls back to waiting. Uses command_group::AsyncCommandGroup and tokio::process::Command. ```rust use tokio::process::Command; use command_group::AsyncCommandGroup; let mut child = Command::new("ls").group_spawn().unwrap(); match child.try_wait() { Ok(Some(status)) => println!("exited with: {}", status), Ok(None) => { println!("status not ready yet, let's really wait"); let res = child.wait().await; println!("result: {:?}", res); } Err(e) => println!("error attempting to wait: {}", e), } ``` -------------------------------- ### fn group_status(&mut self) -> Result Source: https://docs.rs/command-group/latest/command_group/stdlib/trait.CommandGroup.html Executes a command as a child process group, waiting for it to finish and collecting its status. By default, stdin, stdout and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ```APIDOC ## fn group_status(&mut self) -> Result ### Description Executes a command as a child process group, waiting for it to finish and collecting its status. By default, stdin, stdout and stderr are inherited from the parent. On Windows, this creates a job object instead of a POSIX process group. ### Method Provided method ### Signature fn group_status(&mut self) -> Result ### Parameters - **self** (&mut self) - Required - The mutable reference to the command. ### Returns - **Result** - A result containing the exit status of the command. ### Example ```rust use std::process::Command; use command_group::CommandGroup; let status = Command::new("/bin/cat") .arg("file.txt") .group_status() .expect("failed to execute process"); println!("process finished with: {}", status); assert!(status.success()); ``` ``` -------------------------------- ### Implementation of CommandGroup for std::process::Command Source: https://docs.rs/command-group/latest/src/command_group/stdlib.rs.html The trait implementation for `std::process::Command` and its `group` method that creates a new `CommandGroupBuilder`. ```rust impl CommandGroup for Command { fn group(&mut self) -> CommandGroupBuilder<'_, Command> { CommandGroupBuilder::new(self) } } ``` -------------------------------- ### wait_with_output Source: https://docs.rs/command-group/latest/src/command_group/tokio/child.rs.html Simultaneously waits for the child process group to exit and collects all remaining output on the stdout/stderr handles, returning an Output instance. ```APIDOC ## wait_with_output ### Description Simultaneously waits for the child process group to exit and collects all remaining output on the stdout/stderr handles, returning an Output instance. ### Method wait_with_output ### Signature pub async fn wait_with_output(&mut self) -> Result ### Parameters - **self** (&mut Self) - Required - Mutable reference to the child process group. ### Returns - **Result** - Ok(output) containing the exit status and collected output, or an error otherwise. ### Notes - See the Tokio documentation for `Child::wait_with_output` for more details. ``` -------------------------------- ### UnixChildExt trait implementation Source: https://docs.rs/command-group/latest/src/command_group/stdlib/child/unix.rs.html Defines and implements the UnixChildExt trait to allow sending signals to child processes. ```rust pub trait UnixChildExt { fn signal(&self, sig: Signal) -> Result<()>; } impl UnixChildExt for ChildImp { fn signal(&self, sig: Signal) -> Result<()> { self.signal_imp(sig) } } ``` -------------------------------- ### fn group(&mut self) -> CommandGroupBuilder<'_, Command> Source: https://docs.rs/command-group/latest/command_group/stdlib/trait.CommandGroup.html Converts the implementor into a CommandGroupBuilder, which can be used to set flags that are not available on the Command type. ```APIDOC ## fn group(&mut self) -> CommandGroupBuilder<'_, Command> ### Description Converts the implementor into a `CommandGroupBuilder`, which can be used to set flags that are not available on the `Command` type. ### Method Required method ### Signature fn group(&mut self) -> CommandGroupBuilder<'_, Command> ### Parameters - **self** (&mut self) - Required - The mutable reference to the command. ### Returns - **CommandGroupBuilder<'_, Command>** - A builder for configuring process group options. ``` -------------------------------- ### Crate imports and platform module declarations in stdlib.rs Source: https://docs.rs/command-group/latest/src/command_group/stdlib.rs.html The initial part of the module imports `std::process` types, the `CommandGroupBuilder`, and `GroupChild` from the crate, re-exports `ErasedChild`, and conditionally declares Windows, Unix, and internal child/erased modules. ```rust use std::{ io::Result, process::{Command, ExitStatus, Output}, }; use crate::{builder::CommandGroupBuilder, GroupChild}; #[doc(inline)] pub use erased::ErasedChild; #[cfg(target_family = "windows")] mod windows; #[cfg(target_family = "unix")] mod unix; pub(crate) mod child; pub(crate) mod erased; ```