2009-01-31 10:33:39 -08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2005-10-24 07:47:25 -07:00
|
|
|
#include <errno.h>
|
2009-01-31 10:33:39 -08:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
2012-06-21 22:36:00 -07:00
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/resource.h>
|
2011-10-11 11:19:37 -07:00
|
|
|
|
|
|
|
#ifdef HAVE_SYS_PRCTL_H
|
2011-10-07 18:17:19 -07:00
|
|
|
# include <sys/prctl.h>
|
|
|
|
#endif
|
2009-01-31 10:33:39 -08:00
|
|
|
|
2007-07-05 02:51:09 -07:00
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
2007-08-26 04:17:21 -07:00
|
|
|
# include <sys/wait.h>
|
2009-01-31 10:33:39 -08:00
|
|
|
#endif
|
|
|
|
|
2006-01-06 05:56:47 -08:00
|
|
|
#include "Ecore.h"
|
2009-12-22 13:15:12 -08:00
|
|
|
#include "ecore_private.h"
|
2005-10-24 07:47:25 -07:00
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
/* FIXME: Getting respawn to work
|
|
|
|
*
|
|
|
|
* There is no way that we can do anything about the internal state info of
|
|
|
|
* an external exe. The same can be said about the state of user code. User
|
|
|
|
* code in this context means the code that is using ecore_exe to manage exe's
|
|
|
|
* for it.
|
|
|
|
*
|
|
|
|
* Document that the exe must be respawnable, in other words, there is no
|
|
|
|
* state that it cannot regenerate by just killing it and starting it again.
|
|
|
|
* This includes state that the user code knows about, as the respawn is
|
|
|
|
* transparent to that code. On the other hand, maybe a respawn event might
|
|
|
|
* be useful, or maybe resend the currently non existent add event. For
|
|
|
|
* consistancy with ecore_con, an add event is good anyway.
|
|
|
|
*
|
|
|
|
* The Ecore_exe structure is reused for respawning, so that the (opaque)
|
|
|
|
* pointer held by the user remains valid. This means that the Ecore_Exe
|
|
|
|
* init and del functions may need to be split into two parts each to avoid
|
|
|
|
* duplicating code - common code part, and the rest. This implies that
|
|
|
|
* the unchanging members mentioned next should NEVER change.
|
|
|
|
*
|
|
|
|
* These structure members don't need to change -
|
|
|
|
* __list_data - we stay on the list
|
|
|
|
* ECORE_MAGIC - this is a constant
|
|
|
|
* data - passed in originally
|
|
|
|
* cmd - passed in originally
|
|
|
|
* flags - passed in originally
|
|
|
|
*
|
|
|
|
* These structure members need to change -
|
|
|
|
* tag - state that must be regenerated, zap it
|
|
|
|
* pid - it will be different
|
|
|
|
* child_fd_write - it will be different
|
|
|
|
* child_fd_read - it will be different
|
|
|
|
* child_fd_error - it will be different
|
|
|
|
* write_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes.
|
|
|
|
* read_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes.
|
|
|
|
* error_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes.
|
|
|
|
*
|
|
|
|
* Hmm, the read, write, and error buffers could be tricky.
|
|
|
|
* They are not atomic, and could be in a semi complete state.
|
|
|
|
* They fall into the "state must be regenerated" mentioned above.
|
|
|
|
* A respawn/add event should take care of it.
|
|
|
|
*
|
|
|
|
* These structure members need to change -
|
|
|
|
* write_data_buf - state that must be regenerated, zap it
|
|
|
|
* write_data_size - state that must be regenerated, zap it
|
|
|
|
* write_data_offset - state that must be regenerated, zap it
|
|
|
|
* read_data_buf - state that must be regenerated, zap it
|
|
|
|
* read_data_size - state that must be regenerated, zap it
|
|
|
|
* error_data_buf - state that must be regenerated, zap it
|
|
|
|
* error_data_size - state that must be regenerated, zap it
|
|
|
|
* close_write - state that must be regenerated, zap it
|
|
|
|
*
|
|
|
|
* There is the problem that an exe that fell over and needs respawning
|
|
|
|
* might keep falling over, keep needing to be respawned, and tie up system
|
|
|
|
* resources with the constant respawning. An exponentially increasing
|
|
|
|
* timeout (with maximum timeout) between respawns should take care of that.
|
|
|
|
* Although this is not a "contention for a resource" problem, the exe falling
|
|
|
|
* over may be, so a random element added to the timeout may help, and won't
|
|
|
|
* hurt. The user code may need to be informed that a timeout is in progress.
|
|
|
|
*/
|
2010-01-03 13:55:50 -08:00
|
|
|
|
|
|
|
struct _Ecore_Exe
|
|
|
|
{
|
|
|
|
EINA_INLIST;
|
2011-10-20 22:40:39 -07:00
|
|
|
ECORE_MAGIC;
|
|
|
|
pid_t pid;
|
|
|
|
void *data;
|
|
|
|
char *tag, *cmd;
|
|
|
|
Ecore_Exe_Flags flags;
|
2010-01-03 13:55:50 -08:00
|
|
|
Ecore_Fd_Handler *write_fd_handler; /* the fd_handler to handle write to child - if this was used, or NULL if not */
|
|
|
|
Ecore_Fd_Handler *read_fd_handler; /* the fd_handler to handle read from child - if this was used, or NULL if not */
|
|
|
|
Ecore_Fd_Handler *error_fd_handler; /* the fd_handler to handle errors from child - if this was used, or NULL if not */
|
2011-10-20 22:40:39 -07:00
|
|
|
void *write_data_buf; /* a data buffer for data to write to the child -
|
|
|
|
* realloced as needed for more data and flushed when the fd handler says writes are possible
|
|
|
|
*/
|
|
|
|
int write_data_size; /* the size in bytes of the data buffer */
|
|
|
|
int write_data_offset; /* the offset in bytes in the data buffer */
|
|
|
|
void *read_data_buf; /* data read from the child awating delivery to an event */
|
|
|
|
int read_data_size; /* data read from child in bytes */
|
|
|
|
void *error_data_buf; /* errors read from the child awating delivery to an event */
|
|
|
|
int error_data_size; /* errors read from child in bytes */
|
|
|
|
int child_fd_write; /* fd to write TO to send data to the child */
|
|
|
|
int child_fd_read; /* fd to read FROM when child has sent us (the parent) data */
|
|
|
|
int child_fd_error; /* fd to read FROM when child has sent us (the parent) errors */
|
|
|
|
int child_fd_write_x; /* fd to write TO to send data to the child */
|
|
|
|
int child_fd_read_x; /* fd to read FROM when child has sent us (the parent) data */
|
|
|
|
int child_fd_error_x; /* fd to read FROM when child has sent us (the parent) errors */
|
|
|
|
Eina_Bool close_stdin : 1;
|
|
|
|
|
|
|
|
int start_bytes, end_bytes, start_lines, end_lines; /* Number of bytes/lines to auto pipe at start/end of stdout/stderr. */
|
|
|
|
|
|
|
|
Ecore_Timer *doomsday_clock; /* The Timer of Death. Muahahahaha. */
|
|
|
|
void *doomsday_clock_dead; /* data for the doomsday clock */
|
|
|
|
|
|
|
|
Ecore_Exe_Cb pre_free_cb;
|
2010-01-03 13:55:50 -08:00
|
|
|
};
|
|
|
|
|
2006-04-05 18:16:02 -07:00
|
|
|
/* TODO: Something to let people build a command line and does auto escaping -
|
|
|
|
*
|
|
|
|
* ecore_exe_snprintf()
|
|
|
|
*
|
|
|
|
* OR
|
|
|
|
*
|
|
|
|
* cmd = ecore_exe_comand_parameter_append(cmd, "firefox");
|
|
|
|
* cmd = ecore_exe_comand_parameter_append(cmd, "http://www.foo.com/bar.html?baz=yes");
|
2007-08-26 04:17:21 -07:00
|
|
|
* each parameter appended is one argument, and it gets escaped, quoted, and
|
2010-09-08 04:23:42 -07:00
|
|
|
* appended with a preceding space. The first is the command off course.
|
2006-04-05 18:16:02 -07:00
|
|
|
*/
|
|
|
|
|
2006-01-01 12:09:47 -08:00
|
|
|
struct _ecore_exe_dead_exe
|
|
|
|
{
|
2010-01-08 11:49:05 -08:00
|
|
|
pid_t pid;
|
|
|
|
char *cmd;
|
2006-01-01 12:09:47 -08:00
|
|
|
};
|
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
static inline void _ecore_exe_exec_it(const char *exe_cmd,
|
|
|
|
Ecore_Exe_Flags flags);
|
|
|
|
static Eina_Bool _ecore_exe_data_generic_handler(void *data,
|
|
|
|
Ecore_Fd_Handler *fd_handler,
|
|
|
|
Ecore_Exe_Flags flags);
|
|
|
|
static Eina_Bool _ecore_exe_data_error_handler(void *data,
|
|
|
|
Ecore_Fd_Handler *fd_handler);
|
|
|
|
static Eina_Bool _ecore_exe_data_read_handler(void *data,
|
|
|
|
Ecore_Fd_Handler *fd_handler);
|
|
|
|
static Eina_Bool _ecore_exe_data_write_handler(void *data,
|
|
|
|
Ecore_Fd_Handler *fd_handler);
|
|
|
|
static void _ecore_exe_flush(Ecore_Exe *exe);
|
2012-11-25 01:55:32 -08:00
|
|
|
static void _ecore_exe_event_exe_data_free(void *data EINA_UNUSED,
|
2011-10-20 22:40:39 -07:00
|
|
|
void *ev);
|
|
|
|
static Ecore_Exe *_ecore_exe_is_it_alive(pid_t pid);
|
|
|
|
static Eina_Bool _ecore_exe_make_sure_its_dead(void *data);
|
|
|
|
static Eina_Bool _ecore_exe_make_sure_its_really_dead(void *data);
|
2006-01-13 05:18:36 -08:00
|
|
|
static Ecore_Exe_Event_Add *_ecore_exe_event_add_new(void);
|
2011-10-20 22:40:39 -07:00
|
|
|
static void _ecore_exe_event_add_free(void *data,
|
|
|
|
void *ev);
|
|
|
|
static void _ecore_exe_dead_attach(Ecore_Exe *exe);
|
2005-12-10 14:39:51 -08:00
|
|
|
|
2009-12-06 19:06:50 -08:00
|
|
|
EAPI int ECORE_EXE_EVENT_ADD = 0;
|
|
|
|
EAPI int ECORE_EXE_EVENT_DEL = 0;
|
|
|
|
EAPI int ECORE_EXE_EVENT_DATA = 0;
|
|
|
|
EAPI int ECORE_EXE_EVENT_ERROR = 0;
|
2003-09-23 01:09:32 -07:00
|
|
|
|
2009-12-06 19:06:50 -08:00
|
|
|
static Ecore_Exe *exes = NULL;
|
|
|
|
static const char *shell = NULL;
|
2005-12-24 04:13:12 -08:00
|
|
|
|
|
|
|
/* FIXME: This errno checking stuff should be put elsewhere for everybody to use.
|
|
|
|
* For now it lives here though, just to make testing easier.
|
|
|
|
*/
|
2011-10-20 22:40:39 -07:00
|
|
|
static int _ecore_exe_check_errno(int result,
|
|
|
|
const char *file,
|
|
|
|
int line);
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
#define E_IF_NO_ERRNO(result, foo, ok) \
|
|
|
|
while (((ok) = _ecore_exe_check_errno((result) = (foo), __FILE__, __LINE__)) == -1) sleep(1); \
|
|
|
|
if (ok)
|
2005-12-24 04:13:12 -08:00
|
|
|
|
|
|
|
#define E_NO_ERRNO(result, foo, ok) \
|
2011-10-20 22:40:39 -07:00
|
|
|
while (((ok) = _ecore_exe_check_errno((result) = (foo), __FILE__, __LINE__)) == -1) sleep(1)
|
2005-12-24 04:13:12 -08:00
|
|
|
|
|
|
|
#define E_IF_NO_ERRNO_NOLOOP(result, foo, ok) \
|
2011-10-20 22:40:39 -07:00
|
|
|
if (((ok) = _ecore_exe_check_errno((result) = (foo), __FILE__, __LINE__)))
|
2005-12-24 04:13:12 -08:00
|
|
|
|
2006-01-06 09:58:12 -08:00
|
|
|
static int
|
2011-10-20 22:40:39 -07:00
|
|
|
_ecore_exe_check_errno(int result,
|
2012-11-25 01:55:32 -08:00
|
|
|
const char *file EINA_UNUSED,
|
|
|
|
int line EINA_UNUSED)
|
2005-12-24 04:13:12 -08:00
|
|
|
{
|
2009-12-06 19:06:50 -08:00
|
|
|
int saved_errno = errno;
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2005-12-24 04:13:12 -08:00
|
|
|
if (result == -1)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
perror("*** errno reports ");
|
2005-12-24 04:13:12 -08:00
|
|
|
/* What is currently supported -
|
|
|
|
*
|
|
|
|
* pipe
|
|
|
|
* EFAULT Argument is not valid.
|
|
|
|
* EMFILE Too many file descriptors used by process.
|
|
|
|
* ENFILE Too many open files by system.
|
|
|
|
* read
|
|
|
|
* EAGAIN No data now, try again.
|
|
|
|
* EBADF This is not an fd that can be read.
|
|
|
|
* EFAULT This is not a valid buffer.
|
|
|
|
* EINTR Interupted by signal, try again.
|
|
|
|
* EINVAL This is not an fd that can be read.
|
|
|
|
* EIO I/O error.
|
|
|
|
* EISDIR This is a directory, and cannot be read.
|
|
|
|
* others Depending on what sort of thing we are reading from.
|
|
|
|
* close
|
|
|
|
* EBADF This is not an fd that can be closed.
|
|
|
|
* EINTR Interupted by signal, try again.
|
|
|
|
* EIO I/O error.
|
|
|
|
* dup2
|
|
|
|
* EBADF This is not an fd that can be dup2'ed.
|
|
|
|
* EBUSY Race condition between open() and dup()
|
|
|
|
* EINTR Interupted by signal, try again.
|
|
|
|
* EMFILE Too many file descriptors used by process.
|
|
|
|
* fcntl
|
|
|
|
* EACCES, EAGAIN Locked or mapped by something else, try again later.
|
|
|
|
* EBADF This is not an fd that can be fcntl'ed.
|
|
|
|
* EDEADLK This will cause a deadlock.
|
|
|
|
* EFAULT This is not a valid lock.
|
|
|
|
* EINTR Interupted by signal, try again.
|
|
|
|
* EINVAL This is not a valid arg.
|
|
|
|
* EMFILE Too many file descriptors used by process.
|
|
|
|
* ENOLCK Problem getting a lock.
|
|
|
|
* EPERM Not allowed to do that.
|
2005-12-30 11:17:21 -08:00
|
|
|
* fsync
|
|
|
|
* EBADF This is not an fd that is open for writing.
|
|
|
|
* EINVAL, EROFS This is not an fd that can be fsynced.
|
|
|
|
* EIO I/O error.
|
2005-12-24 04:13:12 -08:00
|
|
|
*
|
|
|
|
* How to use it -
|
|
|
|
* int ok = 0;
|
|
|
|
* int result;
|
|
|
|
*
|
|
|
|
* E_IF_NO_ERRNO(result, foo(bar), ok)
|
|
|
|
* {
|
|
|
|
* E_IF_NO_ERRNO_NOLOOP(result, foo(bar), ok)
|
|
|
|
* {
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* if (!ok)
|
|
|
|
* {
|
|
|
|
* // Something failed, cleanup.
|
|
|
|
* }
|
|
|
|
*/
|
2011-10-20 22:40:39 -07:00
|
|
|
switch (saved_errno)
|
|
|
|
{
|
|
|
|
case EACCES:
|
|
|
|
case EAGAIN:
|
|
|
|
case EINTR:
|
|
|
|
{ /* Not now, try later. */
|
|
|
|
ERR("*** Must try again in %s @%u.", file, line);
|
|
|
|
result = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EMFILE:
|
|
|
|
case ENFILE:
|
|
|
|
case ENOLCK:
|
|
|
|
{ /* Low on resources. */
|
|
|
|
ERR("*** Low on resources in %s @%u.", file,
|
|
|
|
line);
|
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EIO:
|
|
|
|
{ /* I/O error. */
|
|
|
|
ERR("*** I/O error in %s @%u.", file, line);
|
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EFAULT:
|
|
|
|
case EBADF:
|
|
|
|
case EINVAL:
|
|
|
|
case EROFS:
|
|
|
|
case EISDIR:
|
|
|
|
case EDEADLK:
|
|
|
|
case EPERM:
|
|
|
|
case EBUSY:
|
|
|
|
{ /* Programmer fucked up. */
|
|
|
|
ERR("*** NAUGHTY PROGRAMMER!!!\n"
|
|
|
|
"*** SPANK SPANK SPANK!!!\n"
|
|
|
|
"*** Now go fix your code in %s @%u. Tut tut tut!",
|
|
|
|
file, line);
|
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
{ /* Unsupported errno code, please add this one. */
|
|
|
|
ERR("*** NAUGHTY PROGRAMMER!!!\n"
|
|
|
|
"*** SPANK SPANK SPANK!!!\n"
|
|
|
|
"*** Unsupported errno code %d, please add this one.\n"
|
|
|
|
"*** Now go fix your code in %s @%u, from %s @%u. Tut tut tut!",
|
|
|
|
saved_errno, __FILE__, __LINE__, file, line);
|
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-01-08 11:49:05 -08:00
|
|
|
else /* Everything is fine. */
|
|
|
|
result = 1;
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2005-12-24 04:13:12 -08:00
|
|
|
errno = saved_errno;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2010-10-17 00:03:28 -07:00
|
|
|
/**
|
2011-08-10 12:14:48 -07:00
|
|
|
* @addtogroup Ecore_Exe_Group
|
2004-09-21 21:25:35 -07:00
|
|
|
*
|
2010-10-17 00:03:28 -07:00
|
|
|
* @{
|
2004-09-21 21:25:35 -07:00
|
|
|
*/
|
|
|
|
|
2008-11-01 18:29:08 -07:00
|
|
|
static int run_pri = ECORE_EXE_PRIORITY_INHERIT;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the priority at which to launch processes
|
|
|
|
*
|
2008-11-29 03:23:17 -08:00
|
|
|
* This sets the priority of processes run by ecore_exe_run() and
|
2010-02-20 01:20:04 -08:00
|
|
|
* ecore_exe_pipe_run().
|
|
|
|
* @li On Windows, the child process is created by default with the
|
2012-03-05 06:59:55 -08:00
|
|
|
* @ref ECORE_EXE_WIN32_PRIORITY_NORMAL priority, unless the calling
|
|
|
|
* process is in @ref ECORE_EXE_WIN32_PRIORITY_IDLE or
|
|
|
|
* @ref ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL priority. In that case, the
|
2010-02-20 01:20:04 -08:00
|
|
|
* child process inherits this priority.
|
2012-03-05 06:59:55 -08:00
|
|
|
* @li On other platforms, if set to @ref ECORE_EXE_PRIORITY_INHERIT child
|
2010-02-20 01:20:04 -08:00
|
|
|
* processes inherits the priority of their parent. This is the default.
|
2008-11-29 03:23:17 -08:00
|
|
|
*
|
2010-02-20 01:20:04 -08:00
|
|
|
* @param pri value a Ecore_Exe_Win32_Priority value on Windows, -20
|
2012-03-05 06:59:55 -08:00
|
|
|
* to 19 or @ref ECORE_EXE_PRIORITY_INHERIT on other OS.
|
2008-11-01 18:29:08 -07:00
|
|
|
*/
|
|
|
|
EAPI void
|
|
|
|
ecore_exe_run_priority_set(int pri)
|
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2008-11-01 18:29:08 -07:00
|
|
|
run_pri = pri;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the priority at which to launch processes
|
|
|
|
*
|
2008-11-29 03:23:17 -08:00
|
|
|
* This gets ths priority of launched processes. See
|
2008-11-01 18:29:08 -07:00
|
|
|
* ecore_exe_run_priority_set() for details. This just returns the value set
|
|
|
|
* by this call.
|
2008-11-29 03:23:17 -08:00
|
|
|
*
|
2008-11-01 18:29:08 -07:00
|
|
|
* @return the value set by ecore_exe_run_priority_set()
|
|
|
|
*/
|
|
|
|
EAPI int
|
|
|
|
ecore_exe_run_priority_get(void)
|
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
|
2008-11-01 18:29:08 -07:00
|
|
|
return run_pri;
|
|
|
|
}
|
|
|
|
|
2004-09-21 21:25:35 -07:00
|
|
|
/**
|
|
|
|
* Spawns a child process.
|
|
|
|
*
|
2006-01-10 08:46:07 -08:00
|
|
|
* This is now just a thin wrapper around ecore_exe_pipe_run()
|
2012-05-16 10:23:51 -07:00
|
|
|
* @note When you use this function you will have no permissions
|
|
|
|
* to write or read on the pipe that connects you with the spwaned process.
|
|
|
|
* If you need to do that use ecore_exe_pipe_run() with the
|
|
|
|
* appropriated flags.
|
2004-09-21 21:25:35 -07:00
|
|
|
*
|
|
|
|
* @param exe_cmd The command to run with @c /bin/sh.
|
|
|
|
* @param data Data to attach to the returned process handle.
|
|
|
|
* @return A process handle to the spawned process.
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
2009-12-06 19:06:50 -08:00
|
|
|
EAPI Ecore_Exe *
|
2011-10-20 22:40:39 -07:00
|
|
|
ecore_exe_run(const char *exe_cmd,
|
|
|
|
const void *data)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
2006-01-10 08:46:07 -08:00
|
|
|
return ecore_exe_pipe_run(exe_cmd, 0, data);
|
2003-09-23 01:09:32 -07:00
|
|
|
}
|
|
|
|
|
2005-10-24 01:53:50 -07:00
|
|
|
/**
|
|
|
|
* Spawns a child process with its stdin/out available for communication.
|
|
|
|
*
|
2006-01-10 08:46:07 -08:00
|
|
|
* This function forks and runs the given command using @c /bin/sh.
|
|
|
|
*
|
|
|
|
* Note that the process handle is only valid until a child process
|
|
|
|
* terminated event is received. After all handlers for the child process
|
|
|
|
* terminated event have been called, the handle will be freed by Ecore.
|
|
|
|
*
|
2005-10-24 01:53:50 -07:00
|
|
|
* This function does the same thing as ecore_exe_run(), but also makes the
|
2008-01-10 23:33:57 -08:00
|
|
|
* standard in and/or out as well as stderr from the child process available
|
2006-01-10 08:46:07 -08:00
|
|
|
* for reading or writing. To write use ecore_exe_send(). To read listen to
|
2007-08-26 04:17:21 -07:00
|
|
|
* ECORE_EXE_EVENT_DATA or ECORE_EXE_EVENT_ERROR events (set up handlers).
|
|
|
|
* Ecore may buffer read and error data until a newline character if asked
|
|
|
|
* for with the @p flags. All data will be included in the events (newlines
|
|
|
|
* will be replaced with NULLS if line buffered). ECORE_EXE_EVENT_DATA events
|
|
|
|
* will only happen if the process is run with ECORE_EXE_PIPE_READ enabled
|
|
|
|
* in the flags. The same with the error version. Writing will only be
|
2006-01-10 08:46:07 -08:00
|
|
|
* allowed with ECORE_EXE_PIPE_WRITE enabled in the flags.
|
2005-12-15 19:36:16 -08:00
|
|
|
*
|
2005-10-24 01:53:50 -07:00
|
|
|
* @param exe_cmd The command to run with @c /bin/sh.
|
|
|
|
* @param flags The flag parameters for how to deal with inter-process I/O
|
|
|
|
* @param data Data to attach to the returned process handle.
|
|
|
|
* @return A process handle to the spawned process.
|
|
|
|
*/
|
2009-12-06 19:06:50 -08:00
|
|
|
EAPI Ecore_Exe *
|
2011-10-20 22:40:39 -07:00
|
|
|
ecore_exe_pipe_run(const char *exe_cmd,
|
|
|
|
Ecore_Exe_Flags flags,
|
|
|
|
const void *data)
|
2005-10-24 01:53:50 -07:00
|
|
|
{
|
2009-12-06 19:06:50 -08:00
|
|
|
Ecore_Exe *exe = NULL;
|
|
|
|
int statusPipe[2] = { -1, -1 };
|
|
|
|
int errorPipe[2] = { -1, -1 };
|
|
|
|
int readPipe[2] = { -1, -1 };
|
|
|
|
int writePipe[2] = { -1, -1 };
|
|
|
|
int n = 0;
|
|
|
|
int ok = 1;
|
|
|
|
int result;
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
2008-01-10 23:33:57 -08:00
|
|
|
if (!exe_cmd) return NULL;
|
2005-11-09 06:09:28 -08:00
|
|
|
exe = calloc(1, sizeof(Ecore_Exe));
|
2010-08-21 06:52:25 -07:00
|
|
|
if (!exe) return NULL;
|
2006-02-28 21:05:58 -08:00
|
|
|
|
|
|
|
if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR))
|
|
|
|
&& (!(flags & ECORE_EXE_PIPE_READ)))
|
2008-01-10 23:33:57 -08:00
|
|
|
/* We need something to auto pipe. */
|
2008-11-29 03:23:17 -08:00
|
|
|
flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR;
|
2006-01-17 03:33:39 -08:00
|
|
|
|
2006-02-14 04:54:26 -08:00
|
|
|
exe->child_fd_error = -1;
|
|
|
|
exe->child_fd_read = -1;
|
|
|
|
exe->child_fd_write = -1;
|
2006-02-14 20:55:14 -08:00
|
|
|
exe->child_fd_error_x = -1;
|
|
|
|
exe->child_fd_read_x = -1;
|
|
|
|
exe->child_fd_write_x = -1;
|
|
|
|
|
2005-12-24 04:13:12 -08:00
|
|
|
/* Create some pipes. */
|
2006-02-28 21:05:58 -08:00
|
|
|
if (ok)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
E_IF_NO_ERRNO_NOLOOP(result, pipe(statusPipe), ok)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
2006-01-17 03:33:39 -08:00
|
|
|
if (ok && (flags & ECORE_EXE_PIPE_ERROR))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
E_IF_NO_ERRNO_NOLOOP(result, pipe(errorPipe), ok)
|
|
|
|
{
|
|
|
|
exe->child_fd_error = errorPipe[0];
|
|
|
|
exe->child_fd_error_x = errorPipe[1];
|
|
|
|
}
|
|
|
|
}
|
2006-01-17 03:33:39 -08:00
|
|
|
if (ok && (flags & ECORE_EXE_PIPE_READ))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
E_IF_NO_ERRNO_NOLOOP(result, pipe(readPipe), ok)
|
|
|
|
{
|
|
|
|
exe->child_fd_read = readPipe[0];
|
|
|
|
exe->child_fd_read_x = readPipe[1];
|
|
|
|
}
|
|
|
|
}
|
2006-01-17 03:33:39 -08:00
|
|
|
if (ok && (flags & ECORE_EXE_PIPE_WRITE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
E_IF_NO_ERRNO_NOLOOP(result, pipe(writePipe), ok)
|
|
|
|
{
|
|
|
|
exe->child_fd_write = writePipe[1];
|
|
|
|
exe->child_fd_write_x = writePipe[0];
|
|
|
|
}
|
|
|
|
}
|
2006-01-10 08:46:07 -08:00
|
|
|
if (ok)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
pid_t pid = 0;
|
|
|
|
volatile int vfork_exec_errno = 0;
|
|
|
|
|
|
|
|
/* FIXME: I should double check this. After a quick look around, this is already done, but via a more modern method. */
|
|
|
|
/* signal(SIGPIPE, SIG_IGN); We only want EPIPE on errors */
|
|
|
|
pid = fork();
|
|
|
|
|
|
|
|
if (pid == -1)
|
|
|
|
{
|
|
|
|
ERR("Failed to fork process");
|
|
|
|
pid = 0;
|
|
|
|
}
|
|
|
|
else if (pid == 0) /* child */
|
|
|
|
{
|
|
|
|
if (run_pri != ECORE_EXE_PRIORITY_INHERIT)
|
|
|
|
{
|
2012-07-18 04:54:32 -07:00
|
|
|
#ifdef PRIO_PROCESS
|
2011-10-20 22:40:39 -07:00
|
|
|
if ((run_pri >= -20) && (run_pri <= 19))
|
|
|
|
setpriority(PRIO_PROCESS, 0, run_pri);
|
2012-07-18 04:54:32 -07:00
|
|
|
#else
|
|
|
|
#warning "Your OS/libc does not provide PRIO_PROCESS (and possibly setpriority())"
|
|
|
|
#warning "This is a POSIX-1.2001 standard and it is highly encouraged that you"
|
|
|
|
#warning "Have support for this"
|
|
|
|
#endif
|
2011-10-20 22:40:39 -07:00
|
|
|
}
|
|
|
|
/* dup2 STDERR, STDIN, and STDOUT. dup2() allegedly closes the
|
|
|
|
* second pipe if it's open. On the other hand, there was the
|
|
|
|
* Great FD Leak Scare of '06, so let's be paranoid. */
|
|
|
|
if (ok && (flags & ECORE_EXE_PIPE_ERROR))
|
|
|
|
{
|
|
|
|
E_NO_ERRNO(result, close(STDERR_FILENO), ok);
|
|
|
|
E_NO_ERRNO(result, dup2(errorPipe[1], STDERR_FILENO), ok);
|
|
|
|
}
|
|
|
|
if (ok && (flags & ECORE_EXE_PIPE_READ))
|
|
|
|
{
|
|
|
|
E_NO_ERRNO(result, close(STDOUT_FILENO), ok);
|
|
|
|
E_NO_ERRNO(result, dup2(readPipe[1], STDOUT_FILENO), ok);
|
|
|
|
}
|
|
|
|
if (ok && (flags & ECORE_EXE_PIPE_WRITE))
|
|
|
|
{
|
|
|
|
E_NO_ERRNO(result, close(STDIN_FILENO), ok);
|
|
|
|
E_NO_ERRNO(result, dup2(writePipe[0], STDIN_FILENO), ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
/* Setup the status pipe. */
|
2010-09-29 23:09:20 -07:00
|
|
|
E_NO_ERRNO(result, close(statusPipe[0]), ok);
|
2011-10-20 22:40:39 -07:00
|
|
|
E_IF_NO_ERRNO(result, fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC), ok) /* close on exec shows success */
|
|
|
|
{
|
|
|
|
/* Run the actual command. */
|
|
|
|
_ecore_exe_exec_it(exe_cmd, flags); /* no return */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Something went 'orribly wrong. */
|
|
|
|
vfork_exec_errno = errno;
|
|
|
|
|
|
|
|
/* Close the pipes. */
|
|
|
|
if (flags & ECORE_EXE_PIPE_ERROR)
|
|
|
|
E_NO_ERRNO(result, close(errorPipe[1]), ok);
|
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
|
|
|
E_NO_ERRNO(result, close(readPipe[1]), ok);
|
|
|
|
if (flags & ECORE_EXE_PIPE_WRITE)
|
|
|
|
E_NO_ERRNO(result, close(writePipe[0]), ok);
|
|
|
|
E_NO_ERRNO(result, close(statusPipe[1]), ok);
|
|
|
|
|
|
|
|
_exit(-1);
|
|
|
|
}
|
|
|
|
else /* parent */
|
|
|
|
{
|
|
|
|
/* Close the unused pipes. */
|
|
|
|
E_NO_ERRNO(result, close(statusPipe[1]), ok);
|
|
|
|
|
|
|
|
/* FIXME: after having a good look at the current e fd
|
|
|
|
* handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */
|
|
|
|
/* FIXME: above F_SETSIG etc. - this is async SIGIO based IO
|
|
|
|
* which is also linux specific so we probably don't want to
|
|
|
|
* do this as long as select() is working fine. the only time
|
|
|
|
* we really want to think of SIGIO async IO is when it all
|
|
|
|
* actually works basically everywhere and we can turn all
|
|
|
|
* IO into DMA async activities (i.e. you do a read() then
|
|
|
|
* the read is complete not on return but when you get a
|
|
|
|
* SIGIO - the read() just starts the transfer and it is
|
|
|
|
* completed in the background by DMA (or whatever mechanism
|
|
|
|
* the kernel choses)) */
|
|
|
|
|
|
|
|
/* Wait for it to start executing. */
|
|
|
|
/* FIXME: this doesn't seem very nice - we sit and block
|
|
|
|
* waiting on a child process... even though it's just
|
|
|
|
* the segment between the fork() and the exec) it just feels
|
|
|
|
* wrong */
|
|
|
|
for (;; )
|
|
|
|
{
|
|
|
|
char buf;
|
|
|
|
|
|
|
|
E_NO_ERRNO(result, read(statusPipe[0], &buf, 1), ok);
|
|
|
|
if (result == 0)
|
|
|
|
{
|
|
|
|
if (vfork_exec_errno != 0)
|
|
|
|
{
|
|
|
|
n = vfork_exec_errno;
|
|
|
|
ERR("Could not start \"%s\"", exe_cmd);
|
|
|
|
pid = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2010-09-29 23:09:20 -07:00
|
|
|
}
|
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
/* Close the status pipe. */
|
|
|
|
E_NO_ERRNO(result, close(statusPipe[0]), ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pid)
|
|
|
|
{
|
|
|
|
/* Setup the exe structure. */
|
|
|
|
ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE);
|
|
|
|
exe->start_bytes = -1;
|
|
|
|
exe->end_bytes = -1;
|
|
|
|
exe->start_lines = -1;
|
|
|
|
exe->end_lines = -1;
|
|
|
|
exe->pid = pid;
|
|
|
|
exe->flags = flags;
|
|
|
|
exe->data = (void *)data;
|
|
|
|
if ((exe->cmd = strdup(exe_cmd)))
|
2010-09-29 23:09:20 -07:00
|
|
|
{
|
2011-10-20 22:40:39 -07:00
|
|
|
if (flags & ECORE_EXE_PIPE_ERROR) /* Setup the error stuff. */
|
|
|
|
{
|
|
|
|
E_IF_NO_ERRNO(result,
|
|
|
|
fcntl(exe->child_fd_error, F_SETFL,
|
|
|
|
O_NONBLOCK), ok) {
|
|
|
|
}
|
|
|
|
E_IF_NO_ERRNO(result,
|
|
|
|
fcntl(exe->child_fd_error, F_SETFD,
|
|
|
|
FD_CLOEXEC), ok) {
|
|
|
|
}
|
|
|
|
E_IF_NO_ERRNO(result,
|
|
|
|
fcntl(exe->child_fd_error_x, F_SETFD,
|
|
|
|
FD_CLOEXEC), ok) {
|
|
|
|
}
|
|
|
|
{
|
|
|
|
exe->error_fd_handler =
|
|
|
|
ecore_main_fd_handler_add(exe->child_fd_error,
|
|
|
|
ECORE_FD_READ,
|
|
|
|
_ecore_exe_data_error_handler,
|
|
|
|
exe, NULL, NULL);
|
|
|
|
if (!exe->error_fd_handler)
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ok && (flags & ECORE_EXE_PIPE_READ)) /* Setup the read stuff. */
|
|
|
|
{
|
|
|
|
E_IF_NO_ERRNO(result,
|
|
|
|
fcntl(exe->child_fd_read, F_SETFL,
|
|
|
|
O_NONBLOCK), ok) {
|
|
|
|
}
|
|
|
|
E_IF_NO_ERRNO(result,
|
|
|
|
fcntl(exe->child_fd_read, F_SETFD,
|
|
|
|
FD_CLOEXEC), ok) {
|
|
|
|
}
|
|
|
|
E_IF_NO_ERRNO(result,
|
|
|
|
fcntl(exe->child_fd_read_x, F_SETFD,
|
|
|
|
FD_CLOEXEC), ok) {
|
|
|
|
}
|
|
|
|
{
|
|
|
|
exe->read_fd_handler =
|
|
|
|
ecore_main_fd_handler_add(exe->child_fd_read,
|
|
|
|
ECORE_FD_READ,
|
|
|
|
_ecore_exe_data_read_handler,
|
|
|
|
exe, NULL, NULL);
|
|
|
|
if (!exe->read_fd_handler)
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ok && (flags & ECORE_EXE_PIPE_WRITE)) /* Setup the write stuff. */
|
|
|
|
{
|
|
|
|
E_IF_NO_ERRNO(result,
|
|
|
|
fcntl(exe->child_fd_write, F_SETFL,
|
|
|
|
O_NONBLOCK), ok) {
|
|
|
|
}
|
|
|
|
E_IF_NO_ERRNO(result,
|
|
|
|
fcntl(exe->child_fd_write, F_SETFD,
|
|
|
|
FD_CLOEXEC), ok) {
|
|
|
|
}
|
|
|
|
E_IF_NO_ERRNO(result,
|
|
|
|
fcntl(exe->child_fd_write_x, F_SETFD,
|
|
|
|
FD_CLOEXEC), ok) {
|
|
|
|
}
|
|
|
|
{
|
|
|
|
exe->write_fd_handler =
|
|
|
|
ecore_main_fd_handler_add(exe->child_fd_write,
|
|
|
|
ECORE_FD_WRITE,
|
|
|
|
_ecore_exe_data_write_handler,
|
|
|
|
exe, NULL, NULL);
|
|
|
|
if (exe->write_fd_handler)
|
|
|
|
ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); /* Nothing to write to start with. */
|
|
|
|
else
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
exes = (Ecore_Exe *)eina_inlist_append(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe));
|
|
|
|
n = 0;
|
2010-09-29 23:09:20 -07:00
|
|
|
}
|
2011-10-20 22:40:39 -07:00
|
|
|
else
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ok) /* Something went wrong, so pull down everything. */
|
|
|
|
{
|
|
|
|
if (exe->pid) ecore_exe_terminate(exe);
|
|
|
|
IF_FN_DEL(ecore_exe_free, exe);
|
|
|
|
}
|
2005-12-30 11:28:54 -08:00
|
|
|
else
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
Ecore_Exe_Event_Add *e;
|
2010-09-29 23:09:20 -07:00
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
e = _ecore_exe_event_add_new();
|
|
|
|
e->exe = exe;
|
|
|
|
if (e) /* Send the event. */
|
|
|
|
ecore_event_add(ECORE_EXE_EVENT_ADD, e,
|
|
|
|
_ecore_exe_event_add_free, NULL);
|
|
|
|
/* INF("Running as %d for %s.\n", exe->pid, exe->cmd); */
|
|
|
|
}
|
2008-11-29 03:23:17 -08:00
|
|
|
|
2005-12-24 04:13:12 -08:00
|
|
|
errno = n;
|
2005-10-25 00:30:29 -07:00
|
|
|
return exe;
|
2005-10-24 01:53:50 -07:00
|
|
|
}
|
|
|
|
|
2010-01-05 21:16:59 -08:00
|
|
|
/**
|
|
|
|
* Defines a function to be called before really freeing the handle data.
|
|
|
|
*
|
|
|
|
* This might be useful for language bindings such as Python and Perl
|
|
|
|
* that need to deallocate wrappers associated with this handle.
|
|
|
|
*
|
|
|
|
* This handle should never be modified by this call. It should be
|
|
|
|
* considered informative only. All getters are valid when the given
|
|
|
|
* function is called back.
|
|
|
|
*
|
|
|
|
* @param exe The child process to attach the pre_free function.
|
|
|
|
* @param func The function to call before @a exe is freed.
|
|
|
|
*/
|
|
|
|
EAPI void
|
2011-10-20 22:40:39 -07:00
|
|
|
ecore_exe_callback_pre_free_set(Ecore_Exe *exe,
|
|
|
|
Ecore_Exe_Cb func)
|
2010-01-05 21:16:59 -08:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2010-01-05 21:16:59 -08:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_callback_pre_free_set");
|
|
|
|
return;
|
|
|
|
}
|
2010-01-05 21:16:59 -08:00
|
|
|
exe->pre_free_cb = func;
|
|
|
|
}
|
|
|
|
|
2005-10-24 01:53:50 -07:00
|
|
|
/**
|
2010-09-08 04:23:42 -07:00
|
|
|
* Sends data to the given child process which it receives on stdin.
|
2007-08-26 04:17:21 -07:00
|
|
|
*
|
2005-10-24 01:53:50 -07:00
|
|
|
* This function writes to a child processes standard in, with unlimited
|
|
|
|
* buffering. This call will never block. It may fail if the system runs out
|
|
|
|
* of memory.
|
2007-08-26 04:17:21 -07:00
|
|
|
*
|
2006-01-04 12:33:58 -08:00
|
|
|
* @param exe The child process to send to
|
2006-01-04 12:28:12 -08:00
|
|
|
* @param data The data to send
|
|
|
|
* @param size The size of the data to send, in bytes
|
2012-04-11 20:51:36 -07:00
|
|
|
* @return @c EINA_TRUE if successful, @c EINA_FALSE on failure.
|
2005-10-24 01:53:50 -07:00
|
|
|
*/
|
2010-01-05 21:16:59 -08:00
|
|
|
EAPI Eina_Bool
|
2011-10-20 22:40:39 -07:00
|
|
|
ecore_exe_send(Ecore_Exe *exe,
|
|
|
|
const void *data,
|
|
|
|
int size)
|
2005-10-24 01:53:50 -07:00
|
|
|
{
|
2009-12-06 19:06:50 -08:00
|
|
|
void *buf;
|
2005-12-10 14:39:51 -08:00
|
|
|
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(EINA_FALSE);
|
2010-01-05 21:16:59 -08:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_send");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
2010-01-05 21:16:59 -08:00
|
|
|
|
|
|
|
if (exe->close_stdin)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ERR("Ecore_Exe %p stdin is closed! Cannot send %d bytes from %p",
|
|
|
|
exe, size, data);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
2010-01-05 21:16:59 -08:00
|
|
|
|
|
|
|
if (exe->child_fd_write == -1)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ERR("Ecore_Exe %p created without ECORE_EXE_PIPE_WRITE! "
|
|
|
|
"Cannot send %d bytes from %p", exe, size, data);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
2010-01-05 21:16:59 -08:00
|
|
|
|
2005-12-10 14:39:51 -08:00
|
|
|
buf = realloc(exe->write_data_buf, exe->write_data_size + size);
|
2010-08-21 06:52:25 -07:00
|
|
|
if (!buf) return EINA_FALSE;
|
2005-12-10 14:39:51 -08:00
|
|
|
|
|
|
|
exe->write_data_buf = buf;
|
2006-11-05 08:42:30 -08:00
|
|
|
memcpy((char *)exe->write_data_buf + exe->write_data_size, data, size);
|
2005-12-10 14:39:51 -08:00
|
|
|
exe->write_data_size += size;
|
2005-12-10 16:11:12 -08:00
|
|
|
|
|
|
|
if (exe->write_fd_handler)
|
2011-10-20 22:40:39 -07:00
|
|
|
ecore_main_fd_handler_active_set(exe->write_fd_handler, ECORE_FD_WRITE);
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2010-06-24 09:15:56 -07:00
|
|
|
return EINA_TRUE;
|
2005-10-24 01:53:50 -07:00
|
|
|
}
|
|
|
|
|
2005-12-30 11:17:21 -08:00
|
|
|
/**
|
2006-01-04 12:53:07 -08:00
|
|
|
* The stdin of the given child process will close when the write buffer is empty.
|
2007-08-26 04:17:21 -07:00
|
|
|
*
|
2006-01-04 12:53:07 -08:00
|
|
|
* @param exe The child process
|
2005-12-30 11:17:21 -08:00
|
|
|
*/
|
2006-01-06 09:58:12 -08:00
|
|
|
EAPI void
|
2009-12-06 19:06:50 -08:00
|
|
|
ecore_exe_close_stdin(Ecore_Exe *exe)
|
2005-12-30 11:17:21 -08:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2005-12-30 11:17:21 -08:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_close_stdin");
|
|
|
|
return;
|
|
|
|
}
|
2006-01-04 12:53:07 -08:00
|
|
|
exe->close_stdin = 1;
|
2005-12-30 11:17:21 -08:00
|
|
|
}
|
|
|
|
|
2006-01-16 05:21:52 -08:00
|
|
|
/**
|
2010-02-20 01:35:48 -08:00
|
|
|
* Sets the auto pipe limits for the given process handle. On Windows
|
|
|
|
* this function does nothing.
|
2006-01-16 05:21:52 -08:00
|
|
|
*
|
|
|
|
* @param exe The given process handle.
|
|
|
|
* @param start_bytes limit of bytes at start of output to buffer.
|
|
|
|
* @param end_bytes limit of bytes at end of output to buffer.
|
|
|
|
* @param start_lines limit of lines at start of output to buffer.
|
2006-05-06 23:14:03 -07:00
|
|
|
* @param end_lines limit of lines at end of output to buffer.
|
2006-01-16 05:21:52 -08:00
|
|
|
*/
|
|
|
|
EAPI void
|
2011-10-20 22:40:39 -07:00
|
|
|
ecore_exe_auto_limits_set(Ecore_Exe *exe,
|
|
|
|
int start_bytes,
|
|
|
|
int end_bytes,
|
|
|
|
int start_lines,
|
|
|
|
int end_lines)
|
2006-01-16 05:21:52 -08:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2006-01-16 05:21:52 -08:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_auto_limits_set");
|
|
|
|
return;
|
|
|
|
}
|
2006-01-16 05:21:52 -08:00
|
|
|
/* FIXME: sanitize the input. */
|
|
|
|
exe->start_bytes = start_bytes;
|
2006-02-28 21:05:58 -08:00
|
|
|
exe->end_bytes = end_bytes;
|
2006-01-16 05:21:52 -08:00
|
|
|
exe->start_lines = start_lines;
|
2006-02-28 21:05:58 -08:00
|
|
|
exe->end_lines = end_lines;
|
2006-01-16 05:21:52 -08:00
|
|
|
|
|
|
|
/* FIXME: get this can of worms working.
|
|
|
|
*
|
|
|
|
* capture stderr & stdout internally
|
|
|
|
*
|
2007-08-26 04:17:21 -07:00
|
|
|
* raster and onefang keep moving the goal posts on this one. It started out as
|
2006-01-16 05:21:52 -08:00
|
|
|
* "show users the error output if an exe fails" and is rapidly approaching
|
|
|
|
* "alternative method of getting the data, poll vs event driven". Some serious
|
|
|
|
* thinking needs to be applied to this. Do we really want to go that far? If
|
|
|
|
* so, we should change the names. The basic design will probably remain the
|
|
|
|
* same which ever way we go. The constant goal post moving is probably due to
|
|
|
|
* generic design methods leading to feature creep as we inspired each other to
|
2007-08-26 04:17:21 -07:00
|
|
|
* more generic designs. It does seem like the closer we get to poll driven,
|
2006-01-16 05:21:52 -08:00
|
|
|
* the more issues and corner cases there are.
|
|
|
|
*
|
2007-08-26 04:17:21 -07:00
|
|
|
* Instead of doing the usual register an event handler thing, we are ecore_exe,
|
2006-01-17 03:33:39 -08:00
|
|
|
* we can take some short cuts. Don't send the events, just leave the exe buffers
|
|
|
|
* as is until the user asks for them, then return the event.
|
|
|
|
*
|
2006-01-16 05:21:52 -08:00
|
|
|
* start = 0, end = 0; clogged arteries get flushed, everything is ignored.
|
|
|
|
* start = -1, end = -1; clogged arteries get transferred to internal buffers. Actually, either == -1 means buffer everything.
|
|
|
|
* start = X, end = 0; buffer first X out of clogged arteries, flush and ignore rest.
|
|
|
|
* start = 0, end = X; circular buffer X
|
|
|
|
* start = X, end = Y; buffer first X out of clogged arteries, circular buffer Y from beginning.
|
2006-01-17 03:33:39 -08:00
|
|
|
*
|
2006-01-16 05:21:52 -08:00
|
|
|
* bytes vs lines, which ever one reaches the limit first.
|
2006-01-20 07:52:12 -08:00
|
|
|
* Before we go beyond the start+end limit, leave the end buffer empty, and store both in the start buffer, coz they overlap.
|
|
|
|
* After we pass the the start+end limit, insert "\n...\n" at the end of the start buffer, copy the rest to the end buffer, then store in the end buffer.
|
2006-01-17 03:33:39 -08:00
|
|
|
*
|
2006-01-16 05:21:52 -08:00
|
|
|
* Other issues -
|
|
|
|
* Spank programmer for polling data if polling is not turned on.
|
2006-01-17 03:33:39 -08:00
|
|
|
* Spank programmer for setting up event callbacks if polling is turned on.
|
2006-01-16 05:21:52 -08:00
|
|
|
* Spank programmer for freeing the event data if it came from the event system, as that autofrees.
|
|
|
|
* Spank the programmer if they try to set the limits bigger than what has been gathered & ignored already, coz they just lost data.
|
|
|
|
* Spank onefang and raster for opening this can of worms.
|
2010-09-08 04:23:42 -07:00
|
|
|
* Should we have separate out/err limits?
|
2006-01-16 05:21:52 -08:00
|
|
|
* Should we remove from the internal buffer the data that was delivered already?
|
|
|
|
* If so, what to do about limits, start, and end? They could loose their meaning.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2006-01-19 20:42:35 -08:00
|
|
|
/**
|
|
|
|
* Gets the auto pipe data for the given process handle
|
|
|
|
*
|
|
|
|
* @param exe The given process handle.
|
2007-08-26 04:17:21 -07:00
|
|
|
* @param flags Is this a ECORE_EXE_PIPE_READ or ECORE_EXE_PIPE_ERROR?
|
2012-04-05 00:00:42 -07:00
|
|
|
* @return The event data.
|
2006-01-19 20:42:35 -08:00
|
|
|
*/
|
2006-01-16 05:21:52 -08:00
|
|
|
EAPI Ecore_Exe_Event_Data *
|
2011-10-20 22:40:39 -07:00
|
|
|
ecore_exe_event_data_get(Ecore_Exe *exe,
|
|
|
|
Ecore_Exe_Flags flags)
|
2006-01-16 05:21:52 -08:00
|
|
|
{
|
2006-01-19 20:42:35 -08:00
|
|
|
Ecore_Exe_Event_Data *e = NULL;
|
2009-12-06 19:06:50 -08:00
|
|
|
int is_buffered = 0;
|
|
|
|
unsigned char *inbuf;
|
|
|
|
int inbuf_num;
|
2006-01-19 20:42:35 -08:00
|
|
|
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
2006-01-16 05:21:52 -08:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_event_data_get");
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-01-19 20:42:35 -08:00
|
|
|
|
|
|
|
/* Sort out what sort of event we are. */
|
2006-01-24 05:58:18 -08:00
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
flags = ECORE_EXE_PIPE_READ;
|
|
|
|
if (exe->flags & ECORE_EXE_PIPE_READ_LINE_BUFFERED)
|
|
|
|
is_buffered = 1;
|
|
|
|
}
|
2006-01-19 20:42:35 -08:00
|
|
|
else
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
flags = ECORE_EXE_PIPE_ERROR;
|
|
|
|
if (exe->flags & ECORE_EXE_PIPE_ERROR_LINE_BUFFERED)
|
|
|
|
is_buffered = 1;
|
|
|
|
}
|
2006-01-19 20:42:35 -08:00
|
|
|
|
|
|
|
/* Get the data. */
|
2006-01-24 05:58:18 -08:00
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
inbuf = exe->read_data_buf;
|
|
|
|
inbuf_num = exe->read_data_size;
|
|
|
|
exe->read_data_buf = NULL;
|
|
|
|
exe->read_data_size = 0;
|
|
|
|
}
|
2006-01-19 20:42:35 -08:00
|
|
|
else
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
inbuf = exe->error_data_buf;
|
|
|
|
inbuf_num = exe->error_data_size;
|
|
|
|
exe->error_data_buf = NULL;
|
|
|
|
exe->error_data_size = 0;
|
|
|
|
}
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2006-01-19 20:42:35 -08:00
|
|
|
e = calloc(1, sizeof(Ecore_Exe_Event_Data));
|
|
|
|
if (e)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
e->exe = exe;
|
|
|
|
e->data = inbuf;
|
|
|
|
e->size = inbuf_num;
|
|
|
|
|
|
|
|
if (is_buffered) /* Deal with line buffering. */
|
|
|
|
{
|
|
|
|
int max = 0;
|
|
|
|
int count = 0;
|
|
|
|
int i;
|
|
|
|
int last = 0;
|
|
|
|
char *c;
|
|
|
|
|
|
|
|
c = (char *)inbuf;
|
|
|
|
for (i = 0; i < inbuf_num; i++) /* Find the lines. */
|
|
|
|
{
|
|
|
|
if (inbuf[i] == '\n')
|
|
|
|
{
|
|
|
|
if (count >= max)
|
2011-08-29 14:20:26 -07:00
|
|
|
{
|
2011-10-20 22:40:39 -07:00
|
|
|
/* In testing, the lines seem to arrive in batches of 500 to 1000 lines at most, roughly speaking. */
|
|
|
|
max += 10; /* FIXME: Maybe keep track of the largest number of lines ever sent, and add half that many instead of 10. */
|
|
|
|
e->lines = realloc(e->lines, sizeof(Ecore_Exe_Event_Data_Line) * (max + 1)); /* Allow room for the NULL termination. */
|
2011-08-29 14:20:26 -07:00
|
|
|
}
|
2011-10-20 22:40:39 -07:00
|
|
|
/* raster said to leave the line endings as line endings, however -
|
|
|
|
* This is line buffered mode, we are not dealing with binary here, but lines.
|
|
|
|
* If we are not dealing with binary, we must be dealing with ASCII, unicode, or some other text format.
|
|
|
|
* Thus the user is most likely gonna deal with this text as strings.
|
|
|
|
* Thus the user is most likely gonna pass this data to str functions.
|
|
|
|
* rasters way - the endings are always gonna be '\n'; onefangs way - they will always be '\0'
|
|
|
|
* We are handing them the string length as a convenience.
|
|
|
|
* Thus if they really want it in raw format, they can e->lines[i].line[e->lines[i].size - 1] = '\n'; easily enough.
|
|
|
|
* In the default case, we can do this conversion quicker than the user can, as we already have the index and pointer.
|
|
|
|
* Let's make it easy on them to use these as standard C strings.
|
|
|
|
*
|
|
|
|
* onefang is proud to announce that he has just set a new personal record for the
|
|
|
|
* most over documentation of a simple assignment statement. B-)
|
|
|
|
*/
|
|
|
|
inbuf[i] = '\0';
|
|
|
|
e->lines[count].line = c;
|
|
|
|
e->lines[count].size = i - last;
|
|
|
|
last = i + 1;
|
|
|
|
c = (char *)&inbuf[last];
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i > last) /* Partial line left over, save it for next time. */
|
|
|
|
{
|
|
|
|
if (count != 0) e->size = last;
|
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
|
|
|
{
|
|
|
|
exe->read_data_size = i - last;
|
|
|
|
exe->read_data_buf = malloc(exe->read_data_size);
|
|
|
|
memcpy(exe->read_data_buf, c, exe->read_data_size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
exe->error_data_size = i - last;
|
|
|
|
exe->error_data_buf = malloc(exe->error_data_size);
|
|
|
|
memcpy(exe->error_data_buf, c, exe->error_data_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (count == 0) /* No lines to send, cancel the event. */
|
|
|
|
{
|
|
|
|
_ecore_exe_event_exe_data_free(NULL, e);
|
|
|
|
e = NULL;
|
|
|
|
}
|
|
|
|
else /* NULL terminate the array, so that people know where the end is. */
|
|
|
|
{
|
|
|
|
e->lines[count].line = NULL;
|
|
|
|
e->lines[count].size = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-01-19 20:42:35 -08:00
|
|
|
|
|
|
|
return e;
|
2006-01-16 05:21:52 -08:00
|
|
|
}
|
|
|
|
|
2005-09-28 06:09:09 -07:00
|
|
|
/**
|
|
|
|
* Sets the string tag for the given process handle
|
|
|
|
*
|
|
|
|
* @param exe The given process handle.
|
|
|
|
* @param tag The string tag to set on the process handle.
|
|
|
|
*/
|
2006-01-06 09:58:12 -08:00
|
|
|
EAPI void
|
2011-10-20 22:40:39 -07:00
|
|
|
ecore_exe_tag_set(Ecore_Exe *exe,
|
|
|
|
const char *tag)
|
2005-09-28 06:09:09 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2005-09-28 06:09:09 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_set");
|
|
|
|
return;
|
|
|
|
}
|
2005-12-24 04:13:12 -08:00
|
|
|
IF_FREE(exe->tag);
|
2006-02-28 21:05:58 -08:00
|
|
|
if (tag)
|
2011-10-20 22:40:39 -07:00
|
|
|
exe->tag = strdup(tag);
|
2010-01-05 21:16:59 -08:00
|
|
|
else
|
2011-10-20 22:40:39 -07:00
|
|
|
exe->tag = NULL;
|
2005-09-28 06:09:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves the tag attached to the given process handle. There is no need to
|
|
|
|
* free it as it just returns the internal pointer value. This value is only
|
|
|
|
* valid as long as the @p exe is valid or until the tag is set to something
|
|
|
|
* else on this @p exe.
|
2007-08-26 04:17:21 -07:00
|
|
|
*
|
2005-09-28 06:09:09 -07:00
|
|
|
* @param exe The given process handle.
|
2010-01-05 21:16:59 -08:00
|
|
|
* @return The string attached to @p exe. It is a handle to existing
|
|
|
|
* internal string and should not be modified, use
|
|
|
|
* ecore_exe_tag_set() to change it. It might be @c NULL.
|
2005-09-28 06:09:09 -07:00
|
|
|
*/
|
2010-01-05 21:16:59 -08:00
|
|
|
EAPI const char *
|
|
|
|
ecore_exe_tag_get(const Ecore_Exe *exe)
|
2005-09-28 06:09:09 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
2005-09-28 06:09:09 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_get");
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-09-28 06:09:09 -07:00
|
|
|
return exe->tag;
|
|
|
|
}
|
|
|
|
|
2003-09-23 01:09:32 -07:00
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* Frees the given process handle.
|
|
|
|
*
|
|
|
|
* Note that the process that the handle represents is unaffected by this
|
|
|
|
* function.
|
|
|
|
*
|
|
|
|
* @param exe The given process handle.
|
|
|
|
* @return The data attached to the handle when @ref ecore_exe_run was
|
|
|
|
* called.
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
2009-12-06 19:06:50 -08:00
|
|
|
EAPI void *
|
|
|
|
ecore_exe_free(Ecore_Exe *exe)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
2009-12-06 19:06:50 -08:00
|
|
|
void *data;
|
|
|
|
int ok = 0;
|
|
|
|
int result;
|
2006-01-15 19:20:36 -08:00
|
|
|
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
2003-09-23 01:09:32 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_free");
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-01-15 19:20:36 -08:00
|
|
|
|
|
|
|
data = exe->data;
|
|
|
|
|
2010-01-05 21:16:59 -08:00
|
|
|
if (exe->pre_free_cb)
|
|
|
|
exe->pre_free_cb(data, exe);
|
|
|
|
|
2006-07-29 03:05:13 -07:00
|
|
|
if (exe->doomsday_clock)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
struct _ecore_exe_dead_exe *dead;
|
|
|
|
|
|
|
|
ecore_timer_del(exe->doomsday_clock);
|
|
|
|
exe->doomsday_clock = NULL;
|
|
|
|
dead = exe->doomsday_clock_dead;
|
|
|
|
if (dead)
|
|
|
|
{
|
|
|
|
IF_FREE(dead->cmd);
|
|
|
|
free(dead);
|
|
|
|
exe->doomsday_clock_dead = NULL;
|
|
|
|
}
|
|
|
|
}
|
2006-01-15 19:20:36 -08:00
|
|
|
IF_FN_DEL(ecore_main_fd_handler_del, exe->write_fd_handler);
|
|
|
|
IF_FN_DEL(ecore_main_fd_handler_del, exe->read_fd_handler);
|
|
|
|
IF_FN_DEL(ecore_main_fd_handler_del, exe->error_fd_handler);
|
2006-02-28 21:05:58 -08:00
|
|
|
if (exe->child_fd_write_x != -1)
|
2011-10-20 22:40:39 -07:00
|
|
|
E_NO_ERRNO(result, close(exe->child_fd_write_x), ok);
|
2006-02-28 21:05:58 -08:00
|
|
|
if (exe->child_fd_read_x != -1)
|
2011-10-20 22:40:39 -07:00
|
|
|
E_NO_ERRNO(result, close(exe->child_fd_read_x), ok);
|
2006-02-28 21:05:58 -08:00
|
|
|
if (exe->child_fd_error_x != -1)
|
2011-10-20 22:40:39 -07:00
|
|
|
E_NO_ERRNO(result, close(exe->child_fd_error_x), ok);
|
2006-02-28 21:05:58 -08:00
|
|
|
if (exe->child_fd_write != -1)
|
2011-10-20 22:40:39 -07:00
|
|
|
E_NO_ERRNO(result, close(exe->child_fd_write), ok);
|
2006-02-28 21:05:58 -08:00
|
|
|
if (exe->child_fd_read != -1)
|
2011-10-20 22:40:39 -07:00
|
|
|
E_NO_ERRNO(result, close(exe->child_fd_read), ok);
|
2006-02-28 21:05:58 -08:00
|
|
|
if (exe->child_fd_error != -1)
|
2011-10-20 22:40:39 -07:00
|
|
|
E_NO_ERRNO(result, close(exe->child_fd_error), ok);
|
2006-01-15 19:20:36 -08:00
|
|
|
IF_FREE(exe->write_data_buf);
|
|
|
|
IF_FREE(exe->read_data_buf);
|
|
|
|
IF_FREE(exe->error_data_buf);
|
|
|
|
IF_FREE(exe->cmd);
|
2007-08-26 04:17:21 -07:00
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
exes = (Ecore_Exe *)eina_inlist_remove(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe));
|
2006-01-15 19:20:36 -08:00
|
|
|
ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE);
|
|
|
|
IF_FREE(exe->tag);
|
|
|
|
free(exe);
|
|
|
|
return data;
|
2003-09-23 01:09:32 -07:00
|
|
|
}
|
|
|
|
|
2006-01-16 05:21:52 -08:00
|
|
|
/**
|
|
|
|
* Frees the given event data.
|
|
|
|
*
|
|
|
|
* @param e The given event data.
|
|
|
|
*/
|
|
|
|
EAPI void
|
2009-12-06 19:06:50 -08:00
|
|
|
ecore_exe_event_data_free(Ecore_Exe_Event_Data *e)
|
2006-01-16 05:21:52 -08:00
|
|
|
{
|
2010-01-05 21:16:59 -08:00
|
|
|
if (!e) return;
|
2006-01-16 05:21:52 -08:00
|
|
|
IF_FREE(e->lines);
|
|
|
|
IF_FREE(e->data);
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
|
2003-09-23 01:09:32 -07:00
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* Retrieves the process ID of the given spawned process.
|
|
|
|
* @param exe Handle to the given spawned process.
|
|
|
|
* @return The process ID on success. @c -1 otherwise.
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
2009-12-06 19:06:50 -08:00
|
|
|
EAPI pid_t
|
2010-01-05 21:16:59 -08:00
|
|
|
ecore_exe_pid_get(const Ecore_Exe *exe)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
|
2003-09-23 01:09:32 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pid_get");
|
|
|
|
return -1;
|
|
|
|
}
|
2003-09-23 01:09:32 -07:00
|
|
|
return exe->pid;
|
|
|
|
}
|
|
|
|
|
2006-04-15 05:44:31 -07:00
|
|
|
/**
|
|
|
|
* Retrieves the command of the given spawned process.
|
|
|
|
* @param exe Handle to the given spawned process.
|
2012-04-11 20:51:36 -07:00
|
|
|
* @return The command on success, @c NULL otherwise. This string is the
|
2010-01-05 21:16:59 -08:00
|
|
|
* pointer to the internal value and must not be modified in
|
|
|
|
* any way.
|
2006-04-15 05:44:31 -07:00
|
|
|
*/
|
2010-01-05 21:16:59 -08:00
|
|
|
EAPI const char *
|
|
|
|
ecore_exe_cmd_get(const Ecore_Exe *exe)
|
2006-04-15 05:44:31 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
2006-04-15 05:44:31 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_cmd_get");
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-04-15 05:44:31 -07:00
|
|
|
return exe->cmd;
|
|
|
|
}
|
|
|
|
|
2003-09-23 01:09:32 -07:00
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* Retrieves the data attached to the given process handle.
|
|
|
|
* @param exe The given process handle.
|
2010-01-05 21:16:59 -08:00
|
|
|
* @return The data pointer attached to @p exe Given to
|
|
|
|
* ecore_exe_run() or ecore_exe_pipe_run()
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
2009-12-06 19:06:50 -08:00
|
|
|
EAPI void *
|
2010-01-05 21:16:59 -08:00
|
|
|
ecore_exe_data_get(const Ecore_Exe *exe)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
2003-09-23 01:09:32 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get");
|
|
|
|
return NULL;
|
|
|
|
}
|
2003-09-23 01:09:32 -07:00
|
|
|
return exe->data;
|
|
|
|
}
|
|
|
|
|
2011-04-19 14:38:24 -07:00
|
|
|
/**
|
|
|
|
* Sets the data attached to the given process handle.
|
|
|
|
* @param exe The given process handle.
|
|
|
|
* @param data The pointer to attach
|
|
|
|
* @return The data pointer previously attached to @p exe with
|
|
|
|
* ecore_exe_run(), ecore_exe_pipe_run(), or ecore_exe_data_set()
|
|
|
|
* @since 1.1
|
|
|
|
*/
|
|
|
|
EAPI void *
|
2011-10-20 22:40:39 -07:00
|
|
|
ecore_exe_data_set(Ecore_Exe *exe,
|
|
|
|
void *data)
|
2011-04-19 14:38:24 -07:00
|
|
|
{
|
|
|
|
void *ret;
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
2011-04-19 14:38:24 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, __func__);
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-04-19 14:38:24 -07:00
|
|
|
ret = exe->data;
|
|
|
|
exe->data = data;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-01-03 13:55:50 -08:00
|
|
|
/**
|
|
|
|
* Retrieves the flags attached to the given process handle.
|
|
|
|
* @param exe The given process handle.
|
|
|
|
* @return The flags attached to @p exe.
|
|
|
|
*/
|
|
|
|
EAPI Ecore_Exe_Flags
|
2010-01-05 21:16:59 -08:00
|
|
|
ecore_exe_flags_get(const Ecore_Exe *exe)
|
2010-01-03 13:55:50 -08:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(0);
|
2010-01-03 13:55:50 -08:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get");
|
|
|
|
return 0;
|
|
|
|
}
|
2010-01-03 13:55:50 -08:00
|
|
|
return exe->flags;
|
|
|
|
}
|
|
|
|
|
2004-09-21 21:25:35 -07:00
|
|
|
/**
|
|
|
|
* Pauses the given process by sending it a @c SIGSTOP signal.
|
|
|
|
* @param exe Process handle to the given process.
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
2006-01-06 09:58:12 -08:00
|
|
|
EAPI void
|
2009-12-06 19:06:50 -08:00
|
|
|
ecore_exe_pause(Ecore_Exe *exe)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2003-09-23 01:09:32 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pause");
|
|
|
|
return;
|
|
|
|
}
|
2003-09-23 01:09:32 -07:00
|
|
|
kill(exe->pid, SIGSTOP);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* Continues the given paused process by sending it a @c SIGCONT signal.
|
|
|
|
* @param exe Process handle to the given process.
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
2006-01-06 09:58:12 -08:00
|
|
|
EAPI void
|
2009-12-06 19:06:50 -08:00
|
|
|
ecore_exe_continue(Ecore_Exe *exe)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2003-09-23 01:09:32 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_continue");
|
|
|
|
return;
|
|
|
|
}
|
2003-09-23 01:09:32 -07:00
|
|
|
kill(exe->pid, SIGCONT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-07-29 15:07:19 -07:00
|
|
|
* Sends the given spawned process a interrupt (@c SIGINT) signal.
|
2004-09-21 21:25:35 -07:00
|
|
|
* @param exe Process handle to the given process.
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
2006-01-06 09:58:12 -08:00
|
|
|
EAPI void
|
2009-12-06 19:06:50 -08:00
|
|
|
ecore_exe_interrupt(Ecore_Exe *exe)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2003-09-23 01:09:32 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_interrupt");
|
|
|
|
return;
|
|
|
|
}
|
2008-07-29 15:07:19 -07:00
|
|
|
_ecore_exe_dead_attach(exe);
|
|
|
|
kill(exe->pid, SIGINT);
|
|
|
|
}
|
2006-01-01 12:09:47 -08:00
|
|
|
|
2008-07-29 15:07:19 -07:00
|
|
|
/**
|
|
|
|
* Sends the given spawned process a quit (@c SIGQUIT) signal.
|
|
|
|
* @param exe Process handle to the given process.
|
|
|
|
*/
|
|
|
|
EAPI void
|
2009-12-06 19:06:50 -08:00
|
|
|
ecore_exe_quit(Ecore_Exe *exe)
|
2008-07-29 15:07:19 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2008-07-29 15:07:19 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_quit");
|
|
|
|
return;
|
|
|
|
}
|
2008-07-29 15:07:19 -07:00
|
|
|
_ecore_exe_dead_attach(exe);
|
|
|
|
kill(exe->pid, SIGQUIT);
|
|
|
|
}
|
2006-01-10 08:46:07 -08:00
|
|
|
|
2008-07-29 15:07:19 -07:00
|
|
|
/**
|
|
|
|
* Sends the given spawned process a terminate (@c SIGTERM) signal.
|
|
|
|
* @param exe Process handle to the given process.
|
|
|
|
*/
|
|
|
|
EAPI void
|
2009-12-06 19:06:50 -08:00
|
|
|
ecore_exe_terminate(Ecore_Exe *exe)
|
2008-07-29 15:07:19 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2008-07-29 15:07:19 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_terminate");
|
|
|
|
return;
|
|
|
|
}
|
2008-07-29 15:07:19 -07:00
|
|
|
_ecore_exe_dead_attach(exe);
|
2009-12-21 09:32:19 -08:00
|
|
|
INF("Sending TERM signal to %s (%d).", exe->cmd, exe->pid);
|
2006-01-10 08:46:07 -08:00
|
|
|
kill(exe->pid, SIGTERM);
|
2003-09-23 01:09:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* Kills the given spawned process by sending it a @c SIGKILL signal.
|
|
|
|
* @param exe Process handle to the given process.
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
2006-01-06 09:58:12 -08:00
|
|
|
EAPI void
|
2009-12-06 19:06:50 -08:00
|
|
|
ecore_exe_kill(Ecore_Exe *exe)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
2006-01-01 12:09:47 -08:00
|
|
|
struct _ecore_exe_dead_exe *dead;
|
|
|
|
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2003-09-23 01:09:32 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_kill");
|
|
|
|
return;
|
|
|
|
}
|
2006-01-01 12:09:47 -08:00
|
|
|
|
|
|
|
dead = calloc(1, sizeof(struct _ecore_exe_dead_exe));
|
|
|
|
if (dead)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
dead->pid = exe->pid;
|
|
|
|
dead->cmd = strdup(exe->cmd);
|
|
|
|
IF_FN_DEL(ecore_timer_del, exe->doomsday_clock);
|
|
|
|
exe->doomsday_clock =
|
|
|
|
ecore_timer_add(10.0, _ecore_exe_make_sure_its_really_dead, dead);
|
|
|
|
}
|
2006-01-10 08:46:07 -08:00
|
|
|
|
2009-12-21 09:32:19 -08:00
|
|
|
INF("Sending KILL signal to %s (%d).", exe->cmd, exe->pid);
|
2006-01-10 08:46:07 -08:00
|
|
|
kill(exe->pid, SIGKILL);
|
2003-09-23 01:09:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* Sends a @c SIGUSR signal to the given spawned process.
|
|
|
|
* @param exe Process handle to the given process.
|
|
|
|
* @param num The number user signal to send. Must be either 1 or 2, or
|
|
|
|
* the signal will be ignored.
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
2006-01-06 09:58:12 -08:00
|
|
|
EAPI void
|
2011-10-20 22:40:39 -07:00
|
|
|
ecore_exe_signal(Ecore_Exe *exe,
|
|
|
|
int num)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2003-09-23 01:09:32 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_signal");
|
|
|
|
return;
|
|
|
|
}
|
2003-09-23 01:09:32 -07:00
|
|
|
if (num == 1)
|
2011-10-20 22:40:39 -07:00
|
|
|
kill(exe->pid, SIGUSR1);
|
2003-09-23 01:09:32 -07:00
|
|
|
else if (num == 2)
|
2011-10-20 22:40:39 -07:00
|
|
|
kill(exe->pid, SIGUSR2);
|
2003-09-23 01:09:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* Sends a @c SIGHUP signal to the given spawned process.
|
|
|
|
* @param exe Process handle to the given process.
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
2006-01-06 09:58:12 -08:00
|
|
|
EAPI void
|
2009-12-06 19:06:50 -08:00
|
|
|
ecore_exe_hup(Ecore_Exe *exe)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
2012-03-29 01:52:25 -07:00
|
|
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
2003-09-23 01:09:32 -07:00
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_hup");
|
|
|
|
return;
|
|
|
|
}
|
2003-09-23 01:09:32 -07:00
|
|
|
kill(exe->pid, SIGHUP);
|
|
|
|
}
|
|
|
|
|
2010-10-17 00:03:28 -07:00
|
|
|
/**
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
2009-12-06 19:06:50 -08:00
|
|
|
static Ecore_Exe *
|
2006-01-01 12:09:47 -08:00
|
|
|
_ecore_exe_is_it_alive(pid_t pid)
|
|
|
|
{
|
2009-12-06 19:06:50 -08:00
|
|
|
Ecore_Exe *exe = NULL;
|
2006-01-01 12:09:47 -08:00
|
|
|
|
2010-09-08 04:23:42 -07:00
|
|
|
/* FIXME: There is no nice, safe, OS independent way to tell if a
|
2006-01-01 12:09:47 -08:00
|
|
|
* particular PID is still alive. I have written code to do so
|
2007-08-26 04:17:21 -07:00
|
|
|
* for my urunlevel busybox applet (http://urunlevel.sourceforge.net/),
|
2006-01-01 12:09:47 -08:00
|
|
|
* but it's for linux only, and still not guaranteed.
|
|
|
|
*
|
2007-08-26 04:17:21 -07:00
|
|
|
* So for now, we just check that a valid Ecore_Exe structure
|
2006-01-01 12:09:47 -08:00
|
|
|
* exists for it. Even that is not a guarantee, as the structure
|
|
|
|
* can be freed without killing the process.
|
|
|
|
*
|
|
|
|
* I think we can safely put exe's into two categories, those users
|
|
|
|
* that care about the life of the exe, and the run and forget type.
|
2007-08-26 04:17:21 -07:00
|
|
|
* The run and forget type starts up the exe, then free's the
|
|
|
|
* Ecore_Exe structure straight away. They can never call any of
|
2006-01-01 12:09:47 -08:00
|
|
|
* the functions that can call this, so we don't worry about them.
|
|
|
|
*
|
2007-08-26 04:17:21 -07:00
|
|
|
* Those user's that care about the life of exe's will keep the
|
2006-01-01 12:09:47 -08:00
|
|
|
* Ecore_Exe structure around, terminate them eventually, or
|
|
|
|
* register for exit events. For these ones the assumption
|
|
|
|
* that valid Ecore_Exe struct == live exe is almost valid.
|
|
|
|
*
|
|
|
|
* I will probably copy my urunlevel code into here someday.
|
|
|
|
*/
|
|
|
|
exe = _ecore_exe_find(pid);
|
|
|
|
if (exe)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
exe = NULL;
|
|
|
|
}
|
2006-01-01 12:09:47 -08:00
|
|
|
|
2006-01-10 08:46:07 -08:00
|
|
|
return exe;
|
2006-01-01 12:09:47 -08:00
|
|
|
}
|
|
|
|
|
2010-06-24 09:15:56 -07:00
|
|
|
static Eina_Bool
|
2006-01-01 12:09:47 -08:00
|
|
|
_ecore_exe_make_sure_its_dead(void *data)
|
|
|
|
{
|
|
|
|
struct _ecore_exe_dead_exe *dead;
|
|
|
|
|
|
|
|
dead = data;
|
|
|
|
if (dead)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
Ecore_Exe *exe = NULL;
|
|
|
|
|
|
|
|
if ((exe = _ecore_exe_is_it_alive(dead->pid)))
|
|
|
|
{
|
|
|
|
if (dead->cmd)
|
|
|
|
INF("Sending KILL signal to allegedly dead %s (%d).",
|
|
|
|
dead->cmd, dead->pid);
|
|
|
|
else
|
|
|
|
INF("Sending KILL signal to allegedly dead PID %d.",
|
|
|
|
dead->pid);
|
|
|
|
exe->doomsday_clock =
|
|
|
|
ecore_timer_add(10.0, _ecore_exe_make_sure_its_really_dead,
|
|
|
|
dead);
|
|
|
|
kill(dead->pid, SIGKILL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IF_FREE(dead->cmd);
|
|
|
|
free(dead);
|
|
|
|
}
|
|
|
|
}
|
2010-06-24 09:15:56 -07:00
|
|
|
return ECORE_CALLBACK_CANCEL;
|
2006-01-01 12:09:47 -08:00
|
|
|
}
|
|
|
|
|
2010-06-24 09:15:56 -07:00
|
|
|
static Eina_Bool
|
2006-01-01 12:09:47 -08:00
|
|
|
_ecore_exe_make_sure_its_really_dead(void *data)
|
|
|
|
{
|
|
|
|
struct _ecore_exe_dead_exe *dead;
|
|
|
|
|
|
|
|
dead = data;
|
|
|
|
if (dead)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
Ecore_Exe *exe = NULL;
|
|
|
|
|
|
|
|
if ((exe = _ecore_exe_is_it_alive(dead->pid)))
|
|
|
|
{
|
|
|
|
ERR("RUN! The zombie wants to eat your brains! And your CPU!");
|
|
|
|
if (dead->cmd)
|
|
|
|
INF("%s (%d) is not really dead.", dead->cmd, dead->pid);
|
|
|
|
else
|
|
|
|
INF("PID %d is not really dead.", dead->pid);
|
|
|
|
exe->doomsday_clock = NULL;
|
|
|
|
}
|
|
|
|
IF_FREE(dead->cmd);
|
|
|
|
free(dead);
|
|
|
|
}
|
2010-06-24 09:15:56 -07:00
|
|
|
return ECORE_CALLBACK_CANCEL;
|
2006-01-01 12:09:47 -08:00
|
|
|
}
|
|
|
|
|
2006-01-12 20:31:41 -08:00
|
|
|
void
|
|
|
|
_ecore_exe_init(void)
|
|
|
|
{
|
2006-01-13 05:18:36 -08:00
|
|
|
ECORE_EXE_EVENT_ADD = ecore_event_type_new();
|
|
|
|
ECORE_EXE_EVENT_DEL = ecore_event_type_new();
|
|
|
|
ECORE_EXE_EVENT_DATA = ecore_event_type_new();
|
|
|
|
ECORE_EXE_EVENT_ERROR = ecore_event_type_new();
|
2006-01-12 20:31:41 -08:00
|
|
|
}
|
|
|
|
|
2003-09-23 01:09:32 -07:00
|
|
|
void
|
|
|
|
_ecore_exe_shutdown(void)
|
|
|
|
{
|
2006-02-28 21:05:58 -08:00
|
|
|
while (exes)
|
2010-01-08 11:49:05 -08:00
|
|
|
ecore_exe_free(exes);
|
2003-09-23 01:09:32 -07:00
|
|
|
}
|
|
|
|
|
2009-12-06 19:06:50 -08:00
|
|
|
Ecore_Exe *
|
2003-09-23 01:09:32 -07:00
|
|
|
_ecore_exe_find(pid_t pid)
|
|
|
|
{
|
2009-06-17 04:39:37 -07:00
|
|
|
Ecore_Exe *exe;
|
2009-12-06 19:06:50 -08:00
|
|
|
|
2009-06-17 04:39:37 -07:00
|
|
|
EINA_INLIST_FOREACH(exes, exe)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
if (exe->pid == pid)
|
|
|
|
return exe;
|
|
|
|
}
|
2003-09-23 01:09:32 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-01-03 13:55:50 -08:00
|
|
|
Ecore_Timer *
|
|
|
|
_ecore_exe_doomsday_clock_get(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
return exe->doomsday_clock;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-10-20 22:40:39 -07:00
|
|
|
_ecore_exe_doomsday_clock_set(Ecore_Exe *exe,
|
|
|
|
Ecore_Timer *dc)
|
2010-01-03 13:55:50 -08:00
|
|
|
{
|
|
|
|
exe->doomsday_clock = dc;
|
|
|
|
}
|
|
|
|
|
2006-01-12 20:31:41 -08:00
|
|
|
static inline void
|
2011-10-20 22:40:39 -07:00
|
|
|
_ecore_exe_exec_it(const char *exe_cmd,
|
|
|
|
Ecore_Exe_Flags flags)
|
2005-12-10 14:39:51 -08:00
|
|
|
{
|
2009-12-06 19:06:50 -08:00
|
|
|
char use_sh = 1;
|
|
|
|
char *buf = NULL;
|
|
|
|
char **args = NULL;
|
2011-10-20 22:40:39 -07:00
|
|
|
int save_errno = 0;
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2006-01-12 20:31:41 -08:00
|
|
|
/* So what is this doing?
|
|
|
|
*
|
|
|
|
* We are trying 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.
|
|
|
|
*/
|
2006-01-10 00:44:15 -08:00
|
|
|
if (!strpbrk(exe_cmd, "|&;<>()$`\\\"'*?#"))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
char *token;
|
|
|
|
char pre_command = 1;
|
|
|
|
int num_tokens = 0;
|
2010-09-29 23:09:20 -07:00
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
if (!(buf = strdup(exe_cmd)))
|
|
|
|
return;
|
2010-09-29 23:09:20 -07:00
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
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_FREE(buf);
|
|
|
|
if ((!token) && (num_tokens))
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if (!(buf = strdup(exe_cmd)))
|
|
|
|
return;
|
2010-09-29 23:09:20 -07:00
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
token = strtok(buf, " \t\n\v");
|
|
|
|
use_sh = 0;
|
|
|
|
if (!(args = (char **)calloc(num_tokens + 1, sizeof(char *))))
|
|
|
|
{
|
|
|
|
IF_FREE(buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (i = 0; i < num_tokens; i++)
|
|
|
|
{
|
|
|
|
if (token)
|
|
|
|
args[i] = token;
|
|
|
|
token = strtok(NULL, " \t\n\v");
|
|
|
|
}
|
|
|
|
args[num_tokens] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2007-08-26 04:17:21 -07:00
|
|
|
|
2011-10-11 11:19:37 -07:00
|
|
|
#ifdef HAVE_SYS_PRCTL_H
|
2011-10-07 16:37:42 -07:00
|
|
|
if ((flags & ECORE_EXE_TERM_WITH_PARENT))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
|
|
|
}
|
2011-10-07 18:17:19 -07:00
|
|
|
#endif
|
2011-10-07 16:37:42 -07:00
|
|
|
|
2008-03-09 23:44:32 -07:00
|
|
|
if (!(flags & ECORE_EXE_NOT_LEADER)) setsid();
|
2006-04-05 11:05:16 -07:00
|
|
|
if ((flags & ECORE_EXE_USE_SH))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
errno = 0;
|
|
|
|
execl("/bin/sh", "/bin/sh", "-c", exe_cmd, (char *)NULL);
|
|
|
|
}
|
|
|
|
else if (use_sh) /* We have to use a shell to run this. */
|
|
|
|
{
|
|
|
|
if (!shell) /* Find users preferred shell. */
|
|
|
|
{
|
|
|
|
shell = getenv("SHELL");
|
|
|
|
if (!shell)
|
|
|
|
shell = "/bin/sh";
|
|
|
|
}
|
|
|
|
errno = 0;
|
|
|
|
execl(shell, shell, "-c", exe_cmd, (char *)NULL);
|
|
|
|
}
|
2005-12-10 14:39:51 -08:00
|
|
|
else
|
2011-10-20 22:40:39 -07:00
|
|
|
{ /* We can run this directly. */
|
|
|
|
if (!args)
|
|
|
|
{
|
|
|
|
IF_FREE(buf);
|
|
|
|
IF_FREE(args);
|
|
|
|
ERR("arg[0] is NULL!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
errno = 0;
|
|
|
|
execvp(args[0], args);
|
|
|
|
}
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2005-12-10 14:39:51 -08:00
|
|
|
save_errno = errno;
|
2005-12-24 04:13:12 -08:00
|
|
|
IF_FREE(buf);
|
|
|
|
IF_FREE(args);
|
2005-12-10 14:39:51 -08:00
|
|
|
errno = save_errno;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-06-24 09:15:56 -07:00
|
|
|
static Eina_Bool
|
2011-10-20 22:40:39 -07:00
|
|
|
_ecore_exe_data_generic_handler(void *data,
|
|
|
|
Ecore_Fd_Handler *fd_handler,
|
|
|
|
Ecore_Exe_Flags flags)
|
2006-01-10 08:46:07 -08:00
|
|
|
{
|
2009-12-06 19:06:50 -08:00
|
|
|
Ecore_Exe *exe;
|
|
|
|
int child_fd;
|
|
|
|
int event_type;
|
2006-01-10 08:46:07 -08:00
|
|
|
|
|
|
|
exe = data;
|
2006-01-17 03:33:39 -08:00
|
|
|
|
|
|
|
/* Sort out what sort of handler we are. */
|
2006-01-24 05:58:18 -08:00
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
flags = ECORE_EXE_PIPE_READ;
|
|
|
|
event_type = ECORE_EXE_EVENT_DATA;
|
|
|
|
child_fd = exe->child_fd_read;
|
|
|
|
}
|
2006-01-10 10:36:19 -08:00
|
|
|
else
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
flags = ECORE_EXE_PIPE_ERROR;
|
|
|
|
event_type = ECORE_EXE_EVENT_ERROR;
|
|
|
|
child_fd = exe->child_fd_error;
|
|
|
|
}
|
2006-02-28 21:05:58 -08:00
|
|
|
|
|
|
|
if ((fd_handler)
|
|
|
|
&& (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
unsigned char *inbuf;
|
|
|
|
int inbuf_num;
|
|
|
|
|
|
|
|
/* Get any left over data from last time. */
|
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
|
|
|
{
|
|
|
|
inbuf = exe->read_data_buf;
|
|
|
|
inbuf_num = exe->read_data_size;
|
|
|
|
exe->read_data_buf = NULL;
|
|
|
|
exe->read_data_size = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inbuf = exe->error_data_buf;
|
|
|
|
inbuf_num = exe->error_data_size;
|
|
|
|
exe->error_data_buf = NULL;
|
|
|
|
exe->error_data_size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;; )
|
|
|
|
{
|
|
|
|
int num, lost_exe;
|
|
|
|
char buf[READBUFSIZ];
|
|
|
|
|
|
|
|
lost_exe = 0;
|
|
|
|
errno = 0;
|
|
|
|
if ((num = read(child_fd, buf, READBUFSIZ)) < 1)
|
|
|
|
{
|
|
|
|
/* FIXME: SPEED/SIZE TRADE OFF - add a smaller READBUFSIZE
|
|
|
|
* (currently 64k) to inbuf, use that instead of buf, and
|
|
|
|
* save ourselves a memcpy(). */
|
|
|
|
lost_exe = ((errno == EIO) ||
|
|
|
|
(errno == EBADF) ||
|
|
|
|
(errno == EPIPE) ||
|
|
|
|
(errno == EINVAL) || (errno == ENOSPC));
|
|
|
|
if ((errno != EAGAIN) && (errno != EINTR))
|
|
|
|
perror("_ecore_exe_generic_handler() read problem ");
|
|
|
|
}
|
|
|
|
if (num > 0) /* data got read. */
|
|
|
|
{
|
|
|
|
inbuf = realloc(inbuf, inbuf_num + num);
|
|
|
|
memcpy(inbuf + inbuf_num, buf, num);
|
|
|
|
inbuf_num += num;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* No more data to read. */
|
|
|
|
if (inbuf)
|
|
|
|
{
|
|
|
|
Ecore_Exe_Event_Data *e;
|
|
|
|
|
|
|
|
/* Stash the data away for later. */
|
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
|
|
|
{
|
|
|
|
exe->read_data_buf = inbuf;
|
|
|
|
exe->read_data_size = inbuf_num;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
exe->error_data_buf = inbuf;
|
|
|
|
exe->error_data_size = inbuf_num;
|
|
|
|
}
|
2010-09-29 23:09:20 -07:00
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
if (!(exe->flags & ECORE_EXE_PIPE_AUTO))
|
2010-09-29 23:09:20 -07:00
|
|
|
{
|
2011-10-20 22:40:39 -07:00
|
|
|
e = ecore_exe_event_data_get(exe, flags);
|
|
|
|
if (e) /* Send the event. */
|
|
|
|
ecore_event_add(event_type, e,
|
|
|
|
_ecore_exe_event_exe_data_free,
|
|
|
|
NULL);
|
2010-09-29 23:09:20 -07:00
|
|
|
}
|
2011-10-20 22:40:39 -07:00
|
|
|
}
|
|
|
|
if (lost_exe)
|
|
|
|
{
|
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
|
|
|
{
|
|
|
|
if (exe->read_data_size)
|
|
|
|
INF("There are %d bytes left unsent from the dead exe %s.",
|
|
|
|
exe->read_data_size, exe->cmd);
|
2010-09-29 23:09:20 -07:00
|
|
|
}
|
2011-10-20 22:40:39 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (exe->error_data_size)
|
|
|
|
INF("There are %d bytes left unsent from the dead exe %s.",
|
|
|
|
exe->error_data_size, exe->cmd);
|
2010-09-29 23:09:20 -07:00
|
|
|
}
|
2011-10-20 22:40:39 -07:00
|
|
|
/* Thought about this a bit. If the exe has actually
|
|
|
|
* died, this won't do any harm as it must have died
|
|
|
|
* recently and the pid has not had a chance to recycle.
|
|
|
|
* It is also a paranoid catchall, coz the usual ecore_signal
|
|
|
|
* mechenism should kick in. But let's give it a good
|
|
|
|
* kick in the head anyway.
|
|
|
|
*/
|
|
|
|
ecore_exe_terminate(exe);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-01-10 08:46:07 -08:00
|
|
|
|
2010-06-24 09:15:56 -07:00
|
|
|
return ECORE_CALLBACK_RENEW;
|
2006-01-10 08:46:07 -08:00
|
|
|
}
|
|
|
|
|
2010-06-24 09:15:56 -07:00
|
|
|
static Eina_Bool
|
2011-10-20 22:40:39 -07:00
|
|
|
_ecore_exe_data_error_handler(void *data,
|
|
|
|
Ecore_Fd_Handler *fd_handler)
|
2006-01-10 10:36:19 -08:00
|
|
|
{
|
2006-02-28 21:05:58 -08:00
|
|
|
return _ecore_exe_data_generic_handler(data, fd_handler,
|
2010-09-29 23:09:20 -07:00
|
|
|
ECORE_EXE_PIPE_ERROR);
|
2006-01-10 10:36:19 -08:00
|
|
|
}
|
2006-01-10 08:46:07 -08:00
|
|
|
|
2010-06-24 09:15:56 -07:00
|
|
|
static Eina_Bool
|
2011-10-20 22:40:39 -07:00
|
|
|
_ecore_exe_data_read_handler(void *data,
|
|
|
|
Ecore_Fd_Handler *fd_handler)
|
2005-12-10 14:39:51 -08:00
|
|
|
{
|
2006-02-28 21:05:58 -08:00
|
|
|
return _ecore_exe_data_generic_handler(data, fd_handler,
|
2010-09-29 23:09:20 -07:00
|
|
|
ECORE_EXE_PIPE_READ);
|
2005-12-10 14:39:51 -08:00
|
|
|
}
|
|
|
|
|
2010-06-24 09:15:56 -07:00
|
|
|
static Eina_Bool
|
2011-10-20 22:40:39 -07:00
|
|
|
_ecore_exe_data_write_handler(void *data,
|
2012-11-25 01:55:32 -08:00
|
|
|
Ecore_Fd_Handler *fd_handler EINA_UNUSED)
|
2005-12-10 14:39:51 -08:00
|
|
|
{
|
2009-12-06 19:06:50 -08:00
|
|
|
Ecore_Exe *exe;
|
2005-12-10 14:39:51 -08:00
|
|
|
|
|
|
|
exe = data;
|
2010-01-08 11:49:05 -08:00
|
|
|
if ((exe->write_fd_handler) &&
|
2006-02-28 21:05:58 -08:00
|
|
|
(ecore_main_fd_handler_active_get
|
2011-10-20 22:40:39 -07:00
|
|
|
(exe->write_fd_handler, ECORE_FD_WRITE)))
|
2010-01-08 11:49:05 -08:00
|
|
|
_ecore_exe_flush(exe);
|
2005-12-10 14:39:51 -08:00
|
|
|
|
2005-12-30 11:17:21 -08:00
|
|
|
/* If we have sent all there is to send, and we need to close the pipe, then close it. */
|
2006-02-28 21:05:58 -08:00
|
|
|
if ((exe->close_stdin == 1)
|
|
|
|
&& (exe->write_data_size == exe->write_data_offset))
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
int ok = 0;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
INF("Closing stdin for %s", exe->cmd);
|
|
|
|
/* if (exe->child_fd_write != -1) E_NO_ERRNO(result, fsync(exe->child_fd_write), ok); This a) doesn't work, and b) isn't needed. */
|
|
|
|
IF_FN_DEL(ecore_main_fd_handler_del, exe->write_fd_handler);
|
|
|
|
if (exe->child_fd_write != -1)
|
|
|
|
E_NO_ERRNO(result, close(exe->child_fd_write), ok);
|
|
|
|
exe->child_fd_write = -1;
|
|
|
|
IF_FREE(exe->write_data_buf);
|
|
|
|
}
|
2005-12-30 11:17:21 -08:00
|
|
|
|
2010-06-24 09:15:56 -07:00
|
|
|
return ECORE_CALLBACK_RENEW;
|
2005-12-10 14:39:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-12-06 19:06:50 -08:00
|
|
|
_ecore_exe_flush(Ecore_Exe *exe)
|
2005-12-10 14:39:51 -08:00
|
|
|
{
|
2009-12-06 19:06:50 -08:00
|
|
|
int count;
|
2005-12-10 14:39:51 -08:00
|
|
|
|
|
|
|
/* check whether we need to write anything at all. */
|
2006-02-28 21:05:58 -08:00
|
|
|
if ((exe->child_fd_write == -1) || (!exe->write_data_buf))
|
2011-10-20 22:40:39 -07:00
|
|
|
return;
|
2006-02-28 21:05:58 -08:00
|
|
|
if (exe->write_data_size == exe->write_data_offset)
|
2011-10-20 22:40:39 -07:00
|
|
|
return;
|
2005-12-10 14:39:51 -08:00
|
|
|
|
2006-02-28 21:05:58 -08:00
|
|
|
count = write(exe->child_fd_write,
|
2010-09-29 23:09:20 -07:00
|
|
|
(char *)exe->write_data_buf + exe->write_data_offset,
|
|
|
|
exe->write_data_size - exe->write_data_offset);
|
2005-12-10 14:39:51 -08:00
|
|
|
if (count < 1)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
if (errno == EIO || errno == EBADF || errno == EPIPE || errno == EINVAL || errno == ENOSPC) /* we lost our exe! */
|
|
|
|
{
|
|
|
|
ecore_exe_terminate(exe);
|
|
|
|
if (exe->write_fd_handler)
|
|
|
|
ecore_main_fd_handler_active_set(exe->write_fd_handler, 0);
|
|
|
|
}
|
|
|
|
}
|
2005-12-10 14:39:51 -08:00
|
|
|
else
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
exe->write_data_offset += count;
|
|
|
|
if (exe->write_data_offset >= exe->write_data_size) /* Nothing left to write, clean up. */
|
|
|
|
{
|
|
|
|
exe->write_data_size = 0;
|
|
|
|
exe->write_data_offset = 0;
|
|
|
|
IF_FREE(exe->write_data_buf);
|
|
|
|
if (exe->write_fd_handler)
|
|
|
|
ecore_main_fd_handler_active_set(exe->write_fd_handler, 0);
|
|
|
|
}
|
|
|
|
}
|
2005-12-10 14:39:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-11-25 01:55:32 -08:00
|
|
|
_ecore_exe_event_exe_data_free(void *data EINA_UNUSED,
|
2011-10-20 22:40:39 -07:00
|
|
|
void *ev)
|
2005-12-10 14:39:51 -08:00
|
|
|
{
|
2006-01-15 03:27:19 -08:00
|
|
|
Ecore_Exe_Event_Data *e;
|
2005-12-10 14:39:51 -08:00
|
|
|
|
|
|
|
e = ev;
|
2006-01-16 05:21:52 -08:00
|
|
|
ecore_exe_event_data_free(e);
|
2005-12-10 14:39:51 -08:00
|
|
|
}
|
2006-01-13 05:18:36 -08:00
|
|
|
|
|
|
|
static Ecore_Exe_Event_Add *
|
|
|
|
_ecore_exe_event_add_new(void)
|
|
|
|
{
|
|
|
|
Ecore_Exe_Event_Add *e;
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2006-01-13 05:18:36 -08:00
|
|
|
e = calloc(1, sizeof(Ecore_Exe_Event_Add));
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-11-25 01:55:32 -08:00
|
|
|
_ecore_exe_event_add_free(void *data EINA_UNUSED,
|
2011-10-20 22:40:39 -07:00
|
|
|
void *ev)
|
2006-01-13 05:18:36 -08:00
|
|
|
{
|
|
|
|
Ecore_Exe_Event_Add *e;
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2006-01-13 05:18:36 -08:00
|
|
|
e = ev;
|
|
|
|
free(e);
|
|
|
|
}
|
2006-01-15 19:20:36 -08:00
|
|
|
|
2011-10-20 22:40:39 -07:00
|
|
|
void *
|
2006-01-15 19:20:36 -08:00
|
|
|
_ecore_exe_event_del_new(void)
|
|
|
|
{
|
|
|
|
Ecore_Exe_Event_Del *e;
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2006-01-15 19:20:36 -08:00
|
|
|
e = calloc(1, sizeof(Ecore_Exe_Event_Del));
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-11-25 01:55:32 -08:00
|
|
|
_ecore_exe_event_del_free(void *data EINA_UNUSED,
|
2011-10-20 22:40:39 -07:00
|
|
|
void *ev)
|
2006-01-15 19:20:36 -08:00
|
|
|
{
|
|
|
|
Ecore_Exe_Event_Del *e;
|
2006-02-28 21:05:58 -08:00
|
|
|
|
2006-01-15 19:20:36 -08:00
|
|
|
e = ev;
|
2006-02-28 21:05:58 -08:00
|
|
|
if (e->exe)
|
2010-01-08 11:49:05 -08:00
|
|
|
ecore_exe_free(e->exe);
|
2006-01-15 19:20:36 -08:00
|
|
|
free(e);
|
|
|
|
}
|
2006-01-17 03:33:39 -08:00
|
|
|
|
2008-07-29 15:07:19 -07:00
|
|
|
static void
|
|
|
|
_ecore_exe_dead_attach(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
struct _ecore_exe_dead_exe *dead;
|
|
|
|
|
|
|
|
if (exe->doomsday_clock_dead) return;
|
|
|
|
dead = calloc(1, sizeof(struct _ecore_exe_dead_exe));
|
|
|
|
if (dead)
|
2011-10-20 22:40:39 -07:00
|
|
|
{
|
|
|
|
dead->pid = exe->pid;
|
|
|
|
dead->cmd = strdup(exe->cmd);
|
|
|
|
IF_FN_DEL(ecore_timer_del, exe->doomsday_clock);
|
|
|
|
exe->doomsday_clock =
|
|
|
|
ecore_timer_add(10.0, _ecore_exe_make_sure_its_dead, dead);
|
|
|
|
exe->doomsday_clock_dead = dead;
|
|
|
|
}
|
2008-07-29 15:07:19 -07:00
|
|
|
}
|
2011-10-20 22:40:39 -07:00
|
|
|
|