summaryrefslogtreecommitdiffstats
path: root/mmc_updater/src/ProcessUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mmc_updater/src/ProcessUtils.cpp')
-rw-r--r--mmc_updater/src/ProcessUtils.cpp536
1 files changed, 0 insertions, 536 deletions
diff --git a/mmc_updater/src/ProcessUtils.cpp b/mmc_updater/src/ProcessUtils.cpp
deleted file mode 100644
index 3b9ffac2..00000000
--- a/mmc_updater/src/ProcessUtils.cpp
+++ /dev/null
@@ -1,536 +0,0 @@
-#include "ProcessUtils.h"
-
-#include "FileUtils.h"
-#include "Platform.h"
-#include "StringUtils.h"
-#include "Log.h"
-
-#include <string.h>
-#include <vector>
-#include <iostream>
-
-#ifdef PLATFORM_WINDOWS
-#include <windows.h>
-#else
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <errno.h>
-#endif
-
-#ifdef PLATFORM_MAC
-#include <Security/Security.h>
-#include <mach-o/dyld.h>
-#endif
-
-PLATFORM_PID ProcessUtils::currentProcessId()
-{
-#ifdef PLATFORM_UNIX
- return getpid();
-#else
- return GetCurrentProcessId();
-#endif
-}
-
-int ProcessUtils::runSync(const std::string& executable,
- const std::list<std::string>& args)
-{
-#ifdef PLATFORM_UNIX
- return runSyncUnix(executable,args);
-#else
- return runWindows(executable,args,RunSync);
-#endif
-}
-
-#ifdef PLATFORM_UNIX
-int ProcessUtils::runSyncUnix(const std::string& executable,
- const std::list<std::string>& args)
-{
- PLATFORM_PID pid = runAsyncUnix(executable,args);
- int status = 0;
- if (waitpid(pid,&status,0) != -1)
- {
- if (WIFEXITED(status))
- {
- return static_cast<char>(WEXITSTATUS(status));
- }
- else
- {
- LOG(Warn,"Child exited abnormally");
- return -1;
- }
- }
- else
- {
- LOG(Warn,"Failed to get exit status of child " + intToStr(pid));
- return WaitFailed;
- }
-}
-#endif
-
-void ProcessUtils::runAsync(const std::string& executable,
- const std::list<std::string>& args)
-{
-#ifdef PLATFORM_WINDOWS
- runWindows(executable,args,RunAsync);
-#elif defined(PLATFORM_UNIX)
- runAsyncUnix(executable,args);
-#endif
-}
-
-int ProcessUtils::runElevated(const std::string& executable,
- const std::list<std::string>& args,
- const std::string& task)
-{
-#ifdef PLATFORM_WINDOWS
- (void)task;
- return runElevatedWindows(executable,args);
-#elif defined(PLATFORM_MAC)
- (void)task;
- return runElevatedMac(executable,args);
-#elif defined(PLATFORM_LINUX)
- return runElevatedLinux(executable,args,task);
-#endif
-}
-
-bool ProcessUtils::waitForProcess(PLATFORM_PID pid)
-{
-#ifdef PLATFORM_UNIX
- pid_t result = ::waitpid(pid, 0, 0);
- if (result < 0)
- {
- LOG(Error,"waitpid() failed with error: " + std::string(strerror(errno)));
- }
- return result > 0;
-#elif defined(PLATFORM_WINDOWS)
- HANDLE hProc;
-
- if (!(hProc = OpenProcess(SYNCHRONIZE, FALSE, pid)))
- {
- LOG(Error,"Unable to get process handle for pid " + intToStr(pid) + " last error " + intToStr(GetLastError()));
- return false;
- }
-
- DWORD dwRet = WaitForSingleObject(hProc, INFINITE);
- CloseHandle(hProc);
-
- if (dwRet == WAIT_FAILED)
- {
- LOG(Error,"WaitForSingleObject failed with error " + intToStr(GetLastError()));
- }
-
- return (dwRet == WAIT_OBJECT_0);
-#endif
-}
-
-#ifdef PLATFORM_LINUX
-int ProcessUtils::runElevatedLinux(const std::string& executable,
- const std::list<std::string>& args,
- const std::string& _task)
-{
- std::string task(_task);
- if (task.empty())
- {
- task = FileUtils::fileName(executable.c_str());
- }
-
- // try available graphical sudo instances until we find one that works.
- // The different sudo front-ends have different behaviors with respect to error codes:
- //
- // - 'kdesudo': return 1 if the user enters the wrong password 3 times or if
- // they cancel elevation
- //
- // - recent 'gksudo' versions: return 1 if the user enters the wrong password
- // : return -1 if the user cancels elevation
- //
- // - older 'gksudo' versions : return 0 if the user cancels elevation
-
- std::vector<std::string> sudos;
-
- if (getenv("KDE_SESSION_VERSION"))
- {
- sudos.push_back("kdesudo");
- }
- sudos.push_back("gksudo");
-
- for (unsigned int i=0; i < sudos.size(); i++)
- {
- const std::string& sudoBinary = sudos.at(i);
-
- std::list<std::string> sudoArgs;
- sudoArgs.push_back("-u");
- sudoArgs.push_back("root");
-
- if (sudoBinary == "kdesudo")
- {
- sudoArgs.push_back("-d");
- sudoArgs.push_back("--comment");
- std::string sudoMessage = task + " needs administrative privileges. Please enter your password.";
- sudoArgs.push_back(sudoMessage);
- }
- else if (sudoBinary == "gksudo")
- {
- sudoArgs.push_back("--description");
- sudoArgs.push_back(task);
- }
- else
- {
- sudoArgs.push_back(task);
- }
-
- sudoArgs.push_back("--");
- sudoArgs.push_back(executable);
- std::copy(args.begin(),args.end(),std::back_inserter(sudoArgs));
-
- int result = ProcessUtils::runSync(sudoBinary,sudoArgs);
-
- LOG(Info,"Tried to use sudo " + sudoBinary + " with response " + intToStr(result));
-
- if (result != RunFailed)
- {
- return result;
- break;
- }
- }
- return RunElevatedFailed;
-}
-#endif
-
-#ifdef PLATFORM_MAC
-int ProcessUtils::runElevatedMac(const std::string& executable,
- const std::list<std::string>& args)
-{
- // request elevation using the Security Service.
- //
- // This only works when the application is being run directly
- // from the Mac. Attempting to run the app via a remote SSH session
- // (for example) will fail with an interaction-not-allowed error
-
- OSStatus status;
- AuthorizationRef authorizationRef;
-
- status = AuthorizationCreate(
- NULL,
- kAuthorizationEmptyEnvironment,
- kAuthorizationFlagDefaults,
- &authorizationRef);
-
- AuthorizationItem right = { kAuthorizationRightExecute, 0, NULL, 0 };
- AuthorizationRights rights = { 1, &right };
-
- AuthorizationFlags flags = kAuthorizationFlagDefaults |
- kAuthorizationFlagInteractionAllowed |
- kAuthorizationFlagPreAuthorize |
- kAuthorizationFlagExtendRights;
-
- if (status == errAuthorizationSuccess)
- {
- status = AuthorizationCopyRights(authorizationRef, &rights, NULL,
- flags, NULL);
-
- if (status == errAuthorizationSuccess)
- {
- char** argv;
- argv = (char**) malloc(sizeof(char*) * args.size() + 1);
-
- unsigned int i = 0;
- for (std::list<std::string>::const_iterator iter = args.begin(); iter != args.end(); iter++)
- {
- argv[i] = strdup(iter->c_str());
- ++i;
- }
- argv[i] = NULL;
-
- FILE* pipe = NULL;
-
- char* tool = strdup(executable.c_str());
-
- status = AuthorizationExecuteWithPrivileges(authorizationRef, tool,
- kAuthorizationFlagDefaults, argv, &pipe);
-
- if (status == errAuthorizationSuccess)
- {
- // AuthorizationExecuteWithPrivileges does not provide a way to get the process ID
- // of the child process.
- //
- // Discussions on Apple development forums suggest two approaches for working around this,
- //
- // - Modify the child process to sent its process ID back to the parent via
- // the pipe passed to AuthorizationExecuteWithPrivileges.
- //
- // - Use the generic Unix wait() call.
- //
- // This code uses wait(), which is simpler, but suffers from the problem that wait() waits
- // for any child process, not necessarily the specific process launched
- // by AuthorizationExecuteWithPrivileges.
- //
- // Apple's documentation (see 'Authorization Services Programming Guide') suggests
- // installing files in an installer as a legitimate use for
- // AuthorizationExecuteWithPrivileges but in general strongly recommends
- // not using this call and discusses a number of other alternatives
- // for performing privileged operations,
- // which we could consider in future.
-
- int childStatus;
- pid_t childPid = wait(&childStatus);
-
- if (childStatus != 0)
- {
- LOG(Error,"elevated process failed with status " + intToStr(childStatus) + " pid "
- + intToStr(childPid));
- }
- else
- {
- LOG(Info,"elevated process succeded with pid " + intToStr(childPid));
- }
-
- return childStatus;
- }
- else
- {
- LOG(Error,"failed to launch elevated process " + intToStr(status));
- return RunElevatedFailed;
- }
-
- // If we want to know more information about what has happened:
- // http://developer.apple.com/mac/library/documentation/Security/Reference/authorization_ref/Reference/reference.html#//apple_ref/doc/uid/TP30000826-CH4g-CJBEABHG
- free(tool);
- for (i = 0; i < args.size(); i++)
- {
- free(argv[i]);
- }
- }
- else
- {
- LOG(Error,"failed to get rights to launch elevated process. status: " + intToStr(status));
- return RunElevatedFailed;
- }
- }
- else
- {
- return RunElevatedFailed;
- }
-}
-#endif
-
-// convert a list of arguments in a space-separated string.
-// Arguments containing spaces are enclosed in quotes
-std::string quoteArgs(const std::list<std::string>& arguments)
-{
- std::string quotedArgs;
- for (std::list<std::string>::const_iterator iter = arguments.begin();
- iter != arguments.end();
- iter++)
- {
- std::string arg = *iter;
-
- bool isQuoted = !arg.empty() &&
- arg.at(0) == '"' &&
- arg.at(arg.size()-1) == '"';
-
- if (!isQuoted && arg.find(' ') != std::string::npos)
- {
- arg.insert(0,"\"");
- arg.append("\"");
- }
- quotedArgs += arg;
- quotedArgs += " ";
- }
- return quotedArgs;
-}
-
-#ifdef PLATFORM_WINDOWS
-int ProcessUtils::runElevatedWindows(const std::string& executable,
- const std::list<std::string>& arguments)
-{
- std::string args = quoteArgs(arguments);
-
- SHELLEXECUTEINFO executeInfo;
- ZeroMemory(&executeInfo,sizeof(executeInfo));
- executeInfo.cbSize = sizeof(SHELLEXECUTEINFO);
- executeInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
- // request UAC elevation
- executeInfo.lpVerb = "runas";
- executeInfo.lpFile = executable.c_str();
- executeInfo.lpParameters = args.c_str();
- executeInfo.nShow = SW_SHOWNORMAL;
-
- LOG(Info,"Attempting to execute " + executable + " with administrator priviledges");
- if (!ShellExecuteEx(&executeInfo))
- {
- LOG(Error,"Failed to start with admin priviledges using ShellExecuteEx()");
- return RunElevatedFailed;
- }
-
- WaitForSingleObject(executeInfo.hProcess, INFINITE);
-
- // this assumes the process succeeded - we need to check whether
- // this is actually the case.
- return 0;
-}
-#endif
-
-#ifdef PLATFORM_UNIX
-PLATFORM_PID ProcessUtils::runAsyncUnix(const std::string& executable,
- const std::list<std::string>& args)
-{
- pid_t child = fork();
- if (child == 0)
- {
- // in child process
- char** argBuffer = new char*[args.size() + 2];
- argBuffer[0] = strdup(executable.c_str());
- int i = 1;
- for (std::list<std::string>::const_iterator iter = args.begin(); iter != args.end(); iter++)
- {
- argBuffer[i] = strdup(iter->c_str());
- ++i;
- }
- argBuffer[i] = 0;
-
- if (execvp(executable.c_str(),argBuffer) == -1)
- {
- LOG(Error,"error starting child: " + std::string(strerror(errno)));
- exit(RunFailed);
- }
- }
- else
- {
- LOG(Info,"Started child process " + intToStr(child));
- }
- return child;
-}
-#endif
-
-#ifdef PLATFORM_WINDOWS
-int ProcessUtils::runWindows(const std::string& _executable,
- const std::list<std::string>& _args,
- RunMode runMode)
-{
- // most Windows API functions allow back and forward slashes to be
- // used interchangeably. However, an application started with
- // CreateProcess() may fail to find Side-by-Side library dependencies
- // in the same directory as the executable if forward slashes are
- // used as path separators, so convert the path to use back slashes here.
- //
- // This may be related to LoadLibrary() requiring backslashes instead
- // of forward slashes.
- std::string executable = FileUtils::toWindowsPathSeparators(_executable);
-
- std::list<std::string> args(_args);
- args.push_front(executable);
- std::string commandLine = quoteArgs(args);
-
- STARTUPINFO startupInfo;
- ZeroMemory(&startupInfo,sizeof(startupInfo));
- startupInfo.cb = sizeof(startupInfo);
-
- PROCESS_INFORMATION processInfo;
- ZeroMemory(&processInfo,sizeof(processInfo));
-
- char* commandLineStr = strdup(commandLine.c_str());
- bool result = CreateProcess(
- executable.c_str(),
- commandLineStr,
- 0 /* process attributes */,
- 0 /* thread attributes */,
- false /* inherit handles */,
- NORMAL_PRIORITY_CLASS /* creation flags */,
- 0 /* environment */,
- 0 /* current directory */,
- &startupInfo /* startup info */,
- &processInfo /* process information */
- );
-
- if (!result)
- {
- LOG(Error,"Failed to start child process. " + executable + " Last error: " + intToStr(GetLastError()));
- return RunFailed;
- }
- else
- {
- if (runMode == RunSync)
- {
- if (WaitForSingleObject(processInfo.hProcess,INFINITE) == WAIT_OBJECT_0)
- {
- DWORD status = WaitFailed;
- if (GetExitCodeProcess(processInfo.hProcess,&status) != 0)
- {
- LOG(Error,"Failed to get exit code for process");
- }
- return status;
- }
- else
- {
- LOG(Error,"Failed to wait for process to finish");
- return WaitFailed;
- }
- }
- else
- {
- // process is being run asynchronously - return zero as if it had
- // succeeded
- return 0;
- }
- }
-}
-#endif
-
-std::string ProcessUtils::currentProcessPath()
-{
-#ifdef PLATFORM_LINUX
- std::string path = FileUtils::canonicalPath("/proc/self/exe");
- LOG(Info,"Current process path " + path);
- return path;
-#elif defined(PLATFORM_MAC)
- uint32_t bufferSize = PATH_MAX;
- char buffer[bufferSize];
- _NSGetExecutablePath(buffer,&bufferSize);
- return buffer;
-#else
- char fileName[MAX_PATH];
- GetModuleFileName(0 /* get path of current process */,fileName,MAX_PATH);
- return fileName;
-#endif
-}
-
-#ifdef PLATFORM_WINDOWS
-void ProcessUtils::convertWindowsCommandLine(LPCWSTR commandLine, int& argc, char**& argv)
-{
- argc = 0;
- LPWSTR* argvUnicode = CommandLineToArgvW(commandLine,&argc);
-
- argv = new char*[argc];
- for (int i=0; i < argc; i++)
- {
- const int BUFFER_SIZE = 4096;
- char buffer[BUFFER_SIZE];
-
- int length = WideCharToMultiByte(CP_ACP,
- 0 /* flags */,
- argvUnicode[i],
- -1, /* argvUnicode is null terminated */
- buffer,
- BUFFER_SIZE,
- 0,
- false);
-
- // note: if WideCharToMultiByte() fails it will return zero,
- // in which case we store a zero-length argument in argv
- if (length == 0)
- {
- argv[i] = new char[1];
- argv[i][0] = '\0';
- }
- else
- {
- // if the input string to WideCharToMultiByte is null-terminated,
- // the output is also null-terminated
- argv[i] = new char[length];
- strncpy(argv[i],buffer,length);
- }
- }
- LocalFree(argvUnicode);
-}
-#endif
-