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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! 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 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.