1use core::{
6 convert::TryFrom,
7 ffi::VaList,
8 mem::{self, MaybeUninit},
9 ptr, slice,
10};
11
12#[expect(deprecated)]
13use crate::platform::types::useconds_t;
14use crate::{
15 c_str::CStr,
16 error::{Errno, ResultExt},
17 header::{
18 bits_sigset_t::sigset_t,
19 crypt::{crypt_data, crypt_r},
20 errno::{self, ENAMETOOLONG},
21 fcntl, limits,
22 signal::{sigprocmask, sigsuspend},
23 stdlib::getenv,
24 sys_ioctl, sys_resource,
25 sys_select::timeval,
26 sys_time, sys_utsname, termios,
27 time::timespec,
28 unistd::{alarm::alarm_timespec, path::PathSearchIter},
29 },
30 out::Out,
31 platform::{
32 self, ERRNO, Pal, Sys,
33 types::{
34 c_char, c_int, c_long, c_short, c_uint, c_ulonglong, c_void, gid_t, off_t, pid_t,
35 size_t, ssize_t, suseconds_t, time_t, uid_t,
36 },
37 },
38};
39
40pub use self::{brk::*, getopt::*, pathconf::*, sysconf::*};
41pub use crate::header::pthread::fork_hooks;
42
43#[deprecated]
47pub use crate::header::stdio::ctermid;
48#[allow(deprecated)]
49pub use crate::header::stdio::cuserid;
50
51use super::{
52 errno::{E2BIG, EINVAL, ENOMEM},
53 stdio::snprintf,
54};
55
56mod alarm;
57mod brk;
58mod getopt;
59mod getpass;
60pub mod path;
61mod pathconf;
62#[cfg(target_os = "linux")]
63pub mod syscall;
64mod sysconf;
65
66pub const F_OK: c_int = 0;
67pub const R_OK: c_int = 4;
68pub const W_OK: c_int = 2;
69pub const X_OK: c_int = 1;
70
71pub const SEEK_SET: c_int = 0;
72pub const SEEK_CUR: c_int = 1;
73pub const SEEK_END: c_int = 2;
74
75pub const F_ULOCK: c_int = 0;
77pub const F_LOCK: c_int = 1;
79pub const F_TLOCK: c_int = 2;
81pub const F_TEST: c_int = 3;
83
84pub const STDIN_FILENO: c_int = 0;
85pub const STDOUT_FILENO: c_int = 1;
86pub const STDERR_FILENO: c_int = 2;
87
88pub const L_cuserid: usize = 9;
89
90pub const _CS_PATH: c_int = 0;
93pub const _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS: c_int = 1;
94pub const _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS: c_int = 4;
95pub const _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS: c_int = 5;
96pub const _CS_POSIX_V6_ILP32_OFF32_CFLAGS: c_int = 1116;
97pub const _CS_POSIX_V6_ILP32_OFF32_LDFLAGS: c_int = 1117;
98pub const _CS_POSIX_V6_ILP32_OFF32_LIBS: c_int = 1118;
99pub const _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS: c_int = 1119;
100pub const _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS: c_int = 1120;
101pub const _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS: c_int = 1121;
102pub const _CS_POSIX_V6_ILP32_OFFBIG_LIBS: c_int = 1122;
103pub const _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS: c_int = 1123;
104pub const _CS_POSIX_V6_LP64_OFF64_CFLAGS: c_int = 1124;
105pub const _CS_POSIX_V6_LP64_OFF64_LDFLAGS: c_int = 1125;
106pub const _CS_POSIX_V6_LP64_OFF64_LIBS: c_int = 1126;
107pub const _CS_POSIX_V6_LP64_OFF64_LINTFLAGS: c_int = 1127;
108pub const _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS: c_int = 1128;
109pub const _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS: c_int = 1129;
110pub const _CS_POSIX_V6_LPBIG_OFFBIG_LIBS: c_int = 1130;
111pub const _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS: c_int = 1131;
112pub const _CS_POSIX_V7_ILP32_OFF32_CFLAGS: c_int = 1132;
113pub const _CS_POSIX_V7_ILP32_OFF32_LDFLAGS: c_int = 1133;
114pub const _CS_POSIX_V7_ILP32_OFF32_LIBS: c_int = 1134;
115pub const _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS: c_int = 1135;
116pub const _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS: c_int = 1136;
117pub const _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS: c_int = 1137;
118pub const _CS_POSIX_V7_ILP32_OFFBIG_LIBS: c_int = 1138;
119pub const _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS: c_int = 1139;
120pub const _CS_POSIX_V7_LP64_OFF64_CFLAGS: c_int = 1140;
121pub const _CS_POSIX_V7_LP64_OFF64_LDFLAGS: c_int = 1141;
122pub const _CS_POSIX_V7_LP64_OFF64_LIBS: c_int = 1142;
123pub const _CS_POSIX_V7_LP64_OFF64_LINTFLAGS: c_int = 1143;
124pub const _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS: c_int = 1144;
125pub const _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS: c_int = 1145;
126pub const _CS_POSIX_V7_LPBIG_OFFBIG_LIBS: c_int = 1146;
127pub const _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS: c_int = 1147;
128
129#[unsafe(no_mangle)]
131pub unsafe extern "C" fn _Fork() -> pid_t {
132 unsafe { Sys::fork() }.or_minus_one_errno()
133}
134
135#[unsafe(no_mangle)]
137pub extern "C" fn _exit(status: c_int) -> ! {
138 Sys::exit(status)
139}
140
141#[unsafe(no_mangle)]
143pub unsafe extern "C" fn access(path: *const c_char, mode: c_int) -> c_int {
144 let path = unsafe { CStr::from_ptr(path) };
145 Sys::access(path, mode).map(|()| 0).or_minus_one_errno()
146}
147
148#[unsafe(no_mangle)]
150pub unsafe extern "C" fn faccessat(
151 fd: c_int,
152 path: *const c_char,
153 mode: c_int,
154 flags: c_int,
155) -> c_int {
156 let path = unsafe { CStr::from_ptr(path) };
157 Sys::faccessat(fd, path, mode, flags)
158 .map(|()| 0)
159 .or_minus_one_errno()
160}
161
162#[unsafe(no_mangle)]
164pub extern "C" fn alarm(seconds: c_uint) -> c_uint {
165 alarm_timespec(timespec {
166 tv_sec: seconds.into(),
167 tv_nsec: 0,
168 })
169}
170
171#[unsafe(no_mangle)]
173pub unsafe extern "C" fn chdir(path: *const c_char) -> c_int {
174 let path = unsafe { CStr::from_ptr(path) };
175 Sys::chdir(path).map(|()| 0).or_minus_one_errno()
176}
177
178#[unsafe(no_mangle)]
180pub unsafe extern "C" fn chown(path: *const c_char, owner: uid_t, group: gid_t) -> c_int {
181 let path = unsafe { CStr::from_ptr(path) };
182 Sys::chown(path, owner, group)
183 .map(|()| 0)
184 .or_minus_one_errno()
185}
186
187#[deprecated]
193#[unsafe(no_mangle)]
194pub unsafe extern "C" fn chroot(path: *const c_char) -> c_int {
195 platform::ERRNO.set(crate::header::errno::EPERM);
197
198 -1
199}
200
201#[unsafe(no_mangle)]
203pub extern "C" fn close(fildes: c_int) -> c_int {
204 Sys::close(fildes).map(|()| 0).or_minus_one_errno()
205}
206
207#[unsafe(no_mangle)]
209pub unsafe extern "C" fn confstr(name: c_int, buf: *mut c_char, len: size_t) -> size_t {
210 match name {
213 _CS_PATH => {
214 let posix2_path = c"/usr/bin";
215 unsafe { snprintf(buf, len, c"%s".as_ptr(), posix2_path.as_ptr()) + 1 }
216 .try_into()
217 .unwrap_or_default()
218 }
219 _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS
220 | _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS
221 | _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS
222 | _CS_POSIX_V6_LP64_OFF64_LIBS..=_CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS => 1,
223 _ => {
224 platform::ERRNO.set(errno::EINVAL);
225 0
226 }
227 }
228}
229
230#[unsafe(no_mangle)]
232pub unsafe extern "C" fn crypt(key: *const c_char, salt: *const c_char) -> *mut c_char {
233 let mut data = crypt_data::new();
234 unsafe { crypt_r(key, salt, &raw mut data) }
235}
236
237#[unsafe(no_mangle)]
239pub extern "C" fn daemon(nochdir: c_int, noclose: c_int) -> c_int {
240 if nochdir == 0 && Sys::chdir(c"/".into()).map(|()| 0).or_minus_one_errno() < 0 {
241 return -1;
242 }
243
244 if noclose == 0 {
245 let fd = Sys::open(c"/dev/null".into(), fcntl::O_RDWR, 0).or_minus_one_errno();
246 if fd < 0 {
247 return -1;
248 }
249 if dup2(fd, 0) < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0 {
250 close(fd);
251 return -1;
252 }
253 if fd > 2 {
254 close(fd);
255 }
256 }
257
258 match unsafe { fork() } {
259 0 => {}
260 -1 => return -1,
261 _ => _exit(0),
262 }
263
264 if setsid() < 0 {
265 return -1;
266 }
267
268 0
269}
270
271#[unsafe(no_mangle)]
273pub extern "C" fn dup(fildes: c_int) -> c_int {
274 Sys::dup(fildes).or_minus_one_errno()
275}
276
277#[unsafe(no_mangle)]
279pub extern "C" fn dup2(fildes: c_int, fildes2: c_int) -> c_int {
280 Sys::dup2(fildes, fildes2).or_minus_one_errno()
281}
282
283pub extern "C" fn dup3(fildes: c_int, fildes2: c_int, flag: c_int) -> c_int {
286 unimplemented!();
287}
288
289#[unsafe(no_mangle)]
301pub unsafe extern "C" fn execl(
302 path: *const c_char,
303 arg0: *const c_char,
304 mut __valist: ...
305) -> c_int {
306 unsafe {
307 with_argv(__valist, arg0, |args, _remaining_va| {
308 execv(path, args.as_ptr().cast())
309 })
310 }
311}
312
313#[unsafe(no_mangle)]
315pub unsafe extern "C" fn execle(
316 path: *const c_char,
317 arg0: *const c_char,
318 mut __valist: ...
319) -> c_int {
320 unsafe {
321 with_argv(__valist, arg0, |args, mut remaining_va| {
322 let envp = remaining_va.next_arg::<*const *mut c_char>();
323 execve(path, args.as_ptr().cast(), envp)
324 })
325 }
326}
327
328#[unsafe(no_mangle)]
330pub unsafe extern "C" fn execlp(
331 file: *const c_char,
332 arg0: *const c_char,
333 mut __valist: ...
334) -> c_int {
335 unsafe {
336 with_argv(__valist, arg0, |args, _remaining_va| {
337 execvp(file, args.as_ptr().cast())
338 })
339 }
340}
341
342#[unsafe(no_mangle)]
344pub unsafe extern "C" fn execv(path: *const c_char, argv: *const *mut c_char) -> c_int {
345 unsafe { execve(path, argv, platform::environ) }
346}
347
348#[unsafe(no_mangle)]
350pub unsafe extern "C" fn execve(
351 path: *const c_char,
352 argv: *const *mut c_char,
353 envp: *const *mut c_char,
354) -> c_int {
355 let path = unsafe { CStr::from_ptr(path) };
356 unsafe { Sys::execve(path, argv, envp) }
357 .map(|()| unreachable!())
358 .or_minus_one_errno()
359}
360
361#[unsafe(no_mangle)]
363pub unsafe extern "C" fn fexecve(
364 fd: c_int,
365 argv: *const *mut c_char,
366 envp: *const *mut c_char,
367) -> c_int {
368 unsafe { Sys::fexecve(fd, argv, envp) }
369 .map(|()| unreachable!())
370 .or_minus_one_errno()
371}
372
373#[unsafe(no_mangle)]
375pub unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int {
376 let file = unsafe { CStr::from_ptr(file) };
377 let file_bytes = file.to_bytes();
378
379 if file_bytes.contains(&b'/') || (cfg!(target_os = "redox") && file_bytes.contains(&b':')) {
380 unsafe { execv(file.as_ptr(), argv) }
381 } else {
382 let mut error = errno::ENOENT;
383
384 let path_env = unsafe { getenv(c"PATH".as_ptr()) };
385 if !path_env.is_null() {
386 let path_env = unsafe { CStr::from_ptr(path_env) };
387 for program_buf in PathSearchIter::new(&file.to_bytes(), &path_env) {
388 let program_c =
390 unsafe { CStr::from_bytes_with_nul_unchecked(program_buf.as_slice()) };
391 unsafe { execv(program_c.as_ptr(), argv) };
392
393 match platform::ERRNO.get() {
394 errno::ENOENT => (),
395 other => error = other,
396 }
397 }
398 }
399
400 platform::ERRNO.set(error);
401 -1
402 }
403}
404
405#[unsafe(no_mangle)]
407pub extern "C" fn fchdir(fildes: c_int) -> c_int {
408 Sys::fchdir(fildes).map(|()| 0).or_minus_one_errno()
409}
410
411#[unsafe(no_mangle)]
413pub extern "C" fn fchown(fildes: c_int, owner: uid_t, group: gid_t) -> c_int {
414 Sys::fchown(fildes, owner, group)
415 .map(|()| 0)
416 .or_minus_one_errno()
417}
418#[unsafe(no_mangle)]
420pub unsafe extern "C" fn fchownat(
421 fd: c_int,
422 path: *const c_char,
423 owner: uid_t,
424 group: gid_t,
425 flags: c_int,
426) -> c_int {
427 let path = unsafe { CStr::from_ptr(path) };
428 Sys::fchownat(fd, path, owner, group, flags)
429 .map(|()| 0)
430 .or_minus_one_errno()
431}
432
433#[unsafe(no_mangle)]
435pub extern "C" fn fdatasync(fildes: c_int) -> c_int {
436 Sys::fdatasync(fildes).map(|()| 0).or_minus_one_errno()
437}
438
439#[unsafe(no_mangle)]
441pub unsafe extern "C" fn fork() -> pid_t {
442 for prepare in unsafe { &fork_hooks[0] } {
443 prepare();
444 }
445 let pid = unsafe { Sys::fork() }.or_minus_one_errno();
446 if pid == 0 {
447 for child in unsafe { &fork_hooks[2] } {
448 child();
449 }
450 } else if pid != -1 {
451 for parent in unsafe { &fork_hooks[1] } {
452 parent();
453 }
454 }
455 pid
456}
457
458#[unsafe(no_mangle)]
460pub extern "C" fn fsync(fildes: c_int) -> c_int {
461 Sys::fsync(fildes).map(|()| 0).or_minus_one_errno()
462}
463
464#[unsafe(no_mangle)]
466pub extern "C" fn ftruncate(fildes: c_int, length: off_t) -> c_int {
467 Sys::ftruncate(fildes, length)
468 .map(|()| 0)
469 .or_minus_one_errno()
470}
471
472#[unsafe(no_mangle)]
474pub unsafe extern "C" fn getcwd(mut buf: *mut c_char, mut size: size_t) -> *mut c_char {
475 let alloc = buf.is_null();
476 let mut stack_buf = [0; limits::PATH_MAX];
477 if alloc {
478 buf = stack_buf.as_mut_ptr();
479 size = stack_buf.len();
480 }
481
482 let ret = match Sys::getcwd(unsafe { Out::from_raw_parts(buf.cast(), size) }) {
483 Ok(()) => buf,
484 Err(Errno(errno)) => {
485 ERRNO.set(errno);
486 return ptr::null_mut();
487 }
488 };
489
490 if alloc {
491 let len = stack_buf
492 .iter()
493 .position(|b| *b == 0)
494 .expect("no nul-byte in getcwd string")
495 + 1;
496 let heap_buf = unsafe { platform::alloc(len).cast::<c_char>() };
497 for (i, inner) in stack_buf.iter().enumerate().take(len) {
498 unsafe {
499 *heap_buf.add(i) = *inner;
500 }
501 }
502 heap_buf
503 } else {
504 ret
505 }
506}
507
508#[deprecated]
514#[unsafe(no_mangle)]
515pub extern "C" fn getdtablesize() -> c_int {
516 #[cfg(not(target_os = "redox"))]
518 {
519 let mut lim = mem::MaybeUninit::<sys_resource::rlimit>::uninit();
520 let r = unsafe {
521 sys_resource::getrlimit(
522 sys_resource::RLIMIT_NOFILE as c_int,
523 lim.as_mut_ptr().cast::<sys_resource::rlimit>(),
524 )
525 };
526 if r == 0 {
527 let cur = unsafe { lim.assume_init() }.rlim_cur;
528 return match cur {
529 c if c < i32::MAX as u64 => c as i32,
530 _ => i32::MAX,
531 };
532 }
533 }
534 -1
535}
536
537#[unsafe(no_mangle)]
539pub extern "C" fn getegid() -> gid_t {
540 Sys::getegid()
541}
542
543pub extern "C" fn getentropy(buffer: *mut c_void, length: size_t) -> c_int {
546 unimplemented!();
547}
548
549#[unsafe(no_mangle)]
551pub extern "C" fn geteuid() -> uid_t {
552 Sys::geteuid()
553}
554
555#[unsafe(no_mangle)]
557pub extern "C" fn getgid() -> gid_t {
558 Sys::getgid()
559}
560
561#[unsafe(no_mangle)]
563pub unsafe extern "C" fn getgroups(size: c_int, list: *mut gid_t) -> c_int {
564 (|| {
565 let size = usize::try_from(size)
566 .map_err(|_| Errno(EINVAL))?;
569
570 let list = unsafe { Out::from_raw_parts(list, size) };
571
572 Sys::getgroups(list)
573 })()
574 .or_minus_one_errno()
575}
576
577pub extern "C" fn gethostid() -> c_long {
580 unimplemented!();
581}
582
583#[unsafe(no_mangle)]
585pub unsafe extern "C" fn gethostname(mut name: *mut c_char, mut len: size_t) -> c_int {
586 let mut uts = mem::MaybeUninit::<sys_utsname::utsname>::uninit();
587 let err = Sys::uname(Out::from_uninit_mut(&mut uts))
589 .map(|()| 0)
590 .or_minus_one_errno();
591 if err < 0 {
592 return err;
593 }
594 for c in unsafe { uts.assume_init() }.nodename.iter() {
595 if len == 0 {
596 break;
597 }
598 len -= 1;
599
600 unsafe { *name = *c };
601
602 if unsafe { *name } == 0 {
603 break;
605 }
606
607 name = unsafe { name.offset(1) };
608 }
609 0
610}
611
612#[unsafe(no_mangle)]
614pub unsafe extern "C" fn getlogin() -> *mut c_char {
615 const LOGIN_LEN: usize = limits::LOGIN_NAME_MAX as usize;
616 static mut LOGIN: [c_char; LOGIN_LEN] = [0; LOGIN_LEN];
617 if getlogin_r((&raw mut LOGIN).cast(), LOGIN_LEN) == 0 {
618 (&raw mut LOGIN).cast()
619 } else {
620 ptr::null_mut()
621 }
622}
623
624#[unsafe(no_mangle)]
626pub extern "C" fn getlogin_r(name: *mut c_char, namesize: size_t) -> c_int {
627 platform::ERRNO.set(errno::ENOENT);
629 -1
630}
631
632#[deprecated]
638#[unsafe(no_mangle)]
639pub extern "C" fn getpagesize() -> c_int {
640 Sys::getpagesize()
642 .try_into()
643 .expect("page size not representable as type `int`")
644}
645
646#[unsafe(no_mangle)]
648pub extern "C" fn getpgid(pid: pid_t) -> pid_t {
649 Sys::getpgid(pid).or_minus_one_errno()
650}
651
652#[unsafe(no_mangle)]
654pub extern "C" fn getpgrp() -> pid_t {
655 Sys::getpgid(Sys::getpid()).or_minus_one_errno()
656}
657
658#[unsafe(no_mangle)]
660pub extern "C" fn getpid() -> pid_t {
661 Sys::getpid()
662}
663
664#[unsafe(no_mangle)]
666pub extern "C" fn getppid() -> pid_t {
667 Sys::getppid()
668}
669
670#[unsafe(no_mangle)]
672pub unsafe extern "C" fn getresgid(rgid: *mut gid_t, egid: *mut gid_t, sgid: *mut gid_t) -> c_int {
673 Sys::getresgid(
674 unsafe { Out::nullable(rgid) },
675 unsafe { Out::nullable(egid) },
676 unsafe { Out::nullable(sgid) },
677 )
678 .map(|()| 0)
679 .or_minus_one_errno()
680}
681
682#[unsafe(no_mangle)]
684pub unsafe extern "C" fn getresuid(ruid: *mut uid_t, euid: *mut uid_t, suid: *mut uid_t) -> c_int {
685 Sys::getresuid(
686 unsafe { Out::nullable(ruid) },
687 unsafe { Out::nullable(euid) },
688 unsafe { Out::nullable(suid) },
689 )
690 .map(|()| 0)
691 .or_minus_one_errno()
692}
693
694#[unsafe(no_mangle)]
696pub extern "C" fn getsid(pid: pid_t) -> pid_t {
697 Sys::getsid(pid).or_minus_one_errno()
698}
699
700#[unsafe(no_mangle)]
702pub extern "C" fn getuid() -> uid_t {
703 Sys::getuid()
704}
705
706#[deprecated]
712#[unsafe(no_mangle)]
713pub unsafe extern "C" fn getwd(path_name: *mut c_char) -> *mut c_char {
714 unsafe { getcwd(path_name, limits::PATH_MAX) }
715}
716
717#[unsafe(no_mangle)]
719pub extern "C" fn isatty(fd: c_int) -> c_int {
720 let mut t = termios::termios::default();
721 if unsafe { termios::tcgetattr(fd, &raw mut t) == 0 } {
722 1
723 } else {
724 0
725 }
726}
727
728#[unsafe(no_mangle)]
730pub unsafe extern "C" fn lchown(path: *const c_char, owner: uid_t, group: gid_t) -> c_int {
731 let path = unsafe { CStr::from_ptr(path) };
732 Sys::lchown(path, owner, group)
733 .map(|()| 0)
734 .or_minus_one_errno()
735}
736
737#[unsafe(no_mangle)]
739pub unsafe extern "C" fn link(path1: *const c_char, path2: *const c_char) -> c_int {
740 let path1 = unsafe { CStr::from_ptr(path1) };
741 let path2 = unsafe { CStr::from_ptr(path2) };
742 Sys::link(path1, path2).map(|()| 0).or_minus_one_errno()
743}
744
745#[unsafe(no_mangle)]
747pub unsafe extern "C" fn linkat(
748 fd1: c_int,
749 path1: *const c_char,
750 fd2: c_int,
751 path2: *const c_char,
752 flags: c_int,
753) -> c_int {
754 let path1 = unsafe { CStr::from_ptr(path1) };
755 let path2 = unsafe { CStr::from_ptr(path2) };
756 Sys::linkat(fd1, path1, fd2, path2, flags)
757 .map(|()| 0)
758 .or_minus_one_errno()
759}
760
761#[unsafe(no_mangle)]
763pub unsafe extern "C" fn lockf(fildes: c_int, function: c_int, size: off_t) -> c_int {
764 let mut fl = fcntl::flock {
765 l_type: fcntl::F_WRLCK as c_short,
766 l_whence: SEEK_CUR as c_short,
767 l_start: 0,
768 l_len: size,
769 l_pid: -1,
770 };
771
772 match function {
773 F_TEST => {
774 fl.l_type = fcntl::F_RDLCK as c_short;
775 if unsafe { fcntl::fcntl(fildes, fcntl::F_GETLK, &raw mut fl as c_ulonglong) } < 0 {
776 return -1;
777 }
778 if fl.l_type == fcntl::F_UNLCK as c_short || fl.l_pid == getpid() {
779 return 0;
780 }
781 platform::ERRNO.set(errno::EACCES);
782 -1
783 }
784 F_ULOCK => {
785 fl.l_type = fcntl::F_UNLCK as c_short;
786 unsafe { fcntl::fcntl(fildes, fcntl::F_SETLK, &raw mut fl as c_ulonglong) }
787 }
788 F_TLOCK => unsafe { fcntl::fcntl(fildes, fcntl::F_SETLK, &raw mut fl as c_ulonglong) },
789 F_LOCK => unsafe { fcntl::fcntl(fildes, fcntl::F_SETLKW, &raw mut fl as c_ulonglong) },
790 _ => {
791 platform::ERRNO.set(errno::EINVAL);
792 -1
793 }
794 }
795}
796
797#[unsafe(no_mangle)]
799pub extern "C" fn lseek(fildes: c_int, offset: off_t, whence: c_int) -> off_t {
800 Sys::lseek(fildes, offset, whence).or_minus_one_errno()
801}
802
803#[unsafe(no_mangle)]
805pub extern "C" fn nice(incr: c_int) -> c_int {
806 let prio = Sys::getpriority(sys_resource::PRIO_PROCESS, 0).or_minus_one_errno();
807 if prio < 0 {
808 return prio;
809 }
810
811 let current_nice = 20 - prio;
812 let new_nice = current_nice.saturating_add(incr).clamp(-20, 19);
813
814 if Sys::setpriority(sys_resource::PRIO_PROCESS, 0, new_nice)
815 .map(|()| 0)
816 .or_minus_one_errno()
817 < 0
818 {
819 return -1;
820 }
821
822 new_nice
823}
824
825#[unsafe(no_mangle)]
827pub unsafe extern "C" fn pause() -> c_int {
828 let mut pset = mem::MaybeUninit::<sigset_t>::uninit();
829 unsafe { sigprocmask(0, ptr::null_mut(), pset.as_mut_ptr()) };
830 let set = unsafe { pset.assume_init() };
831 unsafe { sigsuspend(&raw const set) }
832}
833
834#[unsafe(no_mangle)]
836pub unsafe extern "C" fn pipe(fildes: *mut c_int) -> c_int {
837 unsafe { pipe2(fildes, 0) }
838}
839
840#[unsafe(no_mangle)]
842pub unsafe extern "C" fn pipe2(fildes: *mut c_int, flags: c_int) -> c_int {
843 Sys::pipe2(unsafe { Out::nonnull(fildes.cast::<[c_int; 2]>()) }, flags)
844 .map(|()| 0)
845 .or_minus_one_errno()
846}
847
848#[unsafe(no_mangle)]
850pub extern "C" fn posix_close(fildes: c_int, flag: c_int) -> c_int {
851 close(fildes)
856}
857
858#[unsafe(no_mangle)]
866pub unsafe extern "C" fn pread(
867 fildes: c_int,
868 buf: *mut c_void,
869 nbyte: size_t,
870 offset: off_t,
871) -> ssize_t {
872 Sys::pread(
873 fildes,
874 unsafe { slice::from_raw_parts_mut(buf.cast::<u8>(), nbyte) },
875 offset,
876 )
877 .map(|read| read as ssize_t)
878 .or_minus_one_errno()
879}
880
881#[unsafe(no_mangle)]
890pub unsafe extern "C" fn pwrite(
891 fildes: c_int,
892 buf: *const c_void,
893 nbyte: size_t,
894 offset: off_t,
895) -> ssize_t {
896 Sys::pwrite(
897 fildes,
898 unsafe { slice::from_raw_parts(buf.cast::<u8>(), nbyte) },
899 offset,
900 )
901 .map(|read| read as ssize_t)
902 .or_minus_one_errno()
903}
904
905#[unsafe(no_mangle)]
913pub unsafe extern "C" fn read(fildes: c_int, buf: *mut c_void, nbyte: size_t) -> ssize_t {
914 let buf = unsafe { slice::from_raw_parts_mut(buf.cast::<u8>(), nbyte) };
915 trace_expr!(
916 Sys::read(fildes, buf)
917 .map(|read| read as ssize_t)
918 .or_minus_one_errno(),
919 "read({}, {:p}, {})",
920 fildes,
921 buf,
922 nbyte
923 )
924}
925
926#[unsafe(no_mangle)]
928pub unsafe extern "C" fn readlink(
929 path: *const c_char,
930 buf: *mut c_char,
931 bufsize: size_t,
932) -> ssize_t {
933 let path = unsafe { CStr::from_ptr(path) };
934 let buf = unsafe { slice::from_raw_parts_mut(buf.cast::<u8>(), bufsize) };
935 Sys::readlink(path, buf)
936 .map(|read| read as ssize_t)
937 .or_minus_one_errno()
938}
939
940#[unsafe(no_mangle)]
942pub unsafe extern "C" fn readlinkat(
943 dirfd: c_int,
944 pathname: *const c_char,
945 buf: *mut c_char,
946 len: size_t,
947) -> ssize_t {
948 let pathname = unsafe { CStr::from_ptr(pathname) };
949 let buf = unsafe { slice::from_raw_parts_mut(buf.cast(), len) };
950 Sys::readlinkat(dirfd, pathname, buf)
951 .map(|read| {
952 read.try_into()
953 .map_err(|_| Errno(ENAMETOOLONG))
954 .or_minus_one_errno()
955 })
956 .or_minus_one_errno()
957}
958
959#[unsafe(no_mangle)]
961pub unsafe extern "C" fn rmdir(path: *const c_char) -> c_int {
962 let path = unsafe { CStr::from_ptr(path) };
963 Sys::rmdir(path).map(|()| 0).or_minus_one_errno()
964}
965
966#[unsafe(no_mangle)]
968pub extern "C" fn setegid(gid: gid_t) -> c_int {
969 Sys::setresgid(-1, gid, -1).map(|()| 0).or_minus_one_errno()
970}
971
972#[unsafe(no_mangle)]
974pub extern "C" fn seteuid(uid: uid_t) -> c_int {
975 Sys::setresuid(-1, uid, -1).map(|()| 0).or_minus_one_errno()
976}
977
978#[unsafe(no_mangle)]
980pub extern "C" fn setgid(gid: gid_t) -> c_int {
981 Sys::setresgid(gid, gid, -1)
982 .map(|()| 0)
983 .or_minus_one_errno()
984}
985
986#[unsafe(no_mangle)]
988pub extern "C" fn setpgid(pid: pid_t, pgid: pid_t) -> c_int {
989 Sys::setpgid(pid, pgid).map(|()| 0).or_minus_one_errno()
990}
991
992#[deprecated]
998#[unsafe(no_mangle)]
999pub extern "C" fn setpgrp() -> pid_t {
1000 setpgid(0, 0)
1001}
1002
1003#[unsafe(no_mangle)]
1005pub extern "C" fn setregid(rgid: gid_t, egid: gid_t) -> c_int {
1006 Sys::setresgid(rgid, egid, -1)
1007 .map(|()| 0)
1008 .or_minus_one_errno()
1009}
1010
1011#[unsafe(no_mangle)]
1013pub extern "C" fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) -> c_int {
1014 Sys::setresgid(rgid, egid, sgid)
1015 .map(|()| 0)
1016 .or_minus_one_errno()
1017}
1018
1019#[unsafe(no_mangle)]
1021pub extern "C" fn setresuid(ruid: uid_t, euid: uid_t, suid: uid_t) -> c_int {
1022 Sys::setresuid(ruid, euid, suid)
1023 .map(|()| 0)
1024 .or_minus_one_errno()
1025}
1026
1027#[unsafe(no_mangle)]
1029pub extern "C" fn setreuid(ruid: uid_t, euid: uid_t) -> c_int {
1030 Sys::setresuid(ruid, euid, -1)
1031 .map(|()| 0)
1032 .or_minus_one_errno()
1033}
1034
1035#[unsafe(no_mangle)]
1037pub extern "C" fn setsid() -> pid_t {
1038 Sys::setsid().or_minus_one_errno()
1039}
1040
1041#[unsafe(no_mangle)]
1043pub extern "C" fn setuid(uid: uid_t) -> c_int {
1044 Sys::setresuid(uid, uid, -1)
1045 .map(|()| 0)
1046 .or_minus_one_errno()
1047}
1048
1049#[unsafe(no_mangle)]
1051pub extern "C" fn sleep(seconds: c_uint) -> c_uint {
1052 let rqtp = timespec {
1053 tv_sec: time_t::from(seconds),
1054 tv_nsec: 0,
1055 };
1056 let mut rmtp = timespec {
1057 tv_sec: 0,
1058 tv_nsec: 0,
1059 };
1060
1061 match unsafe { Sys::nanosleep(&raw const rqtp, &raw mut rmtp) } {
1065 Err(Errno(EINTR)) => rmtp.tv_sec as c_uint,
1066 r => 0,
1067 }
1068}
1069
1070#[unsafe(no_mangle)]
1072pub unsafe extern "C" fn swab(src: *const c_void, dest: *mut c_void, nbytes: ssize_t) {
1073 if nbytes <= 0 {
1074 return;
1075 }
1076 let number_of_swaps = nbytes / 2;
1077 let mut offset = 0;
1078 for _ in 0..number_of_swaps {
1079 unsafe {
1080 src.offset(offset).copy_to(dest.offset(offset + 1), 1);
1081 src.offset(offset + 1).copy_to(dest.offset(offset), 1);
1082 }
1083 offset += 2;
1084 }
1085}
1086
1087#[unsafe(no_mangle)]
1089pub unsafe extern "C" fn symlink(path1: *const c_char, path2: *const c_char) -> c_int {
1090 let path1 = unsafe { CStr::from_ptr(path1) };
1091 let path2 = unsafe { CStr::from_ptr(path2) };
1092 Sys::symlink(path1, path2).map(|()| 0).or_minus_one_errno()
1093}
1094
1095#[unsafe(no_mangle)]
1097pub unsafe extern "C" fn symlinkat(path1: *const c_char, fd: c_int, path2: *const c_char) -> c_int {
1098 let path1 = unsafe { CStr::from_ptr(path1) };
1099 let path2 = unsafe { CStr::from_ptr(path2) };
1100 Sys::symlinkat(path1, fd, path2)
1101 .map(|()| 0)
1102 .or_minus_one_errno()
1103}
1104
1105#[unsafe(no_mangle)]
1107pub extern "C" fn sync() {
1108 if let Ok(()) = Sys::sync() {}; }
1110
1111#[unsafe(no_mangle)]
1113pub extern "C" fn tcgetpgrp(fd: c_int) -> pid_t {
1114 let mut pgrp = 0;
1115 if unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCGPGRP, (&raw mut pgrp).cast()) } < 0 {
1116 return -1;
1117 }
1118 pgrp
1119}
1120
1121#[unsafe(no_mangle)]
1123pub extern "C" fn tcsetpgrp(fd: c_int, pgrp: pid_t) -> c_int {
1124 if unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCSPGRP, &raw const pgrp as _) } < 0 {
1125 return -1;
1126 }
1127 pgrp
1128}
1129
1130#[unsafe(no_mangle)]
1132pub unsafe extern "C" fn truncate(path: *const c_char, length: off_t) -> c_int {
1133 let file = unsafe { CStr::from_ptr(path) };
1134 let fd = Sys::open(file, fcntl::O_WRONLY, 0).or_minus_one_errno();
1136 if fd < 0 {
1137 return -1;
1138 }
1139
1140 let res = ftruncate(fd, length);
1141
1142 if let Ok(()) = Sys::close(fd) {}; res
1145}
1146
1147#[unsafe(no_mangle)]
1149pub unsafe extern "C" fn ttyname(fildes: c_int) -> *mut c_char {
1150 const TTYNAME_LEN: usize = 4096;
1151 static mut TTYNAME: [c_char; TTYNAME_LEN] = [0; TTYNAME_LEN];
1152 if ttyname_r(fildes, (&raw mut TTYNAME).cast(), TTYNAME_LEN) == 0 {
1153 (&raw mut TTYNAME).cast()
1154 } else {
1155 ptr::null_mut()
1156 }
1157}
1158
1159#[unsafe(no_mangle)]
1161pub extern "C" fn ttyname_r(fildes: c_int, name: *mut c_char, namesize: size_t) -> c_int {
1162 let name = unsafe { slice::from_raw_parts_mut(name.cast::<u8>(), namesize) };
1163 if name.is_empty() {
1164 return errno::ERANGE;
1165 }
1166
1167 let len = Sys::fpath(fildes, &mut name[..namesize - 1])
1168 .map(|read| read as ssize_t)
1169 .or_minus_one_errno();
1170 if len < 0 {
1171 return -platform::ERRNO.get();
1172 }
1173 name[len as usize] = 0;
1174
1175 0
1176}
1177
1178#[deprecated]
1184#[allow(deprecated)]
1185#[unsafe(no_mangle)]
1186pub extern "C" fn ualarm(usecs: useconds_t, interval: useconds_t) -> useconds_t {
1187 let mut timer = sys_time::itimerval {
1189 it_value: timeval {
1190 tv_sec: 0,
1191 tv_usec: usecs as suseconds_t,
1192 },
1193 it_interval: timeval {
1194 tv_sec: 0,
1195 tv_usec: interval as suseconds_t,
1196 },
1197 };
1198 let errno_backup = platform::ERRNO.get();
1199 let ret =
1200 if unsafe { sys_time::setitimer(sys_time::ITIMER_REAL, &raw const timer, &raw mut timer) }
1201 < 0
1202 {
1203 0
1204 } else {
1205 timer.it_value.tv_sec as useconds_t * 1_000_000 + timer.it_value.tv_usec as useconds_t
1206 };
1207 platform::ERRNO.set(errno_backup);
1208
1209 ret
1210}
1211
1212#[unsafe(no_mangle)]
1214pub unsafe extern "C" fn unlink(path: *const c_char) -> c_int {
1215 let path = unsafe { CStr::from_ptr(path) };
1216 Sys::unlink(path).map(|()| 0).or_minus_one_errno()
1217}
1218
1219#[unsafe(no_mangle)]
1221pub unsafe extern "C" fn unlinkat(fd: c_int, path: *const c_char, flags: c_int) -> c_int {
1222 let path = unsafe { CStr::from_ptr(path) };
1223 Sys::unlinkat(fd, path, flags)
1224 .map(|()| 0)
1225 .or_minus_one_errno()
1226}
1227#[deprecated]
1233#[allow(deprecated)]
1234#[unsafe(no_mangle)]
1235pub extern "C" fn usleep(useconds: useconds_t) -> c_int {
1236 #[cfg(not(target_arch = "x86"))]
1237 let tv_nsec = c_long::from((useconds % 1_000_000) * 1000);
1238 #[cfg(target_arch = "x86")]
1239 let tv_nsec = ((useconds % 1_000_000) * 1000) as c_long;
1240 let rqtp = timespec {
1241 tv_sec: time_t::from(useconds / 1_000_000),
1242 tv_nsec,
1243 };
1244 let rmtp = ptr::null_mut();
1245 unsafe { Sys::nanosleep(&raw const rqtp, rmtp) }
1246 .map(|()| 0)
1247 .or_minus_one_errno()
1248}
1249
1250#[deprecated]
1256pub extern "C" fn vfork() -> pid_t {
1258 unimplemented!();
1259}
1260
1261unsafe fn with_argv(
1262 mut va: VaList,
1263 arg0: *const c_char,
1264 f: impl FnOnce(&[*const c_char], VaList) -> c_int,
1265) -> c_int {
1266 let argc = 1 + unsafe {
1267 let mut copy = va.clone();
1268 core::iter::from_fn(|| Some(copy.next_arg::<*const c_char>()))
1269 .position(|p| p.is_null())
1270 .unwrap()
1271 };
1272
1273 let mut stack: [MaybeUninit<*const c_char>; 32] = [MaybeUninit::uninit(); 32];
1274
1275 let out = if argc < 32 {
1276 stack.as_mut_slice()
1277 } else if argc < 4096 {
1278 let ptr =
1280 unsafe { crate::header::stdlib::malloc((argc + 1) * mem::size_of::<*const c_char>()) };
1281 if ptr.is_null() {
1282 platform::ERRNO.set(ENOMEM);
1283 return -1;
1284 }
1285 unsafe { slice::from_raw_parts_mut(ptr.cast::<MaybeUninit<*const c_char>>(), argc + 1) }
1286 } else {
1287 platform::ERRNO.set(E2BIG);
1288 return -1;
1289 };
1290 out[0].write(arg0);
1291
1292 for inner in out.iter_mut().take(argc).skip(1) {
1293 (*inner).write(unsafe { va.next_arg::<*const c_char>() });
1294 }
1295 out[argc].write(core::ptr::null());
1296 unsafe { va.next_arg::<*const c_char>() };
1298
1299 f(unsafe { out.assume_init_ref() }, va);
1300
1301 if argc >= 32 {
1303 unsafe { crate::header::stdlib::free(out.as_mut_ptr().cast()) };
1304 }
1305 -1
1306}
1307
1308#[unsafe(no_mangle)]
1317pub unsafe extern "C" fn write(fildes: c_int, buf: *const c_void, nbyte: size_t) -> ssize_t {
1318 let buf = unsafe { slice::from_raw_parts(buf.cast::<u8>(), nbyte) };
1319 Sys::write(fildes, buf)
1320 .map(|bytes| bytes as ssize_t)
1321 .or_minus_one_errno()
1322}