use daemonize::Daemonize;
use log::{debug, error};
use std::ffi::CString;
use std::fs::{self, OpenOptions};
use std::os::unix::prelude::OpenOptionsExt;
use std::path::Path;
use crate::server::configuration::ServerConf;
fn move_old_pid(path: &str) {
if !Path::new(path).exists() {
debug!("Old pid file does not exist");
return;
}
let new_path = format!("{path}.old");
match fs::rename(path, &new_path) {
Ok(()) => {
debug!("Old pid file renamed");
}
Err(e) => {
error!(
"failed to rename pid file from {} to {}: {}",
path, new_path, e
);
}
}
}
unsafe fn gid_for_username(name: &CString) -> Option<libc::gid_t> {
let passwd = libc::getpwnam(name.as_ptr() as *const libc::c_char);
if !passwd.is_null() {
return Some((*passwd).pw_gid);
}
None
}
#[cfg(unix)]
pub fn daemonize(conf: &ServerConf) {
let daemonize = Daemonize::new()
.umask(0o007) .pid_file(&conf.pid_file);
let daemonize = if let Some(error_log) = conf.error_log.as_ref() {
let err = OpenOptions::new()
.append(true)
.create(true)
.read(true)
.custom_flags(libc::O_NONBLOCK)
.open(error_log)
.unwrap();
daemonize.stderr(err)
} else {
daemonize
};
let daemonize = match conf.user.as_ref() {
Some(user) => {
let user_cstr = CString::new(user.as_str()).unwrap();
#[cfg(target_os = "macos")]
let group_id = unsafe { gid_for_username(&user_cstr).map(|gid| gid as i32) };
#[cfg(target_os = "freebsd")]
let group_id = unsafe { gid_for_username(&user_cstr).map(|gid| gid as u32) };
#[cfg(target_os = "linux")]
let group_id = unsafe { gid_for_username(&user_cstr) };
daemonize
.privileged_action(move || {
if let Some(gid) = group_id {
unsafe {
libc::initgroups(user_cstr.as_ptr() as *const libc::c_char, gid);
}
}
})
.user(user.as_str())
.chown_pid_file(true)
}
None => daemonize,
};
let daemonize = match conf.group.as_ref() {
Some(group) => daemonize.group(group.as_str()),
None => daemonize,
};
move_old_pid(&conf.pid_file);
daemonize.start().unwrap(); }