mirror of
https://github.com/zebrajr/SamRewritten.git
synced 2025-12-06 12:19:51 +01:00
Respect XDG and dynamically find steamclient.so
XDG Base Directory Specification is now followed. See globals.h for details. With XDG respected, steamclient.so is dynamically detected with a best-effort approach. SamRewritten must dynamically hook into it at runtime, and must use the running version, so now the git repo doesn't need to be updated everytime steamclient.so updates. Using the same steamclient.so for both app detection and game launching causes stale shared object state to be present in the child upon fork, so explictly unload the parent's steamclient.so so we can get a clean one. 32bit and SteamBeta detection is not implemented at this time, but can be in the future if there is interest. Misc: Disallow running as root Wrap directory creation Move most directory creation to main() Fix some typos
This commit is contained in:
parent
799edb845f
commit
c145c38567
Binary file not shown.
|
|
@ -1,5 +1,6 @@
|
|||
#include "GameServerManager.h"
|
||||
#include "MyGameServer.h"
|
||||
#include "MySteamClient.h"
|
||||
|
||||
// TODO: shouldn't really need MySteam inside here
|
||||
#include "MySteam.h"
|
||||
|
|
@ -20,6 +21,12 @@ GameServerManager::quick_server_create(AppId_t appid)
|
|||
if((pid = fork()) == 0) {
|
||||
// Son's process: server role
|
||||
|
||||
// We need to delete this to unload steamclient.so from the
|
||||
// child's process map, otherwise we pick up on a steam client
|
||||
// state from the app detection stage that doesn't have an appid
|
||||
// associated with it.
|
||||
delete g_steamclient;
|
||||
|
||||
MyGameServer server(appid);
|
||||
server.run();
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ MyGameServer::run()
|
|||
|
||||
if (!SteamAPI_Init()) {
|
||||
std::cerr << "An error occurred launching the Steam API. Aborting." << std::endl;
|
||||
std::cerr << "Make sure you are trying to run an app you own, and running with lauch.sh" << std::endl;
|
||||
std::cerr << "Make sure you are trying to run an app you own, and running with launch.sh" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,11 +86,6 @@ MySteam::quit_game() {
|
|||
*/
|
||||
void
|
||||
MySteam::refresh_owned_apps() {
|
||||
/*
|
||||
Hypothesis: the steamclient.so file must be from the same version than the currently installed
|
||||
Steam version.
|
||||
*/
|
||||
|
||||
if(m_owned_games_lock.try_lock()) {
|
||||
Game_t game;
|
||||
SteamAppDAO* appDAO = SteamAppDAO::get_instance();
|
||||
|
|
@ -124,18 +119,28 @@ MySteam::refresh_owned_apps() {
|
|||
* Tries to locate the steam folder in multiple locations,
|
||||
* which is not a failsafe implementation.
|
||||
*
|
||||
* The original steamclient library path is tthe returned path + "/linux64/steamclient.so"
|
||||
* The original steamclient library path is the returned path + "/linux64/steamclient.so"
|
||||
*/
|
||||
std::string
|
||||
std::string
|
||||
MySteam::get_steam_install_path() {
|
||||
static const std::string home_path(getenv("HOME"));
|
||||
if(file_exists(home_path + "/.local/share/Steam/appcache/appinfo.vdf")) {
|
||||
return std::string(home_path + "/.local/share/Steam");
|
||||
std::string data_home_path;
|
||||
if (getenv("XDG_DATA_HOME") != NULL) {
|
||||
data_home_path = getenv("XDG_DATA_HOME");
|
||||
} else {
|
||||
data_home_path = getenv("HOME") + std::string("/.local/share");
|
||||
}
|
||||
else if(file_exists(home_path + "/.steam/appcache/appinfo.vdf")) {
|
||||
|
||||
if (file_exists(data_home_path + "/Steam/appcache/appinfo.vdf")) {
|
||||
return std::string(data_home_path + "/Steam");
|
||||
}
|
||||
|
||||
std::cerr << "Trying to find Steam install with legacy Steam paths" << std::endl;
|
||||
|
||||
const std::string home_path = getenv("HOME");
|
||||
if (file_exists(home_path + "/.steam/appcache/appinfo.vdf")) {
|
||||
return std::string(home_path + "/.steam");
|
||||
}
|
||||
else if(file_exists(home_path + "/.steam/steam/appcache/appinfo.vdf")) {
|
||||
else if (file_exists(home_path + "/.steam/steam/appcache/appinfo.vdf")) {
|
||||
return std::string(home_path + "/.steam/steam");
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
#include <iostream>
|
||||
#include <dlfcn.h>
|
||||
#include "../steam/steam_api.h"
|
||||
#include "MySteam.h"
|
||||
|
||||
#define STEAM_CLIENT_LIB_PATH "steamclient.so"
|
||||
#define RELATIVE_STEAM_CLIENT_LIB_PATH "/linux64/steamclient.so"
|
||||
|
||||
/**
|
||||
* Purpose:
|
||||
|
|
@ -39,20 +40,21 @@ public:
|
|||
m_steamclient->BShutdownIfAllPipesClosed();
|
||||
dlclose(m_handle);
|
||||
}
|
||||
MySteamClient() {
|
||||
MySteamClient() {
|
||||
char* error;
|
||||
m_handle = dlopen(STEAM_CLIENT_LIB_PATH, RTLD_LAZY);
|
||||
const std::string steam_client_lib_path = MySteam::get_steam_install_path() + RELATIVE_STEAM_CLIENT_LIB_PATH;
|
||||
m_handle = dlopen(steam_client_lib_path.c_str(), RTLD_LAZY);
|
||||
if (!m_handle) {
|
||||
std::cerr << "Error opening the Steam Client library. Exitting. Info:" << std::endl;
|
||||
std::cerr << "Error opening the Steam Client library. Exiting. Info:" << std::endl;
|
||||
std::cerr << dlerror() << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
ISteamClient* (*CreateInterface)(const char* version, void*);
|
||||
|
||||
CreateInterface = (ISteamClient* (*)(const char*, void*))dlsym(m_handle, "CreateInterface");
|
||||
if ((error = dlerror()) != NULL) {
|
||||
std::cerr << "Error reading the CreateInterface symbol from the Steam Client library. Exitting. Info:" << std::endl;
|
||||
std::cerr << "Error reading the CreateInterface symbol from the Steam Client library. Exiting. Info:" << std::endl;
|
||||
std::cerr << error << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,14 +45,6 @@ SteamAppDAO::update_name_database() {
|
|||
static const char* local_file_name = concat(g_cache_folder, "/app_names");
|
||||
const std::time_t current_time(std::time(0));
|
||||
|
||||
// Make sure the cache folder is there
|
||||
const int mkdir_error = mkdir(g_cache_folder, S_IRWXU | S_IRWXG | S_IROTH);
|
||||
if(mkdir_error != 0 && errno != EEXIST) {
|
||||
std::cerr << "Unable to create the cache folder ( ~/.SamRewritten/, errno " << errno << ")." << std::endl;
|
||||
std::cerr << "Don't tell me you're running this as root.." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Check if the file is already there
|
||||
if (file_exists(local_file_name)) {
|
||||
//Check the last time it was updated
|
||||
|
|
@ -70,7 +62,7 @@ SteamAppDAO::update_name_database() {
|
|||
}
|
||||
}
|
||||
else {
|
||||
std::cerr << "~/.SamRewritten/app_names exists but an error occurred analyzing it. To avoid further complications, ";
|
||||
std::cerr << "~/.cache/SamRewritten/app_names exists but an error occurred analyzing it. To avoid further complications, ";
|
||||
std::cerr << "the program will stop here. Before retrying make sure you have enough privilege to read and write to ";
|
||||
std::cerr << "your home folder folder." << std::endl;
|
||||
|
||||
|
|
@ -99,11 +91,7 @@ SteamAppDAO::download_app_icon(const AppId_t& app_id) {
|
|||
const std::string local_path(local_folder + "/banner");
|
||||
const std::string url("http://cdn.akamai.steamstatic.com/steam/apps/" + std::to_string(app_id) + "/header_292x136.jpg");
|
||||
|
||||
const int mkdir_error = mkdir(local_folder.c_str(), S_IRWXU | S_IRWXG | S_IROTH);
|
||||
if(mkdir_error != 0 && errno != EEXIST) {
|
||||
std::cerr << "Unable to create the cache folder (" << local_folder << ", errno " << errno << ")." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mkdir_default(local_folder.c_str());
|
||||
|
||||
Downloader::get_instance()->download_file_async(url, local_path, app_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ char* concat(const char *s1, const char *s2)
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool strstri(const std::string & strHaystack, const std::string & strNeedle)
|
||||
{
|
||||
auto it = std::search(
|
||||
|
|
@ -70,3 +69,12 @@ bool strstri(const std::string & strHaystack, const std::string & strNeedle)
|
|||
);
|
||||
return (it != strHaystack.end() );
|
||||
}
|
||||
|
||||
void mkdir_default(const char *pathname)
|
||||
{
|
||||
int mkdir_error = mkdir(pathname, S_IRWXU | S_IRWXG | S_IROTH);
|
||||
if (mkdir_error != 0 && errno != EEXIST) {
|
||||
std::cerr << "Unable to create the folder " << pathname << ", errno " << errno << ")." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
|
@ -31,3 +31,9 @@ char* concat(const char *s1, const char *s2);
|
|||
* Insensitive "string in string"
|
||||
*/
|
||||
bool strstri(const std::string & strHaystack, const std::string & strNeedle);
|
||||
|
||||
/**
|
||||
* Make a directory with reasonable defaults
|
||||
* or fail hard on error
|
||||
*/
|
||||
void mkdir_default(const char *pathname);
|
||||
|
|
|
|||
|
|
@ -31,12 +31,26 @@ extern MainPickerWindow *g_main_gui;
|
|||
/**
|
||||
* The absolute path to the cache folder. It's global, because everyone will
|
||||
* need to write or read into this folder at some point.
|
||||
* As of right now the default path is:
|
||||
*
|
||||
* ~/.SamRewritten
|
||||
* XDG Base Directory Specification is followed:
|
||||
* If present, this variable uses XDG_CACHE_HOME and takes the value
|
||||
* $XDG_CACHE_HOME/SamRewritten
|
||||
* Otherwise, this variable properly defaults to
|
||||
* ~/.cache/SamRewritten
|
||||
*/
|
||||
extern char *g_cache_folder;
|
||||
|
||||
/**
|
||||
* The absolute path to the runtime folder. It's global, because everyone will
|
||||
* need to write or read into this folder at some point. It's used for storing
|
||||
* sockets used by the program.
|
||||
* XDG Base Directory Specification is followed:
|
||||
* If present, this variable uses XDG_RUNTIME_DIR and takes the value
|
||||
* $XDG_RUNTIME_DIR/SamRewritten
|
||||
* Warnings are properly issued if it is not set, but still defaults to the
|
||||
* cache folder for simplicity
|
||||
*/
|
||||
extern char *g_runtime_folder;
|
||||
|
||||
/**
|
||||
* A basic performance monitor
|
||||
*/
|
||||
|
|
|
|||
27
src/main.cpp
27
src/main.cpp
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <gmodule.h>
|
||||
#include <sys/stat.h>
|
||||
#include "MySteam.h"
|
||||
#include "MySteamClient.h"
|
||||
#include "MyGameServer.h"
|
||||
|
|
@ -20,6 +21,7 @@
|
|||
MySteam* g_steam = nullptr;
|
||||
MainPickerWindow* g_main_gui = nullptr;
|
||||
char* g_cache_folder = nullptr;
|
||||
char* g_runtime_folder = nullptr;
|
||||
MySteamClient* g_steamclient = nullptr;
|
||||
PerfMon* g_perfmon = nullptr;
|
||||
|
||||
|
|
@ -31,16 +33,35 @@ int
|
|||
main(int argc, char *argv[])
|
||||
{
|
||||
// Test if glib2 is installed, gtk will not work without it.
|
||||
if( !g_module_supported() ) {
|
||||
if ( !g_module_supported() ) {
|
||||
std::cout << "You are missing the Gnome libraries. Please read the README to know which libraries to install." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (getuid() == 0) {
|
||||
std::cout << "Do not run this application as root" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
g_perfmon = new PerfMon();
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
g_steamclient = new MySteamClient();
|
||||
g_cache_folder = concat( getenv("HOME"), "/.SamRewritten" );
|
||||
|
||||
if (getenv("XDG_CACHE_HOME")) {
|
||||
g_cache_folder = concat( getenv("XDG_CACHE_HOME"), "/SamRewritten" );
|
||||
} else {
|
||||
g_cache_folder = concat( getenv("HOME"), "/.cache/SamRewritten" );
|
||||
}
|
||||
mkdir_default(g_cache_folder);
|
||||
|
||||
if (getenv("XDG_RUNTIME_DIR")) {
|
||||
g_runtime_folder = concat( getenv("XDG_RUNTIME_DIR"), "/SamRewritten" );
|
||||
mkdir_default(g_runtime_folder);
|
||||
} else {
|
||||
std::cerr << "XDG_RUNTIME_DIR is not set! Your distribution is improper... falling back to cache dir" << std::endl;
|
||||
g_runtime_folder = g_cache_folder;
|
||||
}
|
||||
|
||||
g_steam = MySteam::get_instance();
|
||||
g_main_gui = new MainPickerWindow();
|
||||
g_perfmon->log("Globals initialized.");
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
#include <iostream>
|
||||
|
||||
MySocket::MySocket(AppId_t appid) : m_appid(appid), m_socket_fd(-1)
|
||||
{
|
||||
m_socket_path = std::string(g_cache_folder) + "/" + std::to_string(m_appid) + "/ipc.sock";
|
||||
{
|
||||
m_socket_path = std::string(g_runtime_folder) + "/" + std::to_string(m_appid) + "-ipc.sock";
|
||||
}
|
||||
|
||||
MySocket::~MySocket()
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user