2003-09-23 01:09:32 -07:00
|
|
|
#include "ecore_private.h"
|
|
|
|
#include "Ecore.h"
|
|
|
|
|
2005-10-24 07:47:25 -07:00
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
2004-10-20 10:51:29 -07:00
|
|
|
#ifndef WIN32
|
2005-12-10 14:39:51 -08:00
|
|
|
|
|
|
|
static void _ecore_exe_exec_it(const char *exe_cmd);
|
|
|
|
static int _ecore_exe_data_read_handler(void *data, Ecore_Fd_Handler *fd_handler);
|
|
|
|
static int _ecore_exe_data_write_handler(void *data, Ecore_Fd_Handler *fd_handler);
|
|
|
|
static void _ecore_exe_flush(Ecore_Exe *exe);
|
|
|
|
static void _ecore_exe_event_exe_data_free(void *data __UNUSED__, void *ev);
|
|
|
|
|
2003-09-23 01:09:32 -07:00
|
|
|
static Ecore_Exe *exes = NULL;
|
2005-12-10 14:39:51 -08:00
|
|
|
static char *shell = NULL;
|
2003-09-23 01:09:32 -07:00
|
|
|
|
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* @defgroup Ecore_Exe_Basic_Group Process Spawning Functions
|
|
|
|
*
|
|
|
|
* Functions that deal with spawned processes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Spawns a child process.
|
|
|
|
*
|
|
|
|
* 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.
|
2003-09-23 01:09:32 -07:00
|
|
|
*
|
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.
|
|
|
|
* @ingroup Ecore_Exe_Basic_Group
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
|
|
|
Ecore_Exe *
|
|
|
|
ecore_exe_run(const char *exe_cmd, const void *data)
|
|
|
|
{
|
|
|
|
Ecore_Exe *exe;
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
if (!exe_cmd) return NULL;
|
2005-11-29 04:39:09 -08:00
|
|
|
pid = fork();
|
2003-09-23 01:09:32 -07:00
|
|
|
if (pid)
|
|
|
|
{
|
|
|
|
exe = calloc(1, sizeof(Ecore_Exe));
|
|
|
|
if (!exe)
|
|
|
|
{
|
|
|
|
kill(pid, SIGKILL);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE);
|
|
|
|
exe->pid = pid;
|
|
|
|
exe->data = (void *)data;
|
2005-08-30 03:05:27 -07:00
|
|
|
exes = _ecore_list2_append(exes, exe);
|
2003-09-23 01:09:32 -07:00
|
|
|
return exe;
|
|
|
|
}
|
2005-12-10 14:39:51 -08:00
|
|
|
/* FIXME: replace this lot with _ecore_exe_exec_it(exe_cmd); once it gets a bit of testing. */
|
2005-11-29 04:39:09 -08:00
|
|
|
{
|
|
|
|
char use_sh = 1;
|
|
|
|
char* buf = NULL;
|
|
|
|
char** args = NULL;
|
|
|
|
if (! strpbrk(exe_cmd, "|&;<>()$`\\\"'*?#"))
|
|
|
|
{
|
|
|
|
if (! (buf = strdup(exe_cmd)))
|
|
|
|
return NULL;
|
|
|
|
char* token = strtok(buf, " \t\n\v");
|
|
|
|
char pre_command = 1;
|
|
|
|
int num_tokens = 0;
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
free(buf);
|
|
|
|
buf = NULL;
|
|
|
|
if (! token && num_tokens)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
char* token;
|
|
|
|
if (! (buf = strdup(exe_cmd)))
|
|
|
|
return NULL;
|
|
|
|
token = strtok(buf, " \t\n\v");
|
|
|
|
use_sh = 0;
|
|
|
|
if (! (args = (char**) calloc(num_tokens + 1, sizeof(char*)))) {
|
|
|
|
free (buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
for (i = 0; i < num_tokens; i ++)
|
|
|
|
{
|
|
|
|
if (token)
|
|
|
|
args[i] = token;
|
|
|
|
token = strtok(NULL, " \t\n\v");
|
|
|
|
}
|
|
|
|
args[num_tokens] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setsid();
|
|
|
|
if (use_sh)
|
|
|
|
execl("/bin/sh", "/bin/sh", "-c", exe_cmd, (char *)NULL);
|
|
|
|
else
|
|
|
|
execvp(args[0], args);
|
|
|
|
if (buf)
|
|
|
|
free(buf);
|
|
|
|
if(args)
|
|
|
|
free(args);
|
|
|
|
}
|
2005-07-06 20:31:34 -07:00
|
|
|
exit(127);
|
2003-09-23 01:09:32 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-10-24 01:53:50 -07:00
|
|
|
/**
|
|
|
|
* Spawns a child process with its stdin/out available for communication.
|
|
|
|
*
|
|
|
|
* This function does the same thing as ecore_exe_run(), but also makes the
|
|
|
|
* standard in and/or out from the child process available for reading or
|
|
|
|
* writing. To write use ecore_exe_pipe_write(). To read listen to
|
|
|
|
* ECORE_EVENT_EXE_DATA events (set up a handler). Ecore may buffer read data
|
2005-12-10 14:39:51 -08:00
|
|
|
* until a newline character if asked for with the @p flags. All data will be
|
2005-10-24 01:53:50 -07:00
|
|
|
* included in the events (newlines will not be stripped). This will only
|
|
|
|
* happen if the process is run with ECORE_EXE_PIPE_READ enabled in the flags.
|
|
|
|
*
|
|
|
|
* @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.
|
|
|
|
* @ingroup Ecore_Exe_Basic_Group
|
|
|
|
*/
|
|
|
|
Ecore_Exe *
|
|
|
|
ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
|
|
|
|
{
|
2005-10-25 00:30:29 -07:00
|
|
|
Ecore_Exe *exe = NULL;
|
2005-10-24 07:47:25 -07:00
|
|
|
pid_t pid = 0;
|
2005-12-10 14:39:51 -08:00
|
|
|
int readPipe[2] = { -1, -1 };
|
|
|
|
int writePipe[2] = { -1, -1 };
|
2005-10-24 07:47:25 -07:00
|
|
|
int statusPipe[2] = { -1, -1 };
|
2005-11-09 06:09:28 -08:00
|
|
|
int n = 0;
|
2005-10-24 07:47:25 -07:00
|
|
|
volatile int vfork_exec_errno = 0;
|
2005-10-24 01:53:50 -07:00
|
|
|
|
|
|
|
if (!exe_cmd) return NULL;
|
2005-10-24 07:47:25 -07:00
|
|
|
|
2005-10-25 00:30:29 -07:00
|
|
|
if ((flags & (ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE)) == 0) return ecore_exe_run(exe_cmd, data);
|
|
|
|
|
2005-11-09 06:09:28 -08:00
|
|
|
exe = calloc(1, sizeof(Ecore_Exe));
|
|
|
|
if (exe == NULL) return NULL;
|
|
|
|
|
2005-12-10 14:39:51 -08:00
|
|
|
if ((pipe(readPipe) == -1) || (pipe(writePipe) == -1) || (pipe(statusPipe) == -1))
|
2005-11-09 06:09:28 -08:00
|
|
|
printf("Failed to create pipes\n");
|
|
|
|
/* 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 */
|
2005-10-24 07:47:25 -07:00
|
|
|
pid = fork();
|
|
|
|
|
2005-11-09 06:09:28 -08:00
|
|
|
if (pid == -1)
|
|
|
|
{
|
|
|
|
printf("Failed to fork process\n");
|
|
|
|
pid = 0;
|
|
|
|
}
|
|
|
|
else if (pid == 0) /* child */
|
|
|
|
{
|
|
|
|
close(STDOUT_FILENO); /* FIXME: Check for -1 then errno. */
|
|
|
|
close(STDERR_FILENO); /* FIXME: Check for -1 then errno. */
|
|
|
|
close(STDIN_FILENO); /* FIXME: Check for -1 then errno. */
|
2005-10-25 00:30:29 -07:00
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
|
|
|
{
|
2005-12-10 14:39:51 -08:00
|
|
|
dup2(readPipe[1], STDOUT_FILENO); /* FIXME: Check for -1 then errno. */
|
|
|
|
// dup2(dataPipe[1], STDERR_FILENO); /* FIXME: Check for -1 then errno. */
|
2005-10-25 00:30:29 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-12-10 14:39:51 -08:00
|
|
|
close(readPipe[1]); /* FIXME: Check for -1 then errno. */
|
2005-10-25 00:30:29 -07:00
|
|
|
}
|
|
|
|
if (flags & ECORE_EXE_PIPE_WRITE)
|
|
|
|
{
|
2005-12-10 14:39:51 -08:00
|
|
|
dup2(writePipe[0], STDIN_FILENO); /* FIXME: Check for -1 then errno. */
|
2005-10-25 00:30:29 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-12-10 14:39:51 -08:00
|
|
|
close(writePipe[0]); /* FIXME: Check for -1 then errno. */
|
2005-10-25 00:30:29 -07:00
|
|
|
}
|
2005-11-09 06:09:28 -08:00
|
|
|
close(statusPipe[0]); /* FIXME: Check for -1 then errno. */
|
|
|
|
fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows sucess */ /* FIXME: Check for -1 then errno. */
|
2005-10-24 07:47:25 -07:00
|
|
|
|
2005-12-10 14:39:51 -08:00
|
|
|
_ecore_exe_exec_it(exe_cmd);
|
2005-10-24 07:47:25 -07:00
|
|
|
|
2005-11-09 06:09:28 -08:00
|
|
|
/* Something went 'orribly wrong. */
|
2005-10-24 07:47:25 -07:00
|
|
|
vfork_exec_errno = errno;
|
2005-12-10 14:39:51 -08:00
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
|
|
|
close(readPipe[1]); /* FIXME: Check for -1 then errno. */
|
|
|
|
if (flags & ECORE_EXE_PIPE_WRITE)
|
|
|
|
close(writePipe[0]); /* FIXME: Check for -1 then errno. */
|
2005-11-29 14:22:21 -08:00
|
|
|
close(statusPipe[1]); /* FIXME: Check for -1 then errno. */
|
2005-10-24 07:47:25 -07:00
|
|
|
_exit(-1);
|
|
|
|
}
|
2005-11-09 06:09:28 -08:00
|
|
|
else /* parent */
|
|
|
|
{
|
2005-10-25 00:30:29 -07:00
|
|
|
if (! (flags & ECORE_EXE_PIPE_READ))
|
2005-12-10 14:39:51 -08:00
|
|
|
close(readPipe[0]); /* FIXME: Check for -1 then errno. */
|
2005-10-25 00:30:29 -07:00
|
|
|
if (! (flags & ECORE_EXE_PIPE_WRITE))
|
2005-12-10 14:39:51 -08:00
|
|
|
close(writePipe[1]); /* FIXME: Check for -1 then errno. */
|
2005-11-09 06:09:28 -08:00
|
|
|
close(statusPipe[1]); /* FIXME: Check for -1 then errno. */
|
2005-10-24 07:47:25 -07:00
|
|
|
|
2005-12-10 14:39:51 -08:00
|
|
|
/* FIXME: after having a good look at the current e fd handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */
|
2005-11-09 06:09:28 -08:00
|
|
|
|
|
|
|
while (1) /* Wait for it to start executing. */
|
2005-10-24 07:47:25 -07:00
|
|
|
{
|
|
|
|
char buf;
|
|
|
|
|
|
|
|
n = read(statusPipe[0], &buf, 1);
|
|
|
|
|
2005-11-09 06:09:28 -08:00
|
|
|
if ((n == -1) && ((errno == EAGAIN) || (errno == EINTR)))
|
|
|
|
continue; /* try it again */
|
|
|
|
if (n == 0)
|
2005-10-24 07:47:25 -07:00
|
|
|
{
|
2005-11-09 06:09:28 -08:00
|
|
|
if (vfork_exec_errno != 0)
|
|
|
|
{
|
|
|
|
n = vfork_exec_errno;
|
|
|
|
printf("Could not exec process\n"); /* FIXME: maybe set the pid to 0? */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2005-10-24 07:47:25 -07:00
|
|
|
}
|
|
|
|
close(statusPipe[0]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pid)
|
|
|
|
{
|
2005-11-09 06:09:28 -08:00
|
|
|
ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE);
|
|
|
|
exe->pid = pid;
|
|
|
|
exe->flags = flags;
|
|
|
|
exe->data = (void *)data;
|
|
|
|
exe->cmd = exe_cmd; /* FIXME: should calloc and cpy. */
|
|
|
|
if (flags & ECORE_EXE_PIPE_READ)
|
2005-12-10 14:39:51 -08:00
|
|
|
{
|
|
|
|
exe->child_fd_read = readPipe[0];
|
|
|
|
fcntl(exe->child_fd_read, F_SETFL, O_NONBLOCK); /* FIXME: Check for -1 then errno. */
|
|
|
|
exe->read_fd_handler = ecore_main_fd_handler_add(exe->child_fd_read,
|
|
|
|
ECORE_FD_READ, _ecore_exe_data_read_handler, exe,
|
|
|
|
NULL, NULL);
|
|
|
|
}
|
2005-11-09 06:09:28 -08:00
|
|
|
if (flags & ECORE_EXE_PIPE_WRITE)
|
2005-12-10 14:39:51 -08:00
|
|
|
{
|
|
|
|
exe->child_fd_write = writePipe[1];
|
|
|
|
exe->write_fd_handler = ecore_main_fd_handler_add(exe->child_fd_write,
|
|
|
|
ECORE_FD_WRITE, _ecore_exe_data_write_handler, exe,
|
|
|
|
NULL, NULL);
|
|
|
|
}
|
|
|
|
|
2005-11-09 06:09:28 -08:00
|
|
|
exes = _ecore_list2_append(exes, exe);
|
|
|
|
n = 0;
|
|
|
|
printf("Ecore_Exe %s success!\n", exe_cmd);
|
2005-10-24 07:47:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
errno = n;
|
|
|
|
|
2005-10-25 00:30:29 -07:00
|
|
|
return exe;
|
2005-10-24 01:53:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes data to the given child process which it recieves on stdin.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* @param exe The child process to write to
|
|
|
|
* @param data The data to write
|
|
|
|
* @param size The size of the data to write, in bytes
|
|
|
|
* @return 1 if successful, 0 on failure.
|
|
|
|
* @ingroup Ecore_Exe_Basic_Group
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ecore_exe_pipe_write(Ecore_Exe *exe, void *data, int size)
|
|
|
|
{
|
2005-12-10 14:39:51 -08:00
|
|
|
void *buf;
|
|
|
|
|
|
|
|
buf = realloc(exe->write_data_buf, exe->write_data_size + size);
|
|
|
|
if (buf == NULL) return 0;
|
|
|
|
|
|
|
|
exe->write_data_buf = buf;
|
|
|
|
memcpy(exe->write_data_buf + exe->write_data_size, data, size);
|
|
|
|
exe->write_data_size += size;
|
|
|
|
|
|
|
|
return 1;
|
2005-10-24 01:53:50 -07: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.
|
|
|
|
* @ingroup Ecore_Exe_Basic_Group
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ecore_exe_tag_set(Ecore_Exe *exe, const char *tag)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_tag_set");
|
2005-10-04 04:35:50 -07:00
|
|
|
return;
|
2005-09-28 06:09:09 -07:00
|
|
|
}
|
|
|
|
if (exe->tag) free(exe->tag);
|
|
|
|
exe->tag = NULL;
|
|
|
|
if (tag) exe->tag = strdup(tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* @param exe The given process handle.
|
|
|
|
* @return The string attached to @p exe.
|
|
|
|
* @ingroup Ecore_Exe_Basic_Group
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
ecore_exe_tag_get(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_tag_get");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
* @ingroup Ecore_Exe_Basic_Group
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
|
|
|
void *
|
|
|
|
ecore_exe_free(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_free");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return _ecore_exe_free(exe);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
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.
|
|
|
|
* @ingroup Ecore_Exe_Basic_Group
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
|
|
|
pid_t
|
|
|
|
ecore_exe_pid_get(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_pid_get");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return exe->pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* Retrieves the data attached to the given process handle.
|
|
|
|
* @param exe The given process handle.
|
|
|
|
* @return The data pointer attached to @p exe.
|
|
|
|
* @ingroup Ecore_Exe_Basic_Group
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
|
|
|
void *
|
|
|
|
ecore_exe_data_get(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_data_get");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return exe->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* @defgroup Ecore_Exe_Signal_Group Spawned Process Signal Functions
|
|
|
|
*
|
|
|
|
* Functions that send signals to spawned processes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Pauses the given process by sending it a @c SIGSTOP signal.
|
|
|
|
* @param exe Process handle to the given process.
|
|
|
|
* @ingroup Ecore_Exe_Signal_Group
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
ecore_exe_pause(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_pause");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
* @ingroup Ecore_Exe_Signal_Group
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
ecore_exe_continue(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_continue");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
kill(exe->pid, SIGCONT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2004-09-21 21:25:35 -07:00
|
|
|
* Sends the given spawned process a terminate (@c SIGTERM) signal.
|
|
|
|
* @param exe Process handle to the given process.
|
|
|
|
* @ingroup Ecore_Exe_Signal_Group
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
ecore_exe_terminate(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_terminate");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
kill(exe->pid, SIGTERM);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
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.
|
|
|
|
* @ingroup Ecore_Exe_Signal_Group
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
ecore_exe_kill(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_kill");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
kill(exe->pid, SIGKILL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
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.
|
|
|
|
* @ingroup Ecore_Exe_Signal_Group
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
ecore_exe_signal(Ecore_Exe *exe, int num)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_signal");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (num == 1)
|
|
|
|
kill(exe->pid, SIGUSR1);
|
|
|
|
else if (num == 2)
|
|
|
|
kill(exe->pid, SIGUSR2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
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.
|
|
|
|
* @ingroup Ecore_Exe_Signal_Group
|
2003-09-23 01:09:32 -07:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
ecore_exe_hup(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
|
|
|
|
{
|
|
|
|
ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
|
|
|
|
"ecore_exe_hup");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
kill(exe->pid, SIGHUP);
|
|
|
|
}
|
|
|
|
|
2005-12-10 14:39:51 -08:00
|
|
|
|
2003-09-23 01:09:32 -07:00
|
|
|
void
|
|
|
|
_ecore_exe_shutdown(void)
|
|
|
|
{
|
|
|
|
while (exes) _ecore_exe_free(exes);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ecore_Exe *
|
|
|
|
_ecore_exe_find(pid_t pid)
|
|
|
|
{
|
2005-08-30 03:05:27 -07:00
|
|
|
Ecore_List2 *l;
|
2003-09-23 01:09:32 -07:00
|
|
|
|
2005-08-30 03:05:27 -07:00
|
|
|
for (l = (Ecore_List2 *)exes; l; l = l->next)
|
2003-09-23 01:09:32 -07:00
|
|
|
{
|
|
|
|
Ecore_Exe *exe;
|
|
|
|
|
|
|
|
exe = (Ecore_Exe *)l;
|
|
|
|
if (exe->pid == pid) return exe;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-12-10 14:39:51 -08:00
|
|
|
static void
|
|
|
|
_ecore_exe_exec_it(const char *exe_cmd)
|
|
|
|
{
|
|
|
|
char use_sh = 1;
|
|
|
|
char* buf = NULL;
|
|
|
|
char** args = NULL;
|
|
|
|
int save_errno = 0;
|
|
|
|
|
|
|
|
if (! strpbrk(exe_cmd, "|&;<>()$`\\\"'*?#"))
|
|
|
|
{
|
|
|
|
char* token;
|
|
|
|
char pre_command = 1;
|
|
|
|
int num_tokens = 0;
|
|
|
|
|
|
|
|
if (! (buf = strdup(exe_cmd)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
free(buf);
|
|
|
|
buf = NULL;
|
|
|
|
if (! token && num_tokens)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
char* token;
|
|
|
|
|
|
|
|
if (! (buf = strdup(exe_cmd)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
token = strtok(buf, " \t\n\v");
|
|
|
|
use_sh = 0;
|
|
|
|
if (! (args = (char**) calloc(num_tokens + 1, sizeof(char*))))
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setsid();
|
|
|
|
if (use_sh)
|
|
|
|
{
|
|
|
|
if (shell == NULL)
|
|
|
|
{
|
|
|
|
shell = getenv("SHELL");
|
|
|
|
if (shell == 0)
|
|
|
|
shell = "/bin/sh";
|
|
|
|
}
|
|
|
|
errno = 0;
|
|
|
|
execl(shell, shell, "-c", exe_cmd, (char *)NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
errno = 0;
|
|
|
|
execvp(args[0], args);
|
|
|
|
}
|
|
|
|
|
|
|
|
save_errno = errno;
|
|
|
|
if (buf)
|
|
|
|
free(buf);
|
|
|
|
if(args)
|
|
|
|
free(args);
|
|
|
|
errno = save_errno;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-09-23 01:09:32 -07:00
|
|
|
void *
|
|
|
|
_ecore_exe_free(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
void *data;
|
2005-10-24 01:53:50 -07:00
|
|
|
|
2003-09-23 01:09:32 -07:00
|
|
|
data = exe->data;
|
2005-11-09 06:09:28 -08:00
|
|
|
|
2005-12-10 14:39:51 -08:00
|
|
|
if (exe->write_fd_handler) ecore_main_fd_handler_del(exe->write_fd_handler);
|
|
|
|
if (exe->read_fd_handler) ecore_main_fd_handler_del(exe->read_fd_handler);
|
|
|
|
if (exe->write_data_buf) free(exe->write_data_buf);
|
|
|
|
if (exe->read_data_buf) free(exe->read_data_buf);
|
|
|
|
if (exe->flags & ECORE_EXE_PIPE_READ) close(exe->child_fd_read); /* FIXME: Check for -1 then errno. */
|
|
|
|
if (exe->flags & ECORE_EXE_PIPE_WRITE) close(exe->child_fd_write); /* FIXME: Check for -1 then errno. */
|
2005-11-09 06:09:28 -08:00
|
|
|
|
2005-08-30 03:05:27 -07:00
|
|
|
exes = _ecore_list2_remove(exes, exe);
|
2003-09-23 01:09:32 -07:00
|
|
|
ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE);
|
2005-09-28 06:09:09 -07:00
|
|
|
if (exe->tag) free(exe->tag);
|
2003-09-23 01:09:32 -07:00
|
|
|
free(exe);
|
|
|
|
return data;
|
|
|
|
}
|
2005-12-10 14:39:51 -08:00
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
_ecore_exe_data_read_handler(void *data, Ecore_Fd_Handler *fd_handler)
|
|
|
|
{
|
|
|
|
Ecore_Exe *exe;
|
|
|
|
|
|
|
|
exe = data;
|
|
|
|
if ((exe->read_fd_handler) && (ecore_main_fd_handler_active_get(exe->read_fd_handler, ECORE_FD_READ)))
|
|
|
|
{
|
|
|
|
unsigned char *inbuf = NULL;
|
|
|
|
int inbuf_num = 0;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
int num, lost_server;
|
|
|
|
char buf[READBUFSIZ];
|
|
|
|
|
|
|
|
lost_server = 0;
|
|
|
|
errno = 0;
|
|
|
|
if ((num = read(exe->child_fd_read, buf, READBUFSIZ)) < 1)
|
|
|
|
{
|
|
|
|
lost_server = ((errno == EIO) ||
|
|
|
|
(errno == EBADF) ||
|
|
|
|
(errno == EPIPE) ||
|
|
|
|
(errno == EINVAL) ||
|
|
|
|
(errno == ENOSPC) ||
|
|
|
|
(num == 0));
|
|
|
|
/* is num == 0 is right - when the server closes us
|
|
|
|
* off we will get this (as this is called when select
|
|
|
|
* tells us there is data to read!)
|
|
|
|
*/
|
|
|
|
if ((errno != EAGAIN) && (errno != EINTR))
|
|
|
|
perror("_ecore_exe_data_handler() read problem ");
|
|
|
|
}
|
|
|
|
if (num < 1)
|
|
|
|
{
|
|
|
|
if (inbuf)
|
|
|
|
{
|
|
|
|
Ecore_Event_Exe_Data *e;
|
|
|
|
|
|
|
|
e = calloc(1, sizeof(Ecore_Event_Exe_Data));
|
|
|
|
if (e)
|
|
|
|
{
|
|
|
|
e->exe = exe;
|
|
|
|
e->data = inbuf;
|
|
|
|
e->size = inbuf_num;
|
|
|
|
ecore_event_add(ECORE_EVENT_EXE_DATA, e,
|
|
|
|
_ecore_exe_event_exe_data_free, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lost_server)
|
|
|
|
{
|
|
|
|
/* we lost our server! */
|
|
|
|
ecore_exe_terminate(exe);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inbuf = realloc(inbuf, inbuf_num + num);
|
|
|
|
memcpy(inbuf + inbuf_num, buf, num);
|
|
|
|
inbuf_num += num;
|
|
|
|
/* FIXME:
|
|
|
|
* when fd handlers report data - if line buffering is not enabled instantly
|
|
|
|
* copy data to a exe data event struct and add the event like ecore_con. if
|
|
|
|
* line buffering is enabled, parse new data block for a \n. if there is
|
|
|
|
* none, then simply append to read buf. if there are 1 or more, append
|
|
|
|
* until, and including the first \n, to the existing read buf (if any) then
|
|
|
|
* generate data event for that. repeat for each other \n found until no \n
|
|
|
|
* chars are left, then take trailing data (if any) and put in read buf
|
|
|
|
* waiting for more data.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
_ecore_exe_data_write_handler(void *data, Ecore_Fd_Handler *fd_handler)
|
|
|
|
{
|
|
|
|
Ecore_Exe *exe;
|
|
|
|
|
|
|
|
exe = data;
|
|
|
|
if ((exe->write_fd_handler) && (ecore_main_fd_handler_active_get(exe->write_fd_handler, ECORE_FD_WRITE)))
|
|
|
|
_ecore_exe_flush(exe);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_ecore_exe_flush(Ecore_Exe *exe)
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
|
|
|
|
/* check whether we need to write anything at all. */
|
|
|
|
if ((!exe->child_fd_write) && (!exe->write_data_buf)) return;
|
|
|
|
if (exe->write_data_size == exe->write_data_offset) return;
|
|
|
|
|
|
|
|
count = write(exe->child_fd_write,
|
|
|
|
exe->write_data_buf + exe->write_data_offset,
|
|
|
|
exe->write_data_size - exe->write_data_offset);
|
|
|
|
if (count < 1)
|
|
|
|
{
|
|
|
|
if (errno == EIO || errno == EBADF ||
|
|
|
|
errno == EPIPE || errno == EINVAL ||
|
|
|
|
errno == ENOSPC) /* we lost our server! */
|
|
|
|
ecore_exe_terminate(exe);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
exe->write_data_offset += count;
|
|
|
|
if (exe->write_data_offset >= exe->write_data_size)
|
|
|
|
{
|
|
|
|
exe->write_data_size = 0;
|
|
|
|
exe->write_data_offset = 0;
|
|
|
|
free(exe->write_data_buf);
|
|
|
|
exe->write_data_buf = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_ecore_exe_event_exe_data_free(void *data __UNUSED__, void *ev)
|
|
|
|
{
|
|
|
|
Ecore_Event_Exe_Data *e;
|
|
|
|
|
|
|
|
e = ev;
|
|
|
|
if (e->data) free(e->data);
|
|
|
|
free(e);
|
|
|
|
}
|
2004-10-20 10:51:29 -07:00
|
|
|
#endif
|