conch_runtime_pshaw/sys/unix/
io.rs1use crate::io::FileDesc;
4use crate::sys::cvt_r;
5use crate::IntoInner;
6use libc::{self, c_void, size_t};
7use std::fs::File;
8use std::io::{Result, SeekFrom};
9use std::mem;
10use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
11use std::process::Stdio;
12
13#[derive(Debug, PartialEq, Eq)]
17pub struct RawIo {
18 fd: RawFd,
20}
21
22impl Into<Stdio> for RawIo {
23 fn into(self) -> Stdio {
24 unsafe { FromRawFd::from_raw_fd(self.into_inner()) }
25 }
26}
27
28impl FromRawFd for FileDesc {
29 unsafe fn from_raw_fd(fd: RawFd) -> Self {
30 Self::new(fd)
31 }
32}
33
34impl AsRawFd for FileDesc {
35 fn as_raw_fd(&self) -> RawFd {
36 self.inner().inner()
37 }
38}
39
40impl IntoRawFd for FileDesc {
41 fn into_raw_fd(self) -> RawFd {
42 unsafe { self.into_inner().into_inner() }
43 }
44}
45
46impl From<File> for FileDesc {
47 fn from(file: File) -> Self {
48 unsafe { FromRawFd::from_raw_fd(file.into_raw_fd()) }
49 }
50}
51
52impl mio::Evented for FileDesc {
53 fn register(
54 &self,
55 poll: &mio::Poll,
56 token: mio::Token,
57 interest: mio::Ready,
58 opts: mio::PollOpt,
59 ) -> Result<()> {
60 mio::unix::EventedFd(&self.as_raw_fd()).register(poll, token, interest, opts)
61 }
62
63 fn reregister(
64 &self,
65 poll: &mio::Poll,
66 token: mio::Token,
67 interest: mio::Ready,
68 opts: mio::PollOpt,
69 ) -> Result<()> {
70 mio::unix::EventedFd(&self.as_raw_fd()).reregister(poll, token, interest, opts)
71 }
72
73 fn deregister(&self, poll: &mio::Poll) -> Result<()> {
74 mio::unix::EventedFd(&self.as_raw_fd()).deregister(poll)
75 }
76}
77
78impl RawIo {
79 pub unsafe fn new(fd: RawFd) -> Self {
81 RawIo { fd }
82 }
83
84 pub unsafe fn into_inner(self) -> RawFd {
86 let fd = self.fd;
89 mem::forget(self);
90 fd
91 }
92
93 pub fn inner(&self) -> RawFd {
95 self.fd
96 }
97
98 pub fn duplicate(&self) -> Result<Self> {
100 unsafe { Ok(RawIo::new(cvt_r(|| libc::dup(self.fd))?)) }
101 }
102
103 pub fn read_inner(&self, buf: &mut [u8]) -> Result<usize> {
106 let ret = cvt_r(|| unsafe {
107 libc::read(
108 self.fd,
109 buf.as_mut_ptr() as *mut c_void,
110 buf.len() as size_t,
111 )
112 })?;
113 Ok(ret as usize)
114 }
115
116 pub fn write_inner(&self, buf: &[u8]) -> Result<usize> {
119 let ret = cvt_r(|| unsafe {
120 libc::write(self.fd, buf.as_ptr() as *const c_void, buf.len() as size_t)
121 })?;
122 Ok(ret as usize)
123 }
124
125 pub fn flush_inner(&self) -> Result<()> {
126 Ok(())
127 }
128
129 pub fn seek(&self, pos: SeekFrom) -> Result<u64> {
132 let (whence, pos) = match pos {
133 SeekFrom::Start(off) => (libc::SEEK_SET, off as libc::off_t),
134 SeekFrom::End(off) => (libc::SEEK_END, off as libc::off_t),
135 SeekFrom::Current(off) => (libc::SEEK_CUR, off as libc::off_t),
136 };
137 let n = cvt_r(|| unsafe { libc::lseek(self.fd, pos, whence) })?;
138 Ok(n as u64)
139 }
140
141 #[cfg_attr(
144 any(target_os = "linux", target_os = "android", target_os = "emscripten"),
145 allow(dead_code)
146 )]
147 pub fn set_cloexec(&self, set: bool) -> Result<()> {
149 unsafe {
150 let flags = cvt_r(|| libc::fcntl(self.fd, libc::F_GETFD))?;
151 let new_flags = if set {
152 flags | libc::FD_CLOEXEC
153 } else {
154 flags & !libc::FD_CLOEXEC
155 };
156 cvt_r(|| libc::fcntl(self.fd, libc::F_SETFD, new_flags)).map(|_| ())
157 }
158 }
159
160 pub fn set_nonblock(&mut self, set: bool) -> Result<()> {
165 unsafe {
166 let flags = cvt_r(|| libc::fcntl(self.fd, libc::F_GETFL))?;
167 let new_flags = if set {
168 flags | libc::O_NONBLOCK
169 } else {
170 flags & !libc::O_NONBLOCK
171 };
172 cvt_r(|| libc::fcntl(self.fd, libc::F_SETFL, new_flags)).map(|_| ())
173 }
174 }
175}
176
177impl Drop for RawIo {
178 fn drop(&mut self) {
180 let _ = unsafe { libc::close(self.fd) };
186 }
187}
188
189unsafe fn dup_fd_cloexec(fd: RawFd) -> Result<RawIo> {
191 let min_fd = libc::STDERR_FILENO + 1;
192 Ok(RawIo::new(cvt_r(|| {
193 libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, min_fd)
194 })?))
195}
196
197#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
201pub fn pipe() -> Result<(RawIo, RawIo)> {
202 unsafe {
203 let mut fds = [0; 2];
204 cvt_r(|| libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?;
205
206 let reader = RawIo::new(fds[0]);
207 let writer = RawIo::new(fds[1]);
208
209 Ok((reader, writer))
210 }
211}
212
213#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
218pub fn pipe() -> Result<(RawIo, RawIo)> {
219 unsafe {
220 let mut fds = [0; 2];
221 cvt_r(|| libc::pipe(fds.as_mut_ptr()))?;
222 let reader = RawIo::new(fds[0]);
223 let writer = RawIo::new(fds[1]);
224
225 reader.set_cloexec(true)?;
226 writer.set_cloexec(true)?;
227
228 Ok((reader, writer))
229 }
230}
231
232pub fn dup_stdio() -> Result<(RawIo, RawIo, RawIo)> {
234 unsafe {
235 Ok((
236 dup_fd_cloexec(libc::STDIN_FILENO)?,
237 dup_fd_cloexec(libc::STDOUT_FILENO)?,
238 dup_fd_cloexec(libc::STDERR_FILENO)?,
239 ))
240 }
241}
242
243pub fn getpid() -> libc::pid_t {
245 unsafe { libc::getpid() }
246}