mirror of
https://github.com/autc04/Retro68.git
synced 2024-12-27 07:31:35 +00:00
LaunchAPPL: add new method 'SSH' and move utility functions to separate module
This commit is contained in:
parent
1657cf599c
commit
ed80c2c09f
@ -3,6 +3,7 @@ find_package(Boost COMPONENTS filesystem program_options)
|
||||
set(LAUNCHMETHODS
|
||||
Executor.h Executor.cc
|
||||
MiniVMac.h MiniVMac.cc
|
||||
SSH.h SSH.cc
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
@ -21,6 +22,8 @@ add_executable(LaunchAPPL
|
||||
LaunchMethod.h LaunchMethod.cc
|
||||
Launcher.h Launcher.cc
|
||||
|
||||
Utilities.h Utilities.cc
|
||||
|
||||
${LAUNCHMETHODS})
|
||||
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "Carbon.h"
|
||||
#include "Launcher.h"
|
||||
#include "Utilities.h"
|
||||
|
||||
const std::string launchCFM =
|
||||
"/System/Library/Frameworks/Carbon.framework/Versions/A/Support/LaunchCFMApp";
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "Executor.h"
|
||||
#include "Launcher.h"
|
||||
#include "Utilities.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#endif
|
||||
#include "Executor.h"
|
||||
#include "MiniVMac.h"
|
||||
#include "SSH.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace fs = boost::filesystem;
|
||||
@ -40,7 +41,8 @@ static void RegisterLaunchMethods()
|
||||
# endif
|
||||
new Carbon(),
|
||||
#endif
|
||||
new Executor(), new MiniVMac()
|
||||
new Executor(), new MiniVMac(),
|
||||
new SSH()
|
||||
// #### Add new `LaunchMethod`s here.
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,4 @@
|
||||
#include "LaunchMethod.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
LaunchMethod::LaunchMethod()
|
||||
{
|
||||
@ -27,39 +23,3 @@ bool LaunchMethod::CheckOptions(boost::program_options::variables_map &options)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LaunchMethod::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;
|
||||
}
|
||||
|
@ -66,13 +66,6 @@ public:
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief CheckExecutable
|
||||
* @param program
|
||||
* @return true if "program" exists in the $PATH and is executable.
|
||||
*/
|
||||
bool CheckExecutable(std::string program);
|
||||
};
|
||||
|
||||
#endif // LAUNCHMETHOD_H
|
||||
|
@ -2,10 +2,6 @@
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
@ -60,91 +56,3 @@ Launcher::~Launcher()
|
||||
|
||||
|
||||
|
||||
int Launcher::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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ protected:
|
||||
ResourceFile app;
|
||||
boost::filesystem::path tempDir, appPath, outPath;
|
||||
bool keepTempFiles;
|
||||
|
||||
int ChildProcess(std::string program, std::vector<std::string> args, int timeout);
|
||||
public:
|
||||
/**
|
||||
* @brief Launcher
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "MiniVMac.h"
|
||||
#include "Launcher.h"
|
||||
#include "Utilities.h"
|
||||
|
||||
extern "C" {
|
||||
#include "hfs.h"
|
||||
|
150
LaunchAPPL/SSH.cc
Normal file
150
LaunchAPPL/SSH.cc
Normal file
@ -0,0 +1,150 @@
|
||||
#include "SSH.h"
|
||||
#include "Launcher.h"
|
||||
#include "Utilities.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace po = boost::program_options;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
class SSHLauncher : public Launcher
|
||||
{
|
||||
public:
|
||||
SSHLauncher(po::variables_map& options);
|
||||
virtual ~SSHLauncher();
|
||||
|
||||
virtual bool Go(int timeout = 0);
|
||||
|
||||
};
|
||||
|
||||
SSHLauncher::SSHLauncher(po::variables_map &options)
|
||||
: Launcher(options, ResourceFile::Format::percent_appledouble)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SSHLauncher::~SSHLauncher()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void insertArgs(vector<string>& args, po::variables_map& options, string name)
|
||||
{
|
||||
if(options.count(name))
|
||||
{
|
||||
auto extraArgs = SplitArguments(options[name].as<vector<string>>());
|
||||
args.insert(args.end(), extraArgs.begin(), extraArgs.end());
|
||||
}
|
||||
}
|
||||
|
||||
bool SSHLauncher::Go(int timeout)
|
||||
{
|
||||
std::vector<std::string> args;
|
||||
args.push_back(options["ssh-host"].as<string>());
|
||||
insertArgs(args, options, "ssh-args");
|
||||
args.push_back("--");
|
||||
args.push_back(options["ssh-remote-path"].as<string>());
|
||||
insertArgs(args, options, "ssh-remote-args");
|
||||
if(timeout)
|
||||
{
|
||||
args.push_back("--timeout");
|
||||
args.push_back(boost::lexical_cast<std::string>(timeout));
|
||||
}
|
||||
args.push_back("-");
|
||||
|
||||
std::string program = options["ssh-path"].as<std::string>();
|
||||
|
||||
std::vector<const char*> argv;
|
||||
argv.push_back(program.c_str());
|
||||
for(std::string& s : args)
|
||||
argv.push_back(s.c_str());
|
||||
argv.push_back(NULL);
|
||||
|
||||
int fd[2];
|
||||
pipe(fd);
|
||||
const int READ_END = 0;
|
||||
const int WRITE_END = 1;
|
||||
|
||||
pid_t pid = fork();
|
||||
if(pid < 0)
|
||||
{
|
||||
perror("unable to fork");
|
||||
return 1;
|
||||
}
|
||||
else if(pid == 0)
|
||||
{
|
||||
dup2(fd[READ_END], STDIN_FILENO);
|
||||
close(fd[WRITE_END]);
|
||||
close(fd[READ_END]);
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
close(fd[READ_END]);
|
||||
|
||||
std::ostringstream tmp;
|
||||
app.write(tmp, ResourceFile::Format::macbin);
|
||||
const std::string data = tmp.str();
|
||||
|
||||
write(fd[WRITE_END], data.data(), data.size());
|
||||
close(fd[WRITE_END]);
|
||||
|
||||
int wstatus;
|
||||
int result = 0;
|
||||
do
|
||||
{
|
||||
result = waitpid(pid, &wstatus, 0);
|
||||
} while(result == -1 && errno == EINTR);
|
||||
|
||||
if(!WIFEXITED(wstatus))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//int exitcode = WEXITSTATUS(wstatus);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SSH::GetOptions(options_description &desc)
|
||||
{
|
||||
desc.add_options()
|
||||
("ssh-path", po::value<string>()->default_value("ssh"),"ssh command to use")
|
||||
("ssh-host", po::value<string>(),
|
||||
"[username@]address of remote host")
|
||||
("ssh-args", po::value<vector<string>>(),
|
||||
"additional arguments for ssh")
|
||||
("ssh-remote-path", po::value<string>()->default_value("LaunchAPPL"),
|
||||
"path to LaunchAPPL on remote host")
|
||||
("ssh-remote-args", po::value<vector<string>>(),
|
||||
"additional arguments for LaunchAPPL on remote host")
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
bool SSH::CheckOptions(variables_map &options)
|
||||
{
|
||||
return options.count("ssh-host") != 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> SSH::MakeLauncher(variables_map &options)
|
||||
{
|
||||
return std::unique_ptr<Launcher>(new SSHLauncher(options));
|
||||
}
|
16
LaunchAPPL/SSH.h
Normal file
16
LaunchAPPL/SSH.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef SSH_H
|
||||
#define SSH_H
|
||||
|
||||
#include "LaunchMethod.h"
|
||||
|
||||
class SSH : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "ssh"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
#endif // SSH_H
|
192
LaunchAPPL/Utilities.cc
Normal file
192
LaunchAPPL/Utilities.cc
Normal file
@ -0,0 +1,192 @@
|
||||
#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;
|
||||
}
|
21
LaunchAPPL/Utilities.h
Normal file
21
LaunchAPPL/Utilities.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef UTILITIES_H
|
||||
#define UTILITIES_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int ChildProcess(std::string program, std::vector<std::string> args, int timeout);
|
||||
|
||||
|
||||
/**
|
||||
* @brief CheckExecutable
|
||||
* @param program
|
||||
* @return true if "program" exists in the $PATH and is executable.
|
||||
*/
|
||||
bool CheckExecutable(std::string program);
|
||||
|
||||
|
||||
std::vector<std::string> SplitArguments(std::string str);
|
||||
std::vector<std::string> SplitArguments(std::vector<std::string> strs);
|
||||
|
||||
#endif // UTILITIES_H
|
Loading…
Reference in New Issue
Block a user