mirror of
https://github.com/awesomeWM/awesome
synced 2024-11-17 07:47:41 +01:00
Merge pull request #1979 from psychon/spawn_env
Allow setting environment vars for spawned processes
This commit is contained in:
commit
4604ce705d
2 changed files with 89 additions and 30 deletions
95
spawn.c
95
spawn.c
|
@ -369,16 +369,57 @@ spawn_callback(gpointer user_data)
|
||||||
unsetenv("DESKTOP_STARTUP_ID");
|
unsetenv("DESKTOP_STARTUP_ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Convert a Lua table of strings to a char** array.
|
||||||
|
* \param L The Lua VM state.
|
||||||
|
* \param idx The index of the table that we should parse.
|
||||||
|
* \return The argv array.
|
||||||
|
*/
|
||||||
|
static gchar **
|
||||||
|
parse_table_array(lua_State *L, int idx, GError **error)
|
||||||
|
{
|
||||||
|
gchar **argv = NULL;
|
||||||
|
size_t i, len;
|
||||||
|
|
||||||
|
luaL_checktype(L, idx, LUA_TTABLE);
|
||||||
|
idx = luaA_absindex(L, idx);
|
||||||
|
len = luaA_rawlen(L, idx);
|
||||||
|
|
||||||
|
/* First verify that the table is sane: All integer keys must contain
|
||||||
|
* strings. Do this by pushing them all onto the stack.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
lua_rawgeti(L, idx, i+1);
|
||||||
|
if (lua_type(L, -1) != LUA_TSTRING)
|
||||||
|
{
|
||||||
|
g_set_error(error, G_SPAWN_ERROR, 0,
|
||||||
|
"Non-string argument at table index %zd", i+1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* From this point on nothing can go wrong and so we can safely allocate
|
||||||
|
* memory.
|
||||||
|
*/
|
||||||
|
argv = g_new0(gchar *, len + 1);
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
argv[len - i - 1] = g_strdup(lua_tostring(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
|
||||||
/** Parse a command line.
|
/** Parse a command line.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
* \param idx The index of the argument that we should parse
|
* \param idx The index of the argument that we should parse.
|
||||||
* \return The argv array for the new process.
|
* \return The argv array for the new process.
|
||||||
*/
|
*/
|
||||||
static gchar **
|
static gchar **
|
||||||
parse_command(lua_State *L, int idx, GError **error)
|
parse_command(lua_State *L, int idx, GError **error)
|
||||||
{
|
{
|
||||||
gchar **argv = NULL;
|
gchar **argv = NULL;
|
||||||
idx = luaA_absindex(L, idx);
|
|
||||||
|
|
||||||
if (lua_isstring(L, idx))
|
if (lua_isstring(L, idx))
|
||||||
{
|
{
|
||||||
|
@ -388,31 +429,13 @@ parse_command(lua_State *L, int idx, GError **error)
|
||||||
}
|
}
|
||||||
else if (lua_istable(L, idx))
|
else if (lua_istable(L, idx))
|
||||||
{
|
{
|
||||||
size_t i, len = luaA_rawlen(L, idx);
|
argv = parse_table_array(L, idx, error);
|
||||||
|
|
||||||
/* First verify that the table is sane: All integer keys must contain
|
|
||||||
* strings. Do this by pushing them all onto the stack.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
lua_rawgeti(L, idx, i+1);
|
|
||||||
if (lua_type(L, -1) != LUA_TSTRING)
|
|
||||||
luaL_error(L, "Non-string argument at table index %d", i+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* From this point on nothing can go wrong and so we can safely allocate
|
|
||||||
* memory.
|
|
||||||
*/
|
|
||||||
argv = g_new0(gchar *, len + 1);
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
argv[len - i - 1] = g_strdup(lua_tostring(L, -1));
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
luaL_error(L, "Invalid argument to spawn(), expect string or table");
|
g_set_error_literal(error, G_SPAWN_ERROR, 0,
|
||||||
|
"Invalid argument to spawn(), expected string or table");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return argv;
|
return argv;
|
||||||
|
@ -450,20 +473,22 @@ child_exit_callback(GPid pid, gint status, gpointer user_data)
|
||||||
* @tparam[opt=false] boolean stdout Return a fd for stdout?
|
* @tparam[opt=false] boolean stdout Return a fd for stdout?
|
||||||
* @tparam[opt=false] boolean stderr Return a fd for stderr?
|
* @tparam[opt=false] boolean stderr Return a fd for stderr?
|
||||||
* @tparam[opt=nil] function exit_callback Function to call on process exit. The
|
* @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
|
* function arguments will be type of exit ("exit" or "signal") and the exit
|
||||||
* code / the signal number causing process termination.
|
* code / the signal number causing process termination.
|
||||||
|
* @tparam[opt=nil] table cmd The environment to use for the spawned program.
|
||||||
|
* Without this the spawned process inherits awesome's environment.
|
||||||
* @treturn[1] integer Process ID if everything is OK.
|
* @treturn[1] integer Process ID if everything is OK.
|
||||||
* @treturn[1] string Startup-notification ID, if `use_sn` is true.
|
* @treturn[1] string Startup-notification ID, if `use_sn` is true.
|
||||||
* @treturn[1] integer stdin, if `stdin` is true.
|
* @treturn[1] integer stdin, if `stdin` is true.
|
||||||
* @treturn[1] integer stdout, if `stdout` is true.
|
* @treturn[1] integer stdout, if `stdout` is true.
|
||||||
* @treturn[1] integer stderr, if `stderr` is true.
|
* @treturn[1] integer stderr, if `stderr` is true.
|
||||||
* @treturn[2] string An error string if an error occured.
|
* @treturn[2] string An error string if an error occurred.
|
||||||
* @function spawn
|
* @function spawn
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
luaA_spawn(lua_State *L)
|
luaA_spawn(lua_State *L)
|
||||||
{
|
{
|
||||||
gchar **argv = NULL;
|
gchar **argv = NULL, **envp = NULL;
|
||||||
bool use_sn = true, return_stdin = false, return_stdout = false, return_stderr = false;
|
bool use_sn = true, return_stdin = false, return_stdout = false, return_stderr = false;
|
||||||
int stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
|
int stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
|
||||||
int *stdin_ptr = NULL, *stdout_ptr = NULL, *stderr_ptr = NULL;
|
int *stdin_ptr = NULL, *stdout_ptr = NULL, *stderr_ptr = NULL;
|
||||||
|
@ -505,6 +530,17 @@ luaA_spawn(lua_State *L)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!lua_isnoneornil(L, 7)) {
|
||||||
|
envp = parse_table_array(L, 7, &error);
|
||||||
|
if (error) {
|
||||||
|
g_strfreev(argv);
|
||||||
|
g_strfreev(envp);
|
||||||
|
lua_pushfstring(L, "spawn: environment parse error: %s", error->message);
|
||||||
|
g_error_free(error);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SnLauncherContext *context = NULL;
|
SnLauncherContext *context = NULL;
|
||||||
if(use_sn)
|
if(use_sn)
|
||||||
{
|
{
|
||||||
|
@ -520,10 +556,11 @@ luaA_spawn(lua_State *L)
|
||||||
}
|
}
|
||||||
|
|
||||||
flags |= G_SPAWN_SEARCH_PATH | G_SPAWN_CLOEXEC_PIPES;
|
flags |= G_SPAWN_SEARCH_PATH | G_SPAWN_CLOEXEC_PIPES;
|
||||||
retval = g_spawn_async_with_pipes(NULL, argv, NULL, flags,
|
retval = g_spawn_async_with_pipes(NULL, argv, envp, flags,
|
||||||
spawn_callback, context, &pid,
|
spawn_callback, context, &pid,
|
||||||
stdin_ptr, stdout_ptr, stderr_ptr, &error);
|
stdin_ptr, stdout_ptr, stderr_ptr, &error);
|
||||||
g_strfreev(argv);
|
g_strfreev(argv);
|
||||||
|
g_strfreev(envp);
|
||||||
if(!retval)
|
if(!retval)
|
||||||
{
|
{
|
||||||
lua_pushstring(L, error->message);
|
lua_pushstring(L, error->message);
|
||||||
|
|
|
@ -71,6 +71,28 @@ local steps = {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
-- Test that setting env vars works and that the env is cleared
|
||||||
|
local read_line = false
|
||||||
|
local pid, _, _, stdout = awesome.spawn({ "sh", "-c", "echo $AWESOME_SPAWN_TEST_VAR $HOME $USER" },
|
||||||
|
false, false, true, false, nil, { "AWESOME_SPAWN_TEST_VAR=42" })
|
||||||
|
assert(type(pid) ~= "string", pid)
|
||||||
|
spawn.read_lines(require("lgi").Gio.UnixInputStream.new(stdout, true),
|
||||||
|
function(line)
|
||||||
|
assert(not read_line)
|
||||||
|
read_line = true
|
||||||
|
assert(line == "42", line)
|
||||||
|
spawns_done = spawns_done + 1
|
||||||
|
end, nil, true)
|
||||||
|
|
||||||
|
-- Test error in parse_table_array.
|
||||||
|
pid = awesome.spawn({"true"}, false, false, true, false, nil, { 0 })
|
||||||
|
assert(pid == 'spawn: environment parse error: Non-string argument at table index 1', pid)
|
||||||
|
|
||||||
|
-- Test error in parse_command.
|
||||||
|
pid = awesome.spawn({0}, false, false, true, false, nil, {})
|
||||||
|
assert(pid == 'spawn: parse error: Non-string argument at table index 1', pid)
|
||||||
|
|
||||||
|
|
||||||
local steps_count = 0
|
local steps_count = 0
|
||||||
local err_count = 0
|
local err_count = 0
|
||||||
spawn.with_line_callback({ "sh", "-c", "printf line1\\\\nline2\\\\nline3 ; echo err >&2 ; exit 42" }, {
|
spawn.with_line_callback({ "sh", "-c", "printf line1\\\\nline2\\\\nline3 ; echo err >&2 ; exit 42" }, {
|
||||||
|
@ -98,7 +120,7 @@ local steps = {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
if spawns_done == 2 then
|
if spawns_done == 3 then
|
||||||
assert(exit_yay == 0)
|
assert(exit_yay == 0)
|
||||||
assert(exit_snd == 42)
|
assert(exit_snd == 42)
|
||||||
assert(async_spawns_done == 2)
|
assert(async_spawns_done == 2)
|
||||||
|
|
Loading…
Reference in a new issue