1use std::ffi::CStr;
2use std::fs::{File, OpenOptions};
3use std::io::Result;
4use std::os::raw::c_int;
5use std::os::unix::prelude::{AsRawFd, FromRawFd};
6use std::path::Path;
7
8use crate::anon_pipe::{anon_pipe, AnonPipe};
9use crate::file_desc::FileDesc;
10
11const DEV_NULL: &str = "/dev/null\0";
12
13pub struct StdioPipes {
14 pub stdin: Option<AnonPipe>,
15 pub stdout: Option<AnonPipe>,
16 pub stderr: Option<AnonPipe>,
17}
18
19pub struct ChildPipes {
20 pub stdin: ChildStdio,
21 pub stdout: ChildStdio,
22 pub stderr: ChildStdio,
23}
24
25pub enum ChildStdio {
26 Inherit,
27 Explicit(c_int),
28 Owned(FileDesc),
29}
30
31#[derive(Debug)]
33pub enum Stdio {
34 Inherit,
36 Null,
38 MakePipe,
40 Fd(FileDesc),
42}
43
44impl Stdio {
45 pub fn to_child_stdio(&self, readable: bool) -> Result<(ChildStdio, Option<AnonPipe>)> {
46 match *self {
47 Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
48
49 Stdio::Fd(ref fd) => {
57 if fd.as_raw_fd() >= 0 && fd.as_raw_fd() <= libc::STDERR_FILENO {
58 Ok((ChildStdio::Owned(fd.duplicate()?), None))
59 } else {
60 Ok((ChildStdio::Explicit(fd.as_raw_fd()), None))
61 }
62 }
63
64 Stdio::MakePipe => {
65 let (reader, writer) = anon_pipe()?;
66 let (ours, theirs) = if readable {
67 (writer, reader)
68 } else {
69 (reader, writer)
70 };
71 Ok((ChildStdio::Owned(theirs.into()), Some(ours)))
72 }
73
74 Stdio::Null => {
75 let mut opts = OpenOptions::new();
76 opts.read(readable);
77 opts.write(!readable);
78 let path = unsafe { CStr::from_ptr(DEV_NULL.as_ptr() as *const _) };
79 let path = Path::new(path.to_str().unwrap());
80 let fd = File::open(path)?.as_raw_fd();
81 Ok((
82 ChildStdio::Owned(unsafe { FileDesc::from_raw_fd(fd) }),
83 None,
84 ))
85 }
86 }
87 }
88
89 pub fn piped() -> Stdio {
93 Stdio::MakePipe
94 }
95
96 pub fn null() -> Stdio {
99 Stdio::Null
100 }
101
102 pub fn inherit() -> Stdio {
105 Stdio::Inherit
106 }
107}
108
109impl From<AnonPipe> for Stdio {
110 fn from(pipe: AnonPipe) -> Stdio {
111 Stdio::Fd(pipe.into())
112 }
113}
114
115impl ChildStdio {
116 pub fn fd(&self) -> Option<c_int> {
117 match *self {
118 ChildStdio::Inherit => None,
119 ChildStdio::Explicit(fd) => Some(fd),
120 ChildStdio::Owned(ref fd) => Some(fd.as_raw_fd()),
121 }
122 }
123}