2018-02-20 22:44:11 -08:00
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# define EFL_IO_READER_PROTECTED 1
# define EFL_IO_WRITER_PROTECTED 1
# define EFL_IO_CLOSER_PROTECTED 1
# include <Ecore.h>
# include "ecore_private.h"
# ifdef _WIN32
# else
# include <sys / time.h>
# include <sys / resource.h>
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <errno.h>
# include <sys / types.h>
# include <unistd.h>
# include <fcntl.h>
# include <signal.h>
# include <sys / socket.h>
# ifdef HAVE_PRCTL
# include <sys / prctl.h>
# endif
# ifdef HAVE_SYS_WAIT_H
# include <sys / wait.h>
# endif
2018-02-21 07:15:57 -08:00
# ifndef HAVE_CLEARENV
extern char * * environ ;
# endif
2018-02-20 22:44:11 -08:00
# endif
# define MY_CLASS EFL_EXE_CLASS
typedef struct _Efl_Exe_Data Efl_Exe_Data ;
struct _Efl_Exe_Data
{
int exit_signal ;
2018-03-06 01:31:48 -08:00
Efl_Exe_Flags flags ;
2018-02-20 22:44:11 -08:00
# ifdef _WIN32
struct {
Eo * in_handler , * out_handler ;
Eina_Bool can_read : 1 ;
Eina_Bool eos_read : 1 ;
Eina_Bool can_write : 1 ;
} fd ;
# else
2018-03-20 04:43:47 -07:00
Eina_Promise * promise ;
2018-02-20 22:44:11 -08:00
Eo * exit_handler ;
pid_t pid ;
struct {
int in , out , exited_read , exited_write ;
Eo * in_handler , * out_handler ;
Eina_Bool can_read : 1 ;
Eina_Bool eos_read : 1 ;
Eina_Bool can_write : 1 ;
} fd ;
# endif
Eina_Bool exit_called : 1 ;
2018-03-10 03:02:09 -08:00
Eina_Bool run : 1 ;
2018-02-20 22:44:11 -08:00
} ;
//////////////////////////////////////////////////////////////////////////
# ifdef _WIN32
# else
static const signed char primap [ EFL_TASK_PRIORITY_ULTRA + 1 ] =
{
10 , // EFL_TASK_PRIORITY_NORMAL
19 , // EFL_TASK_PRIORITY_BACKGROUND
15 , // EFL_TASK_PRIORITY_LOW
5 , // EFL_TASK_PRIORITY_HIGH
0 // EFL_TASK_PRIORITY_ULTRA
} ;
static void
_close_fds ( Efl_Exe_Data * pd )
{
if ( pd - > fd . in > = 0 ) close ( pd - > fd . in ) ;
if ( pd - > fd . out > = 0 ) close ( pd - > fd . out ) ;
if ( pd - > fd . exited_read > = 0 ) close ( pd - > fd . exited_read ) ;
if ( pd - > fd . exited_write > = 0 ) close ( pd - > fd . exited_write ) ;
pd - > fd . in = - 1 ;
pd - > fd . out = - 1 ;
pd - > fd . exited_read = - 1 ;
pd - > fd . exited_write = - 1 ;
}
static void
_exec ( const char * cmd , Efl_Exe_Flags flags )
{
char use_sh = 1 , * buf = NULL , * * args = NULL ;
// Try to avoid wrapping the exe call with /bin/sh -c.
// We conservatively search for certain shell meta characters,
// If we don't find them, we can call the exe directly.
if ( ! strpbrk ( cmd , " |&;<>()$ \\ \" '*?# " ) )
{
char * token , pre_command = 1 ;
int num_tokens = 0 , len ;
len = strlen ( cmd ) ;
buf = alloca ( len + 1 ) ;
strcpy ( buf , cmd ) ;
buf [ len ] = 0 ;
token = strtok ( buf , " \t \n \v " ) ;
while ( token )
{
if ( token [ 0 ] = = ' ~ ' ) break ;
if ( pre_command )
{
if ( token [ 0 ] = = ' [ ' ) break ;
if ( strchr ( token , ' = ' ) ) break ;
else pre_command = 0 ;
}
num_tokens + + ;
token = strtok ( NULL , " \t \n \v " ) ;
}
if ( ( ! token ) & & ( num_tokens ) )
{
int i = 0 ;
len = strlen ( cmd ) ;
buf = alloca ( len + 1 ) ;
strcpy ( buf , cmd ) ;
buf [ len ] = 0 ;
token = strtok ( buf , " \t \n \v " ) ;
use_sh = 0 ;
args = alloca ( ( num_tokens + 1 ) * sizeof ( char * ) ) ;
for ( i = 0 ; i < num_tokens ; i + + )
{
if ( token ) args [ i ] = token ;
token = strtok ( NULL , " \t \n \v " ) ;
}
args [ num_tokens ] = NULL ;
}
}
# ifdef HAVE_PRCTL
if ( flags & EFL_EXE_FLAGS_EXIT_WITH_PARENT )
prctl ( PR_SET_PDEATHSIG , SIGTERM ) ;
# endif
if ( flags & EFL_EXE_FLAGS_GROUP_LEADER ) setsid ( ) ;
if ( use_sh ) // We have to use a shell to run this.
{
errno = 0 ;
execl ( " /bin/sh " , " /bin/sh " , " -c " , cmd , NULL ) ;
}
else
{ // We can run this directly.
if ( ! args )
{
ERR ( " arg[0] is NULL! " ) ;
return ;
}
errno = 0 ;
if ( args [ 0 ] ) execvp ( args [ 0 ] , args ) ;
}
}
2019-02-12 12:11:44 -08:00
static Eina_Bool
_foreach_env ( const Eina_Hash * hash EINA_UNUSED , const void * key , void * data , void * fdata EINA_UNUSED )
{
int keylen ;
char * buf , * s ;
if ( ! data ) return EINA_TRUE ;
keylen = strlen ( key ) ;
buf = alloca ( keylen + 1 + strlen ( data ) + 1 ) ;
strcpy ( buf , key ) ;
buf [ keylen ] = ' = ' ;
strcpy ( buf + keylen + 1 , data ) ;
if ( ( s = strdup ( buf ) ) ) putenv ( s ) ;
return EINA_TRUE ;
}
2018-02-20 22:44:11 -08:00
static void
_exe_exit_eval ( Eo * obj , Efl_Exe_Data * pd )
{
2018-02-27 04:19:17 -08:00
if ( ( pd - > fd . out = = - 1 ) & & /*(pd->fd.in == -1) &&*/
( pd - > fd . exited_read = = - 1 ) & & ( ! pd - > exit_called ) )
2018-02-20 22:44:11 -08:00
{
pd - > exit_called = EINA_TRUE ;
2018-03-20 04:43:47 -07:00
if ( pd - > promise )
{
2018-03-26 04:53:06 -07:00
Eina_Promise * p = pd - > promise ;
2018-03-20 04:43:47 -07:00
int exit_code = efl_task_exit_code_get ( obj ) ;
2018-04-03 10:34:10 -07:00
if ( ( exit_code ! = 0 ) & & ( ! ( efl_task_flags_get ( obj ) &
EFL_TASK_FLAGS_NO_EXIT_CODE_ERROR ) ) )
2018-04-04 02:57:55 -07:00
{
Eina_Error err = exit_code + 1000000 ;
// Code Meaning Example Comments
// ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
// 1 Catchall for general errors let "var1 = 1/0" Miscellaneous errors, such as "divide by zero" and other impermissible operations
// 2 Misuse of shell builtins empty_function() {} Missing keyword or command, or permission problem (and diff return code on a failed binary file comparison).
// 126 Command invoked cannot execute /dev/null Permission problem or command is not an executable
// 127 "command not found" illegal_command Possible problem with $PATH or a typo
// 128 Invalid argument to exit exit 3.14159 exit takes only integer args in the range 0 - 255 (see first footnote)
// 128+n Fatal error signal "n" kill -9 $PPID $? returns 137 (128 + 9)
// 130 Script terminated by Control-C Ctl-C Control-C is fatal error signal 2, (130 = 128 + 2, see above)
// 255* Exit status out of range exit -1 exit takes only integer args in the range 0 - 255
2019-02-12 12:11:44 -08:00
//
2018-04-04 02:57:55 -07:00
// According to the above table, exit codes 1 - 2,
// 126 - 165, and 255 [1] have special meanings, and
// should therefore be avoided for user-specified exit
// parameters. Ending a script with exit 127 would
// certainly cause confusion when troubleshooting (is
// the error code a "command not found" or a user-defined
// one?). However, many scripts use an exit 1 as a general
// bailout-upon-error. Since exit code 1 signifies so many
// possible errors, it is not particularly useful in
// debugging.
if ( exit_code = = 1 ) err = EBADF ;
else if ( exit_code = = 2 ) err = EDOM ;
else if ( exit_code = = 126 ) err = ENOEXEC ;
else if ( exit_code = = 127 ) err = ENOENT ;
else if ( exit_code = = 128 ) err = EINVAL ;
else if ( exit_code = = 129 ) err = EFAULT ;
else if ( exit_code = = 130 ) err = EINTR ;
else if ( ( exit_code > = 131 ) & & ( exit_code < = 165 ) ) err = EFAULT ;
eina_promise_reject ( p , err ) ;
}
2018-04-03 10:34:10 -07:00
else eina_promise_resolve ( p , eina_value_int_init ( exit_code ) ) ;
2018-03-20 04:43:47 -07:00
}
2018-02-20 22:44:11 -08:00
}
}
static void
_cb_exe_exit_read ( void * data , const Efl_Event * event EINA_UNUSED )
{
Eo * obj = data ;
Efl_Exe_Data * pd = efl_data_scope_get ( obj , MY_CLASS ) ;
Ecore_Signal_Pid_Info pinfo ;
if ( ! pd ) return ;
if ( read ( pd - > fd . exited_read , & pinfo , sizeof ( Ecore_Signal_Pid_Info ) ) = =
sizeof ( Ecore_Signal_Pid_Info ) )
{
Efl_Task_Data * td = efl_data_scope_get ( obj , EFL_TASK_CLASS ) ;
if ( td )
{
td - > exited = EINA_TRUE ;
td - > exit_code = pinfo . exit_code ;
pd - > exit_signal = pinfo . exit_signal ;
}
}
// we don't need this fd and handler anymore now we code exit status
close ( pd - > fd . exited_read ) ;
pd - > fd . exited_read = - 1 ;
efl_del ( pd - > exit_handler ) ;
pd - > exit_handler = NULL ;
_exe_exit_eval ( obj , pd ) ;
// XXX: autodel of object here is the sensible easy thing to do in C
// because then you can just run exe's and not have to listen to them exit
// and do your own del every time - they will then not leak and just
// self-cleanup without needing a del of the obj on run. but other
// languages don't like this, so if you dont care to listen to end/death
// and then del/unref the obj there... always del/unref it immediately.
}
static void
_cb_exe_out ( void * data , const Efl_Event * event EINA_UNUSED )
{
Eo * obj = data ;
efl_io_reader_can_read_set ( obj , EINA_TRUE ) ;
}
static void
_cb_exe_in ( void * data , const Efl_Event * event EINA_UNUSED )
{
Eo * obj = data ;
efl_io_writer_can_write_set ( obj , EINA_TRUE ) ;
}
2018-03-20 04:43:47 -07:00
2019-01-04 17:42:26 -08:00
static Eina_Value
_run_cancel_cb ( Efl_Loop_Consumer * consumer , void * data EINA_UNUSED , Eina_Error error )
{
if ( error = = ECANCELED ) efl_task_end ( consumer ) ;
return eina_value_error_init ( error ) ;
}
2018-03-20 04:43:47 -07:00
static void
2019-01-04 17:42:26 -08:00
_run_clean_cb ( Efl_Loop_Consumer * consumer EINA_UNUSED ,
void * data ,
const Eina_Future * dead_future EINA_UNUSED )
2018-03-20 04:43:47 -07:00
{
2019-01-04 17:42:26 -08:00
Efl_Exe_Data * pd = data ;
2018-03-20 04:43:47 -07:00
pd - > promise = NULL ;
}
2019-01-04 17:42:26 -08:00
2018-02-20 22:44:11 -08:00
# endif
//////////////////////////////////////////////////////////////////////////
EOLIAN static void
_efl_exe_signal ( Eo * obj EINA_UNUSED , Efl_Exe_Data * pd , Efl_Exe_Signal sig )
{
# ifdef _WIN32
# else
int s = 0 ;
if ( pd - > pid = = - 1 ) return ;
switch ( sig )
{
case EFL_EXE_SIGNAL_INT : s = SIGINT ; break ;
case EFL_EXE_SIGNAL_QUIT : s = SIGQUIT ; break ;
case EFL_EXE_SIGNAL_TERM : s = SIGTERM ; break ;
case EFL_EXE_SIGNAL_KILL : s = SIGKILL ; break ;
case EFL_EXE_SIGNAL_CONT : s = SIGCONT ; break ;
case EFL_EXE_SIGNAL_STOP : s = SIGSTOP ; break ;
case EFL_EXE_SIGNAL_HUP : s = SIGHUP ; break ;
case EFL_EXE_SIGNAL_USR1 : s = SIGUSR1 ; break ;
case EFL_EXE_SIGNAL_USR2 : s = SIGUSR2 ; break ;
default : return ;
}
kill ( pd - > pid , s ) ;
# endif
}
EOLIAN static void
2018-03-06 01:31:48 -08:00
_efl_exe_exe_flags_set ( Eo * obj EINA_UNUSED , Efl_Exe_Data * pd , Efl_Exe_Flags flags )
2018-02-20 22:44:11 -08:00
{
pd - > flags = flags ;
}
EOLIAN static Efl_Exe_Flags
2018-04-17 11:09:44 -07:00
_efl_exe_exe_flags_get ( const Eo * obj EINA_UNUSED , Efl_Exe_Data * pd )
2018-02-20 22:44:11 -08:00
{
return pd - > flags ;
}
EOLIAN static void
_efl_exe_efl_task_priority_set ( Eo * obj EINA_UNUSED , Efl_Exe_Data * pd , Efl_Task_Priority priority )
{
efl_task_priority_set ( efl_super ( obj , MY_CLASS ) , priority ) ;
# ifdef _WIN32
# else
int p = 0 ;
if ( pd - > pid ! = - 1 )
{
if ( ( priority > = EFL_TASK_PRIORITY_NORMAL ) & &
( priority < = EFL_TASK_PRIORITY_ULTRA ) )
p = primap [ priority ] ;
}
setpriority ( PRIO_PROCESS , pd - > pid , p ) ;
# endif
}
EOLIAN static Efl_Task_Priority
2018-04-17 11:09:44 -07:00
_efl_exe_efl_task_priority_get ( const Eo * obj EINA_UNUSED , Efl_Exe_Data * pd )
2018-02-20 22:44:11 -08:00
{
Efl_Task_Priority pri = EFL_TASK_PRIORITY_NORMAL ;
# ifdef _WIN32
# else
int p , i , dist = 0x7fffffff , d ;
if ( pd - > pid = = - 1 )
return efl_task_priority_get ( efl_super ( obj , MY_CLASS ) ) ;
// p is -20 -> 19
errno = 0 ;
p = getpriority ( PRIO_PROCESS , pd - > pid ) ;
if ( errno ! = 0 )
return efl_task_priority_get ( efl_super ( obj , MY_CLASS ) ) ;
// find the closest matching priority in primap
for ( i = EFL_TASK_PRIORITY_NORMAL ; i < = EFL_TASK_PRIORITY_ULTRA ; i + + )
{
d = primap [ i ] - p ;
if ( d < 0 ) d = - d ;
if ( d < dist )
{
pri = i ;
dist = d ;
}
}
Efl_Task_Data * td = efl_data_scope_get ( obj , EFL_TASK_CLASS ) ;
if ( td ) td - > priority = pri ;
# endif
return pri ;
}
2018-03-20 04:43:47 -07:00
EOLIAN static Eina_Future *
2019-02-12 11:54:22 -08:00
_efl_exe_efl_task_run ( Eo * obj EINA_UNUSED , Efl_Exe_Data * pd )
2018-02-20 22:44:11 -08:00
{
# ifdef _WIN32
return EINA_FALSE ;
# else
Eo * loop ;
Efl_Task_Data * tdl , * td = efl_data_scope_get ( obj , EFL_TASK_CLASS ) ;
const char * cmd ;
int devnull ;
int pipe_stdin [ 2 ] ;
int pipe_stdout [ 2 ] ;
int pipe_exited [ 2 ] ;
2018-02-25 01:38:57 -08:00
int ret ;
2018-02-20 22:44:11 -08:00
2018-03-20 04:43:47 -07:00
if ( pd - > run ) return NULL ;
if ( pd - > pid ! = - 1 ) return NULL ;
if ( ! td ) return NULL ;
2018-02-20 22:44:11 -08:00
// get a cmdline to run
2019-02-12 11:54:22 -08:00
cmd = efl_task_command_get ( obj ) ;
2018-03-20 04:43:47 -07:00
if ( ! cmd ) return NULL ;
2018-02-20 22:44:11 -08:00
2018-02-25 01:38:57 -08:00
ret = pipe ( pipe_exited ) ;
if ( EINA_UNLIKELY ( ret ! = 0 ) )
{
const int error = errno ;
ERR ( " pipe() failed: %s " , strerror ( error ) ) ;
2018-03-20 04:43:47 -07:00
return NULL ;
2018-02-25 01:38:57 -08:00
}
2018-02-20 22:44:11 -08:00
pd - > fd . exited_read = pipe_exited [ 0 ] ;
eina_file_close_on_exec ( pd - > fd . exited_write , EINA_TRUE ) ;
pd - > fd . exited_write = pipe_exited [ 1 ] ;
eina_file_close_on_exec ( pd - > fd . exited_read , EINA_TRUE ) ;
2018-03-06 01:31:48 -08:00
if ( td - > flags & EFL_TASK_FLAGS_USE_STDIN )
2018-02-20 22:44:11 -08:00
{
2018-02-25 01:38:57 -08:00
ret = pipe ( pipe_stdin ) ;
if ( EINA_UNLIKELY ( ret ! = 0 ) )
{
const int error = errno ;
ERR ( " pipe() failed: %s " , strerror ( error ) ) ;
2018-03-20 04:43:47 -07:00
return NULL ;
2018-02-25 01:38:57 -08:00
}
2018-02-20 22:44:11 -08:00
pd - > fd . in = pipe_stdin [ 1 ] ;
2018-09-26 21:58:08 -07:00
if ( fcntl ( pd - > fd . in , F_SETFL , O_NONBLOCK ) < 0 )
ERR ( " can't set pipe to NONBLOCK " ) ;
2018-02-20 22:44:11 -08:00
eina_file_close_on_exec ( pd - > fd . in , EINA_TRUE ) ;
pd - > fd . in_handler =
efl_add ( EFL_LOOP_HANDLER_CLASS , obj ,
efl_loop_handler_fd_set ( efl_added , pd - > fd . in ) ,
efl_event_callback_add
( efl_added , EFL_LOOP_HANDLER_EVENT_WRITE , _cb_exe_in , obj ) ) ;
}
2018-03-06 01:31:48 -08:00
if ( td - > flags & EFL_TASK_FLAGS_USE_STDOUT )
2018-02-20 22:44:11 -08:00
{
2018-02-25 01:38:57 -08:00
ret = pipe ( pipe_stdout ) ;
if ( EINA_UNLIKELY ( ret ! = 0 ) )
{
const int error = errno ;
ERR ( " pipe() failed: %s " , strerror ( error ) ) ;
2018-03-20 04:43:47 -07:00
return NULL ;
2018-02-25 01:38:57 -08:00
}
2018-02-20 22:44:11 -08:00
pd - > fd . out = pipe_stdout [ 0 ] ;
2018-09-26 21:58:08 -07:00
if ( fcntl ( pd - > fd . out , F_SETFL , O_NONBLOCK ) < 0 )
ERR ( " can't set pipe to NONBLOCK " ) ;
2018-02-20 22:44:11 -08:00
eina_file_close_on_exec ( pd - > fd . out , EINA_TRUE ) ;
pd - > fd . out_handler =
efl_add ( EFL_LOOP_HANDLER_CLASS , obj ,
efl_loop_handler_fd_set ( efl_added , pd - > fd . out ) ,
efl_event_callback_add
( efl_added , EFL_LOOP_HANDLER_EVENT_READ , _cb_exe_out , obj ) ,
efl_loop_handler_active_set
( efl_added , EFL_LOOP_HANDLER_FLAGS_READ ) ) ;
}
_ecore_signal_pid_lock ( ) ;
pd - > pid = fork ( ) ;
if ( pd - > pid ! = 0 )
{
// parent process is here inside this if block
2018-03-06 01:31:48 -08:00
if ( td - > flags & EFL_TASK_FLAGS_USE_STDIN ) close ( pipe_stdin [ 0 ] ) ;
if ( td - > flags & EFL_TASK_FLAGS_USE_STDOUT ) close ( pipe_stdout [ 1 ] ) ;
2018-02-20 22:44:11 -08:00
// fork failed... close up and clean and release locks
if ( pd - > pid = = - 1 )
{
_close_fds ( pd ) ;
_ecore_signal_pid_unlock ( ) ;
2018-03-20 04:43:47 -07:00
return NULL ;
2018-02-20 22:44:11 -08:00
}
// register this pid in the core sigchild/pid exit code watcher
_ecore_signal_pid_register ( pd - > pid , pd - > fd . exited_write ) ;
pd - > exit_handler =
efl_add ( EFL_LOOP_HANDLER_CLASS , obj ,
efl_loop_handler_fd_set ( efl_added , pd - > fd . exited_read ) ,
efl_event_callback_add ( efl_added ,
EFL_LOOP_HANDLER_EVENT_READ ,
_cb_exe_exit_read , obj ) ,
efl_loop_handler_active_set ( efl_added ,
EFL_LOOP_HANDLER_FLAGS_READ ) ) ;
_ecore_signal_pid_unlock ( ) ;
2018-03-10 03:02:09 -08:00
pd - > run = EINA_TRUE ;
2019-01-04 17:42:26 -08:00
pd - > promise = efl_loop_promise_new ( obj ) ;
return efl_future_then ( obj , eina_future_new ( pd - > promise ) ,
. data = pd ,
. error = _run_cancel_cb ,
. free = _run_clean_cb ) ;
2018-02-20 22:44:11 -08:00
}
// this code is in the child here, and is temporary setup until we
// exec() the child to replace everything.
2018-03-06 01:31:48 -08:00
if ( td - > flags & EFL_TASK_FLAGS_USE_STDIN ) close ( pipe_stdin [ 1 ] ) ;
if ( td - > flags & EFL_TASK_FLAGS_USE_STDOUT ) close ( pipe_stdout [ 0 ] ) ;
2018-02-20 22:44:11 -08:00
// set priority of self
if ( ( td - > priority > = EFL_TASK_PRIORITY_NORMAL ) & &
( td - > priority < = EFL_TASK_PRIORITY_ULTRA ) )
setpriority ( PRIO_PROCESS , 0 , primap [ td - > priority ] ) ;
// if we want to hide or use any of the stdio, close the fd's
2018-03-06 01:31:48 -08:00
if ( ( td - > flags & EFL_TASK_FLAGS_USE_STDIN ) | |
2018-02-20 22:44:11 -08:00
( pd - > flags & EFL_EXE_FLAGS_HIDE_IO ) )
close ( STDIN_FILENO ) ;
2018-03-06 01:31:48 -08:00
if ( ( td - > flags & EFL_TASK_FLAGS_USE_STDOUT ) | |
2018-02-20 22:44:11 -08:00
( pd - > flags & EFL_EXE_FLAGS_HIDE_IO ) )
close ( STDOUT_FILENO ) ;
if ( ( pd - > flags & EFL_EXE_FLAGS_HIDE_IO ) )
close ( STDERR_FILENO ) ;
2018-03-06 01:31:48 -08:00
if ( ! ( td - > flags & EFL_TASK_FLAGS_USE_STDIN ) & &
2018-02-20 22:44:11 -08:00
( pd - > flags & EFL_EXE_FLAGS_HIDE_IO ) )
{
// hide stdin
devnull = open ( " /dev/null " , O_RDONLY ) ;
dup2 ( devnull , STDIN_FILENO ) ;
close ( devnull ) ;
}
2018-03-06 01:31:48 -08:00
else if ( ( td - > flags & EFL_TASK_FLAGS_USE_STDIN ) )
2018-02-20 22:44:11 -08:00
{
// hook up stdin to the pipe going to the parent
dup2 ( pipe_stdin [ 0 ] , STDIN_FILENO ) ;
close ( pipe_stdin [ 0 ] ) ;
}
2018-03-06 01:31:48 -08:00
if ( ! ( td - > flags & EFL_TASK_FLAGS_USE_STDOUT ) & &
2018-02-20 22:44:11 -08:00
( pd - > flags & EFL_EXE_FLAGS_HIDE_IO ) )
{
// hide stdout
devnull = open ( " /dev/null " , O_WRONLY ) ;
dup2 ( devnull , STDOUT_FILENO ) ;
close ( devnull ) ;
}
2018-03-06 01:31:48 -08:00
else if ( ( td - > flags & EFL_TASK_FLAGS_USE_STDOUT ) )
2018-02-20 22:44:11 -08:00
{
// hook up stdout to the pipe going to the parent
dup2 ( pipe_stdout [ 1 ] , STDOUT_FILENO ) ;
close ( pipe_stdout [ 1 ] ) ;
}
if ( ( pd - > flags & EFL_EXE_FLAGS_HIDE_IO ) )
{
// hide stderr
devnull = open ( " /dev/null " , O_WRONLY ) ;
dup2 ( devnull , STDERR_FILENO ) ;
close ( devnull ) ;
}
2018-03-26 05:07:46 -07:00
if ( ! ( loop = efl_provider_find ( obj , EFL_LOOP_CLASS ) ) ) exit ( 1 ) ;
2018-02-20 22:44:11 -08:00
2018-03-26 05:07:46 -07:00
if ( ! ( tdl = efl_data_scope_get ( loop , EFL_TASK_CLASS ) ) ) exit ( 1 ) ;
2018-02-20 22:44:11 -08:00
// clear systemd notify socket... only relevant for systemd world,
// otherwise shouldn't be trouble
putenv ( " NOTIFY_SOCKET= " ) ;
2019-02-12 12:11:44 -08:00
// force the env hash to update from env vars
efl_task_env_get ( loop , " HOME " ) ;
2018-02-20 22:44:11 -08:00
2019-02-12 12:11:44 -08:00
// actually setenv the env hash (clear what was there before so it is
2018-02-20 22:44:11 -08:00
// the only env there)
2019-02-12 12:11:44 -08:00
# ifdef HAVE_CLEARENV
clearenv ( ) ;
# else
environ = NULL ;
# endif
eina_hash_foreach ( td - > env , _foreach_env , NULL ) ;
2018-02-20 22:44:11 -08:00
// actually execute!
_exec ( cmd , pd - > flags ) ;
// we couldn't exec... uh oh. HAAAAAAAALP!
2018-03-26 05:07:46 -07:00
if ( ( errno = = EACCES ) | | ( errno = = EINVAL ) | | ( errno = = ELOOP ) | |
( errno = = ENOEXEC ) | | ( errno = = ENOMEM ) )
exit ( 126 ) ;
exit ( 127 ) ;
2018-03-20 04:43:47 -07:00
return NULL ;
2018-02-20 22:44:11 -08:00
# endif
}
EOLIAN static void
_efl_exe_efl_task_end ( Eo * obj EINA_UNUSED , Efl_Exe_Data * pd )
{
# ifdef _WIN32
# else
if ( pd - > pid = = - 1 ) return ;
kill ( pd - > pid , SIGINT ) ;
# endif
}
EOLIAN static int
2018-04-17 11:09:44 -07:00
_efl_exe_exit_signal_get ( const Eo * obj EINA_UNUSED , Efl_Exe_Data * pd )
2018-02-20 22:44:11 -08:00
{
return pd - > exit_signal ;
}
EOLIAN static Efl_Object *
_efl_exe_efl_object_constructor ( Eo * obj , Efl_Exe_Data * pd )
{
obj = efl_constructor ( efl_super ( obj , MY_CLASS ) ) ;
# ifdef _WIN32
# else
pd - > pid = - 1 ;
pd - > fd . in = - 1 ;
pd - > fd . out = - 1 ;
pd - > fd . exited_read = - 1 ;
# endif
pd - > fd . can_write = EINA_TRUE ;
pd - > flags = EFL_EXE_FLAGS_EXIT_WITH_PARENT ;
pd - > exit_signal = - 1 ;
return obj ;
}
EOLIAN static void
_efl_exe_efl_object_destructor ( Eo * obj , Efl_Exe_Data * pd )
{
# ifdef _WIN32
# else
2018-03-26 04:53:06 -07:00
if ( pd - > promise )
ERR ( " Exe being destroyed while child has not exited yet. " ) ;
2018-02-20 22:44:11 -08:00
if ( pd - > fd . exited_read > = 0 )
{
_ecore_signal_pid_lock ( ) ;
_ecore_signal_pid_unregister ( pd - > pid , pd - > fd . exited_read ) ;
_ecore_signal_pid_unlock ( ) ;
close ( pd - > fd . exited_read ) ;
pd - > fd . exited_read = - 1 ;
efl_del ( pd - > exit_handler ) ;
pd - > exit_handler = NULL ;
}
if ( pd - > fd . in_handler ) efl_del ( pd - > fd . in_handler ) ;
if ( pd - > fd . out_handler ) efl_del ( pd - > fd . out_handler ) ;
pd - > fd . in_handler = NULL ;
pd - > fd . out_handler = NULL ;
_close_fds ( pd ) ;
# endif
efl_destructor ( efl_super ( obj , MY_CLASS ) ) ;
}
EOLIAN static Eina_Error
_efl_exe_efl_io_closer_close ( Eo * obj , Efl_Exe_Data * pd )
{
EINA_SAFETY_ON_TRUE_RETURN_VAL ( efl_io_closer_closed_get ( obj ) , EBADF ) ;
efl_io_writer_can_write_set ( obj , EINA_FALSE ) ;
efl_io_reader_can_read_set ( obj , EINA_FALSE ) ;
efl_io_reader_eos_set ( obj , EINA_TRUE ) ;
# ifdef _WIN32
# else
if ( pd - > fd . in > = 0 ) close ( pd - > fd . in ) ;
if ( pd - > fd . out > = 0 ) close ( pd - > fd . out ) ;
if ( pd - > fd . exited_read > = 0 ) close ( pd - > fd . exited_read ) ;
if ( pd - > fd . in_handler ) efl_del ( pd - > fd . in_handler ) ;
if ( pd - > fd . out_handler ) efl_del ( pd - > fd . out_handler ) ;
pd - > fd . in = - 1 ;
pd - > fd . out = - 1 ;
pd - > fd . exited_read = - 1 ;
pd - > fd . in_handler = NULL ;
pd - > fd . out_handler = NULL ;
# endif
return 0 ;
}
EOLIAN static Eina_Bool
2018-04-17 11:09:44 -07:00
_efl_exe_efl_io_closer_closed_get ( const Eo * obj EINA_UNUSED , Efl_Exe_Data * pd )
2018-02-20 22:44:11 -08:00
{
# ifdef _WIN32
return EINA_FALSE ;
# else
if ( ( pd - > fd . in = = - 1 ) & & ( pd - > fd . out = = - 1 ) ) return EINA_TRUE ;
# endif
return EINA_FALSE ;
}
EOLIAN static Eina_Error
_efl_exe_efl_io_reader_read ( Eo * obj , Efl_Exe_Data * pd , Eina_Rw_Slice * rw_slice )
{
# ifdef _WIN32
return EINVAL ;
# else
ssize_t r ;
errno = 0 ;
if ( pd - > fd . out = = - 1 ) goto err ;
do
{
errno = 0 ;
r = read ( pd - > fd . out , rw_slice - > mem , rw_slice - > len ) ;
if ( r = = - 1 )
{
if ( errno = = EINTR ) continue ;
goto err ;
}
}
while ( r = = - 1 ) ;
rw_slice - > len = r ;
if ( r = = 0 )
{
efl_io_reader_can_read_set ( obj , EINA_FALSE ) ;
efl_io_reader_eos_set ( obj , EINA_TRUE ) ;
close ( pd - > fd . out ) ;
pd - > fd . out = - 1 ;
efl_del ( pd - > fd . out_handler ) ;
pd - > fd . out_handler = NULL ;
_exe_exit_eval ( obj , pd ) ;
return EPIPE ;
}
return 0 ;
err :
if ( ( pd - > fd . out ! = - 1 ) & & ( errno ! = EAGAIN ) )
{
close ( pd - > fd . out ) ;
pd - > fd . out = - 1 ;
efl_del ( pd - > fd . out_handler ) ;
pd - > fd . out_handler = NULL ;
}
rw_slice - > len = 0 ;
rw_slice - > mem = NULL ;
efl_io_reader_can_read_set ( obj , EINA_FALSE ) ;
_exe_exit_eval ( obj , pd ) ;
return EINVAL ;
# endif
}
EOLIAN static void
_efl_exe_efl_io_reader_can_read_set ( Eo * obj , Efl_Exe_Data * pd , Eina_Bool can_read )
{
Eina_Bool old = efl_io_reader_can_read_get ( obj ) ;
if ( old = = can_read ) return ;
pd - > fd . can_read = can_read ;
2018-02-27 04:19:17 -08:00
if ( ! pd - > fd . out_handler ) return ;
2018-02-20 22:44:11 -08:00
if ( can_read )
2018-02-27 04:19:17 -08:00
efl_loop_handler_active_set ( pd - > fd . out_handler , 0 ) ;
2018-02-20 22:44:11 -08:00
else
2018-02-27 04:19:17 -08:00
efl_loop_handler_active_set ( pd - > fd . out_handler ,
2018-02-20 22:44:11 -08:00
EFL_LOOP_HANDLER_FLAGS_READ ) ;
efl_event_callback_call ( obj , EFL_IO_READER_EVENT_CAN_READ_CHANGED , NULL ) ;
}
EOLIAN static Eina_Bool
2018-04-17 11:09:44 -07:00
_efl_exe_efl_io_reader_can_read_get ( const Eo * obj EINA_UNUSED , Efl_Exe_Data * pd )
2018-02-20 22:44:11 -08:00
{
return pd - > fd . can_read ;
}
EOLIAN static void
_efl_exe_efl_io_reader_eos_set ( Eo * obj , Efl_Exe_Data * pd , Eina_Bool is_eos )
{
Eina_Bool old = efl_io_reader_eos_get ( obj ) ;
if ( old = = is_eos ) return ;
pd - > fd . eos_read = is_eos ;
if ( ! is_eos ) return ;
if ( pd - > fd . out_handler )
efl_loop_handler_active_set ( pd - > fd . out_handler , 0 ) ;
efl_event_callback_call ( obj , EFL_IO_READER_EVENT_EOS , NULL ) ;
}
EOLIAN static Eina_Bool
2018-04-17 11:09:44 -07:00
_efl_exe_efl_io_reader_eos_get ( const Eo * obj EINA_UNUSED , Efl_Exe_Data * pd )
2018-02-20 22:44:11 -08:00
{
return pd - > fd . eos_read ;
}
EOLIAN static Eina_Error
_efl_exe_efl_io_writer_write ( Eo * obj , Efl_Exe_Data * pd , Eina_Slice * slice , Eina_Slice * remaining )
{
# ifdef _WIN32
return EINVAL ;
# else
ssize_t r ;
errno = 0 ;
if ( pd - > fd . in = = - 1 ) goto err ;
do
{
errno = 0 ;
r = write ( pd - > fd . in , slice - > mem , slice - > len ) ;
if ( r = = - 1 )
{
if ( errno = = EINTR ) continue ;
goto err ;
}
}
while ( r = = - 1 ) ;
if ( remaining )
{
remaining - > len = slice - > len - r ;
remaining - > bytes = slice - > bytes + r ;
}
slice - > len = r ;
if ( ( slice ) & & ( slice - > len > 0 ) )
efl_io_writer_can_write_set ( obj , EINA_FALSE ) ;
if ( r = = 0 )
{
close ( pd - > fd . in ) ;
pd - > fd . in = - 1 ;
efl_del ( pd - > fd . in_handler ) ;
pd - > fd . in_handler = NULL ;
_exe_exit_eval ( obj , pd ) ;
return EPIPE ;
}
return 0 ;
err :
if ( ( pd - > fd . in ! = - 1 ) & & ( errno ! = EAGAIN ) )
{
close ( pd - > fd . in ) ;
pd - > fd . in = - 1 ;
efl_del ( pd - > fd . in_handler ) ;
pd - > fd . in_handler = NULL ;
}
if ( remaining ) * remaining = * slice ;
slice - > len = 0 ;
slice - > mem = NULL ;
efl_io_writer_can_write_set ( obj , EINA_FALSE ) ;
_exe_exit_eval ( obj , pd ) ;
return EINVAL ;
# endif
}
EOLIAN static void
_efl_exe_efl_io_writer_can_write_set ( Eo * obj , Efl_Exe_Data * pd , Eina_Bool can_write )
{
Eina_Bool old = efl_io_writer_can_write_get ( obj ) ;
if ( old = = can_write ) return ;
pd - > fd . can_write = can_write ;
if ( can_write )
efl_loop_handler_active_set ( pd - > fd . in_handler , 0 ) ;
else
efl_loop_handler_active_set ( pd - > fd . in_handler ,
EFL_LOOP_HANDLER_FLAGS_WRITE ) ;
efl_event_callback_call ( obj , EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED , NULL ) ;
}
EOLIAN static Eina_Bool
2018-04-17 11:09:44 -07:00
_efl_exe_efl_io_writer_can_write_get ( const Eo * obj EINA_UNUSED , Efl_Exe_Data * pd )
2018-02-20 22:44:11 -08:00
{
return pd - > fd . can_write ;
}
//////////////////////////////////////////////////////////////////////////
# include "efl_exe.eo.c"