fix typos from #28614
[tor.git] / src / lib / process / env.c
blob0060200ba178db1604743c12375e71ef19986847
1 /* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2019, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 /**
7 * \file env.c
8 * \brief Inspect and manipulate the environment variables.
9 **/
11 #include "orconfig.h"
12 #include "lib/process/env.h"
14 #include "lib/malloc/malloc.h"
15 #include "lib/ctime/di_ops.h"
16 #include "lib/container/smartlist.h"
17 #include "lib/log/util_bug.h"
18 #include "lib/log/log.h"
19 #include "lib/malloc/malloc.h"
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 #ifdef HAVE_CRT_EXTERNS_H
27 /* For _NSGetEnviron on macOS */
28 #include <crt_externs.h>
29 #endif
31 #ifndef HAVE__NSGETENVIRON
32 #ifndef HAVE_EXTERN_ENVIRON_DECLARED
33 /* Some platforms declare environ under some circumstances, others don't. */
34 #ifndef RUNNING_DOXYGEN
35 extern char **environ;
36 #endif
37 #endif /* !defined(HAVE_EXTERN_ENVIRON_DECLARED) */
38 #endif /* !defined(HAVE__NSGETENVIRON) */
40 /** Return the current environment. This is a portable replacement for
41 * 'environ'. */
42 char **
43 get_environment(void)
45 #ifdef HAVE__NSGETENVIRON
46 /* This is for compatibility between OSX versions. Otherwise (for example)
47 * when we do a mostly-static build on OSX 10.7, the resulting binary won't
48 * work on OSX 10.6. */
49 return *_NSGetEnviron();
50 #else /* !(defined(HAVE__NSGETENVIRON)) */
51 return environ;
52 #endif /* defined(HAVE__NSGETENVIRON) */
55 /** Helper: return the number of characters in <b>s</b> preceding the first
56 * occurrence of <b>ch</b>. If <b>ch</b> does not occur in <b>s</b>, return
57 * the length of <b>s</b>. Should be equivalent to strspn(s, "ch"). */
58 static inline size_t
59 str_num_before(const char *s, char ch)
61 const char *cp = strchr(s, ch);
62 if (cp)
63 return cp - s;
64 else
65 return strlen(s);
68 /** Return non-zero iff getenv would consider <b>s1</b> and <b>s2</b>
69 * to have the same name as strings in a process's environment. */
70 int
71 environment_variable_names_equal(const char *s1, const char *s2)
73 size_t s1_name_len = str_num_before(s1, '=');
74 size_t s2_name_len = str_num_before(s2, '=');
76 return (s1_name_len == s2_name_len &&
77 tor_memeq(s1, s2, s1_name_len));
80 /** Free <b>env</b> (assuming it was produced by
81 * process_environment_make). */
82 void
83 process_environment_free_(process_environment_t *env)
85 if (env == NULL) return;
87 /* As both an optimization hack to reduce consing on Unixoid systems
88 * and a nice way to ensure that some otherwise-Windows-specific
89 * code will always get tested before changes to it get merged, the
90 * strings which env->unixoid_environment_block points to are packed
91 * into env->windows_environment_block. */
92 tor_free(env->unixoid_environment_block);
93 tor_free(env->windows_environment_block);
95 tor_free(env);
98 /** Make a process_environment_t containing the environment variables
99 * specified in <b>env_vars</b> (as C strings of the form
100 * "NAME=VALUE"). */
101 process_environment_t *
102 process_environment_make(struct smartlist_t *env_vars)
104 process_environment_t *env = tor_malloc_zero(sizeof(process_environment_t));
105 int n_env_vars = smartlist_len(env_vars);
106 int i;
107 size_t total_env_length;
108 smartlist_t *env_vars_sorted;
110 tor_assert(n_env_vars + 1 != 0);
111 env->unixoid_environment_block = tor_calloc(n_env_vars + 1, sizeof(char *));
112 /* env->unixoid_environment_block is already NULL-terminated,
113 * because we assume that NULL == 0 (and check that during compilation). */
115 total_env_length = 1; /* terminating NUL of terminating empty string */
116 for (i = 0; i < n_env_vars; ++i) {
117 const char *s = smartlist_get(env_vars, (int)i);
118 size_t slen = strlen(s);
120 tor_assert(slen + 1 != 0);
121 tor_assert(slen + 1 < SIZE_MAX - total_env_length);
122 total_env_length += slen + 1;
125 env->windows_environment_block = tor_malloc_zero(total_env_length);
126 /* env->windows_environment_block is already
127 * (NUL-terminated-empty-string)-terminated. */
129 /* Some versions of Windows supposedly require that environment
130 * blocks be sorted. Or maybe some Windows programs (or their
131 * runtime libraries) fail to look up strings in non-sorted
132 * environment blocks.
134 * Also, sorting strings makes it easy to find duplicate environment
135 * variables and environment-variable strings without an '=' on all
136 * OSes, and they can cause badness. Let's complain about those. */
137 env_vars_sorted = smartlist_new();
138 smartlist_add_all(env_vars_sorted, env_vars);
139 smartlist_sort_strings(env_vars_sorted);
141 /* Now copy the strings into the environment blocks. */
143 char *cp = env->windows_environment_block;
144 const char *prev_env_var = NULL;
146 for (i = 0; i < n_env_vars; ++i) {
147 const char *s = smartlist_get(env_vars_sorted, (int)i);
148 size_t slen = strlen(s);
149 size_t s_name_len = str_num_before(s, '=');
151 if (s_name_len == slen) {
152 log_warn(LD_GENERAL,
153 "Preparing an environment containing a variable "
154 "without a value: %s",
157 if (prev_env_var != NULL &&
158 environment_variable_names_equal(s, prev_env_var)) {
159 log_warn(LD_GENERAL,
160 "Preparing an environment containing two variables "
161 "with the same name: %s and %s",
162 prev_env_var, s);
165 prev_env_var = s;
167 /* Actually copy the string into the environment. */
168 memcpy(cp, s, slen+1);
169 env->unixoid_environment_block[i] = cp;
170 cp += slen+1;
173 tor_assert(cp == env->windows_environment_block + total_env_length - 1);
176 smartlist_free(env_vars_sorted);
178 return env;
181 /** Return a newly allocated smartlist containing every variable in
182 * this process's environment, as a NUL-terminated string of the form
183 * "NAME=VALUE". Note that on some/many/most/all OSes, the parent
184 * process can put strings not of that form in our environment;
185 * callers should try to not get crashed by that.
187 * The returned strings are heap-allocated, and must be freed by the
188 * caller. */
189 struct smartlist_t *
190 get_current_process_environment_variables(void)
192 smartlist_t *sl = smartlist_new();
194 char **environ_tmp; /* Not const char ** ? Really? */
195 for (environ_tmp = get_environment(); *environ_tmp; ++environ_tmp) {
196 smartlist_add_strdup(sl, *environ_tmp);
199 return sl;
202 /** For each string s in <b>env_vars</b> such that
203 * environment_variable_names_equal(s, <b>new_var</b>), remove it; if
204 * <b>free_p</b> is non-zero, call <b>free_old</b>(s). If
205 * <b>new_var</b> contains '=', insert it into <b>env_vars</b>. */
206 void
207 set_environment_variable_in_smartlist(struct smartlist_t *env_vars,
208 const char *new_var,
209 void (*free_old)(void*),
210 int free_p)
212 SMARTLIST_FOREACH_BEGIN(env_vars, const char *, s) {
213 if (environment_variable_names_equal(s, new_var)) {
214 SMARTLIST_DEL_CURRENT(env_vars, s);
215 if (free_p) {
216 free_old((void *)s);
219 } SMARTLIST_FOREACH_END(s);
221 if (strchr(new_var, '=') != NULL) {
222 smartlist_add(env_vars, (void *)new_var);