GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tmux/environ.c Lines: 33 91 36.3 %
Date: 2017-11-07 Branches: 101 206 49.0 %

Line Branch Exec Source
1
/* $OpenBSD: environ.c,v 1.20 2017/05/11 07:34:54 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@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








































5956
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
896
	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
12
	env = xcalloc(1, sizeof *env);
48
6
	RB_INIT(env);
49
50
6
	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

352
	RB_FOREACH_SAFE(envent, environ, env, envent1) {
60
82
		RB_REMOVE(environ, env, envent);
61
82
		free(envent->name);
62
82
		free(envent->value);
63
82
		free(envent);
64
	}
65
6
	free(env);
66
6
}
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
164
	struct environ_entry	envent;
99
100
82
	envent.name = (char *) name;
101
164
	return (RB_FIND(environ, env, &envent));
102
82
}
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
164
	va_list			 ap;
110
111
82
	va_start(ap, fmt);
112
82
	if ((envent = environ_find(env, name)) != NULL) {
113
		free(envent->value);
114
		xvasprintf(&envent->value, fmt, ap);
115
	} else {
116
82
		envent = xmalloc(sizeof *envent);
117
82
		envent->name = xstrdup(name);
118
82
		xvasprintf(&envent->value, fmt, ap);
119
82
		RB_INSERT(environ, env, envent);
120
	}
121
82
	va_end(ap);
122
82
}
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
152
	value = strchr(var, '=');
148
76
	if (value == NULL)
149
		return;
150
76
	value++;
151
152
76
	name = xstrdup(var);
153
76
	name[strcspn(name, "=")] = '\0';
154
155
76
	environ_set(env, name, "%s", value);
156
76
	free(name);
157
152
}
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
	u_int			 size, idx;
180
	const char		*value;
181
182
	o = options_get(oo, "update-environment");
183
	if (o == NULL || options_array_size(o, &size) == -1)
184
		return;
185
	for (idx = 0; idx < size; idx++) {
186
		value = options_array_get(o, idx);
187
		if (value == NULL)
188
			continue;
189
		if ((envent = environ_find(src, value)) == NULL)
190
			environ_clear(dst, value);
191
		else
192
			environ_set(dst, envent->name, "%s", envent->value);
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
}