1use crate::error::{Errno, Result};
4
5#[derive(Debug)]
7pub(crate) struct OwnedFd(libc::c_int);
8
9impl OwnedFd {
10 pub(crate) const fn new(fd: libc::c_int) -> Self {
11 Self(fd)
12 }
13
14 pub(crate) const fn as_raw(&self) -> libc::c_int {
15 self.0
16 }
17}
18
19impl Drop for OwnedFd {
20 fn drop(&mut self) {
21 if self.0 >= 0 {
22 unsafe {
23 libc::close(self.0);
24 }
25 }
26 }
27}
28
29#[derive(Clone, Copy, Debug, Eq, PartialEq)]
31pub enum FdAction {
32 Dup2 { src: libc::c_int, dst: libc::c_int },
33 Close(libc::c_int),
34}
35
36pub fn close(fd: libc::c_int) -> Result<()> {
41 let ret = unsafe { libc::close(fd) };
42 if ret == 0 { Ok(()) } else { Err(Errno::last()) }
43}
44
45pub fn dup2(src: libc::c_int, dst: libc::c_int) -> Result<()> {
47 loop {
48 let ret = unsafe { libc::dup2(src, dst) };
49 if ret >= 0 {
50 return Ok(());
51 }
52 let err = Errno::last();
53 if err.0 == libc::EINTR {
54 continue;
55 }
56 return Err(err);
57 }
58}
59
60pub fn apply_actions(actions: &[FdAction]) -> Result<()> {
62 for action in actions {
63 match *action {
64 FdAction::Dup2 { src, dst } if src != dst => dup2(src, dst)?,
65 FdAction::Dup2 { .. } => {}
66 FdAction::Close(fd) => close(fd)?,
67 }
68 }
69 Ok(())
70}
71
72pub fn close_other_fds(keep_sorted: &[libc::c_int], extra_keep: &[libc::c_int]) -> Result<()> {
78 let mut cursor = 3u32;
79
80 loop {
81 let next_keep = next_keep_fd(cursor, keep_sorted, extra_keep);
82 if next_keep == u32::MAX {
83 close_range(cursor, u32::MAX)?;
84 return Ok(());
85 }
86 if next_keep > cursor {
87 close_range(cursor, next_keep - 1)?;
88 }
89 cursor = next_keep.saturating_add(1);
90 }
91}
92
93fn next_keep_fd(cursor: u32, keep_sorted: &[libc::c_int], extra_keep: &[libc::c_int]) -> u32 {
94 let mut next = u32::MAX;
95
96 for &fd in keep_sorted {
98 let fd = fd as u32;
99 if fd >= cursor {
100 next = fd;
101 break;
102 }
103 }
104
105 for &fd in extra_keep {
106 if fd < 3 {
107 continue;
108 }
109 let fd = fd as u32;
110 if fd >= cursor && fd < next {
111 next = fd;
112 }
113 }
114
115 next
116}
117
118fn close_range(first: u32, last: u32) -> Result<()> {
119 if first > last {
120 return Ok(());
121 }
122
123 let ret = unsafe { libc::syscall(libc::SYS_close_range, first, last, 0u32) };
124 if ret == 0 { Ok(()) } else { Err(Errno::last()) }
125}