chiark / gitweb /
daemon: wip
[hippotat.git] / server / daemon.rs
index 4294edae5ab98cd8a77d328f4a0c98abfabc91f3..05252e704da2dc694f0f3b40834e601d093e36a1 100644 (file)
@@ -4,14 +4,19 @@
 
 #![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 {
 }
@@ -33,11 +38,16 @@ macro_rules! crashv { { $( $m:expr ),* $(,)? } => { {
   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]
@@ -45,31 +55,89 @@ impl<T> nix::Result<T> {
   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!");
+            
+
     }
   }
-*/
 }
+
+*/