Library for creating a new process detached from the controlling terminal (daemon) on Unix-like systems.
- ✅ Minimal - Small, focused library for process forking and daemonization
- ✅ Safe - Comprehensive test coverage (35 tests: 13 unit + 17 integration + 5 doc)
- ✅ Well-documented - Extensive documentation with real-world examples
- ✅ Unix-first - Built specifically for Unix-like systems (Linux, macOS, BSD)
- ✅ Edition 2024 - Uses latest Rust edition features
- Minimal library to daemonize, fork, double-fork a process
- daemon(3) has been
deprecated in macOS 10.5. By using
fork
andsetsid
syscalls, new methods can be created to achieve the same goal - Provides the building blocks for creating proper Unix daemons
Add fork
to your Cargo.toml
:
[dependencies]
fork = "0.3"
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};
match fork() {
Ok(Fork::Parent(child)) => {
println!("Parent process, child PID: {}", child);
}
Ok(Fork::Child) => {
println!("Child process");
}
Err(_) => println!("Fork failed"),
}
fork()
- Creates a new child processdaemon(nochdir, noclose)
- Creates a daemon using double-fork patternnochdir
: iffalse
, changes working directory to/
noclose
: iffalse
, redirects stdin/stdout/stderr to/dev/null
setsid()
- Creates a new session and sets the process group IDwaitpid(pid)
- Waits for child process to change stategetpgrp()
- Returns the process group IDchdir()
- Changes current directory to/
close_fd()
- Closes stdin, stdout, and stderr
See the documentation for detailed usage.
When using daemon(false, false)
, it will change directory to /
and close the standard file descriptors.
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 terminal- New
PGID = 48737
- Own process group
Process hierarchy:
1 - root (init/systemd)
└── 48738 myapp PGID - 48737
└── 48753 sleep PGID - 48737
The daemon()
function implements the classic double-fork pattern:
- First fork - Creates child process
- setsid() - Child becomes session leader
- Second fork - Grandchild is created (not a session leader)
- First child exits - Leaves grandchild orphaned
- Grandchild continues - As daemon (no controlling terminal)
This prevents the daemon from ever acquiring a controlling terminal.
The library has comprehensive test coverage:
- 13 unit tests in
src/lib.rs
- 17 integration tests in
tests/
directory - 5 documentation tests
Run tests:
cargo test
See tests/README.md
for detailed information about integration tests.
This library is designed for Unix-like operating systems:
- ✅ Linux
- ✅ macOS
- ✅ FreeBSD
- ✅ NetBSD
- ✅ OpenBSD
- ❌ Windows (not supported)
See the examples/
directory for more usage examples:
example_daemon.rs
- Daemon creationexample_pipe.rs
- Fork with pipe communicationexample_touch_pid.rs
- PID file creation
Run an example:
cargo run --example example_daemon
Contributions are welcome! Please ensure:
- All tests pass:
cargo test
- Code is formatted:
cargo fmt
- No clippy warnings:
cargo clippy -- -D warnings
- Documentation is updated
BSD 3-Clause License - see LICENSE file for details.