Home | History | Annotate | Line # | Download | only in dist
environ.c revision 1.10
      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 	union options_value		*ov;
    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 		ov = options_array_item_value(a);
    188 		if ((envent = environ_find(src, ov->string)) == NULL)
    189 			environ_clear(dst, ov->string);
    190 		else
    191 			environ_set(dst, envent->name, "%s", envent->value);
    192 		a = options_array_next(a);
    193 	}
    194 }
    195 
    196 /* Push environment into the real environment - use after fork(). */
    197 void
    198 environ_push(struct environ *env)
    199 {
    200 	struct environ_entry	*envent;
    201 
    202 	environ = xcalloc(1, sizeof *environ);
    203 	RB_FOREACH(envent, environ, env) {
    204 		if (envent->value != NULL && *envent->name != '\0')
    205 			setenv(envent->name, envent->value, 1);
    206 	}
    207 }
    208 
    209 /* Log the environment. */
    210 void
    211 environ_log(struct environ *env, const char *fmt, ...)
    212 {
    213 	struct environ_entry	*envent;
    214 	va_list			 ap;
    215 	char			*prefix;
    216 
    217 	va_start(ap, fmt);
    218 	vasprintf(&prefix, fmt, ap);
    219 	va_end(ap);
    220 
    221 	RB_FOREACH(envent, environ, env) {
    222 		if (envent->value != NULL && *envent->name != '\0') {
    223 			log_debug("%s%s=%s", prefix, envent->name,
    224 			    envent->value);
    225 		}
    226 	}
    227 
    228 	free(prefix);
    229 }
    230 
    231 /* Create initial environment for new child. */
    232 struct environ *
    233 environ_for_session(struct session *s, int no_TERM)
    234 {
    235 	struct environ	*env;
    236 	const char	*value;
    237 	int		 idx;
    238 
    239 	env = environ_create();
    240 	environ_copy(global_environ, env);
    241 	if (s != NULL)
    242 		environ_copy(s->environ, env);
    243 
    244 	if (!no_TERM) {
    245 		value = options_get_string(global_options, "default-terminal");
    246 		environ_set(env, "TERM", "%s", value);
    247 	}
    248 
    249 	if (s != NULL)
    250 		idx = s->id;
    251 	else
    252 		idx = -1;
    253 	environ_set(env, "TMUX", "%s,%ld,%d", socket_path, (long)getpid(), idx);
    254 
    255 	return (env);
    256 }
    257