1 /* $OpenBSD: environ.c,v 1.16 2016/10/10 21:29:23 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 24 #include "tmux.h" 25 26 /* 27 * Environment - manipulate a set of environment variables. 28 */ 29 30 RB_HEAD(environ, environ_entry); 31 static int environ_cmp(struct environ_entry *, struct environ_entry *); 32 RB_GENERATE_STATIC(environ, environ_entry, entry, environ_cmp); 33 34 static int 35 environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2) 36 { 37 return (strcmp(envent1->name, envent2->name)); 38 } 39 40 /* Initialise the environment. */ 41 struct environ * 42 environ_create(void) 43 { 44 struct environ *env; 45 46 env = xcalloc(1, sizeof *env); 47 RB_INIT(env); 48 49 return (env); 50 } 51 52 /* Free an environment. */ 53 void 54 environ_free(struct environ *env) 55 { 56 struct environ_entry *envent, *envent1; 57 58 RB_FOREACH_SAFE(envent, environ, env, envent1) { 59 RB_REMOVE(environ, env, envent); 60 free(envent->name); 61 free(envent->value); 62 free(envent); 63 } 64 free(env); 65 } 66 67 struct environ_entry * 68 environ_first(struct environ *env) 69 { 70 return (RB_MIN(environ, env)); 71 } 72 73 struct environ_entry * 74 environ_next(struct environ_entry *envent) 75 { 76 return (RB_NEXT(environ, env, envent)); 77 } 78 79 /* Copy one environment into another. */ 80 void 81 environ_copy(struct environ *srcenv, struct environ *dstenv) 82 { 83 struct environ_entry *envent; 84 85 RB_FOREACH(envent, environ, srcenv) { 86 if (envent->value == NULL) 87 environ_clear(dstenv, envent->name); 88 else 89 environ_set(dstenv, envent->name, "%s", envent->value); 90 } 91 } 92 93 /* Find an environment variable. */ 94 struct environ_entry * 95 environ_find(struct environ *env, const char *name) 96 { 97 struct environ_entry envent; 98 99 envent.name = (char *) name; 100 return (RB_FIND(environ, env, &envent)); 101 } 102 103 /* Set an environment variable. */ 104 void 105 environ_set(struct environ *env, const char *name, const char *fmt, ...) 106 { 107 struct environ_entry *envent; 108 va_list ap; 109 110 va_start(ap, fmt); 111 if ((envent = environ_find(env, name)) != NULL) { 112 free(envent->value); 113 xvasprintf(&envent->value, fmt, ap); 114 } else { 115 envent = xmalloc(sizeof *envent); 116 envent->name = xstrdup(name); 117 xvasprintf(&envent->value, fmt, ap); 118 RB_INSERT(environ, env, envent); 119 } 120 va_end(ap); 121 } 122 123 /* Clear an environment variable. */ 124 void 125 environ_clear(struct environ *env, const char *name) 126 { 127 struct environ_entry *envent; 128 129 if ((envent = environ_find(env, name)) != NULL) { 130 free(envent->value); 131 envent->value = NULL; 132 } else { 133 envent = xmalloc(sizeof *envent); 134 envent->name = xstrdup(name); 135 envent->value = NULL; 136 RB_INSERT(environ, env, envent); 137 } 138 } 139 140 /* Set an environment variable from a NAME=VALUE string. */ 141 void 142 environ_put(struct environ *env, const char *var) 143 { 144 char *name, *value; 145 146 value = strchr(var, '='); 147 if (value == NULL) 148 return; 149 value++; 150 151 name = xstrdup(var); 152 name[strcspn(name, "=")] = '\0'; 153 154 environ_set(env, name, "%s", value); 155 free(name); 156 } 157 158 /* Unset an environment variable. */ 159 void 160 environ_unset(struct environ *env, const char *name) 161 { 162 struct environ_entry *envent; 163 164 if ((envent = environ_find(env, name)) == NULL) 165 return; 166 RB_REMOVE(environ, env, envent); 167 free(envent->name); 168 free(envent->value); 169 free(envent); 170 } 171 172 /* 173 * Copy a space-separated list of variables from a destination into a source 174 * environment. 175 */ 176 void 177 environ_update(const char *vars, struct environ *srcenv, 178 struct environ *dstenv) 179 { 180 struct environ_entry *envent; 181 char *copyvars, *var, *next; 182 183 copyvars = next = xstrdup(vars); 184 while ((var = strsep(&next, " ")) != NULL) { 185 if ((envent = environ_find(srcenv, var)) == NULL) 186 environ_clear(dstenv, var); 187 else 188 environ_set(dstenv, envent->name, "%s", envent->value); 189 } 190 free(copyvars); 191 } 192 193 /* Push environment into the real environment - use after fork(). */ 194 void 195 environ_push(struct environ *env) 196 { 197 struct environ_entry *envent; 198 199 environ = xcalloc(1, sizeof *environ); 200 RB_FOREACH(envent, environ, env) { 201 if (envent->value != NULL && *envent->name != '\0') 202 setenv(envent->name, envent->value, 1); 203 } 204 } 205 206 /* Log the environment. */ 207 void 208 environ_log(struct environ *env, const char *prefix) 209 { 210 struct environ_entry *envent; 211 212 RB_FOREACH(envent, environ, env) { 213 if (envent->value != NULL && *envent->name != '\0') { 214 log_debug("%s%s=%s", prefix, envent->name, 215 envent->value); 216 } 217 } 218 } 219