You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MangoHud/src/shell.cpp

98 lines
2.6 KiB
C++

#include "shell.h"
#include <thread>
#include <iostream>
#include <sys/wait.h>
#include <spdlog/spdlog.h>
std::string Shell::readOutput() {
std::string output;
char buffer[256];
ssize_t bytesRead;
bool dataAvailable = false;
// Wait for up to 500 milliseconds for output to become available
for (int i = 0; i < 10; ++i) {
bytesRead = read(from_shell[0], buffer, sizeof(buffer) - 1);
if (bytesRead > 0) {
buffer[bytesRead] = '\0';
output += buffer;
dataAvailable = true;
break; // Break as soon as we get some data
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
// If we detected data, keep reading until no more is available
while (dataAvailable) {
bytesRead = read(from_shell[0], buffer, sizeof(buffer) - 1);
if (bytesRead > 0) {
buffer[bytesRead] = '\0';
output += buffer;
} else {
break; // No more data available
}
}
return output;
}
Shell::Shell() {
static bool failed;
if (pipe(to_shell) == -1) {
SPDLOG_ERROR("Failed to create to_shell pipe: {}", strerror(errno));
failed = true;
}
if (pipe(from_shell) == -1) {
SPDLOG_ERROR("Failed to create from_shell pipe: {}", strerror(errno));
failed = true;
}
// if either pipe fails, there's no point in continuing.
if (failed){
SPDLOG_ERROR("Shell has failed, will not be able to use exec");
return;
}
shell_pid = fork();
if (shell_pid == 0) { // Child process
close(to_shell[1]);
close(from_shell[0]);
dup2(to_shell[0], STDIN_FILENO);
dup2(from_shell[1], STDOUT_FILENO);
dup2(from_shell[1], STDERR_FILENO);
execl("/bin/sh", "sh", nullptr);
exit(1); // Exit if execl fails
} else {
close(to_shell[0]);
close(from_shell[1]);
// Set the read end of the from_shell pipe to non-blocking
setNonBlocking(from_shell[0]);
}
success = true;
}
std::string Shell::exec(std::string cmd) {
if (!success)
return "";
writeCommand(cmd);
return readOutput();
}
void Shell::writeCommand(const std::string& command) {
if (write(to_shell[1], command.c_str(), command.length()) == -1)
SPDLOG_ERROR("Failed to write to shell");
}
Shell::~Shell() {
if (write(to_shell[1], "exit\n", 5) == -1)
SPDLOG_ERROR("Failed exit shell");
close(to_shell[1]);
close(from_shell[0]);
waitpid(shell_pid, nullptr, 0);
}