1#![feature(never_type)]
2
3use libredox::{error::{Error, Result}, errno::{EINTR, EIO}};
4
5#[must_use = "Daemon::ready must be called"]
6pub struct Daemon {
7 write_pipe: libc::c_int,
8}
9
10fn errno() -> libc::c_int {
11 unsafe { libc::__errno_location().read() }
12}
13
14impl Daemon {
15 pub fn new<F: FnOnce(Daemon) -> !>(f: F) -> Result<!> {
16 let mut pipes = [0; 2];
17
18 match unsafe { libc::pipe(pipes.as_mut_ptr()) } {
19 0 => (),
20 -1 => return Err(Error::new(errno())),
21 _ => unreachable!(),
22 }
23
24 let [read_pipe, write_pipe] = pipes;
25
26 match unsafe { libc::fork() } {
27 0 => {
28 let _ = unsafe { libc::close(read_pipe) };
29
30 f(Daemon { write_pipe })
31 }
32 -1 => return Err(Error::new(errno())),
33 _pid => {
34 let _ = unsafe { libc::close(write_pipe) };
35
36 let mut data = [0];
37
38 let res = loop {
39 match unsafe { libc::read(read_pipe, data.as_mut_ptr().cast(), data.len()) } {
40 -1 if errno() == EINTR => continue,
41 -1 => break Err(Error::new(errno())),
42
43 count => break Ok(count as usize),
44 }
45 };
46
47 let _ = unsafe { libc::close(read_pipe) };
48
49 if res? == 1 {
50 unsafe { libc::_exit(data[0].into()) };
51 } else {
52 Err(Error::new(EIO))
53 }
54 }
55 }
56 }
57
58 pub fn ready(self) -> Result<()> {
59 let res;
60
61 unsafe {
62 let src = [0_u8];
63 res = loop {
64 match libc::write(self.write_pipe, src.as_ptr().cast(), src.len()) {
65 -1 if errno() == EINTR => continue,
66 -1 => break Err(Error::new(errno())),
67 count => break Ok(count),
68 }
69 };
70 let _ = libc::close(self.write_pipe);
71 }
72
73 if res? == 1 {
74 Ok(())
75 } else {
76 Err(Error::new(EIO))
77 }
78 }
79}