1 //! Unix-specific extensions to primitives in the [`std::process`] module. 2 //! 3 //! [`std::process`]: crate::std::process 4 5 use crate::std::ffi::OsStr; 6 use crate::std::io; 7 use crate::std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; 8 use crate::std::process; 9 use crate::std::sealed::Sealed; 10 use crate::std::sys; 11 use crate::std::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; 12 13 use cfg_if::cfg_if; 14 15 cfg_if! { 16 if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon", target_os = "vita"))] { 17 type UserId = u16; 18 type GroupId = u16; 19 } else if #[cfg(target_os = "nto")] { 20 // Both IDs are signed, see `sys/target_nto.h` of the QNX Neutrino SDP. 21 // Only positive values should be used, see e.g. 22 // https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/s/setuid.html 23 type UserId = i32; 24 type GroupId = i32; 25 } else { 26 type UserId = u32; 27 type GroupId = u32; 28 } 29 } 30 31 /// Unix-specific extensions to the [`process::Command`] builder. 32 /// 33 /// This trait is sealed: it cannot be implemented outside the standard library. 34 /// This is so that future additional methods are not breaking changes. 35 pub trait CommandExt: Sealed { 36 /// Sets the child process's user ID. This translates to a 37 /// `setuid` call in the child process. Failure in the `setuid` 38 /// call will cause the spawn to fail. 39 fn uid(&mut self, id: UserId) -> &mut process::Command; 40 41 /// Similar to `uid`, but sets the group ID of the child process. This has 42 /// the same semantics as the `uid` field. 43 fn gid(&mut self, id: GroupId) -> &mut process::Command; 44 45 /// Sets the supplementary group IDs for the calling process. Translates to 46 /// a `setgroups` call in the child process. 47 fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command; 48 49 /// Schedules a closure to be run just before the `exec` function is 50 /// invoked. 51 /// 52 /// The closure is allowed to return an I/O error whose OS error code will 53 /// be communicated back to the parent and returned as an error from when 54 /// the spawn was requested. 55 /// 56 /// Multiple closures can be registered and they will be called in order of 57 /// their registration. If a closure returns `Err` then no further closures 58 /// will be called and the spawn operation will immediately return with a 59 /// failure. 60 /// 61 /// # Notes and Safety 62 /// 63 /// This closure will be run in the context of the child process after a 64 /// `fork`. This primarily means that any modifications made to memory on 65 /// behalf of this closure will **not** be visible to the parent process. 66 /// This is often a very constrained environment where normal operations 67 /// like `malloc`, accessing environment variables through [`std::env`] 68 /// or acquiring a mutex are not guaranteed to work (due to 69 /// other threads perhaps still running when the `fork` was run). 70 /// 71 /// For further details refer to the [POSIX fork() specification] 72 /// and the equivalent documentation for any targeted 73 /// platform, especially the requirements around *async-signal-safety*. 74 /// 75 /// This also means that all resources such as file descriptors and 76 /// memory-mapped regions got duplicated. It is your responsibility to make 77 /// sure that the closure does not violate library invariants by making 78 /// invalid use of these duplicates. 79 /// 80 /// Panicking in the closure is safe only if all the format arguments for the 81 /// panic message can be safely formatted; this is because although 82 /// `Command` calls [`std::panic::always_abort`](crate::std::panic::always_abort) 83 /// before calling the pre_exec hook, panic will still try to format the 84 /// panic message. 85 /// 86 /// When this closure is run, aspects such as the stdio file descriptors and 87 /// working directory have successfully been changed, so output to these 88 /// locations might not appear where intended. 89 /// 90 /// [POSIX fork() specification]: 91 /// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html 92 /// [`std::env`]: mod@crate::std::env 93 unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command 94 where 95 F: FnMut() -> io::Result<()> + Send + Sync + 'static; 96 97 /// Schedules a closure to be run just before the `exec` function is 98 /// invoked. 99 /// 100 /// This method is stable and usable, but it should be unsafe. To fix 101 /// that, it got deprecated in favor of the unsafe [`pre_exec`]. 102 /// 103 /// [`pre_exec`]: CommandExt::pre_exec 104 #[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")] 105 fn before_exec<F>(&mut self, f: F) -> &mut process::Command 106 where 107 F: FnMut() -> io::Result<()> + Send + Sync + 'static, 108 { 109 unsafe { self.pre_exec(f) } 110 } 111 112 /// Performs all the required setup by this `Command`, followed by calling 113 /// the `execvp` syscall. 114 /// 115 /// On success this function will not return, and otherwise it will return 116 /// an error indicating why the exec (or another part of the setup of the 117 /// `Command`) failed. 118 /// 119 /// `exec` not returning has the same implications as calling 120 /// [`process::exit`] – no destructors on the current stack or any other 121 /// thread’s stack will be run. Therefore, it is recommended to only call 122 /// `exec` at a point where it is fine to not run any destructors. Note, 123 /// that the `execvp` syscall independently guarantees that all memory is 124 /// freed and all file descriptors with the `CLOEXEC` option (set by default 125 /// on all file descriptors opened by the standard library) are closed. 126 /// 127 /// This function, unlike `spawn`, will **not** `fork` the process to create 128 /// a new child. Like spawn, however, the default behavior for the stdio 129 /// descriptors will be to inherited from the current process. 130 /// 131 /// # Notes 132 /// 133 /// The process may be in a "broken state" if this function returns in 134 /// error. For example the working directory, environment variables, signal 135 /// handling settings, various user/group information, or aspects of stdio 136 /// file descriptors may have changed. If a "transactional spawn" is 137 /// required to gracefully handle errors it is recommended to use the 138 /// cross-platform `spawn` instead. 139 fn exec(&mut self) -> io::Error; 140 141 /// Set executable argument 142 /// 143 /// Set the first process argument, `argv[0]`, to something other than the 144 /// default executable path. 145 fn arg0<S>(&mut self, arg: S) -> &mut process::Command 146 where 147 S: AsRef<OsStr>; 148 149 /// Sets the process group ID (PGID) of the child process. Equivalent to a 150 /// `setpgid` call in the child process, but may be more efficient. 151 /// 152 /// Process groups determine which processes receive signals. 153 /// 154 /// # Examples 155 /// 156 /// Pressing Ctrl-C in a terminal will send SIGINT to all processes in 157 /// the current foreground process group. By spawning the `sleep` 158 /// subprocess in a new process group, it will not receive SIGINT from the 159 /// terminal. 160 /// 161 /// The parent process could install a signal handler and manage the 162 /// subprocess on its own terms. 163 /// 164 /// A process group ID of 0 will use the process ID as the PGID. 165 /// 166 /// ```no_run 167 /// use std::process::Command; 168 /// use std::os::unix::process::CommandExt; 169 /// 170 /// Command::new("sleep") 171 /// .arg("10") 172 /// .process_group(0) 173 /// .spawn()? 174 /// .wait()?; 175 /// # 176 /// # Ok::<_, Box<dyn std::error::Error>>(()) 177 /// ``` 178 fn process_group(&mut self, pgroup: i32) -> &mut process::Command; 179 } 180 181 impl CommandExt for process::Command { 182 fn uid(&mut self, id: UserId) -> &mut process::Command { 183 self.as_inner_mut().uid(id); 184 self 185 } 186 187 fn gid(&mut self, id: GroupId) -> &mut process::Command { 188 self.as_inner_mut().gid(id); 189 self 190 } 191 192 fn groups(&mut self, groups: &[GroupId]) -> &mut process::Command { 193 self.as_inner_mut().groups(groups); 194 self 195 } 196 197 unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command 198 where 199 F: FnMut() -> io::Result<()> + Send + Sync + 'static, 200 { 201 self.as_inner_mut().pre_exec(Box::new(f)); 202 self 203 } 204 205 fn exec(&mut self) -> io::Error { 206 // NOTE: This may *not* be safe to call after `dlibc::fork`, because it 207 // may allocate. That may be worth fixing at some point in the future. 208 self.as_inner_mut().exec(sys::process::Stdio::Inherit) 209 } 210 211 fn arg0<S>(&mut self, arg: S) -> &mut process::Command 212 where 213 S: AsRef<OsStr>, 214 { 215 self.as_inner_mut().set_arg_0(arg.as_ref()); 216 self 217 } 218 219 fn process_group(&mut self, pgroup: i32) -> &mut process::Command { 220 self.as_inner_mut().pgroup(pgroup); 221 self 222 } 223 } 224 225 /// Unix-specific extensions to [`process::ExitStatus`] and 226 /// [`ExitStatusError`](process::ExitStatusError). 227 /// 228 /// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as 229 /// passed to the `_exit` system call or returned by 230 /// [`ExitStatus::code()`](crate::std::process::ExitStatus::code). It represents **any wait status** 231 /// as returned by one of the `wait` family of system 232 /// calls. 233 /// 234 /// A Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but can also 235 /// represent other kinds of process event. 236 /// 237 /// This trait is sealed: it cannot be implemented outside the standard library. 238 /// This is so that future additional methods are not breaking changes. 239 pub trait ExitStatusExt: Sealed { 240 /// Creates a new `ExitStatus` or `ExitStatusError` from the raw underlying integer status 241 /// value from `wait` 242 /// 243 /// The value should be a **wait status, not an exit status**. 244 /// 245 /// # Panics 246 /// 247 /// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`. 248 /// 249 /// Making an `ExitStatus` always succeeds and never panics. 250 fn from_raw(raw: i32) -> Self; 251 252 /// If the process was terminated by a signal, returns that signal. 253 /// 254 /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`. 255 fn signal(&self) -> Option<i32>; 256 257 /// If the process was terminated by a signal, says whether it dumped core. 258 fn core_dumped(&self) -> bool; 259 260 /// If the process was stopped by a signal, returns that signal. 261 /// 262 /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from 263 /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`. 264 fn stopped_signal(&self) -> Option<i32>; 265 266 /// Whether the process was continued from a stopped status. 267 /// 268 /// Ie, `WIFCONTINUED`. This is only possible if the status came from a `wait` system call 269 /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`. 270 fn continued(&self) -> bool; 271 272 /// Returns the underlying raw `wait` status. 273 /// 274 /// The returned integer is a **wait status, not an exit status**. 275 fn into_raw(self) -> i32; 276 } 277 278 impl ExitStatusExt for process::ExitStatus { 279 fn from_raw(raw: i32) -> Self { 280 process::ExitStatus::from_inner(From::from(raw)) 281 } 282 283 fn signal(&self) -> Option<i32> { 284 self.as_inner().signal() 285 } 286 287 fn core_dumped(&self) -> bool { 288 self.as_inner().core_dumped() 289 } 290 291 fn stopped_signal(&self) -> Option<i32> { 292 self.as_inner().stopped_signal() 293 } 294 295 fn continued(&self) -> bool { 296 self.as_inner().continued() 297 } 298 299 fn into_raw(self) -> i32 { 300 self.as_inner().into_raw().into() 301 } 302 } 303 304 impl ExitStatusExt for process::ExitStatusError { 305 fn from_raw(raw: i32) -> Self { 306 process::ExitStatus::from_raw(raw) 307 .exit_ok() 308 .expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error") 309 } 310 311 fn signal(&self) -> Option<i32> { 312 self.into_status().signal() 313 } 314 315 fn core_dumped(&self) -> bool { 316 self.into_status().core_dumped() 317 } 318 319 fn stopped_signal(&self) -> Option<i32> { 320 self.into_status().stopped_signal() 321 } 322 323 fn continued(&self) -> bool { 324 self.into_status().continued() 325 } 326 327 fn into_raw(self) -> i32 { 328 self.into_status().into_raw() 329 } 330 } 331 332 impl FromRawFd for process::Stdio { 333 #[inline] 334 unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { 335 let fd = sys::fd::FileDesc::from_raw_fd(fd); 336 let io = sys::process::Stdio::Fd(fd); 337 process::Stdio::from_inner(io) 338 } 339 } 340 341 impl From<OwnedFd> for process::Stdio { 342 #[inline] 343 fn from(fd: OwnedFd) -> process::Stdio { 344 let fd = sys::fd::FileDesc::from_inner(fd); 345 let io = sys::process::Stdio::Fd(fd); 346 process::Stdio::from_inner(io) 347 } 348 } 349 350 impl AsRawFd for process::ChildStdin { 351 #[inline] 352 fn as_raw_fd(&self) -> RawFd { 353 self.as_inner().as_raw_fd() 354 } 355 } 356 357 impl AsRawFd for process::ChildStdout { 358 #[inline] 359 fn as_raw_fd(&self) -> RawFd { 360 self.as_inner().as_raw_fd() 361 } 362 } 363 364 impl AsRawFd for process::ChildStderr { 365 #[inline] 366 fn as_raw_fd(&self) -> RawFd { 367 self.as_inner().as_raw_fd() 368 } 369 } 370 371 impl IntoRawFd for process::ChildStdin { 372 #[inline] 373 fn into_raw_fd(self) -> RawFd { 374 self.into_inner().into_inner().into_raw_fd() 375 } 376 } 377 378 impl IntoRawFd for process::ChildStdout { 379 #[inline] 380 fn into_raw_fd(self) -> RawFd { 381 self.into_inner().into_inner().into_raw_fd() 382 } 383 } 384 385 impl IntoRawFd for process::ChildStderr { 386 #[inline] 387 fn into_raw_fd(self) -> RawFd { 388 self.into_inner().into_inner().into_raw_fd() 389 } 390 } 391 392 impl AsFd for crate::std::process::ChildStdin { 393 #[inline] 394 fn as_fd(&self) -> BorrowedFd<'_> { 395 self.as_inner().as_fd() 396 } 397 } 398 399 impl From<crate::std::process::ChildStdin> for OwnedFd { 400 #[inline] 401 fn from(child_stdin: crate::std::process::ChildStdin) -> OwnedFd { 402 child_stdin.into_inner().into_inner().into_inner() 403 } 404 } 405 406 impl AsFd for crate::std::process::ChildStdout { 407 #[inline] 408 fn as_fd(&self) -> BorrowedFd<'_> { 409 self.as_inner().as_fd() 410 } 411 } 412 413 impl From<crate::std::process::ChildStdout> for OwnedFd { 414 #[inline] 415 fn from(child_stdout: crate::std::process::ChildStdout) -> OwnedFd { 416 child_stdout.into_inner().into_inner().into_inner() 417 } 418 } 419 420 impl AsFd for crate::std::process::ChildStderr { 421 #[inline] 422 fn as_fd(&self) -> BorrowedFd<'_> { 423 self.as_inner().as_fd() 424 } 425 } 426 427 impl From<crate::std::process::ChildStderr> for OwnedFd { 428 #[inline] 429 fn from(child_stderr: crate::std::process::ChildStderr) -> OwnedFd { 430 child_stderr.into_inner().into_inner().into_inner() 431 } 432 } 433 434 /// Returns the OS-assigned process identifier associated with this process's parent. 435 #[must_use] 436 pub fn parent_id() -> u32 { 437 crate::std::sys::os::getppid() 438 } 439