} ProcMgr_ProcList;
-#if defined(_WIN32)
-/*
- * If a caller needs to use a non-default set of arguments for
- * CreateProcess[AsUser] in ProcMgr_Exec[A]sync, this structure should be used.
- *
- * - If 'userArgs' is NULL, defaults are used:
- * - bInheritHandles defaults to TRUE
- * - lpStartupInfo is instantiated and initialized with:
- * - cb initialized to size of the object
- * - dwFlags initialized to STARTF_USESHOWWINDOW
- * - wShowWindow initialized to SW_MINIMIZE.
- * - defaults for all other parameters are NULL/FALSE
- *
- * - If 'userArgs' is not NULL, the values in the 'userArgs' object are used
- * according to the following rules:
- * - If lpStartupInfo is NULL, it is instantiated and initialized with:
- * - cb initialized to size of the object
- * - dwFlags initialized to STARTF_USESHOWWINDOW
- * - wShowWindow initialized to SW_MINIMIZE.
- * - The caller would need to do some of this initialization if they set
- * lpStartupInfo.
- * - If hToken is set:
- * - if lpStartupInfo->lpDesktop is not NULL, then it is used directly. Otherwise,
- * lpStartupInfo->lpDesktop is initialized appropriately.
- *
- * XXX: Make it more convenient for callers(like ToolsDaemonTcloRunProgramImpl)
- * to set just wShowWindow without needing to instantiate and initialize a
- * STARTUPINFO object.
- */
typedef struct ProcMgr_ProcArgs {
+#if defined(_WIN32)
+ /*
+ * If a caller needs to use a non-default set of arguments for
+ * CreateProcess[AsUser] in ProcMgr_Exec[A]sync, this structure should be used.
+ *
+ * - If 'userArgs' is NULL, defaults are used:
+ * - bInheritHandles defaults to TRUE
+ * - lpStartupInfo is instantiated and initialized with:
+ * - cb initialized to size of the object
+ * - dwFlags initialized to STARTF_USESHOWWINDOW
+ * - wShowWindow initialized to SW_MINIMIZE.
+ * - defaults for all other parameters are NULL/FALSE
+ *
+ * - If 'userArgs' is not NULL, the values in the 'userArgs' object are used
+ * according to the following rules:
+ * - If lpStartupInfo is NULL, it is instantiated and initialized with:
+ * - cb initialized to size of the object
+ * - dwFlags initialized to STARTF_USESHOWWINDOW
+ * - wShowWindow initialized to SW_MINIMIZE.
+ * - The caller would need to do some of this initialization if they set
+ * lpStartupInfo.
+ * - If hToken is set:
+ * - if lpStartupInfo->lpDesktop is not NULL, then it is used directly. Otherwise,
+ * lpStartupInfo->lpDesktop is initialized appropriately.
+ *
+ * XXX: Make it more convenient for callers(like ToolsDaemonTcloRunProgramImpl)
+ * to set just wShowWindow without needing to instantiate and initialize a
+ * STARTUPINFO object.
+ */
HANDLE hToken;
LPCWSTR lpApplicationName;
LPVOID lpEnvironment;
LPCWSTR lpCurrentDirectory;
LPSTARTUPINFO lpStartupInfo;
-} ProcMgr_ProcArgs;
#else
-/* Placeholder type for non win32 platforms. Not used. */
-typedef void * ProcMgr_ProcArgs;
+ /*
+ * The environment variables to run the program with. If NULL, use the current
+ * environment.
+ */
+ char **envp;
#endif
+} ProcMgr_ProcArgs;
+
+
typedef void ProcMgr_Callback(Bool status, void *clientData);
#include "str.h"
#include "fileIO.h"
#include "codeset.h"
+#include "unicode.h"
/*
int exitCode;
};
-static pid_t ProcMgrStartProcess(char const *cmd);
+static pid_t ProcMgrStartProcess(char const *cmd,
+ char * const *envp);
static Bool ProcMgrWaitForProcCompletion(pid_t pid,
Bool *validExitCode,
Bool
ProcMgr_ExecSync(char const *cmd, // IN: UTF-8 command line
- ProcMgr_ProcArgs *userArgs) // IN: Unused
+ ProcMgr_ProcArgs *userArgs) // IN: optional
{
pid_t pid;
Debug("Executing sync command: %s\n", cmd);
- pid = ProcMgrStartProcess(cmd);
+ pid = ProcMgrStartProcess(cmd, userArgs ? userArgs->envp : NULL);
if (pid == -1) {
return FALSE;
*----------------------------------------------------------------------
*/
-static pid_t
-ProcMgrStartProcess(char const *cmd) // IN: UTF-8 encoded cmd
+static pid_t
+ProcMgrStartProcess(char const *cmd, // IN: UTF-8 encoded cmd
+ char * const *envp) // IN: UTF-8 encoded env vars
{
pid_t pid;
char *cmdCurrent = NULL;
+ char **envpCurrent = NULL;
if (cmd == NULL) {
ASSERT(FALSE);
return -1;
}
+ /*
+ * Convert the strings before the call to fork(), since the conversion
+ * routines may rely on locks that do not survive fork().
+ */
+
if (!CodeSet_Utf8ToCurrent(cmd, strlen(cmd), &cmdCurrent, NULL)) {
Warning("Could not convert from UTF-8 to current\n");
return -1;
}
+ if (NULL != envp) {
+ envpCurrent = Unicode_GetAllocList(envp, -1, STRING_ENCODING_DEFAULT);
+ }
+
pid = fork();
if (pid == -1) {
Warning("Unable to fork: %s.\n\n", strerror(errno));
} else if (pid == 0) {
+ static const char shellPath[] = "/bin/sh";
+ char *args[] = { "sh", "-c", cmdCurrent, NULL };
/*
* Child
*/
- execl("/bin/sh", "sh", "-c", cmdCurrent, (char *)NULL);
+ if (NULL != envpCurrent) {
+ execve(shellPath, args, envpCurrent);
+ } else {
+ execv(shellPath, args);
+ }
/* Failure */
Panic("Unable to execute the \"%s\" shell command: %s.\n\n",
- cmdCurrent, strerror(errno));
+ cmd, strerror(errno));
}
/*
*/
free(cmdCurrent);
+ Unicode_FreeList(envpCurrent, -1);
return pid;
}
ProcMgr_AsyncProc *
ProcMgr_ExecAsync(char const *cmd, // IN: UTF-8 command line
- ProcMgr_ProcArgs *userArgs) // IN: Unused
+ ProcMgr_ProcArgs *userArgs) // IN: optional
{
ProcMgr_AsyncProc *asyncProc = NULL;
pid_t pid;
* Only run the program if we have not already experienced a failure.
*/
if (status) {
- childPid = ProcMgrStartProcess(cmd);
+ childPid = ProcMgrStartProcess(cmd, userArgs ? userArgs->envp : NULL);
status = childPid != -1;
}
#include "codeset.h"
#include "posix.h"
#include "unicode.h"
+#include "hashTable.h"
#if defined(linux) || defined(_WIN32)
#include "netutil.h"
static VixToolsReportProgramDoneProcType reportProgramDoneProc = NULL;
static void *reportProgramDoneData = NULL;
+#ifndef _WIN32
+typedef struct VixToolsEnvironmentTableIterator {
+ char **envp;
+ size_t pos;
+} VixToolsEnvironmentTableIterator;
+
+/*
+ * Stores the environment variables to use when executing guest applications.
+ */
+static HashTable *userEnvironmentTable = NULL;
+#endif
+
static VixError VixToolsGetFileInfo(VixCommandRequestHeader *requestMsg,
char **result);
static Bool VixToolsPidRefersToThisProcess(ProcMgr_Pid pid);
+#ifndef _WIN32
+static void VixToolsBuildUserEnvironmentTable(const char * const *envp);
+
+static char **VixToolsEnvironmentTableToEnvp(const HashTable *envTable);
+
+static int VixToolsEnvironmentTableEntryToEnvpEntry(const char *key, void *value,
+ void *clientData);
+
+static void VixToolsFreeEnvp(char **envp);
+#endif
+
/*
*-----------------------------------------------------------------------------
VixError
VixTools_Initialize(Bool thisProcessRunsAsRootParam, // IN
+ const char * const *originalEnvp, // IN
VixToolsReportProgramDoneProcType reportProgramDoneProcParam, // IN
void *clientData) // IN
{
reportProgramDoneProc = reportProgramDoneProcParam;
reportProgramDoneData = clientData;
+#ifndef _WIN32
+ VixToolsBuildUserEnvironmentTable(originalEnvp);
+#endif
+
return(err);
} // VixTools_Initialize
+#ifndef _WIN32
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VixToolsBuildUserEnvironmentTable --
+ *
+ * Takes an array of strings of the form "<key>=<value>" storing the
+ * environment variables (as per environ(7)) that should be used when
+ * running programs, and populates the hash table with them.
+ *
+ * If 'envp' is NULL, skip creating the user environment table, so that
+ * we just use the current environment.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * May initialize the global userEnvironmentTable.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VixToolsBuildUserEnvironmentTable(const char * const *envp) // IN: optional
+{
+ if (NULL == envp) {
+ ASSERT(NULL == userEnvironmentTable);
+ return;
+ }
+
+ if (NULL == userEnvironmentTable) {
+ userEnvironmentTable = HashTable_Alloc(64, // buckets (power of 2)
+ HASH_STRING_KEY | HASH_FLAG_COPYKEY,
+ free); // freeFn for the values
+ } else {
+ /*
+ * If we're being reinitialized, we can just clear the table and
+ * load the new values into it. They shouldn't have changed, but
+ * in case they ever do this will cover it.
+ */
+ HashTable_Clear(userEnvironmentTable);
+ }
+
+ for (; NULL != *envp; envp++) {
+ char *name;
+ char *value;
+ char *whereToSplit;
+ size_t nameLen;
+
+ whereToSplit = strchr(*envp, '=');
+ if (NULL == whereToSplit) {
+ /* Our code generated this list, so this shouldn't happen. */
+ ASSERT(0);
+ continue;
+ }
+
+ nameLen = whereToSplit - *envp;
+ name = Util_SafeMalloc(nameLen + 1);
+ memcpy(name, *envp, nameLen);
+ name[nameLen] = '\0';
+
+ whereToSplit++; // skip over '='
+
+ value = Util_SafeStrdup(whereToSplit);
+
+ HashTable_Insert(userEnvironmentTable, name, value);
+ DEBUG_ONLY(value = NULL;) // the hash table now owns 'value'
+
+ free(name);
+ DEBUG_ONLY(name = NULL;)
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VixToolsEnvironmentTableToEnvp --
+ *
+ * Take a hash table storing environment variables names and values and
+ * build an array out of them.
+ *
+ * Results:
+ * char ** - envp array as per environ(7). Must be freed using
+ * VixToolsFreeEnvp
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static char **
+VixToolsEnvironmentTableToEnvp(const HashTable *envTable) // IN
+{
+ char **envp;
+
+ if (NULL != envTable) {
+ VixToolsEnvironmentTableIterator itr;
+ size_t numEntries = HashTable_GetNumElements(envTable);
+
+ itr.envp = envp = Util_SafeMalloc((numEntries + 1) * sizeof *envp);
+ itr.pos = 0;
+
+ HashTable_ForEach(envTable, VixToolsEnvironmentTableEntryToEnvpEntry, &itr);
+
+ ASSERT(numEntries == itr.pos);
+
+ envp[numEntries] = NULL;
+ } else {
+ envp = NULL;
+ }
+
+ return envp;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VixToolsEnvironmentTableEntryToEnvpEntry --
+ *
+ * Callback for HashTable_ForEach(). Gets called for each entry in an
+ * environment table, converting the key (environment variable name) and
+ * value (environment variable value) into a string of the form
+ * "<key>=<value>" and adding that to the envp array passed in with the
+ * VixToolsEnvironmentTableIterator client data.
+ *
+ * Results:
+ * int - always 0
+ *
+ * Side effects:
+ * Sets one entry in the envp.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+VixToolsEnvironmentTableEntryToEnvpEntry(const char *key, // IN
+ void *value, // IN
+ void *clientData) // IN/OUT
+{
+ VixToolsEnvironmentTableIterator *itr = clientData;
+
+ itr->envp[itr->pos++] = Str_SafeAsprintf(NULL, "%s=%s", key, (char *)value);
+
+ return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VixToolsFreeEnvp --
+ *
+ * Free's an array of strings where both the strings and the array
+ * were heap allocated.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VixToolsFreeEnvp(char **envp) // IN
+{
+ if (NULL != envp) {
+ char **itr;
+
+ for (itr = envp; NULL != *itr; itr++) {
+ free(*itr);
+ }
+
+ free(envp);
+ }
+}
+#endif // #ifndef _WIN32
+
+
/*
*-----------------------------------------------------------------------------
*
char *stopProgramFileName;
Bool programExists;
Bool programIsExecutable;
+ ProcMgr_ProcArgs procArgs;
#if defined(_WIN32)
Bool forcedRoot = FALSE;
- ProcMgr_ProcArgs procArgs;
STARTUPINFO si;
#endif
#if defined(VMTOOLS_USE_GLIB)
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = (VIX_RUNPROGRAM_ACTIVATE_WINDOW & runProgramOptions)
? SW_SHOWNORMAL : SW_MINIMIZE;
- asyncState->procState = ProcMgr_ExecAsync(fullCommandLine, &procArgs);
#else
- asyncState->procState = ProcMgr_ExecAsync(fullCommandLine, NULL);
+ procArgs.envp = VixToolsEnvironmentTableToEnvp(userEnvironmentTable);
#endif
+ asyncState->procState = ProcMgr_ExecAsync(fullCommandLine, &procArgs);
+
#if defined(_WIN32)
if (forcedRoot) {
Impersonate_UnforceRoot();
}
+#else
+ VixToolsFreeEnvp(procArgs.envp);
+ DEBUG_ONLY(procArgs.envp = NULL;)
#endif
if (NULL == asyncState->procState) {
* Alwasy get environment variable for the current user, even if the
* current user is root/administrator
*/
+#ifndef _WIN32
+ /*
+ * If we are maintaining our own set of environment variables
+ * because the application we're running from changed the user's
+ * environment, then we should be reading from that.
+ */
+ if (NULL != userEnvironmentTable) {
+ if (HashTable_Lookup(userEnvironmentTable, valueName,
+ (void **) &value)) {
+ value = Util_SafeStrdup(value);
+ } else {
+ value = Util_SafeStrdup("");
+ }
+ break;
+ }
+#endif
+
value = System_GetEnv(FALSE, valueName);
if (NULL == value) {
value = Util_SafeStrdup("");
result = System_SetEnv(FALSE, valueName, value);
if (0 != result) {
err = FoundryToolsDaemon_TranslateSystemErr();
+ goto abort;
}
+
+#ifndef _WIN32
+ /*
+ * We need to make sure that this change is reflected in the table of
+ * environment variables we use when launching programs. This is so if a
+ * a user sets LD_LIBRARY_PATH with WriteVariable, and then calls
+ * RunProgramInGuest, that program will see the new value.
+ */
+ if (NULL != userEnvironmentTable) {
+ /*
+ * The hash table will make a copy of valueName, but we have to supply
+ * a deep copy of the value.
+ */
+ HashTable_ReplaceOrInsert(userEnvironmentTable, valueName,
+ Util_SafeStrdup(value));
+ }
+#endif
break;
case VIX_GUEST_CONFIG:
static char resultBuffer[32];
VixMsgRunScriptRequest *scriptRequest;
const char *interpreterFlags = "";
+ ProcMgr_ProcArgs procArgs;
#if defined(_WIN32)
Bool forcedRoot = FALSE;
- ProcMgr_ProcArgs procArgs;
#endif
#if defined(VMTOOLS_USE_GLIB)
GSource *timer;
memset(&procArgs, 0, sizeof procArgs);
procArgs.hToken = (PROCESS_CREATOR_USER_TOKEN == userToken) ? NULL : userToken;
procArgs.bInheritHandles = TRUE;
- asyncState->procState = ProcMgr_ExecAsync(fullCommandLine, &procArgs);
#else
- asyncState->procState = ProcMgr_ExecAsync(fullCommandLine, NULL);
+ procArgs.envp = VixToolsEnvironmentTableToEnvp(userEnvironmentTable);
#endif
+ asyncState->procState = ProcMgr_ExecAsync(fullCommandLine, &procArgs);
+
#if defined(_WIN32)
if (forcedRoot) {
Impersonate_UnforceRoot();
}
+#else
+ VixToolsFreeEnvp(procArgs.envp);
+ DEBUG_ONLY(procArgs.envp = NULL;)
#endif
if (NULL == asyncState->procState) {
return ret;
}
#endif
-
-