maelstrom_linux/
lib.rs

1//! Function wrappers for Linux syscalls.
2#![no_std]
3
4#[cfg(any(test, feature = "std"))]
5extern crate std;
6
7use core::{
8    ffi::CStr,
9    fmt,
10    mem::{self, MaybeUninit},
11    ops::Deref,
12    ptr,
13    time::Duration,
14};
15use derive_more::{BitOr, BitOrAssign, Display};
16use libc::{
17    c_char, c_int, c_long, c_short, c_uint, c_ulong, c_void, gid_t, id_t, idtype_t, mode_t, nfds_t,
18    pid_t, pollfd, sa_family_t, sighandler_t, siginfo_t, sigset_t, size_t, sockaddr,
19    sockaddr_storage, sockaddr_un, socklen_t, uid_t,
20};
21
22#[cfg(any(test, feature = "std"))]
23use std::os::fd;
24
25extern "C" {
26    fn sigabbrev_np(sig: c_int) -> *const c_char;
27    fn strerrorname_np(errnum: c_int) -> *const c_char;
28    fn strerrordesc_np(errnum: c_int) -> *const c_char;
29}
30
31/*  _
32 * | |_ _   _ _ __   ___  ___
33 * | __| | | | '_ \ / _ \/ __|
34 * | |_| |_| | |_) |  __/\__ \
35 *  \__|\__, | .__/ \___||___/
36 *      |___/|_|
37 *  FIGLET: types
38 */
39
40#[derive(BitOr, Clone, Copy, Default)]
41pub struct AccessMode(c_int);
42
43impl AccessMode {
44    pub const F: Self = Self(libc::F_OK);
45    pub const R: Self = Self(libc::R_OK);
46    pub const W: Self = Self(libc::W_OK);
47    pub const X: Self = Self(libc::X_OK);
48}
49
50#[derive(BitOr, Clone, Copy, Default)]
51pub struct AcceptFlags(c_int);
52
53impl AcceptFlags {
54    pub const CLOEXEC: Self = Self(libc::SOCK_CLOEXEC);
55    pub const NONBLOCK: Self = Self(libc::SOCK_NONBLOCK);
56}
57
58pub trait AsFd {
59    fn fd(&self) -> Fd;
60}
61
62#[derive(Clone)]
63#[repr(transparent)]
64pub struct CloneArgs(libc::clone_args);
65
66impl Default for CloneArgs {
67    fn default() -> Self {
68        unsafe { mem::zeroed() }
69    }
70}
71
72impl CloneArgs {
73    pub fn flags(mut self, flags: CloneFlags) -> Self {
74        self.0.flags = flags.as_u64();
75        self
76    }
77
78    pub fn exit_signal(mut self, signal: Signal) -> Self {
79        self.0.exit_signal = signal.as_u64();
80        self
81    }
82}
83
84#[derive(BitOr, BitOrAssign, Clone, Copy, Default)]
85pub struct CloneFlags(c_int);
86
87impl CloneFlags {
88    pub const CLEAR_SIGHAND: Self = Self(libc::CLONE_CLEAR_SIGHAND);
89    pub const FILES: Self = Self(libc::CLONE_FILES);
90    pub const FS: Self = Self(libc::CLONE_FS);
91    pub const NEWCGROUP: Self = Self(libc::CLONE_NEWCGROUP);
92    pub const NEWIPC: Self = Self(libc::CLONE_NEWIPC);
93    pub const NEWNET: Self = Self(libc::CLONE_NEWNET);
94    pub const NEWNS: Self = Self(libc::CLONE_NEWNS);
95    pub const NEWPID: Self = Self(libc::CLONE_NEWPID);
96    pub const NEWUSER: Self = Self(libc::CLONE_NEWUSER);
97    pub const VM: Self = Self(libc::CLONE_VM);
98    pub const VFORK: Self = Self(libc::CLONE_VFORK);
99
100    fn as_u64(&self) -> u64 {
101        self.0.try_into().unwrap()
102    }
103}
104
105#[derive(Clone, Copy, Default)]
106pub struct CloseRangeFlags(c_uint);
107
108impl CloseRangeFlags {
109    pub const CLOEXEC: Self = Self(libc::CLOSE_RANGE_CLOEXEC);
110
111    // The documentation for close_range(2) says it takes an unsigned int flags parameter. The
112    // flags are defined as unsigned ints as well. However, the close_range wrapper we get from the
113    // libc crate expects a signed int for the flags parameter.
114    fn as_c_int(&self) -> c_int {
115        self.0.try_into().unwrap()
116    }
117}
118
119#[derive(Clone, Copy)]
120pub enum CloseRangeFirst {
121    AfterStderr,
122    Fd(Fd),
123}
124
125#[derive(Clone, Copy)]
126pub enum CloseRangeLast {
127    Max,
128    Fd(Fd),
129}
130
131#[derive(PartialEq, Eq)]
132pub struct Errno(c_int);
133
134impl Errno {
135    pub fn from_u64(errno: u64) -> Self {
136        Errno(errno.try_into().unwrap())
137    }
138
139    pub fn as_u64(&self) -> u64 {
140        self.0.try_into().unwrap()
141    }
142
143    pub fn as_i32(&self) -> i32 {
144        self.0
145    }
146
147    pub fn name(&self) -> Option<&'static str> {
148        let errno = unsafe { strerrorname_np(self.0) };
149        (!errno.is_null()).then(|| unsafe { CStr::from_ptr(errno) }.to_str().unwrap())
150    }
151
152    pub fn desc(&self) -> Option<&'static str> {
153        let errno = unsafe { strerrordesc_np(self.0) };
154        (!errno.is_null()).then(|| unsafe { CStr::from_ptr(errno) }.to_str().unwrap())
155    }
156
157    /// Returns `Ok(value)` if it does not contain the sentinel value. This
158    /// should not be used when `-1` is not the errno sentinel value.
159    fn result<S: ErrnoSentinel + PartialEq<S>>(value: S) -> Result<S, Errno> {
160        if value == S::sentinel() {
161            Err(Errno(unsafe { *libc::__errno_location() }))
162        } else {
163            Ok(value)
164        }
165    }
166
167    pub const ENOSYS: Self = Self(libc::ENOSYS);
168    pub const EPERM: Self = Self(libc::EPERM);
169    pub const ENOENT: Self = Self(libc::ENOENT);
170    pub const ESRCH: Self = Self(libc::ESRCH);
171    pub const EINTR: Self = Self(libc::EINTR);
172    pub const EIO: Self = Self(libc::EIO);
173    pub const ENXIO: Self = Self(libc::ENXIO);
174    pub const E2BIG: Self = Self(libc::E2BIG);
175    pub const ENOEXEC: Self = Self(libc::ENOEXEC);
176    pub const EBADF: Self = Self(libc::EBADF);
177    pub const ECHILD: Self = Self(libc::ECHILD);
178    pub const EAGAIN: Self = Self(libc::EAGAIN);
179    pub const ENOMEM: Self = Self(libc::ENOMEM);
180    pub const EACCES: Self = Self(libc::EACCES);
181    pub const EFAULT: Self = Self(libc::EFAULT);
182    pub const ENOTBLK: Self = Self(libc::ENOTBLK);
183    pub const EBUSY: Self = Self(libc::EBUSY);
184    pub const EEXIST: Self = Self(libc::EEXIST);
185    pub const EXDEV: Self = Self(libc::EXDEV);
186    pub const ENODEV: Self = Self(libc::ENODEV);
187    pub const ENOTDIR: Self = Self(libc::ENOTDIR);
188    pub const EISDIR: Self = Self(libc::EISDIR);
189    pub const EINVAL: Self = Self(libc::EINVAL);
190    pub const ENFILE: Self = Self(libc::ENFILE);
191    pub const EMFILE: Self = Self(libc::EMFILE);
192    pub const ENOTTY: Self = Self(libc::ENOTTY);
193    pub const ETXTBSY: Self = Self(libc::ETXTBSY);
194    pub const EFBIG: Self = Self(libc::EFBIG);
195    pub const ENOSPC: Self = Self(libc::ENOSPC);
196    pub const ESPIPE: Self = Self(libc::ESPIPE);
197    pub const EROFS: Self = Self(libc::EROFS);
198    pub const EMLINK: Self = Self(libc::EMLINK);
199    pub const EPIPE: Self = Self(libc::EPIPE);
200    pub const EDOM: Self = Self(libc::EDOM);
201    pub const ERANGE: Self = Self(libc::ERANGE);
202    pub const EWOULDBLOCK: Self = Self::EAGAIN;
203}
204
205impl fmt::Debug for Errno {
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        match self.name() {
208            Some(name) => write!(f, "{name}"),
209            None => write!(f, "UNKNOWN({})", self.0),
210        }
211    }
212}
213
214impl fmt::Display for Errno {
215    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216        match (self.name(), self.desc()) {
217            (Some(name), Some(desc)) => {
218                write!(f, "{name}: {desc}")
219            }
220            _ => {
221                write!(f, "{}: Unknown error", self.0)
222            }
223        }
224    }
225}
226
227#[cfg(any(test, feature = "std"))]
228impl std::error::Error for Errno {}
229
230#[cfg(any(test, feature = "std"))]
231impl From<Errno> for std::io::Error {
232    fn from(e: Errno) -> Self {
233        std::io::Error::from_raw_os_error(e.0)
234    }
235}
236
237/// The sentinel value indicates that a function failed and more detailed
238/// information about the error can be found in `errno`
239pub trait ErrnoSentinel: Sized {
240    fn sentinel() -> Self;
241}
242
243impl ErrnoSentinel for isize {
244    fn sentinel() -> Self {
245        -1
246    }
247}
248
249impl ErrnoSentinel for i32 {
250    fn sentinel() -> Self {
251        -1
252    }
253}
254
255impl ErrnoSentinel for i64 {
256    fn sentinel() -> Self {
257        -1
258    }
259}
260
261impl ErrnoSentinel for *mut c_void {
262    fn sentinel() -> Self {
263        libc::MAP_FAILED
264    }
265}
266
267#[derive(Clone, Copy, Debug, PartialEq, Eq)]
268pub struct ExitCode(c_int);
269
270impl ExitCode {
271    // Only 8 bits of exit code is actually stored by the kernel.
272    pub fn from_u8(code: u8) -> Self {
273        Self(code.into())
274    }
275
276    pub fn as_u8(&self) -> u8 {
277        self.0 as u8
278    }
279}
280
281#[derive(Clone, Copy, Debug, Eq, PartialEq)]
282#[repr(transparent)]
283pub struct Fd(c_int);
284
285impl Fd {
286    pub const STDIN: Self = Self(libc::STDIN_FILENO);
287    pub const STDOUT: Self = Self(libc::STDOUT_FILENO);
288    pub const STDERR: Self = Self(libc::STDERR_FILENO);
289    pub const AT_FDCWD: Self = Self(libc::AT_FDCWD);
290
291    fn from_c_long(fd: c_long) -> Self {
292        Self(fd.try_into().unwrap())
293    }
294
295    fn as_c_uint(self) -> c_uint {
296        self.0.try_into().unwrap()
297    }
298
299    pub fn from_raw(raw: c_int) -> Self {
300        Self(raw)
301    }
302
303    pub fn as_c_int(self) -> c_int {
304        self.0
305    }
306}
307
308impl AsFd for Fd {
309    fn fd(&self) -> Fd {
310        *self
311    }
312}
313
314#[derive(BitOr, Clone, Copy, Default)]
315pub struct FileMode(mode_t);
316
317impl FileMode {
318    pub const SUID: Self = Self(libc::S_ISUID);
319    pub const SGID: Self = Self(libc::S_ISGID);
320    pub const SVTX: Self = Self(libc::S_ISVTX);
321
322    pub const RWXU: Self = Self(libc::S_IRWXU);
323    pub const RUSR: Self = Self(libc::S_IRUSR);
324    pub const WUSR: Self = Self(libc::S_IWUSR);
325    pub const XUSR: Self = Self(libc::S_IXUSR);
326
327    pub const RWXG: Self = Self(libc::S_IRWXG);
328    pub const RGRP: Self = Self(libc::S_IRGRP);
329    pub const WGRP: Self = Self(libc::S_IWGRP);
330    pub const XGRP: Self = Self(libc::S_IXGRP);
331
332    pub const RWXO: Self = Self(libc::S_IRWXO);
333    pub const ROTH: Self = Self(libc::S_IROTH);
334    pub const WOTH: Self = Self(libc::S_IWOTH);
335    pub const XOTH: Self = Self(libc::S_IXOTH);
336}
337
338#[derive(BitOr, Clone, Copy, Default)]
339pub struct FsconfigCommand(c_uint);
340
341impl FsconfigCommand {
342    pub const SET_FLAG: Self = Self(0);
343    pub const SET_STRING: Self = Self(1);
344    pub const SET_BINARY: Self = Self(2);
345    pub const SET_PATH: Self = Self(3);
346    pub const SET_PATH_EMPTY: Self = Self(4);
347    pub const SET_FD: Self = Self(5);
348    pub const CMD_CREATE: Self = Self(6);
349    pub const CMD_RECONFIGURE: Self = Self(7);
350    pub const CMD_CREATE_EXCL: Self = Self(8);
351}
352
353#[derive(BitOr, Clone, Copy, Default)]
354pub struct FsmountFlags(c_ulong);
355
356impl FsmountFlags {
357    pub const CLOEXEC: Self = Self(1);
358}
359
360#[derive(BitOr, Clone, Copy, Default)]
361pub struct FsopenFlags(c_uint);
362
363impl FsopenFlags {
364    pub const CLOEXEC: Self = Self(1);
365}
366
367#[derive(Clone, Copy, Display)]
368pub struct Gid(gid_t);
369
370impl Gid {
371    pub fn as_u32(&self) -> u32 {
372        self.0
373    }
374
375    pub fn from_u32(v: u32) -> Self {
376        Self(v)
377    }
378}
379
380#[derive(BitOr, BitOrAssign, Clone, Copy, Default)]
381pub struct MapFlags(c_int);
382
383impl MapFlags {
384    pub const ANONYMOUS: Self = Self(libc::MAP_ANONYMOUS);
385    pub const PRIVATE: Self = Self(libc::MAP_PRIVATE);
386}
387
388#[derive(BitOr, BitOrAssign, Clone, Copy, Default)]
389pub struct MemoryProtection(c_int);
390
391impl MemoryProtection {
392    pub const EXEC: Self = Self(libc::PROT_EXEC);
393    pub const READ: Self = Self(libc::PROT_READ);
394    pub const WRITE: Self = Self(libc::PROT_WRITE);
395    pub const NONE: Self = Self(libc::PROT_NONE);
396}
397
398#[derive(BitOr, Clone, Copy, Default)]
399pub struct MountAttrs(c_uint);
400
401impl MountAttrs {
402    pub const RDONLY: Self = Self(0x00000001);
403    pub const NOSUID: Self = Self(0x00000002);
404    pub const NODEV: Self = Self(0x00000004);
405    pub const NOEXEC: Self = Self(0x00000008);
406    pub const _ATIME: Self = Self(0x00000070);
407    pub const RELATIME: Self = Self(0x00000000);
408    pub const NOATIME: Self = Self(0x00000010);
409    pub const STRICTATIME: Self = Self(0x00000020);
410    pub const NODIRATIME: Self = Self(0x00000080);
411    pub const IDMAP: Self = Self(0x00100000);
412    pub const NOSYMFOLLOW: Self = Self(0x00200000);
413}
414
415#[derive(BitOr, Clone, Copy, Default)]
416pub struct MountFlags(c_ulong);
417
418impl MountFlags {
419    pub const BIND: Self = Self(libc::MS_BIND);
420    pub const REMOUNT: Self = Self(libc::MS_REMOUNT);
421    pub const RDONLY: Self = Self(libc::MS_RDONLY);
422    pub const NOSUID: Self = Self(libc::MS_NOSUID);
423    pub const NOEXEC: Self = Self(libc::MS_NOEXEC);
424    pub const NODEV: Self = Self(libc::MS_NODEV);
425}
426
427#[derive(BitOr, Clone, Copy, Default)]
428pub struct MoveMountFlags(c_uint);
429
430impl MoveMountFlags {
431    pub const F_EMPTY_PATH: Self = Self(libc::MOVE_MOUNT_F_EMPTY_PATH);
432    pub const T_EMPTY_PATH: Self = Self(libc::MOVE_MOUNT_T_EMPTY_PATH);
433}
434
435#[derive(BitOr, BitOrAssign, Clone, Copy, Default)]
436pub struct OpenFlags(c_int);
437
438impl OpenFlags {
439    pub const RDWR: Self = Self(libc::O_RDWR);
440    pub const WRONLY: Self = Self(libc::O_WRONLY);
441    pub const TRUNC: Self = Self(libc::O_TRUNC);
442    pub const NONBLOCK: Self = Self(libc::O_NONBLOCK);
443    pub const NOCTTY: Self = Self(libc::O_NOCTTY);
444}
445
446#[derive(BitOr, Clone, Copy, Default)]
447pub struct OpenTreeFlags(c_uint);
448
449impl OpenTreeFlags {
450    pub const CLOEXEC: Self = Self(libc::OPEN_TREE_CLOEXEC);
451    pub const CLONE: Self = Self(libc::OPEN_TREE_CLONE);
452    pub const RECURSIVE: Self = Self(libc::AT_RECURSIVE as c_uint);
453    pub const EMPTY_PATH: Self = Self(libc::AT_EMPTY_PATH as c_uint);
454}
455
456pub struct OwnedFd(Fd);
457
458impl OwnedFd {
459    pub fn from_fd(fd: Fd) -> Self {
460        Self(fd)
461    }
462
463    pub fn as_fd(&self) -> Fd {
464        self.0
465    }
466
467    pub fn into_fd(self) -> Fd {
468        let raw_fd = self.0;
469        mem::forget(self);
470        raw_fd
471    }
472}
473
474impl AsFd for OwnedFd {
475    fn fd(&self) -> Fd {
476        self.0
477    }
478}
479
480#[cfg(any(test, feature = "std"))]
481impl fd::AsRawFd for OwnedFd {
482    fn as_raw_fd(&self) -> fd::RawFd {
483        self.0 .0
484    }
485}
486
487#[cfg(any(test, feature = "std"))]
488impl From<OwnedFd> for fd::OwnedFd {
489    fn from(owned_fd: OwnedFd) -> Self {
490        let raw_fd = owned_fd.into_fd();
491        unsafe { <Self as fd::FromRawFd>::from_raw_fd(raw_fd.0) }
492    }
493}
494
495#[cfg(any(test, feature = "std"))]
496impl From<fd::OwnedFd> for OwnedFd {
497    fn from(owned_fd: fd::OwnedFd) -> Self {
498        let raw_fd = fd::IntoRawFd::into_raw_fd(owned_fd);
499        Self(Fd(raw_fd))
500    }
501}
502
503#[cfg(any(test, feature = "std"))]
504impl From<OwnedFd> for std::os::unix::net::UnixStream {
505    fn from(owned_fd: OwnedFd) -> std::os::unix::net::UnixStream {
506        fd::OwnedFd::from(owned_fd).into()
507    }
508}
509
510#[cfg(feature = "tokio")]
511impl TryFrom<OwnedFd> for tokio::net::UnixStream {
512    type Error = std::io::Error;
513    fn try_from(owned_fd: OwnedFd) -> Result<tokio::net::UnixStream, Self::Error> {
514        tokio::net::UnixStream::from_std(fd::OwnedFd::from(owned_fd).into())
515    }
516}
517
518#[cfg(any(test, feature = "std"))]
519impl From<OwnedFd> for std::os::unix::net::UnixListener {
520    fn from(owned_fd: OwnedFd) -> std::os::unix::net::UnixListener {
521        fd::OwnedFd::from(owned_fd).into()
522    }
523}
524
525#[cfg(feature = "tokio")]
526impl TryFrom<OwnedFd> for tokio::net::UnixListener {
527    type Error = std::io::Error;
528    fn try_from(owned_fd: OwnedFd) -> Result<tokio::net::UnixListener, Self::Error> {
529        tokio::net::UnixListener::from_std(fd::OwnedFd::from(owned_fd).into())
530    }
531}
532
533impl Drop for OwnedFd {
534    fn drop(&mut self) {
535        // Just ignore the return value from close.
536        unsafe { libc::close(self.0 .0) };
537    }
538}
539
540#[derive(Clone, Copy, Debug, Display, Eq, Hash, PartialEq, PartialOrd, Ord)]
541pub struct Pid(pid_t);
542
543impl Pid {
544    fn from_c_long(pid: c_long) -> Self {
545        Self(pid.try_into().unwrap())
546    }
547
548    #[cfg(feature = "test")]
549    pub fn new_for_test(pid: pid_t) -> Self {
550        Self(pid)
551    }
552
553    pub fn as_i32(self) -> i32 {
554        self.0
555    }
556}
557
558#[cfg(any(test, feature = "std"))]
559impl From<std::process::Child> for Pid {
560    fn from(p: std::process::Child) -> Self {
561        Self::from(&p)
562    }
563}
564
565#[cfg(any(test, feature = "std"))]
566impl<'a> From<&'a std::process::Child> for Pid {
567    fn from(p: &'a std::process::Child) -> Self {
568        Self(p.id().try_into().unwrap())
569    }
570}
571
572#[derive(BitOr, Clone, Copy, Default)]
573pub struct PollEvents(c_short);
574
575impl PollEvents {
576    pub const IN: Self = Self(libc::POLLIN);
577}
578
579#[repr(transparent)]
580pub struct PollFd(pollfd);
581
582impl PollFd {
583    pub fn new(fd: Fd, events: PollEvents) -> Self {
584        PollFd(pollfd {
585            fd: fd.0,
586            events: events.0,
587            revents: 0,
588        })
589    }
590}
591
592#[derive(Debug, Copy, Clone, PartialEq, Eq)]
593pub struct Rlimit {
594    pub current: u64,
595    pub max: u64,
596}
597
598#[repr(u32)]
599pub enum RlimitResource {
600    NoFile = libc::RLIMIT_NOFILE,
601}
602
603#[derive(Clone, Copy, Debug, Eq, PartialEq)]
604pub struct Sighandler(sighandler_t);
605
606impl Sighandler {
607    pub const IGN: Self = Self(libc::SIG_IGN);
608    pub const DFL: Self = Self(libc::SIG_DFL);
609}
610
611#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
612pub struct Signal(c_int);
613
614impl Signal {
615    pub const ALRM: Self = Self(libc::SIGALRM);
616    pub const CHLD: Self = Self(libc::SIGCHLD);
617    pub const HUP: Self = Self(libc::SIGHUP);
618    pub const INT: Self = Self(libc::SIGINT);
619    pub const IO: Self = Self(libc::SIGIO);
620    pub const KILL: Self = Self(libc::SIGKILL);
621    pub const LOST: Self = Self(29);
622    pub const PIPE: Self = Self(libc::SIGPIPE);
623    pub const POLL: Self = Self(libc::SIGPOLL);
624    pub const PROF: Self = Self(libc::SIGPROF);
625    pub const PWR: Self = Self(libc::SIGPWR);
626    pub const QUIT: Self = Self(libc::SIGQUIT);
627    pub const TERM: Self = Self(libc::SIGTERM);
628    pub const TSTP: Self = Self(libc::SIGTSTP);
629    pub const TTIN: Self = Self(libc::SIGTTIN);
630    pub const TTOU: Self = Self(libc::SIGTTOU);
631    pub const USR1: Self = Self(libc::SIGUSR1);
632    pub const USR2: Self = Self(libc::SIGUSR2);
633    pub const VTALRM: Self = Self(libc::SIGVTALRM);
634    pub const WINCH: Self = Self(libc::SIGWINCH);
635
636    pub fn from_c_int(signo: c_int) -> Self {
637        Self(signo)
638    }
639
640    pub fn from_u8(signo: u8) -> Self {
641        Self(signo.into())
642    }
643
644    pub fn as_u8(&self) -> u8 {
645        self.0.try_into().unwrap()
646    }
647
648    pub fn as_c_int(&self) -> c_int {
649        self.0
650    }
651
652    fn as_c_ulong(&self) -> c_ulong {
653        self.0.try_into().unwrap()
654    }
655
656    fn as_u64(&self) -> u64 {
657        self.0.try_into().unwrap()
658    }
659}
660
661impl fmt::Display for Signal {
662    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
663        let abbrev = unsafe { sigabbrev_np(self.0) };
664        if abbrev.is_null() {
665            write!(f, "Invalid Signal {}", self.0)
666        } else {
667            let abbrev = unsafe { CStr::from_ptr(abbrev) }.to_str().unwrap();
668            write!(f, "SIG{abbrev}")
669        }
670    }
671}
672
673#[repr(transparent)]
674pub struct SignalSet(sigset_t);
675
676impl SignalSet {
677    pub fn empty() -> Self {
678        let mut inner: MaybeUninit<sigset_t> = MaybeUninit::uninit();
679        let inner_ptr = inner.as_mut_ptr();
680        Errno::result(unsafe { libc::sigemptyset(inner_ptr) }).unwrap();
681        Self(unsafe { inner.assume_init() })
682    }
683
684    pub fn full() -> Self {
685        let mut inner: MaybeUninit<sigset_t> = MaybeUninit::uninit();
686        let inner_ptr = inner.as_mut_ptr();
687        Errno::result(unsafe { libc::sigfillset(inner_ptr) }).unwrap();
688        Self(unsafe { inner.assume_init() })
689    }
690
691    pub fn insert(&mut self, signal: Signal) {
692        Errno::result(unsafe { libc::sigaddset(&mut self.0, signal.0) }).unwrap();
693    }
694
695    pub fn remove(&mut self, signal: Signal) {
696        Errno::result(unsafe { libc::sigdelset(&mut self.0, signal.0) }).unwrap();
697    }
698
699    pub fn contains(&mut self, signal: Signal) -> bool {
700        Errno::result(unsafe { libc::sigismember(&self.0, signal.0) })
701            .map(|res| res != 0)
702            .unwrap()
703    }
704}
705
706#[derive(Clone, Copy)]
707pub struct SigprocmaskHow(c_int);
708
709impl SigprocmaskHow {
710    pub const BLOCK: Self = Self(libc::SIG_BLOCK);
711    pub const UNBLOCK: Self = Self(libc::SIG_UNBLOCK);
712    pub const SETMASK: Self = Self(libc::SIG_SETMASK);
713}
714
715#[repr(C)]
716pub struct Sockaddr {
717    family: sa_family_t,
718    data: [u8],
719}
720
721impl Sockaddr {
722    pub fn family(&self) -> sa_family_t {
723        self.family
724    }
725
726    /// Return the size, in bytes, of the pointed-to `Sockaddr`. This byte count includes the
727    /// leading two bytes used to store the address family.
728    #[allow(clippy::len_without_is_empty)]
729    pub fn len(&self) -> usize {
730        let res = mem::size_of_val(self);
731        assert_eq!(res, self.data.len() + mem::size_of::<sa_family_t>());
732        res
733    }
734
735    /// Return a reference to the underlying `sockaddr` and the length. This is useful for calling
736    /// underlying libc functions that take a constant sockaddr. For libc functions that take
737    /// mutable sockaddrs, see [`SockaddrStorage::as_mut_parts`].
738    pub fn as_parts(&self) -> (&sockaddr, socklen_t) {
739        unsafe {
740            (
741                &*(&self.family as *const sa_family_t as *const sockaddr),
742                self.len() as socklen_t,
743            )
744        }
745    }
746
747    /// Create a `Sockaddr` reference from a `sockaddr` pointer and a size.
748    ///
749    /// # Safety
750    ///
751    /// The `sockaddr` pointer must point to a valid `sockaddr` of some sort, and `len` must be
752    /// less than or equal to the size of the underlying `sockaddr` object.
753    pub unsafe fn from_raw_parts<'a>(addr: *const sockaddr, len: usize) -> &'a Self {
754        let res =
755            &*(ptr::slice_from_raw_parts(addr as *const u8, len - mem::size_of::<sa_family_t>())
756                as *const Self);
757        assert_eq!(res.len(), len);
758        res
759    }
760
761    pub fn as_sockaddr_un(&self) -> Option<&SockaddrUn> {
762        (self.family == libc::AF_UNIX as sa_family_t).then(|| unsafe { mem::transmute(self) })
763    }
764}
765
766pub struct SockaddrStorage {
767    inner: sockaddr_storage,
768    len: socklen_t,
769}
770
771impl SockaddrStorage {
772    /// Return raw mutable references into the `SockaddrStorage` so that a function can be used to
773    /// initialize the sockaddr.
774    ///
775    /// # Safety
776    ///
777    /// The referenced length cannot be adjusted to a larger size.
778    pub unsafe fn as_mut_parts(&mut self) -> (&mut sockaddr, &mut socklen_t) {
779        (
780            mem::transmute::<&mut libc::sockaddr_storage, &mut libc::sockaddr>(&mut self.inner),
781            &mut self.len,
782        )
783    }
784}
785
786impl Default for SockaddrStorage {
787    fn default() -> Self {
788        Self {
789            inner: unsafe { mem::zeroed() },
790            len: mem::size_of::<sockaddr_storage>() as socklen_t,
791        }
792    }
793}
794
795impl Deref for SockaddrStorage {
796    type Target = Sockaddr;
797    fn deref(&self) -> &Self::Target {
798        unsafe {
799            Sockaddr::from_raw_parts(
800                &self.inner as *const sockaddr_storage as *const sockaddr,
801                self.len as usize,
802            )
803        }
804    }
805}
806
807#[repr(C)]
808pub struct SockaddrNetlink {
809    sin_family: sa_family_t,
810    nl_pad: u16,
811    nl_pid: u32,
812    nl_groups: u32,
813}
814
815impl Default for SockaddrNetlink {
816    fn default() -> Self {
817        Self {
818            sin_family: libc::AF_NETLINK as sa_family_t,
819            nl_pad: 0,
820            nl_pid: 0, // the kernel
821            nl_groups: 0,
822        }
823    }
824}
825
826impl Deref for SockaddrNetlink {
827    type Target = Sockaddr;
828    fn deref(&self) -> &Self::Target {
829        unsafe {
830            Sockaddr::from_raw_parts(
831                self as *const SockaddrNetlink as *const sockaddr,
832                mem::size_of_val(self),
833            )
834        }
835    }
836}
837
838#[repr(C)]
839pub struct SockaddrUn {
840    family: sa_family_t,
841    path: [u8],
842}
843
844impl SockaddrUn {
845    pub fn path(&self) -> &[u8] {
846        &self.path
847    }
848
849    /// Create a `SockaddrUn` reference from a `sockaddr_un` pointer and a size.
850    ///
851    /// # Safety
852    ///
853    /// The `sockaddr_un` pointer must point to a valid `sockaddr_un`, and `len` must be less than
854    /// or equal to the size of the underlying `sockaddr` object.
855    pub unsafe fn from_raw_parts<'a>(addr: *const sockaddr, len: usize) -> &'a Self {
856        let res =
857            &*(ptr::slice_from_raw_parts(addr as *const u8, len - mem::size_of::<sa_family_t>())
858                as *const Self);
859        assert_eq!(res.len(), len);
860        assert_eq!(res.family, libc::AF_UNIX as sa_family_t);
861        res
862    }
863}
864
865impl Deref for SockaddrUn {
866    type Target = Sockaddr;
867    fn deref(&self) -> &Self::Target {
868        unsafe { mem::transmute(self) }
869    }
870}
871
872pub struct SockaddrUnStorage {
873    inner: sockaddr_un,
874    len: socklen_t,
875}
876
877impl SockaddrUnStorage {
878    pub fn new(path: &[u8]) -> Result<Self, SockaddrUnStoragePathTooLongError> {
879        let mut inner = sockaddr_un {
880            sun_family: libc::AF_UNIX as sa_family_t,
881            sun_path: unsafe { mem::zeroed() },
882        };
883        if mem::size_of_val(&inner.sun_path) < path.len() {
884            Err(SockaddrUnStoragePathTooLongError {
885                maximum_accepted: mem::size_of_val(&inner.sun_path),
886                actual: path.len(),
887            })
888        } else {
889            unsafe {
890                ptr::copy_nonoverlapping(
891                    path.as_ptr(),
892                    inner.sun_path.as_mut_ptr() as *mut u8,
893                    path.len(),
894                )
895            };
896            Ok(Self {
897                inner,
898                len: (path.len() + mem::size_of::<sa_family_t>()) as socklen_t,
899            })
900        }
901    }
902
903    pub fn new_autobind() -> Self {
904        Self::new(b"").unwrap()
905    }
906}
907
908impl Deref for SockaddrUnStorage {
909    type Target = SockaddrUn;
910    fn deref(&self) -> &Self::Target {
911        unsafe {
912            SockaddrUn::from_raw_parts(
913                &self.inner as *const sockaddr_un as *const sockaddr,
914                self.len as usize,
915            )
916        }
917    }
918}
919
920#[derive(Debug)]
921pub struct SockaddrUnStoragePathTooLongError {
922    pub maximum_accepted: usize,
923    pub actual: usize,
924}
925
926impl fmt::Display for SockaddrUnStoragePathTooLongError {
927    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
928        write!(
929            f,
930            "sockaddr_un path too long; maximum_accepted: {maximum_accepted}, actual: {actual}",
931            maximum_accepted = self.maximum_accepted,
932            actual = self.actual
933        )
934    }
935}
936
937#[cfg(any(test, feature = "std"))]
938impl std::error::Error for SockaddrUnStoragePathTooLongError {}
939
940#[derive(Clone, Copy)]
941pub struct SocketDomain(c_int);
942
943impl SocketDomain {
944    pub const NETLINK: Self = Self(libc::PF_NETLINK);
945    pub const UNIX: Self = Self(libc::PF_UNIX);
946}
947
948#[derive(Clone, Copy, Default)]
949pub struct SocketProtocol(c_int);
950
951impl SocketProtocol {
952    pub const NETLINK_ROUTE: Self = Self(0);
953}
954
955#[derive(BitOr, Clone, Copy, Default)]
956pub struct SocketType(c_int);
957
958impl SocketType {
959    pub const RAW: Self = Self(libc::SOCK_RAW);
960    pub const STREAM: Self = Self(libc::SOCK_STREAM);
961    pub const NONBLOCK: Self = Self(libc::SOCK_NONBLOCK);
962    pub const CLOEXEC: Self = Self(libc::SOCK_CLOEXEC);
963}
964
965#[derive(Clone, Copy, Display)]
966pub struct Uid(uid_t);
967
968impl Uid {
969    pub fn as_u32(&self) -> u32 {
970        self.0
971    }
972
973    pub fn from_u32(v: u32) -> Self {
974        Self(v)
975    }
976}
977
978#[derive(BitOr, Clone, Copy, Default)]
979pub struct UmountFlags(c_int);
980
981impl UmountFlags {
982    pub const DETACH: Self = Self(libc::MNT_DETACH);
983}
984
985#[derive(Clone, Copy)]
986pub struct WaitResult {
987    pub pid: Pid,
988    pub status: WaitStatus,
989}
990
991#[derive(Clone, Copy, Debug, PartialEq, Eq)]
992pub enum WaitStatus {
993    Exited(ExitCode),
994    Signaled(Signal),
995}
996
997pub enum Whence {
998    SeekSet,
999    SeekCur,
1000    SeekEnd,
1001}
1002
1003impl Whence {
1004    fn as_i32(&self) -> i32 {
1005        match self {
1006            Self::SeekSet => libc::SEEK_SET,
1007            Self::SeekCur => libc::SEEK_CUR,
1008            Self::SeekEnd => libc::SEEK_END,
1009        }
1010    }
1011}
1012
1013/*   __                  _   _
1014 *  / _|_   _ _ __   ___| |_(_) ___  _ __  ___
1015 * | |_| | | | '_ \ / __| __| |/ _ \| '_ \/ __|
1016 * |  _| |_| | | | | (__| |_| | (_) | | | \__ \
1017 * |_|  \__,_|_| |_|\___|\__|_|\___/|_| |_|___/
1018 *  FIGLET: functions
1019 */
1020
1021pub fn abort() -> ! {
1022    unsafe { libc::abort() }
1023}
1024
1025pub fn access(path: &CStr, mode: AccessMode) -> Result<(), Errno> {
1026    let path_ptr = path.as_ptr();
1027    Errno::result(unsafe { libc::access(path_ptr, mode.0) }).map(drop)
1028}
1029
1030pub fn accept(fd: &impl AsFd, flags: AcceptFlags) -> Result<(OwnedFd, SockaddrStorage), Errno> {
1031    let fd = fd.fd();
1032    let mut sockaddr = SockaddrStorage::default();
1033    let (addr_ptr, len_ptr) = unsafe { sockaddr.as_mut_parts() };
1034    let fd = Errno::result(unsafe { libc::accept4(fd.0, addr_ptr, len_ptr, flags.0) })
1035        .map(Fd)
1036        .map(OwnedFd)?;
1037    Ok((fd, sockaddr))
1038}
1039
1040pub fn autobound_unix_listener(
1041    socket_flags: SocketType,
1042    backlog: u32,
1043) -> Result<(OwnedFd, [u8; 6]), Errno> {
1044    let sock = socket(
1045        SocketDomain::UNIX,
1046        SocketType::STREAM | socket_flags,
1047        Default::default(),
1048    )?;
1049    bind(&sock, &SockaddrUnStorage::new_autobind())?;
1050    listen(&sock, backlog)?;
1051    let addr = getsockname(&sock)?
1052        .as_sockaddr_un()
1053        .unwrap()
1054        .path()
1055        .try_into()
1056        .unwrap();
1057    Ok((sock, addr))
1058}
1059
1060pub fn bind(fd: &impl AsFd, sockaddr: &Sockaddr) -> Result<(), Errno> {
1061    let fd = fd.fd();
1062    let (addr, len) = sockaddr.as_parts();
1063    Errno::result(unsafe { libc::bind(fd.0, addr, len) }).map(drop)
1064}
1065
1066pub fn chdir(path: &CStr) -> Result<(), Errno> {
1067    let path_ptr = path.as_ptr();
1068    Errno::result(unsafe { libc::chdir(path_ptr) }).map(drop)
1069}
1070
1071pub fn clone3(args: &mut CloneArgs) -> Result<Option<Pid>, Errno> {
1072    assert_eq!(args.0.flags & libc::CLONE_VM as c_ulong, 0);
1073    let args_ptr = args as *mut CloneArgs;
1074    let size = mem::size_of::<CloneArgs>() as size_t;
1075    let ret = Errno::result(unsafe { libc::syscall(libc::SYS_clone3, args_ptr, size) })?;
1076    Ok(if ret == 0 {
1077        None
1078    } else {
1079        Some(Pid::from_c_long(ret))
1080    })
1081}
1082
1083pub fn clone3_with_child_pidfd(args: &mut CloneArgs) -> Result<Option<(Pid, OwnedFd)>, Errno> {
1084    assert_eq!(args.0.flags & libc::CLONE_VM as c_ulong, 0);
1085    let inner = |args: &mut CloneArgs, child_pidfd: &mut Fd| {
1086        assert_eq!(args.0.flags & (libc::CLONE_PIDFD as c_ulong), 0);
1087        args.0.flags |= libc::CLONE_PIDFD as c_ulong;
1088        args.0.pidfd = child_pidfd as *mut Fd as u64;
1089        let args_ptr = args as *mut CloneArgs;
1090        let size = mem::size_of::<CloneArgs>() as size_t;
1091        unsafe { libc::syscall(libc::SYS_clone3, args_ptr, size) }
1092    };
1093    let mut child_pidfd = Fd(0);
1094    let ret = Errno::result(inner(args, &mut child_pidfd))?;
1095    Ok(if ret == 0 {
1096        None
1097    } else {
1098        Some((Pid::from_c_long(ret), OwnedFd(child_pidfd)))
1099    })
1100}
1101
1102/// # Safety
1103///
1104/// stack and arg pointers must point to memory the child can access while it is around
1105pub unsafe fn clone_with_child_pidfd(
1106    func: extern "C" fn(*mut c_void) -> i32,
1107    stack: *mut c_void,
1108    arg: *mut c_void,
1109    args: &mut CloneArgs,
1110) -> Result<(Pid, OwnedFd), Errno> {
1111    let inner = |args: &mut CloneArgs, child_pidfd: &mut Fd| {
1112        assert_eq!(args.0.flags & (libc::CLONE_PIDFD as c_ulong), 0);
1113        args.0.flags |= libc::CLONE_PIDFD as c_ulong;
1114        args.0.pidfd = child_pidfd as *mut Fd as u64;
1115
1116        let flags = args.0.flags as i32 | (args.0.exit_signal & 0xFF) as i32;
1117        unsafe { libc::clone(func, stack, flags, arg, args.0.pidfd) }
1118    };
1119    let mut child_pidfd = Fd(0);
1120    let ret = Errno::result(inner(args, &mut child_pidfd))?;
1121    Ok((Pid(ret), OwnedFd(child_pidfd)))
1122}
1123
1124/// # Safety
1125///
1126/// stack and arg pointers must point to memory the child can access while it is around
1127pub unsafe fn clone(
1128    func: extern "C" fn(*mut c_void) -> i32,
1129    stack: *mut c_void,
1130    arg: *mut c_void,
1131    args: &CloneArgs,
1132) -> Result<Pid, Errno> {
1133    let flags = args.0.flags as i32 | (args.0.exit_signal & 0xFF) as i32;
1134    let ret = Errno::result(unsafe { libc::clone(func, stack, flags, arg) })?;
1135    Ok(Pid(ret))
1136}
1137
1138pub fn close_range(
1139    first: CloseRangeFirst,
1140    last: CloseRangeLast,
1141    flags: CloseRangeFlags,
1142) -> Result<(), Errno> {
1143    let first = match first {
1144        CloseRangeFirst::AfterStderr => (libc::STDERR_FILENO + 1) as c_uint,
1145        CloseRangeFirst::Fd(fd) => fd.as_c_uint(),
1146    };
1147    let last = match last {
1148        CloseRangeLast::Max => c_uint::MAX,
1149        CloseRangeLast::Fd(fd) => fd.as_c_uint(),
1150    };
1151    let flags = flags.as_c_int();
1152    Errno::result(unsafe { libc::close_range(first, last, flags) }).map(drop)
1153}
1154
1155pub fn connect(fd: &impl AsFd, sockaddr: &Sockaddr) -> Result<(), Errno> {
1156    let fd = fd.fd();
1157    let (addr, len) = sockaddr.as_parts();
1158    Errno::result(unsafe { libc::connect(fd.0, addr, len) }).map(drop)
1159}
1160
1161pub fn dup2(from: &impl AsFd, to: &impl AsFd) -> Result<Fd, Errno> {
1162    let from = from.fd();
1163    let to = to.fd();
1164    Errno::result(unsafe { libc::dup2(from.0, to.0) }).map(Fd)
1165}
1166
1167pub fn execve(path: &CStr, argv: &[Option<&u8>], envp: &[Option<&u8>]) -> Result<(), Errno> {
1168    let path_ptr = path.as_ptr();
1169    let argv_ptr = argv.as_ptr() as *const *const c_char;
1170    let envp_ptr = envp.as_ptr() as *const *const c_char;
1171    Errno::result(unsafe { libc::execve(path_ptr, argv_ptr, envp_ptr) }).map(drop)
1172}
1173
1174pub fn execvpe(path: &CStr, argv: &[Option<&u8>], envp: &[Option<&u8>]) -> Result<(), Errno> {
1175    let path_ptr = path.as_ptr();
1176    let argv_ptr = argv.as_ptr() as *const *const c_char;
1177    let envp_ptr = envp.as_ptr() as *const *const c_char;
1178    Errno::result(unsafe { libc::execvpe(path_ptr, argv_ptr, envp_ptr) }).map(drop)
1179}
1180
1181pub fn _exit(status: ExitCode) -> ! {
1182    unsafe { libc::_exit(status.0) };
1183}
1184
1185pub fn fcntl_setfl(fd: &impl AsFd, flags: OpenFlags) -> Result<(), Errno> {
1186    let fd = fd.fd();
1187    Errno::result(unsafe { libc::fcntl(fd.0, libc::F_SETFL, flags.0) }).map(drop)
1188}
1189
1190pub fn fcntl_getpipe_sz(fd: &impl AsFd) -> Result<usize, Errno> {
1191    let fd = fd.fd();
1192    Errno::result(unsafe { libc::fcntl(fd.0, libc::F_GETPIPE_SZ) }).map(|sz| sz as usize)
1193}
1194
1195pub fn fcntl_setpipe_sz(fd: &impl AsFd, size: usize) -> Result<(), Errno> {
1196    let fd = fd.fd();
1197    Errno::result(unsafe { libc::fcntl(fd.0, libc::F_SETPIPE_SZ, i32::try_from(size).unwrap()) })
1198        .map(drop)
1199}
1200
1201pub fn fork() -> Result<Option<Pid>, Errno> {
1202    Errno::result(unsafe { libc::fork() }).map(|p| (p != 0).then_some(Pid(p)))
1203}
1204
1205pub struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t);
1206
1207impl Default for PosixSpawnFileActions {
1208    fn default() -> Self {
1209        Self::new()
1210    }
1211}
1212
1213impl PosixSpawnFileActions {
1214    pub fn new() -> Self {
1215        let mut inner: libc::posix_spawn_file_actions_t = unsafe { mem::zeroed() };
1216        Errno::result(unsafe { libc::posix_spawn_file_actions_init(&mut inner) }).unwrap();
1217        Self(inner)
1218    }
1219
1220    pub fn add_dup2(&mut self, from: &impl AsFd, to: &impl AsFd) -> Result<(), Errno> {
1221        Errno::result(unsafe {
1222            libc::posix_spawn_file_actions_adddup2(&mut self.0, from.fd().0, to.fd().0)
1223        })?;
1224        Ok(())
1225    }
1226}
1227
1228impl Drop for PosixSpawnFileActions {
1229    fn drop(&mut self) {
1230        Errno::result(unsafe { libc::posix_spawn_file_actions_destroy(&mut self.0) }).unwrap();
1231    }
1232}
1233
1234pub struct PosixSpawnAttrs(libc::posix_spawnattr_t);
1235
1236impl Default for PosixSpawnAttrs {
1237    fn default() -> Self {
1238        Self::new()
1239    }
1240}
1241
1242impl PosixSpawnAttrs {
1243    pub fn new() -> Self {
1244        let mut inner: libc::posix_spawnattr_t = unsafe { mem::zeroed() };
1245        Errno::result(unsafe { libc::posix_spawnattr_init(&mut inner) }).unwrap();
1246        Self(inner)
1247    }
1248}
1249
1250impl Drop for PosixSpawnAttrs {
1251    fn drop(&mut self) {
1252        Errno::result(unsafe { libc::posix_spawnattr_destroy(&mut self.0) }).unwrap();
1253    }
1254}
1255
1256pub fn posix_spawn(
1257    path: &CStr,
1258    file_actions: &PosixSpawnFileActions,
1259    attrs: &PosixSpawnAttrs,
1260    argv: &[Option<&u8>],
1261    envp: &[Option<&u8>],
1262) -> Result<Pid, Errno> {
1263    let mut pid = Pid(0);
1264    let path_ptr = path.as_ptr();
1265    let argv_ptr = argv.as_ptr() as *const *mut c_char;
1266    let envp_ptr = envp.as_ptr() as *const *mut c_char;
1267    Errno::result(unsafe {
1268        libc::posix_spawn(
1269            &mut pid.0,
1270            path_ptr,
1271            &file_actions.0,
1272            &attrs.0,
1273            argv_ptr,
1274            envp_ptr,
1275        )
1276    })?;
1277
1278    Ok(pid)
1279}
1280
1281pub fn fsconfig(
1282    fd: &impl AsFd,
1283    command: FsconfigCommand,
1284    key: Option<&CStr>,
1285    value: Option<&u8>,
1286    aux: Option<i32>,
1287) -> Result<(), Errno> {
1288    let fd = fd.fd();
1289    let key_ptr = key.map(|key| key.as_ptr()).unwrap_or(ptr::null());
1290    let value_ptr = value.map(|value| value as *const u8).unwrap_or(ptr::null());
1291    let aux = aux.unwrap_or(0);
1292    Errno::result(unsafe {
1293        libc::syscall(libc::SYS_fsconfig, fd.0, command.0, key_ptr, value_ptr, aux)
1294    })
1295    .map(drop)
1296}
1297
1298pub fn fsmount(
1299    fsfd: &impl AsFd,
1300    flags: FsmountFlags,
1301    mount_attrs: MountAttrs,
1302) -> Result<OwnedFd, Errno> {
1303    let fsfd = fsfd.fd();
1304    Errno::result(unsafe { libc::syscall(libc::SYS_fsmount, fsfd.0, flags.0, mount_attrs.0) })
1305        .map(Fd::from_c_long)
1306        .map(OwnedFd)
1307}
1308
1309pub fn fsopen(fsname: &CStr, flags: FsopenFlags) -> Result<OwnedFd, Errno> {
1310    let fsname_ptr = fsname.as_ptr();
1311    Errno::result(unsafe { libc::syscall(libc::SYS_fsopen, fsname_ptr, flags.0) })
1312        .map(Fd::from_c_long)
1313        .map(OwnedFd)
1314}
1315
1316pub fn getgid() -> Gid {
1317    Gid(unsafe { libc::getgid() })
1318}
1319
1320pub fn getpid() -> Pid {
1321    Pid(unsafe { libc::getpid() })
1322}
1323
1324pub fn getrlimit(resource: RlimitResource) -> Result<Rlimit, Errno> {
1325    let mut rlimit: libc::rlimit = unsafe { mem::zeroed() };
1326    Errno::result(unsafe { libc::getrlimit(resource as u32, &mut rlimit) })?;
1327    Ok(Rlimit {
1328        current: rlimit.rlim_cur,
1329        max: rlimit.rlim_max,
1330    })
1331}
1332
1333pub fn getsockname(fd: &impl AsFd) -> Result<SockaddrStorage, Errno> {
1334    let fd = fd.fd();
1335    let mut sockaddr = SockaddrStorage::default();
1336    let (addr_ptr, len_ptr) = unsafe { sockaddr.as_mut_parts() };
1337    Errno::result(unsafe { libc::getsockname(fd.0, addr_ptr, len_ptr) })?;
1338    Ok(sockaddr)
1339}
1340
1341pub fn getuid() -> Uid {
1342    Uid(unsafe { libc::getuid() })
1343}
1344
1345pub fn grantpt(fd: &impl AsFd) -> Result<(), Errno> {
1346    let fd = fd.fd();
1347    Errno::result(unsafe { libc::grantpt(fd.0) }).map(drop)
1348}
1349
1350pub fn ioctl_tiocsctty(fd: &impl AsFd, arg: i32) -> Result<(), Errno> {
1351    let fd = fd.fd();
1352    Errno::result(unsafe { libc::ioctl(fd.0, libc::TIOCSCTTY, arg as c_int) }).map(drop)
1353}
1354
1355pub fn ioctl_tiocgwinsz(fd: &impl AsFd) -> Result<(u16, u16), Errno> {
1356    let fd = fd.fd();
1357    let mut winsize: libc::winsize = unsafe { mem::zeroed() };
1358    Errno::result(unsafe { libc::ioctl(fd.0, libc::TIOCGWINSZ, &mut winsize) }).map(drop)?;
1359    Ok((winsize.ws_row, winsize.ws_col))
1360}
1361
1362pub fn ioctl_tiocswinsz(fd: &impl AsFd, rows: u16, columns: u16) -> Result<(), Errno> {
1363    let fd = fd.fd();
1364    let winsize = libc::winsize {
1365        ws_row: rows,
1366        ws_col: columns,
1367        ws_xpixel: 0,
1368        ws_ypixel: 0,
1369    };
1370    Errno::result(unsafe { libc::ioctl(fd.0, libc::TIOCSWINSZ, &winsize) }).map(drop)
1371}
1372
1373pub fn kill(pid: Pid, signal: Signal) -> Result<(), Errno> {
1374    Errno::result(unsafe { libc::kill(pid.0, signal.0) }).map(drop)
1375}
1376
1377pub fn listen(fd: &impl AsFd, backlog: u32) -> Result<(), Errno> {
1378    let fd = fd.fd();
1379    Errno::result(unsafe { libc::listen(fd.0, backlog as c_int) }).map(drop)
1380}
1381
1382pub fn lseek(fd: &impl AsFd, offset: i64, whence: Whence) -> Result<i64, Errno> {
1383    let fd = fd.fd();
1384    Errno::result(unsafe { libc::lseek(fd.0, offset, whence.as_i32()) })
1385}
1386
1387pub fn mkdir(path: &CStr, mode: FileMode) -> Result<(), Errno> {
1388    let path_ptr = path.as_ptr();
1389    Errno::result(unsafe { libc::mkdir(path_ptr, mode.0) }).map(drop)
1390}
1391
1392// N.B. From the man page description I don't think the kernel actually dereferences the pointer, so we
1393// don't have to worry about marking this function "unsafe".
1394//
1395// TODO: We should return some type which will provides a safe way to get a reference and will call
1396// `unmap` for us when it is dropped.
1397#[allow(clippy::not_unsafe_ptr_arg_deref)]
1398pub fn mmap(
1399    addr: *mut c_void,
1400    len: usize,
1401    prot: MemoryProtection,
1402    flags: MapFlags,
1403    fd: Option<Fd>,
1404    offset: i64,
1405) -> Result<*mut c_void, Errno> {
1406    Errno::result(unsafe {
1407        libc::mmap(
1408            addr,
1409            len,
1410            prot.0,
1411            flags.0,
1412            fd.map(|fd| fd.0).unwrap_or(0),
1413            offset,
1414        )
1415    })
1416}
1417
1418pub fn mount(
1419    source: Option<&CStr>,
1420    target: &CStr,
1421    fstype: Option<&CStr>,
1422    flags: MountFlags,
1423    data: Option<&[u8]>,
1424) -> Result<(), Errno> {
1425    let source_ptr = source.map(CStr::as_ptr).unwrap_or(ptr::null());
1426    let target_ptr = target.as_ptr();
1427    let fstype_ptr = fstype.map(CStr::as_ptr).unwrap_or(ptr::null());
1428    let data_ptr = data.map(|r| r.as_ptr()).unwrap_or(ptr::null()) as *const c_void;
1429    Errno::result(unsafe { libc::mount(source_ptr, target_ptr, fstype_ptr, flags.0, data_ptr) })
1430        .map(drop)
1431}
1432
1433pub fn move_mount(
1434    from_dirfd: &impl AsFd,
1435    from_path: &CStr,
1436    to_dirfd: &impl AsFd,
1437    to_path: &CStr,
1438    flags: MoveMountFlags,
1439) -> Result<(), Errno> {
1440    let from_dirfd = from_dirfd.fd();
1441    let to_dirfd = to_dirfd.fd();
1442    let from_path_ptr = from_path.as_ptr();
1443    let to_path_ptr = to_path.as_ptr();
1444    Errno::result(unsafe {
1445        libc::syscall(
1446            libc::SYS_move_mount,
1447            from_dirfd.0,
1448            from_path_ptr,
1449            to_dirfd.0,
1450            to_path_ptr,
1451            flags.0,
1452        )
1453    })
1454    .map(drop)
1455}
1456
1457pub fn open(path: &CStr, flags: OpenFlags, mode: FileMode) -> Result<OwnedFd, Errno> {
1458    let path_ptr = path.as_ptr();
1459    let fd = Errno::result(unsafe { libc::open(path_ptr, flags.0, mode.0) })
1460        .map(Fd)
1461        .map(OwnedFd)?;
1462    Ok(fd)
1463}
1464
1465pub fn open_tree(dirfd: &impl AsFd, path: &CStr, flags: OpenTreeFlags) -> Result<OwnedFd, Errno> {
1466    let dirfd = dirfd.fd();
1467    let path_ptr = path.as_ptr();
1468    Errno::result(unsafe { libc::syscall(libc::SYS_open_tree, dirfd.0, path_ptr, flags.0) })
1469        .map(Fd::from_c_long)
1470        .map(OwnedFd)
1471}
1472
1473pub fn pause() {
1474    unsafe { libc::pause() };
1475}
1476
1477pub fn pidfd_open(pid: Pid) -> Result<OwnedFd, Errno> {
1478    let flags = 0 as c_uint;
1479    Errno::result(unsafe { libc::syscall(libc::SYS_pidfd_open, pid.0, flags) })
1480        .map(Fd::from_c_long)
1481        .map(OwnedFd)
1482}
1483
1484pub fn pidfd_send_signal(pidfd: &impl AsFd, signal: Signal) -> Result<(), Errno> {
1485    let pidfd = pidfd.fd();
1486    let info: *const siginfo_t = ptr::null();
1487    let flags = 0 as c_uint;
1488    Errno::result(unsafe {
1489        libc::syscall(libc::SYS_pidfd_send_signal, pidfd.0, signal.0, info, flags)
1490    })
1491    .map(drop)
1492}
1493
1494pub fn pipe() -> Result<(OwnedFd, OwnedFd), Errno> {
1495    let mut fds: [c_int; 2] = [0; 2];
1496    let fds_ptr = fds.as_mut_ptr() as *mut c_int;
1497    Errno::result(unsafe { libc::pipe(fds_ptr) })
1498        .map(|_| (OwnedFd(Fd(fds[0])), OwnedFd(Fd(fds[1]))))
1499}
1500
1501pub fn pivot_root(new_root: &CStr, put_old: &CStr) -> Result<(), Errno> {
1502    let new_root_ptr = new_root.as_ptr();
1503    let put_old_ptr = put_old.as_ptr();
1504    Errno::result(unsafe { libc::syscall(libc::SYS_pivot_root, new_root_ptr, put_old_ptr) })
1505        .map(drop)
1506}
1507
1508pub fn poll(fds: &mut [PollFd], timeout: Duration) -> Result<usize, Errno> {
1509    let fds_ptr = fds.as_mut_ptr() as *mut pollfd;
1510    let nfds = fds.len() as nfds_t;
1511    let timeout = c_int::try_from(timeout.as_millis()).unwrap();
1512    Errno::result(unsafe { libc::poll(fds_ptr, nfds, timeout) }).map(|ret| ret as usize)
1513}
1514
1515pub fn posix_openpt(flags: OpenFlags) -> Result<OwnedFd, Errno> {
1516    let fd = Errno::result(unsafe { libc::posix_openpt(flags.0) })
1517        .map(Fd)
1518        .map(OwnedFd)?;
1519    Ok(fd)
1520}
1521
1522pub fn prctl_set_pdeathsig(signal: Signal) -> Result<(), Errno> {
1523    let signal = signal.as_c_ulong();
1524    Errno::result(unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, signal) }).map(drop)
1525}
1526
1527pub fn pthread_sigmask(how: SigprocmaskHow, set: Option<&SignalSet>) -> Result<SignalSet, Errno> {
1528    let set: *const sigset_t = set.map(|s| &s.0 as *const sigset_t).unwrap_or(ptr::null());
1529    let mut oldset: MaybeUninit<sigset_t> = MaybeUninit::uninit();
1530    Errno::result(unsafe { libc::pthread_sigmask(how.0, set, oldset.as_mut_ptr()) })?;
1531    Ok(SignalSet(unsafe { oldset.assume_init() }))
1532}
1533
1534pub fn ptsname(fd: &impl AsFd, name: &mut [u8]) -> Result<(), Errno> {
1535    let fd = fd.fd();
1536    let buf_ptr = name.as_mut_ptr() as *mut c_char;
1537    let buf_len = name.len();
1538    Errno::result(unsafe { libc::ptsname_r(fd.0, buf_ptr, buf_len) }).map(drop)
1539}
1540
1541pub fn raise(signal: Signal) -> Result<(), Errno> {
1542    Errno::result(unsafe { libc::raise(signal.0) }).map(drop)
1543}
1544
1545pub fn read(fd: &impl AsFd, buf: &mut [u8]) -> Result<usize, Errno> {
1546    let fd = fd.fd();
1547    let buf_ptr = buf.as_mut_ptr() as *mut c_void;
1548    let buf_len = buf.len();
1549    Errno::result(unsafe { libc::read(fd.0, buf_ptr, buf_len) }).map(|ret| ret as usize)
1550}
1551
1552pub fn setsid() -> Result<(), Errno> {
1553    Errno::result(unsafe { libc::setsid() }).map(drop)
1554}
1555
1556pub fn setsockopt_so_keepalive(sock: &impl AsFd, value: bool) -> Result<(), Errno> {
1557    setsockopt_u32(sock, libc::SOL_SOCKET, libc::SO_KEEPALIVE, value as u32)
1558}
1559
1560pub fn setsockopt_tcp_nodelay(sock: &impl AsFd, value: bool) -> Result<(), Errno> {
1561    setsockopt_u32(sock, libc::IPPROTO_TCP, libc::TCP_NODELAY, value as u32)
1562}
1563
1564pub fn setsockopt_tcp_keepcnt(sock: &impl AsFd, value: u32) -> Result<(), Errno> {
1565    setsockopt_u32(sock, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, value)
1566}
1567
1568pub fn setsockopt_tcp_keepidle(sock: &impl AsFd, value: u32) -> Result<(), Errno> {
1569    setsockopt_u32(sock, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, value)
1570}
1571
1572pub fn setsockopt_tcp_keepintvl(sock: &impl AsFd, value: u32) -> Result<(), Errno> {
1573    setsockopt_u32(sock, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, value)
1574}
1575
1576fn setsockopt_u32(sock: &impl AsFd, level: c_int, name: c_int, value: u32) -> Result<(), Errno> {
1577    let fd = sock.fd();
1578    let value = value as c_int;
1579    let value_ptr: *const c_int = &value;
1580    let value_len = mem::size_of::<c_int>() as socklen_t;
1581    Errno::result(unsafe {
1582        libc::setsockopt(fd.0, level, name, value_ptr as *const c_void, value_len)
1583    })
1584    .map(drop)
1585}
1586
1587pub fn signal(signal: Signal, handler: Sighandler) -> Sighandler {
1588    Sighandler(unsafe { libc::signal(signal.0, handler.0) })
1589}
1590
1591pub fn sigprocmask(how: SigprocmaskHow, set: Option<&SignalSet>) -> Result<SignalSet, Errno> {
1592    let set: *const sigset_t = set.map(|s| &s.0 as *const sigset_t).unwrap_or(ptr::null());
1593    let mut oldset: MaybeUninit<sigset_t> = MaybeUninit::uninit();
1594    Errno::result(unsafe { libc::sigprocmask(how.0, set, oldset.as_mut_ptr()) })?;
1595    Ok(SignalSet(unsafe { oldset.assume_init() }))
1596}
1597
1598pub fn sigwait(blocked_signals: &SignalSet) -> Result<Signal, Errno> {
1599    let mut signal = Signal::default();
1600    Errno::result(unsafe { libc::sigwait(&blocked_signals.0, &mut signal.0) })?;
1601    Ok(signal)
1602}
1603
1604pub fn socket(
1605    domain: SocketDomain,
1606    type_: SocketType,
1607    protocol: SocketProtocol,
1608) -> Result<OwnedFd, Errno> {
1609    Errno::result(unsafe { libc::socket(domain.0, type_.0, protocol.0) })
1610        .map(Fd)
1611        .map(OwnedFd)
1612}
1613
1614pub fn umount2(path: &CStr, flags: UmountFlags) -> Result<(), Errno> {
1615    let path_ptr = path.as_ptr();
1616    Errno::result(unsafe { libc::umount2(path_ptr, flags.0) }).map(drop)
1617}
1618
1619pub fn unlockpt(fd: &impl AsFd) -> Result<(), Errno> {
1620    let fd = fd.fd();
1621    Errno::result(unsafe { libc::unlockpt(fd.0) }).map(drop)
1622}
1623
1624fn extract_wait_status(status: c_int) -> WaitStatus {
1625    if libc::WIFEXITED(status) {
1626        WaitStatus::Exited(ExitCode(libc::WEXITSTATUS(status)))
1627    } else if libc::WIFSIGNALED(status) {
1628        WaitStatus::Signaled(Signal(libc::WTERMSIG(status)))
1629    } else {
1630        panic!("neither WIFEXITED nor WIFSIGNALED true on wait status {status}");
1631    }
1632}
1633
1634fn extract_wait_status_from_siginfo(siginfo: siginfo_t) -> WaitStatus {
1635    let status = unsafe { siginfo.si_status() };
1636    match siginfo.si_code {
1637        libc::CLD_EXITED => WaitStatus::Exited(ExitCode(status)),
1638        libc::CLD_KILLED | libc::CLD_DUMPED => WaitStatus::Signaled(Signal(status)),
1639        code => panic!("siginfo's si_code was {code} instead of CLD_EXITED or CLD_KILLED"),
1640    }
1641}
1642
1643pub fn wait() -> Result<WaitResult, Errno> {
1644    let inner = |status: &mut c_int| {
1645        let status_ptr = status as *mut c_int;
1646        unsafe { libc::wait(status_ptr) }
1647    };
1648    let mut status = 0;
1649    Errno::result(inner(&mut status)).map(|pid| WaitResult {
1650        pid: Pid(pid),
1651        status: extract_wait_status(status),
1652    })
1653}
1654
1655pub fn waitpid(pid: Pid) -> Result<WaitStatus, Errno> {
1656    let inner = |status: &mut c_int| {
1657        let status_ptr = status as *mut c_int;
1658        let flags = 0 as c_int;
1659        unsafe { libc::waitpid(pid.0, status_ptr, flags) }
1660    };
1661    let mut status = 0;
1662    Errno::result(inner(&mut status)).map(|_| extract_wait_status(status))
1663}
1664
1665pub fn waitid(pidfd: &impl AsFd) -> Result<WaitStatus, Errno> {
1666    let pidfd = pidfd.fd();
1667    let inner = |siginfo: &mut siginfo_t| {
1668        let idtype = libc::P_PIDFD as idtype_t;
1669        let id = pidfd.0 as id_t;
1670        let siginfo_ptr = siginfo as *mut siginfo_t;
1671        let options = libc::WEXITED;
1672        unsafe { libc::waitid(idtype, id, siginfo_ptr, options) }
1673    };
1674    let mut siginfo = unsafe { mem::zeroed() };
1675    Errno::result(inner(&mut siginfo)).map(|_| extract_wait_status_from_siginfo(siginfo))
1676}
1677
1678pub fn write(fd: &impl AsFd, buf: &[u8]) -> Result<usize, Errno> {
1679    let fd = fd.fd();
1680    let buf_ptr = buf.as_ptr() as *const c_void;
1681    let buf_len = buf.len();
1682    Errno::result(unsafe { libc::write(fd.0, buf_ptr, buf_len) }).map(|ret| ret as usize)
1683}
1684
1685fn with_iovec<RetT>(buffer: &[u8], body: impl FnOnce(&libc::iovec) -> RetT) -> RetT {
1686    let io_vec = libc::iovec {
1687        iov_base: buffer.as_ptr() as *mut libc::c_void,
1688        iov_len: buffer.len(),
1689    };
1690    body(&io_vec)
1691}
1692
1693fn with_iovec_mut<RetT>(buffer: &mut [u8], body: impl FnOnce(&mut libc::iovec) -> RetT) -> RetT {
1694    let mut io_vec = libc::iovec {
1695        iov_base: buffer.as_mut_ptr() as *mut libc::c_void,
1696        iov_len: buffer.len(),
1697    };
1698    body(&mut io_vec)
1699}
1700
1701// prepare message with enough cmsg space for a file descriptor
1702const CMSG_BUFFER_LEN: c_uint = unsafe { libc::CMSG_SPACE(mem::size_of::<c_int>() as c_uint) };
1703
1704fn with_msghdr<RetT>(buffer: &[u8], body: impl FnOnce(&mut libc::msghdr) -> RetT) -> RetT {
1705    let mut cmsg_buffer = [0u8; CMSG_BUFFER_LEN as usize];
1706
1707    with_iovec(buffer, |io_vec| {
1708        let mut message = libc::msghdr {
1709            msg_name: ptr::null_mut(),
1710            msg_namelen: 0,
1711            msg_iov: io_vec as *const _ as *mut _,
1712            msg_iovlen: 1,
1713            msg_control: cmsg_buffer.as_mut_ptr() as *mut libc::c_void,
1714            msg_controllen: cmsg_buffer.len(),
1715            msg_flags: 0,
1716        };
1717        body(&mut message)
1718    })
1719}
1720
1721fn with_msghdr_mut<RetT>(buffer: &mut [u8], body: impl FnOnce(&mut libc::msghdr) -> RetT) -> RetT {
1722    let mut cmsg_buffer = [0u8; CMSG_BUFFER_LEN as usize];
1723
1724    with_iovec_mut(buffer, |io_vec| {
1725        let mut message = libc::msghdr {
1726            msg_name: ptr::null_mut(),
1727            msg_namelen: 0,
1728            msg_iov: io_vec,
1729            msg_iovlen: 1,
1730            msg_control: cmsg_buffer.as_mut_ptr() as *mut libc::c_void,
1731            msg_controllen: cmsg_buffer.len(),
1732            msg_flags: 0,
1733        };
1734        body(&mut message)
1735    })
1736}
1737
1738pub struct UnixStream {
1739    fd: OwnedFd,
1740}
1741
1742#[cfg(any(test, feature = "std"))]
1743impl fd::AsRawFd for UnixStream {
1744    fn as_raw_fd(&self) -> fd::RawFd {
1745        self.fd.as_raw_fd()
1746    }
1747}
1748
1749impl From<OwnedFd> for UnixStream {
1750    fn from(fd: OwnedFd) -> Self {
1751        Self { fd }
1752    }
1753}
1754
1755impl UnixStream {
1756    pub fn pair() -> Result<(Self, Self), Errno> {
1757        let mut fds = [0, 0];
1758
1759        Errno::result(unsafe {
1760            libc::socketpair(
1761                libc::AF_UNIX,
1762                libc::SOCK_STREAM | libc::SOCK_CLOEXEC,
1763                0,
1764                fds.as_mut_ptr(),
1765            )
1766        })?;
1767
1768        Ok((
1769            OwnedFd::from_fd(Fd(fds[0])).into(),
1770            OwnedFd::from_fd(Fd(fds[1])).into(),
1771        ))
1772    }
1773
1774    pub fn as_fd(&self) -> Fd {
1775        self.fd.as_fd()
1776    }
1777
1778    pub fn recv_with_fd(&self, buffer: &mut [u8]) -> Result<(usize, Option<OwnedFd>), Errno> {
1779        with_msghdr_mut(buffer, |message| {
1780            let count = Errno::result(unsafe {
1781                libc::recvmsg(self.fd.as_fd().0, message, 0 /* flags */)
1782            })? as usize;
1783
1784            assert_eq!(message.msg_flags & libc::MSG_TRUNC, 0);
1785
1786            // I have deduced that when we have too many files open, this is what happens
1787            if message.msg_flags & libc::MSG_CTRUNC != 0 {
1788                return Err(Errno::EMFILE);
1789            }
1790
1791            // See if we got a file descriptor, only checking the first message
1792            let mut fd_out = None;
1793            let control_msg = unsafe { libc::CMSG_FIRSTHDR(message) };
1794            if !control_msg.is_null() && unsafe { (*control_msg).cmsg_type == libc::SCM_RIGHTS } {
1795                let fd_data = unsafe { libc::CMSG_DATA(control_msg) };
1796
1797                let fd = unsafe { *(fd_data as *const c_int) };
1798                fd_out = Some(OwnedFd(Fd(fd)));
1799            }
1800
1801            Ok((count, fd_out))
1802        })
1803    }
1804
1805    pub fn send(&self, buffer: &[u8]) -> Result<usize, Errno> {
1806        Ok(Errno::result(unsafe {
1807            libc::send(
1808                self.fd.as_fd().0,
1809                buffer.as_ptr() as *const c_void,
1810                buffer.len(),
1811                0, /* flags */
1812            )
1813        })? as usize)
1814    }
1815
1816    pub fn send_with_fd(&self, buffer: &[u8], fd: Fd) -> Result<usize, Errno> {
1817        with_msghdr(buffer, |message| {
1818            let control_msg = unsafe { &mut *libc::CMSG_FIRSTHDR(message) };
1819            control_msg.cmsg_level = libc::SOL_SOCKET;
1820            control_msg.cmsg_type = libc::SCM_RIGHTS;
1821            control_msg.cmsg_len =
1822                unsafe { libc::CMSG_LEN(mem::size_of::<c_int>() as libc::c_uint) } as libc::size_t;
1823
1824            let fd_data = unsafe { &mut *(libc::CMSG_DATA(control_msg) as *mut c_int) };
1825            *fd_data = fd.0;
1826
1827            Ok(Errno::result(unsafe { libc::sendmsg(self.fd.as_fd().0, message, 0) })? as usize)
1828        })
1829    }
1830
1831    pub fn shutdown(&self) -> Result<(), Errno> {
1832        Errno::result(unsafe { libc::shutdown(self.fd.as_fd().0, libc::SHUT_RDWR) }).map(drop)
1833    }
1834}
1835
1836pub fn splice(
1837    fd_in: &impl AsFd,
1838    off_in: Option<u64>,
1839    fd_out: &impl AsFd,
1840    off_out: Option<u64>,
1841    length: usize,
1842) -> Result<usize, Errno> {
1843    let fd_in = fd_in.fd();
1844    let fd_out = fd_out.fd();
1845    let off_in = off_in.map(|v| i64::try_from(v).unwrap());
1846    let off_out = off_out.map(|v| i64::try_from(v).unwrap());
1847
1848    let inner = |off_in: &Option<i64>, off_out: &Option<i64>| {
1849        let off_in = off_in
1850            .as_ref()
1851            .map(|v| v as *const i64 as *mut _)
1852            .unwrap_or(core::ptr::null_mut());
1853        let off_out = off_out
1854            .as_ref()
1855            .map(|v| v as *const i64 as *mut _)
1856            .unwrap_or(core::ptr::null_mut());
1857        Ok(
1858            Errno::result(unsafe { libc::splice(fd_in.0, off_in, fd_out.0, off_out, length, 0) })?
1859                as usize,
1860        )
1861    };
1862    inner(&off_in, &off_out)
1863}
1864
1865#[cfg(test)]
1866mod tests {
1867    use super::*;
1868
1869    #[test]
1870    fn signal_display() {
1871        assert_eq!(std::format!("{}", Signal::CHLD).as_str(), "SIGCHLD");
1872    }
1873
1874    #[test]
1875    fn invalid_signal_display() {
1876        assert_eq!(
1877            std::format!("{}", Signal(1234)).as_str(),
1878            "Invalid Signal 1234",
1879        );
1880    }
1881
1882    #[test]
1883    fn pid_display() {
1884        assert_eq!(std::format!("{}", Pid(1234)).as_str(), "1234");
1885    }
1886
1887    #[test]
1888    fn uid_display() {
1889        assert_eq!(std::format!("{}", Uid(1234)).as_str(), "1234");
1890    }
1891
1892    #[test]
1893    fn gid_display() {
1894        assert_eq!(std::format!("{}", Gid(1234)).as_str(), "1234");
1895    }
1896
1897    #[test]
1898    fn errno_display() {
1899        assert_eq!(
1900            std::format!("{}", Errno(libc::EPERM)).as_str(),
1901            "EPERM: Operation not permitted"
1902        );
1903    }
1904
1905    #[test]
1906    fn invalid_errno_display() {
1907        assert_eq!(
1908            std::format!("{}", Errno(1234)).as_str(),
1909            "1234: Unknown error"
1910        );
1911    }
1912
1913    #[test]
1914    fn errno_debug() {
1915        assert_eq!(std::format!("{:?}", Errno(libc::EPERM)).as_str(), "EPERM");
1916    }
1917
1918    #[test]
1919    fn invalid_errno_debug() {
1920        assert_eq!(std::format!("{:?}", Errno(1234)).as_str(), "UNKNOWN(1234)");
1921    }
1922
1923    #[test]
1924    fn unix_stream_send_recv() {
1925        let (a, b) = UnixStream::pair().unwrap();
1926
1927        let count = a.send(b"abcdefg").unwrap();
1928        assert_eq!(count, 7);
1929
1930        let mut buf = [0; 7];
1931        let (count, fd) = b.recv_with_fd(&mut buf).unwrap();
1932        assert_eq!(count, 7);
1933        assert_eq!(&buf, b"abcdefg");
1934        assert!(fd.is_none());
1935    }
1936
1937    #[test]
1938    fn unix_stream_send_recv_with_fd() {
1939        let (a1, a2) = UnixStream::pair().unwrap();
1940
1941        if clone3(&mut CloneArgs::default()).unwrap().is_none() {
1942            let (b1, b2) = UnixStream::pair().unwrap();
1943            a2.send_with_fd(b"boop", b1.as_fd()).unwrap();
1944            b2.send(b"bop").unwrap();
1945            return;
1946        }
1947
1948        let mut buf = [0; 4];
1949        let (count, fd) = a1.recv_with_fd(&mut buf).unwrap();
1950        assert_eq!(count, 4);
1951        assert_eq!(&buf, b"boop");
1952
1953        let b1 = UnixStream::from(fd.unwrap());
1954        let mut buf = [0; 3];
1955        let (count, fd) = b1.recv_with_fd(&mut buf).unwrap();
1956        assert_eq!(count, 3);
1957        assert_eq!(&buf, b"bop");
1958        assert!(fd.is_none());
1959    }
1960
1961    #[test]
1962    fn unix_stream_send_message_without_then_with_fd() {
1963        let (a1, a2) = UnixStream::pair().unwrap();
1964
1965        if clone3(&mut CloneArgs::default()).unwrap().is_none() {
1966            let (b1, b2) = UnixStream::pair().unwrap();
1967            a2.send(b"boop").unwrap();
1968            a2.send_with_fd(b"bing", b1.as_fd()).unwrap();
1969            b2.send(b"bop").unwrap();
1970            return;
1971        }
1972
1973        let mut buf = [0; 4];
1974        let (count, fd) = a1.recv_with_fd(&mut buf).unwrap();
1975        assert_eq!(count, 4);
1976        assert_eq!(&buf, b"boop");
1977        assert!(fd.is_none());
1978
1979        let mut buf = [0; 4];
1980        let (count, fd) = a1.recv_with_fd(&mut buf).unwrap();
1981        assert_eq!(count, 4);
1982        assert_eq!(&buf, b"bing");
1983
1984        let b1 = UnixStream::from(fd.unwrap());
1985        let mut buf = [0; 3];
1986        let (count, fd) = b1.recv_with_fd(&mut buf).unwrap();
1987        assert_eq!(count, 3);
1988        assert_eq!(&buf, b"bop");
1989        assert!(fd.is_none());
1990    }
1991
1992    #[test]
1993    fn sockaddr_len() {
1994        let mut sa: sockaddr = unsafe { mem::zeroed() };
1995        sa.sa_family = libc::AF_UNIX as sa_family_t;
1996        let sa2 = unsafe { Sockaddr::from_raw_parts(&sa, mem::size_of::<sockaddr>()) };
1997        assert_eq!(mem::size_of::<sockaddr>(), 16);
1998        assert_eq!(sa2.data.len(), 14);
1999        assert_eq!(sa2.family(), libc::AF_UNIX as sa_family_t);
2000        assert_eq!(sa2.len(), mem::size_of::<sockaddr>());
2001    }
2002}