tor  0.4.1.0-alpha-dev
env.c
Go to the documentation of this file.
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 */
5 
11 #include "orconfig.h"
12 #include "lib/process/env.h"
13 
14 #include "lib/malloc/malloc.h"
15 #include "lib/ctime/di_ops.h"
17 #include "lib/log/util_bug.h"
18 #include "lib/log/log.h"
19 #include "lib/malloc/malloc.h"
20 
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
30 
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) */
39 
42 char **
44 {
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) */
53 }
54 
58 static inline size_t
59 str_num_before(const char *s, char ch)
60 {
61  const char *cp = strchr(s, ch);
62  if (cp)
63  return cp - s;
64  else
65  return strlen(s);
66 }
67 
70 int
71 environment_variable_names_equal(const char *s1, const char *s2)
72 {
73  size_t s1_name_len = str_num_before(s1, '=');
74  size_t s2_name_len = str_num_before(s2, '=');
75 
76  return (s1_name_len == s2_name_len &&
77  tor_memeq(s1, s2, s1_name_len));
78 }
79 
82 void
84 {
85  if (env == NULL) return;
86 
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. */
94 
95  tor_free(env);
96 }
97 
103 {
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;
109 
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). */
114 
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);
119 
120  tor_assert(slen + 1 != 0);
121  tor_assert(slen + 1 < SIZE_MAX - total_env_length);
122  total_env_length += slen + 1;
123  }
124 
125  env->windows_environment_block = tor_malloc_zero(total_env_length);
126  /* env->windows_environment_block is already
127  * (NUL-terminated-empty-string)-terminated. */
128 
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.
133  *
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);
140 
141  /* Now copy the strings into the environment blocks. */
142  {
143  char *cp = env->windows_environment_block;
144  const char *prev_env_var = NULL;
145 
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, '=');
150 
151  if (s_name_len == slen) {
152  log_warn(LD_GENERAL,
153  "Preparing an environment containing a variable "
154  "without a value: %s",
155  s);
156  }
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);
163  }
164 
165  prev_env_var = s;
166 
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;
171  }
172 
173  tor_assert(cp == env->windows_environment_block + total_env_length - 1);
174  }
175 
176  smartlist_free(env_vars_sorted);
177 
178  return env;
179 }
180 
189 struct smartlist_t *
191 {
192  smartlist_t *sl = smartlist_new();
193 
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);
197  }
198 
199  return sl;
200 }
201 
206 void
208  const char *new_var,
209  void (*free_old)(void*),
210  int free_p)
211 {
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);
217  }
218  }
219  } SMARTLIST_FOREACH_END(s);
220 
221  if (strchr(new_var, '=') != NULL) {
222  smartlist_add(env_vars, (void *)new_var);
223  }
224 }
Header for smartlist.c.
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
Headers for di_ops.c.
struct smartlist_t * get_current_process_environment_variables(void)
Definition: env.c:190
void smartlist_add_strdup(struct smartlist_t *sl, const char *string)
#define LD_GENERAL
Definition: log.h:58
char * windows_environment_block
Definition: env.h:24
void smartlist_add(smartlist_t *sl, void *element)
process_environment_t * process_environment_make(struct smartlist_t *env_vars)
Definition: env.c:102
#define tor_free(p)
Definition: malloc.h:52
Header for env.c.
#define SMARTLIST_DEL_CURRENT(sl, var)
Headers for util_malloc.c.
void smartlist_sort_strings(smartlist_t *sl)
Definition: smartlist.c:549
static size_t str_num_before(const char *s, char ch)
Definition: env.c:59
void process_environment_free_(process_environment_t *env)
Definition: env.c:83
char ** unixoid_environment_block
Definition: env.h:27
tor_assert(buffer)
int tor_memeq(const void *a, const void *b, size_t sz)
Definition: di_ops.c:107
int environment_variable_names_equal(const char *s1, const char *s2)
Definition: env.c:71
void set_environment_variable_in_smartlist(struct smartlist_t *env_vars, const char *new_var, void(*free_old)(void *), int free_p)
Definition: env.c:207
void smartlist_add_all(smartlist_t *s1, const smartlist_t *s2)
char ** get_environment(void)
Definition: env.c:43
Headers for log.c.
Macros to manage assertions, fatal and non-fatal.