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::mem::MaybeUninit;
9use core::{ptr, slice};
10
11use dirent_display::Dirent64Display;
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::errno::{Errno, ToErrno};
25use crate::executor::block_on;
26use crate::fd::{
27 self, AccessOption, AccessPermission, EventFlags, ObjectInterface, OpenOption, PollFd, RawFd,
28 dup_object, dup_object2, get_object, isatty, remove_object,
29};
30use crate::fs::{self, FileAttr, SeekWhence};
31#[cfg(all(target_os = "none", not(feature = "common-os")))]
32use crate::mm::ALLOCATOR;
33use crate::{env, init_buf};
34
35mod condvar;
36mod entropy;
37mod futex;
38#[cfg(feature = "mman")]
39pub mod mman;
40mod processor;
41#[cfg(feature = "newlib")]
42mod recmutex;
43mod semaphore;
44#[cfg(any(feature = "net", feature = "virtio-vsock"))]
45pub mod socket;
46mod spinlock;
47mod system;
48#[cfg(feature = "common-os")]
49pub(crate) mod table;
50mod tasks;
51mod timer;
52
53#[repr(C)]
54#[derive(Debug, Clone, Copy)]
55struct iovec {
57 pub iov_base: *mut u8,
59 pub iov_len: usize,
61}
62
63const IOV_MAX: usize = 1024;
64
65pub(crate) fn init() {
66 init_entropy();
67}
68
69#[cfg(all(target_os = "none", not(feature = "common-os")))]
76#[hermit_macro::system]
77#[unsafe(no_mangle)]
78pub extern "C" fn sys_alloc(size: usize, align: usize) -> *mut u8 {
79 let layout_res = Layout::from_size_align(size, align);
80 if layout_res.is_err() || size == 0 {
81 warn!("__sys_alloc called with size {size:#x}, align {align:#x} is an invalid layout!");
82 return ptr::null_mut();
83 }
84 let layout = layout_res.unwrap();
85 let ptr = unsafe { ALLOCATOR.alloc(layout) };
86
87 trace!("__sys_alloc: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})");
88
89 ptr
90}
91
92#[cfg(all(target_os = "none", not(feature = "common-os")))]
93#[hermit_macro::system]
94#[unsafe(no_mangle)]
95pub extern "C" fn sys_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
96 let layout_res = Layout::from_size_align(size, align);
97 if layout_res.is_err() || size == 0 {
98 warn!(
99 "__sys_alloc_zeroed called with size {size:#x}, align {align:#x} is an invalid layout!"
100 );
101 return ptr::null_mut();
102 }
103 let layout = layout_res.unwrap();
104 let ptr = unsafe { ALLOCATOR.alloc_zeroed(layout) };
105
106 trace!("__sys_alloc_zeroed: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})");
107
108 ptr
109}
110
111#[cfg(all(target_os = "none", not(feature = "common-os")))]
112#[hermit_macro::system]
113#[unsafe(no_mangle)]
114pub extern "C" fn sys_malloc(size: usize, align: usize) -> *mut u8 {
115 let layout_res = Layout::from_size_align(size, align);
116 if layout_res.is_err() || size == 0 {
117 warn!("__sys_malloc called with size {size:#x}, align {align:#x} is an invalid layout!");
118 return ptr::null_mut();
119 }
120 let layout = layout_res.unwrap();
121 let ptr = unsafe { ALLOCATOR.alloc(layout) };
122
123 trace!("__sys_malloc: allocate memory at {ptr:p} (size {size:#x}, align {align:#x})");
124
125 ptr
126}
127
128#[cfg(all(target_os = "none", not(feature = "common-os")))]
148#[hermit_macro::system]
149#[unsafe(no_mangle)]
150pub unsafe extern "C" fn sys_realloc(
151 ptr: *mut u8,
152 size: usize,
153 align: usize,
154 new_size: usize,
155) -> *mut u8 {
156 unsafe {
157 let layout_res = Layout::from_size_align(size, align);
158 if layout_res.is_err() || size == 0 || new_size == 0 {
159 warn!(
160 "__sys_realloc called with ptr {ptr:p}, size {size:#x}, align {align:#x}, new_size {new_size:#x} is an invalid layout!"
161 );
162 return ptr::null_mut();
163 }
164 let layout = layout_res.unwrap();
165 let new_ptr = ALLOCATOR.realloc(ptr, layout, new_size);
166
167 if new_ptr.is_null() {
168 debug!(
169 "__sys_realloc failed to resize ptr {ptr:p} with size {size:#x}, align {align:#x}, new_size {new_size:#x} !"
170 );
171 } else {
172 trace!("__sys_realloc: resized memory at {ptr:p}, new address {new_ptr:p}");
173 }
174 new_ptr
175 }
176}
177
178#[cfg(all(target_os = "none", not(feature = "common-os")))]
189#[hermit_macro::system]
190#[unsafe(no_mangle)]
191pub unsafe extern "C" fn sys_dealloc(ptr: *mut u8, size: usize, align: usize) {
192 unsafe {
193 let layout_res = Layout::from_size_align(size, align);
194 if layout_res.is_err() || size == 0 {
195 warn!(
196 "__sys_dealloc called with size {size:#x}, align {align:#x} is an invalid layout!"
197 );
198 debug_assert!(layout_res.is_err(), "__sys_dealloc error: Invalid layout");
199 debug_assert_ne!(size, 0, "__sys_dealloc error: size cannot be 0");
200 } else {
201 trace!("sys_free: deallocate memory at {ptr:p} (size {size:#x})");
202 }
203 let layout = layout_res.unwrap();
204 ALLOCATOR.dealloc(ptr, layout);
205 }
206}
207
208#[cfg(all(target_os = "none", not(feature = "common-os")))]
209#[hermit_macro::system]
210#[unsafe(no_mangle)]
211pub unsafe extern "C" fn sys_free(ptr: *mut u8, size: usize, align: usize) {
212 unsafe {
213 let layout_res = Layout::from_size_align(size, align);
214 if layout_res.is_err() || size == 0 {
215 warn!("__sys_free called with size {size:#x}, align {align:#x} is an invalid layout!");
216 debug_assert!(layout_res.is_err(), "__sys_free error: Invalid layout");
217 debug_assert_ne!(size, 0, "__sys_free error: size cannot be 0");
218 } else {
219 trace!("sys_free: deallocate memory at {ptr:p} (size {size:#x})");
220 }
221 let layout = layout_res.unwrap();
222 ALLOCATOR.dealloc(ptr, layout);
223 }
224}
225
226pub(crate) fn get_application_parameters() -> (i32, *const *const u8, *const *const u8) {
227 use alloc::boxed::Box;
228 use alloc::vec::Vec;
229
230 let mut argv = Vec::new();
231
232 let name = Box::leak(Box::new("bin\0")).as_ptr();
233 argv.push(name);
234
235 let args = env::args();
236 debug!("Setting argv as: {args:?}");
237 for arg in args {
238 let ptr = Box::leak(format!("{arg}\0").into_boxed_str()).as_ptr();
239 argv.push(ptr);
240 }
241
242 let mut envv = Vec::new();
243
244 let envs = env::vars();
245 debug!("Setting envv as: {envs:?}");
246 for (key, value) in envs {
247 let ptr = Box::leak(format!("{key}={value}\0").into_boxed_str()).as_ptr();
248 envv.push(ptr);
249 }
250 envv.push(ptr::null::<u8>());
251
252 let argc = argv.len() as i32;
253 let argv = argv.leak().as_ptr();
254 let envv = if envv.len() == 1 {
256 ptr::null::<*const u8>()
257 } else {
258 envv.leak().as_ptr()
259 };
260
261 (argc, argv, envv)
262}
263
264pub(crate) fn shutdown(arg: i32) -> ! {
265 crate::arch::kernel::print_statistics();
267
268 #[cfg(feature = "uhyve")]
269 if env::is_uhyve() {
270 crate::uhyve::shutdown(arg);
271 }
272
273 panic_println!("exit status {arg}");
275
276 crate::arch::kernel::processor::shutdown(arg)
277}
278
279#[hermit_macro::system(errno)]
280#[unsafe(no_mangle)]
281pub unsafe extern "C" fn sys_unlink(name: *const c_char) -> i32 {
282 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
283
284 fs::unlink(name).map_or_else(|e| -i32::from(e), |()| 0)
285}
286
287#[hermit_macro::system(errno)]
288#[unsafe(no_mangle)]
289pub unsafe extern "C" fn sys_mkdir(name: *const c_char, mode: u32) -> i32 {
290 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
291 let Some(mode) = AccessPermission::from_bits(mode) else {
292 return -i32::from(Errno::Inval);
293 };
294
295 fs::create_dir(name, mode).map_or_else(|e| -i32::from(e), |()| 0)
296}
297
298#[hermit_macro::system(errno)]
299#[unsafe(no_mangle)]
300pub unsafe extern "C" fn sys_rmdir(name: *const c_char) -> i32 {
301 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
302
303 fs::remove_dir(name).map_or_else(|e| -i32::from(e), |()| 0)
304}
305
306#[hermit_macro::system(errno)]
307#[unsafe(no_mangle)]
308pub unsafe extern "C" fn sys_stat(name: *const c_char, stat: *mut FileAttr) -> i32 {
309 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
310
311 match fs::read_stat(name) {
312 Ok(attr) => unsafe {
313 *stat = attr;
314 0
315 },
316 Err(e) => -i32::from(e),
317 }
318}
319
320#[hermit_macro::system(errno)]
321#[unsafe(no_mangle)]
322pub unsafe extern "C" fn sys_lstat(name: *const c_char, stat: *mut FileAttr) -> i32 {
323 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
324
325 match fs::read_lstat(name) {
326 Ok(attr) => unsafe {
327 *stat = attr;
328 0
329 },
330 Err(e) => -i32::from(e),
331 }
332}
333
334#[hermit_macro::system(errno)]
335#[unsafe(no_mangle)]
336pub unsafe extern "C" fn sys_fstat(fd: RawFd, stat: *mut FileAttr) -> i32 {
337 if stat.is_null() {
338 return -i32::from(Errno::Inval);
339 }
340
341 fd::fstat(fd).map_or_else(
342 |e| -i32::from(e),
343 |v| unsafe {
344 *stat = v;
345 0
346 },
347 )
348}
349
350#[hermit_macro::system(errno)]
351#[unsafe(no_mangle)]
352pub unsafe extern "C" fn sys_opendir(name: *const c_char) -> RawFd {
353 let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() else {
354 return -i32::from(Errno::Inval);
355 };
356
357 fs::opendir(name).unwrap_or_else(|e| -i32::from(e))
358}
359
360#[hermit_macro::system(errno)]
361#[unsafe(no_mangle)]
362pub unsafe extern "C" fn sys_open(name: *const c_char, flags: i32, mode: u32) -> RawFd {
363 let Some(flags) = OpenOption::from_bits(flags) else {
364 return -i32::from(Errno::Inval);
365 };
366 let Some(mode) = AccessPermission::from_bits(mode) else {
367 return -i32::from(Errno::Inval);
368 };
369
370 let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() else {
371 return -i32::from(Errno::Inval);
372 };
373
374 fs::open(name, flags, mode).unwrap_or_else(|e| -i32::from(e))
375}
376
377#[hermit_macro::system]
378#[unsafe(no_mangle)]
379pub unsafe extern "C" fn sys_getcwd(buf: *mut c_char, size: usize) -> *const c_char {
380 let error = |e: Errno| {
381 e.set_errno();
382 ptr::null::<c_char>()
383 };
384
385 if size == 0 {
386 return error(Errno::Inval);
387 }
388
389 if buf.is_null() {
390 return error(Errno::Noent);
392 }
393
394 let cwd = match fs::get_cwd() {
395 Err(e) => {
396 return error(e);
397 }
398 Ok(cwd) => cwd,
399 };
400
401 let Ok(cwd) = CString::new(cwd) else {
402 return error(Errno::Noent);
403 };
404
405 if (cwd.count_bytes() + 1) > size {
406 return error(Errno::Range);
407 }
408
409 unsafe {
410 buf.copy_from(cwd.as_ptr(), size);
411 }
412
413 buf
414}
415
416#[hermit_macro::system(errno)]
417#[unsafe(no_mangle)]
418pub extern "C" fn sys_fchdir(_fd: RawFd) -> i32 {
419 -i32::from(Errno::Nosys)
420}
421
422#[hermit_macro::system(errno)]
423#[unsafe(no_mangle)]
424pub unsafe extern "C" fn sys_chdir(path: *mut c_char) -> i32 {
425 let Ok(name) = unsafe { CStr::from_ptr(path) }.to_str() else {
426 return -i32::from(Errno::Inval);
427 };
428
429 fs::set_cwd(name)
430 .map(|()| 0)
431 .unwrap_or_else(|e| -i32::from(e))
432}
433
434#[hermit_macro::system]
435#[unsafe(no_mangle)]
436pub unsafe extern "C" fn sys_umask(umask: u32) -> u32 {
437 fs::umask(AccessPermission::from_bits_truncate(umask)).bits()
438}
439
440#[hermit_macro::system(errno)]
441#[unsafe(no_mangle)]
442pub unsafe extern "C" fn sys_faccessat(
443 dirfd: RawFd,
444 name: *const c_char,
445 _mode: i32,
446 flags: i32,
447) -> i32 {
448 let Some(access_option) = AccessOption::from_bits(flags) else {
449 return -i32::from(Errno::Inval);
450 };
451
452 let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() else {
453 return -i32::from(Errno::Inval);
454 };
455
456 const AT_SYMLINK_NOFOLLOW: i32 = 0x100;
457 const AT_FDCWD: i32 = -100;
458
459 let stat = if name.starts_with("/") || dirfd == AT_FDCWD {
460 let no_follow: bool = (flags & AT_SYMLINK_NOFOLLOW) != 0;
461
462 if no_follow {
463 fs::read_stat(name)
464 } else {
465 fs::read_lstat(name)
466 }
467 } else {
468 warn!("faccessat with directory relative to fd is not implemented!");
469 return -i32::from(Errno::Nosys);
470 };
471
472 match stat {
473 Err(e) => -i32::from(e),
474 Ok(stat) if access_option.can_access(stat.st_mode) => 0,
475 Ok(_) => -i32::from(Errno::Acces),
476 }
477}
478
479#[hermit_macro::system(errno)]
480#[unsafe(no_mangle)]
481pub unsafe extern "C" fn sys_access(name: *const c_char, flags: i32) -> i32 {
482 let Some(access_option) = AccessOption::from_bits(flags) else {
483 return -i32::from(Errno::Inval);
484 };
485
486 let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() else {
487 return -i32::from(Errno::Inval);
488 };
489
490 match fs::read_lstat(name) {
491 Err(e) => -i32::from(e),
492 Ok(stat) if access_option.can_access(stat.st_mode) => 0,
493 Ok(_) => -i32::from(Errno::Acces),
494 }
495}
496
497#[hermit_macro::system(errno)]
498#[unsafe(no_mangle)]
499pub unsafe extern "C" fn sys_fchmod(fd: RawFd, mode: u32) -> i32 {
500 let Some(access_permission) = AccessPermission::from_bits(mode) else {
501 return -i32::from(Errno::Inval);
502 };
503
504 fd::chmod(fd, access_permission)
505 .map(|()| 0)
506 .unwrap_or_else(|e| -i32::from(e))
507}
508
509#[hermit_macro::system(errno)]
510#[unsafe(no_mangle)]
511pub extern "C" fn sys_close(fd: RawFd) -> i32 {
512 let obj = remove_object(fd);
513 obj.map_or_else(|e| -i32::from(e), |_| 0)
514}
515
516#[hermit_macro::system(errno)]
517#[unsafe(no_mangle)]
518pub unsafe extern "C" fn sys_read(fd: RawFd, buf: *mut u8, len: usize) -> isize {
519 let slice = unsafe { slice::from_raw_parts_mut(buf.cast::<MaybeUninit<u8>>(), len) };
520 let slice = init_buf::init_buf(slice);
521 fd::read(fd, slice).map_or_else(
522 |e| isize::try_from(-i32::from(e)).unwrap(),
523 |v| v.try_into().unwrap(),
524 )
525}
526
527#[hermit_macro::system(errno)]
543#[unsafe(no_mangle)]
544pub unsafe extern "C" fn sys_readv(fd: i32, iov: *const iovec, iovcnt: usize) -> isize {
545 if !(0..=IOV_MAX).contains(&iovcnt) {
546 return (-i32::from(Errno::Inval)).try_into().unwrap();
547 }
548
549 let mut read_bytes: isize = 0;
550 let iovec_buffers = unsafe { slice::from_raw_parts(iov, iovcnt) };
551
552 for iovec_buf in iovec_buffers {
553 let buf =
554 unsafe { slice::from_raw_parts_mut(iovec_buf.iov_base.cast(), iovec_buf.iov_len) };
555
556 let len = fd::read(fd, buf).map_or_else(
557 |e| isize::try_from(-i32::from(e)).unwrap(),
558 |v| v.try_into().unwrap(),
559 );
560
561 if len < 0 {
562 return len;
563 }
564
565 read_bytes += len;
566
567 if len < isize::try_from(iovec_buf.iov_len).unwrap() {
568 return read_bytes;
569 }
570 }
571
572 read_bytes
573}
574
575unsafe fn write(fd: RawFd, buf: *const u8, len: usize) -> isize {
576 let slice = unsafe { slice::from_raw_parts(buf, len) };
577 fd::write(fd, slice).map_or_else(
578 |e| isize::try_from(-i32::from(e)).unwrap(),
579 |v| v.try_into().unwrap(),
580 )
581}
582
583#[hermit_macro::system(errno)]
584#[unsafe(no_mangle)]
585pub unsafe extern "C" fn sys_write(fd: RawFd, buf: *const u8, len: usize) -> isize {
586 unsafe { write(fd, buf, len) }
587}
588
589#[hermit_macro::system(errno)]
590#[unsafe(no_mangle)]
591pub unsafe extern "C" fn sys_ftruncate(fd: RawFd, size: usize) -> i32 {
592 fd::truncate(fd, size).map_or_else(|e| -i32::from(e), |()| 0)
593}
594
595#[hermit_macro::system(errno)]
596#[unsafe(no_mangle)]
597pub unsafe extern "C" fn sys_truncate(path: *const c_char, size: usize) -> i32 {
598 let Ok(path) = unsafe { CStr::from_ptr(path) }.to_str() else {
599 return -i32::from(Errno::Inval);
600 };
601
602 fs::truncate(path, size).map_or_else(|e| -i32::from(e), |()| 0)
603}
604
605#[hermit_macro::system(errno)]
621#[unsafe(no_mangle)]
622pub unsafe extern "C" fn sys_writev(fd: RawFd, iov: *const iovec, iovcnt: usize) -> isize {
623 if !(0..=IOV_MAX).contains(&iovcnt) {
624 return (-i32::from(Errno::Inval)).try_into().unwrap();
625 }
626
627 let mut written_bytes: isize = 0;
628 let iovec_buffers = unsafe { slice::from_raw_parts(iov, iovcnt) };
629
630 for iovec_buf in iovec_buffers {
631 let buf = unsafe { slice::from_raw_parts(iovec_buf.iov_base, iovec_buf.iov_len) };
632
633 let len = fd::write(fd, buf).map_or_else(
634 |e| isize::try_from(-i32::from(e)).unwrap(),
635 |v| v.try_into().unwrap(),
636 );
637
638 if len < 0 {
639 return len;
640 }
641
642 written_bytes += len;
643
644 if len < isize::try_from(iovec_buf.iov_len).unwrap() {
645 return written_bytes;
646 }
647 }
648
649 written_bytes
650}
651
652#[hermit_macro::system(errno)]
653#[unsafe(no_mangle)]
654pub unsafe extern "C" fn sys_ioctl(fd: RawFd, cmd: i32, argp: *mut core::ffi::c_void) -> i32 {
655 const FIONBIO: i32 = 0x8008_667eu32 as i32;
656
657 if cmd == FIONBIO {
658 let value = unsafe { *(argp as *const i32) };
659 let status_flags = if value != 0 {
660 fd::StatusFlags::O_NONBLOCK
661 } else {
662 fd::StatusFlags::empty()
663 };
664
665 let obj = get_object(fd);
666 obj.map_or_else(
667 |e| -i32::from(e),
668 |v| {
669 block_on(
670 async { v.write().await.set_status_flags(status_flags).await },
671 None,
672 )
673 .map_or_else(|e| -i32::from(e), |()| 0)
674 },
675 )
676 } else {
677 -i32::from(Errno::Inval)
678 }
679}
680
681#[hermit_macro::system(errno)]
683#[unsafe(no_mangle)]
684pub extern "C" fn sys_fcntl(fd: i32, cmd: i32, arg: i32) -> i32 {
685 const F_GETFD: i32 = 1;
686 const F_SETFD: i32 = 2;
687 const F_GETFL: i32 = 3;
688 const F_SETFL: i32 = 4;
689 const FD_CLOEXEC: i32 = 1;
690
691 if cmd == F_SETFD && arg == FD_CLOEXEC {
692 0
693 } else if cmd == F_GETFD {
694 0
696 } else if cmd == F_GETFL {
697 let obj = get_object(fd);
698 obj.map_or_else(
699 |e| -i32::from(e),
700 |v| {
701 block_on(async { v.read().await.status_flags().await }, None)
702 .map_or_else(|e| -i32::from(e), |status_flags| status_flags.bits())
703 },
704 )
705 } else if cmd == F_SETFL {
706 let obj = get_object(fd);
707 obj.map_or_else(
708 |e| -i32::from(e),
709 |v| {
710 block_on(
711 async {
712 v.write()
713 .await
714 .set_status_flags(fd::StatusFlags::from_bits_retain(arg))
715 .await
716 },
717 None,
718 )
719 .map_or_else(|e| -i32::from(e), |()| 0)
720 },
721 )
722 } else {
723 -i32::from(Errno::Inval)
724 }
725}
726
727#[hermit_macro::system(errno)]
728#[unsafe(no_mangle)]
729pub extern "C" fn sys_lseek(fd: RawFd, offset: isize, whence: i32) -> isize {
730 let whence = u8::try_from(whence).unwrap();
731 let whence = SeekWhence::try_from(whence).unwrap();
732 fd::lseek(fd, offset, whence).unwrap_or_else(|e| isize::try_from(-i32::from(e)).unwrap())
733}
734
735#[repr(C)]
736pub struct Dirent64 {
737 pub d_ino: u64,
739 pub d_off: i64,
741 pub d_reclen: u16,
743 pub d_type: fs::FileType,
745 pub d_name: PhantomData<c_char>,
747}
748impl Dirent64 {
749 #[allow(dead_code)]
755 unsafe fn display<'a>(&'a self) -> Dirent64Display<'a> {
756 unsafe { Dirent64Display::new(self) }
757 }
758}
759
760mod dirent_display {
761 use core::ffi::{CStr, c_char};
762 use core::fmt;
763
764 use super::Dirent64;
765
766 pub(super) struct Dirent64Display<'a> {
770 dirent: &'a Dirent64,
771 }
772
773 impl<'a> Dirent64Display<'a> {
774 pub(super) unsafe fn new(dirent: &'a Dirent64) -> Self {
777 Self { dirent }
778 }
779 }
780
781 impl fmt::Debug for Dirent64Display<'_> {
782 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
783 let cstr = unsafe { CStr::from_ptr((&raw const self.dirent.d_name).cast::<c_char>()) };
784
785 f.debug_struct("Dirent64")
786 .field("d_ino", &self.dirent.d_ino)
787 .field("d_off", &self.dirent.d_off)
788 .field("d_reclen", &self.dirent.d_reclen)
789 .field("d_type", &self.dirent.d_type)
790 .field("d_name", &cstr)
791 .finish()
792 }
793 }
794}
795
796#[hermit_macro::system(errno)]
813#[unsafe(no_mangle)]
814pub unsafe extern "C" fn sys_getdents64(fd: RawFd, dirp: *mut Dirent64, count: usize) -> i64 {
815 debug!("getdents for fd {fd:?} - count: {count}");
816 if dirp.is_null() || count == 0 {
817 return (-i32::from(Errno::Inval)).into();
818 }
819
820 let slice = unsafe { slice::from_raw_parts_mut(dirp.cast(), count) };
821
822 let obj = get_object(fd);
823 obj.map_or_else(
824 |_| (-i32::from(Errno::Inval)).into(),
825 |v| {
826 block_on(async { v.read().await.getdents(slice).await }, None)
827 .map_or_else(|e| (-i32::from(e)).into(), |cnt| cnt as i64)
828 },
829 )
830}
831
832#[hermit_macro::system(errno)]
833#[unsafe(no_mangle)]
834pub extern "C" fn sys_dup(fd: i32) -> i32 {
835 dup_object(fd).unwrap_or_else(|e| -i32::from(e))
836}
837
838#[hermit_macro::system(errno)]
839#[unsafe(no_mangle)]
840pub extern "C" fn sys_dup2(fd1: i32, fd2: i32) -> i32 {
841 dup_object2(fd1, fd2).unwrap_or_else(|e| -i32::from(e))
842}
843
844#[hermit_macro::system(errno)]
845#[unsafe(no_mangle)]
846pub extern "C" fn sys_isatty(fd: i32) -> i32 {
847 match isatty(fd) {
848 Err(e) => -i32::from(e),
849 Ok(v) => {
850 if v {
851 1
852 } else {
853 0
854 }
855 }
856 }
857}
858
859#[hermit_macro::system(errno)]
860#[unsafe(no_mangle)]
861pub unsafe extern "C" fn sys_poll(fds: *mut PollFd, nfds: usize, timeout: i32) -> i32 {
862 let slice = unsafe { slice::from_raw_parts_mut(fds, nfds) };
863 let timeout = if timeout >= 0 {
864 Some(core::time::Duration::from_millis(
865 timeout.try_into().unwrap(),
866 ))
867 } else {
868 None
869 };
870
871 fd::poll(slice, timeout).map_or_else(
872 |e| {
873 if e == Errno::Time { 0 } else { -i32::from(e) }
874 },
875 |v| v.try_into().unwrap(),
876 )
877}
878
879#[hermit_macro::system(errno)]
880#[unsafe(no_mangle)]
881pub extern "C" fn sys_eventfd(initval: u64, flags: i16) -> i32 {
882 let Some(flags) = EventFlags::from_bits(flags) else {
883 return -i32::from(Errno::Inval);
884 };
885
886 fd::eventfd(initval, flags).unwrap_or_else(|e| -i32::from(e))
887}
888
889#[hermit_macro::system]
890#[unsafe(no_mangle)]
891pub extern "C" fn sys_image_start_addr() -> usize {
892 crate::mm::kernel_start_address().as_usize()
893}
894
895#[cfg(test)]
896mod tests {
897 use super::*;
898
899 #[cfg(target_os = "none")]
900 #[test_case]
901 fn test_get_application_parameters() {
902 env::init();
903 let (argc, argv, _envp) = get_application_parameters();
904 assert_ne!(argc, 0);
905 assert_ne!(argv, ptr::null());
906 }
907}