-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathstdio.rs
138 lines (127 loc) · 4.62 KB
/
stdio.rs
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use std::io;
use std::os::unix::io::{RawFd, AsRawFd, IntoRawFd};
use nix;
use nix::fcntl::{fcntl, FcntlArg};
use libc;
/// An enumeration that is used to configure stdio file descritors
///
/// The enumeration members might be non-stable, it's better to use
/// one of the constructors to create an instance
pub enum Stdio {
/// This fd will use pipe to/from the appliation
Pipe,
/// This fd will be inherited from the parent application
Inherit,
/// This fd will open /dev/null in read or write mode
Null,
/// This is fd passed by application (and closed by `unshare`)
Fd(Closing),
}
/// An enumeration that is used to configure non-stdio file descriptors. It
/// differs from stdio one because we must differentiate from readable and
/// writable file descriptors for things open by the library
///
/// The enumeration members might be non-stable, it's better to use
/// one of the constructors to create an instance
// TODO(tailhook) should this object be hidden?
pub enum Fd {
/// This fd is a reading end of a pipe
ReadPipe,
/// This fd is a writing end of a pipe
WritePipe,
/// This fd is inherited from parent (current) process
Inherit,
/// This fd is redirected from `/dev/null`
ReadNull,
/// This fd is redirected to `/dev/null`
WriteNull,
/// This is fd passed by application (and closed by `unshare`)
Fd(Closing),
}
pub struct Closing(RawFd);
pub fn dup_file_cloexec<F: AsRawFd>(file: &F) -> io::Result<Closing> {
match fcntl(file.as_raw_fd(), FcntlArg::F_DUPFD_CLOEXEC(3)) {
Ok(fd) => Ok(Closing::new(fd)),
Err(nix::Error::Sys(errno)) => {
return Err(io::Error::from_raw_os_error(errno as i32));
}
Err(nix::Error::InvalidPath) => unreachable!(),
Err(nix::Error::InvalidUtf8) => unreachable!(),
Err(nix::Error::UnsupportedOperation) => {
return Err(io::Error::new(io::ErrorKind::Other,
"nix error: unsupported operation"));
}
}
}
impl Stdio {
/// Pipe is created for child process
pub fn piped() -> Stdio { Stdio::Pipe }
/// The child inherits file descriptor from the parent process
pub fn inherit() -> Stdio { Stdio::Inherit }
/// Stream is attached to `/dev/null`
pub fn null() -> Stdio { Stdio::Null }
/// Converts stdio definition to file descriptor definition
/// (mostly needed internally)
pub fn to_fd(self, write: bool) -> Fd {
match (self, write) {
(Stdio::Fd(x), _) => Fd::Fd(x),
(Stdio::Pipe, false) => Fd::ReadPipe,
(Stdio::Pipe, true) => Fd::WritePipe,
(Stdio::Inherit, _) => Fd::Inherit,
(Stdio::Null, false) => Fd::ReadNull,
(Stdio::Null, true) => Fd::WriteNull,
}
}
/// A simpler helper method for `from_raw_fd`, that does dup of file
/// descriptor, so is actually safe to use (but can fail)
pub fn dup_file<F: AsRawFd>(file: &F) -> io::Result<Stdio> {
dup_file_cloexec(file).map(|f| Stdio::Fd(f))
}
/// A simpler helper method for `from_raw_fd`, that consumes file
///
/// Note: we assume that file descriptor **already has** the `CLOEXEC`
/// flag. This is by default for all files opened by rust.
pub fn from_file<F: IntoRawFd>(file: F) -> Stdio {
Stdio::Fd(Closing(file.into_raw_fd()))
}
}
impl Fd {
/// Create a pipe so that child can read from it
pub fn piped_read() -> Fd { Fd::ReadPipe }
/// Create a pipe so that child can write to it
pub fn piped_write() -> Fd { Fd::WritePipe }
/// Inherit the child descriptor from parent
///
/// Not very useful for custom file descriptors better use `from_file()`
pub fn inherit() -> Fd { Fd::Inherit }
/// Create a readable pipe that always has end of file condition
pub fn read_null() -> Fd { Fd::ReadNull }
/// Create a writable pipe that ignores all the input
pub fn write_null() -> Fd { Fd::WriteNull }
/// A simpler helper method for `from_raw_fd`, that does dup of file
/// descriptor, so is actually safe to use (but can fail)
pub fn dup_file<F: AsRawFd>(file: &F) -> io::Result<Fd> {
dup_file_cloexec(file).map(|f| Fd::Fd(f))
}
/// A simpler helper method for `from_raw_fd`, that consumes file
pub fn from_file<F: IntoRawFd>(file: F) -> Fd {
Fd::Fd(Closing(file.into_raw_fd()))
}
}
impl Closing {
pub fn new(fd: RawFd) -> Closing {
Closing(fd)
}
}
impl AsRawFd for Closing {
fn as_raw_fd(&self) -> RawFd {
return self.0;
}
}
impl Drop for Closing {
fn drop(&mut self) {
unsafe {
libc::close(self.0);
}
}
}