redox_daemon/
lib.rs

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}