X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fporting.cpp;h=09627431c7e8bd501498d9ef147b92c93da787a4;hb=e1f707d7e1ac0412eedbfcc200a1b90339d3ab0d;hp=84df15b3093d166670a3b268e6c2354ad899989f;hpb=979ca23f1eae1adeb8b0083dffe7203c54d87395;p=dragonfireclient.git diff --git a/src/porting.cpp b/src/porting.cpp index 84df15b30..09627431c 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -23,27 +23,60 @@ with this program; if not, write to the Free Software Foundation, Inc., See comments in porting.h */ -#if defined(linux) - #include -#elif defined(__APPLE__) - #include - #include -#elif defined(__FreeBSD__) - #include +#include "porting.h" + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) #include #include + extern char **environ; +#elif defined(_WIN32) + #include + #include + #include + #include + #include + #include +#endif +#if !defined(_WIN32) + #include + #include + #if !defined(__ANDROID__) + #include + #endif +#endif +#if defined(__hpux) + #define _PSTAT64 + #include +#endif +#if defined(__ANDROID__) + #include "porting_android.h" +#endif +#if defined(__APPLE__) + // For _NSGetEnviron() + // Related: https://gitlab.haskell.org/ghc/ghc/issues/2458 + #include +#endif + +#if defined(__HAIKU__) + #include #endif -#include "porting.h" #include "config.h" #include "debug.h" #include "filesys.h" #include "log.h" #include "util/string.h" #include - -#ifdef __APPLE__ - #include "CoreFoundation/CoreFoundation.h" +#include +#include + +#if !defined(SERVER) && defined(_WIN32) +// On Windows export some driver-specific variables to encourage Minetest to be +// executed on the discrete GPU in case of systems with two. Portability is fun. +extern "C" { + __declspec(dllexport) DWORD NvOptimusEnablement = 1; + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; +} #endif namespace porting @@ -55,7 +88,7 @@ namespace porting bool g_killed = false; -bool * signal_handler_killstatus(void) +bool *signal_handler_killstatus() { return &g_killed; } @@ -63,429 +96,696 @@ 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< - 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<=0; i--) + { + if(path[i] == delim) + break; + } + path[i] = 0; +} + +bool detectMSVCBuildDir(const std::string &path) +{ + const char *ends[] = { + "bin\\Release", + "bin\\MinSizeRel", + "bin\\RelWithDebInfo", + "bin\\Debug", + "bin\\Build", + NULL + }; + return (!removeStringEnd(path, ends).empty()); +} -#elif defined(__FreeBSD__) || defined(__APPLE__) +std::string get_sysinfo() +{ +#ifdef _WIN32 - unsigned int len, count; - len = sizeof(count); - return sysctlbyname("hw.ncpu", &count, &len, NULL, 0); + std::ostringstream oss; + LPSTR filePath = new char[MAX_PATH]; + UINT blockSize; + VS_FIXEDFILEINFO *fixedFileInfo; -#elif defined(_GNU_SOURCE) + GetSystemDirectoryA(filePath, MAX_PATH); + PathAppendA(filePath, "kernel32.dll"); - return get_nprocs(); + DWORD dwVersionSize = GetFileVersionInfoSizeA(filePath, NULL); + LPBYTE lpVersionInfo = new BYTE[dwVersionSize]; -#elif defined(_WIN32) + GetFileVersionInfoA(filePath, 0, dwVersionSize, lpVersionInfo); + VerQueryValueA(lpVersionInfo, "\\", (LPVOID *)&fixedFileInfo, &blockSize); - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - return sysinfo.dwNumberOfProcessors; + oss << "Windows/" + << HIWORD(fixedFileInfo->dwProductVersionMS) << '.' // Major + << LOWORD(fixedFileInfo->dwProductVersionMS) << '.' // Minor + << HIWORD(fixedFileInfo->dwProductVersionLS) << ' '; // Build -#elif defined(PTW32_VERSION) || defined(__hpux) + #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 - return pthread_num_processors_np(); + delete[] lpVersionInfo; + delete[] filePath; + return oss.str(); #else + struct utsname osinfo; + uname(&osinfo); + return std::string(osinfo.sysname) + "/" + + osinfo.release + " " + osinfo.machine; +#endif +} - return 1; +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 } -bool threadBindToProcessor(threadid_t tid, int pnumber) { -#if defined(_WIN32) +bool getExecPathFromProcfs(char *buf, size_t buflen) +{ +#ifndef _WIN32 + buflen--; - HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, 0, tid); - if (!hThread) + 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; - bool success = SetThreadAffinityMask(hThread, 1 << pnumber) != 0; - - CloseHandle(hThread); - return success; + buf[len] = '\0'; + return true; +#else + return false; +#endif +} -#elif (defined(__FreeBSD__) && (__FreeBSD_version >= 702106)) \ - || defined(__linux) || defined(linux) +//// Windows +#if defined(_WIN32) - cpu_set_t cpuset; +bool getCurrentExecPath(char *buf, size_t len) +{ + DWORD written = GetModuleFileNameA(NULL, buf, len); + if (written == 0 || written == len) + return false; - CPU_ZERO(&cpuset); - CPU_SET(pnumber, &cpuset); - return pthread_setaffinity_np(tid, sizeof(cpuset), &cpuset) == 0; + return true; +} -#elif defined(__sun) || defined(sun) - return processor_bind(P_LWPID, MAKE_LWPID_PTHREAD(tid), - pnumber, NULL) == 0; +//// Linux +#elif defined(__linux__) -#elif defined(_AIX) - - return bindprocessor(BINDTHREAD, (tid_t)tid, pnumber) == 0; +bool getCurrentExecPath(char *buf, size_t len) +{ + if (!getExecPathFromProcfs(buf, len)) + return false; -#elif defined(__hpux) || defined(hpux) + return true; +} - pthread_spu_t answer; - return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP, - &answer, pnumber, tid) == 0; - +//// Mac OS X, Darwin #elif defined(__APPLE__) - struct thread_affinity_policy tapol; - - thread_port_t threadport = pthread_mach_thread_np(tid); - tapol.affinity_tag = pnumber + 1; - return thread_policy_set(threadport, THREAD_AFFINITY_POLICY, - (thread_policy_t)&tapol, THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS; - -#else - - return false; +bool getCurrentExecPath(char *buf, size_t len) +{ + uint32_t lenb = (uint32_t)len; + if (_NSGetExecutablePath(buf, &lenb) == -1) + return false; -#endif + return true; } -bool threadSetPriority(threadid_t tid, int prio) { -#if defined(_WIN32) +//// FreeBSD, NetBSD, DragonFlyBSD +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) - HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, 0, tid); - if (!hThread) - return false; +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; - bool success = SetThreadPriority(hThread, prio) != 0; + int mib[4]; - CloseHandle(hThread); - return success; - -#else + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; - struct sched_param sparam; - int policy; - - if (pthread_getschedparam(tid, &policy, &sparam) != 0) + if (sysctl(mib, 4, buf, &len, NULL, 0) == -1) return false; - - int min = sched_get_priority_min(policy); - int max = sched_get_priority_max(policy); - sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST; - return pthread_setschedparam(tid, policy, &sparam) == 0; - -#endif + return true; } +#elif defined(__HAIKU__) -/* - Path mangler -*/ +bool getCurrentExecPath(char *buf, size_t len) +{ + return find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, buf, len) == B_OK; +} -// Default to RUN_IN_PLACE style relative paths -std::string path_share = ".."; -std::string path_user = ".."; +//// Solaris +#elif defined(__sun) || defined(sun) -std::string getDataPath(const char *subpath) +bool getCurrentExecPath(char *buf, size_t len) { - return path_share + DIR_DELIM + subpath; + const char *exec = getexecname(); + if (exec == NULL) + return false; + + if (strlcpy(buf, exec, len) >= len) + return false; + + return true; } -void pathRemoveFile(char *path, char delim) + +// HP-UX +#elif defined(__hpux) + +bool getCurrentExecPath(char *buf, size_t len) { - // Remove filename and path delimiter - int i; - for(i = strlen(path)-1; i>=0; i--) - { - if(path[i] == delim) - break; - } - path[i] = 0; + 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; } -bool detectMSVCBuildDir(char *c_path) + +#else + +bool getCurrentExecPath(char *buf, size_t len) { - std::string path(c_path); - const char *ends[] = {"bin\\Release", "bin\\Build", NULL}; - return (removeStringEnd(path, ends) != ""); + return false; } -void initializePaths() +#endif + + +//// Non-Windows +#if !defined(_WIN32) + +const char *getHomeOrFail() { -#if RUN_IN_PLACE - /* - Use relative paths if RUN_IN_PLACE - */ + const char *home = getenv("HOME"); + // In rare cases the HOME environment variable may be unset + FATAL_ERROR_IF(!home, + "Required environment variable HOME is not set"); + return home; +} + +#endif - infostream<<"Using relative paths (RUN_IN_PLACE)"<\AppData\Roaming\" + DWORD len = GetEnvironmentVariable("APPDATA", buf, sizeof(buf)); + FATAL_ERROR_IF(len == 0 || len > sizeof(buf), "Failed to get APPDATA"); - pathRemoveFile(buf, '/'); + path_user = std::string(buf) + DIR_DELIM + PROJECT_NAME_C; + return true; +} - path_share = std::string(buf) + "/.."; - path_user = std::string(buf) + "/.."; - /* - OS X - */ - #elif defined(__APPLE__) +//// Linux +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) - //https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/dyld.3.html - //TODO: Test this code +bool setSystemPaths() +{ char buf[BUFSIZ]; - uint32_t len = sizeof(buf); - assert(_NSGetExecutablePath(buf, &len) != -1); + + 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.empty() && static_sharedir != ".") + trylist.push_back(static_sharedir); - path_share = std::string(buf) + "/.."; - path_user = std::string(buf) + "/.."; + trylist.push_back(bindir + DIR_DELIM ".." DIR_DELIM "share" + DIR_DELIM + PROJECT_NAME); + trylist.push_back(bindir + DIR_DELIM ".."); - /* - FreeBSD - */ - #elif defined(__FreeBSD__) +#ifdef __ANDROID__ + trylist.push_back(path_user); +#endif - int mib[4]; - char buf[BUFSIZ]; - size_t len = sizeof(buf); + for (std::list::const_iterator + i = trylist.begin(); i != trylist.end(); ++i) { + const std::string &trypath = *i; + if (!fs::PathExists(trypath) || + !fs::PathExists(trypath + DIR_DELIM + "builtin")) { + warningstream << "system-wide share not found at \"" + << trypath << "\""<< std::endl; + continue; + } - 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); + // Warn if was not the first alternative + if (i != trylist.begin()) { + warningstream << "system-wide share found at \"" + << trypath << "\"" << std::endl; + } - pathRemoveFile(buf, '/'); + path_share = trypath; + break; + } - path_share = std::string(buf) + "/.."; - path_user = std::string(buf) + "/.."; +#ifndef __ANDROID__ + path_user = std::string(getHomeOrFail()) + DIR_DELIM "." + + PROJECT_NAME; +#endif - #else + return true; +} - //TODO: Get path of executable. This assumes working directory is bin/ - dstream<<"WARNING: Relative path not properly supported on this platform" - <" - len = GetEnvironmentVariable("APPDATA", buf, buflen); - assert(len < buflen); - path_user = std::string(buf) + DIR_DELIM + PROJECT_NAME; +void migrateCachePath() +{ + const std::string local_cache_path = path_user + DIR_DELIM + "cache"; - /* - Linux - */ - #elif defined(linux) + // Delete tmp folder if it exists (it only ever contained + // a temporary ogg file, which is no longer used). + if (fs::PathExists(local_cache_path + DIR_DELIM + "tmp")) + fs::RecursiveDelete(local_cache_path + DIR_DELIM + "tmp"); - // 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; + // Bail if migration impossible + if (path_cache == local_cache_path || !fs::PathExists(local_cache_path) + || fs::PathExists(path_cache)) { + return; } + if (!fs::Rename(local_cache_path, path_cache)) { + errorstream << "Failed to migrate local cache path " + "to system path!" << std::endl; + } +} - // 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 != ".") - trylist.push_back(static_sharedir); - trylist.push_back(bindir + "/../share/" + PROJECT_NAME); - trylist.push_back(bindir + "/.."); +void initializePaths() +{ +#if RUN_IN_PLACE + char buf[BUFSIZ]; - 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'; } - path_share = trypath; - break; + + 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; + + +# ifdef _WIN32 + path_cache = path_user + DIR_DELIM + "cache"; +# else + // 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 && cache_dir[0] != '\0') { + 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 // _WIN32 +#endif // RUN_IN_PLACE + + 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 + /* STATIC_LOCALEDIR may be a generalized path such as /usr/share/locale that + * doesn't necessarily contain our locale files, so check data path first. */ + 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." << std::endl; + } else if (STATIC_LOCALEDIR[0] && fs::PathExists(STATIC_LOCALEDIR)) { + found_localedir = true; + path_locale = STATIC_LOCALEDIR; + infostream << "Using static locale directory " << STATIC_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 +} - path_user = std::string(getenv("HOME")) + "/." + PROJECT_NAME; +//// +//// OS-specific Secure Random +//// - /* - OS X - */ - #elif defined(__APPLE__) +#ifdef WIN32 - // Code based on - // http://stackoverflow.com/questions/516200/relative-paths-not-working-in-xcode-c - CFBundleRef main_bundle = CFBundleGetMainBundle(); - CFURLRef resources_url = CFBundleCopyResourcesDirectoryURL(main_bundle); - char path[PATH_MAX]; - if(CFURLGetFileSystemRepresentation(resources_url, TRUE, (UInt8 *)path, PATH_MAX)) - { - dstream<<"Bundle resource path: "< 32; +#elif defined(__ANDROID__) + openURIAndroid(uri); + return true; +#elif defined(__APPLE__) + const char *argv[] = {"open", uri.c_str(), NULL}; + return posix_spawnp(NULL, "open", NULL, NULL, (char**)argv, + (*_NSGetEnviron())) == 0; +#else + const char *argv[] = {"xdg-open", uri.c_str(), NULL}; + return posix_spawnp(NULL, "xdg-open", NULL, NULL, (char**)argv, environ) == 0; +#endif +} - #endif +bool open_url(const std::string &url) +{ + if (url.substr(0, 7) != "http://" && url.substr(0, 8) != "https://") { + errorstream << "Unable to open browser as URL is missing schema: " << url << std::endl; + return false; + } -#endif // RUN_IN_PLACE + return open_uri(url); } -} //namespace porting +bool open_directory(const std::string &path) +{ + if (!fs::IsDir(path)) { + errorstream << "Unable to open directory as it does not exist: " << path << std::endl; + return false; + } + + return open_uri(path); +} +// Load performance counter frequency only once at startup +#ifdef _WIN32 + +inline double get_perf_freq() +{ + // Also use this opportunity to enable high-res timers + timeBeginPeriod(1); + + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return freq.QuadPart; +} + +double perf_freq = get_perf_freq(); + +#endif + +} //namespace porting