1*35014fc2Snicm /* $OpenBSD: environ.c,v 1.27 2022/08/15 08:37:03 nicm Exp $ */
26f7d62ebSnicm
36f7d62ebSnicm /*
498ca8272Snicm * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
56f7d62ebSnicm *
66f7d62ebSnicm * Permission to use, copy, modify, and distribute this software for any
76f7d62ebSnicm * purpose with or without fee is hereby granted, provided that the above
86f7d62ebSnicm * copyright notice and this permission notice appear in all copies.
96f7d62ebSnicm *
106f7d62ebSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
116f7d62ebSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
126f7d62ebSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
136f7d62ebSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
146f7d62ebSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
156f7d62ebSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
166f7d62ebSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176f7d62ebSnicm */
186f7d62ebSnicm
196f7d62ebSnicm #include <sys/types.h>
206f7d62ebSnicm
219b8516b6Snicm #include <fnmatch.h>
226f7d62ebSnicm #include <stdlib.h>
236f7d62ebSnicm #include <string.h>
24720ef0b5Snicm #include <unistd.h>
256f7d62ebSnicm
266f7d62ebSnicm #include "tmux.h"
276f7d62ebSnicm
286f7d62ebSnicm /*
296f7d62ebSnicm * Environment - manipulate a set of environment variables.
306f7d62ebSnicm */
316f7d62ebSnicm
32fb46cb3dSnicm RB_HEAD(environ, environ_entry);
339883b791Snicm static int environ_cmp(struct environ_entry *, struct environ_entry *);
349883b791Snicm RB_GENERATE_STATIC(environ, environ_entry, entry, environ_cmp);
356f7d62ebSnicm
369883b791Snicm static int
environ_cmp(struct environ_entry * envent1,struct environ_entry * envent2)376f7d62ebSnicm environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2)
386f7d62ebSnicm {
396f7d62ebSnicm return (strcmp(envent1->name, envent2->name));
406f7d62ebSnicm }
416f7d62ebSnicm
42bcaf4493Snicm /* Initialise the environment. */
43fb46cb3dSnicm struct environ *
environ_create(void)44fb46cb3dSnicm environ_create(void)
456f7d62ebSnicm {
46fb46cb3dSnicm struct environ *env;
47fb46cb3dSnicm
48fb46cb3dSnicm env = xcalloc(1, sizeof *env);
496f7d62ebSnicm RB_INIT(env);
50fb46cb3dSnicm
51fb46cb3dSnicm return (env);
526f7d62ebSnicm }
536f7d62ebSnicm
54bcaf4493Snicm /* Free an environment. */
556f7d62ebSnicm void
environ_free(struct environ * env)566f7d62ebSnicm environ_free(struct environ *env)
576f7d62ebSnicm {
58fb46cb3dSnicm struct environ_entry *envent, *envent1;
596f7d62ebSnicm
60fb46cb3dSnicm RB_FOREACH_SAFE(envent, environ, env, envent1) {
616f7d62ebSnicm RB_REMOVE(environ, env, envent);
627d053cf9Snicm free(envent->name);
637d053cf9Snicm free(envent->value);
647d053cf9Snicm free(envent);
656f7d62ebSnicm }
66fb46cb3dSnicm free(env);
67fb46cb3dSnicm }
68fb46cb3dSnicm
69fb46cb3dSnicm struct environ_entry *
environ_first(struct environ * env)70fb46cb3dSnicm environ_first(struct environ *env)
71fb46cb3dSnicm {
72fb46cb3dSnicm return (RB_MIN(environ, env));
73fb46cb3dSnicm }
74fb46cb3dSnicm
75fb46cb3dSnicm struct environ_entry *
environ_next(struct environ_entry * envent)76fb46cb3dSnicm environ_next(struct environ_entry *envent)
77fb46cb3dSnicm {
78fb46cb3dSnicm return (RB_NEXT(environ, env, envent));
796f7d62ebSnicm }
806f7d62ebSnicm
81bcaf4493Snicm /* Copy one environment into another. */
826f7d62ebSnicm void
environ_copy(struct environ * srcenv,struct environ * dstenv)836f7d62ebSnicm environ_copy(struct environ *srcenv, struct environ *dstenv)
846f7d62ebSnicm {
856f7d62ebSnicm struct environ_entry *envent;
866f7d62ebSnicm
87c4ce9d7aSnicm RB_FOREACH(envent, environ, srcenv) {
88c4ce9d7aSnicm if (envent->value == NULL)
89c4ce9d7aSnicm environ_clear(dstenv, envent->name);
90d6f6a5d2Snicm else {
91d6f6a5d2Snicm environ_set(dstenv, envent->name, envent->flags,
92d6f6a5d2Snicm "%s", envent->value);
93d6f6a5d2Snicm }
94c4ce9d7aSnicm }
956f7d62ebSnicm }
966f7d62ebSnicm
97bcaf4493Snicm /* Find an environment variable. */
986f7d62ebSnicm struct environ_entry *
environ_find(struct environ * env,const char * name)996f7d62ebSnicm environ_find(struct environ *env, const char *name)
1006f7d62ebSnicm {
1016f7d62ebSnicm struct environ_entry envent;
1026f7d62ebSnicm
1036f7d62ebSnicm envent.name = (char *) name;
1046f7d62ebSnicm return (RB_FIND(environ, env, &envent));
1056f7d62ebSnicm }
1066f7d62ebSnicm
107bcaf4493Snicm /* Set an environment variable. */
1086f7d62ebSnicm void
environ_set(struct environ * env,const char * name,int flags,const char * fmt,...)109d6f6a5d2Snicm environ_set(struct environ *env, const char *name, int flags, const char *fmt,
110d6f6a5d2Snicm ...)
111c4ce9d7aSnicm {
112c4ce9d7aSnicm struct environ_entry *envent;
113c4ce9d7aSnicm va_list ap;
114c4ce9d7aSnicm
115c4ce9d7aSnicm va_start(ap, fmt);
116c4ce9d7aSnicm if ((envent = environ_find(env, name)) != NULL) {
117d6f6a5d2Snicm envent->flags = flags;
118c4ce9d7aSnicm free(envent->value);
119c4ce9d7aSnicm xvasprintf(&envent->value, fmt, ap);
120c4ce9d7aSnicm } else {
121c4ce9d7aSnicm envent = xmalloc(sizeof *envent);
122c4ce9d7aSnicm envent->name = xstrdup(name);
123d6f6a5d2Snicm envent->flags = flags;
124c4ce9d7aSnicm xvasprintf(&envent->value, fmt, ap);
125c4ce9d7aSnicm RB_INSERT(environ, env, envent);
126c4ce9d7aSnicm }
127c4ce9d7aSnicm va_end(ap);
128c4ce9d7aSnicm }
129c4ce9d7aSnicm
130c4ce9d7aSnicm /* Clear an environment variable. */
131c4ce9d7aSnicm void
environ_clear(struct environ * env,const char * name)132c4ce9d7aSnicm environ_clear(struct environ *env, const char *name)
1336f7d62ebSnicm {
1346f7d62ebSnicm struct environ_entry *envent;
1356f7d62ebSnicm
1366f7d62ebSnicm if ((envent = environ_find(env, name)) != NULL) {
1377d053cf9Snicm free(envent->value);
1386f7d62ebSnicm envent->value = NULL;
1396f7d62ebSnicm } else {
1406f7d62ebSnicm envent = xmalloc(sizeof *envent);
1416f7d62ebSnicm envent->name = xstrdup(name);
142d6f6a5d2Snicm envent->flags = 0;
1436f7d62ebSnicm envent->value = NULL;
1446f7d62ebSnicm RB_INSERT(environ, env, envent);
1456f7d62ebSnicm }
1466f7d62ebSnicm }
1476f7d62ebSnicm
148bcaf4493Snicm /* Set an environment variable from a NAME=VALUE string. */
1496f7d62ebSnicm void
environ_put(struct environ * env,const char * var,int flags)150d6f6a5d2Snicm environ_put(struct environ *env, const char *var, int flags)
1516f7d62ebSnicm {
1526f7d62ebSnicm char *name, *value;
1536f7d62ebSnicm
1546f7d62ebSnicm value = strchr(var, '=');
1556f7d62ebSnicm if (value == NULL)
1566f7d62ebSnicm return;
1576f7d62ebSnicm value++;
1586f7d62ebSnicm
1596f7d62ebSnicm name = xstrdup(var);
1606f7d62ebSnicm name[strcspn(name, "=")] = '\0';
1616f7d62ebSnicm
162d6f6a5d2Snicm environ_set(env, name, flags, "%s", value);
1637d053cf9Snicm free(name);
1646f7d62ebSnicm }
1656f7d62ebSnicm
166bcaf4493Snicm /* Unset an environment variable. */
1676f7d62ebSnicm void
environ_unset(struct environ * env,const char * name)1686f7d62ebSnicm environ_unset(struct environ *env, const char *name)
1696f7d62ebSnicm {
1706f7d62ebSnicm struct environ_entry *envent;
1716f7d62ebSnicm
1726f7d62ebSnicm if ((envent = environ_find(env, name)) == NULL)
1736f7d62ebSnicm return;
1746f7d62ebSnicm RB_REMOVE(environ, env, envent);
1757d053cf9Snicm free(envent->name);
1767d053cf9Snicm free(envent->value);
1777d053cf9Snicm free(envent);
1786f7d62ebSnicm }
1796f7d62ebSnicm
180d6f6a5d2Snicm /* Copy variables from a destination into a source environment. */
1816f7d62ebSnicm void
environ_update(struct options * oo,struct environ * src,struct environ * dst)182d96735deSnicm environ_update(struct options *oo, struct environ *src, struct environ *dst)
1836f7d62ebSnicm {
1846f7d62ebSnicm struct environ_entry *envent;
185*35014fc2Snicm struct environ_entry *envent1;
186d96735deSnicm struct options_entry *o;
18739052edfSnicm struct options_array_item *a;
18884306383Snicm union options_value *ov;
189*35014fc2Snicm int found;
1906f7d62ebSnicm
191d96735deSnicm o = options_get(oo, "update-environment");
19239052edfSnicm if (o == NULL)
193d96735deSnicm return;
19439052edfSnicm a = options_array_first(o);
19539052edfSnicm while (a != NULL) {
19684306383Snicm ov = options_array_item_value(a);
197*35014fc2Snicm found = 0;
198*35014fc2Snicm RB_FOREACH_SAFE(envent, environ, src, envent1) {
199*35014fc2Snicm if (fnmatch(ov->string, envent->name, 0) == 0) {
200d6f6a5d2Snicm environ_set(dst, envent->name, 0, "%s", envent->value);
201*35014fc2Snicm found = 1;
202*35014fc2Snicm }
203*35014fc2Snicm }
204*35014fc2Snicm if (!found)
205*35014fc2Snicm environ_clear(dst, ov->string);
20639052edfSnicm a = options_array_next(a);
2076f7d62ebSnicm }
2086f7d62ebSnicm }
209bcaf4493Snicm
210bcaf4493Snicm /* Push environment into the real environment - use after fork(). */
211bcaf4493Snicm void
environ_push(struct environ * env)212bcaf4493Snicm environ_push(struct environ *env)
213bcaf4493Snicm {
214bcaf4493Snicm struct environ_entry *envent;
215bcaf4493Snicm
216cbb5bb31Snicm environ = xcalloc(1, sizeof *environ);
217bcaf4493Snicm RB_FOREACH(envent, environ, env) {
218d6f6a5d2Snicm if (envent->value != NULL &&
219d6f6a5d2Snicm *envent->name != '\0' &&
220d6f6a5d2Snicm (~envent->flags & ENVIRON_HIDDEN))
221bcaf4493Snicm setenv(envent->name, envent->value, 1);
222bcaf4493Snicm }
223bcaf4493Snicm }
224bafc17a6Snicm
225bafc17a6Snicm /* Log the environment. */
226bafc17a6Snicm void
environ_log(struct environ * env,const char * fmt,...)227511eaaabSnicm environ_log(struct environ *env, const char *fmt, ...)
228bafc17a6Snicm {
229bafc17a6Snicm struct environ_entry *envent;
230511eaaabSnicm va_list ap;
231511eaaabSnicm char *prefix;
232511eaaabSnicm
233511eaaabSnicm va_start(ap, fmt);
234511eaaabSnicm vasprintf(&prefix, fmt, ap);
235511eaaabSnicm va_end(ap);
236bafc17a6Snicm
2378386d11bSnicm RB_FOREACH(envent, environ, env) {
2388386d11bSnicm if (envent->value != NULL && *envent->name != '\0') {
2398386d11bSnicm log_debug("%s%s=%s", prefix, envent->name,
2408386d11bSnicm envent->value);
2418386d11bSnicm }
2428386d11bSnicm }
243511eaaabSnicm
244511eaaabSnicm free(prefix);
245bafc17a6Snicm }
246720ef0b5Snicm
247720ef0b5Snicm /* Create initial environment for new child. */
248720ef0b5Snicm struct environ *
environ_for_session(struct session * s,int no_TERM)249ff7b5ef0Snicm environ_for_session(struct session *s, int no_TERM)
250720ef0b5Snicm {
251720ef0b5Snicm struct environ *env;
252720ef0b5Snicm const char *value;
253720ef0b5Snicm int idx;
254720ef0b5Snicm
255720ef0b5Snicm env = environ_create();
256720ef0b5Snicm environ_copy(global_environ, env);
257720ef0b5Snicm if (s != NULL)
258720ef0b5Snicm environ_copy(s->environ, env);
259720ef0b5Snicm
260ff7b5ef0Snicm if (!no_TERM) {
261720ef0b5Snicm value = options_get_string(global_options, "default-terminal");
262d6f6a5d2Snicm environ_set(env, "TERM", 0, "%s", value);
263381ed420Snicm environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux");
264381ed420Snicm environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
265ff7b5ef0Snicm }
266720ef0b5Snicm
267720ef0b5Snicm if (s != NULL)
268720ef0b5Snicm idx = s->id;
269720ef0b5Snicm else
270720ef0b5Snicm idx = -1;
271d6f6a5d2Snicm environ_set(env, "TMUX", 0, "%s,%ld,%d", socket_path, (long)getpid(),
272d6f6a5d2Snicm idx);
273720ef0b5Snicm
274720ef0b5Snicm return (env);
275720ef0b5Snicm }
276