Merge branch 'obsd-master'
[tmux.git] / environ.c
blob5abf383c0706553ac1600aebe8c5702e59204644
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
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.
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.
19 #include <sys/types.h>
21 #include <fnmatch.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
26 #include "tmux.h"
29 * Environment - manipulate a set of environment variables.
32 RB_HEAD(environ, environ_entry);
33 static int environ_cmp(struct environ_entry *, struct environ_entry *);
34 RB_GENERATE_STATIC(environ, environ_entry, entry, environ_cmp);
36 static int
37 environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2)
39 return (strcmp(envent1->name, envent2->name));
42 /* Initialise the environment. */
43 struct environ *
44 environ_create(void)
46 struct environ *env;
48 env = xcalloc(1, sizeof *env);
49 RB_INIT(env);
51 return (env);
54 /* Free an environment. */
55 void
56 environ_free(struct environ *env)
58 struct environ_entry *envent, *envent1;
60 RB_FOREACH_SAFE(envent, environ, env, envent1) {
61 RB_REMOVE(environ, env, envent);
62 free(envent->name);
63 free(envent->value);
64 free(envent);
66 free(env);
69 struct environ_entry *
70 environ_first(struct environ *env)
72 return (RB_MIN(environ, env));
75 struct environ_entry *
76 environ_next(struct environ_entry *envent)
78 return (RB_NEXT(environ, env, envent));
81 /* Copy one environment into another. */
82 void
83 environ_copy(struct environ *srcenv, struct environ *dstenv)
85 struct environ_entry *envent;
87 RB_FOREACH(envent, environ, srcenv) {
88 if (envent->value == NULL)
89 environ_clear(dstenv, envent->name);
90 else {
91 environ_set(dstenv, envent->name, envent->flags,
92 "%s", envent->value);
97 /* Find an environment variable. */
98 struct environ_entry *
99 environ_find(struct environ *env, const char *name)
101 struct environ_entry envent;
103 envent.name = (char *) name;
104 return (RB_FIND(environ, env, &envent));
107 /* Set an environment variable. */
108 void
109 environ_set(struct environ *env, const char *name, int flags, const char *fmt,
110 ...)
112 struct environ_entry *envent;
113 va_list ap;
115 va_start(ap, fmt);
116 if ((envent = environ_find(env, name)) != NULL) {
117 envent->flags = flags;
118 free(envent->value);
119 xvasprintf(&envent->value, fmt, ap);
120 } else {
121 envent = xmalloc(sizeof *envent);
122 envent->name = xstrdup(name);
123 envent->flags = flags;
124 xvasprintf(&envent->value, fmt, ap);
125 RB_INSERT(environ, env, envent);
127 va_end(ap);
130 /* Clear an environment variable. */
131 void
132 environ_clear(struct environ *env, const char *name)
134 struct environ_entry *envent;
136 if ((envent = environ_find(env, name)) != NULL) {
137 free(envent->value);
138 envent->value = NULL;
139 } else {
140 envent = xmalloc(sizeof *envent);
141 envent->name = xstrdup(name);
142 envent->flags = 0;
143 envent->value = NULL;
144 RB_INSERT(environ, env, envent);
148 /* Set an environment variable from a NAME=VALUE string. */
149 void
150 environ_put(struct environ *env, const char *var, int flags)
152 char *name, *value;
154 value = strchr(var, '=');
155 if (value == NULL)
156 return;
157 value++;
159 name = xstrdup(var);
160 name[strcspn(name, "=")] = '\0';
162 environ_set(env, name, flags, "%s", value);
163 free(name);
166 /* Unset an environment variable. */
167 void
168 environ_unset(struct environ *env, const char *name)
170 struct environ_entry *envent;
172 if ((envent = environ_find(env, name)) == NULL)
173 return;
174 RB_REMOVE(environ, env, envent);
175 free(envent->name);
176 free(envent->value);
177 free(envent);
180 /* Copy variables from a destination into a source environment. */
181 void
182 environ_update(struct options *oo, struct environ *src, struct environ *dst)
184 struct environ_entry *envent;
185 struct environ_entry *envent1;
186 struct options_entry *o;
187 struct options_array_item *a;
188 union options_value *ov;
189 int found;
191 o = options_get(oo, "update-environment");
192 if (o == NULL)
193 return;
194 a = options_array_first(o);
195 while (a != NULL) {
196 ov = options_array_item_value(a);
197 found = 0;
198 RB_FOREACH_SAFE(envent, environ, src, envent1) {
199 if (fnmatch(ov->string, envent->name, 0) == 0) {
200 environ_set(dst, envent->name, 0, "%s", envent->value);
201 found = 1;
204 if (!found)
205 environ_clear(dst, ov->string);
206 a = options_array_next(a);
210 /* Push environment into the real environment - use after fork(). */
211 void
212 environ_push(struct environ *env)
214 struct environ_entry *envent;
216 environ = xcalloc(1, sizeof *environ);
217 RB_FOREACH(envent, environ, env) {
218 if (envent->value != NULL &&
219 *envent->name != '\0' &&
220 (~envent->flags & ENVIRON_HIDDEN))
221 setenv(envent->name, envent->value, 1);
225 /* Log the environment. */
226 void
227 environ_log(struct environ *env, const char *fmt, ...)
229 struct environ_entry *envent;
230 va_list ap;
231 char *prefix;
233 va_start(ap, fmt);
234 vasprintf(&prefix, fmt, ap);
235 va_end(ap);
237 RB_FOREACH(envent, environ, env) {
238 if (envent->value != NULL && *envent->name != '\0') {
239 log_debug("%s%s=%s", prefix, envent->name,
240 envent->value);
244 free(prefix);
247 /* Create initial environment for new child. */
248 struct environ *
249 environ_for_session(struct session *s, int no_TERM)
251 struct environ *env;
252 const char *value;
253 int idx;
255 env = environ_create();
256 environ_copy(global_environ, env);
257 if (s != NULL)
258 environ_copy(s->environ, env);
260 if (!no_TERM) {
261 value = options_get_string(global_options, "default-terminal");
262 environ_set(env, "TERM", 0, "%s", value);
263 environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux");
264 environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
267 if (s != NULL)
268 idx = s->id;
269 else
270 idx = -1;
271 environ_set(env, "TMUX", 0, "%s,%ld,%d", socket_path, (long)getpid(),
272 idx);
274 return (env);