lolautoaccept/src/clientaccess_linux.cpp

118 lines
3.1 KiB
C++

#include "clientaccess.h"
#include <cstring>
# include <sys/mman.h>
# include <dirent.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <string>
#include <vector>
#include <Log.h>
#include "defer.h"
static const std::string CLIENTNAME = "LeagueClientUx.exe"; // returns the name and value of a argument or empty string if it could not be parsed
static std::shared_ptr<ClientAccess> findUsingLockfile(const std::vector<std::string>& cmdline, pid_t pid);
static bool endsWith(const std::string& all, const std::string& end) {
return all.size() >= end.size() && all.rfind(end) == all.size() - end.size();
}
// reads a procfile into a vector (strings are \0 seperated)
static std::vector<std::string> readProcFile(const std::string& path) {
std::ifstream in(path);
std::vector<std::string> out;
std::string line;
while(std::getline(in, line, '\0')) {
if(!line.empty()) {
out.push_back(line);
}
}
return out;
}
std::shared_ptr<ClientAccess> ClientAccess::find() {
DIR* procdir = opendir("/proc");
if(!procdir) return nullptr;
defer( closedir(procdir) );
dirent* entry = nullptr;
while ((entry = readdir(procdir)) != NULL) {
if (entry->d_type != DT_DIR) continue;
std::string name(entry->d_name);
pid_t pid = -1;
try {
pid = std::stoi(name);
} catch(std::exception& e) {
// could not parse -> not a pid
continue;
}
// get info on the exe
std::string cmdfile = "/proc/" + std::to_string(pid) + "/cmdline";
std::vector<std::string> args = readProcFile(cmdfile);
// Log::debug << "process: " << pid << " has " << args.size() << " args";
if(args.empty()) continue;
std::string& exename = args.at(0);
if(endsWith(exename, CLIENTNAME)) {
Log::info << CLIENTNAME << " found: " << exename;
std::shared_ptr<ClientAccess> out;
out = findUsingLockfile(args, pid);
if(out) {
return out;
}
}
}
return nullptr;
}
std::shared_ptr<ClientAccess> findUsingLockfile(const std::vector<std::string>& cmdline, pid_t pid) {
// get WINEPREFIX env
std::vector<std::string> envs = readProcFile("/proc/" + std::to_string(pid) + "/environ");
const static std::string WINEPREFIX = "WINEPREFIX=";
// find WINEPREFIX
auto found = std::find_if(envs.begin(), envs.end(), [](const std::string& s) {
return s.find(WINEPREFIX) == 0;
});
// WINEPREFIX env not present
if(found == envs.end()) {
Log::debug << "WINEPREFIX environment variable not set";
return {};
}
const std::string wineprefix = found->substr(WINEPREFIX.size());
const std::string binarypath = cmdline.at(0);
std::string gamefolder = binarypath.substr(2, binarypath.rfind('/')-1); // remove the "C:" and the name of the binary
// TODO: gamefoldre could contain '\' so replacing every occurance with '/' would be a good idea
const std::string lockfilepath = wineprefix + "/drive_c/" + gamefolder + "/lockfile";
Log::debug << "lockfilepath: " << std::quoted(lockfilepath);
// read lockfile
std::ifstream lockfile(lockfilepath);
return createFromLockfile(lockfile);
}