diff options
author | Christian Pointner <equinox@spreadspace.org> | 2010-11-22 01:29:23 +0000 |
---|---|---|
committer | Christian Pointner <equinox@spreadspace.org> | 2010-11-22 01:29:23 +0000 |
commit | a02695a4c39ebbea948dd52eb8ee184174011f3b (patch) | |
tree | caeea81bd4c25e7a3cd4d3c3bb05b1f35830519b | |
parent | environment pointer works now at exec (diff) |
added error pipe in case execve returns - not working yet..
git-svn-id: https://svn.spreadspace.org/gcsd/trunk@47 ac14a137-c7f1-4531-abe0-07747231d213
-rw-r--r-- | src/l_util.c | 132 | ||||
-rw-r--r-- | src/l_util.h | 1 |
2 files changed, 131 insertions, 2 deletions
diff --git a/src/l_util.c b/src/l_util.c index 0b417ac..6ef6236 100644 --- a/src/l_util.c +++ b/src/l_util.c @@ -219,6 +219,103 @@ void free_ptrptr(char** ptrptr) free(ptrptr); } +struct child_struct { + pid_t pid_; + int fd_; + struct child_struct* next_; +}; +typedef struct child_struct child_t; + +child_t* child_get_last(child_t* first) +{ + if(!first) + return NULL; + + while(first->next_) { + first = first->next_; + } + return first; +} + +int child_add(lua_State *L, pid_t pid, int fd) +{ + lua_getglobal(L, LUA_UTILLIBNAME); + lua_getfield(L, -1, LUA_UTILCHLIDRENNAME); + child_t* first = lua_touserdata(L, -1); + lua_pop(L, 1); + + child_t* new_child = malloc(sizeof(child_t)); + if(!new_child) + return -1; + + new_child->pid_ = pid; + new_child->fd_ = fd; + new_child->next_ = NULL; + if(!first) { + lua_pushlightuserdata(L, new_child); + lua_setfield(L, -2, LUA_UTILCHLIDRENNAME); + lua_pop(L, 1); + return 0; + } + child_get_last(first)->next_ = new_child; + lua_pop(L, 1); + return 0; +} + +void child_remove(lua_State *L, pid_t pid) +{ + lua_getglobal(L, LUA_UTILLIBNAME); + lua_getfield(L, -1, LUA_UTILCHLIDRENNAME); + child_t* first = lua_touserdata(L, -1); + if(!first) { + lua_pop(L, 2); + return; + } + lua_pop(L, 1); + + child_t* deletee = first; + if(first->pid_ == pid) { + lua_pushlightuserdata(L, first->next_); + lua_setfield(L, -2, LUA_UTILCHLIDRENNAME); + lua_pop(L, 1); + close(deletee->fd_); + free(deletee); + return; + } + lua_pop(L, 1); + child_t* prev = deletee; + deletee = deletee->next_; + while(deletee) { + if(deletee->pid_ == pid) { + prev->next_ = deletee->next_; + close(deletee->fd_); + free(deletee); + return; + } + prev = deletee; + deletee = deletee->next_; + } +} + +child_t* child_find(lua_State *L, pid_t pid) +{ + lua_getglobal(L, LUA_UTILLIBNAME); + lua_getfield(L, -1, LUA_UTILCHLIDRENNAME); + child_t* first = lua_touserdata(L, -1); + lua_pop(L, 2); + + if(!first) + return NULL; + + while(first) { + if(first->pid_ == pid) + return first; + + first = first->next_; + } + return NULL; +} + static int l_util_exec(lua_State *L) { const char* script = luaL_checkstring(L, 1); @@ -231,10 +328,17 @@ static int l_util_exec(lua_State *L) return 2; } + int pipefd[2]; + if(pipe(pipefd) == -1) { + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); // FIXXXXXME: strerror is not threadsafe!!! + return 2; + } + if(!pid) { int fd; for (fd=getdtablesize();fd>=0;--fd) // close all file descriptors - close(fd); + if(fd != pipefd[1]) close(fd); char** argv = table_to_argv(L, script, 2); char** evp = table_to_evp(L, 3); @@ -245,11 +349,17 @@ static int l_util_exec(lua_State *L) } execve(script, argv, evp); + // if execve returns, an error occurred, but logging doesn't work + // because we closed all file descriptors, so just write errno to + // pipe and call exit + int ret = write(pipefd[1], (void*)(&errno), sizeof(errno)); free_ptrptr(argv); free_ptrptr(evp); lua_close(L); - exit(-1); + exit(ret); } + close(pipefd[1]); + child_add(L, pid, pipefd[0]); lua_pushinteger(L, pid); return 1; @@ -270,6 +380,22 @@ static int l_util_waitpid(lua_State *L) } lua_pushinteger(L, pid); + child_t* child = child_find(L, pid); + if(child) { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(child->fd_, &rfds); + struct timeval tv = { 0 , 0 }; + if(select(child->fd_+1, &rfds, NULL, NULL, &tv) == 1) { + int err = 0; + if(read(child->fd_, (void*)(&err), sizeof(err)) >= sizeof(err)) { + lua_pushliteral(L, "error"); + lua_pushstring(L, strerror(errno)); // FIXXXXXME: strerror is not threadsafe!!! + return 3; + } + } + child_remove(L, pid); + } if(WIFEXITED(status)) { lua_pushliteral(L, "exit"); lua_pushinteger(L, WEXITSTATUS(status)); @@ -309,5 +435,7 @@ static const struct luaL_reg util_funcs [] = { LUALIB_API int luaopen_util(lua_State *L) { luaL_register(L, LUA_UTILLIBNAME, util_funcs); + lua_pushlightuserdata(L, NULL); + lua_setfield(L, -2, LUA_UTILCHLIDRENNAME); return 1; } diff --git a/src/l_util.h b/src/l_util.h index c0b558a..14422b8 100644 --- a/src/l_util.h +++ b/src/l_util.h @@ -36,6 +36,7 @@ #include <lua.h> #define LUA_UTILLIBNAME "util" +#define LUA_UTILCHLIDRENNAME "__children" LUALIB_API int luaopen_util(lua_State *L); #endif |