base/sys/unix/
descriptor.rs1use std::convert::TryFrom;
6use std::fs::File;
7use std::io::Stderr;
8use std::io::Stdin;
9use std::io::Stdout;
10use std::net::TcpListener;
11use std::net::TcpStream;
12use std::net::UdpSocket;
13use std::ops::Drop;
14use std::os::fd::OwnedFd;
15use std::os::unix::io::AsRawFd;
16use std::os::unix::io::FromRawFd;
17use std::os::unix::io::IntoRawFd;
18use std::os::unix::io::RawFd;
19use std::os::unix::net::UnixDatagram;
20use std::os::unix::net::UnixListener;
21use std::os::unix::net::UnixStream;
22
23use crate::descriptor::AsRawDescriptor;
24use crate::descriptor::Descriptor;
25use crate::descriptor::FromRawDescriptor;
26use crate::descriptor::IntoRawDescriptor;
27use crate::descriptor::SafeDescriptor;
28use crate::errno::errno_result;
29use crate::errno::Result;
30
31pub type RawDescriptor = RawFd;
32
33pub const INVALID_DESCRIPTOR: RawDescriptor = -1;
34
35pub fn clone_descriptor(descriptor: &(impl AsRawDescriptor + ?Sized)) -> Result<SafeDescriptor> {
39 clone_fd(descriptor.as_raw_descriptor())
40}
41
42fn clone_fd(fd: RawFd) -> Result<SafeDescriptor> {
46 let ret = unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) };
49 if ret < 0 {
50 errno_result()
51 } else {
52 Ok(unsafe { SafeDescriptor::from_raw_descriptor(ret) })
54 }
55}
56
57pub fn set_descriptor_cloexec<A: AsRawDescriptor>(fd_owner: &A) -> Result<()> {
59 modify_descriptor_flags(fd_owner.as_raw_descriptor(), |flags| {
60 flags | libc::FD_CLOEXEC
61 })
62}
63
64pub fn clear_descriptor_cloexec<A: AsRawDescriptor>(fd_owner: &A) -> Result<()> {
66 modify_descriptor_flags(fd_owner.as_raw_descriptor(), |flags| {
67 flags & !libc::FD_CLOEXEC
68 })
69}
70
71fn modify_descriptor_flags(
73 desc: RawDescriptor,
74 modify_flags: impl FnOnce(libc::c_int) -> libc::c_int,
75) -> Result<()> {
76 let flags = unsafe { libc::fcntl(desc, libc::F_GETFD) };
79 if flags == -1 {
80 return errno_result();
81 }
82
83 let new_flags = modify_flags(flags);
84
85 if new_flags != flags && unsafe { libc::fcntl(desc, libc::F_SETFD, new_flags) } == -1 {
88 errno_result()
89 } else {
90 Ok(())
91 }
92}
93
94impl Drop for SafeDescriptor {
95 fn drop(&mut self) {
96 let _ = unsafe { libc::close(self.descriptor) };
99 }
100}
101
102impl AsRawFd for SafeDescriptor {
103 fn as_raw_fd(&self) -> RawFd {
104 self.as_raw_descriptor()
105 }
106}
107
108impl TryFrom<&dyn AsRawFd> for SafeDescriptor {
109 type Error = std::io::Error;
110
111 fn try_from(fd: &dyn AsRawFd) -> std::result::Result<Self, Self::Error> {
112 Ok(clone_fd(fd.as_raw_fd())?)
113 }
114}
115
116impl SafeDescriptor {
117 pub fn try_clone(&self) -> Result<SafeDescriptor> {
120 let descriptor = unsafe { libc::fcntl(self.descriptor, libc::F_DUPFD_CLOEXEC, 0) };
123 if descriptor < 0 {
124 errno_result()
125 } else {
126 Ok(SafeDescriptor { descriptor })
127 }
128 }
129}
130
131impl From<SafeDescriptor> for File {
132 fn from(s: SafeDescriptor) -> File {
133 unsafe { File::from_raw_fd(s.into_raw_descriptor()) }
136 }
137}
138
139impl From<SafeDescriptor> for TcpListener {
140 fn from(s: SafeDescriptor) -> Self {
141 unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
144 }
145}
146
147impl From<SafeDescriptor> for TcpStream {
148 fn from(s: SafeDescriptor) -> Self {
149 unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
152 }
153}
154
155impl From<SafeDescriptor> for UnixStream {
156 fn from(s: SafeDescriptor) -> Self {
157 unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
160 }
161}
162
163impl From<SafeDescriptor> for OwnedFd {
164 fn from(s: SafeDescriptor) -> Self {
165 unsafe { OwnedFd::from_raw_descriptor(s.into_raw_descriptor()) }
168 }
169}
170
171impl From<OwnedFd> for SafeDescriptor {
172 fn from(fd: OwnedFd) -> Self {
173 unsafe { SafeDescriptor::from_raw_descriptor(fd.into_raw_descriptor()) }
176 }
177}
178
179impl AsRawFd for Descriptor {
182 fn as_raw_fd(&self) -> RawFd {
183 self.0
184 }
185}
186
187macro_rules! AsRawDescriptor {
188 ($name:ident) => {
189 impl AsRawDescriptor for $name {
190 fn as_raw_descriptor(&self) -> RawDescriptor {
191 self.as_raw_fd()
192 }
193 }
194 };
195}
196
197macro_rules! FromRawDescriptor {
198 ($name:ident) => {
199 impl FromRawDescriptor for $name {
200 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
201 $name::from_raw_fd(descriptor)
202 }
203 }
204 };
205}
206
207macro_rules! IntoRawDescriptor {
208 ($name:ident) => {
209 impl IntoRawDescriptor for $name {
210 fn into_raw_descriptor(self) -> RawDescriptor {
211 self.into_raw_fd()
212 }
213 }
214 };
215}
216
217AsRawDescriptor!(File);
222AsRawDescriptor!(OwnedFd);
223AsRawDescriptor!(TcpListener);
224AsRawDescriptor!(TcpStream);
225AsRawDescriptor!(UdpSocket);
226AsRawDescriptor!(UnixDatagram);
227AsRawDescriptor!(UnixListener);
228AsRawDescriptor!(UnixStream);
229FromRawDescriptor!(File);
230FromRawDescriptor!(OwnedFd);
231FromRawDescriptor!(UnixStream);
232FromRawDescriptor!(UnixDatagram);
233IntoRawDescriptor!(File);
234IntoRawDescriptor!(OwnedFd);
235IntoRawDescriptor!(UnixDatagram);
236IntoRawDescriptor!(UnixStream);
237AsRawDescriptor!(Stdin);
238AsRawDescriptor!(Stdout);
239AsRawDescriptor!(Stderr);