diff options
author | Přemysl Eric Janouch <p@janouch.name> | 2025-01-03 10:46:12 +0100 |
---|---|---|
committer | Přemysl Eric Janouch <p@janouch.name> | 2025-01-03 10:46:12 +0100 |
commit | bd264787c167368e11c4397aac3e84440b7f1f17 (patch) | |
tree | 47c18262ea87ec0ce08b0f8d19f4ab9d8293f986 /tools | |
parent | a6e7cb553f9cc136cb7358385ca266d40a33523d (diff) | |
download | liberty-bd264787c167368e11c4397aac3e84440b7f1f17.tar.gz liberty-bd264787c167368e11c4397aac3e84440b7f1f17.tar.xz liberty-bd264787c167368e11c4397aac3e84440b7f1f17.zip |
WIP
Diffstat (limited to 'tools')
-rw-r--r-- | tools/wdye/wdye.c | 104 |
1 files changed, 58 insertions, 46 deletions
diff --git a/tools/wdye/wdye.c b/tools/wdye/wdye.c index 31652c6..3985abf 100644 --- a/tools/wdye/wdye.c +++ b/tools/wdye/wdye.c @@ -191,7 +191,7 @@ struct process { int terminal_fd; ///< Process stdin/stdout/stderr pid_t pid; ///< Process ID - // TODO(p): Either `TERMINAL *` or read-out values. + int ref_term; ///< Terminal information }; static struct process * @@ -200,6 +200,10 @@ xlua_process_new (lua_State *L) struct process *self = lua_newuserdata (L, sizeof *self); luaL_setmetatable (L, XLUA_PROCESS_METATABLE); memset (self, 0, sizeof *self); + + self->terminal_fd = -1; + self->pid = -1; + self->ref_term = LUA_NOREF; return self; } @@ -211,6 +215,7 @@ xlua_process_gc (lua_State *L) xclose (self->terminal_fd); if (self->pid != -1) kill (self->pid, SIGKILL); + luaL_unref (L, LUA_REGISTRYINDEX, self->ref_term); return 0; } @@ -237,8 +242,6 @@ xlua_process_send (lua_State *L) static luaL_Reg xlua_process_table[] = { { "__gc", xlua_process_gc }, -// { "__index", xlua_process_index }, -// { "__newindex", xlua_process_newindex }, { "expect", xlua_process_expect }, { "send", xlua_process_send }, { NULL, NULL } @@ -246,13 +249,34 @@ static luaL_Reg xlua_process_table[] = // --- Terminal ---------------------------------------------------------------- -// TODO(p): Probably create an object to interact with tinfo. +static bool +load_terminfo (const char *term, struct str_map *strings) +{ + // TODO(p): See if we can get away with using a bogus FD. + int err = 0; + TERMINAL *saved_term = set_curterm (NULL); + if (setupterm ((char *) term, STDOUT_FILENO, &err) != OK) + { + set_curterm (saved_term); + return false; + } + + for (size_t i = 0; strfnames[i]; i++) + { + const char *value = tigetstr (strnames[i]); + if (value && value != (char *) -1) + str_map_set (strings, strfnames[i], xstrdup (value)); + } + del_curterm (set_curterm (saved_term)); + return true; +} // --- Library ----------------------------------------------------------------- struct xlua_spawn_context { struct str_map env; ///< Subprocess environment map + struct str_map term; ///< terminfo database strings struct strv envv; ///< Subprocess environment vector struct strv argv; ///< Subprocess argument vector @@ -264,6 +288,9 @@ xlua_spawn_context_make (void) { struct xlua_spawn_context self = {}; self.env = str_map_make (free); + self.term = str_map_make (free); + + // XXX: It might make sense to enable starting from an empty environment. for (char **p = environ; *p; p++) { const char *equals = strchr (*p, '='); @@ -283,6 +310,7 @@ static void xlua_spawn_context_free (struct xlua_spawn_context *self) { str_map_free (&self->env); + str_map_free (&self->term); strv_free (&self->envv); strv_free (&self->argv); @@ -317,31 +345,6 @@ environ_map_serialize (struct str_map *env, struct strv *envv) xstrdup_printf ("%s=%s", iter.link->key, value)); } -static bool -xlua_load_terminal (lua_State *L, const char *term) -{ - // TODO(p): See if we can get away with using a bogus FD. - int err = 0; - TERMINAL *saved_term = set_curterm (NULL); - if (setupterm ((char *) term, STDOUT_FILENO, &err) != OK) - { - set_curterm (saved_term); - return false; - } - - for (size_t i = 0; strfnames[i]; i++) - { - const char *name = strfnames[i]; - const char *value = tigetstr (strnames[i]); - if (value && value != (char *) -1) - continue; - } - - del_curterm (set_curterm (saved_term)); - - return true; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static int @@ -349,28 +352,24 @@ xlua_spawn_protected (lua_State *L) { struct xlua_spawn_context *ctx = lua_touserdata (L, 1); - // TODO(p): Consider taking the TERM from the passed environ, - // or defaulting to inherited TERM. These should match anyway. - - // Step 1: Prepare a terminal object. - (void) xlua_getfield (L, 1, "term", LUA_TSTRING, true); - const char *term = lua_tostring (L, -1); - - - // TODO(p): Process the terminal name, - // possibly by creating another indexable Lua object/table. - // - Remember to use a default when `term == NULL`. - - lua_pop (L, 1); - - // Step 2: Prepare process environment. + // Step 1: Prepare process environment. if (xlua_getfield (L, 1, "environ", LUA_TTABLE, true)) { environ_map_update (&ctx->env, L); lua_pop (L, 1); } + char *term = str_map_find (&ctx->env, "TERM"); + if (!term) + { + print_debug ("setting a default TERM"); + str_map_set (&ctx->env, "TERM", (term = xstrdup ("dumb"))); + } environ_map_serialize (&ctx->env, &ctx->envv); + // Step 2: Load terminal information. + if (!load_terminfo (term, &ctx->term)) + luaL_error (L, "failed to initialize terminfo for %s", term); + // Step 3: Prepare process command line. size_t argc = lua_rawlen (L, 1); for (size_t i = 1; i <= argc; i++) @@ -391,6 +390,18 @@ xlua_spawn_protected (lua_State *L) // This will get garbage collected as appropriate on failure. struct process *process = xlua_process_new (L); + // This could be made into an object that can adjust winsize/termios. + lua_createtable (L, 0, ctx->term.len); + struct str_map_iter iter = str_map_iter_make (&ctx->term); + const char *value = NULL; + while ((value = str_map_iter_next (&iter))) + { + lua_pushstring (L, iter.link->key); + lua_pushstring (L, value); + lua_settable (L, -3); + } + process->ref_term = luaL_ref (L, LUA_REGISTRYINDEX); + // Step 5: Spawn the process, which gets a new process group. process->pid = pty_fork (&process->terminal_fd, NULL, NULL, NULL, &ctx->error); @@ -497,8 +508,9 @@ main (int argc, char *argv[]) print_error ("%s: %s", path, lua_tostring (g.L, -1)); lua_pop (g.L, 1); } - - // TODO(p): Do we need to pop the error handler? + lua_pop (g.L, 1); lua_close (g.L); + + poller_free (&g.poller); return 0; } |