feat: allow passing G_SPAWN stdio flags to awesome.spawn (#3932)
Fixes: #3865 Currently works by allowing the exact strings "DEV_NULL" or "INHERIT" to be passed to return_std*. Signed-off-by: aarondill <aaronsacks2006@gmail.com>
This commit is contained in:
parent
fcd23a7478
commit
0f950cbb62
84
spawn.c
84
spawn.c
|
@ -412,9 +412,21 @@ spawn_child_exited(pid_t pid, int status)
|
|||
*
|
||||
* @tparam string|table cmd The command to launch.
|
||||
* @tparam[opt=true] boolean use_sn Use startup-notification?
|
||||
* @tparam[opt=false] boolean stdin Return a fd for stdin?
|
||||
* @tparam[opt=false] boolean stdout Return a fd for stdout?
|
||||
* @tparam[opt=false] boolean stderr Return a fd for stderr?
|
||||
* @tparam[opt="DEV_NULL"] boolean|string stdin Pass `true` to return a fd for
|
||||
* stdin. Use `"DEV_NULL"` to redirect to /dev/null, or `"INHERIT"` to inherit
|
||||
* the parent's stdin. Implementation note: Pre-2.74 glib doesn't support
|
||||
* *explicit* `DEV_NULL`. When `DEV_NULL` is passed on glib <2.74, Awesome will
|
||||
* use glib's default behaviour.
|
||||
* @tparam[opt="INHERIT"] boolean|string stdout Pass `true` to return a fd for
|
||||
* stdout. Use `"DEV_NULL"` to redirect to /dev/null, or `"INHERIT"` to
|
||||
* inherit the parent's stdout. Implementation note: Pre-2.74 glib doesn't
|
||||
* support *explicit* `INHERIT`. When `INHERIT` is passed on glib <2.74,
|
||||
* Awesome will use glib's default behaviour.
|
||||
* @tparam[opt="INHERIT"] boolean|string stderr Pass `true` to return a fd for
|
||||
* stderr. Use `"DEV_NULL"` to redirect to /dev/null, or `"INHERIT"` to
|
||||
* inherit the parent's stderr. Implementation note: Pre-2.74 glib doesn't
|
||||
* support *explicit* `INHERIT`. When `INHERIT` is passed on glib <2.74,
|
||||
* Awesome will use glib's default behaviour.
|
||||
* @tparam[opt=nil] function exit_callback Function to call on process exit. The
|
||||
* function arguments will be type of exit ("exit" or "signal") and the exit
|
||||
* code / the signal number causing process termination.
|
||||
|
@ -441,12 +453,66 @@ luaA_spawn(lua_State *L)
|
|||
|
||||
if(lua_gettop(L) >= 2)
|
||||
use_sn = luaA_checkboolean(L, 2);
|
||||
if(lua_gettop(L) >= 3)
|
||||
return_stdin = luaA_checkboolean(L, 3);
|
||||
if(lua_gettop(L) >= 4)
|
||||
return_stdout = luaA_checkboolean(L, 4);
|
||||
if(lua_gettop(L) >= 5)
|
||||
return_stderr = luaA_checkboolean(L, 5);
|
||||
/* Valid values for return_std* are:
|
||||
* true -> return a fd
|
||||
* false -> keep glib's default behaviour
|
||||
* "DEV_NULL" -> use direct output to /dev/null
|
||||
* "INHERIT" -> use the same fd as the parent
|
||||
*/
|
||||
if(lua_gettop(L) >= 3) {
|
||||
if (lua_isstring(L, 3)) {
|
||||
const char *str = lua_tostring(L, 3);
|
||||
if (a_strcmp(str, "DEV_NULL") == 0){
|
||||
// This is the default behaviour. Compiles to a no-op before 2.74.
|
||||
#if GLIB_CHECK_VERSION(2, 74, 0)
|
||||
flags |= G_SPAWN_STDIN_FROM_DEV_NULL;
|
||||
# endif
|
||||
} else if (a_strcmp(str, "INHERIT") == 0)
|
||||
flags |= G_SPAWN_CHILD_INHERITS_STDIN;
|
||||
else
|
||||
luaA_typerror(L, 3, "DEV_NULL or INHERIT");
|
||||
} else if(lua_isboolean(L, 3)) {
|
||||
return_stdin = lua_toboolean(L, 3);
|
||||
} else {
|
||||
luaA_typerror(L, 3, "boolean or string");
|
||||
}
|
||||
}
|
||||
if(lua_gettop(L) >= 4) {
|
||||
if (lua_isstring(L, 4)) {
|
||||
const char *str = lua_tostring(L, 4);
|
||||
if (a_strcmp(str, "DEV_NULL") == 0)
|
||||
flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
|
||||
else if (a_strcmp(str, "INHERIT") == 0) {
|
||||
// This is the default behaviour. Compiles to a no-op before 2.74.
|
||||
#if GLIB_CHECK_VERSION(2, 74, 0)
|
||||
flags |= G_SPAWN_CHILD_INHERITS_STDOUT;
|
||||
# endif
|
||||
} else
|
||||
luaA_typerror(L, 4, "DEV_NULL or INHERIT");
|
||||
} else if(lua_isboolean(L, 4)) {
|
||||
return_stdout = lua_toboolean(L, 4);
|
||||
} else {
|
||||
luaA_typerror(L, 4, "boolean or string");
|
||||
}
|
||||
}
|
||||
if(lua_gettop(L) >= 5) {
|
||||
if (lua_isstring(L, 5)) {
|
||||
const char *str = lua_tostring(L, 5);
|
||||
if (a_strcmp(str, "DEV_NULL") == 0)
|
||||
flags |= G_SPAWN_STDERR_TO_DEV_NULL;
|
||||
else if (a_strcmp(str, "INHERIT") == 0) {
|
||||
// This is the default behaviour. Compiles to a no-op before 2.74.
|
||||
#if GLIB_CHECK_VERSION(2, 74, 0)
|
||||
flags |= G_SPAWN_CHILD_INHERITS_STDERR;
|
||||
# endif
|
||||
} else
|
||||
luaA_typerror(L, 5, "DEV_NULL or INHERIT");
|
||||
} else if(lua_isboolean(L, 5)) {
|
||||
return_stderr = lua_toboolean(L, 5);
|
||||
} else {
|
||||
luaA_typerror(L, 5, "boolean or string");
|
||||
}
|
||||
}
|
||||
if (!lua_isnoneornil(L, 6))
|
||||
{
|
||||
luaA_checkfunction(L, 6);
|
||||
|
|
|
@ -10,6 +10,7 @@ end
|
|||
|
||||
local spawns_done = 0
|
||||
local async_spawns_done = 0
|
||||
local io_spawns_done = 0
|
||||
local exit_yay, exit_snd = nil, nil
|
||||
|
||||
-- * Using spawn with array is already covered by the test client.
|
||||
|
@ -161,6 +162,72 @@ local steps = {
|
|||
return true
|
||||
end
|
||||
end,
|
||||
-- Test inheriting stdio
|
||||
function(count)
|
||||
if count == 1 then
|
||||
do -- Test that DEV_NULL works and doesn't return a fd
|
||||
local read_line = false
|
||||
local pid, _, _, stdout, stderr = awesome.spawn({ 'readlink', '/proc/self/fd/2' },
|
||||
false, false, true, "DEV_NULL")
|
||||
assert(type(pid) ~= "string", pid)
|
||||
assert(stderr == nil)
|
||||
spawn.read_lines(require("lgi").Gio.UnixInputStream.new(stdout, true),
|
||||
function(line)
|
||||
assert(not read_line)
|
||||
read_line = true
|
||||
assert(line == "/dev/null", line)
|
||||
io_spawns_done = io_spawns_done + 1
|
||||
end, nil, true)
|
||||
end
|
||||
|
||||
do -- Test that INHERIT works and doesn't return a fd
|
||||
-- Note: if this is /dev/null, this test is useless.
|
||||
local test_stdin = require('lgi').GLib.file_read_link('/proc/self/fd/0')
|
||||
|
||||
local read_line = false
|
||||
local pid, _, stdin, stdout = awesome.spawn({ 'readlink', '/proc/self/fd/0' },
|
||||
false, "INHERIT", true, false)
|
||||
assert(type(pid) ~= "string", pid)
|
||||
assert(stdin == nil)
|
||||
spawn.read_lines(require("lgi").Gio.UnixInputStream.new(stdout, true),
|
||||
function(line)
|
||||
assert(not read_line)
|
||||
read_line = true
|
||||
assert(line == test_stdin, line)
|
||||
io_spawns_done = io_spawns_done + 1
|
||||
end, nil, true)
|
||||
end
|
||||
|
||||
do -- Test that false doesn't return a pointer (behavior is untested - GLib defaults)
|
||||
local pid, _, stdin, stdout, stderr = awesome.spawn({"true"},
|
||||
false, false, false, false)
|
||||
assert(type(pid) ~= "string", pid)
|
||||
assert(stdin == nil)
|
||||
assert(stdout == nil)
|
||||
assert(stderr == nil)
|
||||
end
|
||||
|
||||
do -- Test that true returns a pipe
|
||||
local read_line = false
|
||||
local pid, _, stdin, stdout, stderr = awesome.spawn({ 'readlink', '/proc/self/fd/0' },
|
||||
false, true, true, true)
|
||||
assert(type(pid) ~= "string", pid)
|
||||
assert(stdin ~= nil)
|
||||
assert(stdout ~= nil)
|
||||
assert(stderr ~= nil)
|
||||
spawn.read_lines(require("lgi").Gio.UnixInputStream.new(stdout, true),
|
||||
function(line)
|
||||
assert(not read_line)
|
||||
read_line = true
|
||||
assert(line:find("^pipe:%[[0-9]+%]$"), line)
|
||||
io_spawns_done = io_spawns_done + 1
|
||||
end, nil, true)
|
||||
end
|
||||
end
|
||||
if io_spawns_done == 3 then
|
||||
return true
|
||||
end
|
||||
end,
|
||||
-- Test spawn_once
|
||||
function()
|
||||
if #client.get() ~= 1 then return end
|
||||
|
|
Loading…
Reference in New Issue