hermit/fd/
mod.rs

1use alloc::boxed::Box;
2use alloc::sync::Arc;
3use alloc::vec::Vec;
4use core::future::{self, Future};
5use core::task::Poll::{Pending, Ready};
6use core::time::Duration;
7
8use async_trait::async_trait;
9#[cfg(any(feature = "tcp", feature = "udp"))]
10use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
11
12use crate::arch::kernel::core_local::core_scheduler;
13use crate::executor::block_on;
14use crate::fs::{DirectoryEntry, FileAttr, SeekWhence};
15use crate::io;
16
17mod eventfd;
18#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
19pub(crate) mod socket;
20pub(crate) mod stdio;
21
22pub(crate) const STDIN_FILENO: FileDescriptor = 0;
23pub(crate) const STDOUT_FILENO: FileDescriptor = 1;
24pub(crate) const STDERR_FILENO: FileDescriptor = 2;
25
26#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
27#[derive(Debug)]
28pub(crate) enum Endpoint {
29	#[cfg(any(feature = "tcp", feature = "udp"))]
30	Ip(IpEndpoint),
31	#[cfg(feature = "vsock")]
32	Vsock(socket::vsock::VsockEndpoint),
33}
34
35#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
36#[derive(Debug)]
37pub(crate) enum ListenEndpoint {
38	#[cfg(any(feature = "tcp", feature = "udp"))]
39	Ip(IpListenEndpoint),
40	#[cfg(feature = "vsock")]
41	Vsock(socket::vsock::VsockListenEndpoint),
42}
43
44#[allow(dead_code)]
45#[derive(Debug, PartialEq)]
46pub(crate) enum SocketOption {
47	TcpNoDelay,
48}
49
50#[allow(dead_code)]
51#[derive(Debug, PartialEq)]
52pub(crate) enum IoCtl {
53	NonBlocking,
54}
55
56pub(crate) type FileDescriptor = i32;
57
58bitflags! {
59	/// Options for opening files
60	#[derive(Debug, Copy, Clone, Default)]
61	pub struct OpenOption: i32 {
62		const O_RDONLY = 0o0000;
63		const O_WRONLY = 0o0001;
64		const O_RDWR = 0o0002;
65		const O_CREAT = 0o0100;
66		const O_EXCL = 0o0200;
67		const O_TRUNC = 0o1000;
68		const O_APPEND = 0o2000;
69		const O_DIRECT = 0o40000;
70		const O_DIRECTORY = 0o200_000;
71	}
72}
73
74bitflags! {
75	#[derive(Debug, Copy, Clone, Default)]
76	pub struct PollEvent: i16 {
77		const POLLIN = 0x1;
78		const POLLPRI = 0x2;
79		const POLLOUT = 0x4;
80		const POLLERR = 0x8;
81		const POLLHUP = 0x10;
82		const POLLNVAL = 0x20;
83		const POLLRDNORM = 0x040;
84		const POLLRDBAND = 0x080;
85		const POLLWRNORM = 0x0100;
86		const POLLWRBAND = 0x0200;
87		const POLLRDHUP = 0x2000;
88	}
89}
90
91#[repr(C)]
92#[derive(Debug, Default, Copy, Clone)]
93pub struct PollFd {
94	/// file descriptor
95	pub fd: i32,
96	/// events to look for
97	pub events: PollEvent,
98	/// events returned
99	pub revents: PollEvent,
100}
101
102bitflags! {
103	#[derive(Debug, Default, Copy, Clone)]
104	pub struct EventFlags: i16 {
105		const EFD_SEMAPHORE = 0o1;
106		const EFD_NONBLOCK = 0o4000;
107		const EFD_CLOEXEC = 0o40000;
108	}
109}
110
111bitflags! {
112	#[derive(Debug, Copy, Clone)]
113	pub struct AccessPermission: u32 {
114		const S_IFMT = 0o170_000;
115		const S_IFSOCK = 0o140_000;
116		const S_IFLNK = 0o120_000;
117		const S_IFREG = 0o100_000;
118		const S_IFBLK = 0o060_000;
119		const S_IFDIR = 0o040_000;
120		const S_IFCHR = 0o020_000;
121		const S_IFIFO = 0o010_000;
122		const S_IRUSR = 0o400;
123		const S_IWUSR = 0o200;
124		const S_IXUSR = 0o100;
125		const S_IRWXU = 0o700;
126		const S_IRGRP = 0o040;
127		const S_IWGRP = 0o020;
128		const S_IXGRP = 0o010;
129		const S_IRWXG = 0o070;
130		const S_IROTH = 0o004;
131		const S_IWOTH = 0o002;
132		const S_IXOTH = 0o001;
133		const S_IRWXO = 0o007;
134		// Allow bits unknown to us to be set externally. See bitflags documentation for further explanation.
135		const _ = !0;
136	}
137}
138
139impl Default for AccessPermission {
140	fn default() -> Self {
141		AccessPermission::from_bits(0o666).unwrap()
142	}
143}
144
145#[async_trait]
146pub(crate) trait ObjectInterface: Sync + Send + core::fmt::Debug {
147	/// check if an IO event is possible
148	async fn poll(&self, _event: PollEvent) -> io::Result<PollEvent> {
149		Ok(PollEvent::empty())
150	}
151
152	/// `async_read` attempts to read `len` bytes from the object references
153	/// by the descriptor
154	async fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
155		Err(io::Error::ENOSYS)
156	}
157
158	/// `async_write` attempts to write `len` bytes to the object references
159	/// by the descriptor
160	async fn write(&self, _buf: &[u8]) -> io::Result<usize> {
161		Err(io::Error::ENOSYS)
162	}
163
164	/// `lseek` function repositions the offset of the file descriptor fildes
165	async fn lseek(&self, _offset: isize, _whence: SeekWhence) -> io::Result<isize> {
166		Err(io::Error::EINVAL)
167	}
168
169	/// `fstat`
170	async fn fstat(&self) -> io::Result<FileAttr> {
171		Err(io::Error::EINVAL)
172	}
173
174	/// 'readdir' returns a pointer to a dirent structure
175	/// representing the next directory entry in the directory stream
176	/// pointed to by the file descriptor
177	async fn readdir(&self) -> io::Result<Vec<DirectoryEntry>> {
178		Err(io::Error::EINVAL)
179	}
180
181	/// `accept` a connection on a socket
182	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
183	async fn accept(&self) -> io::Result<(Arc<dyn ObjectInterface>, Endpoint)> {
184		Err(io::Error::EINVAL)
185	}
186
187	/// initiate a connection on a socket
188	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
189	async fn connect(&self, _endpoint: Endpoint) -> io::Result<()> {
190		Err(io::Error::EINVAL)
191	}
192
193	/// `bind` a name to a socket
194	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
195	async fn bind(&self, _name: ListenEndpoint) -> io::Result<()> {
196		Err(io::Error::EINVAL)
197	}
198
199	/// `listen` for connections on a socket
200	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
201	async fn listen(&self, _backlog: i32) -> io::Result<()> {
202		Err(io::Error::EINVAL)
203	}
204
205	/// `setsockopt` sets options on sockets
206	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
207	async fn setsockopt(&self, _opt: SocketOption, _optval: bool) -> io::Result<()> {
208		Err(io::Error::ENOTSOCK)
209	}
210
211	/// `getsockopt` gets options on sockets
212	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
213	async fn getsockopt(&self, _opt: SocketOption) -> io::Result<bool> {
214		Err(io::Error::ENOTSOCK)
215	}
216
217	/// `getsockname` gets socket name
218	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
219	async fn getsockname(&self) -> io::Result<Option<Endpoint>> {
220		Ok(None)
221	}
222
223	/// `getpeername` get address of connected peer
224	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
225	#[allow(dead_code)]
226	async fn getpeername(&self) -> io::Result<Option<Endpoint>> {
227		Ok(None)
228	}
229
230	/// receive a message from a socket
231	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
232	async fn recvfrom(&self, _buffer: &mut [u8]) -> io::Result<(usize, Endpoint)> {
233		Err(io::Error::ENOSYS)
234	}
235
236	/// send a message from a socket
237	///
238	/// The sendto() function shall send a message.
239	/// If the socket is a connectionless-mode socket, the message shall
240	/// If a peer address has been prespecified, either the message shall
241	/// be sent to the address specified by dest_addr (overriding the pre-specified peer
242	/// address).
243	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
244	async fn sendto(&self, _buffer: &[u8], _endpoint: Endpoint) -> io::Result<usize> {
245		Err(io::Error::ENOSYS)
246	}
247
248	/// shut down part of a full-duplex connection
249	#[cfg(any(feature = "tcp", feature = "udp", feature = "vsock"))]
250	async fn shutdown(&self, _how: i32) -> io::Result<()> {
251		Err(io::Error::ENOSYS)
252	}
253
254	/// The `ioctl` function manipulates the underlying device parameters of special
255	/// files.
256	async fn ioctl(&self, _cmd: IoCtl, _value: bool) -> io::Result<()> {
257		Err(io::Error::ENOSYS)
258	}
259}
260
261pub(crate) fn read(fd: FileDescriptor, buf: &mut [u8]) -> io::Result<usize> {
262	let obj = get_object(fd)?;
263
264	if buf.is_empty() {
265		return Ok(0);
266	}
267
268	block_on(obj.read(buf), None)
269}
270
271pub(crate) fn lseek(fd: FileDescriptor, offset: isize, whence: SeekWhence) -> io::Result<isize> {
272	let obj = get_object(fd)?;
273
274	block_on(obj.lseek(offset, whence), None)
275}
276
277pub(crate) fn write(fd: FileDescriptor, buf: &[u8]) -> io::Result<usize> {
278	let obj = get_object(fd)?;
279
280	if buf.is_empty() {
281		return Ok(0);
282	}
283
284	block_on(obj.write(buf), None)
285}
286
287async fn poll_fds(fds: &mut [PollFd]) -> io::Result<u64> {
288	future::poll_fn(|cx| {
289		let mut counter: u64 = 0;
290
291		for i in &mut *fds {
292			let fd = i.fd;
293			i.revents = PollEvent::empty();
294			let mut pinned_obj = core::pin::pin!(core_scheduler().get_object(fd));
295			if let Ready(Ok(obj)) = pinned_obj.as_mut().poll(cx) {
296				let mut pinned = core::pin::pin!(obj.poll(i.events));
297				if let Ready(Ok(e)) = pinned.as_mut().poll(cx) {
298					if !e.is_empty() {
299						counter += 1;
300						i.revents = e;
301					}
302				}
303			}
304		}
305
306		if counter > 0 {
307			Ready(Ok(counter))
308		} else {
309			Pending
310		}
311	})
312	.await
313}
314
315/// Wait for some event on a file descriptor.
316///
317/// The unix-like `poll` waits for one of a set of file descriptors
318/// to become ready to perform I/O. The set of file descriptors to be
319/// monitored is specified in the `fds` argument, which is an array
320/// of structs of `PollFd`.
321pub fn poll(fds: &mut [PollFd], timeout: Option<Duration>) -> io::Result<u64> {
322	let result = block_on(poll_fds(fds), timeout);
323	if let Err(ref e) = result {
324		if timeout.is_some() {
325			// A return value of zero indicates that the system call timed out
326			if *e == io::Error::EAGAIN {
327				return Ok(0);
328			}
329		}
330	}
331
332	result
333}
334
335pub fn fstat(fd: FileDescriptor) -> io::Result<FileAttr> {
336	let obj = get_object(fd)?;
337	block_on(obj.fstat(), None)
338}
339
340/// Wait for some event on a file descriptor.
341///
342/// `eventfd` creates an linux-like "eventfd object" that can be used
343/// as an event wait/notify mechanism by user-space applications, and by
344/// the kernel to notify user-space applications of events. The
345/// object contains an unsigned 64-bit integer counter
346/// that is maintained by the kernel. This counter is initialized
347/// with the value specified in the argument `initval`.
348///
349/// As its return value, `eventfd` returns a new file descriptor that
350/// can be used to refer to the eventfd object.
351///
352/// The following values may be bitwise set in flags to change the
353/// behavior of `eventfd`:
354///
355/// `EFD_NONBLOCK`: Set the file descriptor in non-blocking mode
356/// `EFD_SEMAPHORE`: Provide semaphore-like semantics for reads
357/// from the new file descriptor.
358pub fn eventfd(initval: u64, flags: EventFlags) -> io::Result<FileDescriptor> {
359	let obj = self::eventfd::EventFd::new(initval, flags);
360
361	let fd = block_on(core_scheduler().insert_object(Arc::new(obj)), None)?;
362
363	Ok(fd)
364}
365
366pub(crate) fn get_object(fd: FileDescriptor) -> io::Result<Arc<dyn ObjectInterface>> {
367	block_on(core_scheduler().get_object(fd), None)
368}
369
370pub(crate) fn insert_object(obj: Arc<dyn ObjectInterface>) -> io::Result<FileDescriptor> {
371	block_on(core_scheduler().insert_object(obj), None)
372}
373
374// The dup system call allocates a new file descriptor that refers
375// to the same open file description as the descriptor oldfd. The new
376// file descriptor number is guaranteed to be the lowest-numbered
377// file descriptor that was unused in the calling process.
378pub(crate) fn dup_object(fd: FileDescriptor) -> io::Result<FileDescriptor> {
379	block_on(core_scheduler().dup_object(fd), None)
380}
381
382pub(crate) fn remove_object(fd: FileDescriptor) -> io::Result<Arc<dyn ObjectInterface>> {
383	block_on(core_scheduler().remove_object(fd), None)
384}