1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use super::*;

use libc;
use std::fs::File;
use std::io;
use std::os::unix::io::{AsRawFd, FromRawFd};

pub struct Impl;

impl Create for Impl {
    fn create_files() -> io::Result<(File, File)> {
        let mut outputs = [0; 2];

        if unsafe { libc::pipe(outputs.as_mut_ptr()) } == -1 {
            return Err(io::Error::last_os_error())
        }

        let read_fd = outputs[0];
        let write_fd = outputs[1];

        let read_file = unsafe { FromRawFd::from_raw_fd(read_fd) };
        let write_file = unsafe { FromRawFd::from_raw_fd(write_fd) };

        Ok((read_file, write_file))
    }
}

impl Divert<io::Stdout> for Impl {
    fn divert_std_stream(write_file: &File) -> io::Result<()> {
        set_std_fd(libc::STDOUT_FILENO, write_file.as_raw_fd())
    }

    fn reinstate_std_stream(original_fd: Fdandle) -> io::Result<()> {
        set_std_fd(libc::STDOUT_FILENO, original_fd)?;
        close_handle(original_fd)
    }
}

impl Divert<io::Stderr> for Impl {
    fn divert_std_stream(write_file: &File) -> io::Result<()> {
        set_std_fd(libc::STDERR_FILENO, write_file.as_raw_fd())
    }

    fn reinstate_std_stream(original_fd: Fdandle) -> io::Result<()> {
        set_std_fd(libc::STDERR_FILENO, original_fd)?;
        close_handle(original_fd)
    }
}

impl Device for io::Stdout {
    fn obtain_original() -> io::Result<Fdandle> {
        get_std_handle(libc::STDOUT_FILENO)
    }
}

impl Device for io::Stderr {
    fn obtain_original() -> io::Result<Fdandle> {
        get_std_handle(libc::STDERR_FILENO)
    }
}

impl ShhRead for Impl {
    fn shh_read(mut read_file: &File, buf: &mut [u8]) -> io::Result<usize> {
        let mut avail = 0;

        let r = unsafe { libc::ioctl(read_file.as_raw_fd(), libc::FIONREAD, &mut avail) };

        if r == -1 {
             Err(io::Error::last_os_error())
        } else if avail == 0 {
             Ok(0)
        } else {
            read_file.read(buf)
        }
    }
}

fn close_handle(device: Fdandle) -> io::Result<()> {
    match unsafe { libc::close(device) } {
        0 => Ok(()),
        _ => Err(io::Error::last_os_error()),
    }
}

fn get_std_handle(device: Fdandle) -> io::Result<Fdandle> {
    match unsafe { libc::dup(device) } {
        -1 => Err(io::Error::last_os_error()),
        handle => Ok(handle),
    }
}

fn set_std_fd(device: Fdandle, fd: Fdandle) -> io::Result<()> {
    match unsafe { libc::dup2(fd, device) } {
        -1 => Err(io::Error::last_os_error()),
        _ => Ok(()),
    }
}