Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/unix/descriptor.rs
5394 views
1
// Copyright 2020 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::convert::TryFrom;
6
use std::fs::File;
7
use std::io::Stderr;
8
use std::io::Stdin;
9
use std::io::Stdout;
10
use std::net::TcpListener;
11
use std::net::TcpStream;
12
use std::net::UdpSocket;
13
use std::ops::Drop;
14
use std::os::fd::OwnedFd;
15
use std::os::unix::io::AsRawFd;
16
use std::os::unix::io::FromRawFd;
17
use std::os::unix::io::IntoRawFd;
18
use std::os::unix::io::RawFd;
19
use std::os::unix::net::UnixDatagram;
20
use std::os::unix::net::UnixListener;
21
use std::os::unix::net::UnixStream;
22
23
use crate::descriptor::AsRawDescriptor;
24
use crate::descriptor::Descriptor;
25
use crate::descriptor::FromRawDescriptor;
26
use crate::descriptor::IntoRawDescriptor;
27
use crate::descriptor::SafeDescriptor;
28
use crate::errno::errno_result;
29
use crate::errno::Result;
30
31
pub type RawDescriptor = RawFd;
32
33
pub const INVALID_DESCRIPTOR: RawDescriptor = -1;
34
35
/// Clones `descriptor`, returning a new `SafeDescriptor` that refers to the same file
36
/// `descriptor`. The cloned descriptor will have the `FD_CLOEXEC` flag set but will not share any
37
/// other file descriptor flags with `descriptor`.
38
pub fn clone_descriptor(descriptor: &(impl AsRawDescriptor + ?Sized)) -> Result<SafeDescriptor> {
39
clone_fd(descriptor.as_raw_descriptor())
40
}
41
42
/// Clones `fd`, returning a new file descriptor that refers to the same open file as `fd`. The
43
/// cloned fd will have the `FD_CLOEXEC` flag set but will not share any other file descriptor
44
/// flags with `fd`.
45
fn clone_fd(fd: RawFd) -> Result<SafeDescriptor> {
46
// SAFETY:
47
// Safe because this doesn't modify any memory and we check the return value.
48
let ret = unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) };
49
if ret < 0 {
50
errno_result()
51
} else {
52
// SAFETY: We just dup'd the FD and so have exclusive access.
53
Ok(unsafe { SafeDescriptor::from_raw_descriptor(ret) })
54
}
55
}
56
57
/// Adds CLOEXEC flag on descriptor
58
pub 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
64
/// Clears CLOEXEC flag on descriptor
65
pub 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
71
/// Apply the specified modification to the file descriptor's flags.
72
fn modify_descriptor_flags(
73
desc: RawDescriptor,
74
modify_flags: impl FnOnce(libc::c_int) -> libc::c_int,
75
) -> Result<()> {
76
// SAFETY:
77
// Safe because fd is read only.
78
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
// SAFETY:
86
// Safe because this has no side effect(s) on the current process.
87
if new_flags != flags && unsafe { libc::fcntl(desc, libc::F_SETFD, new_flags) } == -1 {
88
errno_result()
89
} else {
90
Ok(())
91
}
92
}
93
94
impl Drop for SafeDescriptor {
95
fn drop(&mut self) {
96
// SAFETY:
97
// Safe because descriptor is valid.
98
let _ = unsafe { libc::close(self.descriptor) };
99
}
100
}
101
102
impl AsRawFd for SafeDescriptor {
103
fn as_raw_fd(&self) -> RawFd {
104
self.as_raw_descriptor()
105
}
106
}
107
108
impl 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
116
impl SafeDescriptor {
117
/// Clones this descriptor, internally creating a new descriptor. The new SafeDescriptor will
118
/// share the same underlying count within the kernel.
119
pub fn try_clone(&self) -> Result<SafeDescriptor> {
120
// SAFETY:
121
// Safe because this doesn't modify any memory and we check the return value.
122
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
131
impl From<SafeDescriptor> for File {
132
fn from(s: SafeDescriptor) -> File {
133
// SAFETY:
134
// Safe because we own the SafeDescriptor at this point.
135
unsafe { File::from_raw_fd(s.into_raw_descriptor()) }
136
}
137
}
138
139
impl From<SafeDescriptor> for TcpListener {
140
fn from(s: SafeDescriptor) -> Self {
141
// SAFETY:
142
// Safe because we own the SafeDescriptor at this point.
143
unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
144
}
145
}
146
147
impl From<SafeDescriptor> for TcpStream {
148
fn from(s: SafeDescriptor) -> Self {
149
// SAFETY:
150
// Safe because we own the SafeDescriptor at this point.
151
unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
152
}
153
}
154
155
impl From<SafeDescriptor> for UnixStream {
156
fn from(s: SafeDescriptor) -> Self {
157
// SAFETY:
158
// Safe because we own the SafeDescriptor at this point.
159
unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
160
}
161
}
162
163
impl From<SafeDescriptor> for OwnedFd {
164
fn from(s: SafeDescriptor) -> Self {
165
// SAFETY:
166
// Safe because we own the SafeDescriptor at this point.
167
unsafe { OwnedFd::from_raw_descriptor(s.into_raw_descriptor()) }
168
}
169
}
170
171
impl From<OwnedFd> for SafeDescriptor {
172
fn from(fd: OwnedFd) -> Self {
173
// SAFETY:
174
// Safe because we own the OwnedFd at this point.
175
unsafe { SafeDescriptor::from_raw_descriptor(fd.into_raw_descriptor()) }
176
}
177
}
178
179
// AsRawFd for interoperability with interfaces that require it. Within crosvm,
180
// always use AsRawDescriptor when possible.
181
impl AsRawFd for Descriptor {
182
fn as_raw_fd(&self) -> RawFd {
183
self.0
184
}
185
}
186
187
macro_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
197
macro_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
207
macro_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
217
// Implementations for File. This enables the File-type to use
218
// RawDescriptor, but does not mean File should be used as a generic
219
// descriptor container. That should go to either SafeDescriptor or another more
220
// relevant container type.
221
AsRawDescriptor!(File);
222
AsRawDescriptor!(OwnedFd);
223
AsRawDescriptor!(TcpListener);
224
AsRawDescriptor!(TcpStream);
225
AsRawDescriptor!(UdpSocket);
226
AsRawDescriptor!(UnixDatagram);
227
AsRawDescriptor!(UnixListener);
228
AsRawDescriptor!(UnixStream);
229
FromRawDescriptor!(File);
230
FromRawDescriptor!(OwnedFd);
231
FromRawDescriptor!(UnixStream);
232
FromRawDescriptor!(UnixDatagram);
233
IntoRawDescriptor!(File);
234
IntoRawDescriptor!(OwnedFd);
235
IntoRawDescriptor!(UnixDatagram);
236
IntoRawDescriptor!(UnixStream);
237
AsRawDescriptor!(Stdin);
238
AsRawDescriptor!(Stdout);
239
AsRawDescriptor!(Stderr);
240
241