env-util.c revision c69a177207ed18d0f0210347430a60957136bd6c
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "lib.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "array.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "env-util.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#ifdef __APPLE__
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch# include <crt_externs.h>
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#endif
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstruct env_backup {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch pool_t pool;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char **strings;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch};
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic pool_t env_pool = NULL;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvoid env_put(const char *env)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (env_pool == NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch env_pool = pool_alloconly_create(MEMPOOL_GROWING"Environment",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch 2048);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (putenv(p_strdup(env_pool, env)) != 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_fatal("putenv(%s) failed: %m", env);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvoid env_remove(const char *name)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#ifdef HAVE_UNSETENV
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#ifdef UNSETENV_RET_INT
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (unsetenv(name) < 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_fatal("unsetenv(%s) failed: %m", name);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#else
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsetenv(name);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#endif
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#else
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch extern char **environ;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch size_t len;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch char **envp;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch len = strlen(name);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (envp = environ; *envp != NULL; envp++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (strncmp(name, *envp, len) == 0 &&
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch (*envp)[len] == '=') {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch do {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch envp[0] = envp[1];
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } while (*++envp != NULL);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#endif
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvoid env_clean(void)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#ifdef HAVE_CLEARENV
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (clearenv() < 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_fatal("clearenv() failed");
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#else
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch char ***environ_p = env_get_environ_p();
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* Try to clear the environment.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch a) environ = NULL crashes on OS X.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch b) *environ = NULL doesn't work on FreeBSD 7.0.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch c) environ = emptyenv doesn't work on Haiku OS
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch d) environ = calloc() should work everywhere
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch *environ_p = calloc(1, sizeof(**environ_p));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#endif
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (env_pool != NULL)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch p_clear(env_pool);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void env_clean_except_real(const char *const preserve_envs[])
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ARRAY_TYPE(const_string) copy;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *value, *const *envp;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_array_init(&copy, 16);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (i = 0; preserve_envs[i] != NULL; i++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *key = preserve_envs[i];
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch value = getenv(key);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (value != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch value = t_strconcat(key, "=", value, NULL);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_append(&copy, &value, 1);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* Note that if the original environment was set with env_put(), the
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch environment strings will be invalid after env_clean(). That's why
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch we t_strconcat() them above. */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch env_clean();
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_foreach(&copy, envp)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch env_put(*envp);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvoid env_clean_except(const char *const preserve_envs[])
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch T_BEGIN {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch env_clean_except_real(preserve_envs);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } T_END;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstruct env_backup *env_backup_save(void)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch char **environ = *env_get_environ_p();
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct env_backup *env;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i, count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch pool_t pool;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert(environ != NULL);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (count = 0; environ[count] != NULL; count++) ;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch pool = pool_alloconly_create("saved environment", 4096);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch env = p_new(pool, struct env_backup, 1);
dc78180b54a05d5736d0e0e444cba0332265eb62Phil Carmody env->pool = pool;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch env->strings = p_new(pool, const char *, count + 1);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (i = 0; i < count; i++)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch env->strings[i] = p_strdup(pool, environ[i]);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return env;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvoid env_backup_restore(struct env_backup *env)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch env_clean();
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (i = 0; env->strings[i] != NULL; i++)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch env_put(env->strings[i]);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmodyvoid env_backup_free(struct env_backup **_env)
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct env_backup *env = *_env;
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody *_env = NULL;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch pool_unref(&env->pool);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschchar ***env_get_environ_p(void)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#ifdef __APPLE__
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return _NSGetEnviron();
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#else
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch extern char **environ;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return &environ;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#endif
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmodyvoid env_deinit(void)
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch pool_unref(&env_pool);
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody}
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody