dmon 0.2.2

A library for building daemon processes.
Documentation
use nix::{
    fcntl::{self, OFlag},
    sys::stat::Mode,
    unistd::{dup2_stderr, dup2_stdin, dup2_stdout},
};
use std::{os::fd::OwnedFd, path::Path};

enum Rw {
    ReadOnly,
    WriteOnly,
}

use Rw::*;

pub fn redirect_stdin() -> Result<(), String> {
    let file = Path::new("/dev/null");

    open(file, ReadOnly)
        .and_then(|fd| dup2_stdin(fd).map_err(|err| err.to_string()))
        .map_err(|err| {
            format!("failed to redirect stdin to '{}': {err}", file.display())
        })
}

pub fn redirect_stdout(file: &Path) -> Result<(), String> {
    open(file, WriteOnly)
        .and_then(|fd| dup2_stdout(fd).map_err(|err| err.to_string()))
        .map_err(|err| {
            format!("failed to redirect stdout to '{}': {err}", file.display())
        })
}

pub fn redirect_stderr(file: &Path) -> Result<(), String> {
    open(file, WriteOnly)
        .and_then(|fd| dup2_stderr(fd).map_err(|err| err.to_string()))
        .map_err(|err| {
            format!("failed to redirect stderr to '{}': {err}", file.display())
        })
}

fn open(file: &Path, rw: Rw) -> Result<OwnedFd, String> {
    let flags = match rw {
        Rw::ReadOnly => OFlag::O_RDONLY,
        Rw::WriteOnly => OFlag::O_WRONLY | OFlag::O_APPEND,
    };

    fcntl::open(
        file,
        flags | OFlag::O_CREAT,
        Mode::S_IRUSR | Mode::S_IWUSR | Mode::S_IRGRP | Mode::S_IWGRP,
    )
    .map_err(|err| format!("failed to open file: {err}"))
}