Kylin/Universal/ProcessUtility.cpp
2023-12-07 19:46:15 +08:00

202 lines
6.5 KiB
C++

#include "ProcessUtility.h"
#include "BoostLog.h"
#include <boost/algorithm/string.hpp>
#include <filesystem>
#include <regex>
#include <sstream>
#ifdef __linux__
#include <unistd.h>
#elif defined(_WIN32)
#include <boost/winapi/dll.hpp>
#endif
bool DockerUtility::supervisorStatus(std::string_view container, const std::string &module) {
using namespace boost::process;
boost::process::ipstream ips;
auto docker = search_path("docker");
auto ctl = boost::process::search_path("supervisorctl");
auto env = boost::this_process::environment();
if (env.count("USER")) {
auto user = env["USER"].to_string();
system(docker, args = {"exec", "-u", user, container.data(), "supervisorctl", "status", module}, std_out > ips);
std::string line;
if (!ips) return false;
std::getline(ips, line);
if (line.empty()) return false;
boost::algorithm::trim(line);
std::vector<std::string> s;
boost::algorithm::split(s, line, boost::algorithm::is_any_of(" "), boost::algorithm::token_compress_on);
if (s.size() < 3) return false;
return s.at(2) == "RUNNING";
} else {
LOG(error) << "this_process did not contain USER env value.";
return false;
}
}
bool DockerUtility::running(std::string_view container, std::error_code &error) {
#ifdef __linux__
using namespace boost::process;
boost::process::ipstream stream;
std::ostringstream oss;
oss << "docker ps -q --filter \"name=" << container << "\" --filter \"status=running\"";
system(oss.str(), boost::process::std_out > stream, error);
if (error) return false;
bool ret = false;
std::string line;
while (std::getline(stream, line) && !line.empty()) {
ret = true;
break;
}
return ret;
#else
return false;
#endif
}
std::string NativeUtility::currentExecutable() {
// win32 GetModuleFileNameA
#ifdef __linux__
char buffer[512] = {0};
auto status = readlink("/proc/self/exe", buffer, sizeof(buffer));
return status == -1 ? std::string() : std::string(buffer);
#else
char buffer[MAX_PATH];
boost::winapi::get_module_file_name(nullptr, buffer, MAX_PATH);
return buffer;
#endif
}
std::string NativeUtility::executableDirectory() {
auto path = currentExecutable();
#ifdef __linux__
auto slashPos = path.find_last_of("/");
#else
auto slashPos = path.find_last_of("\\");
#endif
return path.substr(0, slashPos);
}
std::string NativeUtility::applicationDataDirectory(bool create) {
std::string directory;
#ifdef WIN32
DWORD bufferSize = GetEnvironmentVariable("APPDATA", 0, 0);
char *buffer = new char[bufferSize + 2];
GetEnvironmentVariable("APPDATA", buffer, bufferSize);
directory.assign(buffer);
delete[] buffer;
#else
const char *result = std::getenv("XDG_CONFIG_HOME");
if (result && strlen(result)) {
directory = std::string(result);
} else {
directory = std::string(std::getenv("HOME")) + std::string("/.config/");
}
#endif
auto exePath = currentExecutable();
auto slashPos = exePath.find_last_of("\\");
auto dotPos = exePath.find_last_of(".");
auto appName = exePath.substr(slashPos + 1, dotPos - slashPos - 1);
std::ostringstream oss;
oss << directory << "/" << appName << "/";
directory = oss.str();
if (create) {
try {
std::filesystem::path path(std::filesystem::u8path(directory));
if (!std::filesystem::exists(path)) {
std::filesystem::create_directories(path);
}
} catch (...) {
}
}
return directory;
}
std::string NativeUtility::homeDirectory() {
std::string directory;
#ifdef WIN32
DWORD bufferSize = GetEnvironmentVariable("USERPROFILE", 0, 0);
char *buffer = new char[bufferSize + 2];
GetEnvironmentVariable("USERPROFILE", buffer, bufferSize);
directory.assign(buffer);
delete[] buffer;
#else
directory = std::string(std::getenv("HOME"));
#endif
return directory;
}
bool NativeUtility::processRunning(const std::string &nameFilter) {
boost::process::ipstream ips;
// for unknow reason,on gdb debug mode,the columns is very short.
boost::process::system("ps -eF --columns 999", boost::process::std_out > ips);
std::string line;
std::regex regex(nameFilter);
while (std::getline(ips, line)) {
if (line.empty()) continue;
// LOG(debug) << "processRunning: " << line;
if (std::regex_search(line, regex)) {
return true;
}
}
return false;
}
void DockerUtility::executeBashCommand(const std::string &command) {
std::ostringstream oss;
oss << "bash -c \"" << command << "\"";
boost::process::system("bash -c \" \"");
// ps -aux | grep rosbridge | awk '{print $2}' | xargs kill -s 9 2>/dev/null
}
void DockerUtility::execute(const std::string_view &container, const std::string_view &command) {
std::ostringstream oss;
auto env = boost::this_process::environment();
auto user = env["USER"].to_string();
oss << "docker exec -u " << user << " -d " << container << " " << command;
using namespace boost::process;
system(oss.str());
}
void DockerUtility::kill(const std::string &nameFilter) {
std::ostringstream oss;
oss << "ps -aux | grep " << nameFilter << " | awk '{print $2}' | xargs kill -s 9 2>/dev/null";
executeBashCommand(oss.str());
}
bool DockerUtility::containerExisted(const std::string_view &name) {
boost::process::ipstream ips;
std::ostringstream oss;
oss << "docker ps -aq --filter name=" << name;
boost::process::system(oss.str(), boost::process::std_out > ips);
std::string line;
while (std::getline(ips, line)) {
if (line.empty()) continue;
return true;
}
return false;
}
void DockerUtility::supervisorctl(const std::string_view &container, const std::string &module, bool isStart) {
using namespace boost::process;
auto docker = search_path("docker");
auto env = boost::this_process::environment();
auto user = env["USER"].to_string();
system(docker, args = {"exec", "-u", user, container.data(), "supervisorctl", isStart ? "start" : "stop", module});
}
void DockerUtility::stop(const std::string &nameFilter) {
using namespace boost::process;
ipstream ips;
std::ostringstream oss;
oss << "docker ps -q --filter \"name=" << nameFilter << "\" --filter \"status=running\" ";
system(oss.str(), std_out > ips);
std::string id;
auto docker = search_path("docker");
while (std::getline(ips, id) && !id.empty()) {
system(docker, "stop", args += {id});
}
}