Skip to main content

relibc/header/unistd/
mod.rs

1//! `unistd.h` implementation.
2//!
3//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/unistd.h.html>.
4
5use 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// Inclusion of ctermid() prototype marked as obsolescent since Issue 7, cf.
44// <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html>.
45// cuserid() marked legacy in Issue 5.
46#[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
75/// Unlock locked sections.
76pub const F_ULOCK: c_int = 0;
77/// Lock a section for exclusive use.
78pub const F_LOCK: c_int = 1;
79/// Test and lock a section for exclusive use.
80pub const F_TLOCK: c_int = 2;
81/// Test section for locks by other processes.
82pub 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
90// confstr constants
91// These are copied from Rust's libc and match musl as well.
92pub 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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fork.html>.
130#[unsafe(no_mangle)]
131pub unsafe extern "C" fn _Fork() -> pid_t {
132    unsafe { Sys::fork() }.or_minus_one_errno()
133}
134
135/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/_Exit.html>.
136#[unsafe(no_mangle)]
137pub extern "C" fn _exit(status: c_int) -> ! {
138    Sys::exit(status)
139}
140
141/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/access.html>.
142#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/faccessat.html>.
149#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/alarm.html>.
163#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/chdir.html>.
172#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/chown.html>.
179#[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/// See <https://pubs.opengroup.org/onlinepubs/7908799/xsh/chroot.html>.
188///
189/// # Deprecation
190/// The `chroot()` function was marked legacy in the System Interface & Headers
191/// Issue 5, and removed in Issue 6.
192#[deprecated]
193#[unsafe(no_mangle)]
194pub unsafe extern "C" fn chroot(path: *const c_char) -> c_int {
195    // TODO: Implement
196    platform::ERRNO.set(crate::header::errno::EPERM);
197
198    -1
199}
200
201/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/close.html>.
202#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/confstr.html>.
208#[unsafe(no_mangle)]
209pub unsafe extern "C" fn confstr(name: c_int, buf: *mut c_char, len: size_t) -> size_t {
210    // confstr returns the number of bytes required to hold the string INCLUDING the NUL
211    // terminator. This is different from other C functions hence the + 1.
212    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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/crypt.html>.
231#[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/// Non-POSIX, see <https://www.man7.org/linux/man-pages/man3/daemon.3.html>.
238#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/dup.html>.
272#[unsafe(no_mangle)]
273pub extern "C" fn dup(fildes: c_int) -> c_int {
274    Sys::dup(fildes).or_minus_one_errno()
275}
276
277/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/dup.html>.
278#[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
283/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/dup.html>.
284// #[unsafe(no_mangle)]
285pub extern "C" fn dup3(fildes: c_int, fildes2: c_int, flag: c_int) -> c_int {
286    unimplemented!();
287}
288
289// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/encrypt.html>.
290//
291// # Deprecation
292// The `encrypt()` function was marked obsolescent in the Open Group Base Specifications Issue 8.
293//#[deprecated]
294// #[unsafe(no_mangle)]
295//pub extern "C" fn encrypt(block: [c_char; 64], edflag: c_int) {
296//    unimplemented!();
297//}
298
299/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/exec.html>.
300#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/exec.html>.
314#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/exec.html>.
329#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/exec.html>.
343#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/exec.html>.
349#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fexecve.html>.
362#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/exec.html>.
374#[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                // SAFETY: CStr::from_ptr().to_bytes() always stop at null, no need to check again
389                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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchdir.html>.
406#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchown.html>.
412#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchownat.html>.
419#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fdatasync.html>.
434#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fork.html>.
440#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fsync.html>.
459#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/ftruncate.html>.
465#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getcwd.html>.
473#[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/// See <https://pubs.opengroup.org/onlinepubs/7908799/xsh/getdtablesize.html>.
509///
510/// # Deprecation
511/// The `getdtablesize()` function was marked legacy in the System Interface &
512/// Headers Issue 5, and removed in Issue 6.
513#[deprecated]
514#[unsafe(no_mangle)]
515pub extern "C" fn getdtablesize() -> c_int {
516    // TODO: Have getrlimit working in Redox
517    #[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getegid.html>.
538#[unsafe(no_mangle)]
539pub extern "C" fn getegid() -> gid_t {
540    Sys::getegid()
541}
542
543/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html>.
544// #[unsafe(no_mangle)]
545pub extern "C" fn getentropy(buffer: *mut c_void, length: size_t) -> c_int {
546    unimplemented!();
547}
548
549/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/geteuid.html>.
550#[unsafe(no_mangle)]
551pub extern "C" fn geteuid() -> uid_t {
552    Sys::geteuid()
553}
554
555/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getgid.html>.
556#[unsafe(no_mangle)]
557pub extern "C" fn getgid() -> gid_t {
558    Sys::getgid()
559}
560
561/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getgroups.html>.
562#[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            // fails for negative size, but EINVAL required if size != 0 && size < actual size,
567            // where the actual number of entries in the group list is obviously nonnegative
568            .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
577/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/gethostid.html>.
578// #[unsafe(no_mangle)]
579pub extern "C" fn gethostid() -> c_long {
580    unimplemented!();
581}
582
583/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/gethostname.html>.
584#[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    // TODO
588    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            // We do want to copy the zero also, so we check this after the copying.
604            break;
605        }
606
607        name = unsafe { name.offset(1) };
608    }
609    0
610}
611
612/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getlogin.html>.
613#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getlogin.html>.
625#[unsafe(no_mangle)]
626pub extern "C" fn getlogin_r(name: *mut c_char, namesize: size_t) -> c_int {
627    //TODO: Determine correct getlogin result on Redox
628    platform::ERRNO.set(errno::ENOENT);
629    -1
630}
631
632/// See <https://pubs.opengroup.org/onlinepubs/7908799/xsh/getpagesize.html>.
633///
634/// # Deprecation
635/// The `getpagesize()` function was marked legacy in the System Interface &
636/// Headers Issue 5, and removed in Issue 6.
637#[deprecated]
638#[unsafe(no_mangle)]
639pub extern "C" fn getpagesize() -> c_int {
640    // Panic if we can't uphold the required behavior (no errors are specified for this function)
641    Sys::getpagesize()
642        .try_into()
643        .expect("page size not representable as type `int`")
644}
645
646/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getpgid.html>.
647#[unsafe(no_mangle)]
648pub extern "C" fn getpgid(pid: pid_t) -> pid_t {
649    Sys::getpgid(pid).or_minus_one_errno()
650}
651
652/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getpgrp.html>.
653#[unsafe(no_mangle)]
654pub extern "C" fn getpgrp() -> pid_t {
655    Sys::getpgid(Sys::getpid()).or_minus_one_errno()
656}
657
658/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getpid.html>.
659#[unsafe(no_mangle)]
660pub extern "C" fn getpid() -> pid_t {
661    Sys::getpid()
662}
663
664/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getppid.html>.
665#[unsafe(no_mangle)]
666pub extern "C" fn getppid() -> pid_t {
667    Sys::getppid()
668}
669
670/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getresgid.html>.
671#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getresuid.html>.
683#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getsid.html>.
695#[unsafe(no_mangle)]
696pub extern "C" fn getsid(pid: pid_t) -> pid_t {
697    Sys::getsid(pid).or_minus_one_errno()
698}
699
700/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getuid.html>.
701#[unsafe(no_mangle)]
702pub extern "C" fn getuid() -> uid_t {
703    Sys::getuid()
704}
705
706/// See <https://pubs.opengroup.org/onlinepubs/009695399/functions/getwd.html>.
707///
708/// # Deprecation
709/// The `getwd()` function was marked legacy in the Open Group Base
710/// Specifications Issue 6, and removed in Issue 7.
711#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/isatty.html>.
718#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/lchown.html>.
729#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/link.html>.
738#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/linkat.html>.
746#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/lockf.html>.
762#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/lseek.html>.
798#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/nice.html>.
804#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pause.html>.
826#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pipe.html>.
835#[unsafe(no_mangle)]
836pub unsafe extern "C" fn pipe(fildes: *mut c_int) -> c_int {
837    unsafe { pipe2(fildes, 0) }
838}
839
840/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pipe.html>.
841#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_close.html>.
849#[unsafe(no_mangle)]
850pub extern "C" fn posix_close(fildes: c_int, flag: c_int) -> c_int {
851    // Since we do not define `POSIX_CLOSE_RESTART`, this function is
852    // equivalent to `close`. In the future when we move file descriptors
853    // to userspace, it would only make sense to define `POSIX_CLOSE_RESTART`
854    // if `close` is not atomic.
855    close(fildes)
856}
857
858/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/read.html>.
859///
860/// Equivalent to `read()`, except that it shall read from a given position in
861/// the file without changing the file offset.
862///
863/// When successful, returns a non-negative number indicating the number of
864/// bytes actually read. Upon failure, returns `-1`.
865#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/write.html>.
882///
883/// Equivalent to `write()`, except that it writes into a given position and
884/// does not change the file offset (regardless of whether `O_APPEND` is set).
885///
886/// When successful, returns a non-negative number indicating the number of
887/// bytes actually written to the file associated with `fildes`. Upon failure,
888/// returns `-1`.
889#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/read.html>.
906///
907/// Attempts to read `nbyte` bytes from the file associated with the open file
908/// descriptor, `fildes`, into the buffer pointed to by `buf`.
909///
910/// When successful, returns a non-negative number indicating the number of
911/// bytes actually read. Upon failure, returns `-1`.
912#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/readlink.html>.
927#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/readlinkat.html>.
941#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/rmdir.html>.
960#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setegid.html>.
967#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/seteuid.html>.
973#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setgid.html>.
979#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setpgid.html>.
987#[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/// See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgrp.html>.
993///
994/// # Deprecation
995/// The `setpgrp()` function was marked obsolescent in the Open Group Base
996/// Specifications Issue 7, and removed in Issue 8.
997#[deprecated]
998#[unsafe(no_mangle)]
999pub extern "C" fn setpgrp() -> pid_t {
1000    setpgid(0, 0)
1001}
1002
1003/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setregid.html>.
1004#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setresgid.html>.
1012#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setresuid.html>.
1020#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setreuid.html>.
1028#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setsid.html>.
1036#[unsafe(no_mangle)]
1037pub extern "C" fn setsid() -> pid_t {
1038    Sys::setsid().or_minus_one_errno()
1039}
1040
1041/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setuid.html>.
1042#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sleep.html>.
1050#[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    // If sleep() returns because the requested time has elapsed, the value returned shall be 0.
1062    // If sleep() returns due to delivery of a signal, the return value shall be the "unslept" amount
1063    // (the requested time minus the time actually slept) in seconds.
1064    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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/swab.html>.
1071#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/symlink.html>.
1088#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/symlinkat.html>.
1096#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sync.html>.
1106#[unsafe(no_mangle)]
1107pub extern "C" fn sync() {
1108    if let Ok(()) = Sys::sync() {}; // TODO handle error
1109}
1110
1111/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcgetpgrp.html>.
1112#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcsetpgrp.html>.
1122#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/truncate.html>.
1131#[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    // TODO: Rustify
1135    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) {}; // TODO handle error
1143
1144    res
1145}
1146
1147/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/ttyname.html>.
1148#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/ttyname.html>.
1160#[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/// See <https://pubs.opengroup.org/onlinepubs/009695399/functions/ualarm.html>.
1179///
1180/// # Deprecation
1181/// The `ualarm()` function was marked obsolescent in the Open Group Base
1182/// Specifications Issue 6, and removed in Issue 7.
1183#[deprecated]
1184#[allow(deprecated)]
1185#[unsafe(no_mangle)]
1186pub extern "C" fn ualarm(usecs: useconds_t, interval: useconds_t) -> useconds_t {
1187    // TODO setitimer is unimplemented on Redox and obsolete
1188    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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/unlink.html>.
1213#[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/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/unlinkat.html>.
1220#[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/// See <https://pubs.opengroup.org/onlinepubs/009695399/functions/usleep.html>.
1228///
1229/// # Deprecation
1230/// The `usleep()` function was marked obsolescent in the Open Group Base
1231/// Specifications Issue 6, and removed in Issue 7.
1232#[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/// See <https://pubs.opengroup.org/onlinepubs/009695399/functions/vfork.html>.
1251///
1252/// # Deprecation
1253/// The `vfork()` function was marked obsolescent in the Open Group Base
1254/// Specifications Issue 6, and removed in Issue 7.
1255#[deprecated]
1256// #[unsafe(no_mangle)]
1257pub 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        // TODO: Use ARG_MAX, not this hardcoded constant
1279        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    // NULL
1297    unsafe { va.next_arg::<*const c_char>() };
1298
1299    f(unsafe { out.assume_init_ref() }, va);
1300
1301    // f only returns if it fails
1302    if argc >= 32 {
1303        unsafe { crate::header::stdlib::free(out.as_mut_ptr().cast()) };
1304    }
1305    -1
1306}
1307
1308/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/write.html>.
1309///
1310/// Attempts to write `nbyte` bytes from the buffer pointed to by `buf` to the
1311/// file associated with the open file descriptor, `fildes`.
1312///
1313/// When successful, returns a non-negative number indicating the number of
1314/// bytes actually written to the file associated with `fildes`. Upon failure,
1315/// returns `-1`.
1316#[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}