rewire/cli/main.cpp

225 lines
6.4 KiB
C++

#include <iostream>
#include <filesystem>
#include <vector>
#include <sstream>
#include "cli.hpp"
#include "dl.hpp"
#include "install.hpp"
#include "interface.hpp"
int launch_help(int argc, char** argv) {
std::cout << "Use rewire via one of the following commands:" << std::endl;
std::cout << " \"rewire help\" -> You appear to already know what it does ;)" << std::endl;
std::cout << " \"rewire install <wirekit.so> <name>\" -> Installs a wirekit to execute programs with" << std::endl;
std::cout << " <wirekit.so> -> The shared object to be installed as wirekit" << std::endl;
std::cout << " <name> -> (Optional) The name via which the wirekit is supposed to be used" << std::endl;
std::cout << " -> Defaults to \"wirekit\" when installing \"wirekit.so\"" << std::endl;
std::cout << " \"rewire uninstall <name>\" -> Removes a wirekit from the system" << std::endl;
std::cout << " <name> -> The name of the wirekit to be uninstalled" << std::endl;
std::cout << " \"rewire list\" -> Lists all installed wirekits" << std::endl;
std::cout << " \"rewire <wirekit> <command+args>\"" << std::endl;
std::cout << " <wirekit> -> The wirekit to use for execution" << std::endl;
std::cout << " -> Can either be installed or in current working directory" << std::endl;
std::cout << " <command+args> -> (Optional) A command to be executed" << std::endl;
std::cout << " -> Acts as rewired shell if no command is given" << std::endl;
return 0;
}
int launch_install(int argc, char** argv) {
if (argc < 3 || argc > 4) {
std::cout << "Invalid usage, try \"rewire help\" for more information!" << std::endl;
return 1;
}
InstallManager im;
if (!im) {
std::cout << "Unable to manage installations!" << std::endl;
return 1;
}
auto kitcheck = [](const std::filesystem::path& kit) -> bool {
DL tmp_dl { kit };
if (!tmp_dl) {
std::cout << "Failed to check wirekit requirements for installation!" << std::endl;
return false;
}
if (!tmp_dl.resolve("wirekit_prepare")) {
std::cout << "Wirekit must implement \"wirekit_prepare\" to be installed!" << std::endl;
return false;
}
if (!tmp_dl.resolve("wirekit_command_start")) {
std::cout << "Wirekit must implement \"wirekit_command_start\" to be installed!" << std::endl;
return false;
}
return true;
};
if (!im.install(argv[2], (argc == 4 ? argv[3] : nullptr), kitcheck)) {
std::cout << "Failed to install wirekit!" << std::endl;
return 1;
}
std::cout << "Successfully installed wirekit!" << std::endl;
return 0;
}
int launch_uninstall(int argc, char** argv) {
if (argc != 3) {
std::cout << "Invalid usage, try \"rewire help\" for more information!" << std::endl;
return 1;
}
InstallManager im;
if (!im) {
std::cout << "Unable to manage installations!" << std::endl;
return 1;
}
if (!im.uninstall(argv[2])) {
std::cout << "Failed to uninstall wirekit!" << std::endl;
return 1;
}
std::cout << "Successfully uninstalled wirekit!" << std::endl;
return 0;
}
int launch_list(int argc, char** argv) {
if (argc != 2) {
std::cout << "Invalid usage, try \"rewire help\" for more information!" << std::endl;
return 1;
}
InstallManager im;
if (!im) {
std::cout << "Unable to access installations!" << std::endl;
return 1;
}
auto wirekits = im.installs();
if (wirekits.empty()) {
std::cout << "Currently, no wirekits are installed!" << std::endl;
} else {
std::cout << "Currently, the following wirekits are installed:" << std::endl;
for (const std::string& kit : wirekits)
std::cout << " \"" << kit << "\"" << std::endl;
}
return 0;
}
int launch_run(int argc, char** argv) {
if (argc < 2) {
std::cout << "Invalid usage, try \"rewire help\" for more information!" << std::endl;
return 1;
}
InstallManager im;
if (!im) {
std::cout << "Unable to access installations!" << std::endl;
return 1;
}
std::filesystem::path wirekit_path;
if (!im.get(argv[1], wirekit_path)) {
std::cout << "No wirekit named \"" << argv[1] << "\" is installed!" << std::endl;
return 1;
}
DL wirekit { wirekit_path };
if (!wirekit) {
std::cout << "Unable to load wirekit!" << std::endl;
return 1;
}
// Collect wirekit control function handles
KitInterface ki;
ki.prepare = (err_t(*)())wirekit.resolve("wirekit_prepare");
ki.command_start = (err_t(*)(int, const char* const*))wirekit.resolve("wirekit_command_start");
ki.command_exit = (void(*)())wirekit.resolve("wirekit_command_exit");
ki.subject_start = (void(*)())wirekit.resolve("wirekit_subject_start");
ki.subject_exit = (void(*)())wirekit.resolve("wirekit_subject_exit");
// Initialize rewire (internally prepares wirekit)
if (!rewire_init(ki)) {
std::cout << "Rewire and wirekit preparation failed!" << std::endl;
return 1;
}
// Execute commands in rewired syscall environment
if (argc > 2) {
rewire_run(argc - 2, (const char**)(argv + 2));
} else {
// Shell mode
while (true) {
std::cout << "> ";
std::string command;
std::getline(std::cin, command);
// Split command at whitespaces
std::stringstream command_stream { command };
std::vector<std::string> command_split; // No need to reserve, presumably not many elements
std::string part;
while (command_stream >> std::quoted(part))
command_split.emplace_back(std::move(part));
if (command_split.empty())
continue;
if (command_split[0] == "exit")
break;
// Compile argv (cstr pointer array)
std::vector<const char*> command_split_cstr;
command_split_cstr.resize(command_split.size() + 1, nullptr); // +1 for nullptr termination
for (std::size_t i = 0; i < command_split.size(); i++)
command_split_cstr[i] = command_split[i].c_str();
// Execute command
rewire_run((int)command_split_cstr.size() - 1, command_split_cstr.data());
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc < 2) {
std::cout << "Invalid usage, try \"rewire help\"!" << std::endl;
return 1;
}
LAUNCH_MODE lm = launch_mode(argv[1]);
switch (lm) {
case LAUNCH_MODE::HELP:
return launch_help(argc, argv);
case LAUNCH_MODE::INSTALL:
return launch_install(argc, argv);
case LAUNCH_MODE::UNINSTALL:
return launch_uninstall(argc, argv);
case LAUNCH_MODE::LIST:
return launch_list(argc, argv);
case LAUNCH_MODE::RUN:
return launch_run(argc, argv);
default:
std::cout << "Invalid launch mode!" << std::endl;
return 1;
}
return 0;
}