BROKEN
Some checks failed
Dropshell Test / Build_and_Test (push) Failing after 21s

This commit is contained in:
Your Name
2025-05-06 21:32:41 +12:00
parent 484613d10d
commit bbc280a50a
9 changed files with 335 additions and 245 deletions

167
src/utils/execute.cpp Normal file
View File

@ -0,0 +1,167 @@
#include "execute.hpp"
#include "assert.hpp"
#include "contrib/base64.hpp"
#include "utils/utils.hpp"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <vector>
#include <iostream>
#include <string>
#include <cstdlib>
#include <sstream>
bool EXITSTATUSCHECK(int ret) {
return (ret != -1 && WIFEXITED(ret) && (WEXITSTATUS(ret) == 0)); // ret is -1 if the command failed to execute.
}
namespace dropshell {
bool execute_local_command_interactive(const sCommand &command, bool silent)
{
if (command.get_command_to_run().empty())
return false;
std::string full_command = command.construct_cmd(cStyle::Raw); // Get the command string
pid_t pid = fork();
if (pid == -1) {
// Fork failed
perror("fork failed");
return false;
} else if (pid == 0) {
// Child process
std::vector<const char *> commandvec = {"bash", "-c", full_command.c_str(),NULL};
if (!silent) {
std::cout << "Executing command: ";
for (auto & x : commandvec) std::cout << x << " ";
std::cout << std::endl;
}
execvp(commandvec[0], const_cast<char* const*>(commandvec.data()));
// If execvp returns, it means an error occurred
perror("execvp failed");
exit(EXIT_FAILURE); // Exit child process on error
} else {
// Parent process
int ret;
// Wait for the child process to complete
waitpid(pid, &ret, 0);
return EXITSTATUSCHECK(ret);
}
}
bool execute_local_command(const sCommand& command, bool silent, bool safe) {
if (command.get_command_to_run().empty())
return false;
cStyle style = safe ? cStyle::Safe : cStyle::Raw;
std::string full_cmd = command.construct_cmd(style) + " 2>&1" + (silent ? " > /dev/null" : "");
int ret = system(full_cmd.c_str());
return EXITSTATUSCHECK(ret);
}
bool execute_local_command_and_capture_output(const sCommand& command, std::string &output, bool silent, bool safe)
{
if (command.get_command_to_run().empty())
return false;
cStyle style = safe ? cStyle::Safe : cStyle::Raw;
std::string full_cmd = command.construct_cmd(style) + " 2>&1";
FILE *pipe = popen(full_cmd.c_str(), "r");
if (!pipe) {
return false;
}
char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
output += buffer;
}
int ret = pclose(pipe);
return EXITSTATUSCHECK(ret);
}
bool execute_local_command(const sCommand & command, cMode mode, std::string * output /* = nullptr */)
{
if (mode & cMode::Interactive) {
ASSERT_MSG((mode & cMode::CaptureOutput), "Interactive mode and capture output mode cannot be used together");
ASSERT_MSG(output == nullptr, "Interactive mode and an output string cannot be used together");
ASSERT_MSG(! (mode & cMode::SafeCommand), "Interactive mode and safe command mode cannot be used together");
return execute_local_command_interactive(command, mode & cMode::Silent);
}
if (mode & cMode::CaptureOutput) {
ASSERT_MSG(output != nullptr, "Capture output mode requires an output string to be provided");
return execute_local_command_and_capture_output(command, *output, mode & cMode::Silent, mode & cMode::SafeCommand);
}
return execute_local_command(command, mode & cMode::Silent, mode & cMode::SafeCommand);
}
bool execute_ssh_command(const sSSHInfo &ssh_info, const sCommand &command, cMode mode, std::string *output)
{
if (command.get_command_to_run().empty())
return false;
ASSERT_MSG(!(mode & cMode::Interactive && mode & cMode::SafeCommand), "Safe command mode must not be used with Interactive mode");
std::stringstream ssh_cmd;
ssh_cmd << "ssh -p " << ssh_info.port << " " << (mode & cMode::Interactive ? "-tt " : "")
<< ssh_info.user << "@" << ssh_info.host;
std::string full_cmd = ssh_cmd.str() + " " + command.get_command_to_run();
sCommand ssh_command = {
command.get_directory_to_run_in(),
full_cmd,
command.get_env_vars()
};
bool rval = execute_local_command(ssh_command, mode, output);
if (!rval) {
std::cerr <<std::endl<<std::endl;
std::cerr << "Error: Failed to execute ssh command: { [" << ssh_command.get_directory_to_run_in() << "], [";
std::cerr << ssh_command.get_command_to_run() << "], [";
for (const auto& env_var : ssh_command.get_env_vars()) {
std::cerr << env_var.first << "=" << env_var.second << ", ";
}
std::cerr << "] }" << std::endl;
std::cerr <<std::endl<<std::endl;
}
return rval;
}
std::string makesafecmd(const std::string &command)
{
if (command.empty())
return "";
std::string encoded = base64_encode(dequote(trim(command)));
std::string commandstr = "echo " + encoded + " | base64 -d | bash";
return commandstr;
}
std::string sCommand::construct_cmd(cStyle style) const
{
if (mCmd.empty())
return "";
std::string cdcmd;
if (!mDir.empty())
cdcmd = "cd " + quote(mDir) + " && ";
std::string cmdstr;
for (const auto& env_var : mVars) {
cmdstr += env_var.first + "=" + quote(dequote(trim(env_var.second))) + " ";
}
cmdstr += mCmd;
if (is_safe(style))
cmdstr = makesafecmd(cmdstr);
return cdcmd + cmdstr;
}
} // namespace dropshell