mirror of
https://github.com/autc04/Retro68.git
synced 2024-12-01 11:52:47 +00:00
193 lines
4.0 KiB
C++
193 lines
4.0 KiB
C++
#include "Utilities.h"
|
|
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <signal.h>
|
|
#include <boost/filesystem.hpp>
|
|
#include <iostream>
|
|
|
|
namespace fs = boost::filesystem;
|
|
using std::string;
|
|
using std::vector;
|
|
|
|
int ChildProcess(string program, vector<string> args, int timeout)
|
|
{
|
|
std::vector<const char*> argv;
|
|
argv.push_back(program.c_str());
|
|
for(string& s : args)
|
|
argv.push_back(s.c_str());
|
|
argv.push_back(NULL);
|
|
|
|
pid_t pid = fork();
|
|
if(pid < 0)
|
|
{
|
|
perror("unable to fork");
|
|
return 1;
|
|
}
|
|
else if(pid == 0)
|
|
{
|
|
pid_t worker_pid = timeout ? fork() : 0;
|
|
if(worker_pid < 0)
|
|
{
|
|
perror("unable to fork");
|
|
_exit(1);
|
|
}
|
|
if(worker_pid == 0)
|
|
{
|
|
execvp(argv[0], const_cast<char* const *> (argv.data()));
|
|
perror("exec failed");
|
|
std::cerr << "Tried to execute: " << program;
|
|
for(auto a : args)
|
|
std::cerr << " " << a;
|
|
std::cerr << std::endl;
|
|
_exit(1);
|
|
}
|
|
|
|
pid_t timeout_pid = fork();
|
|
if(timeout_pid < 0)
|
|
{
|
|
perror("unable to fork");
|
|
_exit(1);
|
|
}
|
|
if(timeout_pid == 0)
|
|
{
|
|
sleep(timeout);
|
|
_exit(0);
|
|
}
|
|
int wstatus;
|
|
pid_t exited_pid = wait(&wstatus);
|
|
if(exited_pid == worker_pid)
|
|
{
|
|
kill(timeout_pid, SIGKILL);
|
|
wait(NULL);
|
|
if(!WIFEXITED(wstatus))
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
int exitcode = WEXITSTATUS(wstatus);
|
|
_exit(exitcode);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
kill(worker_pid, SIGKILL);
|
|
wait(NULL);
|
|
_exit(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int wstatus;
|
|
int result = 0;
|
|
do
|
|
{
|
|
result = waitpid(pid, &wstatus, 0);
|
|
} while(result == -1 && errno == EINTR);
|
|
|
|
if(!WIFEXITED(wstatus))
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
int exitcode = WEXITSTATUS(wstatus);
|
|
return exitcode;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CheckExecutable(std::string program)
|
|
{
|
|
if(access(program.c_str(), X_OK) == 0)
|
|
return true;
|
|
if(program.find("/") != std::string::npos)
|
|
return false;
|
|
const char *PATH = getenv("PATH");
|
|
|
|
if(PATH)
|
|
{
|
|
bool endFound = false;
|
|
do
|
|
{
|
|
const char *end = strchr(PATH, ':');
|
|
if(!end)
|
|
{
|
|
end = strchr(PATH, '\0');
|
|
endFound = true;
|
|
}
|
|
std::string pathElement(PATH, end);
|
|
|
|
if(pathElement == "")
|
|
pathElement = ".";
|
|
|
|
fs::path f = fs::path(pathElement) / program;
|
|
|
|
if(access(f.string().c_str(), X_OK) == 0)
|
|
return true;
|
|
|
|
PATH = end + 1;
|
|
} while(!endFound);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
vector<string> SplitArguments(std::string str)
|
|
{
|
|
bool backslash = false;
|
|
bool quote = false;
|
|
bool begun = false;
|
|
vector<string> args;
|
|
|
|
for(char c : str)
|
|
{
|
|
if(!backslash && !quote && isspace(c))
|
|
{
|
|
begun = false;
|
|
}
|
|
else if(!backslash && c == '"')
|
|
{
|
|
quote = !quote;
|
|
if(quote && !begun)
|
|
{
|
|
args.emplace_back();
|
|
begun = true;
|
|
}
|
|
}
|
|
else if(!backslash && c == '\\')
|
|
{
|
|
backslash = true;
|
|
}
|
|
else
|
|
{
|
|
backslash = false;
|
|
|
|
if(!begun)
|
|
{
|
|
args.emplace_back();
|
|
begun = true;
|
|
}
|
|
args.back() += c;
|
|
}
|
|
}
|
|
|
|
return args;
|
|
}
|
|
|
|
vector<string> SplitArguments(vector<string> strs)
|
|
{
|
|
vector<string> args;
|
|
for(string str : strs)
|
|
{
|
|
vector<string> args1 = SplitArguments(str);
|
|
args.insert(args.end(), args1.begin(), args1.end());
|
|
}
|
|
return args;
|
|
}
|