00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #define FORBIDDEN_SYMBOL_EXCEPTION_getenv
00024 #define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
00025 #define FORBIDDEN_SYMBOL_EXCEPTION_exit
00026 #define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
00027 #define FORBIDDEN_SYMBOL_EXCEPTION_time_h //On IRIX, sys/stat.h includes sys/time.h
00028 #define FORBIDDEN_SYMBOL_EXCEPTION_system
00029 #define FORBIDDEN_SYMBOL_EXCEPTION_random
00030 #define FORBIDDEN_SYMBOL_EXCEPTION_srandom
00031
00032 #include "common/scummsys.h"
00033
00034 #ifdef POSIX
00035
00036 #include "backends/platform/sdl/posix/posix.h"
00037 #include "backends/saves/posix/posix-saves.h"
00038 #include "backends/fs/posix/posix-fs-factory.h"
00039 #include "backends/fs/posix/posix-fs.h"
00040 #include "backends/taskbar/unity/unity-taskbar.h"
00041
00042 #ifdef USE_LINUXCD
00043 #include "backends/audiocd/linux/linux-audiocd.h"
00044 #endif
00045
00046 #include "common/textconsole.h"
00047
00048 #include <stdlib.h>
00049 #include <errno.h>
00050 #include <sys/stat.h>
00051 #include <sys/wait.h>
00052 #include <unistd.h>
00053
00054 #ifdef HAS_POSIX_SPAWN
00055 #include <spawn.h>
00056 #endif
00057 extern char **environ;
00058
00059 OSystem_POSIX::OSystem_POSIX(Common::String baseConfigName)
00060 :
00061 _baseConfigName(baseConfigName) {
00062 }
00063
00064 void OSystem_POSIX::init() {
00065
00066 _fsFactory = new POSIXFilesystemFactory();
00067
00068 #if defined(USE_TASKBAR) && defined(USE_UNITY)
00069
00070 _taskbarManager = new UnityTaskbarManager();
00071 #endif
00072
00073
00074 OSystem_SDL::init();
00075 }
00076
00077 void OSystem_POSIX::initBackend() {
00078
00079 if (_savefileManager == 0)
00080 _savefileManager = new POSIXSaveFileManager();
00081
00082
00083 OSystem_SDL::initBackend();
00084
00085 #if defined(USE_TASKBAR) && defined(USE_UNITY)
00086
00087 _eventManager->getEventDispatcher()->registerSource((UnityTaskbarManager *)_taskbarManager, false);
00088 #endif
00089 }
00090
00091 bool OSystem_POSIX::hasFeature(Feature f) {
00092 if (f == kFeatureDisplayLogFile)
00093 return true;
00094 #ifdef HAS_POSIX_SPAWN
00095 if (f == kFeatureOpenUrl)
00096 return true;
00097 #endif
00098 return OSystem_SDL::hasFeature(f);
00099 }
00100
00101 Common::String OSystem_POSIX::getDefaultConfigFileName() {
00102 Common::String configFile;
00103
00104 Common::String prefix;
00105 #ifdef MACOSX
00106 prefix = getenv("HOME");
00107 #elif !defined(SAMSUNGTV)
00108 const char *envVar;
00109
00110
00111 envVar = getenv("HOME");
00112 if (envVar && *envVar) {
00113 configFile = envVar;
00114 configFile += '/';
00115 configFile += ".residualvmrc";
00116
00117 if (configFile.size() < MAXPATHLEN) {
00118 struct stat sb;
00119 if (stat(configFile.c_str(), &sb) == 0) {
00120 return configFile;
00121 }
00122 }
00123 }
00124
00125
00126
00127
00128 envVar = getenv("XDG_CONFIG_HOME");
00129 if (!envVar || !*envVar) {
00130 envVar = getenv("HOME");
00131 if (!envVar) {
00132 return 0;
00133 }
00134
00135 if (Posix::assureDirectoryExists(".config", envVar)) {
00136 prefix = envVar;
00137 prefix += "/.config";
00138 }
00139 } else {
00140 prefix = envVar;
00141 }
00142
00143 if (!prefix.empty() && Posix::assureDirectoryExists("residualvm", prefix.c_str())) {
00144 prefix += "/residualvm";
00145 }
00146 #endif
00147
00148 if (!prefix.empty() && (prefix.size() + 1 + _baseConfigName.size()) < MAXPATHLEN) {
00149 configFile = prefix;
00150 configFile += '/';
00151 configFile += _baseConfigName;
00152 } else {
00153 configFile = _baseConfigName;
00154 }
00155
00156 return configFile;
00157 }
00158
00159 Common::String OSystem_POSIX::getXdgUserDir(const char *name) {
00160
00161
00162 Common::String configHome = getenv("XDG_CONFIG_HOME");
00163 if (configHome.empty()) {
00164 const char *home = getenv("HOME");
00165 if (!home) {
00166 return "";
00167 }
00168
00169 configHome = Common::String::format("%s/.config", home);
00170 }
00171
00172
00173
00174 Common::FSNode userDirsFile(configHome + "/user-dirs.dirs");
00175 if (!userDirsFile.exists() || !userDirsFile.isReadable() || userDirsFile.isDirectory()) {
00176 return "";
00177 }
00178
00179 Common::SeekableReadStream *userDirsStream = userDirsFile.createReadStream();
00180 if (!userDirsStream) {
00181 return "";
00182 }
00183
00184 Common::String dirLinePrefix = Common::String::format("XDG_%s_DIR=", name);
00185
00186 Common::String directoryValue;
00187 while (!userDirsStream->eos() && !userDirsStream->err()) {
00188 Common::String userDirsLine = userDirsStream->readLine();
00189 userDirsLine.trim();
00190
00191 if (userDirsLine.hasPrefix(dirLinePrefix)) {
00192 directoryValue = Common::String(userDirsLine.c_str() + dirLinePrefix.size());
00193 break;
00194 }
00195 }
00196
00197 delete userDirsStream;
00198
00199
00200
00201 if (directoryValue.empty() || directoryValue[0] != '"') {
00202 return "";
00203 }
00204
00205 if (directoryValue[directoryValue.size() - 1] != '"') {
00206 return "";
00207 }
00208
00209
00210
00211
00212 Common::String directoryPath(directoryValue.c_str() + 1, directoryValue.size() - 2);
00213
00214 if (directoryPath.hasPrefix("$HOME/")) {
00215 const char *home = getenv("HOME");
00216 directoryPath = Common::String::format("%s%s", home, directoryPath.c_str() + 5);
00217 }
00218
00219
00220 if (directoryPath.empty() || directoryPath[0] != '/') {
00221 return "";
00222 }
00223
00224 return directoryPath;
00225 }
00226
00227 Common::String OSystem_POSIX::getScreenshotsPath() {
00228
00229 const Common::String path = OSystem_SDL::getScreenshotsPath();
00230 if (!path.empty()) {
00231 return path;
00232 }
00233
00234
00235
00236
00237 Common::String picturesPath = getXdgUserDir("PICTURES");
00238 if (picturesPath.empty()) {
00239 return "";
00240 }
00241
00242 if (!picturesPath.hasSuffix("/")) {
00243 picturesPath += "/";
00244 }
00245
00246 static const char *SCREENSHOTS_DIR_NAME = "ResidualVM Screenshots";
00247 if (!Posix::assureDirectoryExists(SCREENSHOTS_DIR_NAME, picturesPath.c_str())) {
00248 return "";
00249 }
00250
00251 return picturesPath + SCREENSHOTS_DIR_NAME + "/";
00252 }
00253
00254 void OSystem_POSIX::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
00255 #ifdef DATA_PATH
00256 const char *snap = getenv("SNAP");
00257 if (snap) {
00258 Common::String dataPath = Common::String(snap) + DATA_PATH;
00259 Common::FSNode dataNode(dataPath);
00260 if (dataNode.exists() && dataNode.isDirectory()) {
00261
00262
00263 s.add(dataPath, new Common::FSDirectory(dataNode, 4), priority);
00264 }
00265 }
00266 #endif
00267
00268
00269 OSystem_SDL::addSysArchivesToSearchSet(s, priority);
00270 }
00271
00272 Common::WriteStream *OSystem_POSIX::createLogFile() {
00273
00274
00275 _logFilePath.clear();
00276
00277 const char *prefix = nullptr;
00278 Common::String logFile;
00279 #ifdef MACOSX
00280 prefix = getenv("HOME");
00281 if (prefix == nullptr) {
00282 return 0;
00283 }
00284
00285 logFile = "Library/Logs";
00286 #elif SAMSUNGTV
00287 prefix = nullptr;
00288 logFile = "/mtd_ram";
00289 #else
00290
00291
00292
00293 prefix = getenv("XDG_CACHE_HOME");
00294 if (prefix == nullptr || !*prefix) {
00295 prefix = getenv("HOME");
00296 if (prefix == nullptr) {
00297 return 0;
00298 }
00299
00300 logFile = ".cache/";
00301 }
00302
00303 logFile += "residualvm/logs";
00304 #endif
00305
00306 if (!Posix::assureDirectoryExists(logFile, prefix)) {
00307 return 0;
00308 }
00309
00310 if (prefix) {
00311 logFile = Common::String::format("%s/%s", prefix, logFile.c_str());
00312 }
00313
00314 logFile += "/residualvm.log";
00315
00316 Common::FSNode file(logFile);
00317 Common::WriteStream *stream = file.createWriteStream();
00318 if (stream)
00319 _logFilePath = logFile;
00320 return stream;
00321 }
00322
00323 bool OSystem_POSIX::displayLogFile() {
00324 if (_logFilePath.empty())
00325 return false;
00326
00327
00328
00329
00330
00331
00332 pid_t pid = fork();
00333 if (pid < 0) {
00334
00335 return false;
00336 } else if (pid == 0) {
00337
00338
00339 execlp("xdg-open", "xdg-open", _logFilePath.c_str(), (char *)0);
00340
00341
00342
00343
00344
00345
00346
00347
00348 execlp("xterm", "xterm", "-e", "less", _logFilePath.c_str(), (char *)0);
00349
00350
00351
00352
00353
00354
00355 exit(127);
00356 }
00357
00358 int status;
00359
00360
00361
00362
00363
00364 pid = waitpid(pid, &status, 0);
00365
00366 if (pid < 0) {
00367
00368 return false;
00369 }
00370
00371 return WIFEXITED(status) && WEXITSTATUS(status) == 0;
00372 }
00373
00374 bool OSystem_POSIX::openUrl(const Common::String &url) {
00375 #ifdef HAS_POSIX_SPAWN
00376
00377
00378
00379 if (launchBrowser("xdg-open", url))
00380 return true;
00381 if (launchBrowser(getenv("DEFAULT_BROWSER"), url))
00382 return true;
00383 if (launchBrowser(getenv("BROWSER"), url))
00384 return true;
00385
00386
00387 if (launchBrowser("gnome-open", url))
00388 return true;
00389 if (launchBrowser("kfmclient", url))
00390 return true;
00391 if (launchBrowser("exo-open", url))
00392 return true;
00393
00394
00395 if (launchBrowser("firefox", url))
00396 return true;
00397 if (launchBrowser("mozilla", url))
00398 return true;
00399 if (launchBrowser("netscape", url))
00400 return true;
00401 if (launchBrowser("opera", url))
00402 return true;
00403 if (launchBrowser("chromium-browser", url))
00404 return true;
00405 if (launchBrowser("google-chrome", url))
00406 return true;
00407
00408 warning("openUrl() (POSIX) failed to open URL");
00409 return false;
00410 #else
00411 return false;
00412 #endif
00413 }
00414
00415 bool OSystem_POSIX::launchBrowser(const Common::String &client, const Common::String &url) {
00416 #ifdef HAS_POSIX_SPAWN
00417 pid_t pid;
00418 const char *argv[] = {
00419 client.c_str(),
00420 url.c_str(),
00421 NULL,
00422 NULL
00423 };
00424 if (client == "kfmclient") {
00425 argv[2] = argv[1];
00426 argv[1] = "openURL";
00427 }
00428 if (posix_spawnp(&pid, client.c_str(), NULL, NULL, const_cast<char **>(argv), environ) != 0) {
00429 return false;
00430 }
00431 return (waitpid(pid, NULL, WNOHANG) != -1);
00432 #else
00433 return false;
00434 #endif
00435 }
00436
00437 AudioCDManager *OSystem_POSIX::createAudioCDManager() {
00438 #ifdef USE_LINUXCD
00439 return createLinuxAudioCDManager();
00440 #else
00441 return OSystem_SDL::createAudioCDManager();
00442 #endif
00443 }
00444
00445 #endif