199e242abSchristos /* $OpenBSD$ */ 2698d5317Sjmmv 3698d5317Sjmmv /* 4f26e8bc9Schristos * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com> 5698d5317Sjmmv * 6698d5317Sjmmv * Permission to use, copy, modify, and distribute this software for any 7698d5317Sjmmv * purpose with or without fee is hereby granted, provided that the above 8698d5317Sjmmv * copyright notice and this permission notice appear in all copies. 9698d5317Sjmmv * 10698d5317Sjmmv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11698d5317Sjmmv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12698d5317Sjmmv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13698d5317Sjmmv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14698d5317Sjmmv * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15698d5317Sjmmv * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16698d5317Sjmmv * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17698d5317Sjmmv */ 18698d5317Sjmmv 19698d5317Sjmmv #include <sys/types.h> 20698d5317Sjmmv 21e271dbb8Schristos #include <fnmatch.h> 22698d5317Sjmmv #include <stdlib.h> 23698d5317Sjmmv #include <string.h> 24e9a2d6faSchristos #include <unistd.h> 25698d5317Sjmmv 26698d5317Sjmmv #include "tmux.h" 27698d5317Sjmmv 28698d5317Sjmmv /* 29698d5317Sjmmv * Environment - manipulate a set of environment variables. 30698d5317Sjmmv */ 31698d5317Sjmmv 32f26e8bc9Schristos RB_HEAD(environ, environ_entry); 33e9a2d6faSchristos static int environ_cmp(struct environ_entry *, struct environ_entry *); 34e9a2d6faSchristos RB_GENERATE_STATIC(environ, environ_entry, entry, environ_cmp); 35698d5317Sjmmv 36e9a2d6faSchristos static int 37698d5317Sjmmv environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2) 38698d5317Sjmmv { 39698d5317Sjmmv return (strcmp(envent1->name, envent2->name)); 40698d5317Sjmmv } 41698d5317Sjmmv 42698d5317Sjmmv /* Initialise the environment. */ 43f26e8bc9Schristos struct environ * 44f26e8bc9Schristos environ_create(void) 45698d5317Sjmmv { 46f26e8bc9Schristos struct environ *env; 47f26e8bc9Schristos 48f26e8bc9Schristos env = xcalloc(1, sizeof *env); 49698d5317Sjmmv RB_INIT(env); 50f26e8bc9Schristos 51f26e8bc9Schristos return (env); 52698d5317Sjmmv } 53698d5317Sjmmv 54698d5317Sjmmv /* Free an environment. */ 55698d5317Sjmmv void 56698d5317Sjmmv environ_free(struct environ *env) 57698d5317Sjmmv { 58f26e8bc9Schristos struct environ_entry *envent, *envent1; 59698d5317Sjmmv 60f26e8bc9Schristos RB_FOREACH_SAFE(envent, environ, env, envent1) { 61698d5317Sjmmv RB_REMOVE(environ, env, envent); 6261fba46bSchristos free(envent->name); 6361fba46bSchristos free(envent->value); 6461fba46bSchristos free(envent); 65698d5317Sjmmv } 66f26e8bc9Schristos free(env); 67f26e8bc9Schristos } 68f26e8bc9Schristos 69f26e8bc9Schristos struct environ_entry * 70f26e8bc9Schristos environ_first(struct environ *env) 71f26e8bc9Schristos { 72f26e8bc9Schristos return (RB_MIN(environ, env)); 73f26e8bc9Schristos } 74f26e8bc9Schristos 75f26e8bc9Schristos struct environ_entry * 76f26e8bc9Schristos environ_next(struct environ_entry *envent) 77f26e8bc9Schristos { 78f26e8bc9Schristos return (RB_NEXT(environ, env, envent)); 79698d5317Sjmmv } 80698d5317Sjmmv 81698d5317Sjmmv /* Copy one environment into another. */ 82698d5317Sjmmv void 83698d5317Sjmmv environ_copy(struct environ *srcenv, struct environ *dstenv) 84698d5317Sjmmv { 85698d5317Sjmmv struct environ_entry *envent; 86698d5317Sjmmv 87f26e8bc9Schristos RB_FOREACH(envent, environ, srcenv) { 88f26e8bc9Schristos if (envent->value == NULL) 89f26e8bc9Schristos environ_clear(dstenv, envent->name); 90e271dbb8Schristos else { 91e271dbb8Schristos environ_set(dstenv, envent->name, envent->flags, 92e271dbb8Schristos "%s", envent->value); 93e271dbb8Schristos } 94f26e8bc9Schristos } 95698d5317Sjmmv } 96698d5317Sjmmv 97698d5317Sjmmv /* Find an environment variable. */ 98698d5317Sjmmv struct environ_entry * 99698d5317Sjmmv environ_find(struct environ *env, const char *name) 100698d5317Sjmmv { 101698d5317Sjmmv struct environ_entry envent; 102698d5317Sjmmv 103cad4076fSchristos envent.name = __UNCONST(name); 104698d5317Sjmmv return (RB_FIND(environ, env, &envent)); 105698d5317Sjmmv } 106698d5317Sjmmv 107698d5317Sjmmv /* Set an environment variable. */ 108698d5317Sjmmv void 109e271dbb8Schristos environ_set(struct environ *env, const char *name, int flags, const char *fmt, 110e271dbb8Schristos ...) 111f26e8bc9Schristos { 112f26e8bc9Schristos struct environ_entry *envent; 113f26e8bc9Schristos va_list ap; 114f26e8bc9Schristos 115f26e8bc9Schristos va_start(ap, fmt); 116f26e8bc9Schristos if ((envent = environ_find(env, name)) != NULL) { 117e271dbb8Schristos envent->flags = flags; 118f26e8bc9Schristos free(envent->value); 119f26e8bc9Schristos xvasprintf(&envent->value, fmt, ap); 120f26e8bc9Schristos } else { 121f26e8bc9Schristos envent = xmalloc(sizeof *envent); 122f26e8bc9Schristos envent->name = xstrdup(name); 123e271dbb8Schristos envent->flags = flags; 124f26e8bc9Schristos xvasprintf(&envent->value, fmt, ap); 125f26e8bc9Schristos RB_INSERT(environ, env, envent); 126f26e8bc9Schristos } 127f26e8bc9Schristos va_end(ap); 128f26e8bc9Schristos } 129f26e8bc9Schristos 130f26e8bc9Schristos /* Clear an environment variable. */ 131f26e8bc9Schristos void 132f26e8bc9Schristos environ_clear(struct environ *env, const char *name) 133698d5317Sjmmv { 134698d5317Sjmmv struct environ_entry *envent; 135698d5317Sjmmv 136698d5317Sjmmv if ((envent = environ_find(env, name)) != NULL) { 13761fba46bSchristos free(envent->value); 138698d5317Sjmmv envent->value = NULL; 139698d5317Sjmmv } else { 140698d5317Sjmmv envent = xmalloc(sizeof *envent); 141698d5317Sjmmv envent->name = xstrdup(name); 142e271dbb8Schristos envent->flags = 0; 143698d5317Sjmmv envent->value = NULL; 144698d5317Sjmmv RB_INSERT(environ, env, envent); 145698d5317Sjmmv } 146698d5317Sjmmv } 147698d5317Sjmmv 148698d5317Sjmmv /* Set an environment variable from a NAME=VALUE string. */ 149698d5317Sjmmv void 150e271dbb8Schristos environ_put(struct environ *env, const char *var, int flags) 151698d5317Sjmmv { 152698d5317Sjmmv char *name, *value; 153698d5317Sjmmv 154698d5317Sjmmv value = strchr(var, '='); 155698d5317Sjmmv if (value == NULL) 156698d5317Sjmmv return; 157698d5317Sjmmv value++; 158698d5317Sjmmv 159698d5317Sjmmv name = xstrdup(var); 160698d5317Sjmmv name[strcspn(name, "=")] = '\0'; 161698d5317Sjmmv 162e271dbb8Schristos environ_set(env, name, flags, "%s", value); 16361fba46bSchristos free(name); 164698d5317Sjmmv } 165698d5317Sjmmv 166698d5317Sjmmv /* Unset an environment variable. */ 167698d5317Sjmmv void 168698d5317Sjmmv environ_unset(struct environ *env, const char *name) 169698d5317Sjmmv { 170698d5317Sjmmv struct environ_entry *envent; 171698d5317Sjmmv 172698d5317Sjmmv if ((envent = environ_find(env, name)) == NULL) 173698d5317Sjmmv return; 174698d5317Sjmmv RB_REMOVE(environ, env, envent); 17561fba46bSchristos free(envent->name); 17661fba46bSchristos free(envent->value); 17761fba46bSchristos free(envent); 178698d5317Sjmmv } 179698d5317Sjmmv 180e271dbb8Schristos /* Copy variables from a destination into a source environment. */ 181698d5317Sjmmv void 182e9a2d6faSchristos environ_update(struct options *oo, struct environ *src, struct environ *dst) 183698d5317Sjmmv { 184698d5317Sjmmv struct environ_entry *envent; 185f844e94eSwiz struct environ_entry *envent1; 186e9a2d6faSchristos struct options_entry *o; 1870a274e86Schristos struct options_array_item *a; 18830744affSchristos union options_value *ov; 189f844e94eSwiz int found; 190698d5317Sjmmv 191e9a2d6faSchristos o = options_get(oo, "update-environment"); 1920a274e86Schristos if (o == NULL) 193e9a2d6faSchristos return; 1940a274e86Schristos a = options_array_first(o); 1950a274e86Schristos while (a != NULL) { 19630744affSchristos ov = options_array_item_value(a); 197f844e94eSwiz found = 0; 198f844e94eSwiz RB_FOREACH_SAFE(envent, environ, src, envent1) { 199f844e94eSwiz if (fnmatch(ov->string, envent->name, 0) == 0) { 200e271dbb8Schristos environ_set(dst, envent->name, 0, "%s", envent->value); 201f844e94eSwiz found = 1; 202f844e94eSwiz } 203f844e94eSwiz } 204f844e94eSwiz if (!found) 205f844e94eSwiz environ_clear(dst, ov->string); 2060a274e86Schristos a = options_array_next(a); 207698d5317Sjmmv } 208698d5317Sjmmv } 209698d5317Sjmmv 210698d5317Sjmmv /* Push environment into the real environment - use after fork(). */ 211698d5317Sjmmv void 212698d5317Sjmmv environ_push(struct environ *env) 213698d5317Sjmmv { 214698d5317Sjmmv struct environ_entry *envent; 215698d5317Sjmmv 216e9a2d6faSchristos environ = xcalloc(1, sizeof *environ); 217698d5317Sjmmv RB_FOREACH(envent, environ, env) { 218e271dbb8Schristos if (envent->value != NULL && 219e271dbb8Schristos *envent->name != '\0' && 220e271dbb8Schristos (~envent->flags & ENVIRON_HIDDEN)) 221698d5317Sjmmv setenv(envent->name, envent->value, 1); 222698d5317Sjmmv } 223698d5317Sjmmv } 224e9a2d6faSchristos 225e9a2d6faSchristos /* Log the environment. */ 226e9a2d6faSchristos void 227fe99a117Schristos environ_log(struct environ *env, const char *fmt, ...) 228e9a2d6faSchristos { 229e9a2d6faSchristos struct environ_entry *envent; 230fe99a117Schristos va_list ap; 231fe99a117Schristos char *prefix; 232fe99a117Schristos 233fe99a117Schristos va_start(ap, fmt); 234fe99a117Schristos vasprintf(&prefix, fmt, ap); 235fe99a117Schristos va_end(ap); 236e9a2d6faSchristos 237e9a2d6faSchristos RB_FOREACH(envent, environ, env) { 238e9a2d6faSchristos if (envent->value != NULL && *envent->name != '\0') { 239e9a2d6faSchristos log_debug("%s%s=%s", prefix, envent->name, 240e9a2d6faSchristos envent->value); 241e9a2d6faSchristos } 242e9a2d6faSchristos } 243fe99a117Schristos 244fe99a117Schristos free(prefix); 245e9a2d6faSchristos } 246e9a2d6faSchristos 247e9a2d6faSchristos /* Create initial environment for new child. */ 248e9a2d6faSchristos struct environ * 249fe99a117Schristos environ_for_session(struct session *s, int no_TERM) 250e9a2d6faSchristos { 251e9a2d6faSchristos struct environ *env; 252e9a2d6faSchristos const char *value; 253e9a2d6faSchristos int idx; 254e9a2d6faSchristos 255e9a2d6faSchristos env = environ_create(); 256e9a2d6faSchristos environ_copy(global_environ, env); 257e9a2d6faSchristos if (s != NULL) 258e9a2d6faSchristos environ_copy(s->environ, env); 259e9a2d6faSchristos 260fe99a117Schristos if (!no_TERM) { 261e9a2d6faSchristos value = options_get_string(global_options, "default-terminal"); 262e271dbb8Schristos environ_set(env, "TERM", 0, "%s", value); 263e271dbb8Schristos environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux"); 264e271dbb8Schristos environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion()); 265fe99a117Schristos } 266e9a2d6faSchristos 267*890b6d91Swiz #ifdef HAVE_SYSTEMD 268*890b6d91Swiz environ_clear(env, "LISTEN_PID"); 269*890b6d91Swiz environ_clear(env, "LISTEN_FDS"); 270*890b6d91Swiz environ_clear(env, "LISTEN_FDNAMES"); 271*890b6d91Swiz #endif 272*890b6d91Swiz 273e9a2d6faSchristos if (s != NULL) 274e9a2d6faSchristos idx = s->id; 275e9a2d6faSchristos else 276e9a2d6faSchristos idx = -1; 277e271dbb8Schristos environ_set(env, "TMUX", 0, "%s,%ld,%d", socket_path, (long)getpid(), 278e271dbb8Schristos idx); 279e9a2d6faSchristos 280e9a2d6faSchristos return (env); 281e9a2d6faSchristos } 282