1#![allow(clippy::result_unit_err)]
2
3use alloc::boxed::Box;
4use alloc::ffi::CString;
5use alloc::vec::Vec;
6use core::ffi::{CStr, c_char};
7use core::marker::PhantomData;
8use core::mem::MaybeUninit;
9use core::{mem, ptr, slice};
10
11use align_address::Align;
12use dirent_display::Dirent64Display;
13
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::system::*;
21pub use self::tasks::*;
22pub use self::timer::*;
23use crate::errno::{Errno, ToErrno};
24use crate::executor::block_on;
25use crate::fd::{
26 self, AccessOption, AccessPermission, EventFlags, ObjectInterface, OpenOption, PollFd, RawFd,
27 dup_object, dup_object2, get_object, isatty, remove_object,
28};
29use crate::fs::{self, FileAttr, SeekWhence};
30use crate::{env, init_buf};
31
32#[cfg(all(target_os = "none", not(feature = "common-os")))]
33mod alloc_;
34mod entropy;
35mod futex;
36#[cfg(feature = "mman")]
37pub mod mman;
38mod processor;
39#[cfg(feature = "newlib")]
40mod recmutex;
41mod semaphore;
42#[cfg(any(feature = "net", feature = "virtio-vsock"))]
43pub mod socket;
44mod system;
45#[cfg(feature = "common-os")]
46pub(crate) mod table;
47mod tasks;
48mod timer;
49
50#[repr(C)]
51#[derive(Debug, Clone, Copy)]
52struct iovec {
54 pub iov_base: *mut u8,
56 pub iov_len: usize,
58}
59
60const IOV_MAX: usize = 1024;
61
62pub(crate) fn init() {
63 init_entropy();
64}
65
66pub(crate) fn get_application_parameters() -> (i32, *const *const u8, *const *const u8) {
67 let mut argv = Vec::new();
68
69 let name = Box::leak(Box::new("bin\0")).as_ptr();
70 argv.push(name);
71
72 let args = env::args();
73 debug!("Setting argv as: {args:?}");
74 for arg in args {
75 let ptr = Box::leak(format!("{arg}\0").into_boxed_str()).as_ptr();
76 argv.push(ptr);
77 }
78
79 let mut envv = Vec::new();
80
81 let envs = env::vars();
82 debug!("Setting envv as: {envs:?}");
83 for (key, value) in envs {
84 let ptr = Box::leak(format!("{key}={value}\0").into_boxed_str()).as_ptr();
85 envv.push(ptr);
86 }
87 envv.push(ptr::null::<u8>());
88
89 let argc = argv.len() as i32;
90 let argv = argv.leak().as_ptr();
91 let envv = if envv.len() == 1 {
93 ptr::null::<*const u8>()
94 } else {
95 envv.leak().as_ptr()
96 };
97
98 (argc, argv, envv)
99}
100
101pub(crate) fn shutdown(arg: i32) -> ! {
102 crate::arch::kernel::print_statistics();
104
105 #[cfg(feature = "uhyve")]
106 use crate::env::UhyveStartInfo;
107
108 #[cfg(feature = "uhyve")]
109 if env::start_info().is_uhyve() {
110 crate::uhyve::shutdown(arg);
111 }
112
113 panic_println!("exit status {arg}");
115
116 crate::arch::kernel::processor::shutdown(arg)
117}
118
119#[hermit_macro::system(errno)]
120#[unsafe(no_mangle)]
121pub unsafe extern "C" fn sys_unlink(name: *const c_char) -> i32 {
122 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
123
124 fs::unlink(name).map_or_else(|e| -i32::from(e), |()| 0)
125}
126
127#[hermit_macro::system(errno)]
128#[unsafe(no_mangle)]
129pub unsafe extern "C" fn sys_mkdir(name: *const c_char, mode: u32) -> i32 {
130 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
131 let Some(mode) = AccessPermission::from_bits(mode) else {
132 return -i32::from(Errno::Inval);
133 };
134
135 fs::create_dir(name, mode).map_or_else(|e| -i32::from(e), |()| 0)
136}
137
138#[hermit_macro::system(errno)]
139#[unsafe(no_mangle)]
140pub unsafe extern "C" fn sys_rmdir(name: *const c_char) -> i32 {
141 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
142
143 fs::remove_dir(name).map_or_else(|e| -i32::from(e), |()| 0)
144}
145
146#[hermit_macro::system(errno)]
147#[unsafe(no_mangle)]
148pub unsafe extern "C" fn sys_stat(name: *const c_char, stat: *mut FileAttr) -> i32 {
149 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
150
151 match fs::read_stat(name) {
152 Ok(attr) => unsafe {
153 *stat = attr;
154 0
155 },
156 Err(e) => -i32::from(e),
157 }
158}
159
160#[hermit_macro::system(errno)]
161#[unsafe(no_mangle)]
162pub unsafe extern "C" fn sys_lstat(name: *const c_char, stat: *mut FileAttr) -> i32 {
163 let name = unsafe { CStr::from_ptr(name) }.to_str().unwrap();
164
165 match fs::read_lstat(name) {
166 Ok(attr) => unsafe {
167 *stat = attr;
168 0
169 },
170 Err(e) => -i32::from(e),
171 }
172}
173
174#[hermit_macro::system(errno)]
175#[unsafe(no_mangle)]
176pub unsafe extern "C" fn sys_fstat(fd: RawFd, stat: *mut FileAttr) -> i32 {
177 if stat.is_null() {
178 return -i32::from(Errno::Inval);
179 }
180
181 fd::fstat(fd).map_or_else(
182 |e| -i32::from(e),
183 |v| unsafe {
184 *stat = v;
185 0
186 },
187 )
188}
189
190#[hermit_macro::system(errno)]
191#[unsafe(no_mangle)]
192pub unsafe extern "C" fn sys_opendir(name: *const c_char) -> RawFd {
193 let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() else {
194 return -i32::from(Errno::Inval);
195 };
196
197 fs::opendir(name).unwrap_or_else(|e| -i32::from(e))
198}
199
200#[hermit_macro::system(errno)]
201#[unsafe(no_mangle)]
202pub unsafe extern "C" fn sys_open(name: *const c_char, flags: i32, mode: u32) -> RawFd {
203 let Some(flags) = OpenOption::from_bits(flags) else {
204 return -i32::from(Errno::Inval);
205 };
206 let Some(mode) = AccessPermission::from_bits(mode) else {
207 return -i32::from(Errno::Inval);
208 };
209
210 let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() else {
211 return -i32::from(Errno::Inval);
212 };
213
214 fs::open(name, flags, mode).unwrap_or_else(|e| -i32::from(e))
215}
216
217#[hermit_macro::system]
218#[unsafe(no_mangle)]
219pub unsafe extern "C" fn sys_getcwd(buf: *mut c_char, size: usize) -> *const c_char {
220 let error = |e: Errno| {
221 e.set_errno();
222 ptr::null::<c_char>()
223 };
224
225 if size == 0 {
226 return error(Errno::Inval);
227 }
228
229 if buf.is_null() {
230 return error(Errno::Noent);
232 }
233
234 let cwd = match fs::get_cwd() {
235 Err(e) => {
236 return error(e);
237 }
238 Ok(cwd) => cwd,
239 };
240
241 let Ok(cwd) = CString::new(cwd) else {
242 return error(Errno::Noent);
243 };
244
245 if (cwd.count_bytes() + 1) > size {
246 return error(Errno::Range);
247 }
248
249 unsafe {
250 buf.copy_from(cwd.as_ptr(), size);
251 }
252
253 buf
254}
255
256#[hermit_macro::system(errno)]
257#[unsafe(no_mangle)]
258pub extern "C" fn sys_fchdir(_fd: RawFd) -> i32 {
259 -i32::from(Errno::Nosys)
260}
261
262#[hermit_macro::system(errno)]
263#[unsafe(no_mangle)]
264pub unsafe extern "C" fn sys_chdir(path: *mut c_char) -> i32 {
265 let Ok(name) = unsafe { CStr::from_ptr(path) }.to_str() else {
266 return -i32::from(Errno::Inval);
267 };
268
269 fs::set_cwd(name)
270 .map(|()| 0)
271 .unwrap_or_else(|e| -i32::from(e))
272}
273
274#[hermit_macro::system]
275#[unsafe(no_mangle)]
276pub unsafe extern "C" fn sys_umask(umask: u32) -> u32 {
277 fs::umask(AccessPermission::from_bits_truncate(umask)).bits()
278}
279
280#[hermit_macro::system(errno)]
281#[unsafe(no_mangle)]
282pub unsafe extern "C" fn sys_faccessat(
283 dirfd: RawFd,
284 name: *const c_char,
285 _mode: i32,
286 flags: i32,
287) -> i32 {
288 let Some(access_option) = AccessOption::from_bits(flags) else {
289 return -i32::from(Errno::Inval);
290 };
291
292 let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() else {
293 return -i32::from(Errno::Inval);
294 };
295
296 const AT_SYMLINK_NOFOLLOW: i32 = 0x100;
297 const AT_FDCWD: i32 = -100;
298
299 let stat = if name.starts_with("/") || dirfd == AT_FDCWD {
300 let no_follow: bool = (flags & AT_SYMLINK_NOFOLLOW) != 0;
301
302 if no_follow {
303 fs::read_stat(name)
304 } else {
305 fs::read_lstat(name)
306 }
307 } else {
308 warn!("faccessat with directory relative to fd is not implemented!");
309 return -i32::from(Errno::Nosys);
310 };
311
312 match stat {
313 Err(e) => -i32::from(e),
314 Ok(stat) if access_option.can_access(stat.st_mode) => 0,
315 Ok(_) => -i32::from(Errno::Acces),
316 }
317}
318
319#[hermit_macro::system(errno)]
320#[unsafe(no_mangle)]
321pub unsafe extern "C" fn sys_access(name: *const c_char, flags: i32) -> i32 {
322 let Some(access_option) = AccessOption::from_bits(flags) else {
323 return -i32::from(Errno::Inval);
324 };
325
326 let Ok(name) = unsafe { CStr::from_ptr(name) }.to_str() else {
327 return -i32::from(Errno::Inval);
328 };
329
330 match fs::read_lstat(name) {
331 Err(e) => -i32::from(e),
332 Ok(stat) if access_option.can_access(stat.st_mode) => 0,
333 Ok(_) => -i32::from(Errno::Acces),
334 }
335}
336
337#[hermit_macro::system(errno)]
338#[unsafe(no_mangle)]
339pub unsafe extern "C" fn sys_fchmod(fd: RawFd, mode: u32) -> i32 {
340 let Some(access_permission) = AccessPermission::from_bits(mode) else {
341 return -i32::from(Errno::Inval);
342 };
343
344 fd::chmod(fd, access_permission)
345 .map(|()| 0)
346 .unwrap_or_else(|e| -i32::from(e))
347}
348
349#[hermit_macro::system(errno)]
350#[unsafe(no_mangle)]
351pub extern "C" fn sys_close(fd: RawFd) -> i32 {
352 let obj = remove_object(fd);
353 obj.map_or_else(|e| -i32::from(e), |_| 0)
354}
355
356#[hermit_macro::system(errno)]
357#[unsafe(no_mangle)]
358pub unsafe extern "C" fn sys_read(fd: RawFd, buf: *mut u8, len: usize) -> isize {
359 let slice = unsafe { slice::from_raw_parts_mut(buf.cast::<MaybeUninit<u8>>(), len) };
360 let slice = init_buf::init_buf(slice);
361 fd::read(fd, slice).map_or_else(
362 |e| isize::try_from(-i32::from(e)).unwrap(),
363 |v| v.try_into().unwrap(),
364 )
365}
366
367#[hermit_macro::system(errno)]
383#[unsafe(no_mangle)]
384pub unsafe extern "C" fn sys_readv(fd: RawFd, iov: *const iovec, iovcnt: usize) -> isize {
385 if !(0..=IOV_MAX).contains(&iovcnt) {
386 return (-i32::from(Errno::Inval)).try_into().unwrap();
387 }
388
389 let mut read_bytes: isize = 0;
390 let iovec_buffers = unsafe { slice::from_raw_parts(iov, iovcnt) };
391
392 for iovec_buf in iovec_buffers {
393 let iov_base = iovec_buf.iov_base.cast::<MaybeUninit<u8>>();
394 let buf = unsafe { slice::from_raw_parts_mut(iov_base, iovec_buf.iov_len) };
395 let buf = init_buf::init_buf(buf);
396
397 let len = fd::read(fd, buf).map_or_else(
398 |e| isize::try_from(-i32::from(e)).unwrap(),
399 |v| v.try_into().unwrap(),
400 );
401
402 if len < 0 {
403 return len;
404 }
405
406 read_bytes += len;
407
408 if len < isize::try_from(iovec_buf.iov_len).unwrap() {
409 return read_bytes;
410 }
411 }
412
413 read_bytes
414}
415
416unsafe fn write(fd: RawFd, buf: *const u8, len: usize) -> isize {
417 let slice = unsafe { slice::from_raw_parts(buf, len) };
418 fd::write(fd, slice).map_or_else(
419 |e| isize::try_from(-i32::from(e)).unwrap(),
420 |v| v.try_into().unwrap(),
421 )
422}
423
424#[hermit_macro::system(errno)]
425#[unsafe(no_mangle)]
426pub unsafe extern "C" fn sys_write(fd: RawFd, buf: *const u8, len: usize) -> isize {
427 unsafe { write(fd, buf, len) }
428}
429
430#[hermit_macro::system(errno)]
431#[unsafe(no_mangle)]
432pub unsafe extern "C" fn sys_ftruncate(fd: RawFd, size: usize) -> i32 {
433 fd::truncate(fd, size).map_or_else(|e| -i32::from(e), |()| 0)
434}
435
436#[hermit_macro::system(errno)]
437#[unsafe(no_mangle)]
438pub unsafe extern "C" fn sys_truncate(path: *const c_char, size: usize) -> i32 {
439 let Ok(path) = unsafe { CStr::from_ptr(path) }.to_str() else {
440 return -i32::from(Errno::Inval);
441 };
442
443 fs::truncate(path, size).map_or_else(|e| -i32::from(e), |()| 0)
444}
445
446#[hermit_macro::system(errno)]
462#[unsafe(no_mangle)]
463pub unsafe extern "C" fn sys_writev(fd: RawFd, iov: *const iovec, iovcnt: usize) -> isize {
464 if !(0..=IOV_MAX).contains(&iovcnt) {
465 return (-i32::from(Errno::Inval)).try_into().unwrap();
466 }
467
468 let mut written_bytes: isize = 0;
469 let iovec_buffers = unsafe { slice::from_raw_parts(iov, iovcnt) };
470
471 for iovec_buf in iovec_buffers {
472 let buf = unsafe { slice::from_raw_parts(iovec_buf.iov_base, iovec_buf.iov_len) };
473
474 let len = fd::write(fd, buf).map_or_else(
475 |e| isize::try_from(-i32::from(e)).unwrap(),
476 |v| v.try_into().unwrap(),
477 );
478
479 if len < 0 {
480 return len;
481 }
482
483 written_bytes += len;
484
485 if len < isize::try_from(iovec_buf.iov_len).unwrap() {
486 return written_bytes;
487 }
488 }
489
490 written_bytes
491}
492
493#[hermit_macro::system(errno)]
494#[unsafe(no_mangle)]
495pub unsafe extern "C" fn sys_ioctl(fd: RawFd, cmd: i32, argp: *mut core::ffi::c_void) -> i32 {
496 const FIONBIO: i32 = 0x8008_667eu32 as i32;
497
498 if cmd == FIONBIO {
499 let value = unsafe { *(argp as *const i32) };
500 let status_flags = if value != 0 {
501 fd::StatusFlags::O_NONBLOCK
502 } else {
503 fd::StatusFlags::empty()
504 };
505
506 let obj = get_object(fd);
507 obj.map_or_else(
508 |e| -i32::from(e),
509 |v| {
510 block_on(
511 async { v.write().await.set_status_flags(status_flags).await },
512 None,
513 )
514 .map_or_else(|e| -i32::from(e), |()| 0)
515 },
516 )
517 } else {
518 -i32::from(Errno::Inval)
519 }
520}
521
522#[hermit_macro::system(errno)]
524#[unsafe(no_mangle)]
525pub extern "C" fn sys_fcntl(fd: RawFd, cmd: i32, arg: i32) -> i32 {
526 const F_GETFD: i32 = 1;
527 const F_SETFD: i32 = 2;
528 const F_GETFL: i32 = 3;
529 const F_SETFL: i32 = 4;
530 const FD_CLOEXEC: i32 = 1;
531
532 if cmd == F_SETFD && arg == FD_CLOEXEC {
533 0
534 } else if cmd == F_GETFD {
535 0
537 } else if cmd == F_GETFL {
538 let obj = get_object(fd);
539 obj.map_or_else(
540 |e| -i32::from(e),
541 |v| {
542 block_on(async { v.read().await.status_flags().await }, None)
543 .map_or_else(|e| -i32::from(e), |status_flags| status_flags.bits())
544 },
545 )
546 } else if cmd == F_SETFL {
547 let obj = get_object(fd);
548 obj.map_or_else(
549 |e| -i32::from(e),
550 |v| {
551 block_on(
552 async {
553 v.write()
554 .await
555 .set_status_flags(fd::StatusFlags::from_bits_retain(arg))
556 .await
557 },
558 None,
559 )
560 .map_or_else(|e| -i32::from(e), |()| 0)
561 },
562 )
563 } else {
564 -i32::from(Errno::Inval)
565 }
566}
567
568#[hermit_macro::system(errno)]
569#[unsafe(no_mangle)]
570pub extern "C" fn sys_lseek(fd: RawFd, offset: isize, whence: i32) -> isize {
571 let whence = u8::try_from(whence).unwrap();
572 let whence = SeekWhence::try_from(whence).unwrap();
573 fd::lseek(fd, offset, whence).unwrap_or_else(|e| isize::try_from(-i32::from(e)).unwrap())
574}
575
576#[repr(C)]
577pub struct Dirent64 {
578 pub d_ino: u64,
580 pub d_off: i64,
582 pub d_reclen: u16,
584 pub d_type: fs::FileType,
586 pub d_name: PhantomData<c_char>,
588}
589impl Dirent64 {
590 #[allow(dead_code)]
596 unsafe fn display<'a>(&'a self) -> Dirent64Display<'a> {
597 unsafe { Dirent64Display::new(self) }
598 }
599}
600
601mod dirent_display {
602 use core::ffi::{CStr, c_char};
603 use core::fmt;
604
605 use super::Dirent64;
606
607 pub(super) struct Dirent64Display<'a> {
611 dirent: &'a Dirent64,
612 }
613
614 impl<'a> Dirent64Display<'a> {
615 pub(super) unsafe fn new(dirent: &'a Dirent64) -> Self {
618 Self { dirent }
619 }
620 }
621
622 impl fmt::Debug for Dirent64Display<'_> {
623 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
624 let cstr = unsafe { CStr::from_ptr((&raw const self.dirent.d_name).cast::<c_char>()) };
625
626 f.debug_struct("Dirent64")
627 .field("d_ino", &self.dirent.d_ino)
628 .field("d_off", &self.dirent.d_off)
629 .field("d_reclen", &self.dirent.d_reclen)
630 .field("d_type", &self.dirent.d_type)
631 .field("d_name", &cstr)
632 .finish()
633 }
634 }
635}
636
637#[repr(C)]
639pub struct PosixDent {
640 pub d_ino: u64,
642 pub d_reclen: u16,
644 pub d_type: fs::FileType,
646 pub d_name: PhantomData<c_char>,
648}
649
650#[derive(Clone, Copy)]
652pub(crate) enum DirentFormat {
653 Dirent64,
655 PosixDent,
657}
658
659impl DirentFormat {
660 pub(crate) fn write_entry(
664 self,
665 buf: &mut [MaybeUninit<u8>],
666 offset: usize,
667 d_ino: u64,
668 d_type: fs::FileType,
669 name: &[u8],
670 ) -> Option<usize> {
671 let (header_len, align) = match self {
672 Self::Dirent64 => (mem::offset_of!(Dirent64, d_name), align_of::<Dirent64>()),
673 Self::PosixDent => (mem::offset_of!(PosixDent, d_name), align_of::<PosixDent>()),
674 };
675 let entry_len = header_len + name.len() + 1;
676 let next_entry = (offset + entry_len).align_up(align);
677
678 if next_entry > buf.len() {
679 return None;
680 }
681
682 let d_reclen = entry_len.align_up(align).try_into().unwrap();
683
684 let entry_ptr = buf[offset].as_mut_ptr();
685 let name_ptr = match self {
686 Self::Dirent64 => {
687 let dirent = entry_ptr.cast::<Dirent64>();
688 unsafe {
689 dirent.write(Dirent64 {
690 d_ino,
691 d_off: 0,
692 d_reclen,
693 d_type,
694 d_name: PhantomData {},
695 });
696 (&raw mut (*dirent).d_name).cast::<u8>()
697 }
698 }
699 Self::PosixDent => {
700 let dirent = entry_ptr.cast::<PosixDent>();
701 unsafe {
702 dirent.write(PosixDent {
703 d_ino,
704 d_reclen,
705 d_type,
706 d_name: PhantomData {},
707 });
708 (&raw mut (*dirent).d_name).cast::<u8>()
709 }
710 }
711 };
712 unsafe {
713 name_ptr.copy_from_nonoverlapping(name.as_ptr(), name.len());
714 name_ptr.add(name.len()).write(0); }
716
717 Some(next_entry)
718 }
719}
720
721#[hermit_macro::system(errno)]
738#[unsafe(no_mangle)]
739pub unsafe extern "C" fn sys_getdents64(fd: RawFd, dirp: *mut Dirent64, count: usize) -> i64 {
740 debug!("getdents for fd {fd:?} - count: {count}");
741 if dirp.is_null() || count == 0 {
742 return (-i32::from(Errno::Inval)).into();
743 }
744
745 let slice = unsafe { slice::from_raw_parts_mut(dirp.cast(), count) };
746
747 let obj = get_object(fd);
748 obj.map_or_else(
749 |_| (-i32::from(Errno::Inval)).into(),
750 |v| {
751 block_on(
752 async { v.read().await.getdents(slice, DirentFormat::Dirent64).await },
753 None,
754 )
755 .map_or_else(|e| (-i32::from(e)).into(), |cnt| cnt as i64)
756 },
757 )
758}
759
760#[hermit_macro::system(errno)]
780#[unsafe(no_mangle)]
781pub unsafe extern "C" fn sys_posix_getdents(
782 fd: RawFd,
783 buf: *mut PosixDent,
784 nbyte: usize,
785 flags: i32,
786) -> isize {
787 debug!("posix_getdents for fd {fd:?} - nbyte: {nbyte}, flags: {flags}");
788 if buf.is_null() || nbyte == 0 || flags != 0 {
790 return isize::try_from(-i32::from(Errno::Inval)).unwrap();
791 }
792
793 let slice = unsafe { slice::from_raw_parts_mut(buf.cast(), nbyte) };
794
795 let obj = get_object(fd);
796 obj.map_or_else(
797 |e| isize::try_from(-i32::from(e)).unwrap(),
798 |v| {
799 block_on(
800 async {
801 v.read()
802 .await
803 .getdents(slice, DirentFormat::PosixDent)
804 .await
805 },
806 None,
807 )
808 .map_or_else(
809 |e| isize::try_from(-i32::from(e)).unwrap(),
810 |cnt| isize::try_from(cnt).unwrap(),
811 )
812 },
813 )
814}
815
816#[hermit_macro::system(errno)]
817#[unsafe(no_mangle)]
818pub extern "C" fn sys_dup(fd: RawFd) -> i32 {
819 dup_object(fd).unwrap_or_else(|e| -i32::from(e))
820}
821
822#[hermit_macro::system(errno)]
823#[unsafe(no_mangle)]
824pub extern "C" fn sys_dup2(fd1: i32, fd2: i32) -> i32 {
825 dup_object2(fd1, fd2).unwrap_or_else(|e| -i32::from(e))
826}
827
828#[hermit_macro::system(errno)]
829#[unsafe(no_mangle)]
830pub extern "C" fn sys_isatty(fd: RawFd) -> i32 {
831 match isatty(fd) {
832 Err(e) => -i32::from(e),
833 Ok(v) => {
834 if v {
835 1
836 } else {
837 0
838 }
839 }
840 }
841}
842
843#[hermit_macro::system(errno)]
844#[unsafe(no_mangle)]
845pub unsafe extern "C" fn sys_poll(fds: *mut PollFd, nfds: usize, timeout: i32) -> i32 {
846 let slice = unsafe { slice::from_raw_parts_mut(fds, nfds) };
847 let timeout = if timeout >= 0 {
848 Some(core::time::Duration::from_millis(
849 timeout.try_into().unwrap(),
850 ))
851 } else {
852 None
853 };
854
855 fd::poll(slice, timeout).map_or_else(
856 |e| {
857 if e == Errno::Time { 0 } else { -i32::from(e) }
858 },
859 |v| v.try_into().unwrap(),
860 )
861}
862
863#[hermit_macro::system(errno)]
864#[unsafe(no_mangle)]
865pub extern "C" fn sys_eventfd(initval: u64, flags: i16) -> i32 {
866 let Some(flags) = EventFlags::from_bits(flags) else {
867 return -i32::from(Errno::Inval);
868 };
869
870 fd::eventfd(initval, flags).unwrap_or_else(|e| -i32::from(e))
871}
872
873#[hermit_macro::system]
874#[unsafe(no_mangle)]
875pub extern "C" fn sys_image_start_addr() -> usize {
876 use crate::arch::mm::paging::{LargePageSize, PageSize};
877
878 elf_symbols::executable_start()
879 .addr()
880 .align_down(LargePageSize::SIZE as usize)
881}
882
883#[hermit_macro::system(errno)]
885#[unsafe(no_mangle)]
886pub extern "C" fn sys_fsync(fd: RawFd) -> i32 {
887 fd::fsync(fd).map_or_else(|e| -i32::from(e), |()| 0)
888}
889
890#[cfg(test)]
891mod tests {
892 use super::*;
893
894 #[cfg(target_os = "none")]
895 #[test_case]
896 fn test_get_application_parameters() {
897 env::init();
898 let (argc, argv, _envp) = get_application_parameters();
899 assert_ne!(argc, 0);
900 assert_ne!(argv, ptr::null());
901 }
902}