diff --git a/legacy/ecore/src/lib/ecore/Ecore.h b/legacy/ecore/src/lib/ecore/Ecore.h index ff396ee50f..1b7d822618 100644 --- a/legacy/ecore/src/lib/ecore/Ecore.h +++ b/legacy/ecore/src/lib/ecore/Ecore.h @@ -55,14 +55,15 @@ extern "C" { #endif -#define ECORE_EVENT_NONE 0 -#define ECORE_EVENT_EXE_EXIT 1 /**< Spawned Exe has exit event */ -#define ECORE_EVENT_SIGNAL_USER 2 /**< User signal event */ -#define ECORE_EVENT_SIGNAL_HUP 3 /**< Hup signal event */ -#define ECORE_EVENT_SIGNAL_EXIT 4 /**< Exit signal event */ -#define ECORE_EVENT_SIGNAL_POWER 5 /**< Power signal event */ +#define ECORE_EVENT_NONE 0 +#define ECORE_EVENT_EXE_EXIT 1 /**< Spawned Exe has exit event */ +#define ECORE_EVENT_SIGNAL_USER 2 /**< User signal event */ +#define ECORE_EVENT_SIGNAL_HUP 3 /**< Hup signal event */ +#define ECORE_EVENT_SIGNAL_EXIT 4 /**< Exit signal event */ +#define ECORE_EVENT_SIGNAL_POWER 5 /**< Power signal event */ #define ECORE_EVENT_SIGNAL_REALTIME 6 /**< Realtime signal event */ -#define ECORE_EVENT_COUNT 7 +#define ECORE_EVENT_EXE_DATA 7 /**< Data from a child process */ +#define ECORE_EVENT_COUNT 8 #ifndef _ECORE_PRIVATE_H enum _Ecore_Fd_Handler_Flags @@ -73,6 +74,14 @@ extern "C" { }; typedef enum _Ecore_Fd_Handler_Flags Ecore_Fd_Handler_Flags; + enum _Ecore_Exe_Flags /* FIXME: flags for executing a child with its stdin and/or stdout piped back */ + { + ECORE_EXE_PIPE_READ = 1, /**< Exe Pipe Read mask */ + ECORE_EXE_PIPE_WRITE = 2, /**< Exe Pipe Write mask */ + ECORE_EXE_PIPE_READ_LINE_BUFFERED = 4 /**< Reads are buffered until a newline and delivered 1 event per line */ + }; + typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags; + #ifndef WIN32 typedef void Ecore_Exe; /**< A handle for spawned processes */ #endif @@ -86,12 +95,13 @@ extern "C" { typedef void Ecore_Event; /**< A handle for an event */ typedef void Ecore_Animator; /**< A handle for animators */ #endif - typedef struct _Ecore_Event_Exe_Exit Ecore_Event_Exe_Exit; /**< Spawned Exe exit event */ - typedef struct _Ecore_Event_Signal_User Ecore_Event_Signal_User; /**< User signal event */ - typedef struct _Ecore_Event_Signal_Hup Ecore_Event_Signal_Hup; /**< Hup signal event */ - typedef struct _Ecore_Event_Signal_Exit Ecore_Event_Signal_Exit; /**< Exit signal event */ - typedef struct _Ecore_Event_Signal_Power Ecore_Event_Signal_Power; /**< Power signal event */ + typedef struct _Ecore_Event_Exe_Exit Ecore_Event_Exe_Exit; /**< Spawned Exe exit event */ + typedef struct _Ecore_Event_Signal_User Ecore_Event_Signal_User; /**< User signal event */ + typedef struct _Ecore_Event_Signal_Hup Ecore_Event_Signal_Hup; /**< Hup signal event */ + typedef struct _Ecore_Event_Signal_Exit Ecore_Event_Signal_Exit; /**< Exit signal event */ + typedef struct _Ecore_Event_Signal_Power Ecore_Event_Signal_Power; /**< Power signal event */ typedef struct _Ecore_Event_Signal_Realtime Ecore_Event_Signal_Realtime; /**< Realtime signal event */ + typedef struct _Ecore_Event_Exe_Data Ecore_Event_Exe_Data; /**< Data from a child process */ #ifndef WIN32 struct _Ecore_Event_Exe_Exit /** Process exit event */ @@ -156,6 +166,15 @@ extern "C" { #endif }; +#ifndef WIN32 + struct _Ecore_Event_Exe_Data /** Data from a child process event */ + { + Ecore_Exe *exe; /**< The handle to the process */ + void *data; /**< the raw binary data from the child process that was recieved */ + int size; /**< the size of this data in bytes */ + }; +#endif + EAPI int ecore_init(void); EAPI int ecore_shutdown(void); @@ -176,6 +195,8 @@ extern "C" { #ifndef WIN32 EAPI Ecore_Exe *ecore_exe_run(const char *exe_cmd, const void *data); + EAPI Ecore_Exe *ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data); + EAPI int ecore_exe_pipe_write(Ecore_Exe *exe, void *data, int size); EAPI void *ecore_exe_free(Ecore_Exe *exe); EAPI pid_t ecore_exe_pid_get(Ecore_Exe *exe); EAPI void ecore_exe_tag_set(Ecore_Exe *exe, const char *tag); diff --git a/legacy/ecore/src/lib/ecore/ecore_exe.c b/legacy/ecore/src/lib/ecore/ecore_exe.c index bbe02810e4..7db58117a5 100644 --- a/legacy/ecore/src/lib/ecore/ecore_exe.c +++ b/legacy/ecore/src/lib/ecore/ecore_exe.c @@ -52,6 +52,92 @@ ecore_exe_run(const char *exe_cmd, const void *data) return NULL; } +/** + * 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 + * until a newline character if asked to wit the @p flags. All data will be + * 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) +{ + Ecore_Exe *exe; + pid_t pid; + + /* FIXME: + * if flags does not have read or write in them - just execute using + * ecore_exe_run() as normal. + * pipe() to creeate pipes (as necessary accoring to flags) + * in child close() parent side of pipes + * in child dup2() stdin, stdout (according to flags as necessary) + * in parent (here) close() child side of pipes + * set up fd's in ecore_exe struct FIXME - add to struct + * set up fd handler in ecore_exe struct + * see ecore_con for code and examples on this (fd's there are to a socket + * but otherwise work the same as here). the ECORE_EVENT_EXE_EXIT event + * aces like the client del event from ecore_con - signalling that the + * connection is closed. once this event has been handled the child + * ecore_exe struct is freed automatically and is no longer valid. + */ + if (!exe_cmd) return NULL; + pid = fork(); + 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; + exes = _ecore_list2_append(exes, exe); + return exe; + } + setsid(); + execl("/bin/sh", "/bin/sh", "-c", exe_cmd, (char *)NULL); + exit(127); + return NULL; +} + +/** + * 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) +{ + /* FIXME: add data to buffer and flag fd handlers to wake up when write + * to child fd is available, and when it is, flush as much data as possible + * at that time (much like ecore_con). this means the parent is mallocing + * its own write buffer in process space - giving us potentially huge + * buffers, so synchronisation needs to be done at a higher level here as + * buffers could just get huge + */ + return 0; +} + /** * Sets the string tag for the given process handle * @@ -292,7 +378,8 @@ void * _ecore_exe_free(Ecore_Exe *exe) { void *data; - + + /* FIXME: close fdhanlders and free buffers if they exist */ data = exe->data; exes = _ecore_list2_remove(exes, exe); ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE); diff --git a/legacy/ecore/src/lib/ecore/ecore_private.h b/legacy/ecore/src/lib/ecore/ecore_private.h index 287ba6bc20..b44127fc1f 100644 --- a/legacy/ecore/src/lib/ecore/ecore_private.h +++ b/legacy/ecore/src/lib/ecore/ecore_private.h @@ -116,6 +116,13 @@ enum _Ecore_Fd_Handler_Flags ECORE_FD_ERROR = 4 }; typedef enum _Ecore_Fd_Handler_Flags Ecore_Fd_Handler_Flags; +enum _Ecore_Exe_Flags +{ + ECORE_EXE_PIPE_READ = 1, + ECORE_EXE_PIPE_WRITE = 2, + ECORE_EXE_PIPE_READ_LINE_BUFFERED = 4 +}; +typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags; #ifndef WIN32 typedef struct _Ecore_Exe Ecore_Exe; @@ -138,6 +145,11 @@ struct _Ecore_Exe pid_t pid; void *data; char *tag; + Ecore_Fd_Handler *fd_handler; /* FIXME: the fd_handler to handle read/write to child - if this was used, or NULL if not */ + void *data_buf; /* FIXME: 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 data_size; /* FIXME: the size in bytes of the data buffer */ + int child_fd_write; /* FIXME: fd to write TO to send data to the child */ + int child_fd_read; /* FIXME: fd to read FROM whne child has send us (parent) data */ }; #endif diff --git a/legacy/ecore/src/lib/ecore/ecore_signal.c b/legacy/ecore/src/lib/ecore/ecore_signal.c index fb45b1b246..b573ce6d9d 100644 --- a/legacy/ecore/src/lib/ecore/ecore_signal.c +++ b/legacy/ecore/src/lib/ecore/ecore_signal.c @@ -161,6 +161,12 @@ _ecore_signal_call(void) { Ecore_Event_Exe_Exit *e; + /* FIXME: If this process is set to read from the child, DELAY + * the exe event until the pipe from the child dies and reports + * errors - THEN report and exe - so store this exe value in the + * ecore_exe struct waiting for the read fd to die then report + * final read data, THEN this exit event + */ e = _ecore_event_exe_exit_new(); if (e) {