diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index cd88a466d..44b7d0125 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -64,6 +64,7 @@ SET(common_sources path_manager.cpp perl_eqdb.cpp perl_eqdb_res.cpp + process/process.cpp proc_launcher.cpp profanity_manager.cpp ptimer.cpp @@ -568,6 +569,7 @@ SET(common_headers packet_functions.h path_manager.cpp platform.h + process/process.h proc_launcher.h profanity_manager.h profiler.h diff --git a/common/crash.cpp b/common/crash.cpp index 3b0856b80..8fc7323e8 100644 --- a/common/crash.cpp +++ b/common/crash.cpp @@ -1,48 +1,15 @@ #include "global_define.h" #include "eqemu_logsys.h" #include "crash.h" +#include "strings.h" +#include "process/process.h" -inline std::string random_string(size_t length) -{ - auto randchar = []() -> char { - const char charset[] = "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - const size_t max_index = (sizeof(charset) - 1); - return charset[static_cast(std::rand()) % max_index]; - }; - std::string str(length, 0); - std::generate_n(str.begin(), length, randchar); - return str; -} +#include -std::string execute(const std::string &cmd, bool return_result = true) -{ - 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()); +#if WINDOWS +#define popen _popen #endif - } - else { - std::system((cmd).c_str()); - } - std::string result; - - if (return_result) { - std::ifstream file(file_name); - result = {std::istreambuf_iterator(file), std::istreambuf_iterator()}; - std::remove(file_name); - - } - - return result; -} #if defined(_WINDOWS) && defined(CRASH_LOGGING) #include "StackWalker.h" @@ -167,7 +134,7 @@ void set_exception_handler() { 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) { LogCrash( "[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(); - 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 if (uid != 0) { - bool has_passwordless_sudo = execute("sudo -n true").find("a password is required") == std::string::npos; - if (!has_passwordless_sudo) { + bool sudo_password_required = Strings::Contains(Process::execute("sudo -n true"), "a password is required"); + if (sudo_password_required) { LogCrash( "[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 */ } else { - waitpid(child_pid, NULL, 0); + waitpid(child_pid, nullptr, 0); } std::ifstream input(temp_output_file); diff --git a/common/database/database_dump_service.cpp b/common/database/database_dump_service.cpp index b0385664b..eb7d15803 100644 --- a/common/database/database_dump_service.cpp +++ b/common/database/database_dump_service.cpp @@ -27,6 +27,7 @@ #include "../eqemu_config.h" #include "../database_schema.h" #include "../file.h" +#include "../process/process.h" #include @@ -40,38 +41,6 @@ #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(file), std::istreambuf_iterator()}; - std::remove(file_name); - - } - - return result; -} - /** * @return bool */ @@ -88,7 +57,7 @@ bool DatabaseDumpService::IsMySQLInstalled() */ 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; } @@ -99,7 +68,7 @@ bool DatabaseDumpService::IsTarAvailable() */ 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; } @@ -117,7 +86,7 @@ bool DatabaseDumpService::HasCompressionBinary() */ std::string DatabaseDumpService::GetMySQLVersion() { - std::string version_output = execute("mysql --version"); + std::string version_output = Process::execute("mysql --version"); return Strings::Trim(version_output); } @@ -399,8 +368,8 @@ void DatabaseDumpService::Dump() } } else { - std::string execution_result = execute(execute_command, IsDumpOutputToConsole()); - if (!execution_result.empty()) { + std::string execution_result = Process::execute(execute_command); + if (!execution_result.empty() && IsDumpOutputToConsole()) { std::cout << execution_result; } } @@ -416,7 +385,7 @@ void DatabaseDumpService::Dump() LogInfo("Compression requested... Compressing dump [{}.sql]", GetDumpFileNameWithPath()); if (IsTarAvailable()) { - execute( + Process::execute( fmt::format( "tar -zcvf {}.tar.gz -C {} {}.sql", GetDumpFileNameWithPath(), @@ -427,7 +396,7 @@ void DatabaseDumpService::Dump() LogInfo("Compressed dump created at [{}.tar.gz]", GetDumpFileNameWithPath()); } else if (Is7ZipAvailable()) { - execute( + Process::execute( fmt::format( "7z a -t7z {}.zip {}.sql", GetDumpFileNameWithPath(), diff --git a/common/database/database_dump_service.h b/common/database/database_dump_service.h index c14627441..dcb0646d8 100644 --- a/common/database/database_dump_service.h +++ b/common/database/database_dump_service.h @@ -73,7 +73,6 @@ private: std::string dump_path; std::string dump_file_name; - std::string execute(const std::string &cmd, bool return_result); bool IsMySQLInstalled(); std::string GetMySQLVersion(); std::string GetBaseMySQLDumpCommand(); diff --git a/common/process/process.cpp b/common/process/process.cpp new file mode 100644 index 000000000..926c9700b --- /dev/null +++ b/common/process/process.cpp @@ -0,0 +1,18 @@ +#include +#include +#include "process.h" + +std::string Process::execute(const std::string &cmd) +{ + std::shared_ptr 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; +} diff --git a/common/process/process.h b/common/process/process.h new file mode 100644 index 000000000..34dbb27c6 --- /dev/null +++ b/common/process/process.h @@ -0,0 +1,19 @@ +#ifndef EQEMU_PROCESS_H +#define EQEMU_PROCESS_H + +#include "../strings.h" + +#include + +#if _WIN32 +#define popen _popen +#define pclose _pclose +#endif + +class Process { +public: + static std::string execute(const std::string &cmd); +}; + + +#endif //EQEMU_PROCESS_H diff --git a/common/strings.cpp b/common/strings.cpp index deca2ca9f..dc31cf848 100644 --- a/common/strings.cpp +++ b/common/strings.cpp @@ -738,3 +738,18 @@ bool Strings::ToBool(std::string bool_string) 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(std::rand()) % max_index]; + }; + std::string str(length, 0); + std::generate_n(str.begin(), length, randchar); + return str; +} diff --git a/common/strings.h b/common/strings.h index ed6810767..9f4121542 100644 --- a/common/strings.h +++ b/common/strings.h @@ -112,6 +112,7 @@ public: static uint32 TimeToSeconds(std::string time_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 std::string Random(size_t length); template static std::string