mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 12:23:32 +01:00
Add process_environment_make and related utilities
This commit is contained in:
parent
806e0f7e19
commit
98cec14982
@ -3721,6 +3721,117 @@ tor_get_exit_code(const process_handle_t *process_handle,
|
||||
return PROCESS_EXIT_EXITED;
|
||||
}
|
||||
|
||||
/** Return non-zero iff getenv would consider <b>s1</b> and <b>s2</b>
|
||||
* to have the same name as strings in a process's environment. */
|
||||
int
|
||||
environment_variable_names_equal(const char *s1, const char *s2)
|
||||
{
|
||||
size_t s1_name_len = strcspn(s1, "=");
|
||||
size_t s2_name_len = strcspn(s2, "=");
|
||||
|
||||
return (s1_name_len == s2_name_len &&
|
||||
tor_memeq(s1, s2, s1_name_len));
|
||||
}
|
||||
|
||||
/** Free <b>env</b> (assuming it was produced by
|
||||
* process_environment_make). */
|
||||
void
|
||||
process_environment_free(process_environment_t *env)
|
||||
{
|
||||
if (env == NULL) return;
|
||||
|
||||
/* As both an optimization hack to reduce consing on Unixoid systems
|
||||
* and a nice way to ensure that some otherwise-Windows-specific
|
||||
* code will always get tested before changes to it get merged, the
|
||||
* strings which env->unixoid_environment_block points to are packed
|
||||
* into env->windows_environment_block. */
|
||||
tor_free(env->unixoid_environment_block);
|
||||
tor_free(env->windows_environment_block);
|
||||
|
||||
tor_free(env);
|
||||
}
|
||||
|
||||
/** Make a process_environment_t containing the environment variables
|
||||
* specified in <b>env_vars</b> (as C strings of the form
|
||||
* "NAME=VALUE"). */
|
||||
process_environment_t *
|
||||
process_environment_make(struct smartlist_t *env_vars)
|
||||
{
|
||||
process_environment_t *env = tor_malloc_zero(sizeof(process_environment_t));
|
||||
size_t n_env_vars = smartlist_len(env_vars);
|
||||
size_t i;
|
||||
size_t total_env_length;
|
||||
smartlist_t *env_vars_sorted;
|
||||
|
||||
tor_assert(n_env_vars + 1 != 0);
|
||||
env->unixoid_environment_block = tor_calloc(n_env_vars + 1, sizeof(char *));
|
||||
/* env->unixoid_environment_block is already NULL-terminated,
|
||||
* because we assume that NULL == 0 (and check that during compilation). */
|
||||
|
||||
total_env_length = 1; /* terminating NUL of terminating empty string */
|
||||
for (i = 0; i < n_env_vars; ++i) {
|
||||
const char *s = smartlist_get(env_vars, i);
|
||||
size_t slen = strlen(s);
|
||||
|
||||
tor_assert(slen + 1 != 0);
|
||||
tor_assert(slen + 1 < SIZE_MAX - total_env_length);
|
||||
total_env_length += slen + 1;
|
||||
}
|
||||
|
||||
env->windows_environment_block = tor_malloc_zero(total_env_length);
|
||||
/* env->windows_environment_block is already
|
||||
* (NUL-terminated-empty-string)-terminated. */
|
||||
|
||||
/* Some versions of Windows supposedly require that environment
|
||||
* blocks be sorted. Or maybe some Windows programs (or their
|
||||
* runtime libraries) fail to look up strings in non-sorted
|
||||
* environment blocks.
|
||||
*
|
||||
* Also, sorting strings makes it easy to find duplicate environment
|
||||
* variables and environment-variable strings without an '=' on all
|
||||
* OSes, and they can cause badness. Let's complain about those. */
|
||||
env_vars_sorted = smartlist_new();
|
||||
smartlist_add_all(env_vars_sorted, env_vars);
|
||||
smartlist_sort_strings(env_vars_sorted);
|
||||
|
||||
/* Now copy the strings into the environment blocks. */
|
||||
{
|
||||
char *cp = env->windows_environment_block;
|
||||
const char *prev_env_var = NULL;
|
||||
|
||||
for (i = 0; i < n_env_vars; ++i) {
|
||||
const char *s = smartlist_get(env_vars_sorted, i);
|
||||
size_t slen = strlen(s);
|
||||
size_t s_name_len = strcspn(s, "=");
|
||||
|
||||
if (s_name_len == slen) {
|
||||
log_warn(LD_GENERAL,
|
||||
"Preparing an environment containing a variable "
|
||||
"without a value: %s",
|
||||
s);
|
||||
}
|
||||
if (prev_env_var != NULL &&
|
||||
environment_variable_names_equal(s, prev_env_var)) {
|
||||
log_warn(LD_GENERAL,
|
||||
"Preparing an environment containing two variables "
|
||||
"with the same name: %s and %s",
|
||||
prev_env_var, s);
|
||||
}
|
||||
|
||||
prev_env_var = s;
|
||||
|
||||
/* Actually copy the string into the environment. */
|
||||
memcpy(cp, s, slen+1);
|
||||
env->unixoid_environment_block[i] = cp;
|
||||
cp += slen+1;
|
||||
}
|
||||
|
||||
tor_assert(cp == env->windows_environment_block + total_env_length - 1);
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If
|
||||
* <b>hProcess</b> is NULL, the function will return immediately if there is
|
||||
|
@ -379,6 +379,21 @@ int tor_spawn_background(const char *const filename, const char **argv,
|
||||
HANDLE load_windows_system_library(const TCHAR *library_name);
|
||||
#endif
|
||||
|
||||
int environment_variable_names_equal(const char *s1, const char *s2);
|
||||
|
||||
struct process_environment_t {
|
||||
/** A pointer to a sorted empty-string-terminated sequence of
|
||||
* NUL-terminated strings of the form "NAME=VALUE". */
|
||||
char *windows_environment_block;
|
||||
/** A pointer to a NULL-terminated array of pointers to
|
||||
* NUL-terminated strings of the form "NAME=VALUE". */
|
||||
char **unixoid_environment_block;
|
||||
};
|
||||
typedef struct process_environment_t process_environment_t;
|
||||
|
||||
process_environment_t *process_environment_make(struct smartlist_t *env_vars);
|
||||
void process_environment_free(process_environment_t *env);
|
||||
|
||||
/* Values of process_handle_t.status. PROCESS_STATUS_NOTRUNNING must be
|
||||
* 0 because tor_check_port_forwarding depends on this being the initial
|
||||
* statue of the static instance of process_handle_t */
|
||||
|
Loading…
Reference in New Issue
Block a user