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
2019-06-03 17:14:20 -07:00
# if defined (__FreeBSD__) || defined (__OpenBSD__)
# include <dlfcn.h>
static char * * * _dl_environ ;
# else
2018-02-21 07:15:57 -08:00
extern char * * environ ;
2019-06-03 17:14:20 -07:00
# endif
2018-02-21 07:15:57 -08:00
# 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
{
2019-02-12 12:34:27 -08:00
Efl_Core_Env * env ;
2018-02-20 22:44:11 -08:00
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 ) ;
}
}
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:34:27 -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
//////////////////////////////////////////////////////////////////////////
2019-02-12 12:34:27 -08:00
EOLIAN static void
_efl_exe_env_set ( Eo * obj EINA_UNUSED , Efl_Exe_Data * pd , Efl_Core_Env * env )
{
if ( pd - > env = = env ) return ;
if ( ! pd - > env )
efl_unref ( pd - > env ) ;
pd - > env = env ;
if ( pd - > env )
efl_ref ( pd - > env ) ;
}
EOLIAN static Efl_Core_Env *
_efl_exe_env_get ( const Eo * obj EINA_UNUSED , Efl_Exe_Data * pd )
{
return pd - > env ;
}
2018-02-20 22:44:11 -08:00
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 *
Revert "Revert command line array object because it's broken by design"
This reverts commit a57c7f751023fe1d1edeabbf8683574ac7497e5e.
I pretty much hate to just revert your revert, but you failed to read my
replies, and failed to understand what i was talking about.
And YES we talked at fosdem about the platform issue, and do you
remember my answer, that back in time this might be the case, today is
different freebsd suppoerts setenv, and for windows we have a setenv
implementation in evil. And yes, vtorri also created a issue how bad and
evil this commit is, however, i still fail to see the issue since setenv
unsetenv and clearenv usages are taken as needed. (T7693)
The ownership question is answered in
https://phab.enlightenment.org/D7516#137367.
Can we please get into a state of technical discussions, and not *oh
shit, i am going to revert this* this has been in review for a long
time, a lots of people have tested it, we discussed things on it, and
there was 3 weeks of no reply from you.
The issues that exist will be dealed with. Feel free to create tasks if
you want :)
2019-02-12 12:34:30 -08:00
_efl_exe_efl_task_run ( Eo * obj , 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
Revert "Revert command line array object because it's broken by design"
This reverts commit a57c7f751023fe1d1edeabbf8683574ac7497e5e.
I pretty much hate to just revert your revert, but you failed to read my
replies, and failed to understand what i was talking about.
And YES we talked at fosdem about the platform issue, and do you
remember my answer, that back in time this might be the case, today is
different freebsd suppoerts setenv, and for windows we have a setenv
implementation in evil. And yes, vtorri also created a issue how bad and
evil this commit is, however, i still fail to see the issue since setenv
unsetenv and clearenv usages are taken as needed. (T7693)
The ownership question is answered in
https://phab.enlightenment.org/D7516#137367.
Can we please get into a state of technical discussions, and not *oh
shit, i am going to revert this* this has been in review for a long
time, a lots of people have tested it, we discussed things on it, and
there was 3 weeks of no reply from you.
The issues that exist will be dealed with. Feel free to create tasks if
you want :)
2019-02-12 12:34:30 -08:00
cmd = efl_core_command_line_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:34:27 -08:00
// actually setenv the env object (clear what was there before so it is
2018-02-20 22:44:11 -08:00
// the only env there)
2019-02-12 12:34:27 -08:00
if ( pd - > env )
{
Eina_Iterator * itr ;
const char * key ;
2019-03-01 02:06:43 -08:00
# ifdef HAVE_CLEARENV
2019-02-12 12:34:27 -08:00
clearenv ( ) ;
2019-03-01 02:06:43 -08:00
# else
2019-06-03 17:14:20 -07:00
# if defined (__FreeBSD__) || defined (__OpenBSD__)
_dl_environ = dlsym ( NULL , " environ " ) ;
if ( _dl_environ ) * _dl_environ = NULL ;
else ERR ( " Can't find envrion symbol " ) ;
# else
2019-02-12 12:34:27 -08:00
environ = NULL ;
2019-06-03 17:14:20 -07:00
# endif
2019-03-01 02:06:43 -08:00
# endif
2019-02-12 12:34:27 -08:00
itr = efl_core_env_content_get ( pd - > env ) ;
EINA_ITERATOR_FOREACH ( itr , key )
{
setenv ( key , efl_core_env_get ( pd - > env , key ) , 1 ) ;
}
efl_unref ( pd - > env ) ;
pd - > 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 ) ;
2019-03-19 13:32:02 -07:00
efl_event_callback_call ( obj , EFL_IO_READER_EVENT_CAN_READ_CHANGED , & can_read ) ;
2018-02-20 22:44:11 -08:00
}
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 ) ;
2019-03-19 13:32:02 -07:00
efl_event_callback_call ( obj , EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED , & can_write ) ;
2018-02-20 22:44:11 -08:00
}
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"