1#![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#[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 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 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
237pub 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 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 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 #[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 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 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 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, 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 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
1013pub 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
1102pub 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
1124pub 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#[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
1701const 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 )
1782 })? as usize;
1783
1784 assert_eq!(message.msg_flags & libc::MSG_TRUNC, 0);
1785
1786 if message.msg_flags & libc::MSG_CTRUNC != 0 {
1788 return Err(Errno::EMFILE);
1789 }
1790
1791 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, )
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}