3 * Copyright (c) 2016 Ted Unangst <tedu@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <sys/types.h>
32 RB_ENTRY(envnode) node;
38 RB_HEAD(envtree, envnode) root;
43 envcmp(struct envnode *a, struct envnode *b)
45 return strcmp(a->key, b->key);
47 RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
49 static struct envnode *
50 createnode(const char *key, const char *value)
54 node = malloc(sizeof(*node));
57 node->key = strdup(key);
58 node->value = strdup(value);
59 if (!node->key || !node->value)
65 freenode(struct envnode *node)
67 free((char *)node->key);
68 free((char *)node->value);
73 createenv(struct rule *rule)
78 env = malloc(sizeof(*env));
84 if (rule->options & KEEPENV) {
85 extern char **environ;
87 for (i = 0; environ[i] != NULL; i++) {
95 /* ignore invalid or overlong names */
96 if ((eq = strchr(e, '=')) == NULL || eq == e)
99 if (len > sizeof(keybuf) - 1)
101 memcpy(keybuf, e, len);
104 node = createnode(keybuf, eq + 1);
105 if (RB_INSERT(envtree, &env->root, node)) {
106 /* ignore any later duplicates */
118 flattenenv(struct env *env)
121 struct envnode *node;
124 envp = reallocarray(NULL, env->count + 1, sizeof(char *));
128 RB_FOREACH(node, envtree, &env->root) {
129 if (asprintf(&envp[i], "%s=%s", node->key, node->value) == -1)
138 fillenv(struct env *env, const char **envlist)
140 struct envnode *node, key;
147 for (i = 0; envlist[i]; i++) {
150 /* parse out env name */
151 if ((eq = strchr(e, '=')) == NULL)
155 if (len > sizeof(name) - 1)
157 memcpy(name, e, len);
160 /* delete previous copies */
164 if ((node = RB_FIND(envtree, &env->root, &key))) {
165 RB_REMOVE(envtree, &env->root, node);
172 /* assign value or inherit from environ */
176 val = getenv(val + 1);
180 /* at last, we have something to insert */
182 node = createnode(name, val);
183 RB_INSERT(envtree, &env->root, node);
190 prepenv(struct rule *rule)
192 static const char *safeset[] = {
193 "DISPLAY", "HOME", "LOGNAME", "MAIL",
194 "PATH", "TERM", "USER", "USERNAME",
199 env = createenv(rule);
201 /* if we started with blank, fill some defaults then apply rules */
202 if (!(rule->options & KEEPENV))
203 fillenv(env, safeset);
205 fillenv(env, rule->envlist);
207 return flattenenv(env);