2 use crate::io
::{self, Error, ErrorKind}
;
5 use crate::sys
::process
::process_common
::*;
6 use crate::sys_common
::thread
;
8 use libc
::{self, c_char, c_int}
;
10 ////////////////////////////////////////////////////////////////////////////////
12 ////////////////////////////////////////////////////////////////////////////////
19 ) -> io
::Result
<(Process
, StdioPipes
)> {
20 use crate::sys
::cvt_r
;
21 const CLOEXEC_MSG_FOOTER
: &'
static [u8] = b
"NOEX";
22 let envp
= self.capture_env();
25 return Err(io
::Error
::new(ErrorKind
::InvalidInput
, "nul byte found in provided data"));
27 let (ours
, theirs
) = self.setup_io(default, needs_stdin
)?
;
28 let mut p
= Process { pid: 0, status: None }
;
35 Err(e
) => return Err(e
.into()),
40 let mut orig_stdin
= libc
::STDIN_FILENO
;
41 let mut orig_stdout
= libc
::STDOUT_FILENO
;
42 let mut orig_stderr
= libc
::STDERR_FILENO
;
44 if let Some(fd
) = theirs
.stdin
.fd() {
45 orig_stdin
= t
!(cvt_r(|| libc
::dup(libc
::STDIN_FILENO
)));
46 t
!(cvt_r(|| libc
::dup2(fd
, libc
::STDIN_FILENO
)));
48 if let Some(fd
) = theirs
.stdout
.fd() {
49 orig_stdout
= t
!(cvt_r(|| libc
::dup(libc
::STDOUT_FILENO
)));
50 t
!(cvt_r(|| libc
::dup2(fd
, libc
::STDOUT_FILENO
)));
52 if let Some(fd
) = theirs
.stderr
.fd() {
53 orig_stderr
= t
!(cvt_r(|| libc
::dup(libc
::STDERR_FILENO
)));
54 t
!(cvt_r(|| libc
::dup2(fd
, libc
::STDERR_FILENO
)));
57 if let Some(ref cwd
) = *self.get_cwd() {
58 t
!(cvt(libc
::chdir(cwd
.as_ptr())));
64 .unwrap_or_else(|| *sys
::os
::environ() as *const _
);
65 let stack_size
= thread
::min_stack();
67 // ensure that access to the environment is synchronized
68 let _lock
= sys
::os
::env_lock();
70 let ret
= libc
::rtpSpawn(
71 self.get_program_cstr().as_ptr(),
72 self.get_argv().as_ptr() as *mut *const c_char
, // argv
73 c_envp
as *mut *const c_char
,
74 100 as c_int
, // initial priority
75 stack_size
, // initial stack size.
80 // Because FileDesc was not used, each duplicated file descriptor
81 // needs to be closed manually
82 if orig_stdin
!= libc
::STDIN_FILENO
{
83 t
!(cvt_r(|| libc
::dup2(orig_stdin
, libc
::STDIN_FILENO
)));
84 libc
::close(orig_stdin
);
86 if orig_stdout
!= libc
::STDOUT_FILENO
{
87 t
!(cvt_r(|| libc
::dup2(orig_stdout
, libc
::STDOUT_FILENO
)));
88 libc
::close(orig_stdout
);
90 if orig_stderr
!= libc
::STDERR_FILENO
{
91 t
!(cvt_r(|| libc
::dup2(orig_stderr
, libc
::STDERR_FILENO
)));
92 libc
::close(orig_stderr
);
95 if ret
!= libc
::RTP_ID_ERROR
{
99 Err(io
::Error
::last_os_error())
104 pub fn exec(&mut self, default: Stdio
) -> io
::Error
{
105 let ret
= Command
::spawn(self, default, false);
108 let mut status
= 0 as c_int
;
109 libc
::waitpid(t
.0.pid
, &mut status
, 0);
117 ////////////////////////////////////////////////////////////////////////////////
119 ////////////////////////////////////////////////////////////////////////////////
121 /// The unique id of the process (this should never be negative).
124 status
: Option
<ExitStatus
>,
128 pub fn id(&self) -> u32 {
132 pub fn kill(&mut self) -> io
::Result
<()> {
133 // If we've already waited on this process then the pid can be recycled
134 // and used for another process, and we probably shouldn't be killing
135 // random processes, so just return an error.
136 if self.status
.is_some() {
138 ErrorKind
::InvalidInput
,
139 "invalid argument: can't kill an exited process",
142 cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }
).map(drop
)
146 pub fn wait(&mut self) -> io
::Result
<ExitStatus
> {
147 use crate::sys
::cvt_r
;
148 if let Some(status
) = self.status
{
151 let mut status
= 0 as c_int
;
152 cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) }
)?
;
153 self.status
= Some(ExitStatus
::new(status
));
154 Ok(ExitStatus
::new(status
))
157 pub fn try_wait(&mut self) -> io
::Result
<Option
<ExitStatus
>> {
158 if let Some(status
) = self.status
{
159 return Ok(Some(status
));
161 let mut status
= 0 as c_int
;
162 let pid
= cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) }
)?
;
166 self.status
= Some(ExitStatus
::new(status
));
167 Ok(Some(ExitStatus
::new(status
)))
172 /// Unix exit statuses
173 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
174 pub struct ExitStatus(c_int
);
177 pub fn new(status
: c_int
) -> ExitStatus
{
181 fn exited(&self) -> bool
{
182 libc
::WIFEXITED(self.0)
185 pub fn success(&self) -> bool
{
186 self.code() == Some(0)
189 pub fn code(&self) -> Option
<i32> {
190 if self.exited() { Some(libc::WEXITSTATUS(self.0)) }
else { None }
193 pub fn signal(&self) -> Option
<i32> {
194 if !self.exited() { Some(libc::WTERMSIG(self.0)) }
else { None }
198 /// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
199 impl From
<c_int
> for ExitStatus
{
200 fn from(a
: c_int
) -> ExitStatus
{
205 impl fmt
::Display
for ExitStatus
{
206 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
207 if let Some(code
) = self.code() {
208 write
!(f
, "exit code: {}", code
)
210 let signal
= self.signal().unwrap();
211 write
!(f
, "signal: {}", signal
)