]> git.proxmox.com Git - rustc.git/blob - library/std/src/sys/unix/process/process_vxworks.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / library / std / src / sys / unix / process / process_vxworks.rs
1 use crate::convert::{TryFrom, TryInto};
2 use crate::fmt;
3 use crate::io::{self, Error, ErrorKind};
4 use crate::num::NonZeroI32;
5 use crate::sys;
6 use crate::sys::cvt;
7 use crate::sys::process::process_common::*;
8 use crate::sys_common::thread;
9 use core::ffi::NonZero_c_int;
10 use libc::RTP_ID;
11 use libc::{self, c_char, c_int};
12
13 ////////////////////////////////////////////////////////////////////////////////
14 // Command
15 ////////////////////////////////////////////////////////////////////////////////
16
17 impl Command {
18 pub fn spawn(
19 &mut self,
20 default: Stdio,
21 needs_stdin: bool,
22 ) -> io::Result<(Process, StdioPipes)> {
23 use crate::sys::cvt_r;
24 let envp = self.capture_env();
25
26 if self.saw_nul() {
27 return Err(io::const_io_error!(
28 ErrorKind::InvalidInput,
29 "nul byte found in provided data",
30 ));
31 }
32 let (ours, theirs) = self.setup_io(default, needs_stdin)?;
33 let mut p = Process { pid: 0, status: None };
34
35 unsafe {
36 macro_rules! t {
37 ($e:expr) => {
38 match $e {
39 Ok(e) => e,
40 Err(e) => return Err(e.into()),
41 }
42 };
43 }
44
45 let mut orig_stdin = libc::STDIN_FILENO;
46 let mut orig_stdout = libc::STDOUT_FILENO;
47 let mut orig_stderr = libc::STDERR_FILENO;
48
49 if let Some(fd) = theirs.stdin.fd() {
50 orig_stdin = t!(cvt_r(|| libc::dup(libc::STDIN_FILENO)));
51 t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
52 }
53 if let Some(fd) = theirs.stdout.fd() {
54 orig_stdout = t!(cvt_r(|| libc::dup(libc::STDOUT_FILENO)));
55 t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
56 }
57 if let Some(fd) = theirs.stderr.fd() {
58 orig_stderr = t!(cvt_r(|| libc::dup(libc::STDERR_FILENO)));
59 t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
60 }
61
62 if let Some(ref cwd) = *self.get_cwd() {
63 t!(cvt(libc::chdir(cwd.as_ptr())));
64 }
65
66 // pre_exec closures are ignored on VxWorks
67 let _ = self.get_closures();
68
69 let c_envp = envp
70 .as_ref()
71 .map(|c| c.as_ptr())
72 .unwrap_or_else(|| *sys::os::environ() as *const _);
73 let stack_size = thread::min_stack();
74
75 // ensure that access to the environment is synchronized
76 let _lock = sys::os::env_read_lock();
77
78 let ret = libc::rtpSpawn(
79 self.get_program_cstr().as_ptr(),
80 self.get_argv().as_ptr() as *mut *const c_char, // argv
81 c_envp as *mut *const c_char,
82 100 as c_int, // initial priority
83 stack_size, // initial stack size.
84 0, // options
85 0, // task options
86 );
87
88 // Because FileDesc was not used, each duplicated file descriptor
89 // needs to be closed manually
90 if orig_stdin != libc::STDIN_FILENO {
91 t!(cvt_r(|| libc::dup2(orig_stdin, libc::STDIN_FILENO)));
92 libc::close(orig_stdin);
93 }
94 if orig_stdout != libc::STDOUT_FILENO {
95 t!(cvt_r(|| libc::dup2(orig_stdout, libc::STDOUT_FILENO)));
96 libc::close(orig_stdout);
97 }
98 if orig_stderr != libc::STDERR_FILENO {
99 t!(cvt_r(|| libc::dup2(orig_stderr, libc::STDERR_FILENO)));
100 libc::close(orig_stderr);
101 }
102
103 if ret != libc::RTP_ID_ERROR {
104 p.pid = ret;
105 Ok((p, ours))
106 } else {
107 Err(io::Error::last_os_error())
108 }
109 }
110 }
111
112 pub fn exec(&mut self, default: Stdio) -> io::Error {
113 let ret = Command::spawn(self, default, false);
114 match ret {
115 Ok(t) => unsafe {
116 let mut status = 0 as c_int;
117 libc::waitpid(t.0.pid, &mut status, 0);
118 libc::exit(0);
119 },
120 Err(e) => e,
121 }
122 }
123 }
124
125 ////////////////////////////////////////////////////////////////////////////////
126 // Processes
127 ////////////////////////////////////////////////////////////////////////////////
128
129 /// The unique id of the process (this should never be negative).
130 pub struct Process {
131 pid: RTP_ID,
132 status: Option<ExitStatus>,
133 }
134
135 impl Process {
136 pub fn id(&self) -> u32 {
137 self.pid as u32
138 }
139
140 pub fn kill(&mut self) -> io::Result<()> {
141 // If we've already waited on this process then the pid can be recycled
142 // and used for another process, and we probably shouldn't be killing
143 // random processes, so just return an error.
144 if self.status.is_some() {
145 Err(io::const_io_error!(
146 ErrorKind::InvalidInput,
147 "invalid argument: can't kill an exited process",
148 ))
149 } else {
150 cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
151 }
152 }
153
154 pub fn wait(&mut self) -> io::Result<ExitStatus> {
155 use crate::sys::cvt_r;
156 if let Some(status) = self.status {
157 return Ok(status);
158 }
159 let mut status = 0 as c_int;
160 cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
161 self.status = Some(ExitStatus::new(status));
162 Ok(ExitStatus::new(status))
163 }
164
165 pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
166 if let Some(status) = self.status {
167 return Ok(Some(status));
168 }
169 let mut status = 0 as c_int;
170 let pid = cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) })?;
171 if pid == 0 {
172 Ok(None)
173 } else {
174 self.status = Some(ExitStatus::new(status));
175 Ok(Some(ExitStatus::new(status)))
176 }
177 }
178 }
179
180 /// Unix exit statuses
181 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
182 pub struct ExitStatus(c_int);
183
184 impl ExitStatus {
185 pub fn new(status: c_int) -> ExitStatus {
186 ExitStatus(status)
187 }
188
189 fn exited(&self) -> bool {
190 libc::WIFEXITED(self.0)
191 }
192
193 pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
194 // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
195 // true on all actual versions of Unix, is widely assumed, and is specified in SuS
196 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html . If it is not
197 // true for a platform pretending to be Unix, the tests (our doctests, and also
198 // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
199 match NonZero_c_int::try_from(self.0) {
200 Ok(failure) => Err(ExitStatusError(failure)),
201 Err(_) => Ok(()),
202 }
203 }
204
205 pub fn code(&self) -> Option<i32> {
206 if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None }
207 }
208
209 pub fn signal(&self) -> Option<i32> {
210 if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None }
211 }
212
213 pub fn core_dumped(&self) -> bool {
214 // This method is not yet properly implemented on VxWorks
215 false
216 }
217
218 pub fn stopped_signal(&self) -> Option<i32> {
219 if libc::WIFSTOPPED(self.0) { Some(libc::WSTOPSIG(self.0)) } else { None }
220 }
221
222 pub fn continued(&self) -> bool {
223 // This method is not yet properly implemented on VxWorks
224 false
225 }
226
227 pub fn into_raw(&self) -> c_int {
228 self.0
229 }
230 }
231
232 /// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
233 impl From<c_int> for ExitStatus {
234 fn from(a: c_int) -> ExitStatus {
235 ExitStatus(a)
236 }
237 }
238
239 impl fmt::Display for ExitStatus {
240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 if let Some(code) = self.code() {
242 write!(f, "exit code: {code}")
243 } else {
244 let signal = self.signal().unwrap();
245 write!(f, "signal: {signal}")
246 }
247 }
248 }
249
250 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
251 pub struct ExitStatusError(NonZero_c_int);
252
253 impl Into<ExitStatus> for ExitStatusError {
254 fn into(self) -> ExitStatus {
255 ExitStatus(self.0.into())
256 }
257 }
258
259 impl ExitStatusError {
260 pub fn code(self) -> Option<NonZeroI32> {
261 ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
262 }
263 }