aboutsummaryrefslogtreecommitdiff
path: root/libbutl/process.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbutl/process.cxx')
-rw-r--r--libbutl/process.cxx208
1 files changed, 120 insertions, 88 deletions
diff --git a/libbutl/process.cxx b/libbutl/process.cxx
index 6c736c1..570c857 100644
--- a/libbutl/process.cxx
+++ b/libbutl/process.cxx
@@ -253,6 +253,35 @@ namespace butl
} while (*p != nullptr);
}
+#if defined(LIBBUTL_POSIX_SPAWN) || defined(_WIN32)
+ // Return true if the NULL-terminated variable list contains an (un)set of
+ // the specified variable. The NULL list argument denotes an empty list.
+ //
+ // Note that on Windows variable names are case-insensitive.
+ //
+ static inline bool
+ contains_envvar (const char* const* vs, const char* v, size_t n)
+ {
+ if (vs != nullptr)
+ {
+ // Note that we don't expect the number of variables to (un)set to be
+ // large, so the linear search is OK.
+ //
+ while (const char* v1 = *vs++)
+ {
+#ifdef _WIN32
+ if (icasecmp (v1, v, n) == 0 && (v1[n] == '=' || v1[n] == '\0'))
+#else
+ if (strncmp (v1, v, n) == 0 && (v1[n] == '=' || v1[n] == '\0'))
+#endif
+ return true;
+ }
+ }
+
+ return false;
+ }
+#endif
+
#ifndef _WIN32
static process_path
@@ -384,7 +413,7 @@ namespace butl
process (const process_path& pp, const char* args[],
pipe pin, pipe pout, pipe perr,
const char* cwd,
- const char* const* envvars)
+ const char* const* evars)
{
int in (pin.in);
int out (pout.out);
@@ -452,6 +481,8 @@ namespace butl
else if (err == -2)
in_efd.out = open_null ();
+ const char* const* tevars (thread_env ());
+
// The posix_spawn()-based implementation.
//
#ifdef LIBBUTL_POSIX_SPAWN
@@ -540,47 +571,45 @@ namespace butl
fail (r);
#endif
- // Set/unset environment variables if requested.
+ // Set/unset the child process environment variables if requested.
//
- small_vector<const char*, 8> new_env;
+ vector<const char*> new_env;
- if (envvars != nullptr)
+ if (tevars != nullptr || evars != nullptr)
{
- for (const char* const* env (environ); *env != nullptr; ++env)
+ // Copy the non-overridden process environment variables into the
+ // child's environment.
+ //
+ for (const char* const* ev (environ); *ev != nullptr; ++ev)
{
- // Lookup the existing variable among those that are requested to be
- // (un)set. If not present, than add it to the child process
- // environment.
- //
- // Note that on POSIX variable names are case-sensitive.
- //
- // Alse note that we don't expect the number of variables to (un)set
- // to be large, so the linear search is OK.
- //
- const char* cv (*env);
- const char* eq (strchr (cv, '='));
- size_t n (eq != nullptr ? eq - cv : strlen (cv));
-
- const char* const* ev (envvars);
- for (; *ev != nullptr; ++ev)
- {
- const char* v (*ev);
- if (strncmp (cv, v, n) == 0 && (v[n] == '=' || v[n] == '\0'))
- break;
- }
+ const char* v (*ev);
+ const char* e (strchr (v, '='));
+ size_t n (e != nullptr ? e - v : strlen (v));
- if (*ev == nullptr)
- new_env.push_back (cv);
+ if (!contains_envvar (tevars, v, n) &&
+ !contains_envvar (evars, v, n))
+ new_env.push_back (v);
}
- // Copy the environment variables that are requested to be set.
+ // Copy non-overridden variable assignments into the child's
+ // environment.
//
- for (const char* const* ev (envvars); *ev != nullptr; ++ev)
+ auto set_vars = [&new_env] (const char* const* vs,
+ const char* const* ovs = nullptr)
{
- const char* v (*ev);
- if (strchr (v, '=') != nullptr)
- new_env.push_back (v);
- }
+ if (vs != nullptr)
+ {
+ while (const char* v = *vs++)
+ {
+ const char* e (strchr (v, '='));
+ if (e != nullptr && !contains_envvar (ovs, v, e - v))
+ new_env.push_back (v);
+ }
+ }
+ };
+
+ set_vars (tevars, evars);
+ set_vars (evars);
new_env.push_back (nullptr);
}
@@ -598,9 +627,9 @@ namespace butl
&fa,
nullptr /* attrp */,
const_cast<char* const*> (&args[0]),
- envvars != nullptr
- ? const_cast<char* const*> (new_env.data ())
- : environ);
+ new_env.empty ()
+ ? environ
+ : const_cast<char* const*> (new_env.data ()));
if (r != 0)
fail (r);
} // Release the lock in parent.
@@ -688,27 +717,33 @@ namespace butl
if (cwd != nullptr && *cwd != '\0' && chdir (cwd) != 0)
fail (true /* child */);
- // Set/unset environment variables if requested.
+ // Set/unset environment variables.
//
- if (envvars != nullptr)
+ auto set_vars = [] (const char* const* vs)
{
- while (const char* ev = *envvars++)
+ if (vs != nullptr)
{
- const char* v (strchr (ev, '='));
-
- try
+ while (const char* v = *vs++)
{
- if (v != nullptr)
- setenv (string (ev, v - ev), v + 1);
- else
- unsetenv (ev);
- }
- catch (const system_error& e)
- {
- throw process_child_error (e.code ().value ());
+ const char* e (strchr (v, '='));
+
+ try
+ {
+ if (e != nullptr)
+ setenv (string (v, e - v), e + 1);
+ else
+ unsetenv (v);
+ }
+ catch (const system_error& e)
+ {
+ throw process_child_error (e.code ().value ());
+ }
}
}
- }
+ };
+
+ set_vars (tevars);
+ set_vars (evars);
// Try to re-exec after the "text file busy" failure for 450ms.
//
@@ -1334,7 +1369,7 @@ namespace butl
process (const process_path& pp, const char* args[],
pipe pin, pipe pout, pipe perr,
const char* cwd,
- const char* const* envvars)
+ const char* const* evars)
{
int in (pin.in);
int out (pout.out);
@@ -1356,7 +1391,9 @@ namespace butl
//
vector<char> new_env;
- if (envvars != nullptr)
+ const char* const* tevars (thread_env ());
+
+ if (tevars != nullptr || evars != nullptr)
{
// The environment block contains the variables in the following format:
//
@@ -1365,7 +1402,7 @@ namespace butl
// Note the trailing NULL character that follows the last variable
// (null-terminated) string.
//
- unique_ptr<char, void (*)(char*)> cvars (
+ unique_ptr<char, void (*)(char*)> pevars (
GetEnvironmentStringsA (),
[] (char* p)
{
@@ -1376,50 +1413,45 @@ namespace butl
assert (false);
});
- if (cvars.get () == nullptr)
+ if (pevars.get () == nullptr)
fail ();
- const char* cv (cvars.get ());
-
- // Copy the current environment variables.
+ // Copy the non-overridden process environment variables into the
+ // child's environment.
//
- while (*cv != '\0')
+ for (const char* v (pevars.get ()); *v != '\0'; )
{
- // Lookup the existing variable among those that are requested to be
- // (un)set. If not present, than copy it to the new block.
- //
- // Note that on Windows variable names are case-insensitive.
- //
- // Alse note that we don't expect the number of variables to (un)set
- // to be large, so the linear search is OK.
- //
- size_t n (strlen (cv) + 1); // Includes NULL character.
+ size_t n (strlen (v) + 1); // Includes NULL character.
- const char* eq (strchr (cv, '='));
- size_t nn (eq != nullptr ? eq - cv : n - 1);
- const char* const* ev (envvars);
-
- for (; *ev != nullptr; ++ev)
- {
- const char* v (*ev);
- if (icasecmp (cv, v, nn) == 0 && (v[nn] == '=' || v[nn] == '\0'))
- break;
- }
+ const char* e (strchr (v, '='));
+ size_t nn (e != nullptr ? e - v : n - 1);
- if (*ev == nullptr)
- new_env.insert (new_env.end (), cv, cv + n);
+ if (!contains_envvar (tevars, v, nn) &&
+ !contains_envvar (evars, v, nn))
+ new_env.insert (new_env.end (), v, v + n);
- cv += n;
+ v += n;
}
- // Copy the environment variables that are requested to be set.
+ // Copy non-overridden variable assignments into the child's
+ // environment.
//
- for (const char* const* ev (envvars); *ev != nullptr; ++ev)
+ auto set_vars = [&new_env] (const char* const* vs,
+ const char* const* ovs = nullptr)
{
- const char* v (*ev);
- if (strchr (v, '=') != nullptr)
- new_env.insert (new_env.end (), v, v + strlen (v) + 1);
- }
+ if (vs != nullptr)
+ {
+ while (const char* v = *vs++)
+ {
+ const char* e (strchr (v, '='));
+ if (e != nullptr && !contains_envvar (ovs, v, e - v))
+ new_env.insert (new_env.end (), v, v + strlen (v) + 1);
+ }
+ }
+ };
+
+ set_vars (tevars, evars);
+ set_vars (evars);
new_env.push_back ('\0'); // Terminate the new environment block.
}
@@ -1776,7 +1808,7 @@ namespace butl
0, // Primary thread security attributes.
true, // Inherit handles.
0, // Creation flags.
- envvars != nullptr ? new_env.data () : nullptr,
+ new_env.empty () ? nullptr : new_env.data (),
cwd != nullptr && *cwd != '\0' ? cwd : nullptr,
&si,
&pi))