lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hullo all,

I've made myself a small C module for Lua that allows to call an external program while capturing both the input and output streams (using the classic combinaison of fork/exec/dup2) and to ask if
a file handle is readable/writable and to bind the "wait" system call.

Now when I do that(see code below) it works all fine except when one of my file handles needs to
be garbage collected I get a nasty segfault.
But if I put my code into lua's liolib.c (registering it in luaL_Reg iolib[]) and compile it, it works just fine. The crash happens in liolib.c:aux_close():120, seemingly missing the "__close" field. I'm creating my handle the same way iolib does, assigning the metatable, so there must be something very
basic and stupid I'm forgetting right?

Thanks for your help

Relevant code:
static FILE **newfile_fd(lua_State *L, int fd, const char *mode)
{
   FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
   *pf = NULL;  /* file handle is currently `closed' */
   luaL_getmetatable(L, LUA_FILEHANDLE);
   lua_setmetatable(L, -2);

   *pf = fdopen(fd, mode);

   return pf;
}

static int lpc_run(lua_State *L)
{
   int p_out[2];
   int p_in[2];
   int pid;

   if (pipe(p_out) == -1) { lua_pushnil(L); return 1; }
   if (pipe(p_in) == -1)  { lua_pushnil(L); return 1; }

   if ((pid = fork()) == -1) { lua_pushnil(L); return 1; }
   else if (pid == 0)
   {
       char **args;
       int n = lua_gettop(L);  /* number of arguments */
       int i;
       args = luaM_malloc(L, (n + 1) * sizeof(char*));
       for (i = 1; i <= n; i++)
       {
           args[i - 1] = (char*)luaL_checkstring(L, i);
       }
       args[n] = NULL;

       close(p_out[1]);
       close(p_in[0]);
       dup2(p_out[0], 0);
       dup2(p_in[1], 1);
       close(p_out[0]);
       close(p_in[1]);

       execvp(args[0], args);

       perror("LPC child error");
       _exit(1);
       return 0;
   }
   else
   {
       FILE **in;
       FILE **out;

       /* Cleanup */
       close(p_out[0]);
       close(p_in[1]);

       lua_pushnumber(L, pid);
       out = newfile_fd(L, p_out[1], "w");
       in = newfile_fd(L, p_in[0], "r");
       return 3;
   }
}