1use linux_syscall::{Result as LinuxSyscallResult, Result64};
2
3use crate::errno::Errno;
4use crate::ldt::linux_user_desc;
5use crate::posix_types::{Pid, kernel_pid_t};
6use crate::signal::Signal;
7use crate::{bindings, const_conversions};
8
9bitflags::bitflags! {
10 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
14 pub struct CloneFlags: u64 {
15 const CLONE_CLEAR_SIGHAND = bindings::LINUX_CLONE_CLEAR_SIGHAND;
16 const CLONE_INTO_CGROUP = bindings::LINUX_CLONE_INTO_CGROUP;
17 const CLONE_NEWTIME = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWTIME);
18 const CLONE_VM = const_conversions::u64_from_u32(bindings::LINUX_CLONE_VM);
19 const CLONE_FS = const_conversions::u64_from_u32(bindings::LINUX_CLONE_FS);
20 const CLONE_FILES = const_conversions::u64_from_u32(bindings::LINUX_CLONE_FILES);
21 const CLONE_SIGHAND = const_conversions::u64_from_u32(bindings::LINUX_CLONE_SIGHAND);
22 const CLONE_PIDFD = const_conversions::u64_from_u32(bindings::LINUX_CLONE_PIDFD);
23 const CLONE_PTRACE = const_conversions::u64_from_u32(bindings::LINUX_CLONE_PTRACE);
24 const CLONE_VFORK = const_conversions::u64_from_u32(bindings::LINUX_CLONE_VFORK);
25 const CLONE_PARENT = const_conversions::u64_from_u32(bindings::LINUX_CLONE_PARENT);
26 const CLONE_THREAD = const_conversions::u64_from_u32(bindings::LINUX_CLONE_THREAD);
27 const CLONE_NEWNS = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWNS);
28 const CLONE_SYSVSEM = const_conversions::u64_from_u32(bindings::LINUX_CLONE_SYSVSEM);
29 const CLONE_SETTLS = const_conversions::u64_from_u32(bindings::LINUX_CLONE_SETTLS);
30 const CLONE_PARENT_SETTID = const_conversions::u64_from_u32(bindings::LINUX_CLONE_PARENT_SETTID);
31 const CLONE_CHILD_CLEARTID = const_conversions::u64_from_u32(bindings::LINUX_CLONE_CHILD_CLEARTID);
32 const CLONE_DETACHED = const_conversions::u64_from_u32(bindings::LINUX_CLONE_DETACHED);
33 const CLONE_UNTRACED = const_conversions::u64_from_u32(bindings::LINUX_CLONE_UNTRACED);
34 const CLONE_CHILD_SETTID = const_conversions::u64_from_u32(bindings::LINUX_CLONE_CHILD_SETTID);
35 const CLONE_NEWCGROUP = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWCGROUP);
36 const CLONE_NEWUTS = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWUTS);
37 const CLONE_NEWIPC = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWIPC);
38 const CLONE_NEWUSER = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWUSER);
39 const CLONE_NEWPID = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWPID);
40 const CLONE_NEWNET = const_conversions::u64_from_u32(bindings::LINUX_CLONE_NEWNET);
41 const CLONE_IO = const_conversions::u64_from_u32(bindings::LINUX_CLONE_IO);
42 }
43}
44
45pub use bindings::linux_clone_args;
46#[allow(non_camel_case_types)]
47pub type clone_args = linux_clone_args;
48
49#[allow(clippy::derivable_impls)]
50impl Default for clone_args {
51 fn default() -> Self {
52 Self {
53 flags: Default::default(),
54 pidfd: Default::default(),
55 child_tid: Default::default(),
56 parent_tid: Default::default(),
57 exit_signal: Default::default(),
58 stack: Default::default(),
59 stack_size: Default::default(),
60 tls: Default::default(),
61 set_tid: Default::default(),
62 set_tid_size: Default::default(),
63 cgroup: Default::default(),
64 }
65 }
66}
67
68impl clone_args {
69 #[inline]
70 pub fn with_flags(mut self, flags: CloneFlags) -> Self {
71 self.flags = flags.bits();
72 self
73 }
74
75 #[inline]
76 pub fn with_exit_signal(mut self, exit_signal: Option<Signal>) -> Self {
77 self.exit_signal = u64::try_from(Signal::as_raw(exit_signal)).unwrap();
78 self
79 }
80}
81
82unsafe impl shadow_pod::Pod for clone_args {}
83
84#[derive(Copy, Clone, PartialEq, Eq)]
87pub struct SuidDump(i32);
88
89impl SuidDump {
90 pub const SUID_DUMP_DISABLE: Self = Self(const_conversions::i32_from_u32(
91 bindings::LINUX_SUID_DUMP_DISABLE,
92 ));
93 pub const SUID_DUMP_USER: Self = Self(const_conversions::i32_from_u32(
94 bindings::LINUX_SUID_DUMP_USER,
95 ));
96 pub const SUID_DUMP_ROOT: Self = Self(const_conversions::i32_from_u32(
97 bindings::LINUX_SUID_DUMP_ROOT,
98 ));
99 pub const fn new(val: i32) -> Self {
102 Self(val)
103 }
104
105 pub const fn val(&self) -> i32 {
106 self.0
107 }
108
109 pub const fn to_str(&self) -> Option<&'static str> {
110 match *self {
111 Self::SUID_DUMP_DISABLE => Some("SUID_DUMP_DISABLE"),
112 Self::SUID_DUMP_USER => Some("SUID_DUMP_USER"),
113 Self::SUID_DUMP_ROOT => Some("SUID_DUMP_ROOT"),
114 _ => None,
115 }
116 }
117}
118
119impl core::fmt::Display for SuidDump {
120 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
121 match self.to_str() {
122 Some(s) => formatter.write_str(s),
123 None => write!(formatter, "(unknown dumpable option {})", self.0),
124 }
125 }
126}
127
128impl core::fmt::Debug for SuidDump {
129 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
130 match self.to_str() {
131 Some(s) => write!(formatter, "SuidDump::{s}"),
132 None => write!(formatter, "SuidDump::<{}>", self.0),
133 }
134 }
135}
136
137pub fn sched_yield() -> Result<(), Errno> {
138 unsafe { linux_syscall::syscall!(linux_syscall::SYS_sched_yield) }
139 .check()
140 .map_err(Errno::from)
141}
142
143pub unsafe fn clone_raw(
147 flags: core::ffi::c_ulong,
148 stack: core::ffi::c_ulong,
149 parent_tid: *mut core::ffi::c_int,
150 child_tid: *mut core::ffi::c_int,
151 tls: core::ffi::c_ulong,
152) -> Result<core::ffi::c_long, Errno> {
153 unsafe {
154 linux_syscall::syscall!(
155 linux_syscall::SYS_clone,
156 flags,
157 stack,
158 parent_tid,
159 child_tid,
160 tls
161 )
162 }
163 .try_i64()
164 .map_err(Errno::from)
165}
166
167pub unsafe fn clone3_raw(args: *const clone_args, size: usize) -> Result<core::ffi::c_long, Errno> {
171 unsafe { linux_syscall::syscall!(linux_syscall::SYS_clone3, args, size,) }
172 .try_i64()
173 .map_err(Errno::from)
174}
175
176pub enum CloneResult {
177 CallerIsChild,
178 CallerIsParent(Pid),
180}
181
182pub unsafe fn clone(
186 flags: CloneFlags,
187 exit_signal: Option<Signal>,
188 stack: *mut core::ffi::c_void,
189 parent_tid: *mut kernel_pid_t,
190 child_tid: *mut kernel_pid_t,
191 tls: *mut linux_user_desc,
192) -> Result<CloneResult, Errno> {
193 unsafe {
194 clone_raw(
195 flags.bits() | u64::try_from(Signal::as_raw(exit_signal)).unwrap(),
196 stack as core::ffi::c_ulong,
197 parent_tid,
198 child_tid,
199 tls as core::ffi::c_ulong,
200 )
201 }
202 .map(|res| match res.cmp(&0) {
203 core::cmp::Ordering::Equal => CloneResult::CallerIsChild,
204 core::cmp::Ordering::Greater => {
205 CloneResult::CallerIsParent(Pid::from_raw(res.try_into().unwrap()).unwrap())
206 }
207 core::cmp::Ordering::Less => unreachable!(),
208 })
209}
210
211pub unsafe fn clone3(args: &clone_args) -> Result<CloneResult, Errno> {
215 unsafe { clone3_raw(args, core::mem::size_of::<clone_args>()) }.map(|res| match res.cmp(&0) {
216 core::cmp::Ordering::Equal => CloneResult::CallerIsChild,
217 core::cmp::Ordering::Greater => {
218 CloneResult::CallerIsParent(Pid::from_raw(res.try_into().unwrap()).unwrap())
219 }
220 core::cmp::Ordering::Less => unreachable!(),
221 })
222}
223
224pub unsafe fn fork_raw() -> Result<core::ffi::c_long, Errno> {
239 unsafe { linux_syscall::syscall!(linux_syscall::SYS_fork) }
240 .try_i64()
241 .map_err(Errno::from)
242}
243
244pub unsafe fn fork() -> Result<CloneResult, Errno> {
248 unsafe { fork_raw() }.map(|res| match res.cmp(&0) {
249 core::cmp::Ordering::Equal => CloneResult::CallerIsChild,
250 core::cmp::Ordering::Greater => {
251 CloneResult::CallerIsParent(Pid::from_raw(res.try_into().unwrap()).unwrap())
252 }
253 core::cmp::Ordering::Less => unreachable!(),
254 })
255}