1#![allow(clippy::result_unit_err)]
2
3use alloc::ffi::CString;
4#[cfg(all(target_os = "none", not(feature = "common-os")))]
5use core::alloc::{GlobalAlloc, Layout};
6use core::ffi::{CStr, c_char};
7use core::marker::PhantomData;
8use core::ptr::null;
9
10use dirent_display::Dirent64Display;
11use hermit_sync::Lazy;
12
13pub use self::condvar::*;
14pub use self::entropy::*;
15pub use self::futex::*;
16pub use self::processor::*;
17#[cfg(feature = "newlib")]
18pub use self::recmutex::*;
19pub use self::semaphore::*;
20pub use self::spinlock::*;
21pub use self::system::*;
22pub use self::tasks::*;
23pub use self::timer::*;
24use crate::env;
25use crate::errno::{Errno, ToErrno};
26use crate::executor::block_on;
27use crate::fd::{
28 self, AccessOption, AccessPermission, EventFlags, FileDescriptor, OpenOption, PollFd,
29 dup_object, dup_object2, get_object, isatty, remove_object,
30};
31use crate::fs::{self, FileAttr, SeekWhence};
32#[cfg(all(target_os = "none", not(feature = "common-os")))]
33use crate::mm::ALLOCATOR;
34use crate::syscalls::interfaces::SyscallInterface;
35
36mod condvar;
37mod entropy;
38mod futex;
39pub(crate) mod interfaces;
40#[cfg(feature = "mman")]
41mod mman;
42mod processor;
43#[cfg(feature = "newlib")]
44mod recmutex;
45mod semaphore;
46#[cfg(any(feature = "net", feature = "vsock"))]
47pub mod socket;
48mod spinlock;
49mod system;
50#[cfg(feature = "common-os")]
51pub(crate) mod table;
52mod tasks;
53mod timer;
54
55pub(crate) static SYS: Lazy<&'static dyn SyscallInterface> = Lazy::new(|| {
56 if env::is_uhyve() {
57 &self::interfaces::Uhyve
58 } else {
59 &self::interfaces::Generic
60 }
61});
62
63#[repr(C)]
64#[derive(Debug, Clone, Copy)]
65struct iovec {
67 pub iov_base: *mut u8,
69 pub iov_len: usize,
71}
72
73const IOV_MAX: usize = 1024;
74
75pub(crate) fn init() {
76 Lazy::force(&SYS);
77
78 SYS.init();
80
81 init_entropy();
82}
83
84#[cfg(all(target_os = "none", not(feature = "common-os")))]
91#[hermit_macro::system]
92#[unsafe(no_mangle)]
93pub extern "C" fn sys_alloc(size: usize, align: usize) -> *mut u8 {
94 let layout_res = Layout::from_size_align(size, align);
95 if layout_res.is_err() || size == 0 {
96 warn!("__sys_alloc called with size {size:#x}, align {align:#x} is an invalid layout!");
97 return core::ptr::null_mut();
98 }
99 let layout = layout_res.unwrap();
100 let ptr = unsafe { ALLOCATOR.alloc(layout) };
101
102 trace!("__sys_alloc: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})");
103
104 ptr
105}
106
107#[cfg(all(target_os = "none", not(feature = "common-os")))]
108#[hermit_macro::system]
109#[unsafe(no_mangle)]
110pub extern "C" fn sys_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
111 let layout_res = Layout::from_size_align(size, align);
112 if layout_res.is_err() || size == 0 {
113 warn!(
114 "__sys_alloc_zeroed called with size {size:#x}, align {align:#x} is an invalid layout!"
115 );
116 return core::ptr::null_mut();
117 }
118 let layout = layout_res.unwrap();
119 let ptr = unsafe { ALLOCATOR.alloc_zeroed(layout) };
120
121 trace!("__sys_alloc_zeroed: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})");
122
123 ptr
124}
125
126#[cfg(all(target_os = "none", not(feature = "common-os")))]
127#[hermit_macro::system]
128#[unsafe(no_mangle)]
129pub extern "C" fn sys_malloc(size: usize, align: usize) -> *mut u8 {
130 let layout_res = Layout::from_size_align(size, align);
131 if layout_res.is_err() || size == 0 {
132 warn!("__sys_malloc called with size {size:#x}, align {align:#x} is an invalid layout!");
133 return core::ptr::null_mut();
134 }
135 let layout = layout_res.unwrap();
136 let ptr = unsafe { ALLOCATOR.alloc(layout) };
137
138 trace!("__sys_malloc: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})");
139
140 ptr
141}
142
143#[cfg(all(target_os = "none", not(feature = "common-os")))]
163#[hermit_macro::system]
164#[unsafe(no_mangle)]
165pub unsafe extern "C" fn sys_realloc(
166 ptr: *mut u8,
167 size: usize,
168 align: usize,
169 new_size: usize,
170) -> *mut u8 {
171 unsafe {
172 let layout_res = Layout::from_size_align(size, align);
173 if layout_res.is_err() || size == 0 || new_size == 0 {
174 warn!(
175 "__sys_realloc called with ptr {ptr:p}, size {size:#x}, align {align:#x}, new_size {new_size:#x} is an invalid layout!"
176 );
177 return core::ptr::null_mut();
178 }
179 let layout = layout_res.unwrap();
180 let new_ptr = ALLOCATOR.realloc(ptr, layout, new_size);
181
182 if new_ptr.is_null() {
183 debug!(
184 "__sys_realloc failed to resize ptr {ptr:p} with size {size:#x}, align {align:#x}, new_size {new_size:#x} !"
185 );
186 } else {
187 trace!("__sys_realloc: resized memory at {ptr:p}, new address {new_ptr:p}");
188 }
189 new_ptr
190 }
191}
192
193#[cfg(all(target_os = "none", not(feature = "common-os")))]
204#[hermit_macro::system]
205#[unsafe(no_mangle)]
206pub unsafe extern "C" fn sys_dealloc(ptr: *mut u8, size: usize, align: usize) {
207 unsafe {
208 let layout_res = Layout::from_size_align(size, align);
209 if layout_res.is_err() || size == 0 {
210 warn!(
211 "__sys_dealloc called with size {size:#x}, align {align:#x} is an invalid layout!"
212 );
213 debug_assert!(layout_res.is_err(), "__sys_dealloc error: Invalid layout");
214 debug_assert_ne!(size, 0, "__sys_dealloc error: size cannot be 0");
215 } else {
216 trace!("sys_free: deallocate memory at {ptr:p} (size {size:#x})");
217 }
218 let layout = layout_res.unwrap();
219 ALLOCATOR.dealloc(ptr, layout);
220 }
221}
222
223#[cfg(all(target_os = "none", not(feature = "common-os")))]
224#[hermit_macro::system]
225#[unsafe(no_mangle)]
226pub unsafe extern "C" fn sys_free(ptr: *mut u8, size: usize, align: usize) {
227 unsafe {
228 let layout_res = Layout::from_size_align(size, align);
229 if layout_res.is_err() || size == 0 {
230 warn!("__sys_free called with size {size:#x}, align {align:#x} is an invalid layout!");
231 debug_assert!(layout_res.is_err(), "__sys_free error: Invalid layout");
232 debug_assert_ne!(size, 0, "__sys_free error: size cannot be 0");
233 } else {
234 trace!("sys_free: deallocate memory at {ptr:p} (size {size:#x})");
235 }
236 let layout = layout_res.unwrap();
237 ALLOCATOR.dealloc(ptr, layout);
238 }
239}
240
241pub(crate) fn get_application_parameters() -> (i32, *const *const u8, *const *const u8) {
242 SYS.get_application_parameters()
243}
244
245pub(crate) fn shutdown(arg: i32) -> ! {
246 crate::arch::kernel::print_statistics();
248
249 SYS.shutdown(arg)
250}
251
252#[hermit_macro::system(errno)]
253#[unsafe(no_mangle)]
254pub unsafe extern "C" fn sys_unlink(name: *const c_char) -> i32 {
255 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
256
257 fs::unlink(name).map_or_else(|e| -i32::from(e), |()| 0)
258}
259
260#[hermit_macro::system(errno)]
261#[unsafe(no_mangle)]
262pub unsafe extern "C" fn sys_mkdir(name: *const c_char, mode: u32) -> i32 {
263 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
264 let Some(mode) = AccessPermission::from_bits(mode) else {
265 return -i32::from(Errno::Inval);
266 };
267
268 crate::fs::create_dir(name, mode).map_or_else(|e| -i32::from(e), |()| 0)
269}
270
271#[hermit_macro::system(errno)]
272#[unsafe(no_mangle)]
273pub unsafe extern "C" fn sys_rmdir(name: *const c_char) -> i32 {
274 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
275
276 crate::fs::remove_dir(name).map_or_else(|e| -i32::from(e), |()| 0)
277}
278
279#[hermit_macro::system(errno)]
280#[unsafe(no_mangle)]
281pub unsafe extern "C" fn sys_stat(name: *const c_char, stat: *mut FileAttr) -> i32 {
282 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
283
284 match fs::read_stat(name) {
285 Ok(attr) => unsafe {
286 *stat = attr;
287 0
288 },
289 Err(e) => -i32::from(e),
290 }
291}
292
293#[hermit_macro::system(errno)]
294#[unsafe(no_mangle)]
295pub unsafe extern "C" fn sys_lstat(name: *const c_char, stat: *mut FileAttr) -> i32 {
296 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
297
298 match fs::read_lstat(name) {
299 Ok(attr) => unsafe {
300 *stat = attr;
301 0
302 },
303 Err(e) => -i32::from(e),
304 }
305}
306
307#[hermit_macro::system(errno)]
308#[unsafe(no_mangle)]
309pub unsafe extern "C" fn sys_fstat(fd: FileDescriptor, stat: *mut FileAttr) -> i32 {
310 if stat.is_null() {
311 return -i32::from(Errno::Inval);
312 }
313
314 crate::fd::fstat(fd).map_or_else(
315 |e| -i32::from(e),
316 |v| unsafe {
317 *stat = v;
318 0
319 },
320 )
321}
322
323#[hermit_macro::system(errno)]
324#[unsafe(no_mangle)]
325pub unsafe extern "C" fn sys_opendir(name: *const c_char) -> FileDescriptor {
326 if let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() {
327 crate::fs::opendir(name).unwrap_or_else(|e| -i32::from(e))
328 } else {
329 -i32::from(Errno::Inval)
330 }
331}
332
333#[hermit_macro::system(errno)]
334#[unsafe(no_mangle)]
335pub unsafe extern "C" fn sys_open(name: *const c_char, flags: i32, mode: u32) -> FileDescriptor {
336 let Some(flags) = OpenOption::from_bits(flags) else {
337 return -i32::from(Errno::Inval);
338 };
339 let Some(mode) = AccessPermission::from_bits(mode) else {
340 return -i32::from(Errno::Inval);
341 };
342
343 if let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() {
344 crate::fs::open(name, flags, mode).unwrap_or_else(|e| -i32::from(e))
345 } else {
346 -i32::from(Errno::Inval)
347 }
348}
349
350#[hermit_macro::system]
351#[unsafe(no_mangle)]
352pub unsafe extern "C" fn sys_getcwd(buf: *mut c_char, size: usize) -> *const c_char {
353 let error = |e: Errno| {
354 e.set_errno();
355 null::<c_char>()
356 };
357
358 if size == 0 {
359 return error(Errno::Inval);
360 }
361
362 if buf.is_null() {
363 return error(Errno::Noent);
365 }
366
367 let cwd = match fs::get_cwd() {
368 Err(e) => {
369 return error(e);
370 }
371 Ok(cwd) => cwd,
372 };
373
374 let Ok(cwd) = CString::new(cwd) else {
375 return error(Errno::Noent);
376 };
377
378 if (cwd.count_bytes() + 1) > size {
379 return error(Errno::Range);
380 }
381
382 unsafe {
383 buf.copy_from(cwd.as_ptr(), size);
384 }
385
386 buf
387}
388
389#[hermit_macro::system(errno)]
390#[unsafe(no_mangle)]
391pub extern "C" fn sys_fchdir(_fd: FileDescriptor) -> i32 {
392 -i32::from(Errno::Nosys)
393}
394
395#[hermit_macro::system(errno)]
396#[unsafe(no_mangle)]
397pub unsafe extern "C" fn sys_chdir(path: *mut c_char) -> i32 {
398 if let Ok(name) = unsafe { CStr::from_ptr(path) }.to_str() {
399 crate::fs::set_cwd(name)
400 .map(|()| 0)
401 .unwrap_or_else(|e| -i32::from(e))
402 } else {
403 -i32::from(Errno::Inval)
404 }
405}
406
407#[hermit_macro::system]
408#[unsafe(no_mangle)]
409pub unsafe extern "C" fn sys_umask(umask: u32) -> u32 {
410 crate::fs::umask(AccessPermission::from_bits_truncate(umask)).bits()
411}
412
413#[hermit_macro::system(errno)]
414#[unsafe(no_mangle)]
415pub unsafe extern "C" fn sys_faccessat(
416 dirfd: FileDescriptor,
417 name: *const c_char,
418 _mode: i32,
419 flags: i32,
420) -> i32 {
421 let Some(access_option) = AccessOption::from_bits(flags) else {
422 return -i32::from(Errno::Inval);
423 };
424
425 let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() else {
426 return -i32::from(Errno::Inval);
427 };
428
429 const AT_SYMLINK_NOFOLLOW: i32 = 0x100;
430 const AT_FDCWD: i32 = -100;
431
432 let stat = if name.starts_with("/") || dirfd == AT_FDCWD {
433 let no_follow: bool = (flags & AT_SYMLINK_NOFOLLOW) != 0;
434
435 if no_follow {
436 fs::read_stat(name)
437 } else {
438 fs::read_lstat(name)
439 }
440 } else {
441 warn!("faccessat with directory relative to fd is not implemented!");
442 return -i32::from(Errno::Nosys);
443 };
444
445 match stat {
446 Err(e) => -i32::from(e),
447 Ok(stat) if access_option.can_access(stat.st_mode) => 0,
448 Ok(_) => -i32::from(Errno::Acces),
449 }
450}
451
452#[hermit_macro::system(errno)]
453#[unsafe(no_mangle)]
454pub unsafe extern "C" fn sys_access(name: *const c_char, flags: i32) -> i32 {
455 let Some(access_option) = AccessOption::from_bits(flags) else {
456 return -i32::from(Errno::Inval);
457 };
458
459 if access_option.contains(AccessOption::F_OK) && access_option != AccessOption::F_OK {
460 return -i32::from(Errno::Inval);
461 }
462
463 let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() else {
464 return -i32::from(Errno::Inval);
465 };
466
467 match crate::fs::read_lstat(name) {
468 Err(e) => -i32::from(e),
469 Ok(stat) if access_option.can_access(stat.st_mode) => 0,
470 Ok(_) => -i32::from(Errno::Acces),
471 }
472}
473
474#[hermit_macro::system(errno)]
475#[unsafe(no_mangle)]
476pub unsafe extern "C" fn sys_fchmod(fd: FileDescriptor, mode: u32) -> i32 {
477 let Some(access_permission) = AccessPermission::from_bits(mode) else {
478 return -i32::from(Errno::Inval);
479 };
480
481 crate::fd::chmod(fd, access_permission)
482 .map(|()| 0)
483 .unwrap_or_else(|e| -i32::from(e))
484}
485
486#[hermit_macro::system(errno)]
487#[unsafe(no_mangle)]
488pub extern "C" fn sys_close(fd: FileDescriptor) -> i32 {
489 let obj = remove_object(fd);
490 obj.map_or_else(|e| -i32::from(e), |_| 0)
491}
492
493#[hermit_macro::system(errno)]
494#[unsafe(no_mangle)]
495pub unsafe extern "C" fn sys_read(fd: FileDescriptor, buf: *mut u8, len: usize) -> isize {
496 let slice = unsafe { core::slice::from_raw_parts_mut(buf.cast(), len) };
497 crate::fd::read(fd, slice).map_or_else(
498 |e| isize::try_from(-i32::from(e)).unwrap(),
499 |v| v.try_into().unwrap(),
500 )
501}
502
503#[hermit_macro::system(errno)]
519#[unsafe(no_mangle)]
520pub unsafe extern "C" fn sys_readv(fd: i32, iov: *const iovec, iovcnt: usize) -> isize {
521 if !(0..=IOV_MAX).contains(&iovcnt) {
522 return (-i32::from(Errno::Inval)).try_into().unwrap();
523 }
524
525 let mut read_bytes: isize = 0;
526 let iovec_buffers = unsafe { core::slice::from_raw_parts(iov, iovcnt) };
527
528 for iovec_buf in iovec_buffers {
529 let buf = unsafe {
530 core::slice::from_raw_parts_mut(iovec_buf.iov_base.cast(), iovec_buf.iov_len)
531 };
532
533 let len = crate::fd::read(fd, buf).map_or_else(
534 |e| isize::try_from(-i32::from(e)).unwrap(),
535 |v| v.try_into().unwrap(),
536 );
537
538 if len < 0 {
539 return len;
540 }
541
542 read_bytes += len;
543
544 if len < isize::try_from(iovec_buf.iov_len).unwrap() {
545 return read_bytes;
546 }
547 }
548
549 read_bytes
550}
551
552unsafe fn write(fd: FileDescriptor, buf: *const u8, len: usize) -> isize {
553 let slice = unsafe { core::slice::from_raw_parts(buf, len) };
554 crate::fd::write(fd, slice).map_or_else(
555 |e| isize::try_from(-i32::from(e)).unwrap(),
556 |v| v.try_into().unwrap(),
557 )
558}
559
560#[hermit_macro::system(errno)]
561#[unsafe(no_mangle)]
562pub unsafe extern "C" fn sys_write(fd: FileDescriptor, buf: *const u8, len: usize) -> isize {
563 unsafe { write(fd, buf, len) }
564}
565
566#[hermit_macro::system(errno)]
567#[unsafe(no_mangle)]
568pub unsafe extern "C" fn sys_ftruncate(fd: FileDescriptor, size: usize) -> i32 {
569 fd::truncate(fd, size).map_or_else(|e| -i32::from(e), |()| 0)
570}
571
572#[hermit_macro::system(errno)]
573#[unsafe(no_mangle)]
574pub unsafe extern "C" fn sys_truncate(path: *const c_char, size: usize) -> i32 {
575 let Ok(path) = unsafe { CStr::from_ptr(path) }.to_str() else {
576 return -i32::from(Errno::Inval);
577 };
578
579 fs::truncate(path, size).map_or_else(|e| -i32::from(e), |()| 0)
580}
581
582#[hermit_macro::system(errno)]
598#[unsafe(no_mangle)]
599pub unsafe extern "C" fn sys_writev(fd: FileDescriptor, iov: *const iovec, iovcnt: usize) -> isize {
600 if !(0..=IOV_MAX).contains(&iovcnt) {
601 return (-i32::from(Errno::Inval)).try_into().unwrap();
602 }
603
604 let mut written_bytes: isize = 0;
605 let iovec_buffers = unsafe { core::slice::from_raw_parts(iov, iovcnt) };
606
607 for iovec_buf in iovec_buffers {
608 let buf = unsafe { core::slice::from_raw_parts(iovec_buf.iov_base, iovec_buf.iov_len) };
609
610 let len = crate::fd::write(fd, buf).map_or_else(
611 |e| isize::try_from(-i32::from(e)).unwrap(),
612 |v| v.try_into().unwrap(),
613 );
614
615 if len < 0 {
616 return len;
617 }
618
619 written_bytes += len;
620
621 if len < isize::try_from(iovec_buf.iov_len).unwrap() {
622 return written_bytes;
623 }
624 }
625
626 written_bytes
627}
628
629#[hermit_macro::system(errno)]
630#[unsafe(no_mangle)]
631pub unsafe extern "C" fn sys_ioctl(
632 fd: FileDescriptor,
633 cmd: i32,
634 argp: *mut core::ffi::c_void,
635) -> i32 {
636 const FIONBIO: i32 = 0x8008_667eu32 as i32;
637
638 if cmd == FIONBIO {
639 let value = unsafe { *(argp as *const i32) };
640 let status_flags = if value != 0 {
641 fd::StatusFlags::O_NONBLOCK
642 } else {
643 fd::StatusFlags::empty()
644 };
645
646 let obj = get_object(fd);
647 obj.map_or_else(
648 |e| -i32::from(e),
649 |v| {
650 block_on(
651 async { v.write().await.set_status_flags(status_flags).await },
652 None,
653 )
654 .map_or_else(|e| -i32::from(e), |()| 0)
655 },
656 )
657 } else {
658 -i32::from(Errno::Inval)
659 }
660}
661
662#[hermit_macro::system(errno)]
664#[unsafe(no_mangle)]
665pub extern "C" fn sys_fcntl(fd: i32, cmd: i32, arg: i32) -> i32 {
666 const F_SETFD: i32 = 2;
667 const F_GETFL: i32 = 3;
668 const F_SETFL: i32 = 4;
669 const FD_CLOEXEC: i32 = 1;
670
671 if cmd == F_SETFD && arg == FD_CLOEXEC {
672 0
673 } else if cmd == F_GETFL {
674 let obj = get_object(fd);
675 obj.map_or_else(
676 |e| -i32::from(e),
677 |v| {
678 block_on(async { v.read().await.status_flags().await }, None)
679 .map_or_else(|e| -i32::from(e), |status_flags| status_flags.bits())
680 },
681 )
682 } else if cmd == F_SETFL {
683 let obj = get_object(fd);
684 obj.map_or_else(
685 |e| -i32::from(e),
686 |v| {
687 block_on(
688 async {
689 v.write()
690 .await
691 .set_status_flags(fd::StatusFlags::from_bits_retain(arg))
692 .await
693 },
694 None,
695 )
696 .map_or_else(|e| -i32::from(e), |()| 0)
697 },
698 )
699 } else {
700 -i32::from(Errno::Inval)
701 }
702}
703
704#[hermit_macro::system(errno)]
705#[unsafe(no_mangle)]
706pub extern "C" fn sys_lseek(fd: FileDescriptor, offset: isize, whence: i32) -> isize {
707 let whence = u8::try_from(whence).unwrap();
708 let whence = SeekWhence::try_from(whence).unwrap();
709 crate::fd::lseek(fd, offset, whence).unwrap_or_else(|e| isize::try_from(-i32::from(e)).unwrap())
710}
711
712#[repr(C)]
713pub struct Dirent64 {
714 pub d_ino: u64,
716 pub d_off: i64,
718 pub d_reclen: u16,
720 pub d_type: fs::FileType,
722 pub d_name: PhantomData<c_char>,
724}
725impl Dirent64 {
726 #[allow(dead_code)]
732 unsafe fn display<'a>(&'a self) -> Dirent64Display<'a> {
733 unsafe { Dirent64Display::new(self) }
734 }
735}
736
737mod dirent_display {
738 use core::ffi::{CStr, c_char};
739 use core::fmt;
740
741 use super::Dirent64;
742
743 pub(super) struct Dirent64Display<'a> {
745 dirent: &'a Dirent64,
746 }
747 impl<'a> Dirent64Display<'a> {
748 pub(super) unsafe fn new(dirent: &'a Dirent64) -> Self {
751 Self { dirent }
752 }
753 }
754
755 impl<'a> fmt::Debug for Dirent64Display<'a> {
756 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757 let cstr = unsafe { CStr::from_ptr((&raw const self.dirent.d_name).cast::<c_char>()) };
758
759 f.debug_struct("Dirent64")
760 .field("d_ino", &self.dirent.d_ino)
761 .field("d_off", &self.dirent.d_off)
762 .field("d_reclen", &self.dirent.d_reclen)
763 .field("d_type", &self.dirent.d_type)
764 .field("d_name", &cstr)
765 .finish()
766 }
767 }
768}
769
770#[hermit_macro::system(errno)]
787#[unsafe(no_mangle)]
788pub unsafe extern "C" fn sys_getdents64(
789 fd: FileDescriptor,
790 dirp: *mut Dirent64,
791 count: usize,
792) -> i64 {
793 debug!("getdents for fd {fd:?} - count: {count}");
794 if dirp.is_null() || count == 0 {
795 return (-i32::from(Errno::Inval)).into();
796 }
797
798 let slice = unsafe { core::slice::from_raw_parts_mut(dirp.cast(), count) };
799
800 let obj = get_object(fd);
801 obj.map_or_else(
802 |_| (-i32::from(Errno::Inval)).into(),
803 |v| {
804 block_on(async { v.read().await.getdents(slice).await }, None)
805 .map_or_else(|e| (-i32::from(e)).into(), |cnt| cnt as i64)
806 },
807 )
808}
809
810#[hermit_macro::system(errno)]
811#[unsafe(no_mangle)]
812pub extern "C" fn sys_dup(fd: i32) -> i32 {
813 dup_object(fd).unwrap_or_else(|e| -i32::from(e))
814}
815
816#[hermit_macro::system(errno)]
817#[unsafe(no_mangle)]
818pub extern "C" fn sys_dup2(fd1: i32, fd2: i32) -> i32 {
819 dup_object2(fd1, fd2).unwrap_or_else(|e| -i32::from(e))
820}
821
822#[hermit_macro::system(errno)]
823#[unsafe(no_mangle)]
824pub extern "C" fn sys_isatty(fd: i32) -> i32 {
825 match isatty(fd) {
826 Err(e) => -i32::from(e),
827 Ok(v) => {
828 if v {
829 1
830 } else {
831 0
832 }
833 }
834 }
835}
836
837#[hermit_macro::system(errno)]
838#[unsafe(no_mangle)]
839pub unsafe extern "C" fn sys_poll(fds: *mut PollFd, nfds: usize, timeout: i32) -> i32 {
840 let slice = unsafe { core::slice::from_raw_parts_mut(fds, nfds) };
841 let timeout = if timeout >= 0 {
842 Some(core::time::Duration::from_millis(
843 timeout.try_into().unwrap(),
844 ))
845 } else {
846 None
847 };
848
849 crate::fd::poll(slice, timeout).map_or_else(
850 |e| {
851 if e == Errno::Time { 0 } else { -i32::from(e) }
852 },
853 |v| v.try_into().unwrap(),
854 )
855}
856
857#[hermit_macro::system(errno)]
858#[unsafe(no_mangle)]
859pub extern "C" fn sys_eventfd(initval: u64, flags: i16) -> i32 {
860 if let Some(flags) = EventFlags::from_bits(flags) {
861 crate::fd::eventfd(initval, flags).unwrap_or_else(|e| -i32::from(e))
862 } else {
863 -i32::from(Errno::Inval)
864 }
865}
866
867#[hermit_macro::system]
868#[unsafe(no_mangle)]
869pub extern "C" fn sys_image_start_addr() -> usize {
870 crate::mm::kernel_start_address().as_usize()
871}
872
873#[cfg(test)]
874mod tests {
875 use core::ptr;
876
877 use super::*;
878
879 #[cfg(target_os = "none")]
880 #[test_case]
881 fn test_get_application_parameters() {
882 crate::env::init();
883 let (argc, argv, _envp) = get_application_parameters();
884 assert_ne!(argc, 0);
885 assert_ne!(argv, ptr::null());
886 }
887}