1 | /* $OpenBSD$ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2009 Nicholas Marriott <[email protected]> |
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 = (char *) 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 | |