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