1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use libc
::{self, size_t}
;
16 use sys
::process
::zircon
::{Handle, zx_handle_t}
;
17 use sys
::process
::process_common
::*;
19 ////////////////////////////////////////////////////////////////////////////////
21 ////////////////////////////////////////////////////////////////////////////////
24 pub fn spawn(&mut self, default: Stdio
, needs_stdin
: bool
)
25 -> io
::Result
<(Process
, StdioPipes
)> {
27 return Err(io
::Error
::new(io
::ErrorKind
::InvalidInput
,
28 "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)? }
;
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
,
41 "nul byte found in provided data")
44 match self.setup_io(default, true) {
46 // FIXME: This is tough because we don't support the exec syscalls
53 unsafe fn do_exec(&mut self, stdio
: ChildPipes
)
54 -> io
::Result
<zx_handle_t
> {
55 use sys
::process
::zircon
::*;
57 let job_handle
= zx_job_default();
58 let envp
= match *self.get_envp() {
59 Some(ref envp
) => envp
.as_ptr(),
63 // To make sure launchpad_destroy gets called on the launchpad if this function fails
64 struct LaunchpadDestructor(*mut launchpad_t
);
65 impl Drop
for LaunchpadDestructor
{
66 fn drop(&mut self) { unsafe { launchpad_destroy(self.0); }
}
69 // Duplicate the job handle
70 let mut job_copy
: zx_handle_t
= ZX_HANDLE_INVALID
;
71 zx_cvt(zx_handle_duplicate(job_handle
, ZX_RIGHT_SAME_RIGHTS
, &mut job_copy
))?
;
73 let mut launchpad
: *mut launchpad_t
= ptr
::null_mut();
74 zx_cvt(launchpad_create(job_copy
, self.get_argv()[0], &mut launchpad
))?
;
75 let launchpad_destructor
= LaunchpadDestructor(launchpad
);
77 // Set the process argv
78 zx_cvt(launchpad_set_args(launchpad
, self.get_argv().len() as i32 - 1,
79 self.get_argv().as_ptr()))?
;
80 // Setup the environment vars
81 zx_cvt(launchpad_set_environ(launchpad
, envp
))?
;
82 zx_cvt(launchpad_add_vdso_vmo(launchpad
))?
;
83 // Load the executable
84 zx_cvt(launchpad_elf_load(launchpad
, launchpad_vmo_from_file(self.get_argv()[0])))?
;
85 zx_cvt(launchpad_load_vdso(launchpad
, ZX_HANDLE_INVALID
))?
;
86 zx_cvt(launchpad_clone(launchpad
, LP_CLONE_FDIO_NAMESPACE
| LP_CLONE_FDIO_CWD
))?
;
88 // Clone stdin, stdout, and stderr
89 if let Some(fd
) = stdio
.stdin
.fd() {
90 zx_cvt(launchpad_transfer_fd(launchpad
, fd
, 0))?
;
92 zx_cvt(launchpad_clone_fd(launchpad
, 0, 0))?
;
94 if let Some(fd
) = stdio
.stdout
.fd() {
95 zx_cvt(launchpad_transfer_fd(launchpad
, fd
, 1))?
;
97 zx_cvt(launchpad_clone_fd(launchpad
, 1, 1))?
;
99 if let Some(fd
) = stdio
.stderr
.fd() {
100 zx_cvt(launchpad_transfer_fd(launchpad
, fd
, 2))?
;
102 zx_cvt(launchpad_clone_fd(launchpad
, 2, 2))?
;
105 // We don't want FileDesc::drop to be called on any stdio. It would close their fds. The
106 // fds will be closed once the child process finishes.
109 for callback
in self.get_closures().iter_mut() {
113 // `launchpad_go` destroys the launchpad, so we must not
114 mem
::forget(launchpad_destructor
);
116 let mut process_handle
: zx_handle_t
= 0;
117 let mut err_msg
: *const libc
::c_char
= ptr
::null();
118 zx_cvt(launchpad_go(launchpad
, &mut process_handle
, &mut err_msg
))?
;
119 // FIXME: See if we want to do something with that err_msg
125 ////////////////////////////////////////////////////////////////////////////////
127 ////////////////////////////////////////////////////////////////////////////////
134 pub fn id(&self) -> u32 {
135 self.handle
.raw() as u32
138 pub fn kill(&mut self) -> io
::Result
<()> {
139 use sys
::process
::zircon
::*;
141 unsafe { zx_cvt(zx_task_kill(self.handle.raw()))?; }
146 pub fn wait(&mut self) -> io
::Result
<ExitStatus
> {
147 use default::Default
;
148 use sys
::process
::zircon
::*;
150 let mut proc_info
: zx_info_process_t
= Default
::default();
151 let mut actual
: size_t
= 0;
152 let mut avail
: size_t
= 0;
155 zx_cvt(zx_object_wait_one(self.handle
.raw(), ZX_TASK_TERMINATED
,
156 ZX_TIME_INFINITE
, ptr
::null_mut()))?
;
157 zx_cvt(zx_object_get_info(self.handle
.raw(), ZX_INFO_PROCESS
,
158 &mut proc_info
as *mut _
as *mut libc
::c_void
,
159 mem
::size_of
::<zx_info_process_t
>(), &mut actual
,
163 return Err(io
::Error
::new(io
::ErrorKind
::InvalidData
,
164 "Failed to get exit status of process"));
166 Ok(ExitStatus
::new(proc_info
.rec
.return_code
))
169 pub fn try_wait(&mut self) -> io
::Result
<Option
<ExitStatus
>> {
170 use default::Default
;
171 use sys
::process
::zircon
::*;
173 let mut proc_info
: zx_info_process_t
= Default
::default();
174 let mut actual
: size_t
= 0;
175 let mut avail
: size_t
= 0;
178 let status
= zx_object_wait_one(self.handle
.raw(), ZX_TASK_TERMINATED
,
182 x
if x
== ERR_TIMED_OUT
=> {
185 _
=> { panic!("Failed to wait on process handle: {}
", status); },
187 zx_cvt(zx_object_get_info(self.handle.raw(), ZX_INFO_PROCESS,
188 &mut proc_info as *mut _ as *mut libc::c_void,
189 mem::size_of::<zx_info_process_t>(), &mut actual,
193 return Err(io::Error::new(io::ErrorKind::InvalidData,
194 "Failed to get exit status of process
"));
196 Ok(Some(ExitStatus::new(proc_info.rec.return_code)))