X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fporting.cpp;h=d902d3737048d2b49d8025351a9f24c85e34d1b8;hb=6ccb5835ff55d85156be91473c598eca9d6cb9a6;hp=3c2a5c82488f88dfea5b5b1d9c79c7d0e1b9f417;hpb=c410e9182d322a8c095ef94fbadf4d8f541e6b98;p=dragonfireclient.git diff --git a/src/porting.cpp b/src/porting.cpp index 3c2a5c824..d902d3737 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -25,15 +25,35 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting.h" -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) #include #include + extern char **environ; #elif defined(_WIN32) + #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 #include "config.h" @@ -41,9 +61,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "log.h" #include "util/string.h" -#include "main.h" -#include "settings.h" #include +#include +#include namespace porting { @@ -54,7 +74,7 @@ namespace porting bool g_killed = false; -bool * signal_handler_killstatus(void) +bool *signal_handler_killstatus() { return &g_killed; } @@ -62,193 +82,66 @@ 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<= 702106)) \ - || defined(__linux) || defined(linux) - - cpu_set_t cpuset; - - CPU_ZERO(&cpuset); - CPU_SET(pnumber, &cpuset); - return pthread_setaffinity_np(tid, sizeof(cpuset), &cpuset) == 0; - -#elif defined(__sun) || defined(sun) - - return processor_bind(P_LWPID, MAKE_LWPID_PTHREAD(tid), - pnumber, NULL) == 0; - -#elif defined(_AIX) - - return bindprocessor(BINDTHREAD, (tid_t)tid, pnumber) == 0; - -#elif defined(__hpux) || defined(hpux) - - pthread_spu_t answer; - - return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP, - &answer, pnumber, tid) == 0; - -#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; - -#endif +void signal_handler_init(void) +{ + SetConsoleCtrlHandler((PHANDLER_ROUTINE)event_handler, TRUE); } - -bool threadSetPriority(threadid_t tid, int prio) { -#if defined(_WIN32) - - HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, 0, tid); - if (!hThread) - return false; - - bool success = SetThreadPriority(hThread, prio) != 0; - - CloseHandle(hThread); - return success; - -#else - - struct sched_param sparam; - int policy; - - if (pthread_getschedparam(tid, &policy, &sparam) != 0) - 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 -} /* @@ -258,6 +151,9 @@ bool threadSetPriority(threadid_t tid, int prio) { // Default to RUN_IN_PLACE style relative paths std::string path_share = ".."; std::string path_user = ".."; +std::string path_locale = path_share + DIR_DELIM + "locale"; +std::string path_cache = path_user + DIR_DELIM + "cache"; + std::string getDataPath(const char *subpath) { @@ -276,40 +172,55 @@ void pathRemoveFile(char *path, char delim) path[i] = 0; } -bool detectMSVCBuildDir(char *c_path) +bool detectMSVCBuildDir(const std::string &path) { - std::string path(c_path); - const char *ends[] = {"bin\\Release", "bin\\Build", NULL}; - return (removeStringEnd(path, ends) != ""); + const char *ends[] = { + "bin\\Release", + "bin\\MinSizeRel", + "bin\\RelWithDebInfo", + "bin\\Debug", + "bin\\Build", + NULL + }; + return (!removeStringEnd(path, ends).empty()); } std::string get_sysinfo() { #ifdef _WIN32 - OSVERSIONINFO osvi; + std::ostringstream oss; - std::string tmp; - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osvi); - tmp = osvi.szCSDVersion; - std::replace(tmp.begin(), tmp.end(), ' ', '_'); - - oss << "Windows/" << osvi.dwMajorVersion << "." - << osvi.dwMinorVersion; - if(osvi.szCSDVersion[0]) - oss << "-" << tmp; - oss << " "; + LPSTR filePath = new char[MAX_PATH]; + UINT blockSize; + VS_FIXEDFILEINFO *fixedFileInfo; + + GetSystemDirectoryA(filePath, MAX_PATH); + PathAppendA(filePath, "kernel32.dll"); + + DWORD dwVersionSize = GetFileVersionInfoSizeA(filePath, NULL); + LPBYTE lpVersionInfo = new BYTE[dwVersionSize]; + + GetFileVersionInfoA(filePath, 0, dwVersionSize, lpVersionInfo); + VerQueryValueA(lpVersionInfo, "\\", (LPVOID *)&fixedFileInfo, &blockSize); + + oss << "Windows/" + << HIWORD(fixedFileInfo->dwProductVersionMS) << '.' // Major + << LOWORD(fixedFileInfo->dwProductVersionMS) << '.' // Minor + << HIWORD(fixedFileInfo->dwProductVersionLS) << ' '; // Build + #ifdef _WIN64 oss << "x86_64"; #else BOOL is64 = FALSE; - if(IsWow64Process(GetCurrentProcess(), &is64) && is64) + if (IsWow64Process(GetCurrentProcess(), &is64) && is64) oss << "x86_64"; // 32-bit app on 64-bit OS else oss << "x86"; #endif + delete[] lpVersionInfo; + delete[] filePath; + return oss.str(); #else struct utsname osinfo; @@ -319,249 +230,520 @@ std::string get_sysinfo() #endif } -void initializePaths() + +bool getCurrentWorkingDir(char *buf, size_t len) { -#if RUN_IN_PLACE - /* - Use relative paths if RUN_IN_PLACE - */ +#ifdef _WIN32 + DWORD ret = GetCurrentDirectory(len, buf); + return (ret != 0) && (ret <= len); +#else + return getcwd(buf, len); +#endif +} - infostream<<"Using relative paths (RUN_IN_PLACE)"<= len) + return false; - /* scriptapi no longer allows paths that start with "..", so assuming that - the current working directory is bin/, strip off the last component. */ - char *cwd = getcwd(NULL, 0); - pathRemoveFile(cwd, '/'); - path_share = std::string(cwd); - path_user = std::string(cwd); + return true; +} - #endif -#else // RUN_IN_PLACE +// 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 + +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); - path_user = std::string(buf) + DIR_DELIM + PROJECT_NAME; + // Use "C:\Users\\AppData\Roaming\" + DWORD len = GetEnvironmentVariable("APPDATA", buf, sizeof(buf)); + FATAL_ERROR_IF(len == 0 || len > sizeof(buf), "Failed to get APPDATA"); - /* - Linux - */ - #elif defined(linux) + path_user = std::string(buf) + DIR_DELIM + PROJECT_NAME_C; + return true; +} - // 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__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + +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 + DIR_DELIM + ".." + DIR_DELIM + "share" + DIR_DELIM + PROJECT_NAME); - trylist.push_back(bindir + DIR_DELIM + ".."); - 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 + DIR_DELIM + "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; + + +# 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) { + 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 } -static irr::IrrlichtDevice* device; +//// +//// OS-specific Secure Random +//// -void initIrrlicht(irr::IrrlichtDevice * _device) { - device = _device; +#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; } -#ifndef SERVER -v2u32 getWindowSize() { - return device->getVideoDriver()->getScreenSize(); +#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 -float getDisplayDensity() { - float gui_scaling = g_settings->getFloat("gui_scaling"); - // using Y here feels like a bug, this needs to be discussed later! - if (getWindowSize().Y <= 800) { - return (2.0/3.0) * gui_scaling; - } - if (getWindowSize().Y <= 1280) { - return 1.0 * gui_scaling; +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 +} - return (4.0/3.0) * gui_scaling; +int mt_snprintf(char *buf, const size_t buf_size, const char *fmt, ...) +{ + // https://msdn.microsoft.com/en-us/library/bt7tawza.aspx + // Many of the MSVC / Windows printf-style functions do not support positional + // arguments (eg. "%1$s"). We just forward the call to vsnprintf for sane + // platforms, but defer to _vsprintf_p on MSVC / Windows. + // https://github.com/FFmpeg/FFmpeg/blob/5ae9fa13f5ac640bec113120d540f70971aa635d/compat/msvcrt/snprintf.c#L46 + // _vsprintf_p has to be shimmed with _vscprintf_p on -1 (for an example see + // above FFmpeg link). + va_list args; + va_start(args, fmt); +#ifndef _MSC_VER + int c = vsnprintf(buf, buf_size, fmt, args); +#else // _MSC_VER + int c = _vsprintf_p(buf, buf_size, fmt, args); + if (c == -1) + c = _vscprintf_p(fmt, args); +#endif // _MSC_VER + va_end(args); + return c; } -v2u32 getDisplaySize() { - IrrlichtDevice *nulldevice = createDevice(video::EDT_NULL); +bool openURL(const std::string &url) +{ + if ((url.substr(0, 7) != "http://" && url.substr(0, 8) != "https://") || + url.find_first_of("\r\n") != std::string::npos) { + errorstream << "Invalid url: " << url << std::endl; + return false; + } + +#if defined(_WIN32) + return (intptr_t)ShellExecuteA(NULL, NULL, url.c_str(), NULL, NULL, SW_SHOWNORMAL) > 32; +#elif defined(__ANDROID__) + openURLAndroid(url); + return true; +#elif defined(__APPLE__) + const char *argv[] = {"open", url.c_str(), NULL}; + return posix_spawnp(NULL, "open", NULL, NULL, (char**)argv, + (*_NSGetEnviron())) == 0; +#else + const char *argv[] = {"xdg-open", url.c_str(), NULL}; + return posix_spawnp(NULL, "xdg-open", NULL, NULL, (char**)argv, environ) == 0; +#endif +} - core::dimension2d deskres = nulldevice->getVideoModeList()->getDesktopResolution(); - nulldevice -> drop(); +// Load performance counter frequency only once at startup +#ifdef _WIN32 - return deskres; +inline double get_perf_freq() +{ + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return freq.QuadPart; } + +double perf_freq = get_perf_freq(); + #endif } //namespace porting -