Skip to content

Commit 0fbf6a3

Browse files
svenstaroMatheus Xavier
authored andcommitted
Fix and modernize docs a bit
1 parent 8a5ddfa commit 0fbf6a3

File tree

1 file changed

+109
-43
lines changed

1 file changed

+109
-43
lines changed

src/daemon.rs

Lines changed: 109 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,28 @@ use std::io::prelude::*;
66
use std::path::{Path, PathBuf};
77
use std::process::exit;
88

9-
use nix::sys::stat::{Mode, umask};
10-
#[cfg(not(target_os = "macos"))]
9+
use nix::sys::stat::{umask, Mode};
10+
#[cfg(target_os = "macos")]
1111
use nix::unistd::{
12-
chdir, chown, fork, ForkResult, getpid, Gid, initgroups, Pid, setgid, setsid,
13-
setuid, Uid,
12+
chdir, chown, close, dup2, fork, getpid, setgid, setsid, setuid, ForkResult, Gid, Pid, Uid,
1413
};
15-
#[cfg(target_os = "macos")]
14+
#[cfg(not(target_os = "macos"))]
1615
use nix::unistd::{
17-
chdir, chown, close, dup2, fork, ForkResult, getpid, Gid, Pid, setgid, setsid, setuid, Uid,
16+
chdir, chown, fork, getpid, initgroups, setgid, setsid, setuid, ForkResult, Gid, Pid, Uid,
1817
};
1918

20-
use crate::{DaemonError, Result};
21-
use crate::DaemonError::{InvalidGroup, InvalidUser};
22-
use crate::ffi::{PasswdRecord, set_proc_name};
19+
use crate::ffi::{set_proc_name, PasswdRecord};
2320
use crate::group::Group;
2421
use crate::stdio::{redirect_stdio, Stdio};
2522
use crate::user::User;
23+
use crate::DaemonError::{InvalidGroup, InvalidUser};
24+
use crate::{DaemonError, Result};
2625

2726
/// Basic daemonization consists of:
28-
/// forking the process, getting a new sid, setting the umask, changing the standard io streams
27+
/// forking the process, getting a new Session ID (sid), setting the umask, changing the standard io streams
2928
/// to files and finally dropping privileges.
3029
///
31-
/// Options:
32-
/// * user [optional], if set will drop privileges to the specified user **NOTE**: This library is strict and makes no assumptions if you provide a user you must provide a group
33-
/// * group [optional(**see note on user**)], if set will drop privileges to specified group
34-
/// * umask [optional], umask for the process defaults to 0o027
35-
/// * pid_file [optional], if set a pid file will be created default is that no file is created *
36-
/// * stdio [optional][**recommended**], this determines where standard output will be piped to since daemons have no console it's highly recommended to set this
37-
/// * stderr [optional][**recommended**], same as above but for standard error
38-
/// * chdir [optional], default is "/"
39-
/// * name [optional], set the daemon process name eg what shows in `ps` default is to not set a process name
40-
/// * before_fork_hook [optional], called before the fork with the current pid as argument
41-
/// * after_fork_parent_hook [optional], called after the fork with the parent pid as argument, can be used to continue some work on the parent after the fork (do not return)
42-
/// * after_fork_child_hook [optional], called after the fork with the parent and child pid as arguments
43-
///
44-
/// * See the setter function documentation for more details
45-
///
46-
/// **Beware there is no escalation back if dropping privileges**
30+
/// **NOTE:** Beware there is no escalation back if dropping privileges
4731
pub struct Daemon<'a> {
4832
pub(crate) chdir: PathBuf,
4933
pub(crate) pid_file: Option<PathBuf>,
@@ -84,7 +68,10 @@ impl<'a> Daemon<'a> {
8468
}
8569
}
8670

87-
/// This is a setter to give your daemon a pid file
71+
/// Give your daemon a pid file
72+
///
73+
/// By default, no pid file is created.
74+
///
8875
/// # Arguments
8976
/// * `path` - path to the file suggested `/var/run/my_program_name.pid`
9077
/// * `chmod` - if set a chmod of the file to the user and group passed will be attempted (**this being true makes setting an user and group mandatory**)
@@ -101,12 +88,16 @@ impl<'a> Daemon<'a> {
10188
}
10289

10390
/// The code will attempt to drop privileges with `setuid` to the provided user
91+
///
92+
/// **NOTE:** If you provide a user, you must also provide a group.
10493
pub fn user<T: Into<User>>(mut self, user: T) -> Self {
10594
self.user = Some(user.into());
10695
self
10796
}
10897

109-
/// The code will attempt to drop privileges with `setgid` to the provided group, you mut provide a group if you provide an user
98+
/// The code will attempt to drop privileges with `setgid` to the provided group
99+
///
100+
/// **NOTE:** You must provide a group if you provide an user.
110101
pub fn group<T: Into<Group>>(mut self, group: T) -> Self {
111102
self.group = Some(group.into());
112103
self
@@ -121,6 +112,7 @@ impl<'a> Daemon<'a> {
121112
}
122113
}
123114

