1 use crate::convert
::TryInto
;
7 use crate::sys
::process
::process_common
::*;
8 use crate::sys
::process
::zircon
::{zx_handle_t, Handle}
;
10 use libc
::{c_int, size_t}
;
12 ////////////////////////////////////////////////////////////////////////////////
14 ////////////////////////////////////////////////////////////////////////////////
21 ) -> io
::Result
<(Process
, StdioPipes
)> {
22 let envp
= self.capture_env();
25 return Err(io
::Error
::new(
26 io
::ErrorKind
::InvalidInput
,
27 "nul byte found in provided data",
31 let (ours
, theirs
) = self.setup_io(default, needs_stdin
)?
;
33 let process_handle
= unsafe { self.do_exec(theirs, envp.as_ref())? }
;
35 Ok((Process { handle: Handle::new(process_handle) }
, ours
))
38 pub fn exec(&mut self, default: Stdio
) -> io
::Error
{
40 return io
::Error
::new(io
::ErrorKind
::InvalidInput
, "nul byte found in provided data");
43 match self.setup_io(default, true) {
45 // FIXME: This is tough because we don't support the exec syscalls
55 maybe_envp
: Option
<&CStringArray
>,
56 ) -> io
::Result
<zx_handle_t
> {
57 use crate::sys
::process
::zircon
::*;
59 let envp
= match maybe_envp
{
60 // None means to clone the current environment, which is done in the
63 Some(envp
) => envp
.as_ptr(),
66 let make_action
= |local_io
: &ChildStdio
, target_fd
| -> io
::Result
<fdio_spawn_action_t
> {
67 if let Some(local_fd
) = local_io
.fd() {
68 Ok(fdio_spawn_action_t
{
69 action
: FDIO_SPAWN_ACTION_TRANSFER_FD
,
75 if let ChildStdio
::Null
= local_io
{
77 return Ok(Default
::default());
80 let mut handle
= ZX_HANDLE_INVALID
;
81 let status
= fdio_fd_clone(target_fd
, &mut handle
);
82 if status
== ERR_INVALID_ARGS
|| status
== ERR_NOT_SUPPORTED
{
83 // This descriptor is closed; skip it rather than generating an
85 return Ok(Default
::default());
89 let mut cloned_fd
= 0;
90 zx_cvt(fdio_fd_create(handle
, &mut cloned_fd
))?
;
92 Ok(fdio_spawn_action_t
{
93 action
: FDIO_SPAWN_ACTION_TRANSFER_FD
,
94 local_fd
: cloned_fd
as i32,
101 // Clone stdin, stdout, and stderr
102 let action1
= make_action(&stdio
.stdin
, 0)?
;
103 let action2
= make_action(&stdio
.stdout
, 1)?
;
104 let action3
= make_action(&stdio
.stderr
, 2)?
;
105 let actions
= [action1
, action2
, action3
];
107 // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
108 // always consumes transferred file descriptors.
111 for callback
in self.get_closures().iter_mut() {
115 let mut process_handle
: zx_handle_t
= 0;
116 zx_cvt(fdio_spawn_etc(
119 | FDIO_SPAWN_CLONE_LDSVC
120 | FDIO_SPAWN_CLONE_NAMESPACE
121 | FDIO_SPAWN_CLONE_ENVIRON
, // this is ignored when envp is non-null
122 self.get_program().as_ptr(),
123 self.get_argv().as_ptr(),
125 actions
.len() as size_t
,
130 // FIXME: See if we want to do something with that err_msg
136 ////////////////////////////////////////////////////////////////////////////////
138 ////////////////////////////////////////////////////////////////////////////////
145 pub fn id(&self) -> u32 {
146 self.handle
.raw() as u32
149 pub fn kill(&mut self) -> io
::Result
<()> {
150 use crate::sys
::process
::zircon
::*;
153 zx_cvt(zx_task_kill(self.handle
.raw()))?
;
159 pub fn wait(&mut self) -> io
::Result
<ExitStatus
> {
160 use crate::default::Default
;
161 use crate::sys
::process
::zircon
::*;
163 let mut proc_info
: zx_info_process_t
= Default
::default();
164 let mut actual
: size_t
= 0;
165 let mut avail
: size_t
= 0;
168 zx_cvt(zx_object_wait_one(
174 zx_cvt(zx_object_get_info(
177 &mut proc_info
as *mut _
as *mut libc
::c_void
,
178 mem
::size_of
::<zx_info_process_t
>(),
184 return Err(io
::Error
::new(
185 io
::ErrorKind
::InvalidData
,
186 "Failed to get exit status of process",
189 Ok(ExitStatus(proc_info
.return_code
))
192 pub fn try_wait(&mut self) -> io
::Result
<Option
<ExitStatus
>> {
193 use crate::default::Default
;
194 use crate::sys
::process
::zircon
::*;
196 let mut proc_info
: zx_info_process_t
= Default
::default();
197 let mut actual
: size_t
= 0;
198 let mut avail
: size_t
= 0;
202 zx_object_wait_one(self.handle
.raw(), ZX_TASK_TERMINATED
, 0, ptr
::null_mut());
205 x
if x
== ERR_TIMED_OUT
=> {
209 panic
!("Failed to wait on process handle: {}", status
);
212 zx_cvt(zx_object_get_info(
215 &mut proc_info
as *mut _
as *mut libc
::c_void
,
216 mem
::size_of
::<zx_info_process_t
>(),
222 return Err(io
::Error
::new(
223 io
::ErrorKind
::InvalidData
,
224 "Failed to get exit status of process",
227 Ok(Some(ExitStatus(proc_info
.return_code
)))
231 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
232 pub struct ExitStatus(i64);
235 pub fn success(&self) -> bool
{
236 self.code() == Some(0)
239 pub fn code(&self) -> Option
<i32> {
240 // FIXME: support extracting return code as an i64
241 self.0.try_into().ok()
244 pub fn signal(&self) -> Option
<i32> {
249 impl From
<c_int
> for ExitStatus
{
250 fn from(a
: c_int
) -> ExitStatus
{
255 impl fmt
::Display
for ExitStatus
{
256 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
257 write
!(f
, "exit code: {}", self.0)