# # # add_dir "tests/spawn_pipe" # # add_file "tests/spawn_pipe/__driver__.lua" # content [b6b2fbb790474725f0001aceabc3f2bfa00f4aa0] # # add_file "tests/spawn_pipe/testhooks" # content [b1735be0668a2b9768f96add9dbb2eb27022f287] # # patch "lua_hooks.cc" # from [02a923f2e6c785ccc218a67ba83acbbbc04a179b] # to [7455b70dc877298e9c99d421a6f6e3a219ddfb3e] # # patch "luaext_platform.cc" # from [6976e27d72d532b83eb7ca05067e9835b2e0f582] # to [85950c0a7933f6df1c9261172a4df13a0b354255] # # patch "platform.hh" # from [7224b228b7c8f0476b45ed5fb929aba4d6878fd5] # to [2aa9734b2d5a30bce47c8c2f12e8d6729451baf9] # # patch "unix/process.cc" # from [d00d8b746198ce7ca79923ba000d947587b8b485] # to [faa15cf6776000e3dfd3ab41fc4b209daad10e87] # # patch "win32/process.cc" # from [cc87fd97460d2c5245792aca838469129f098e6b] # to [35decb7bfc80bcd54893ce784c325c71c1415e3d] # ============================================================ --- tests/spawn_pipe/__driver__.lua b6b2fbb790474725f0001aceabc3f2bfa00f4aa0 +++ tests/spawn_pipe/__driver__.lua b6b2fbb790474725f0001aceabc3f2bfa00f4aa0 @@ -0,0 +1,9 @@ + +mtn_setup() + +check(get("testhooks")) + +xfail_if(ostype == "Windows", raw_mtn("--rcfile=testhooks", "ls", "unknown"), 0, false, false) + +skip_if(exists("skipfile")) +check(exists("outfile")) ============================================================ --- tests/spawn_pipe/testhooks b1735be0668a2b9768f96add9dbb2eb27022f287 +++ tests/spawn_pipe/testhooks b1735be0668a2b9768f96add9dbb2eb27022f287 @@ -0,0 +1,42 @@ +function ignore_file (name) + ok = true + + mytext = "text from lua1" + + result = "ok" + + if ok then + if existsonpath("cat") == 0 then + procfin, procfout, pid = spawn_pipe("cat") + if pid == -1 then + result = "no pid" + ok = false + else + procfin:write(mytext) + procfin:close() + line, errstr = procfout:read() + if line == nil then + result = "no line" + ok = false + elseif line ~= mytext then + result = "Expected: " .. mytext .. "\nRead: " .. line + ok = false + end + procfout:close() + ret, pid = wait(pid) + end + else + result = "Lacking cat" + x = io.open("skipfile", "w") + x:close() + end + end + + if ok then + x = io.open("outfile", "w") + x:close() + end + + ignore_file = function (name) return true end + return true +end ============================================================ --- lua_hooks.cc 02a923f2e6c785ccc218a67ba83acbbbc04a179b +++ lua_hooks.cc 7455b70dc877298e9c99d421a6f6e3a219ddfb3e @@ -92,8 +92,10 @@ lua_hooks::lua_hooks() // Disable any functions we don't want. This is easiest // to do just by running a lua string. if (!run_string(st, - "os.execute = nil " - "io.popen = nil ", + // "os.unsafeexecute = os.execute " + // "io.unsafepopen = io.popen " + "os.execute = function(c) error(\"os.execute disabled for security reasons. Try spawn().\") end " + "io.popen = function(c,t) error(\"io.popen disabled for security reasons. Try spawn_pipe().\") end ", string(""))) throw oops("lua error while disabling existing functions"); } ============================================================ --- luaext_platform.cc 6976e27d72d532b83eb7ca05067e9835b2e0f582 +++ luaext_platform.cc 85950c0a7933f6df1c9261172a4df13a0b354255 @@ -78,6 +78,59 @@ LUAEXT(spawn_redirected, ) return 1; } +// borrowed from lua/liolib.cc +// Note that making C functions that return FILE* in Lua is tricky +// There is a Lua FAQ entitled: +// "Why does my library-created file segfault on :close() but work otherwise?" + +#define topfile(L) ((FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE)) + +static int io_fclose (lua_State *L) { + FILE **p = topfile(L); + int ok = (fclose(*p) == 0); + *p = NULL; + lua_pushboolean(L, ok); + return 1; +} + +static FILE **newfile (lua_State *L) { + FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); + *pf = NULL; /* file handle is currently `closed' */ + luaL_getmetatable(L, LUA_FILEHANDLE); + lua_setmetatable(L, -2); + + lua_pushcfunction(L, io_fclose); + lua_setfield(L, LUA_ENVIRONINDEX, "__close"); + + return pf; +} + +LUAEXT(spawn_pipe, ) +{ + int n = lua_gettop(L); + char **argv = (char**)malloc((n+1)*sizeof(char*)); + int i; + pid_t pid; + if (argv==NULL) + return 0; + if (n<1) + return 0; + for (i=0; i(luaL_checknumber(L, -1)); ============================================================ --- platform.hh 7224b228b7c8f0476b45ed5fb929aba4d6878fd5 +++ platform.hh 2aa9734b2d5a30bce47c8c2f12e8d6729451baf9 @@ -29,6 +29,7 @@ pid_t process_spawn_redirected(char cons char const * out, char const * err, char const * const argv[]); +pid_t process_spawn_pipe(char const * const argv[], FILE** in, FILE** out); int process_wait(pid_t pid, int *res, int timeout = -1);// default infinite int process_kill(pid_t pid, int signal); int process_sleep(unsigned int seconds); ============================================================ --- unix/process.cc d00d8b746198ce7ca79923ba000d947587b8b485 +++ unix/process.cc faa15cf6776000e3dfd3ab41fc4b209daad10e87 @@ -163,6 +163,56 @@ pid_t process_spawn_redirected(char cons } } +pid_t process_spawn_pipe(char const * const argv[], FILE** in, FILE** out) +{ + int infds[2]; + int outfds[2]; + pid_t pid; + + if (pipe(infds) < 0) + return -1; + if (pipe(outfds) < 0) + { + close(infds[0]); + close(infds[1]); + return -1; + } + + switch(pid = vfork()) + { + case -1: + close(infds[0]); + close(infds[1]); + close(outfds[0]); + close(outfds[1]); + return -1; + case 0: + { + if (infds[0] != STDIN_FILENO) + { + dup2(infds[0], STDIN_FILENO); + close(infds[0]); + } + close(infds[1]); + if (outfds[1] != STDOUT_FILENO) + { + dup2(outfds[1], STDOUT_FILENO); + close(outfds[1]); + } + close(outfds[0]); + + execvp(argv[0], (char * const *)argv); + raise(SIGKILL); + } + } + close(infds[0]); + close(outfds[1]); + *in = fdopen(infds[1], "w"); + *out = fdopen(outfds[0], "r"); + + return pid; +} + int process_wait(pid_t pid, int *res, int timeout) { int status; ============================================================ --- win32/process.cc cc87fd97460d2c5245792aca838469129f098e6b +++ win32/process.cc 35decb7bfc80bcd54893ce784c325c71c1415e3d @@ -228,6 +228,12 @@ pid_t process_spawn_redirected(char cons } } +pid_t process_spawn_pipe(char const * const argv[], FILE** in, FILE** out) +{ + // XXX: not implemented on Win32 yet + return -1; +} + int process_wait(pid_t pid, int *res, int timeout) { HANDLE hProcess = (HANDLE)pid;