capture_stdio/pipe/
mod.rs1use os_pipe::{PipeReader, PipeWriter};
4use std::{
5 io::Error,
6 os::{unix::io::RawFd, unix::prelude::AsRawFd},
7};
8
9pub mod stderr;
10pub mod stdin;
11pub mod stdout;
12
13pub use stderr::PipedStderr;
14pub use stdin::PipedStdin;
15pub use stdout::PipedStdout;
16
17struct PipedFd {
18 reader: PipeReader,
19 writer: PipeWriter,
20 original: RawFd,
21 target: RawFd,
22 restored: bool,
23}
24
25impl PipedFd {
26 fn capture(target: RawFd, is_stdin: bool) -> Result<Self, Error> {
27 let (reader, writer) = os_pipe::pipe()?;
28 let original = if is_stdin {
29 swap_fd(reader.as_raw_fd(), target)
30 } else {
31 swap_fd(writer.as_raw_fd(), target)
32 };
33
34 Ok(Self {
35 reader,
36 writer,
37 original,
38 target,
39 restored: false,
40 })
41 }
42
43 fn restore(&mut self) {
44 assert!(!self.restored, "You can't restore it twice");
45
46 let fd = swap_fd(self.original, self.target);
47 unsafe {
48 libc::close(fd);
49 }
50
51 self.restored = true;
52 }
53}
54
55impl Drop for PipedFd {
56 fn drop(&mut self) {
57 if !self.restored {
58 self.restore();
59 }
60 }
61}
62
63fn swap_fd(fd: RawFd, target: RawFd) -> RawFd {
64 unsafe {
65 let orig_stdin = libc::dup(target as i32);
66 libc::close(target as i32);
67 libc::dup2(fd as i32, target as i32);
68 orig_stdin as RawFd
69 }
70}