Crate fork

Crate fork 

Source
Expand description

Library for creating a new process detached from the controlling terminal (daemon).

§Quick Start

use fork::{daemon, Fork};
use std::process::Command;

if let Ok(Fork::Child) = daemon(false, false) {
    Command::new("sleep")
        .arg("3")
        .output()
        .expect("failed to execute process");
}

§Common Patterns

§Process Supervisor

Track multiple worker processes:

use fork::{fork, Fork, waitpid_nohang, WIFEXITED};
use std::collections::HashMap;

let mut workers = HashMap::new();

// Spawn 3 workers
for i in 0..3 {
    match fork()? {
        result @ Fork::Parent(_) => {
            workers.insert(result, format!("worker-{}", i));
        }
        Fork::Child => {
            // Do work...
            std::thread::sleep(std::time::Duration::from_secs(5));
            std::process::exit(0);
        }
    }
}

// Monitor workers without blocking
while !workers.is_empty() {
    workers.retain(|child, name| {
        match waitpid_nohang(child.child_pid().unwrap()) {
            Ok(Some(status)) if WIFEXITED(status) => {
                println!("{} exited", name);
                false  // Remove from map
            }
            _ => true  // Keep in map
        }
    });
    std::thread::sleep(std::time::Duration::from_millis(100));
}

§Inter-Process Communication (IPC) via Pipe

use fork::{fork, Fork};
use std::io::{Read, Write};
use std::os::unix::io::FromRawFd;

// Create pipe before forking
let mut pipe_fds = [0i32; 2];
unsafe { libc::pipe(pipe_fds.as_mut_ptr()) };

match fork()? {
    Fork::Parent(_child) => {
        unsafe { libc::close(pipe_fds[1]) };  // Close write end

        let mut reader = unsafe { std::fs::File::from_raw_fd(pipe_fds[0]) };
        let mut msg = String::new();
        reader.read_to_string(&mut msg)?;
        println!("Received: {}", msg);
    }
    Fork::Child => {
        unsafe { libc::close(pipe_fds[0]) };  // Close read end

        let mut writer = unsafe { std::fs::File::from_raw_fd(pipe_fds[1]) };
        writer.write_all(b"Hello from child!")?;
        std::process::exit(0);
    }
}

§Daemon with PID File

use fork::{daemon, Fork, getpid};
use std::fs::File;
use std::io::Write;

if let Ok(Fork::Child) = daemon(false, false) {
    // Write PID file
    let pid = getpid();
    let mut file = File::create("/var/run/myapp.pid")?;
    writeln!(file, "{}", pid)?;

    // Run daemon logic...
    loop {
        // Do work
        std::thread::sleep(std::time::Duration::from_secs(60));
    }
}

§Safety and Best Practices

  • Always check fork result - Functions marked #[must_use] prevent accidents
  • Use waitpid() - Reap child processes to avoid zombies
  • Prefer redirect_stdio() - Safer than close_fd() for daemons
  • Fork early - Before creating threads, locks, or complex state
  • Close unused file descriptors - Prevent resource leaks in children
  • Handle signals properly - Consider what happens in both processes

§Platform Compatibility

This library uses POSIX system calls and is designed for Unix-like systems:

  • Linux (all distributions)
  • macOS (10.5+, replacement for deprecated daemon(3))
  • FreeBSD, OpenBSD, NetBSD
  • Other POSIX-compliant systems

Windows is not supported as it lacks fork() system call.

Enums§

Fork
Fork result

Functions§

WEXITSTATUS
WIFEXITED
WIFSIGNALED
WTERMSIG
chdir
Change dir to / see chdir(2)
close_fd
Close file descriptors stdin, stdout, stderr
daemon
The daemon function is for programs wishing to detach themselves from the controlling terminal and run in the background as system daemons.
fork
Create a new child process see fork(2)
getpgrp
Get the process group ID of the current process see getpgrp(2)
getpid
Get the current process ID see getpid(2)
getppid
Get the parent process ID see getppid(2)
redirect_stdio
Redirect stdin, stdout, stderr to /dev/null
setsid
Create session and set process group ID see setsid(2)
waitpid
Wait for process to change status see wait(2)
waitpid_nohang
Wait for process to change status without blocking see wait(2)