1//! libc syscalls supporting `rustix::process`. 2 3use super::super::c; 4#[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))] 5use super::super::conv::borrowed_fd; 6#[cfg(not(target_os = "wasi"))] 7use super::super::conv::ret_pid_t; 8use super::super::conv::{c_str, ret, ret_c_int, ret_discarded_char_ptr}; 9#[cfg(any(target_os = "android", target_os = "linux"))] 10use 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))] 17use super::types::RawCpuSet; 18#[cfg(not(any(target_os = "wasi", target_os = "fuchsia")))] 19use crate::fd::BorrowedFd; 20use crate::ffi::CStr; 21use crate::io; 22use core::mem::MaybeUninit; 23#[cfg(not(any(target_os = "fuchsia", target_os = "redox", target_os = "wasi")))] 24use { 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"))] 31use { 32 super::super::offset::libc_prlimit, 33 crate::process::{Cpuid, MembarrierCommand, MembarrierQuery}, 34}; 35#[cfg(not(target_os = "wasi"))] 36use { 37 super::types::RawUname, 38 crate::process::{Gid, Pid, RawNonZeroPid, RawPid, Signal, Uid, WaitOptions, WaitStatus}, 39}; 40 41#[cfg(not(target_os = "wasi"))] 42pub(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")))] 47pub(crate) fn fchdir(dirfd: BorrowedFd<'_>) -> io::Result<()> { 48 unsafe { ret(c::fchdir(borrowed_fd(dirfd))) } 49} 50 51#[cfg(not(target_os = "wasi"))] 52pub(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"))] 57pub(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"))] 72pub(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"))] 77pub(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] 92pub(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] 102pub(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] 112pub(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] 122pub(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] 132pub(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] 143pub(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] 152pub(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] 163pub(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] 178pub(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] 195pub(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] 206pub(crate) fn sched_yield() { 207 unsafe { 208 let _ = c::sched_yield(); 209 } 210} 211 212#[cfg(not(target_os = "wasi"))] 213#[inline] 214pub(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] 224pub(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] 236pub(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] 248pub(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] 260pub(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] 272pub(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] 278pub(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] 290pub(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] 302pub(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] 312pub(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] 319pub(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")))] 335fn 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")))] 351fn 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] 366pub(crate) fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> { 367 _waitpid(!0, waitopts) 368} 369 370#[cfg(not(target_os = "wasi"))] 371#[inline] 372pub(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] 381pub(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] 398pub(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] 413pub(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] 423pub(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] 429pub(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] 440pub(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] 446pub(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] 458pub(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