1 | use crate::PipeReader; |
2 | use crate::PipeWriter; |
3 | use libc::c_int; |
4 | use std::fs::File; |
5 | use std::io; |
6 | use std::os::unix::prelude::*; |
7 | |
8 | // We need to atomically create pipes and set the CLOEXEC flag on them. This is |
9 | // done with the pipe2() API. However, macOS doesn't support pipe2. There, all |
10 | // we can do is call pipe() followed by fcntl(), and hope that no other threads |
11 | // fork() in between. The following code is copied from the nix crate, where it |
12 | // works but is deprecated. |
13 | #[cfg (not(any( |
14 | target_os = "aix" , |
15 | target_os = "ios" , |
16 | target_os = "visionos" , |
17 | target_os = "macos" , |
18 | target_os = "haiku" |
19 | )))] |
20 | fn pipe2_cloexec() -> io::Result<(OwnedFd, OwnedFd)> { |
21 | let mut fds: [c_int; 2] = [0; 2]; |
22 | let res: i32 = unsafe { libc::pipe2(fds.as_mut_ptr(), flags:libc::O_CLOEXEC) }; |
23 | if res != 0 { |
24 | return Err(io::Error::last_os_error()); |
25 | } |
26 | unsafe { Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1]))) } |
27 | } |
28 | |
29 | #[cfg (any( |
30 | target_os = "aix" , |
31 | target_os = "ios" , |
32 | target_os = "visionos" , |
33 | target_os = "macos" , |
34 | target_os = "haiku" |
35 | ))] |
36 | fn pipe2_cloexec() -> io::Result<(OwnedFd, OwnedFd)> { |
37 | let mut fds: [c_int; 2] = [0; 2]; |
38 | let res = unsafe { libc::pipe(fds.as_mut_ptr()) }; |
39 | if res != 0 { |
40 | return Err(io::Error::last_os_error()); |
41 | } |
42 | // Wrap the fds immediately, so that we'll drop them and close them in the unlikely event that |
43 | // any of the following fcntls fails. |
44 | let owned_fds = unsafe { (OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1])) }; |
45 | let res = unsafe { libc::fcntl(fds[0], libc::F_SETFD, libc::FD_CLOEXEC) }; |
46 | if res != 0 { |
47 | return Err(io::Error::last_os_error()); |
48 | } |
49 | let res = unsafe { libc::fcntl(fds[1], libc::F_SETFD, libc::FD_CLOEXEC) }; |
50 | if res != 0 { |
51 | return Err(io::Error::last_os_error()); |
52 | } |
53 | Ok(owned_fds) |
54 | } |
55 | |
56 | pub(crate) fn pipe() -> io::Result<(PipeReader, PipeWriter)> { |
57 | let (read_fd: OwnedFd, write_fd: OwnedFd) = pipe2_cloexec()?; |
58 | Ok((read_fd.into(), write_fd.into())) |
59 | } |
60 | |
61 | pub(crate) fn dup(handle: impl AsFd) -> io::Result<OwnedFd> { |
62 | handle.as_fd().try_clone_to_owned() |
63 | } |
64 | |
65 | impl IntoRawFd for PipeReader { |
66 | fn into_raw_fd(self) -> RawFd { |
67 | self.0.into_raw_fd() |
68 | } |
69 | } |
70 | |
71 | impl AsRawFd for PipeReader { |
72 | fn as_raw_fd(&self) -> RawFd { |
73 | self.0.as_raw_fd() |
74 | } |
75 | } |
76 | |
77 | impl FromRawFd for PipeReader { |
78 | unsafe fn from_raw_fd(fd: RawFd) -> PipeReader { |
79 | PipeReader(File::from_raw_fd(fd)) |
80 | } |
81 | } |
82 | |
83 | impl From<PipeReader> for OwnedFd { |
84 | fn from(pr: PipeReader) -> Self { |
85 | pr.0.into() |
86 | } |
87 | } |
88 | |
89 | impl AsFd for PipeReader { |
90 | fn as_fd(&self) -> BorrowedFd<'_> { |
91 | self.0.as_fd() |
92 | } |
93 | } |
94 | |
95 | impl From<OwnedFd> for PipeReader { |
96 | fn from(fd: OwnedFd) -> Self { |
97 | PipeReader(fd.into()) |
98 | } |
99 | } |
100 | |
101 | impl IntoRawFd for PipeWriter { |
102 | fn into_raw_fd(self) -> RawFd { |
103 | self.0.into_raw_fd() |
104 | } |
105 | } |
106 | |
107 | impl AsRawFd for PipeWriter { |
108 | fn as_raw_fd(&self) -> RawFd { |
109 | self.0.as_raw_fd() |
110 | } |
111 | } |
112 | |
113 | impl FromRawFd for PipeWriter { |
114 | unsafe fn from_raw_fd(fd: RawFd) -> PipeWriter { |
115 | PipeWriter(File::from_raw_fd(fd)) |
116 | } |
117 | } |
118 | |
119 | impl From<PipeWriter> for OwnedFd { |
120 | fn from(pw: PipeWriter) -> Self { |
121 | pw.0.into() |
122 | } |
123 | } |
124 | |
125 | impl AsFd for PipeWriter { |
126 | fn as_fd(&self) -> BorrowedFd<'_> { |
127 | self.0.as_fd() |
128 | } |
129 | } |
130 | |
131 | impl From<OwnedFd> for PipeWriter { |
132 | fn from(fd: OwnedFd) -> Self { |
133 | PipeWriter(fd.into()) |
134 | } |
135 | } |
136 | |