[Process] Process Execution Refactor (#2632)

* Swap execute output method

* Create "Process" class and move random string to Strings

* test

* Tweaks
This commit is contained in:
Chris Miles 2022-12-11 13:08:55 -06:00 committed by GitHub
parent 70719852d6
commit f5126222c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 73 additions and 83 deletions

View File

@ -64,6 +64,7 @@ SET(common_sources
path_manager.cpp path_manager.cpp
perl_eqdb.cpp perl_eqdb.cpp
perl_eqdb_res.cpp perl_eqdb_res.cpp
process/process.cpp
proc_launcher.cpp proc_launcher.cpp
profanity_manager.cpp profanity_manager.cpp
ptimer.cpp ptimer.cpp
@ -568,6 +569,7 @@ SET(common_headers
packet_functions.h packet_functions.h
path_manager.cpp path_manager.cpp
platform.h platform.h
process/process.h
proc_launcher.h proc_launcher.h
profanity_manager.h profanity_manager.h
profiler.h profiler.h

View File

@ -1,48 +1,15 @@
#include "global_define.h" #include "global_define.h"
#include "eqemu_logsys.h" #include "eqemu_logsys.h"
#include "crash.h" #include "crash.h"
#include "strings.h"
#include "process/process.h"
inline std::string random_string(size_t length) #include <cstdio>
{
auto randchar = []() -> char {
const char charset[] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
return charset[static_cast<size_t>(std::rand()) % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
}
std::string execute(const std::string &cmd, bool return_result = true) #if WINDOWS
{ #define popen _popen
std::string random = "/tmp/" + random_string(25);
const char *file_name = random.c_str();
if (return_result) {
#ifdef _WINDOWS
std::system((cmd + " > " + file_name + " 2>&1").c_str());
#else
std::system((cmd + " > " + file_name + " 2>&1").c_str());
#endif #endif
}
else {
std::system((cmd).c_str());
}
std::string result;
if (return_result) {
std::ifstream file(file_name);
result = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
std::remove(file_name);
}
return result;
}
#if defined(_WINDOWS) && defined(CRASH_LOGGING) #if defined(_WINDOWS) && defined(CRASH_LOGGING)
#include "StackWalker.h" #include "StackWalker.h"
@ -167,7 +134,7 @@ void set_exception_handler() {
void print_trace() void print_trace()
{ {
bool does_gdb_exist = execute("gdb -v").find("GNU") != std::string::npos; bool does_gdb_exist = Strings::Contains(Process::execute("gdb -v"), "GNU");
if (!does_gdb_exist) { if (!does_gdb_exist) {
LogCrash( LogCrash(
"[Error] GDB is not installed, if you want crash dumps on Linux to work properly you will need GDB installed" "[Error] GDB is not installed, if you want crash dumps on Linux to work properly you will need GDB installed"
@ -176,12 +143,12 @@ void print_trace()
} }
auto uid = geteuid(); auto uid = geteuid();
std::string temp_output_file = "/tmp/dump-output"; std::string temp_output_file = fmt::format("/tmp/dump-output-{}", Strings::Random(10));
// check for passwordless sudo if not root // check for passwordless sudo if not root
if (uid != 0) { if (uid != 0) {
bool has_passwordless_sudo = execute("sudo -n true").find("a password is required") == std::string::npos; bool sudo_password_required = Strings::Contains(Process::execute("sudo -n true"), "a password is required");
if (!has_passwordless_sudo) { if (sudo_password_required) {
LogCrash( LogCrash(
"[Error] Current user does not have passwordless sudo installed. It is required to automatically process crash dumps with GDB as non-root." "[Error] Current user does not have passwordless sudo installed. It is required to automatically process crash dumps with GDB as non-root."
); );
@ -210,7 +177,7 @@ void print_trace()
abort(); /* If gdb failed to start */ abort(); /* If gdb failed to start */
} }
else { else {
waitpid(child_pid, NULL, 0); waitpid(child_pid, nullptr, 0);
} }
std::ifstream input(temp_output_file); std::ifstream input(temp_output_file);

View File

@ -27,6 +27,7 @@
#include "../eqemu_config.h" #include "../eqemu_config.h"
#include "../database_schema.h" #include "../database_schema.h"
#include "../file.h" #include "../file.h"
#include "../process/process.h"
#include <ctime> #include <ctime>
@ -40,38 +41,6 @@
#define DATABASE_DUMP_PATH "backups/" #define DATABASE_DUMP_PATH "backups/"
/**
* @param cmd
* @param return_result
* @return
*/
std::string DatabaseDumpService::execute(const std::string &cmd, bool return_result = true)
{
const char *file_name = "db-exec-result.txt";
if (return_result) {
#ifdef _WINDOWS
std::system((cmd + " > " + file_name + " 2>&1").c_str());
#else
std::system((cmd + " > " + file_name).c_str());
#endif
}
else {
std::system((cmd).c_str());
}
std::string result;
if (return_result) {
std::ifstream file(file_name);
result = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
std::remove(file_name);
}
return result;
}
/** /**
* @return bool * @return bool
*/ */
@ -88,7 +57,7 @@ bool DatabaseDumpService::IsMySQLInstalled()
*/ */
bool DatabaseDumpService::IsTarAvailable() bool DatabaseDumpService::IsTarAvailable()
{ {
std::string version_output = execute("tar --version"); std::string version_output = Process::execute("tar --version");
return version_output.find("GNU tar") != std::string::npos; return version_output.find("GNU tar") != std::string::npos;
} }
@ -99,7 +68,7 @@ bool DatabaseDumpService::IsTarAvailable()
*/ */
bool DatabaseDumpService::Is7ZipAvailable() bool DatabaseDumpService::Is7ZipAvailable()
{ {
std::string version_output = execute("7z --help"); std::string version_output = Process::execute("7z --help");
return version_output.find("7-Zip") != std::string::npos; return version_output.find("7-Zip") != std::string::npos;
} }
@ -117,7 +86,7 @@ bool DatabaseDumpService::HasCompressionBinary()
*/ */
std::string DatabaseDumpService::GetMySQLVersion() std::string DatabaseDumpService::GetMySQLVersion()
{ {
std::string version_output = execute("mysql --version"); std::string version_output = Process::execute("mysql --version");
return Strings::Trim(version_output); return Strings::Trim(version_output);
} }
@ -399,8 +368,8 @@ void DatabaseDumpService::Dump()
} }
} }
else { else {
std::string execution_result = execute(execute_command, IsDumpOutputToConsole()); std::string execution_result = Process::execute(execute_command);
if (!execution_result.empty()) { if (!execution_result.empty() && IsDumpOutputToConsole()) {
std::cout << execution_result; std::cout << execution_result;
} }
} }
@ -416,7 +385,7 @@ void DatabaseDumpService::Dump()
LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath()); LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath());
if (IsTarAvailable()) { if (IsTarAvailable()) {
execute( Process::execute(
fmt::format( fmt::format(
"tar -zcvf {}.tar.gz -C {} {}.sql", "tar -zcvf {}.tar.gz -C {} {}.sql",
GetDumpFileNameWithPath(), GetDumpFileNameWithPath(),
@ -427,7 +396,7 @@ void DatabaseDumpService::Dump()
LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath()); LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath());
} }
else if (Is7ZipAvailable()) { else if (Is7ZipAvailable()) {
execute( Process::execute(
fmt::format( fmt::format(
"7z a -t7z {}.zip {}.sql", "7z a -t7z {}.zip {}.sql",
GetDumpFileNameWithPath(), GetDumpFileNameWithPath(),

View File

@ -73,7 +73,6 @@ private:
std::string dump_path; std::string dump_path;
std::string dump_file_name; std::string dump_file_name;
std::string execute(const std::string &cmd, bool return_result);
bool IsMySQLInstalled(); bool IsMySQLInstalled();
std::string GetMySQLVersion(); std::string GetMySQLVersion();
std::string GetBaseMySQLDumpCommand(); std::string GetBaseMySQLDumpCommand();

View File

@ -0,0 +1,18 @@
#include <string>
#include <memory>
#include "process.h"
std::string Process::execute(const std::string &cmd)
{
std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
if (!pipe) { return "ERROR"; }
char buffer[128];
std::string result;
while (!feof(pipe.get())) {
if (fgets(buffer, 128, pipe.get()) != nullptr) {
result += buffer;
}
}
return result;
}

19
common/process/process.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef EQEMU_PROCESS_H
#define EQEMU_PROCESS_H
#include "../strings.h"
#include <cstdio>
#if _WIN32
#define popen _popen
#define pclose _pclose
#endif
class Process {
public:
static std::string execute(const std::string &cmd);
};
#endif //EQEMU_PROCESS_H

View File

@ -738,3 +738,18 @@ bool Strings::ToBool(std::string bool_string)
return false; return false;
} }
// returns a random string of specified length
std::string Strings::Random(size_t length)
{
auto randchar = []() -> char {
const char charset[] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
return charset[static_cast<size_t>(std::rand()) % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
}

View File

@ -112,6 +112,7 @@ public:
static uint32 TimeToSeconds(std::string time_string); static uint32 TimeToSeconds(std::string time_string);
static bool ToBool(std::string bool_string); static bool ToBool(std::string bool_string);
static inline bool EqualFold(const std::string &string_one, const std::string &string_two) { return strcasecmp(string_one.c_str(), string_two.c_str()) == 0; } static inline bool EqualFold(const std::string &string_one, const std::string &string_two) { return strcasecmp(string_one.c_str(), string_two.c_str()) == 0; }
static std::string Random(size_t length);
template<typename T> template<typename T>
static std::string static std::string