1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use libc;
use std::process::exit;

pub enum Fork {
    Parent(libc::pid_t),
    Child,
}

// Upon successful completion, fork() returns a value of 0 to the child process
// and returns the process ID of the child process to the parent process.
// Otherwise, a value of -1 is returned to the parent process, no child process
// is created.
pub fn fork() -> Result<Fork, libc::pid_t> {
    let res = unsafe { libc::fork() };
    match res {
        -1 => Err(res),
        0 => Ok(Fork::Child),
        res => Ok(Fork::Parent(res)),
    }
}

// Upon successful completion, the setsid() system call returns the value of the
// process group ID of the new process group, which is the same as the process ID
// of the calling process. If an error occurs, setsid() returns -1
pub fn setsid() -> Result<libc::pid_t, libc::pid_t> {
    let res = unsafe { libc::setsid() };
    match res {
        -1 => Err(res),
        res => Ok(res),
    }
}

// The parent forks the child
// The parent exits
// The child calls setsid() to start a new session with no controlling terminals
// The child forks a grandchild
// The child exits
// The grandchild is now the daemon
pub fn daemon() -> Result<Fork, libc::pid_t> {
    match fork() {
        Ok(Fork::Parent(_)) => exit(0),
        Ok(Fork::Child) => match setsid() {
            Ok(_) => fork(),
            Err(n) => Err(n),
        },
        Err(n) => Err(n),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_fork() {
        match fork() {
            Ok(Fork::Parent(child)) => assert!(child > 0),
            Ok(Fork::Child) => println!("child process"),
            Err(_) => assert!(false),
        }
    }
}