2019-09-24 21:34:44 -07:00
use crate ::convert ::TryInto ;
use crate ::fmt ;
2019-11-27 10:28:39 -08:00
use crate ::io ;
2019-02-11 04:23:21 +09:00
use crate ::mem ;
use crate ::ptr ;
2016-11-23 13:58:13 -08:00
2019-02-11 04:23:21 +09:00
use crate ::sys ::process ::process_common ::* ;
2019-11-27 10:28:39 -08:00
use crate ::sys ::process ::zircon ::{ zx_handle_t , Handle } ;
2019-02-11 04:23:21 +09:00
2019-09-24 21:34:44 -07:00
use libc ::{ c_int , size_t } ;
2016-11-23 13:58:13 -08:00
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
impl Command {
2019-11-27 10:28:39 -08:00
pub fn spawn (
& mut self ,
default : Stdio ,
needs_stdin : bool ,
) -> io ::Result < ( Process , StdioPipes ) > {
2017-12-17 15:21:47 +00:00
let envp = self . capture_env ( ) ;
2016-11-23 13:58:13 -08:00
if self . saw_nul ( ) {
2021-03-21 20:22:38 +01:00
return Err ( io ::Error ::new_const (
2019-11-27 10:28:39 -08:00
io ::ErrorKind ::InvalidInput ,
2021-03-21 20:22:38 +01:00
& " nul byte found in provided data " ,
2019-11-27 10:28:39 -08:00
) ) ;
2016-11-23 13:58:13 -08:00
}
let ( ours , theirs ) = self . setup_io ( default , needs_stdin ) ? ;
2017-12-17 15:21:47 +00:00
let process_handle = unsafe { self . do_exec ( theirs , envp . as_ref ( ) ) ? } ;
2016-11-23 13:58:13 -08:00
2017-02-27 20:26:55 -08:00
Ok ( ( Process { handle : Handle ::new ( process_handle ) } , ours ) )
2016-11-23 13:58:13 -08:00
}
pub fn exec ( & mut self , default : Stdio ) -> io ::Error {
if self . saw_nul ( ) {
2021-03-21 20:22:38 +01:00
return io ::Error ::new_const (
io ::ErrorKind ::InvalidInput ,
& " nul byte found in provided data " ,
) ;
2016-11-23 13:58:13 -08:00
}
match self . setup_io ( default , true ) {
Ok ( ( _ , _ ) ) = > {
// FIXME: This is tough because we don't support the exec syscalls
unimplemented! ( ) ;
2019-11-27 10:28:39 -08:00
}
2016-11-23 13:58:13 -08:00
Err ( e ) = > e ,
}
}
2019-11-27 10:28:39 -08:00
unsafe fn do_exec (
& mut self ,
stdio : ChildPipes ,
maybe_envp : Option < & CStringArray > ,
) -> io ::Result < zx_handle_t > {
2019-02-11 04:23:21 +09:00
use crate ::sys ::process ::zircon ::* ;
2016-11-23 13:58:13 -08:00
2017-12-17 15:21:47 +00:00
let envp = match maybe_envp {
2019-08-30 18:52:19 -07:00
// None means to clone the current environment, which is done in the
// flags below.
2016-11-23 13:58:13 -08:00
None = > ptr ::null ( ) ,
2019-08-30 18:52:19 -07:00
Some ( envp ) = > envp . as_ptr ( ) ,
2016-11-23 13:58:13 -08:00
} ;
2019-08-30 18:21:57 -07:00
let make_action = | local_io : & ChildStdio , target_fd | -> io ::Result < fdio_spawn_action_t > {
if let Some ( local_fd ) = local_io . fd ( ) {
Ok ( fdio_spawn_action_t {
action : FDIO_SPAWN_ACTION_TRANSFER_FD ,
local_fd ,
target_fd ,
.. Default ::default ( )
} )
} else {
if let ChildStdio ::Null = local_io {
// acts as no-op
return Ok ( Default ::default ( ) ) ;
}
let mut handle = ZX_HANDLE_INVALID ;
let status = fdio_fd_clone ( target_fd , & mut handle ) ;
if status = = ERR_INVALID_ARGS | | status = = ERR_NOT_SUPPORTED {
// This descriptor is closed; skip it rather than generating an
// error.
return Ok ( Default ::default ( ) ) ;
}
zx_cvt ( status ) ? ;
let mut cloned_fd = 0 ;
zx_cvt ( fdio_fd_create ( handle , & mut cloned_fd ) ) ? ;
Ok ( fdio_spawn_action_t {
action : FDIO_SPAWN_ACTION_TRANSFER_FD ,
local_fd : cloned_fd as i32 ,
target_fd ,
.. Default ::default ( )
} )
2018-06-01 12:58:30 -07:00
}
} ;
2016-11-23 13:58:13 -08:00
// Clone stdin, stdout, and stderr
2019-08-30 18:21:57 -07:00
let action1 = make_action ( & stdio . stdin , 0 ) ? ;
let action2 = make_action ( & stdio . stdout , 1 ) ? ;
let action3 = make_action ( & stdio . stderr , 2 ) ? ;
2018-06-01 12:58:30 -07:00
let actions = [ action1 , action2 , action3 ] ;
2016-11-23 13:58:13 -08:00
2018-06-01 12:58:30 -07:00
// We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
// always consumes transferred file descriptors.
2016-11-23 13:58:13 -08:00
mem ::forget ( stdio ) ;
for callback in self . get_closures ( ) . iter_mut ( ) {
callback ( ) ? ;
}
2017-09-15 12:38:08 -07:00
let mut process_handle : zx_handle_t = 0 ;
2018-06-01 12:58:30 -07:00
zx_cvt ( fdio_spawn_etc (
2019-08-30 18:21:57 -07:00
ZX_HANDLE_INVALID ,
2019-11-27 10:28:39 -08:00
FDIO_SPAWN_CLONE_JOB
| FDIO_SPAWN_CLONE_LDSVC
| FDIO_SPAWN_CLONE_NAMESPACE
2020-09-15 13:54:46 -07:00
| FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null
| FDIO_SPAWN_CLONE_UTC_CLOCK ,
2020-09-21 11:32:06 -07:00
self . get_program_cstr ( ) . as_ptr ( ) ,
2019-11-27 10:28:39 -08:00
self . get_argv ( ) . as_ptr ( ) ,
envp ,
actions . len ( ) as size_t ,
actions . as_ptr ( ) ,
2018-06-01 12:58:30 -07:00
& mut process_handle ,
ptr ::null_mut ( ) ,
) ) ? ;
2017-02-27 20:26:55 -08:00
// FIXME: See if we want to do something with that err_msg
Ok ( process_handle )
2016-11-23 13:58:13 -08:00
}
}
////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////
pub struct Process {
2016-11-30 14:20:44 -08:00
handle : Handle ,
2016-11-23 13:58:13 -08:00
}
impl Process {
pub fn id ( & self ) -> u32 {
2016-11-30 14:20:44 -08:00
self . handle . raw ( ) as u32
2016-11-23 13:58:13 -08:00
}
pub fn kill ( & mut self ) -> io ::Result < ( ) > {
2019-02-11 04:23:21 +09:00
use crate ::sys ::process ::zircon ::* ;
2016-11-23 13:58:13 -08:00
2019-11-27 10:28:39 -08:00
unsafe {
zx_cvt ( zx_task_kill ( self . handle . raw ( ) ) ) ? ;
}
2016-11-30 14:20:44 -08:00
Ok ( ( ) )
2016-11-23 13:58:13 -08:00
}
pub fn wait ( & mut self ) -> io ::Result < ExitStatus > {
2019-02-11 04:23:21 +09:00
use crate ::default ::Default ;
use crate ::sys ::process ::zircon ::* ;
2016-11-23 13:58:13 -08:00
2017-09-15 12:38:08 -07:00
let mut proc_info : zx_info_process_t = Default ::default ( ) ;
2017-10-04 15:29:01 -07:00
let mut actual : size_t = 0 ;
let mut avail : size_t = 0 ;
2016-11-23 13:58:13 -08:00
unsafe {
2019-11-27 10:28:39 -08:00
zx_cvt ( zx_object_wait_one (
self . handle . raw ( ) ,
ZX_TASK_TERMINATED ,
ZX_TIME_INFINITE ,
ptr ::null_mut ( ) ,
) ) ? ;
zx_cvt ( zx_object_get_info (
self . handle . raw ( ) ,
ZX_INFO_PROCESS ,
& mut proc_info as * mut _ as * mut libc ::c_void ,
mem ::size_of ::< zx_info_process_t > ( ) ,
& mut actual ,
& mut avail ,
) ) ? ;
2016-11-23 13:58:13 -08:00
}
if actual ! = 1 {
2021-03-21 20:22:38 +01:00
return Err ( io ::Error ::new_const (
2019-11-27 10:28:39 -08:00
io ::ErrorKind ::InvalidData ,
2021-03-21 20:22:38 +01:00
& " Failed to get exit status of process " ,
2019-11-27 10:28:39 -08:00
) ) ;
2016-11-23 13:58:13 -08:00
}
2019-09-24 21:34:44 -07:00
Ok ( ExitStatus ( proc_info . return_code ) )
2016-11-23 13:58:13 -08:00
}
2017-01-24 13:01:47 -08:00
2017-02-03 17:39:41 -05:00
pub fn try_wait ( & mut self ) -> io ::Result < Option < ExitStatus > > {
2019-02-11 04:23:21 +09:00
use crate ::default ::Default ;
use crate ::sys ::process ::zircon ::* ;
2017-01-24 13:01:47 -08:00
2017-09-15 12:38:08 -07:00
let mut proc_info : zx_info_process_t = Default ::default ( ) ;
2017-10-04 15:29:01 -07:00
let mut actual : size_t = 0 ;
let mut avail : size_t = 0 ;
2017-01-24 13:01:47 -08:00
unsafe {
2019-11-27 10:28:39 -08:00
let status =
zx_object_wait_one ( self . handle . raw ( ) , ZX_TASK_TERMINATED , 0 , ptr ::null_mut ( ) ) ;
2017-01-24 13:01:47 -08:00
match status {
2019-11-27 10:28:39 -08:00
0 = > { } // Success
2017-01-24 13:01:47 -08:00
x if x = = ERR_TIMED_OUT = > {
2017-02-03 17:39:41 -05:00
return Ok ( None ) ;
2019-11-27 10:28:39 -08:00
}
_ = > {
panic! ( " Failed to wait on process handle: {} " , status ) ;
}
2017-01-24 13:01:47 -08:00
}
2019-11-27 10:28:39 -08:00
zx_cvt ( zx_object_get_info (
self . handle . raw ( ) ,
ZX_INFO_PROCESS ,
& mut proc_info as * mut _ as * mut libc ::c_void ,
mem ::size_of ::< zx_info_process_t > ( ) ,
& mut actual ,
& mut avail ,
) ) ? ;
2017-01-24 13:01:47 -08:00
}
if actual ! = 1 {
2021-03-21 20:22:38 +01:00
return Err ( io ::Error ::new_const (
2019-11-27 10:28:39 -08:00
io ::ErrorKind ::InvalidData ,
2021-03-21 20:22:38 +01:00
& " Failed to get exit status of process " ,
2019-11-27 10:28:39 -08:00
) ) ;
2017-01-24 13:01:47 -08:00
}
2019-09-24 21:34:44 -07:00
Ok ( Some ( ExitStatus ( proc_info . return_code ) ) )
}
}
#[ derive(PartialEq, Eq, Clone, Copy, Debug) ]
pub struct ExitStatus ( i64 ) ;
impl ExitStatus {
pub fn success ( & self ) -> bool {
self . code ( ) = = Some ( 0 )
}
pub fn code ( & self ) -> Option < i32 > {
// FIXME: support extracting return code as an i64
self . 0. try_into ( ) . ok ( )
}
pub fn signal ( & self ) -> Option < i32 > {
None
}
2021-01-13 11:17:41 +00:00
// FIXME: The actually-Unix implementation in process_unix.rs uses WSTOPSIG, WCOREDUMP et al.
// I infer from the implementation of `success`, `code` and `signal` above that these are not
// available on Fuchsia.
//
// It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many
2021-01-13 22:13:45 -08:00
// other things from std::os::unix) properly. This veneer is always going to be a bodge. So
2021-01-13 11:17:41 +00:00
// while I don't know if these implementations are actually correct, I think they will do for
// now at least.
pub fn core_dumped ( & self ) -> bool {
false
}
pub fn stopped_signal ( & self ) -> Option < i32 > {
None
}
pub fn continued ( & self ) -> bool {
false
}
pub fn into_raw ( & self ) -> c_int {
// We don't know what someone who calls into_raw() will do with this value, but it should
// have the conventional Unix representation. Despite the fact that this is not
// standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
// same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
// Unix.)
//
// The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
// do their own shifting and masking, or even pass the status to another computer running a
// different Unix variant.
//
// The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
// will give a raw Fuchsia status (whatever that is - I don't know, personally). That is
// not possible here becaause we must return a c_int because that's what Unix (including
// SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
// necessarily fit.
//
// It seems to me that that the right answer would be to provide std::os::fuchsia with its
// own ExitStatusExt, rather that trying to provide a not very convincing imitation of
// Unix. Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia. But
// fixing this up that is beyond the scope of my efforts now.
2021-01-13 22:13:45 -08:00
let exit_status_as_if_unix : u8 = self . 0. try_into ( ) . expect ( " Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to convert the value into a traditional Unix-style wait status, which cannot represent values greater than 255. " ) ;
2021-01-13 11:17:41 +00:00
let wait_status_as_if_unix = ( exit_status_as_if_unix as c_int ) < < 8 ;
wait_status_as_if_unix
}
2019-09-24 21:34:44 -07:00
}
2020-07-13 13:47:18 +02:00
/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
2019-09-24 21:34:44 -07:00
impl From < c_int > for ExitStatus {
fn from ( a : c_int ) -> ExitStatus {
ExitStatus ( a as i64 )
}
}
impl fmt ::Display for ExitStatus {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
write! ( f , " exit code: {} " , self . 0 )
2017-01-24 13:01:47 -08:00
}
2016-11-23 13:58:13 -08:00
}