daemon_forge

Crates.iodaemon_forge
lib.rsdaemon_forge
version0.0.2
created_at2025-11-28 17:50:05.52854+00
updated_at2025-11-28 21:15:39.497952+00
descriptionA robust, cross-platform library for daemonizing Rust applications.
homepage
repositoryhttps://github.com/ninunez14/daemon_forge
max_upload_size
id1955809
size37,877
Nicolás Núñez (ninunez14)

documentation

README

DaemonForge

DaemonForge is a cross-platform library for creating system daemons (background services) in Rust. It abstracts away the low-level complexities of operating system process management, providing a safe, idiomatic, and ergonomic builder API.

This crate is suitable for learning and experimentation, but not recommended for serious or production projects.

Key Features

  • True Cross-Platform Support:
    • Unix/Linux: Implements the canonical daemonization routine (double-fork, setsid, umask, and signal handling).
    • Windows: Uses native "Detached Processes" and manages creation flags for true background execution without a console window.
  • Locking Mechanism:
    • Automatically prevents multiple instances of the same service from running simultaneously.
    • Utilizes flock (Unix) and Global Named Mutexes (Windows) for reliable exclusion.
  • Security First:
    • Secure environment variable clearing.
    • Support for privilege dropping (User/Group switching) and chroot jail on Unix systems.
  • Other features:
    • Panic Capture: Redirects stdout/stderr to log files, ensuring that panics and crashes are recorded instead of being lost.

Usage Examples

Linux/Unix Example

use daemon_forge::ForgeDaemon;
use std::fs::File;

fn main() {
    let stdout = File::create("/tmp/daemon.out").unwrap();
    let stderr = File::create("/tmp/daemon.err").unwrap();

    let daemon = ForgeDaemon::new()
        .pid_file("/tmp/test.pid")
        .working_directory("/tmp")
        .user("www-data") // Unix specific: drop privileges
        .group("www-data")
        .stdout(stdout)
        .stderr(stderr)
        .start();

    match daemon {
        Ok(_) => println!("Daemon started successfully"),
        Err(e) => eprintln!("Error starting daemon: {}", e),
    }
}

Windows Example

On Windows, it is highly recommended to set a .name() for your daemon. This creates a global mutex to ensure uniqueness.

use daemon_forge::ForgeDaemon;
use std::fs::File;

fn main() {
    // Use absolute paths on Windows for safety
    let stdout = File::create("C:\\Logs\\service.out").unwrap();
    let stderr = File::create("C:\\Logs\\service.err").unwrap();

    let daemon = ForgeDaemon::new()
        .name("MyUniqueService") // Creates "Global\DaemonForge_MyUniqueService" Mutex
        .pid_file("C:\\Logs\\service.pid")
        .working_directory("C:\\Logs")
        .stdout(stdout)
        .stderr(stderr)
        .start();

    match daemon {
        Ok(_) => println!("Service launched in background"),
        Err(e) => eprintln!("Critical Failure: {}", e),
    }
}

Advanced Configuration

You can execute a privileged_action before the process fully daemonizes. This is useful for tasks that require higher permissions (like binding to port 80) or for checking environment prerequisites.

# use daemon_forge::ForgeDaemon;
ForgeDaemon::new()
    .clear_env(true) // Clears inherited environment variables
    .env("API_KEY", "secret_value") // Sets explicit variables
    .privileged_action(|| {
        println!("Initializing resources before forking...");
        // If this returns Err, the daemon will abort startup.
        Ok("Initialization Done")
    });
Commit count: 0

cargo fmt