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