115+
/// umask for the process, defaults to `0o027`
124116
pub fn umask(mut self, mask: u16) -> Self {
125117
self.umask = mask;
126118
self
@@ -131,38 +123,112 @@ impl<'a> Daemon<'a> {
131123
self
132124
}
133125

126+
/// Determines where standard output will be piped to since daemons have no console attached
127+
///
128+
/// It's highly recommended to set this to a file if you want to see output.
134129
pub fn stdout<T: Into<Stdio>>(mut self, stdio: T) -> Self {
135130
self.stdout = stdio.into();
136131
self
137132
}
138133

134+
/// Determines where standard error will be piped to since daemons have no console attached
135+
///
136+
/// It's highly recommended to set this to a file if you want to see output.
139137
pub fn stderr<T: Into<Stdio>>(mut self, stdio: T) -> Self {
140138
self.stderr = stdio.into();
141139
self
142140
}
143141

142+
/// Set the daemon process name
143+
///
144+
/// For example, this is what shows up in `ps`.
144145
pub fn name(mut self, name: &OsStr) -> Self {
145146
self.name = Some(OsString::from(name));
146147
self
147148
}
148149

150+
/// Hook called before the fork with the current pid as argument
149151
pub fn setup_pre_fork_hook(mut self, pre_fork_hook: fn(pid: i32)) -> Self {
150152
self.before_fork_hook = Some(pre_fork_hook);
151153
self
152154
}
153155

154-
pub fn setup_post_fork_parent_hook(mut self, post_fork_parent_hook: fn(parent_pid: i32, child_pid: i32) -> !) -> Self {
156+
/// Hook called after the fork with the parent pid as argument
157+
///
158+
/// Can be used to continue some work on the parent after the fork.
159+
/// **NOTE:** This hook must not return! For instance, you could call `std::process::exit()`.
160+
///
161+
/// # Examples
162+
///
163+
/// ```
164+
/// # use daemonize_me::Daemon;
165+
///
166+
/// fn post_fork_parent(ppid: i32, cpid: i32) -> ! {
167+
/// println!("Parent pid: {}, Child pid {}", ppid, cpid);
168+
/// println!("Exiting parent now");
169+
/// std::process::exit(0);
170+
/// }
171+
///
172+
/// let daemon = Daemon::new()
173+
/// .setup_post_fork_parent_hook(post_fork_parent)
174+
/// .start();
175+
/// ```
176+
pub fn setup_post_fork_parent_hook(
177+
mut self,
178+
post_fork_parent_hook: fn(parent_pid: i32, child_pid: i32) -> !,
179+
) -> Self {
155180
self.after_fork_parent_hook = Some(post_fork_parent_hook);
156181
self
157182
}
158183

159-
pub fn setup_post_fork_child_hook(mut self, post_fork_child_hook: fn(parent_pid: i32, child_pid: i32) -> ()) -> Self {
184+
/// Hook called after the fork with the parent and child pid as arguments
185+
///
186+
/// # Examples
187+
///
188+
/// ```
189+
/// # use daemonize_me::Daemon;
190+
///
191+
/// fn post_fork_child(ppid: i32, cpid: i32) {
192+
/// println!("Parent pid: {}, Child pid {}", ppid, cpid);
193+
/// println!("This hook is called in the child");
194+
/// // Child hook must return
195+
/// return
196+
/// }
197+
///
198+
/// let daemon = Daemon::new()
199+
/// .setup_post_fork_child_hook(post_fork_child)
200+
/// .start();
201+
/// ```
202+
pub fn setup_post_fork_child_hook(
203+
mut self,
204+
post_fork_child_hook: fn(parent_pid: i32, child_pid: i32) -> (),
205+
) -> Self {
160206
self.after_fork_child_hook = Some(post_fork_child_hook);
161207
self
162208
}
163209

164-
pub fn setup_post_init_hook(mut self, post_fork_child_hook: fn(ctx: Option<&'a dyn Any>),
165-
data: Option<&'a dyn Any>) -> Self {
210+
/// Hook called right before returning control to the caller, that is, right after `start()`
211+
///
212+
/// # Examples
213+
///
214+
/// ```
215+
/// # use std::any::Any;
216+
/// # use daemonize_me::Daemon;
217+
///
218+
/// fn after_init(_: Option<&dyn Any>) {
219+
/// println!("Initialized the daemon!");
220+
/// return
221+
/// }
222+
///
223+
/// let daemon = Daemon::new()
224+
/// .setup_post_init_hook(after_init, None)
225+
/// .start();
226+
/// ```
227+
pub fn setup_post_init_hook(
228+
mut self,
229+
post_fork_child_hook: fn(ctx: Option<&'a dyn Any>),
230+
data: Option<&'a dyn Any>,
231+
) -> Self {
166232
self.after_init_hook = Some(post_fork_child_hook);
167233
self.after_init_hook_data = data;
168234
self
@@ -221,7 +287,7 @@ impl<'a> Daemon<'a> {
221287
if let Some(proc_name) = &self.name {
222288
match set_proc_name(proc_name.as_ref()) {
223289
Ok(()) => (),
224-
Err(e) => return Err(e)
290+
Err(e) => return Err(e),
225291
}
226292
}
227293
// Set the umask either to 0o027 (rwxr-x---) or provided value
@@ -283,16 +349,16 @@ impl<'a> Daemon<'a> {
283349
Err(_) => return Err(DaemonError::SetGid),
284350
};
285351
#[cfg(not(target_os = "macos"))]
286-
{
287-
let u_cstr = match CString::new(uname) {
288-
Ok(cstr) => cstr,
289-
Err(_) => return Err(DaemonError::SetGid),
290-
};
291-
match initgroups(&u_cstr, gr) {
292-
Ok(_) => (),
293-
Err(_) => return Err(DaemonError::InitGroups),
294-
};
295-
}
352+
{
353+
let u_cstr = match CString::new(uname) {
354+
Ok(cstr) => cstr,
355+
Err(_) => return Err(DaemonError::SetGid),
356+
};
357+
match initgroups(&u_cstr, gr) {
358+
Ok(_) => (),
359+
Err(_) => return Err(DaemonError::InitGroups),
360+
};
361+
}
296362
match setuid(user) {
297363
Ok(_) => (),
298364
Err(_) => return Err(DaemonError::SetUid),

0 commit comments

Comments
 (0)