#![allow(unused_imports)]
#![allow(dead_code)]
+#![allow(unused_macros)]
use std::io::IoSlice;
+use std::os::unix::io::RawFd;
use extend::ext;
use nix::errno::*;
+use nix::fcntl::*;
use nix::unistd::*;
+use nix::sys::stat::*;
use nix::sys::uio::*;
+use nix::sys::wait::*;
pub struct Daemoniser {
}
crashv(&ms)
} } }
+macro_rules! cstr { { $b:tt } => {
+ CStr::from_bytes_with_nul(concat!($b b"\0"))
+ .unwrap_or_else(|| crashm("cstr not nul terminated?! bug!"))
+} }
+
fn crash(m: &str) -> ! {
crashv!(m)
}
-fn crashe(m: &str, en: Errno) -> ! {
- crashv!(m, ": ", en.desc())
+fn crashe(m: &str, e: Errno) -> ! {
+ crashv!(m, ": ", e.desc())
}
#[ext]
fn context(self, m: &str) -> T {
match self {
Ok(y) => y,
- Err(en) => crashe(m, en),
+ Err(e) => crashe(m, e),
}
}
}
-impl Daemoniser {
+fn mdup2(oldfd: RawFd, newfd: RawFd, what: &str) {
+ match dup2(oldfd, newfd) {
+ Ok(got) if got == newfd => { },
+ Ok(_) => crash("dup2 gave wrong return value"),
+ Err(e) => crashv!("dup2 ", what, ": ", e.desc()),
+ }
+}
/*
+#[throws(&'static str)]
+unsafe fn handle_child_status(child: Pid, report_pipe: RawFd,
+ wstatus: WaitStatus) -> ! {
+ let pid = wstatus.pid();
+
+
+
+
+impl Daemoniser {
pub fn phase1() -> Self {
unsafe {
- let (st_read, st_write) = pipe().context("pipe");
+ let null_fd = open(cstr!(b"/dev/null"), OFlag::O_RDWR, Mode::empty())
+ .context("open /dev/null");
+ mdup2(null_fd, 0);
+
+ let (st_rfd, st_wfd) = pipe().context("pipe");
mstch fork().context("fork (1)") {
- ForkResult::Parent { child } => {
- let _ = close(st_write);
- let mut buf = [0u8];
+ ForkResult::Parent { child: _ } => {
+ close(st_write).context("close st_write pipe");
+ let mut exitstatus = [0u8];
loop {
- match read(st_read, &mut buf) {
- Ok(0) => {
-
-
- let r =
+ match read(st_read, &mut exitstatus) {
+ Ok(0) => crash("startup/daemonisation failed"),
+ Ok(1) => {},
+ Err(e) if e == Errno::EINTR => continue,
+ Err(e) => crashe("read startup signal pipe", en);
+ }
+ }
+ libc::_exit(exitstatus);
},
ForkResult::Child => { }
+ }
+
+ close(st_read).context("close st_read pipe");
+
+ setsid().context("setsid");
+
+ match fork().context("fork (2)") {
+ ForkResult::Parent { child } => {
+ let wstatus = waitpid(child, None).context("waitpid startup");
+ match wstatus.pid() {
+ Some(got) if got == child => { },
+ Some(got) => crash("await child startup status: wrong pid"),
+ None => crash("await child startup status: no children?!"),
+ }
+
+ match wstatus {
+ WaitStatus::Exited(_, estatus) => {
+ let estatus: u8 = estatus.try_into()
+ .map_err(|_| "exit status out of range!")?;
+ match write(report_pipe, &estatus) {
+ Ok(1) => libc::_exit(0),
+ Ok(_) => crash("write child startup exit status: short write");
+ Err(e) => crashe("write child startup exit status", e);
+ },
+ }
+
+ WaitStatus::Signaled(pid, signal, coredump) => {
+ check_pid(pid);
+ crashv!("startup failed: died due to signal: ", signal.as_str(),
+ if coredump { " (core dumped)" } else { "" });
+ },
+
+ _ => crashm("child startup exit status was strange!");
+
+
}
}
-*/
}
+
+*/