mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
slave: don't skip setting environment variables when using a custom environment
When launching footclient with -E,--client-environment the environment variables that should be set by foot, wasn't. Those variables are: * TERM * COLORTERM * PWD * SHELL and all variables defined by the user in the [environment] section in foot.ini. In the same way, we did not *unset* TERM_PROGRAM and TERM_PROGRAM_VERSION. This patch fixes it by "cloning" the custom environment, making it mutable, and then adding/removing the variables above from it. Instead of calling setenv()/unsetenv() directly, we add the wrapper functions add_to_env() and del_from_env(). When *not* using a custom environment, they simply call setenv()/unsetenv(). When we *are* using a custom environment, add_to_env() first loops all existing variables, looking for a match. If a match is found, it's updated with the new value. If it's not found, a new entry is added. del_from_env() loops all entries, and removes it when a match is found. If no match is found, nothing is done. The mutable environment is allocated on the heap, but never free:d. We don't need to free it, since it's only allocated after forking, in the child process. Closes #1568
This commit is contained in:
parent
208008d717
commit
9da7152f83
8 changed files with 141 additions and 18 deletions
103
slave.c
103
slave.c
|
|
@ -25,6 +25,11 @@
|
|||
|
||||
extern char **environ;
|
||||
|
||||
struct environ {
|
||||
size_t count;
|
||||
char **envp;
|
||||
};
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
static char *
|
||||
find_file_in_path(const char *file)
|
||||
|
|
@ -303,9 +308,69 @@ err:
|
|||
_exit(errno);
|
||||
}
|
||||
|
||||
static bool
|
||||
env_matches_var_name(const char *e, const char *name)
|
||||
{
|
||||
const size_t e_len = strlen(e);
|
||||
const size_t name_len = strlen(name);
|
||||
|
||||
if (e_len <= name_len)
|
||||
return false;
|
||||
if (memcmp(e, name, name_len) != 0)
|
||||
return false;
|
||||
if (e[name_len] != '=')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
add_to_env(struct environ *env, const char *name, const char *value)
|
||||
{
|
||||
if (env->envp == NULL)
|
||||
setenv(name, value, 1);
|
||||
else {
|
||||
char *e = xasprintf("%s=%s", name, value);
|
||||
|
||||
/* Search for existing variable. If found, replace it with the
|
||||
new value */
|
||||
for (size_t i = 0; i < env->count; i++) {
|
||||
if (env_matches_var_name(env->envp[i], name)) {
|
||||
free(env->envp[i]);
|
||||
env->envp[i] = e;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the variable does not already exist, add it */
|
||||
env->envp = xrealloc(env->envp, (env->count + 2) * sizeof(env->envp[0]));
|
||||
env->envp[env->count++] = e;
|
||||
env->envp[env->count] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
del_from_env(struct environ *env, const char *name)
|
||||
{
|
||||
if (env->envp == NULL)
|
||||
unsetenv(name);
|
||||
else {
|
||||
for (size_t i = 0; i < env->count; i++) {
|
||||
if (env_matches_var_name(env->envp[i], name)) {
|
||||
free(env->envp[i]);
|
||||
memmove(&env->envp[i],
|
||||
&env->envp[i + 1],
|
||||
(env->count - i) * sizeof(env->envp[0]));
|
||||
env->count--;
|
||||
xassert(env->envp[env->count] == NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pid_t
|
||||
slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
||||
char *const *envp, const env_var_list_t *extra_env_vars,
|
||||
const char *const *envp, const env_var_list_t *extra_env_vars,
|
||||
const char *term_env, const char *conf_shell, bool login_shell,
|
||||
const user_notifications_t *notifications)
|
||||
{
|
||||
|
|
@ -350,15 +415,30 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
|||
_exit(errno_copy);
|
||||
}
|
||||
|
||||
setenv("TERM", term_env, 1);
|
||||
setenv("COLORTERM", "truecolor", 1);
|
||||
setenv("PWD", cwd, 1);
|
||||
/* Create a mutable copy of the environment */
|
||||
struct environ custom_env = {0};
|
||||
if (envp != NULL) {
|
||||
for (const char *const *e = envp; *e != NULL; e++)
|
||||
custom_env.count++;
|
||||
|
||||
unsetenv("TERM_PROGRAM");
|
||||
unsetenv("TERM_PROGRAM_VERSION");
|
||||
custom_env.envp = xcalloc(
|
||||
custom_env.count + 1, sizeof(custom_env.envp[0]));
|
||||
|
||||
size_t i = 0;
|
||||
for (const char *const *e = envp; *e != NULL; e++, i++)
|
||||
custom_env.envp[i] = xstrdup(*e);
|
||||
xassert(custom_env.envp[custom_env.count] == NULL);
|
||||
}
|
||||
|
||||
add_to_env(&custom_env, "TERM", term_env);
|
||||
add_to_env(&custom_env, "COLORTERM", "truecolor");
|
||||
add_to_env(&custom_env, "PWD", cwd);
|
||||
|
||||
del_from_env(&custom_env, "TERM_PROGRAM");
|
||||
del_from_env(&custom_env, "TERM_PROGRAM_VERSION");
|
||||
|
||||
#if defined(FOOT_TERMINFO_PATH)
|
||||
setenv("TERMINFO", FOOT_TERMINFO_PATH, 1);
|
||||
add_to_env(&custom_envp, "TERMINFO", FOOT_TERMINFO_PATH);
|
||||
#endif
|
||||
|
||||
if (extra_env_vars != NULL) {
|
||||
|
|
@ -367,9 +447,9 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
|||
const char *value = it->item.value;
|
||||
|
||||
if (strlen(value) == 0)
|
||||
unsetenv(name);
|
||||
del_from_env(&custom_env, name);
|
||||
else
|
||||
setenv(name, value, 1);
|
||||
add_to_env(&custom_env, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -393,9 +473,10 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
|||
}
|
||||
|
||||
if (is_valid_shell(shell_argv[0]))
|
||||
setenv("SHELL", shell_argv[0], 1);
|
||||
add_to_env(&custom_env, "SHELL", shell_argv[0]);
|
||||
|
||||
slave_exec(ptmx, shell_argv, envp != NULL ? envp : environ,
|
||||
slave_exec(ptmx, shell_argv,
|
||||
custom_env.envp != NULL ? custom_env.envp : environ,
|
||||
fork_pipe[1], login_shell, notifications);
|
||||
BUG("Unexpected return from slave_exec()");
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue