Home | History | Annotate | Line # | Download | only in dist
environ.c revision 1.9
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott (at) gmail.com>
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  */
     18 
     19 #include <sys/types.h>
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <unistd.h>
     24 
     25 #include "tmux.h"
     26 
     27 /*
     28  * Environment - manipulate a set of environment variables.
     29  */
     30 
     31 RB_HEAD(environ, environ_entry);
     32 static int environ_cmp(struct environ_entry *, struct environ_entry *);
     33 RB_GENERATE_STATIC(environ, environ_entry, entry, environ_cmp);
     34 
     35 static int
     36 environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2)
     37 {
     38 	return (strcmp(envent1->name, envent2->name));
     39 }
     40 
     41 /* Initialise the environment. */
     42 struct environ *
     43 environ_create(void)
     44 {
     45 	struct environ	*env;
     46 
     47 	env = xcalloc(1, sizeof *env);
     48 	RB_INIT(env);
     49 
     50 	return (env);
     51 }
     52 
     53 /* Free an environment. */
     54 void
     55 environ_free(struct environ *env)
     56 {
     57 	struct environ_entry	*envent, *envent1;
     58 
     59 	RB_FOREACH_SAFE(envent, environ, env, envent1) {
     60 		RB_REMOVE(environ, env, envent);
     61 		free(envent->name);
     62 		free(envent->value);
     63 		free(envent);
     64 	}
     65 	free(env);
     66 }
     67 
     68 struct environ_entry *
     69 environ_first(struct environ *env)
     70 {
     71 	return (RB_MIN(environ, env));
     72 }
     73 
     74 struct environ_entry *
     75 environ_next(struct environ_entry *envent)
     76 {
     77 	return (RB_NEXT(environ, env, envent));
     78 }
     79 
     80 /* Copy one environment into another. */
     81 void
     82 environ_copy(struct environ *srcenv, struct environ *dstenv)
     83 {
     84 	struct environ_entry	*envent;
     85 
     86 	RB_FOREACH(envent, environ, srcenv) {
     87 		if (envent->value == NULL)
     88 			environ_clear(dstenv, envent->name);
     89 		else
     90 			environ_set(dstenv, envent->name, "%s", envent->value);
     91 	}
     92 }
     93 
     94 /* Find an environment variable. */
     95 struct environ_entry *
     96 environ_find(struct environ *env, const char *name)
     97 {
     98 	struct environ_entry	envent;
     99 
    100 	envent.name = __UNCONST(name);
    101 	return (RB_FIND(environ, env, &envent));
    102 }
    103 
    104 /* Set an environment variable. */
    105 void
    106 environ_set(struct environ *env, const char *name, const char *fmt, ...)
    107 {
    108 	struct environ_entry	*envent;
    109 	va_list			 ap;
    110 
    111 	va_start(ap, fmt);
    112 	if ((envent = environ_find(env, name)) != NULL) {
    113 		free(envent->value);
    114 		xvasprintf(&envent->value, fmt, ap);
    115 	} else {
    116 		envent = xmalloc(sizeof *envent);
    117 		envent->name = xstrdup(name);
    118 		xvasprintf(&envent->value, fmt, ap);
    119 		RB_INSERT(environ, env, envent);
    120 	}
    121 	va_end(ap);
    122 }
    123 
    124 /* Clear an environment variable. */
    125 void
    126 environ_clear(struct environ *env, const char *name)
    127 {
    128 	struct environ_entry	*envent;
    129 
    130 	if ((envent = environ_find(env, name)) != NULL) {
    131 		free(envent->value);
    132 		envent->value = NULL;
    133 	} else {
    134 		envent = xmalloc(sizeof *envent);
    135 		envent->name = xstrdup(name);
    136 		envent->value = NULL;
    137 		RB_INSERT(environ, env, envent);
    138 	}
    139 }
    140 
    141 /* Set an environment variable from a NAME=VALUE string. */
    142 void
    143 environ_put(struct environ *env, const char *var)
    144 {
    145 	char	*name, *value;
    146 
    147 	value = strchr(var, '=');
    148 	if (value == NULL)
    149 		return;
    150 	value++;
    151 
    152 	name = xstrdup(var);
    153 	name[strcspn(name, "=")] = '\0';
    154 
    155 	environ_set(env, name, "%s", value);
    156 	free(name);
    157 }
    158 
    159 /* Unset an environment variable. */
    160 void
    161 environ_unset(struct environ *env, const char *name)
    162 {
    163 	struct environ_entry	*envent;
    164 
    165 	if ((envent = environ_find(env, name)) == NULL)
    166 		return;
    167 	RB_REMOVE(environ, env, envent);
    168 	free(envent->name);
    169 	free(envent->value);
    170 	free(envent);
    171 }
    172 
    173 /* Copy variables from a destination into a source * environment. */
    174 void
    175 environ_update(struct options *oo, struct environ *src, struct environ *dst)
    176 {
    177 	struct environ_entry		*envent;
    178 	struct options_entry		*o;
    179 	struct options_array_item	*a;
    180 	const char			*value;
    181 
    182 	o = options_get(oo, "update-environment");
    183 	if (o == NULL)
    184 		return;
    185 	a = options_array_first(o);
    186 	while (a != NULL) {
    187 		value = options_array_item_value(a);
    188 		if (value == NULL) {
    189 			a = options_array_next(a);
    190 			continue;
    191 		}
    192 		if ((envent = environ_find(src, value)) == NULL)
    193 			environ_clear(dst, value);
    194 		else
    195 			environ_set(dst, envent->name, "%s", envent->value);
    196 		a = options_array_next(a);
    197 	}
    198 }
    199 
    200 /* Push environment into the real environment - use after fork(). */
    201 void
    202 environ_push(struct environ *env)
    203 {
    204 	struct environ_entry	*envent;
    205 
    206 	environ = xcalloc(1, sizeof *environ);
    207 	RB_FOREACH(envent, environ, env) {
    208 		if (envent->value != NULL && *envent->name != '\0')
    209 			setenv(envent->name, envent->value, 1);
    210 	}
    211 }
    212 
    213 /* Log the environment. */
    214 void
    215 environ_log(struct environ *env, const char *fmt, ...)
    216 {
    217 	struct environ_entry	*envent;
    218 	va_list			 ap;
    219 	char			*prefix;
    220 
    221 	va_start(ap, fmt);
    222 	vasprintf(&prefix, fmt, ap);
    223 	va_end(ap);
    224 
    225 	RB_FOREACH(envent, environ, env) {
    226 		if (envent->value != NULL && *envent->name != '\0') {
    227 			log_debug("%s%s=%s", prefix, envent->name,
    228 			    envent->value);
    229 		}
    230 	}
    231 
    232 	free(prefix);
    233 }
    234 
    235 /* Create initial environment for new child. */
    236 struct environ *
    237 environ_for_session(struct session *s, int no_TERM)
    238 {
    239 	struct environ	*env;
    240 	const char	*value;
    241 	int		 idx;
    242 
    243 	env = environ_create();
    244 	environ_copy(global_environ, env);
    245 	if (s != NULL)
    246 		environ_copy(s->environ, env);
    247 
    248 	if (!no_TERM) {
    249 		value = options_get_string(global_options, "default-terminal");
    250 		environ_set(env, "TERM", "%s", value);
    251 	}
    252 
    253 	if (s != NULL)
    254 		idx = s->id;
    255 	else
    256 		idx = -1;
    257 	environ_set(env, "TMUX", "%s,%ld,%d", socket_path, (long)getpid(), idx);
    258 
    259 	return (env);
    260 }
    261