diff --git a/renderdoc/os/posix/posix_process.cpp b/renderdoc/os/posix/posix_process.cpp index 4f1f3b75d..4c5f7de20 100644 --- a/renderdoc/os/posix/posix_process.cpp +++ b/renderdoc/os/posix/posix_process.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -68,6 +69,45 @@ static map EnvStringToEnvMap(const char **envstring) return ret; } +static string expandHome(const string &in) +{ + string path = trim(in); + + // if it's ~/... then replace with $HOME and return + if(path[0] == '~' && path[1] == '/') + return string(getenv("HOME")) + path.substr(1); + + // if it's ~user/... then use getpwname + if(path[0] == '~') + { + size_t slash = path.find('/'); + + string username; + + if(slash != string::npos) + { + RDCASSERT(slash > 1); + username = path.substr(1, slash - 1); + } + else + { + username = path.substr(1); + } + + passwd *pwdata = getpwnam(username.c_str()); + + if(pwdata) + { + if(slash != string::npos) + return string(pwdata->pw_dir) + path.substr(slash); + + return string(pwdata->pw_dir); + } + } + + return path; +} + void Process::RegisterEnvironmentModification(Process::EnvironmentModification modif) { GetEnvModifications().push_back(modif); @@ -138,8 +178,16 @@ static pid_t RunProcess(const char *app, const char *workingDir, const char *cmd if(!app) return (pid_t)0; + string appName = app; + string workDir = (workingDir && workingDir[0]) ? workingDir : dirname(appName); + + // do very limited expansion. wordexp(3) does too much for our needs, so we just expand ~ + // since that could be quite a common case. + appName = expandHome(appName); + workDir = expandHome(workDir); + // it is safe to use app directly as execve never modifies argv - char *emptyargv[] = {(char *)app, NULL}; + char *emptyargv[] = {(char *)appName.c_str(), NULL}; char **argv = emptyargv; const char *c = cmdLine; @@ -166,9 +214,9 @@ static pid_t RunProcess(const char *app, const char *workingDir, const char *cmd argc = 0; // current argument we're fetching // argv[0] is the application name, by convention - size_t len = strlen(app) + 1; + size_t len = appName.length() + 1; argv[argc] = new char[len]; - strcpy(argv[argc], app); + strcpy(argv[argc], appName.c_str()); argc++; @@ -257,18 +305,10 @@ static pid_t RunProcess(const char *app, const char *workingDir, const char *cmd pid_t childPid = fork(); if(childPid == 0) { - if(workingDir) - { - chdir(workingDir); - } - else - { - string exedir = app; - chdir(dirname(exedir).c_str()); - } + chdir(workDir.c_str()); - execve(app, argv, envp); - RDCERR("Failed to execute %s: %s", app, strerror(errno)); + execve(appName.c_str(), argv, envp); + RDCERR("Failed to execute %s: %s", appName.c_str(), strerror(errno)); exit(0); } diff --git a/renderdoc/serialise/string_utils.cpp b/renderdoc/serialise/string_utils.cpp index b8c6d1d53..d771f4fe3 100644 --- a/renderdoc/serialise/string_utils.cpp +++ b/renderdoc/serialise/string_utils.cpp @@ -74,3 +74,16 @@ wstring strupper(const wstring &str) transform(newstr.begin(), newstr.end(), newstr.begin(), towupper); return newstr; } + +std::string trim(const std::string &str) +{ + size_t start = str.find_first_not_of("\t \n"); + size_t end = str.find_last_not_of("\t \n"); + + // no non-whitespace characters, return the empty string + if(start == std::string::npos) + return ""; + + // searching from the start found something, so searching from the end must have too. + return str.substr(start, end - start + 1); +} diff --git a/renderdoc/serialise/string_utils.h b/renderdoc/serialise/string_utils.h index d14be07fa..cd36cb981 100644 --- a/renderdoc/serialise/string_utils.h +++ b/renderdoc/serialise/string_utils.h @@ -37,6 +37,8 @@ std::wstring strlower(const std::wstring &str); std::string strupper(const std::string &str); std::wstring strupper(const std::wstring &str); +std::string trim(const std::string &str); + uint32_t strhash(const char *str, uint32_t existingHash = 5381); template