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>
|
2020-01-14 18:35:11 -08:00
|
|
|
# elif defined(HAVE_PROCCTL)
|
|
|
|
# include <sys/procctl.h>
|
2018-02-20 22:44:11 -08:00
|
|
|
# endif
|
2020-01-14 18:35:11 -08:00
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
2018-02-20 22:44:11 -08:00
|
|
|
# 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
|
|
|
|
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;
|
2020-03-12 09:16:37 -07:00
|
|
|
Eina_Bool exit_signalled : 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
|
2019-08-26 05:46:32 -07:00
|
|
|
_exec(const char *cmd, Efl_Exe_Flags flags, Efl_Task_Flags task_flags)
|
2018-02-20 22:44:11 -08:00
|
|
|
{
|
|
|
|
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
|
2019-08-26 05:46:32 -07:00
|
|
|
if (task_flags & EFL_TASK_FLAGS_EXIT_WITH_PARENT)
|
2018-02-20 22:44:11 -08:00
|
|
|
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
2020-01-14 18:35:11 -08:00
|
|
|
#elif defined(HAVE_PROCCTL)
|
|
|
|
if (task_flags & EFL_TASK_FLAGS_EXIT_WITH_PARENT)
|
|
|
|
{
|
|
|
|
int sig = SIGTERM;
|
|
|
|
procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &sig);
|
|
|
|
}
|
|
|
|
#endif
|
2018-02-20 22:44:11 -08:00
|
|
|
|
|
|
|
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;
|
2019-09-10 15:01:19 -07:00
|
|
|
efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL);
|
|
|
|
efl_del(obj);
|
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);
|
|
|
|
}
|
|
|
|
#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)
|
|
|
|
{
|
2020-03-12 09:16:37 -07:00
|
|
|
case EFL_EXE_SIGNAL_INT: s = SIGINT; pd->exit_signalled = EINA_TRUE; break;
|
|
|
|
case EFL_EXE_SIGNAL_QUIT: s = SIGQUIT; pd->exit_signalled = EINA_TRUE; break;
|
|
|
|
case EFL_EXE_SIGNAL_TERM: s = SIGTERM; pd->exit_signalled = EINA_TRUE; break;
|
|
|
|
case EFL_EXE_SIGNAL_KILL: s = SIGKILL; pd->exit_signalled = EINA_TRUE; break;
|
2018-02-20 22:44:11 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-09-10 15:01:19 -07:00
|
|
|
EOLIAN static Eina_Bool
|
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
|
|
|
|
2019-09-10 15:01:19 -07:00
|
|
|
if (pd->run) return EINA_FALSE;
|
|
|
|
if (pd->pid != -1) return EINA_FALSE;
|
|
|
|
if (!td) return EINA_FALSE;
|
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);
|
2019-09-10 15:01:19 -07:00
|
|
|
if (!cmd) return EINA_FALSE;
|
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));
|
2019-09-10 15:01:19 -07:00
|
|
|
return EINA_FALSE;
|
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));
|
2019-09-10 15:01:19 -07:00
|
|
|
return EINA_FALSE;
|
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));
|
2019-09-10 15:01:19 -07:00
|
|
|
return EINA_FALSE;
|
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();
|
2019-09-10 15:01:19 -07:00
|
|
|
return EINA_FALSE;
|
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-09-10 15:01:19 -07:00
|
|
|
return EINA_TRUE;
|
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
|
|
|
|
2019-11-20 00:43:26 -08:00
|
|
|
// close all fd's other than the first 3 (0, 1, 2) and exited write fd
|
|
|
|
int except[2] = { 0, -1 };
|
|
|
|
except[0] = pd->fd.exited_write;
|
|
|
|
eina_file_close_from(3, except);
|
2020-03-12 09:15:34 -07:00
|
|
|
#ifdef HAVE_PRCTL
|
|
|
|
if ((pd->flags & EFL_EXE_FLAGS_TERM_WITH_PARENT))
|
|
|
|
{
|
|
|
|
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
|
|
|
}
|
|
|
|
#elif defined(HAVE_PROCCTL)
|
|
|
|
if ((pd->flags & EFL_EXE_FLAGS_TERM_WITH_PARENT))
|
|
|
|
{
|
|
|
|
int sig = SIGTERM;
|
|
|
|
procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &sig);
|
|
|
|
}
|
|
|
|
#endif
|
2018-02-20 22:44:11 -08:00
|
|
|
// actually execute!
|
2019-08-26 05:46:32 -07:00
|
|
|
_exec(cmd, pd->flags, td->flags);
|
2018-02-20 22:44:11 -08:00
|
|
|
// 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);
|
2019-09-10 15:01:19 -07:00
|
|
|
return EINA_FALSE;
|
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;
|
2020-03-12 09:16:37 -07:00
|
|
|
pd->exit_signalled = EINA_TRUE;
|
2018-02-20 22:44:11 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-03-12 09:15:20 -07:00
|
|
|
EOLIAN static int
|
|
|
|
_efl_exe_pid_get(const Eo *obj EINA_UNUSED, Efl_Exe_Data *pd)
|
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
if (pd->pid != -1)
|
|
|
|
return pd->pid;
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-02-20 22:44:11 -08:00
|
|
|
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;
|
2019-08-26 05:46:32 -07:00
|
|
|
pd->flags = 0;
|
2018-02-20 22:44:11 -08:00
|
|
|
pd->exit_signal = -1;
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
EOLIAN static void
|
|
|
|
_efl_exe_efl_object_destructor(Eo *obj, Efl_Exe_Data *pd)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
#else
|
2020-03-12 09:16:37 -07:00
|
|
|
if ((!pd->exit_called) && (!pd->exit_signalled))
|
2018-03-26 04:53:06 -07:00
|
|
|
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;
|
2019-10-18 10:30:03 -07:00
|
|
|
if (!slice) return EINVAL;
|
2018-02-20 22:44:11 -08:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2019-10-18 10:30:03 -07:00
|
|
|
if (slice->len > 0)
|
2018-02-20 22:44:11 -08:00
|
|
|
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"
|