1use alloc::sync::Arc;
2#[cfg(any(feature = "net", feature = "virtio-vsock"))]
3use core::ffi::c_int;
4use core::future;
5use core::mem::MaybeUninit;
6use core::pin::pin;
7use core::task::Poll::{Pending, Ready};
8use core::time::Duration;
9
10use num_enum::{IntoPrimitive, TryFromPrimitive};
11#[cfg(feature = "net")]
12use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
13#[cfg(any(feature = "net", feature = "virtio-vsock"))]
14use zerocopy::{FromBytes, native_endian};
15
16pub(crate) use self::delegate::Fd;
17use crate::arch::kernel::core_local::core_scheduler;
18use crate::errno::Errno;
19use crate::executor::block_on;
20use crate::fs::{FileAttr, SeekWhence};
21use crate::io;
22use crate::syscalls::DirentFormat;
23#[cfg(any(feature = "net", feature = "virtio-vsock"))]
24use crate::syscalls::socket::{Ipproto, SOL_SOCKET, socklen_t};
25
26mod delegate;
27mod eventfd;
28pub(crate) mod null_file;
29pub(crate) mod random_file;
30#[cfg(any(feature = "net", feature = "virtio-vsock"))]
31pub(crate) mod socket;
32pub(crate) mod stdio;
33
34pub(crate) const STDIN_FILENO: RawFd = 0;
35pub(crate) const STDOUT_FILENO: RawFd = 1;
36pub(crate) const STDERR_FILENO: RawFd = 2;
37
38#[cfg(any(feature = "net", feature = "virtio-vsock"))]
39#[derive(Debug)]
40pub(crate) enum Endpoint {
41 #[cfg(feature = "net")]
42 Ip(IpEndpoint),
43 #[cfg(feature = "virtio-vsock")]
44 Vsock(socket::vsock::VsockEndpoint),
45}
46
47#[cfg(any(feature = "net", feature = "virtio-vsock"))]
48#[derive(Debug)]
49pub(crate) enum ListenEndpoint {
50 #[cfg(feature = "net")]
51 Ip(IpListenEndpoint),
52 #[cfg(feature = "virtio-vsock")]
53 Vsock(socket::vsock::VsockListenEndpoint),
54}
55
56#[allow(dead_code)]
57#[derive(Debug, PartialEq, Eq)]
58pub(crate) enum SocketOption {
59 TcpOption(SocketOptionTcp),
60 SocketOption(SocketOptionSocket),
61}
62
63#[cfg(any(feature = "net", feature = "virtio-vsock"))]
64impl SocketOption {
65 pub fn from_level_optname(level: i32, optname: i32) -> Option<SocketOption> {
66 if level == SOL_SOCKET {
67 SocketOptionSocket::try_from(optname)
68 .ok()
69 .map(SocketOption::SocketOption)
70 } else {
71 let protocol = u8::try_from(level)
72 .ok()
73 .and_then(|proto| Ipproto::try_from(proto).ok())?;
74
75 match protocol {
76 Ipproto::Tcp => SocketOptionTcp::try_from(optname)
77 .ok()
78 .map(SocketOption::TcpOption),
79 _ => None,
80 }
81 }
82 }
83}
84
85#[cfg(any(feature = "net", feature = "virtio-vsock"))]
86#[derive(Debug)]
87#[repr(transparent)]
88pub struct SocketOptionValue<'a>(Option<&'a [u8]>);
89
90#[cfg(any(feature = "net", feature = "virtio-vsock"))]
91impl SocketOptionValue<'_> {
92 pub unsafe fn new(optval: *const core::ffi::c_void, optlen: socklen_t) -> Self {
100 if optlen == 0 || optval.is_null() {
101 return Self(None);
102 }
103
104 let slice = unsafe { core::slice::from_raw_parts(optval.cast::<u8>(), optlen as usize) };
105 Self(Some(slice))
106 }
107}
108
109#[cfg(any(feature = "net", feature = "virtio-vsock"))]
110impl TryFrom<&SocketOptionValue<'_>> for i32 {
111 type Error = Errno;
112
113 fn try_from(value: &SocketOptionValue<'_>) -> Result<Self, Self::Error> {
114 let Some(value) = value.0 else {
115 return Err(Errno::Inval);
116 };
117
118 if value.len() != size_of::<i32>() {
119 return Err(Errno::Inval);
120 }
121
122 let value = native_endian::I32::ref_from_bytes(value).map_err(|_| Errno::Inval)?;
123
124 Ok(value.get())
125 }
126}
127
128#[cfg(any(feature = "net", feature = "virtio-vsock"))]
129impl TryFrom<&SocketOptionValue<'_>> for bool {
130 type Error = Errno;
131
132 fn try_from(value: &SocketOptionValue<'_>) -> Result<Self, Self::Error> {
133 let value: i32 = value.try_into()?;
134 Ok(value != 0)
135 }
136}
137
138#[derive(TryFromPrimitive, IntoPrimitive, PartialEq, Eq, Clone, Copy, Debug)]
139#[repr(i32)]
140#[non_exhaustive]
141pub(crate) enum SocketOptionTcp {
142 #[doc(alias = "TCP_NODELAY")]
143 TcpNoDelay = 1,
144}
145
146#[derive(TryFromPrimitive, IntoPrimitive, PartialEq, Eq, Clone, Copy, Debug)]
147#[repr(i32)]
148#[non_exhaustive]
149pub(crate) enum SocketOptionSocket {
150 #[doc(alias = "SO_REUSEADDR")]
151 ReuseAddr = 4,
152 #[doc(alias = "SO_KEEPALIVE")]
153 KeepAlive = 8,
154 #[doc(alias = "SO_SNDBUF")]
155 SoSndbuf = 0x1001,
156 #[doc(alias = "SO_RCVBUF")]
157 SoRcvbuf = 0x1002,
158 #[doc(alias = "SO_SNDTIMEO")]
159 SoSndtimeo = 0x1005,
160 #[doc(alias = "SO_RCVTIMEO")]
161 SoRcvtimeo = 0x1006,
162 #[doc(alias = "SO_ERROR")]
163 SoError = 0x1007,
164}
165
166pub(crate) type RawFd = i32;
167
168bitflags! {
169 #[derive(Debug, Copy, Clone, Default)]
171 pub struct OpenOption: i32 {
172 const O_RDONLY = 0o0000;
173 const O_WRONLY = 0o0001;
174 const O_RDWR = 0o0002;
175 const O_CREAT = 0o0100;
176 const O_EXCL = 0o0200;
177 const O_TRUNC = 0o1000;
178 const O_APPEND = StatusFlags::O_APPEND.bits();
179 const O_NONBLOCK = StatusFlags::O_NONBLOCK.bits();
180 const O_DIRECT = 0o40000;
181 const O_DIRECTORY = 0o200_000;
182 const O_CLOEXEC = 0o2_000_000;
184 }
185}
186
187bitflags! {
188 #[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
190 pub struct AccessOption: i32 {
191 const R_OK = 4;
193 const W_OK = 2;
195 const X_OK = 1;
197 const F_OK = 0;
199 }
200}
201
202impl AccessOption {
203 pub fn can_access(&self, access_permissions: AccessPermission) -> bool {
205 if self.contains(AccessOption::R_OK)
206 && !access_permissions.contains(AccessPermission::S_IRUSR)
207 && !access_permissions.contains(AccessPermission::S_IRGRP)
208 && !access_permissions.contains(AccessPermission::S_IROTH)
209 {
210 return false;
211 }
212
213 if self.contains(AccessOption::W_OK)
214 && !access_permissions.contains(AccessPermission::S_IWUSR)
215 && !access_permissions.contains(AccessPermission::S_IWGRP)
216 && !access_permissions.contains(AccessPermission::S_IWOTH)
217 {
218 return false;
219 }
220
221 if self.contains(AccessOption::X_OK)
222 && !access_permissions.contains(AccessPermission::S_IXUSR)
223 && !access_permissions.contains(AccessPermission::S_IXGRP)
224 && !access_permissions.contains(AccessPermission::S_IXOTH)
225 {
226 return false;
227 }
228
229 true
230 }
231}
232
233bitflags! {
234 #[derive(Debug, Copy, Clone, Default)]
236 pub struct StatusFlags: i32 {
237 const O_APPEND = 0o2000;
238 const O_NONBLOCK = 0o4000;
239 }
240}
241
242bitflags! {
243 #[derive(Debug, Copy, Clone, Default)]
244 pub struct PollEvent: i16 {
245 const POLLIN = 0x1;
246 const POLLPRI = 0x2;
247 const POLLOUT = 0x4;
248 const POLLERR = 0x8;
249 const POLLHUP = 0x10;
250 const POLLNVAL = 0x20;
251 const POLLRDNORM = 0x040;
252 const POLLRDBAND = 0x080;
253 const POLLWRNORM = 0x0100;
254 const POLLWRBAND = 0x0200;
255 const POLLRDHUP = 0x2000;
256 }
257}
258
259#[repr(C)]
260#[derive(Debug, Default, Copy, Clone)]
261pub struct PollFd {
262 pub fd: RawFd,
264 pub events: PollEvent,
266 pub revents: PollEvent,
268}
269
270bitflags! {
271 #[derive(Debug, Default, Copy, Clone)]
272 pub struct EventFlags: i16 {
273 const EFD_SEMAPHORE = 0o1;
274 const EFD_NONBLOCK = 0o4000;
275 const EFD_CLOEXEC = 0o40000;
276 }
277}
278
279bitflags! {
280 #[derive(Debug, Copy, Clone)]
281 pub struct AccessPermission: u32 {
282 const S_IFMT = 0o170_000;
283 const S_IFSOCK = 0o140_000;
284 const S_IFLNK = 0o120_000;
285 const S_IFREG = 0o100_000;
286 const S_IFBLK = 0o060_000;
287 const S_IFDIR = 0o040_000;
288 const S_IFCHR = 0o020_000;
289 const S_IFIFO = 0o010_000;
290 const S_IRUSR = 0o400;
291 const S_IWUSR = 0o200;
292 const S_IXUSR = 0o100;
293 const S_IRWXU = 0o700;
294 const S_IRGRP = 0o040;
295 const S_IWGRP = 0o020;
296 const S_IXGRP = 0o010;
297 const S_IRWXG = 0o070;
298 const S_IROTH = 0o004;
299 const S_IWOTH = 0o002;
300 const S_IXOTH = 0o001;
301 const S_IRWXO = 0o007;
302 const _ = !0;
304 }
305}
306
307impl Default for AccessPermission {
308 fn default() -> Self {
309 AccessPermission::from_bits(0o666).unwrap()
310 }
311}
312
313pub(crate) trait ObjectInterface: Sync + Send {
314 async fn poll(&self, _event: PollEvent) -> io::Result<PollEvent> {
316 Ok(PollEvent::empty())
317 }
318
319 async fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
322 let _buf = buf;
323 Err(Errno::Nosys)
324 }
325
326 async fn write(&self, buf: &[u8]) -> io::Result<usize> {
329 let _buf = buf;
330 Err(Errno::Nosys)
331 }
332
333 async fn lseek(&self, _offset: isize, _whence: SeekWhence) -> io::Result<isize> {
335 Err(Errno::Inval)
336 }
337
338 async fn fstat(&self) -> io::Result<FileAttr> {
340 Err(Errno::Inval)
341 }
342
343 async fn getdents(
347 &self,
348 buf: &mut [MaybeUninit<u8>],
349 format: DirentFormat,
350 ) -> io::Result<usize> {
351 let _buf = buf;
352 let _format = format;
353 Err(Errno::Notdir)
354 }
355
356 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
358 async fn accept(&mut self) -> io::Result<(Arc<async_lock::RwLock<Fd>>, Endpoint)> {
359 Err(Errno::Inval)
360 }
361
362 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
364 async fn connect(&mut self, _endpoint: Endpoint) -> io::Result<()> {
365 Err(Errno::Inval)
366 }
367
368 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
370 async fn bind(&mut self, _name: ListenEndpoint) -> io::Result<()> {
371 Err(Errno::Inval)
372 }
373
374 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
376 async fn listen(&mut self, _backlog: i32) -> io::Result<()> {
377 Err(Errno::Inval)
378 }
379
380 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
382 async fn setsockopt(
383 &self,
384 _opt: SocketOption,
385 _optval: SocketOptionValue<'_>,
386 ) -> io::Result<()> {
387 Err(Errno::Notsock)
388 }
389
390 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
392 async fn getsockopt(&self, _opt: SocketOption) -> io::Result<c_int> {
393 Err(Errno::Notsock)
394 }
395
396 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
398 async fn getsockname(&self) -> io::Result<Option<Endpoint>> {
399 Ok(None)
400 }
401
402 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
404 #[allow(dead_code)]
405 async fn getpeername(&self) -> io::Result<Option<Endpoint>> {
406 Ok(None)
407 }
408
409 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
411 async fn recvfrom(&self, buf: &mut [u8]) -> io::Result<(usize, Endpoint)> {
412 let _buf = buf;
413 Err(Errno::Nosys)
414 }
415
416 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
424 async fn sendto(&self, buf: &[u8], _endpoint: Endpoint) -> io::Result<usize> {
425 let _buf = buf;
426 Err(Errno::Nosys)
427 }
428
429 #[cfg(any(feature = "net", feature = "virtio-vsock"))]
431 async fn shutdown(&self, _how: i32) -> io::Result<()> {
432 Err(Errno::Nosys)
433 }
434
435 async fn status_flags(&self) -> io::Result<StatusFlags> {
437 Err(Errno::Nosys)
438 }
439
440 async fn set_status_flags(&mut self, _status_flags: StatusFlags) -> io::Result<()> {
442 Err(Errno::Nosys)
443 }
444
445 async fn truncate(&self, _size: usize) -> io::Result<()> {
447 Err(Errno::Nosys)
448 }
449
450 async fn chmod(&self, _access_permission: AccessPermission) -> io::Result<()> {
452 Err(Errno::Nosys)
453 }
454
455 async fn isatty(&self) -> io::Result<bool> {
457 Ok(false)
458 }
459
460 async fn fsync(&self) -> io::Result<()> {
462 Ok(())
463 }
464}
465
466pub(crate) fn read(fd: RawFd, buf: &mut [u8]) -> io::Result<usize> {
467 let obj = get_object(fd)?;
468
469 if buf.is_empty() {
470 return Ok(0);
471 }
472
473 block_on(async { obj.read().await.read(buf).await }, None)
474}
475
476pub(crate) fn fsync(fd: RawFd) -> io::Result<()> {
478 let obj = get_object(fd)?;
479
480 block_on(async { obj.read().await.fsync().await }, None)
481}
482
483pub(crate) fn lseek(fd: RawFd, offset: isize, whence: SeekWhence) -> io::Result<isize> {
484 let obj = get_object(fd)?;
485
486 block_on(async { obj.read().await.lseek(offset, whence).await }, None)
487}
488
489pub(crate) fn chmod(fd: RawFd, mode: AccessPermission) -> io::Result<()> {
490 let obj = get_object(fd)?;
491
492 block_on(async { obj.read().await.chmod(mode).await }, None)
493}
494
495pub(crate) fn write(fd: RawFd, buf: &[u8]) -> io::Result<usize> {
496 let obj = get_object(fd)?;
497
498 if buf.is_empty() {
499 return Ok(0);
500 }
501
502 block_on(async { obj.read().await.write(buf).await }, None)
503}
504
505pub(crate) fn truncate(fd: RawFd, length: usize) -> io::Result<()> {
506 let obj = get_object(fd)?;
507 block_on(async { obj.read().await.truncate(length).await }, None)
508}
509
510async fn poll_fds(fds: &mut [PollFd]) -> io::Result<u64> {
511 future::poll_fn(|cx| {
512 let mut counter: u64 = 0;
513
514 for poll_fd in &mut *fds {
515 let fd = poll_fd.fd;
516 poll_fd.revents = PollEvent::empty();
517 let Ok(obj) = core_scheduler().get_object(fd) else {
518 continue;
519 };
520
521 let mut pinned = pin!(async { obj.read().await.poll(poll_fd.events).await });
522 if let Ready(Ok(e)) = pinned.as_mut().poll(cx)
523 && !e.is_empty()
524 {
525 counter += 1;
526 poll_fd.revents = e;
527 }
528 }
529
530 if counter > 0 {
531 Ready(Ok(counter))
532 } else {
533 Pending
534 }
535 })
536 .await
537}
538
539pub fn poll(fds: &mut [PollFd], timeout: Option<Duration>) -> io::Result<u64> {
546 let result = block_on(poll_fds(fds), timeout);
547 if let Err(e) = &result
548 && timeout.is_some()
549 {
550 if *e == Errno::Again {
552 return Ok(0);
553 }
554 }
555
556 result
557}
558
559pub fn fstat(fd: RawFd) -> io::Result<FileAttr> {
560 let obj = get_object(fd)?;
561 block_on(async { obj.read().await.fstat().await }, None)
562}
563
564pub fn eventfd(initval: u64, flags: EventFlags) -> io::Result<RawFd> {
583 let obj = eventfd::EventFd::new(initval, flags);
584
585 let fd = core_scheduler().insert_object(Arc::new(async_lock::RwLock::new(obj.into())))?;
586
587 Ok(fd)
588}
589
590pub(crate) fn get_object(fd: RawFd) -> io::Result<Arc<async_lock::RwLock<Fd>>> {
591 core_scheduler().get_object(fd)
592}
593
594pub(crate) fn insert_object(obj: Arc<async_lock::RwLock<Fd>>) -> io::Result<RawFd> {
595 core_scheduler().insert_object(obj)
596}
597
598pub(crate) fn dup_object(fd: RawFd) -> io::Result<RawFd> {
603 core_scheduler().dup_object(fd)
604}
605
606pub(crate) fn dup_object2(fd1: RawFd, fd2: RawFd) -> io::Result<RawFd> {
607 core_scheduler().dup_object2(fd1, fd2)
608}
609
610pub(crate) fn remove_object(fd: RawFd) -> io::Result<Arc<async_lock::RwLock<Fd>>> {
611 core_scheduler().remove_object(fd)
612}
613
614pub(crate) fn isatty(fd: RawFd) -> io::Result<bool> {
615 let obj = get_object(fd)?;
616 block_on(async { obj.read().await.isatty().await }, None)
617}