| Crates.io | fork |
| lib.rs | fork |
| version | 0.6.0 |
| created_at | 2019-10-23 09:08:09.031679+00 |
| updated_at | 2025-12-06 08:48:03.269384+00 |
| description | Library for creating a new process detached from the controlling terminal (daemon) |
| homepage | https://docs.rs/fork/latest/fork/ |
| repository | https://github.com/immortal/fork |
| max_upload_size | |
| id | 174826 |
| size | 227,647 |
Library for creating a new process detached from the controlling terminal (daemon) on Unix-like systems.
fork and setsid syscalls, new methods
can be created to achieve the same goalAdd fork to your Cargo.toml:
[dependencies]
fork = "0.6.0"
Or use cargo-add:
cargo add fork
use fork::{daemon, Fork};
use std::process::Command;
fn main() {
if let Ok(Fork::Child) = daemon(false, false) {
// This code runs in the daemon process
Command::new("sleep")
.arg("300")
.output()
.expect("failed to execute process");
}
}
use fork::{fork, Fork, waitpid, WIFEXITED, WEXITSTATUS};
match fork() {
Ok(Fork::Parent(child)) => {
println!("Parent process, child PID: {}", child);
// Wait for child and check exit status
match waitpid(child) {
Ok(status) => {
if WIFEXITED(status) {
println!("Child exited with code: {}", WEXITSTATUS(status));
}
}
Err(e) => eprintln!("waitpid failed: {}", e),
}
}
Ok(Fork::Child) => {
println!("Child process");
std::process::exit(0);
}
Err(e) => eprintln!("Fork failed: {}", e),
}
use fork::{fork, Fork};
match fork() {
Ok(Fork::Parent(child)) => {
println!("Spawned child with PID: {}", child);
}
Ok(Fork::Child) => {
println!("I'm the child!");
std::process::exit(0);
}
Err(err) => {
eprintln!("Fork failed: {}", err);
// Access the underlying errno if needed
if let Some(code) = err.raw_os_error() {
eprintln!("OS error code: {}", code);
}
}
}
fork() - Creates a new child processdaemon(nochdir, noclose) - Creates a daemon using double-fork pattern
nochdir: if false, changes working directory to /noclose: if false, redirects stdin/stdout/stderr to /dev/nullsetsid() - Creates a new session and sets the process group IDwaitpid(pid) - Waits for child process to change state (blocking; returns raw status; retries on signals)waitpid_nohang(pid) - Checks child status without blocking (returns Option<status>; for supervisors/polling)getpgrp() - Returns the process group IDgetpid() - Returns the current process IDgetppid() - Returns the parent process IDchdir() - Changes current directory to /redirect_stdio() - Redirects stdin/stdout/stderr to /dev/null (recommended)close_fd() - Closes stdin, stdout, and stderr (legacy, use redirect_stdio() instead)WIFEXITED(status) - Check if child exited normallyWEXITSTATUS(status) - Get exit code (if exited normally)WIFSIGNALED(status) - Check if child was terminated by signalWTERMSIG(status) - Get terminating signal (if signaled)See the documentation for detailed usage.
When using daemon(false, false), it will change directory to / and redirect stdin/stdout/stderr to /dev/null.
Test running:
$ cargo run
Use ps to check the process:
$ ps -axo ppid,pid,pgid,sess,tty,tpgid,stat,uid,%mem,%cpu,command | egrep "myapp|sleep|PID"
Output:
PPID PID PGID SESS TTY TPGID STAT UID %MEM %CPU COMMAND
1 48738 48737 0 ?? 0 S 501 0.0 0.0 target/debug/myapp
48738 48753 48737 0 ?? 0 S 501 0.0 0.0 sleep 300
Key points:
PPID == 1 - Parent is init/systemd (orphaned process)TTY = ?? - No controlling terminalPGID = 48737 - Own process groupProcess hierarchy:
1 - root (init/systemd)
└── 48738 myapp PGID - 48737
└── 48753 sleep PGID - 48737
The daemon() function implements the classic double-fork pattern:
This prevents the daemon from ever acquiring a controlling terminal.
daemon() uses _exit in the forked parents to avoid running non-async-signal-safe destructors between fork/exec (POSIX-safe on Linux/macOS/BSD).redirect_stdio() and close_fd() retry on EINTR for open/dup2/close to prevent spurious failures under signal-heavy workloads.redirect_stdio() over close_fd() so file descriptors 0,1,2 stay occupied (avoids accidental log/data corruption).Run tests:
cargo test
See tests/README.md for detailed information about integration tests.
This library is designed for Unix-like operating systems:
See the examples/ directory for more usage examples:
example_daemon.rs - Daemon creationexample_pipe.rs - Fork with pipe communicationexample_touch_pid.rs - PID file creationRun an example:
cargo run --example example_daemon
Contributions are welcome! Please ensure:
cargo testcargo fmtcargo clippy -- -D warningsBSD 3-Clause License - see LICENSE file for details.