X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fporting.cpp;h=1e3d610bce6609c1e7fea150fac3fd9800efb11e;hb=12d1e4ff0486f86ae20051daa1135dc7db366023;hp=651c92ff966eafaa7f2acae3b83f1cc1214c22d4;hpb=14657bd29a0b6783fc97029769af6d48a05d473d;p=minetest.git diff --git a/src/porting.cpp b/src/porting.cpp index 651c92ff9..1e3d610bc 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -1,6 +1,6 @@ /* -Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -23,31 +23,34 @@ with this program; if not, write to the Free Software Foundation, Inc., See comments in porting.h */ -#if defined(_WIN32) - #include -#elif defined(linux) - #include -#elif defined(__APPLE__) - #include - #include -#elif defined(__FreeBSD__) - #include +#include "porting.h" + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) #include #include +#elif defined(_WIN32) + #include + #include + #include + #include +#endif +#if !defined(_WIN32) + #include + #include +#endif +#if defined(__hpux) + #define _PSTAT64 + #include #endif -#include "porting.h" #include "config.h" #include "debug.h" #include "filesys.h" #include "log.h" #include "util/string.h" +#include "settings.h" #include -#ifdef __APPLE__ - #include "CoreFoundation/CoreFoundation.h" -#endif - namespace porting { @@ -57,7 +60,7 @@ namespace porting bool g_killed = false; -bool * signal_handler_killstatus(void) +bool *signal_handler_killstatus() { return &g_killed; } @@ -65,75 +68,68 @@ bool * signal_handler_killstatus(void) #if !defined(_WIN32) // POSIX #include -void sigint_handler(int sig) +void signal_handler(int sig) { - if(g_killed == false) - { - dstream< - #include - BOOL WINAPI event_handler(DWORD sig) - { - switch(sig) - { - case CTRL_C_EVENT: - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - - if(g_killed == false) - { - dstream<dwProductVersionMS) << '.' // Major + << LOWORD(fixedFileInfo->dwProductVersionMS) << '.' // Minor + << HIWORD(fixedFileInfo->dwProductVersionLS) << ' '; // Build - /* - Linux - */ - #elif defined(linux) + #ifdef _WIN64 + oss << "x86_64"; + #else + BOOL is64 = FALSE; + if (IsWow64Process(GetCurrentProcess(), &is64) && is64) + oss << "x86_64"; // 32-bit app on 64-bit OS + else + oss << "x86"; + #endif - char buf[BUFSIZ]; - memset(buf, 0, BUFSIZ); - // Get path to executable - assert(readlink("/proc/self/exe", buf, BUFSIZ-1) != -1); + delete[] lpVersionInfo; + delete[] filePath; + + return oss.str(); +#else + struct utsname osinfo; + uname(&osinfo); + return std::string(osinfo.sysname) + "/" + + osinfo.release + " " + osinfo.machine; +#endif +} - pathRemoveFile(buf, '/'); - path_share = std::string(buf) + "/.."; - path_user = std::string(buf) + "/.."; +bool getCurrentWorkingDir(char *buf, size_t len) +{ +#ifdef _WIN32 + DWORD ret = GetCurrentDirectory(len, buf); + return (ret != 0) && (ret <= len); +#else + return getcwd(buf, len); +#endif +} - /* - OS X - */ - #elif defined(__APPLE__) - //https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/dyld.3.html - //TODO: Test this code - char buf[BUFSIZ]; - uint32_t len = sizeof(buf); - assert(_NSGetExecutablePath(buf, &len) != 0); +bool getExecPathFromProcfs(char *buf, size_t buflen) +{ +#ifndef _WIN32 + buflen--; + + ssize_t len; + if ((len = readlink("/proc/self/exe", buf, buflen)) == -1 && + (len = readlink("/proc/curproc/file", buf, buflen)) == -1 && + (len = readlink("/proc/curproc/exe", buf, buflen)) == -1) + return false; + + buf[len] = '\0'; + return true; +#else + return false; +#endif +} - pathRemoveFile(buf, '/'); +//// Windows +#if defined(_WIN32) + +bool getCurrentExecPath(char *buf, size_t len) +{ + DWORD written = GetModuleFileNameA(NULL, buf, len); + if (written == 0 || written == len) + return false; + + return true; +} + + +//// Linux +#elif defined(__linux__) + +bool getCurrentExecPath(char *buf, size_t len) +{ + if (!getExecPathFromProcfs(buf, len)) + return false; + + return true; +} + + +//// Mac OS X, Darwin +#elif defined(__APPLE__) - path_share = std::string(buf) + "/.."; - path_user = std::string(buf) + "/.."; +bool getCurrentExecPath(char *buf, size_t len) +{ + uint32_t lenb = (uint32_t)len; + if (_NSGetExecutablePath(buf, &lenb) == -1) + return false; - /* - FreeBSD - */ - #elif defined(__FreeBSD__) + return true; +} + + +//// FreeBSD, NetBSD, DragonFlyBSD +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + +bool getCurrentExecPath(char *buf, size_t len) +{ + // Try getting path from procfs first, since valgrind + // doesn't work with the latter + if (getExecPathFromProcfs(buf, len)) + return true; int mib[4]; - char buf[BUFSIZ]; - size_t len = sizeof(buf); mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = -1; - assert(sysctl(mib, 4, buf, &len, NULL, 0) != -1); - pathRemoveFile(buf, '/'); + if (sysctl(mib, 4, buf, &len, NULL, 0) == -1) + return false; - path_share = std::string(buf) + "/.."; - path_user = std::string(buf) + "/.."; + return true; +} - #else - //TODO: Get path of executable. This assumes working directory is bin/ - dstream<<"WARNING: Relative path not properly supported on this platform" - <= len) + return false; + + return true; +} + + +// HP-UX +#elif defined(__hpux) + +bool getCurrentExecPath(char *buf, size_t len) +{ + struct pst_status psts; + + if (pstat_getproc(&psts, sizeof(psts), 0, getpid()) == -1) + return false; + + if (pstat_getpathname(buf, len, &psts.pst_fid_text) == -1) + return false; + + return true; +} + + +#else -#else // RUN_IN_PLACE +bool getCurrentExecPath(char *buf, size_t len) +{ + return false; +} - /* - Use platform-specific paths otherwise - */ +#endif - infostream<<"Using system-wide paths (NOT RUN_IN_PLACE)"<" - len = GetEnvironmentVariable("APPDATA", buf, buflen); - assert(len < buflen); + DWORD len = GetEnvironmentVariable("APPDATA", buf, sizeof(buf)); + FATAL_ERROR_IF(len == 0 || len > sizeof(buf), "Failed to get APPDATA"); + path_user = std::string(buf) + DIR_DELIM + PROJECT_NAME; + return true; +} - /* - Linux - */ - #elif defined(linux) - // Get path to executable - std::string bindir = ""; - { - char buf[BUFSIZ]; - memset(buf, 0, BUFSIZ); - assert(readlink("/proc/self/exe", buf, BUFSIZ-1) != -1); - pathRemoveFile(buf, '/'); - bindir = buf; +//// Linux +#elif defined(__linux__) + +bool setSystemPaths() +{ + char buf[BUFSIZ]; + + if (!getCurrentExecPath(buf, sizeof(buf))) { +#ifdef __ANDROID__ + errorstream << "Unable to read bindir "<< std::endl; +#else + FATAL_ERROR("Unable to read bindir"); +#endif + return false; } + pathRemoveFile(buf, '/'); + std::string bindir(buf); + // Find share directory from these. // It is identified by containing the subdirectory "builtin". std::list trylist; std::string static_sharedir = STATIC_SHAREDIR; - if(static_sharedir != "" && static_sharedir != ".") + if (!static_sharedir.empty() && static_sharedir != ".") trylist.push_back(static_sharedir); - trylist.push_back(bindir + "/../share/" + PROJECT_NAME); - trylist.push_back(bindir + "/.."); - for(std::list::const_iterator i = trylist.begin(); - i != trylist.end(); i++) - { + trylist.push_back(bindir + DIR_DELIM ".." DIR_DELIM "share" + DIR_DELIM + PROJECT_NAME); + trylist.push_back(bindir + DIR_DELIM ".."); + +#ifdef __ANDROID__ + trylist.push_back(path_user); +#endif + + for (std::list::const_iterator + i = trylist.begin(); i != trylist.end(); ++i) { const std::string &trypath = *i; - if(!fs::PathExists(trypath) || !fs::PathExists(trypath + "/builtin")){ - dstream<<"WARNING: system-wide share not found at \"" - <= 1 && buf[cwdlen - 1] == DIR_DELIM_CHAR) { + cwdlen--; + buf[cwdlen] = '\0'; + } + + if (cwdlen >= 4 && !strcmp(buf + cwdlen - 4, DIR_DELIM "bin")) + pathRemoveFile(buf, DIR_DELIM_CHAR); + + std::string execpath(buf); + + path_share = execpath; + path_user = execpath; + } + path_cache = path_user + DIR_DELIM + "cache"; +#else + infostream << "Using system-wide paths (NOT RUN_IN_PLACE)" << std::endl; + + if (!setSystemPaths()) + errorstream << "Failed to get one or more system-wide path" << std::endl; + + // Initialize path_cache + // First try $XDG_CACHE_HOME/PROJECT_NAME + const char *cache_dir = getenv("XDG_CACHE_HOME"); + const char *home_dir = getenv("HOME"); + if (cache_dir) { + path_cache = std::string(cache_dir) + DIR_DELIM + PROJECT_NAME; + } else if (home_dir) { + // Then try $HOME/.cache/PROJECT_NAME + path_cache = std::string(home_dir) + DIR_DELIM + ".cache" + + DIR_DELIM + PROJECT_NAME; + } else { + // If neither works, use $PATH_USER/cache + path_cache = path_user + DIR_DELIM + "cache"; + } + // Migrate cache folder to new location if possible + migrateCachePath(); +#endif + + infostream << "Detected share path: " << path_share << std::endl; + infostream << "Detected user path: " << path_user << std::endl; + infostream << "Detected cache path: " << path_cache << std::endl; + +#if USE_GETTEXT + bool found_localedir = false; +# ifdef STATIC_LOCALEDIR + if (STATIC_LOCALEDIR[0] && fs::PathExists(STATIC_LOCALEDIR)) { + found_localedir = true; + path_locale = STATIC_LOCALEDIR; + infostream << "Using locale directory " << STATIC_LOCALEDIR << std::endl; + } else { + path_locale = getDataPath("locale"); + if (fs::PathExists(path_locale)) { + found_localedir = true; + infostream << "Using in-place locale directory " << path_locale + << " even though a static one was provided " + << "(RUN_IN_PLACE or CUSTOM_LOCALEDIR)." << std::endl; + } + } +# else + path_locale = getDataPath("locale"); + if (fs::PathExists(path_locale)) { + found_localedir = true; + } +# endif + if (!found_localedir) { + warningstream << "Couldn't find a locale directory!" << std::endl; + } +#endif // USE_GETTEXT +} + +//// +//// OS-specific Secure Random +//// + +#ifdef WIN32 + +bool secure_rand_fill_buf(void *buf, size_t len) +{ + HCRYPTPROV wctx; + + if (!CryptAcquireContext(&wctx, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + return false; + + CryptGenRandom(wctx, len, (BYTE *)buf); + CryptReleaseContext(wctx, 0); + return true; +} + +#else + +bool secure_rand_fill_buf(void *buf, size_t len) +{ + // N.B. This function checks *only* for /dev/urandom, because on most + // common OSes it is non-blocking, whereas /dev/random is blocking, and it + // is exceptionally uncommon for there to be a situation where /dev/random + // exists but /dev/urandom does not. This guesswork is necessary since + // random devices are not covered by any POSIX standard... + FILE *fp = fopen("/dev/urandom", "rb"); + if (!fp) + return false; + + bool success = fread(buf, len, 1, fp) == 1; + + fclose(fp); + return success; +} + +#endif + +void attachOrCreateConsole() +{ +#ifdef _WIN32 + static bool consoleAllocated = false; + const bool redirected = (_fileno(stdout) == -2 || _fileno(stdout) == -1); // If output is redirected to e.g a file + if (!consoleAllocated && redirected && (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole())) { + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + consoleAllocated = true; + } +#endif +} + +// Load performance counter frequency only once at startup +#ifdef _WIN32 + +inline double get_perf_freq() +{ + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return freq.QuadPart; +} + +double perf_freq = get_perf_freq(); + +#endif + +} //namespace porting