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