`os.execute` special output is still undocumented
The thread https://tug.org/pipermail/luatex/2015-November/005536.html points out that `os.execute` is still version `5.1`. It is said there that "one can always wrap os.execute into something that does what one wants" How to do that to get the "5.3" output of `os.execute`, in any situation of course? This design policy is so special that it should definitely be documented.
Hi Jérôme, On Sun, 2024-06-09 at 17:35 +0200, Jérôme LAURENS wrote:
The thread https://tug.org/pipermail/luatex/2015-November/005536.html points out that `os.execute` is still version `5.1`. It is said there that "one can always wrap os.execute into something that does what one wants" How to do that to get the "5.3" output of `os.execute`, in any situation of course?
I can think of two possible implementations, both with varying trade-offs. The first one manually decodes the return value of "os.execute" from Lua. The precise encoding of the return value is platform-dependent, so this option isn't portable. The second one uses the FFI module to access the Lua C API directly. This solution is portable across different platforms, but it's technically undefined behaviour to modify the current Lua state from Lua code. %% Option 1: Non-portable, but less dangerous. \directlua{ local orig_execute = os.execute function os.execute(cmd) local status = orig_execute(cmd) %% The following works on (at least) Linux, but is not portable. local signal = status & 0x7F local exit = (status & 0xFF00) >> 8 if status == 0 then return true, "exit", status elseif signal == 0 then return nil, "exit", exit elseif exit == 0 then return nil, "signal", signal end end } %% Option 2: Portable, but more dangerous. \directlua{ %% We need unrestricted shell escape for this to work, but that is quite %% likely given that you're running "os.execute". local ffi = require("ffi") ffi.cdef[[ typedef struct lua_State lua_State; typedef int (*lua_CFunction) (lua_State *L); lua_State *Luas; void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb); int luaopen_os (lua_State *L); ]] %% Not technically safe to do this from Lua, but it seems to work okay. ffi.C.luaL_requiref(ffi.C.Luas, "lua_os", ffi.C.luaopen_os, 1) os.execute = lua_os.execute } \bye Thanks, -- Max
participants (2)
-
Jérôme LAURENS
-
Max Chernoff