proses 0.1.1

Proses – Professional Secure Execution System
//! Classic Unix double-fork daemonization.
//!
//! Only `libc` is used for all syscalls so that this module has zero
//! dependency on any async runtime and can safely be called before Tokio
//! is ever created.

use std::io;

/// Double-fork daemonization.
///
/// ## Process tree after the call returns
///
/// ```text
/// original caller
/// ├── [fork #1] first child
/// │   ├── setsid()   — new session, no controlling terminal
/// │   └── [fork #2] grandchild  ← the actual daemon
/// │       ├── dup2 stdin/stdout/stderr → /dev/null
/// │       └── daemon_fn()
/// └── waitpid(first child) → returns normally to caller
/// ```
///
/// * **Original process** — waits for the first child (so it does not
///   become a zombie) then **returns normally**.  The `daemon_fn` closure
///   is dropped (not called) here.
///
/// * **First child** — calls `setsid(2)` to detach from the controlling
///   terminal, forks a second time, then exits immediately via `_exit(0)`
///   so that the grandchild is re-parented to `init` / `systemd`.
///
/// * **Grandchild** — the daemon proper: its standard file descriptors are
///   redirected to `/dev/null` so that stray reads/writes cannot interact
///   with a terminal, then `daemon_fn()` is invoked.
///
/// # Panics
///
/// Panics in the original process if `fork()` fails.
///
/// # Safety
///
/// This function **must** be called before any multi-threaded runtime
/// (Tokio, Rayon, …) is started.  Forking a multi-threaded process is
/// undefined behaviour.
pub fn spawn_daemon<F: FnOnce()>(daemon_fn: F) {
    // ── Fork #1 ───────────────────────────────────────────────────────────
    let pid1 = unsafe { libc::fork() };

    if pid1 < 0 {
        panic!("fork() #1 failed: {}", io::Error::last_os_error());
    }

    if pid1 > 0 {
        // ── Original process (parent) ─────────────────────────────────────
        // Reap the first child so it does not linger as a zombie.
        unsafe {
            let mut status: libc::c_int = 0;
            libc::waitpid(pid1, &mut status, 0);
        }
        // `daemon_fn` is intentionally *dropped* here — it must only run in
        // the grandchild.
        return;
    }

    // ── First child ───────────────────────────────────────────────────────
    // Become the leader of a brand-new session.  This severs the connection
    // to any controlling terminal inherited from the parent.
    if unsafe { libc::setsid() } < 0 {
        // Cannot recover; exit without running Rust destructors so we do not
        // flush/corrupt stdio buffers shared with the parent.
        unsafe { libc::_exit(1) };
    }

    // ── Fork #2 ───────────────────────────────────────────────────────────
    let pid2 = unsafe { libc::fork() };

    if pid2 < 0 {
        unsafe { libc::_exit(1) };
    }

    if pid2 > 0 {
        // First child exits immediately.  The grandchild is now an orphan
        // and will be re-parented to PID 1 (init / systemd), ensuring it
        // can never accidentally acquire a controlling terminal.
        // `_exit` is used (rather than `exit`) to avoid double-flushing
        // any stdio buffers inherited from the original process.
        unsafe { libc::_exit(0) };
    }

    // ── Grandchild — the actual daemon ────────────────────────────────────

    // Redirect the standard file descriptors to /dev/null so that any
    // accidental reads or writes do not interact with a terminal or pipe.
    unsafe {
        let dev_null = libc::open(b"/dev/null\0".as_ptr() as *const libc::c_char, libc::O_RDWR);

        if dev_null >= 0 {
            // It is fine if any of these dup2 calls fail — we are already
            // detached, and the daemon will soon open its own log files.
            libc::dup2(dev_null, libc::STDIN_FILENO);
            libc::dup2(dev_null, libc::STDOUT_FILENO);
            libc::dup2(dev_null, libc::STDERR_FILENO);

            // Close the temporary fd only if it is not one of the three
            // standard slots (which would have been installed above).
            if dev_null > libc::STDERR_FILENO {
                libc::close(dev_null);
            }
        }
    }

    // Hand control to the daemon entry point.
    //
    // In normal usage `daemon_fn` is `|| server::run()`, which is `-> !`
    // and never returns.  The `_exit` below is a safety net for any
    // `daemon_fn` that does return.
    daemon_fn();

    unsafe { libc::_exit(0) };
}