PackageTrack
Sign in Get early access

fork

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

0.10.0 6.1M downloads/mo #4118 most downloaded on crates.io immortal/fork

What this package is like to depend on

Last release 1 months ago

18 Jul 2026

Release timing varies

gaps range from 2 weeks to 1.3 years

Some releases are documented

notes for 11 of 35 stable releases

Nothing withdrawn

no release was ever pulled

7 years old

35 releases · first in 2019

10 releases in the last 12 months

see the full history below

Release timeline

35 releases · Oct 2019 to Jul 2026
2020 2021 2022 2023 2024 2025 2026
Release Pre-release

Releases

latest 35
  1. 0.10.0 18 Jul 2026
    Release notes

    Full Changelog: 0.9.1...0.10.0

    Open source →
    Release notes

    Added

    • acquire_subreaper, release_subreaper, and is_subreaper let a supervisor that is not PID 1 adopt orphaned descendants so the wait_any_* families can observe and reap their terminal state. Acquisition and release are idempotent. The role is process-global, is not inherited across fork, and is preserved across exec.
    • Linux support via PR_SET_CHILD_SUBREAPER/PR_GET_CHILD_SUBREAPER and FreeBSD support via PROC_REAP_ACQUIRE/PROC_REAP_RELEASE/PROC_REAP_STATUS. All three functions return ErrorKind::Unsupported on other targets.
    • Standalone harness-free lifecycle contract covering state transitions, fork non-inheritance, exec preservation, and orphan adoption.

    Safety

    • Platform system calls are isolated in a private module and every failure is converted through io::Error::last_os_error.
    • FreeBSD acquisition normalizes EBUSY (already a reaper) to success, and is_subreaper excludes PID 1's implicit REAPER_STATUS_REALINIT role so the query reflects only an explicitly acquired attribute, matching Linux.
    • Adoption observes and reaps orphaned descendants only; it does not enumerate or signal still-running descendants that escape an owned process group, so wait_any_* may report PIDs the supervisor did not spawn directly.
    Open source →
  2. 0.9.1 14 Jul 2026
    Release notes

    Full Changelog: 0.9.0...0.9.1

    Open source →
    Release notes

    Added

    • Additive ProcessGroupGuard for fail-closed process-group owner loss, with a startup anchor, explicit disarm, bounded helper cleanup, descriptor isolation, running/stopped workload contracts, and an explicit session-escape boundary.
    • Signal-safe disarm over a CLOEXEC Unix socket with MSG_NOSIGNAL, plus an adaptive bounded helper wait which avoids both fixed startup delay and busy polling.
    • Standalone single-threaded contracts which kill the owning broker with SIGKILL before and after workload startup, proving that helpers and the workload disappear without Rust destructors, async cleanup, or inherited descriptors.

    Safety

    • Helper cleanup never signals a numeric PID after a terminal event was reaped or direct-child ownership can no longer be proven, preventing cleanup from targeting a reused PID.
    • Workload TERM, STOP, CONT, and KILL delivery cannot disable the out-of-group helper. Invalid deadlines, failed exec, dead or stopped helpers, closed standard descriptors, and deliberate session escape have bounded regression contracts.
    • The API documents exclusive child-reaping ownership and immediate disarm after the final group member exits, because portable Unix cannot pin an empty numeric process-group ID against reuse.
    • Descriptor scan bounds now use checked conversions across signed FreeBSD and unsigned Linux rlim_t definitions.
    • Process tests own and remove their temporary files, suppress core generation for intentional SIGABRT cases, and fail CI if an artifact or test process survives the suite.

    Compatibility

    • This release only adds public API. Existing 0.9.0 callers remain source compatible.
    Open source →
  3. 0.9.0 13 Jul 2026
    Release notes

    Full Changelog: 0.8.0...0.9.0

    Open source →
    Release notes

    Added

    • Checked positive ProcessId and ProcessGroupId types.
    • fork_process() and ProcessFork for a typed parent-side fork result.
    • Explicit process-group creation, joining, inspection, and signal delivery.
    • Nonzero Signal with portable supervisor signal constants; signal zero is not representable.
    • Typed ChildEvent::{Exited, Signalled, Stopped, Continued} collection through blocking and nonblocking child-specific and any-child wait functions.
    • Serial native lifecycle tests covering exit, stop/continue, signal delivery, process groups, event draining, cleanup, and EINTR retry.
    • Native FreeBSD lifecycle CI (latest release) alongside Linux and macOS.
    • Owned close-on-exec Pipe and SocketPair primitives for broker IPC and exec-status handshakes, including descriptor flag and data-flow tests.
    • Additive PreparedCommand fork/exec API with precomputed arguments and environment, bounded startup handshakes, explicit process groups, collision- safe descriptor map/inherit/close actions, numeric identity transitions, and unintended-descriptor closure.
    • Public API compatibility CI against the published 0.8.0 crate.
    • Additive checked double-fork daemon startup with a bounded readiness/failure channel, preserved descriptors, explicit stdio policy, exact startup stages, and residual cleanup ownership.
    • Default child signal-state reset for prepared exec and checked daemon paths, with explicit opt-in inheritance.
    • Regression tests pinning the exact portable Signal constant values and the behavioral compatibility of the pre-broker fork/waitpid/waitpid_nohang path, plus a runnable process_broker example.
    Open source →
  4. 0.8.0 13 Jun 2026
    Release notes

    Full Changelog: 0.7.0...0.8.0

    Open source →
    Release notes

    Added

    • wait_any() and wait_any_nohang() - Add non-breaking wrappers around waitpid(-1, ...) for supervisor-style process management.
      • wait_any() blocks until any child terminates and returns (pid, status).
      • wait_any_nohang() checks for any terminated child without blocking and returns Ok(Some((pid, status))) or Ok(None).
      • Existing waitpid() and waitpid_nohang() signatures are unchanged.
    • Checked daemon startup example - Added checked_daemon_pattern.rs, demonstrating how to use a pre-fork pipe with the existing low-level primitives when the launching process must observe setup success or failure.

    Improved

    • Clarified supervisor identity guidance: HashMap remains appropriate for tracking multiple live children, but long-lived restart/history state should use an application-owned monotonic id with PID as the current live lookup handle. Updated supervisor examples to show this pattern.
    • Documented the daemon(false, false) startup pitfall: relative paths are resolved from /, and stdio/panic diagnostics are discarded through /dev/null. PID/log/config paths should generally be absolute, or startup should use nochdir = true, noclose = true, or a readiness pipe when appropriate.

    Fixed

    • Corrected README guidance for close_fd()/close() on EINTR: the safe portable behavior is to call close() once and treat EINTR as success, not to retry.
    Open source →
  5. 0.7.0 09 Mar 2026
    Release notes

    Full Changelog: 0.6.0...0.7.0

    Open source →
    Release notes

    Fixed

    • close() no longer retries on EINTR — Previously, the internal close_retry helper looped on EINTR, which is unsafe on all modern Unixes:
      • Linux: close() always releases the fd before returning EINTR. Retrying can close an unrelated fd opened by another thread between attempts.
      • FreeBSD / macOS / other BSDs: The fd state after close() + EINTR is unspecified per POSIX 2008+ (Austin Group defect 529), so retrying is equally dangerous.
      • The function has been renamed from close_retry to close_once and now calls close() exactly once, treating both EINTR and EBADF as success — the same approach used by Rust's std::fs::File::drop(), Go's runtime, and glibc internals.
      • Note: open() and dup2() in redirect_stdio() still correctly retry on EINTR, as those calls do not release resources on interruption.

    Improved

    • daemon() return value documentation — Made it prominent that daemon() only ever returns Ok(Fork::Child) or Err(...) to the caller; Ok(Fork::Parent(_)) is never returned because both parent processes call _exit(0) internally. Added recommended if let and match usage patterns to the doc comment. Updated #[must_use] message to reflect this guarantee.

    Code Quality

    • Added test_daemon_never_returns_parent integration test confirming Fork::Parent is unreachable
    • Renamed test_close_retry_ok_and_ebadf to test_close_once_ok_and_ebadf
    • Replaced fragile tty command string-matching in test_daemon_no_controlling_terminal with portable open("/dev/tty") check (works reliably across Linux, macOS, and BSDs)
    • Replaced fixed 100ms sleep in test_getppid_after_parent_exits with a retry loop (up to 1s), preventing flaky failures on slow CI systems
    • Updated tests README to reflect new and renamed tests
    Open source →
  6. 0.6.0 06 Dec 2025
    Release notes

    Full Changelog: 0.5.0...0.6.0

    Open source →
    Release notes

    Breaking Changes

    • getpgrp() signature changed - Now returns libc::pid_t directly instead of io::Result<libc::pid_t>
      • getpgrp() always succeeds per POSIX specification and cannot fail
      • Migration guide:
        • Change getpgrp()? to getpgrp()
        • Change getpgrp().expect("...") to getpgrp()
        • Change match getpgrp() { Ok(pgid) => ... } to let pgid = getpgrp();
      • Rationale: Aligns with POSIX.1 specification and matches getpid()/getppid() patterns
      • Verified on Linux, macOS, FreeBSD, OpenBSD per POSIX.1 specification
      • Updated all tests and documentation to reflect this guarantee

    Improved

    • Enhanced documentation - Comprehensive improvements to library documentation
      • Added "Common Patterns" section with practical examples:
        • Process supervisor using HashMap with Fork
        • Inter-process communication via pipes
        • Daemon with PID file creation
      • Added "Safety and Best Practices" guidelines
      • Added detailed "Common Pitfalls and Safety Considerations" to fork():
        • Mutexes and locks (deadlock risks)
        • File descriptors (shared state issues)
        • Signal handlers (inheritance behavior)
        • Async-signal-safety between fork and exec
        • Memory usage (copy-on-write behavior)
      • Enhanced Fork enum documentation with helper method examples
      • Added "Platform Compatibility" information
    • Test quality improvements
      • Replaced deprecated signal() with sigaction() in EINTR tests
      • More portable signal handling for cross-platform compatibility
      • Renamed test_getpgrp_returns_io_error_type to test_getpgrp_returns_pid_type
      • Updated test README to reflect current test descriptions

    Fixed

    • Documentation warnings - Resolved doctest warnings about main function wrapping
    • EINTR resilience - close_fd and redirect_stdio now retry on EINTR for close/open/dup2, preventing spurious failures under signal-heavy conditions on Linux, macOS, and BSD
    • Daemon exit safety - Replaced std::process::exit in post-fork parents with libc::_exit to avoid running non-async-signal-safe destructors, preventing undefined behavior between fork() and exec()

    Code Quality

    • Modernized C string handling - Replaced runtime CString::new() allocations with compile-time c"" string literals (Rust 2024 feature)
      • chdir() now uses c"/" instead of CString::new("/")
      • redirect_stdio() now uses c"/dev/null" instead of CString::new("/dev/null")
      • Benefits: Eliminated dead error handling code, zero runtime overhead, compile-time validation
      • No API changes, fully backward compatible
    • Enhanced code clarity - Added clarifying comments to redirect_stdio() error handling logic explaining conditional cleanup of file descriptors
    • Comprehensive test coverage - Added 12 dedicated tests for chdir() function (346 lines)
      • Tests idempotent behavior, process isolation, concurrent usage
      • Validates modern c"" string literal implementation
      • Tests integration with setsid() (daemon pattern)
      • Total test count increased from 107 to 119 tests
    Open source →
  7. 0.5.0 05 Dec 2025
    Release notes

    Breaking Changes

    • waitpid() return type changed - Now returns io::Result<libc::c_int> instead of io::Result<()>
      • Returns the raw status code for inspection with WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, etc.
      • Migration: Change waitpid(pid)? to let status = waitpid(pid)?; assert!(WIFEXITED(status));
      • Enables proper exit code checking and signal detection
      • See updated examples in documentation

    Added

    • Fork helper methods - Added convenience methods to Fork enum
      • is_parent() - Check if this is the parent process
      • is_child() - Check if this is the child process
      • child_pid() - Get child PID if parent, otherwise None
    • Hash trait - Fork now derives Hash, enabling use in HashMap and HashSet
      • Useful for process supervisors and tracking multiple children
      • Examples: supervisor.rs and supervisor_advanced.rs
    • must_use attributes - Added #[must_use] to critical functions to prevent accidental misuse
      • fork() - Must check if parent or child
      • daemon() - Must check daemon result
      • setsid() - Must use session ID
      • getpgrp() - Must use process group ID
    • waitpid_nohang() function - Non-blocking variant of waitpid()
      • Returns Ok(Some(status)) if child has exited
      • Returns Ok(None) if child is still running
      • Essential for process supervisors and event loops
      • Enables polling patterns without blocking
      • Includes 7 comprehensive tests
    • PID helper functions - Convenience wrappers for getting process IDs
      • getpid() - Get current process ID (always succeeds, hides unsafe)
      • getppid() - Get parent process ID (always succeeds, hides unsafe)
    • Status macro re-exports - Convenient access to status inspection macros
      • Re-export WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG from libc
      • Users can now use fork::{waitpid, WIFEXITED, WEXITSTATUS} instead of separate libc import
    • Comprehensive test suite - Added extensive tests covering critical edge cases
      • tests/waitpid_tests.rs - Exit codes, signals, error handling, and non-blocking waits
      • tests/error_handling_tests.rs - Error paths and type verification
      • tests/pid_tests.rs - PID helper functions (getpid, getppid)
      • tests/status_macro_tests.rs - Status macro re-exports

    Improved

    • Performance - Added #[inline] hints to thin wrapper functions (chdir, setsid, getpgrp, getpid, getppid)
    • Documentation - Enhanced with comprehensive examples and safety considerations
      • Added doc test for setsid() - Session creation example
      • Added doc test for getpgrp() - Process group query example
      • Added doc test for getpid() - Current PID example
      • Added doc test for getppid() - Parent PID example
      • Enhanced fork() with safety considerations (file descriptors, mutexes, async-signal-safety, signals, memory)
      • Enhanced waitpid() with status inspection examples
      • Added waitpid_nohang() with polling patterns and process supervisor examples
    • Daemon correctness - daemon() now performs the full double-fork, exiting the intermediate session leader so only the daemon continues
      • Docs clarified the numbered double-fork stages
      • Examples updated (example_daemon.rs, example_touch_pid.rs) to reflect that only the daemon process returns Fork::Child
    • waitpid robustness - Automatic retry on EINTR (signal interruption)
      • Takes pid_t instead of i32 for better type safety
      • Returns raw status code enabling exit code inspection and signal detection
    • Code quality - Simplified daemon() implementation using ? operator consistently
    • Test coverage - Comprehensive coverage of all error paths and edge cases
      • Error handling: Invalid PID (ECHILD), double-wait, session leader errors (EPERM)
      • Exit codes: 0, 1, 42, 127, 255, and multiple code variations
      • Signal termination: SIGKILL, SIGTERM, SIGABRT detection
      • Status inspection: WIFEXITED vs WIFSIGNALED distinction
      • Fork helper methods: is_parent(), is_child(), child_pid()
      • io::Error type verification for all functions
    • CI - GitHub Actions now run tests serially (RUST_TEST_THREADS=1) and use the latest checkout action

    Examples

    • Added supervisor.rs - Basic process supervisor example
    • Added supervisor_advanced.rs - Production-ready supervisor with restart policies

    Migration Guide (0.4.x → 0.5.0)

    Before (0.4.x):

    match fork() {
        Ok(Fork::Parent(child)) => {
            waitpid(child)?; // Just waits, no status
        }
        Ok(Fork::Child) => exit(0),
        Err(e) => eprintln!("Fork failed: {}", e),
    }
    

    After (0.5.0):

    use libc::{WIFEXITED, WEXITSTATUS};
    
    match fork() {
        Ok(Fork::Parent(child)) => {
            let status = waitpid(child)?; // Returns status code
            assert!(WIFEXITED(status), "Child should exit normally");
            let exit_code = WEXITSTATUS(status);
            println!("Child exited with code: {}", exit_code);
        }
        Ok(Fork::Child) => exit(0),
        Err(e) => eprintln!("Fork failed: {}", e),
    }
    
    Open source →
  8. 0.4.0 03 Nov 2025
    Release notes

    Breaking Changes

    • Improved error handling - All functions now return io::Result instead of Result<T, i32>
      • fork() now returns io::Result<Fork> (was Result<Fork, i32>)
      • daemon() now returns io::Result<Fork> (was Result<Fork, i32>)
      • setsid() now returns io::Result<libc::pid_t> (was Result<libc::pid_t, i32>)
      • getpgrp() now returns io::Result<libc::pid_t> (was Result<libc::pid_t, i32>)
      • waitpid() now returns io::Result<()> (was Result<(), i32>)
      • chdir() now returns io::Result<()> (was Result<libc::c_int, i32>)
      • close_fd() now returns io::Result<()> (was Result<(), i32>)

    Major Improvements

    • Fixed file descriptor reuse bug (Issue #2)
      • Added redirect_stdio() function that redirects stdio to /dev/null instead of closing
      • Prevents silent file corruption when daemon opens files after stdio is closed
      • daemon() now uses redirect_stdio() instead of close_fd()
      • Matches industry standard implementations (libuv, systemd, BSD daemon(3))

    Benefits

    • Better error diagnostics - Errors now capture and preserve errno values
    • Rich error messages - Error display shows descriptive text (e.g., "Permission denied") instead of -1
    • Rust idioms - Integrates seamlessly with ? operator, anyhow, thiserror, and other error handling crates
    • Type safety - Can match on ErrorKind variants for specific error handling
    • Debugging - .raw_os_error() provides access to underlying errno when needed
    • Correctness - No more file descriptor reuse bugs that could corrupt data files

    Added

    • Fork enum now derives Debug, Clone, Copy, PartialEq, Eq for better usability
    • redirect_stdio() function - Safer alternative to close_fd()
    • Comprehensive tests for stdio redirection (tests/stdio_redirect_tests.rs)
      • Test demonstrating the fd reuse bug with close_fd()
      • Tests verifying redirect_stdio() prevents fd reuse
      • Tests confirming daemon() uses correct behavior

    Improved

    • Simplified close_fd() implementation using iterator pattern
    • Enhanced documentation with detailed error descriptions for all functions
    • Updated all examples to use proper error handling patterns
    • Added warnings to close_fd() documentation about fd reuse risks

    Security

    • CRITICAL FIX: daemon() no longer vulnerable to file descriptor reuse bugs
      • Previously, files opened after daemon(false, false) could get fd 0, 1, or 2
      • Any println!, eprintln!, or panic would write to those files, corrupting them
      • Now stdio is redirected to /dev/null, keeping fd 0,1,2 occupied
      • New files always get fd >= 3
    Open source →
  9. 0.3.1 26 Oct 2025
    Release notes
    • Added comprehensive test coverage for getpgrp() function
      • Unit tests in src/lib.rs (test_getpgrp, test_getpgrp_in_parent)
      • Integration test test_getpgrp_returns_process_group in tests/integration_tests.rs
    • Added coverage recipe to .justfile for generating coverage reports with grcov
    Open source →
  10. 0.3.0 19 Oct 2025
    Release notes

    Changed

    • Updated Rust edition from 2021 to 2024
    • Applied edition 2024 formatting standards (alphabetical import ordering)

    Added

    • Integration tests directory - Added tests/ directory with comprehensive integration tests
      • daemon_tests.rs - 5 tests for daemon functionality (detached process, nochdir, process groups, command execution, no controlling terminal)
      • fork_tests.rs - 7 tests for fork functionality (basic fork, parent-child communication, multiple children, environment inheritance, command execution, different PIDs, waitpid)
      • integration_tests.rs - 5 tests for advanced patterns (double-fork daemon, setsid, chdir, process isolation, getpgrp)

    Improved

    • Significantly expanded test coverage from 1 to 13 comprehensive unit tests
    • Added tests for all public API functions:
      • fork() - Multiple test scenarios including child execution
      • daemon() - Daemon pattern tested (double-fork with setsid)
      • waitpid() - Proper parent-child synchronization
      • setsid() - Session management and verification
      • getpgrp() - Process group queries
      • chdir() - Directory changes with verification
      • close_fd() - File descriptor management
    • Added real-world usage pattern tests:
      • Classic double-fork daemon pattern
      • Multiple sequential forks
      • Command execution in child processes
    • Improved test quality with proper cleanup and zombie process prevention
    • Enhanced CI/CD integration with LLVM coverage instrumentation
    • Total test count: 35 tests (13 unit + 17 integration + 5 doc tests)

    Fixed

    • Daemon tests now properly test the daemon pattern without calling daemon() directly (which would call exit(0) and terminate the test runner)

    Updated

    • GitHub Actions: codecov/codecov-action from v4 to v5
    Open source →
  11. 0.2.0 19 Jul 2024
    Release notes
    • Added waitpid(pid: i32)
    Open source →
  12. 0.1.23 01 Feb 2024

    Nothing published for this version

  13. 0.1.22 06 Jun 2023

    Nothing published for this version

  14. 0.1.21 12 Mar 2023

    Nothing published for this version

  15. 0.1.20 23 Aug 2022

    Nothing published for this version

  16. 0.1.19 11 Mar 2022

    Nothing published for this version

  17. 0.1.18 24 Oct 2020

    Nothing published for this version

  18. 0.1.17 20 Jul 2020

    Nothing published for this version

  19. 0.1.16 20 Jul 2020

    Nothing published for this version

  20. 0.1.15 22 Jun 2020

    Nothing published for this version

  21. 0.1.14 02 May 2020

    Nothing published for this version

  22. 0.1.13 17 Mar 2020

    Nothing published for this version

  23. 0.1.12 21 Feb 2020

    Nothing published for this version

  24. 0.1.11 21 Feb 2020

    Nothing published for this version

  25. 0.1.10 02 Dec 2019

    Nothing published for this version

  26. 0.1.9 28 Oct 2019

    Nothing published for this version

  27. 0.1.8 27 Oct 2019

    Nothing published for this version

  28. 0.1.7 27 Oct 2019

    Nothing published for this version

  29. 0.1.6 26 Oct 2019

    Nothing published for this version

  30. 0.1.5 26 Oct 2019

    Nothing published for this version

  31. 0.1.4 25 Oct 2019

    Nothing published for this version

  32. 0.1.3 25 Oct 2019

    Nothing published for this version

  33. 0.1.2 23 Oct 2019

    Nothing published for this version

  34. 0.1.1 23 Oct 2019

    Nothing published for this version

  35. 0.1.0 23 Oct 2019

    Nothing published for this version

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive