Close

Daemonization

A project log for Adventures in Rust

I decided to find out what the deal is with the Rust programming language

ken-yapKen Yap 02/05/2024 at 02:030 Comments

Daemonization is the process of detaching from the invocation environment. For Linux processes that are to run as a system service, the most important things to do are to detach (and optionally reattach to files) the standard file descriptors stdin, stdout and stderr. Then it has to fork and the parent exits to the invoker, while the child continues on its own. (But things are slightly different if running under systemd, but that's a story for another log.)

In addition other actions are commonly taken, as this snippet of an example of the use of the Daemonize module shows:

    let daemonize = Daemonize::new()
        .pid_file("/tmp/test.pid") // Every method except `new` and `start`
        .chown_pid_file(true)      // is optional, see `Daemonize` documentation
        .working_directory("/tmp") // for default behaviour.
        .user("nobody")
        .group("daemon") // Group name
        .group(2)        // or group id.
        .umask(0o777)    // Set umask, `0o027` by default.
        .stdout(stdout)  // Redirect stdout to `/tmp/daemon.out`.
        .stderr(stderr)  // Redirect stderr to `/tmp/daemon.err`.
        .privileged_action(|| "Executed before drop privileges");

Yes, the cat is out of the bag, we let Daemonize do the heavy lifting. Even back in C days, the 7th commandment enjoined programmers to make use of the provided libraries instead of reinventing from scratch. In the case of Rust, one uses the crate ecosystem instead of libraries.

So here's the snippet from main.rs that does it all:

        if !debug {
                match Daemonize::new().start() {
                        Ok(_) => { },
                        Err(e) => { error!("Error {}", e); },
                };
        };

That's it. If we are debugging then we don't daemonize which helps strace and doesn't require watching the system log. We take all the defaults where none of the options are set. Naturally we need the imports at the top of the file.

extern crate daemonize;
use daemonize::Daemonize;

Discussions