• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! libc syscalls supporting `rustix::process`.
2 
3 use super::super::c;
4 #[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))]
5 use super::super::conv::borrowed_fd;
6 #[cfg(not(target_os = "wasi"))]
7 use super::super::conv::ret_pid_t;
8 use super::super::conv::{c_str, ret, ret_c_int, ret_discarded_char_ptr};
9 #[cfg(any(target_os = "android", target_os = "linux"))]
10 use super::super::conv::{syscall_ret, syscall_ret_u32};
11 #[cfg(any(
12     target_os = "android",
13     target_os = "dragonfly",
14     target_os = "fuchsia",
15     target_os = "linux",
16 ))]
17 use super::types::RawCpuSet;
18 #[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))]
19 use crate::fd::BorrowedFd;
20 use crate::ffi::CStr;
21 use crate::io;
22 use core::mem::MaybeUninit;
23 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
24 use {
25     super::super::conv::ret_infallible,
26     super::super::offset::{libc_getrlimit, libc_rlimit, libc_setrlimit, LIBC_RLIM_INFINITY},
27     crate::process::{Resource, Rlimit},
28     core::convert::TryInto,
29 };
30 #[cfg(any(target_os = "android", target_os = "linux"))]
31 use {
32     super::super::offset::libc_prlimit,
33     crate::process::{Cpuid, MembarrierCommand, MembarrierQuery},
34 };
35 #[cfg(not(target_os = "wasi"))]
36 use {
37     super::types::RawUname,
38     crate::process::{Gid, Pid, RawNonZeroPid, RawPid, Signal, Uid, WaitOptions, WaitStatus},
39 };
40 
41 #[cfg(not(target_os = "wasi"))]
chdir(path: &CStr) -> io::Result<()>42 pub(crate) fn chdir(path: &CStr) -> io::Result<()> {
43     unsafe { ret(c::chdir(c_str(path))) }
44 }
45 
46 #[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))]
fchdir(dirfd: BorrowedFd<'_>) -> io::Result<()>47 pub(crate) fn fchdir(dirfd: BorrowedFd<'_>) -> io::Result<()> {
48     unsafe { ret(c::fchdir(borrowed_fd(dirfd))) }
49 }
50 
51 #[cfg(not(target_os = "wasi"))]
getcwd(buf: &mut [u8]) -> io::Result<()>52 pub(crate) fn getcwd(buf: &mut [u8]) -> io::Result<()> {
53     unsafe { ret_discarded_char_ptr(c::getcwd(buf.as_mut_ptr().cast(), buf.len())) }
54 }
55 
56 #[cfg(any(target_os = "android", target_os = "linux"))]
membarrier_query() -> MembarrierQuery57 pub(crate) fn membarrier_query() -> MembarrierQuery {
58     // GLIBC does not have a wrapper for `membarrier`; [the documentation]
59     // says to use `syscall`.
60     //
61     // [the documentation]: https://man7.org/linux/man-pages/man2/membarrier.2.html#NOTES
62     const MEMBARRIER_CMD_QUERY: u32 = 0;
63     unsafe {
64         match syscall_ret_u32(c::syscall(c::SYS_membarrier, MEMBARRIER_CMD_QUERY, 0)) {
65             Ok(query) => MembarrierQuery::from_bits_unchecked(query),
66             Err(_) => MembarrierQuery::empty(),
67         }
68     }
69 }
70 
71 #[cfg(any(target_os = "android", target_os = "linux"))]
membarrier(cmd: MembarrierCommand) -> io::Result<()>72 pub(crate) fn membarrier(cmd: MembarrierCommand) -> io::Result<()> {
73     unsafe { syscall_ret(c::syscall(c::SYS_membarrier, cmd as u32, 0)) }
74 }
75 
76 #[cfg(any(target_os = "android", target_os = "linux"))]
membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()>77 pub(crate) fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> {
78     const MEMBARRIER_CMD_FLAG_CPU: u32 = 1;
79     unsafe {
80         syscall_ret(c::syscall(
81             c::SYS_membarrier,
82             cmd as u32,
83             MEMBARRIER_CMD_FLAG_CPU,
84             cpu.as_raw(),
85         ))
86     }
87 }
88 
89 #[cfg(not(target_os = "wasi"))]
90 #[inline]
91 #[must_use]
getuid() -> Uid92 pub(crate) fn getuid() -> Uid {
93     unsafe {
94         let uid = c::getuid();
95         Uid::from_raw(uid)
96     }
97 }
98 
99 #[cfg(not(target_os = "wasi"))]
100 #[inline]
101 #[must_use]
geteuid() -> Uid102 pub(crate) fn geteuid() -> Uid {
103     unsafe {
104         let uid = c::geteuid();
105         Uid::from_raw(uid)
106     }
107 }
108 
109 #[cfg(not(target_os = "wasi"))]
110 #[inline]
111 #[must_use]
getgid() -> Gid112 pub(crate) fn getgid() -> Gid {
113     unsafe {
114         let gid = c::getgid();
115         Gid::from_raw(gid)
116     }
117 }
118 
119 #[cfg(not(target_os = "wasi"))]
120 #[inline]
121 #[must_use]
getegid() -> Gid122 pub(crate) fn getegid() -> Gid {
123     unsafe {
124         let gid = c::getegid();
125         Gid::from_raw(gid)
126     }
127 }
128 
129 #[cfg(not(target_os = "wasi"))]
130 #[inline]
131 #[must_use]
getpid() -> Pid132 pub(crate) fn getpid() -> Pid {
133     unsafe {
134         let pid = c::getpid();
135         debug_assert_ne!(pid, 0);
136         Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid))
137     }
138 }
139 
140 #[cfg(not(target_os = "wasi"))]
141 #[inline]
142 #[must_use]
getppid() -> Option<Pid>143 pub(crate) fn getppid() -> Option<Pid> {
144     unsafe {
145         let pid: i32 = c::getppid();
146         Pid::from_raw(pid)
147     }
148 }
149 
150 #[cfg(not(target_os = "wasi"))]
151 #[inline]
getpgid(pid: Option<Pid>) -> io::Result<Pid>152 pub(crate) fn getpgid(pid: Option<Pid>) -> io::Result<Pid> {
153     unsafe {
154         let pgid = ret_pid_t(c::getpgid(Pid::as_raw(pid) as _))?;
155         debug_assert_ne!(pgid, 0);
156         Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid)))
157     }
158 }
159 
160 #[cfg(not(target_os = "wasi"))]
161 #[inline]
162 #[must_use]
getpgrp() -> Pid163 pub(crate) fn getpgrp() -> Pid {
164     unsafe {
165         let pgid = c::getpgrp();
166         debug_assert_ne!(pgid, 0);
167         Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pgid))
168     }
169 }
170 
171 #[cfg(any(
172     target_os = "android",
173     target_os = "dragonfly",
174     target_os = "fuchsia",
175     target_os = "linux",
176 ))]
177 #[inline]
sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()>178 pub(crate) fn sched_getaffinity(pid: Option<Pid>, cpuset: &mut RawCpuSet) -> io::Result<()> {
179     unsafe {
180         ret(c::sched_getaffinity(
181             Pid::as_raw(pid) as _,
182             core::mem::size_of::<RawCpuSet>(),
183             cpuset,
184         ))
185     }
186 }
187 
188 #[cfg(any(
189     target_os = "android",
190     target_os = "dragonfly",
191     target_os = "fuchsia",
192     target_os = "linux",
193 ))]
194 #[inline]
sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()>195 pub(crate) fn sched_setaffinity(pid: Option<Pid>, cpuset: &RawCpuSet) -> io::Result<()> {
196     unsafe {
197         ret(c::sched_setaffinity(
198             Pid::as_raw(pid) as _,
199             core::mem::size_of::<RawCpuSet>(),
200             cpuset,
201         ))
202     }
203 }
204 
205 #[inline]
sched_yield()206 pub(crate) fn sched_yield() {
207     unsafe {
208         let _ = c::sched_yield();
209     }
210 }
211 
212 #[cfg(not(target_os = "wasi"))]
213 #[inline]
uname() -> RawUname214 pub(crate) fn uname() -> RawUname {
215     let mut uname = MaybeUninit::<RawUname>::uninit();
216     unsafe {
217         ret(c::uname(uname.as_mut_ptr())).unwrap();
218         uname.assume_init()
219     }
220 }
221 
222 #[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
223 #[inline]
nice(inc: i32) -> io::Result<i32>224 pub(crate) fn nice(inc: i32) -> io::Result<i32> {
225     libc_errno::set_errno(libc_errno::Errno(0));
226     let r = unsafe { c::nice(inc) };
227     if libc_errno::errno().0 != 0 {
228         ret_c_int(r)
229     } else {
230         Ok(r)
231     }
232 }
233 
234 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
235 #[inline]
getpriority_user(uid: Uid) -> io::Result<i32>236 pub(crate) fn getpriority_user(uid: Uid) -> io::Result<i32> {
237     libc_errno::set_errno(libc_errno::Errno(0));
238     let r = unsafe { c::getpriority(c::PRIO_USER, uid.as_raw() as _) };
239     if libc_errno::errno().0 != 0 {
240         ret_c_int(r)
241     } else {
242         Ok(r)
243     }
244 }
245 
246 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
247 #[inline]
getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32>248 pub(crate) fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> {
249     libc_errno::set_errno(libc_errno::Errno(0));
250     let r = unsafe { c::getpriority(c::PRIO_PGRP, Pid::as_raw(pgid) as _) };
251     if libc_errno::errno().0 != 0 {
252         ret_c_int(r)
253     } else {
254         Ok(r)
255     }
256 }
257 
258 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
259 #[inline]
getpriority_process(pid: Option<Pid>) -> io::Result<i32>260 pub(crate) fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> {
261     libc_errno::set_errno(libc_errno::Errno(0));
262     let r = unsafe { c::getpriority(c::PRIO_PROCESS, Pid::as_raw(pid) as _) };
263     if libc_errno::errno().0 != 0 {
264         ret_c_int(r)
265     } else {
266         Ok(r)
267     }
268 }
269 
270 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
271 #[inline]
setpriority_user(uid: Uid, priority: i32) -> io::Result<()>272 pub(crate) fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> {
273     unsafe { ret(c::setpriority(c::PRIO_USER, uid.as_raw() as _, priority)) }
274 }
275 
276 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
277 #[inline]
setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()>278 pub(crate) fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> {
279     unsafe {
280         ret(c::setpriority(
281             c::PRIO_PGRP,
282             Pid::as_raw(pgid) as _,
283             priority,
284         ))
285     }
286 }
287 
288 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
289 #[inline]
setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()>290 pub(crate) fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> {
291     unsafe {
292         ret(c::setpriority(
293             c::PRIO_PROCESS,
294             Pid::as_raw(pid) as _,
295             priority,
296         ))
297     }
298 }
299 
300 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
301 #[inline]
getrlimit(limit: Resource) -> Rlimit302 pub(crate) fn getrlimit(limit: Resource) -> Rlimit {
303     let mut result = MaybeUninit::<libc_rlimit>::uninit();
304     unsafe {
305         ret_infallible(libc_getrlimit(limit as _, result.as_mut_ptr()));
306         rlimit_from_libc(result.assume_init())
307     }
308 }
309 
310 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
311 #[inline]
setrlimit(limit: Resource, new: Rlimit) -> io::Result<()>312 pub(crate) fn setrlimit(limit: Resource, new: Rlimit) -> io::Result<()> {
313     let lim = rlimit_to_libc(new)?;
314     unsafe { ret(libc_setrlimit(limit as _, &lim)) }
315 }
316 
317 #[cfg(any(target_os = "android", target_os = "linux"))]
318 #[inline]
prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit>319 pub(crate) fn prlimit(pid: Option<Pid>, limit: Resource, new: Rlimit) -> io::Result<Rlimit> {
320     let lim = rlimit_to_libc(new)?;
321     let mut result = MaybeUninit::<libc_rlimit>::uninit();
322     unsafe {
323         ret(libc_prlimit(
324             Pid::as_raw(pid),
325             limit as _,
326             &lim,
327             result.as_mut_ptr(),
328         ))?;
329         Ok(rlimit_from_libc(result.assume_init()))
330     }
331 }
332 
333 /// Convert a Rust [`Rlimit`] to a C `libc_rlimit`.
334 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
rlimit_from_libc(lim: libc_rlimit) -> Rlimit335 fn rlimit_from_libc(lim: libc_rlimit) -> Rlimit {
336     let current = if lim.rlim_cur == LIBC_RLIM_INFINITY {
337         None
338     } else {
339         Some(lim.rlim_cur.try_into().unwrap())
340     };
341     let maximum = if lim.rlim_max == LIBC_RLIM_INFINITY {
342         None
343     } else {
344         Some(lim.rlim_max.try_into().unwrap())
345     };
346     Rlimit { current, maximum }
347 }
348 
349 /// Convert a C `libc_rlimit` to a Rust `Rlimit`.
350 #[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))]
rlimit_to_libc(lim: Rlimit) -> io::Result<libc_rlimit>351 fn rlimit_to_libc(lim: Rlimit) -> io::Result<libc_rlimit> {
352     let Rlimit { current, maximum } = lim;
353     let rlim_cur = match current {
354         Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?,
355         None => LIBC_RLIM_INFINITY as _,
356     };
357     let rlim_max = match maximum {
358         Some(r) => r.try_into().map_err(|_e| io::Errno::INVAL)?,
359         None => LIBC_RLIM_INFINITY as _,
360     };
361     Ok(libc_rlimit { rlim_cur, rlim_max })
362 }
363 
364 #[cfg(not(target_os = "wasi"))]
365 #[inline]
wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>>366 pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
367     _waitpid(!0, waitopts)
368 }
369 
370 #[cfg(not(target_os = "wasi"))]
371 #[inline]
waitpid( pid: Option<Pid>, waitopts: WaitOptions, ) -> io::Result<Option<(Pid, WaitStatus)>>372 pub(crate) fn waitpid(
373     pid: Option<Pid>,
374     waitopts: WaitOptions,
375 ) -> io::Result<Option<(Pid, WaitStatus)>> {
376     _waitpid(Pid::as_raw(pid), waitopts)
377 }
378 
379 #[cfg(not(target_os = "wasi"))]
380 #[inline]
_waitpid( pid: RawPid, waitopts: WaitOptions, ) -> io::Result<Option<(Pid, WaitStatus)>>381 pub(crate) fn _waitpid(
382     pid: RawPid,
383     waitopts: WaitOptions,
384 ) -> io::Result<Option<(Pid, WaitStatus)>> {
385     unsafe {
386         let mut status: c::c_int = 0;
387         let pid = ret_c_int(c::waitpid(pid as _, &mut status, waitopts.bits() as _))?;
388         Ok(RawNonZeroPid::new(pid).map(|non_zero| {
389             (
390                 Pid::from_raw_nonzero(non_zero),
391                 WaitStatus::new(status as _),
392             )
393         }))
394     }
395 }
396 
397 #[inline]
exit_group(code: c::c_int) -> !398 pub(crate) fn exit_group(code: c::c_int) -> ! {
399     // `_exit` and `_Exit` are the same; it's just a matter of which ones
400     // the libc bindings expose.
401     #[cfg(any(target_os = "wasi", target_os = "solid"))]
402     unsafe {
403         c::_Exit(code)
404     }
405     #[cfg(unix)]
406     unsafe {
407         c::_exit(code)
408     }
409 }
410 
411 #[cfg(not(target_os = "wasi"))]
412 #[inline]
setsid() -> io::Result<Pid>413 pub(crate) fn setsid() -> io::Result<Pid> {
414     unsafe {
415         let pid = ret_c_int(c::setsid())?;
416         debug_assert_ne!(pid, 0);
417         Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid)))
418     }
419 }
420 
421 #[cfg(not(target_os = "wasi"))]
422 #[inline]
kill_process(pid: Pid, sig: Signal) -> io::Result<()>423 pub(crate) fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> {
424     unsafe { ret(c::kill(pid.as_raw_nonzero().get(), sig as i32)) }
425 }
426 
427 #[cfg(not(target_os = "wasi"))]
428 #[inline]
kill_process_group(pid: Pid, sig: Signal) -> io::Result<()>429 pub(crate) fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> {
430     unsafe {
431         ret(c::kill(
432             pid.as_raw_nonzero().get().wrapping_neg(),
433             sig as i32,
434         ))
435     }
436 }
437 
438 #[cfg(not(target_os = "wasi"))]
439 #[inline]
kill_current_process_group(sig: Signal) -> io::Result<()>440 pub(crate) fn kill_current_process_group(sig: Signal) -> io::Result<()> {
441     unsafe { ret(c::kill(0, sig as i32)) }
442 }
443 
444 #[cfg(any(target_os = "android", target_os = "linux"))]
445 #[inline]
prctl( option: c::c_int, arg2: *mut c::c_void, arg3: *mut c::c_void, arg4: *mut c::c_void, arg5: *mut c::c_void, ) -> io::Result<c::c_int>446 pub(crate) unsafe fn prctl(
447     option: c::c_int,
448     arg2: *mut c::c_void,
449     arg3: *mut c::c_void,
450     arg4: *mut c::c_void,
451     arg5: *mut c::c_void,
452 ) -> io::Result<c::c_int> {
453     ret_c_int(c::prctl(option, arg2, arg3, arg4, arg5))
454 }
455 
456 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
457 #[inline]
procctl( idtype: c::idtype_t, id: c::id_t, option: c::c_int, data: *mut c::c_void, ) -> io::Result<()>458 pub(crate) unsafe fn procctl(
459     idtype: c::idtype_t,
460     id: c::id_t,
461     option: c::c_int,
462     data: *mut c::c_void,
463 ) -> io::Result<()> {
464     ret(c::procctl(idtype, id, option, data))
465 }
466