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>
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
);
37 environ_cmp(struct environ_entry
*envent1
, struct environ_entry
*envent2
)
39 return (strcmp(envent1
->name
, envent2
->name
));
42 /* Initialise the environment. */
48 env
= xcalloc(1, sizeof *env
);
54 /* Free an environment. */
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
);
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. */
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
);
91 environ_set(dstenv
, envent
->name
, envent
->flags
,
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. */
109 environ_set(struct environ
*env
, const char *name
, int flags
, const char *fmt
,
112 struct environ_entry
*envent
;
116 if ((envent
= environ_find(env
, name
)) != NULL
) {
117 envent
->flags
= flags
;
119 xvasprintf(&envent
->value
, fmt
, ap
);
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
);
130 /* Clear an environment variable. */
132 environ_clear(struct environ
*env
, const char *name
)
134 struct environ_entry
*envent
;
136 if ((envent
= environ_find(env
, name
)) != NULL
) {
138 envent
->value
= NULL
;
140 envent
= xmalloc(sizeof *envent
);
141 envent
->name
= xstrdup(name
);
143 envent
->value
= NULL
;
144 RB_INSERT(environ
, env
, envent
);
148 /* Set an environment variable from a NAME=VALUE string. */
150 environ_put(struct environ
*env
, const char *var
, int flags
)
154 value
= strchr(var
, '=');
160 name
[strcspn(name
, "=")] = '\0';
162 environ_set(env
, name
, flags
, "%s", value
);
166 /* Unset an environment variable. */
168 environ_unset(struct environ
*env
, const char *name
)
170 struct environ_entry
*envent
;
172 if ((envent
= environ_find(env
, name
)) == NULL
)
174 RB_REMOVE(environ
, env
, envent
);
180 /* Copy variables from a destination into a source environment. */
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
;
191 o
= options_get(oo
, "update-environment");
194 a
= options_array_first(o
);
196 ov
= options_array_item_value(a
);
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
);
205 environ_clear(dst
, ov
->string
);
206 a
= options_array_next(a
);
210 /* Push environment into the real environment - use after fork(). */
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. */
227 environ_log(struct environ
*env
, const char *fmt
, ...)
229 struct environ_entry
*envent
;
234 vasprintf(&prefix
, fmt
, ap
);
237 RB_FOREACH(envent
, environ
, env
) {
238 if (envent
->value
!= NULL
&& *envent
->name
!= '\0') {
239 log_debug("%s%s=%s", prefix
, envent
->name
,
247 /* Create initial environment for new child. */
249 environ_for_session(struct session
*s
, int no_TERM
)
255 env
= environ_create();
256 environ_copy(global_environ
, env
);
258 environ_copy(s
->environ
, env
);
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());
268 environ_clear(env
, "LISTEN_PID");
269 environ_clear(env
, "LISTEN_FDS");
270 environ_clear(env
, "LISTEN_FDNAMES");
277 environ_set(env
, "TMUX", 0, "%s,%ld,%d", socket_path
, (long)getpid(),