diff --git a/sources/libcore/systemInformation.cpp b/sources/libcore/systemInformation.cpp index b2d74a66..168ef23d 100644 --- a/sources/libcore/systemInformation.cpp +++ b/sources/libcore/systemInformation.cpp @@ -6,202 +6,293 @@ #pragma comment(lib, "PowrProf.lib") // CallNtPowerInformation #pragma comment(lib, "Advapi32.lib") // RegGetValue #else - #include - #include - #include + #include + #include // getenv + #include + #include #endif +#include // currentProcessId +#include +#include #include #include namespace cage { - String systemName() +#ifndef CAGE_SYSTEM_WINDOWS + namespace { -#ifdef CAGE_SYSTEM_WINDOWS - static_assert(sizeof(DWORD) == sizeof(uint32)); - const auto &readUint = [](StringPointer name) -> uint32 - { - uint32 res = 0; - DWORD sz = sizeof(res); - auto ret = RegGetValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", name, RRF_RT_REG_DWORD, nullptr, &res, &sz); - if (ret != ERROR_SUCCESS) - return 0; - return res; - }; - const auto &readString = [](StringPointer name) -> String - { - String res; - DWORD sz = String::MaxLength; - auto ret = RegGetValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", name, RRF_RT_REG_SZ, nullptr, res.rawData(), &sz); - if (ret != ERROR_SUCCESS) - res.rawLength() = 0; - else - res.rawLength() = sz - 1; - return res; - }; - return Stringizer() + readString("ProductName") + " " + readString("DisplayVersion") + " (" + readString("CurrentVersion") + ", " + readUint("CurrentMajorVersionNumber") + "." + readUint("CurrentMinorVersionNumber") + ", " + readString("CurrentBuildNumber") + ", " + readString("EditionID") + ", " + readString("InstallationType") + ")"; -#else - Holder prg = newProcess(String("lsb_release -d")); - String newName = prg->readLine(); - if (!isPattern(newName, "Description", "", "")) + std::string getFile(const String &path) { - // lsb_release is not installed, let's at least return full uname - prg = newProcess(String("uname -a")); - return prg->readLine(); + Holder f = readFile(path); + std::string res; + try + { + detail::OverrideException o; + while (true) + { + char c = 0; + f->read(PointerRange(&c, &c + 1)); + res += c; + } + } + catch (...) + { + // done + } + return res; } - newName = remove(newName, 0, String("Description:").length()); - String systemName = trim(newName); - - prg = newProcess(String("lsb_release -r")); - newName = remove(prg->readLine(), 0, String("Release:").length()); - systemName = systemName + " " + trim(newName); - - prg = newProcess(String("uname -r")); - systemName = systemName + ", kernel " + prg->readLine(); + std::string grepLine(const std::string &data, const char *pattern) + { + std::istringstream stream(data); + std::string line; + while (std::getline(stream, line)) + { + auto p = line.find(pattern); + if (p != std::string::npos) + return line; + } + return ""; + } + } +#endif - return systemName; + String systemName() + { + try + { +#ifdef CAGE_SYSTEM_WINDOWS + static_assert(sizeof(DWORD) == sizeof(uint32)); + const auto &readUint = [](StringPointer name) -> uint32 + { + uint32 res = 0; + DWORD sz = sizeof(res); + auto ret = RegGetValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", name, RRF_RT_REG_DWORD, nullptr, &res, &sz); + if (ret != ERROR_SUCCESS) + return 0; + return res; + }; + const auto &readString = [](StringPointer name) -> String + { + String res; + DWORD sz = String::MaxLength; + auto ret = RegGetValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", name, RRF_RT_REG_SZ, nullptr, res.rawData(), &sz); + if (ret != ERROR_SUCCESS) + res.rawLength() = 0; + else + res.rawLength() = sz - 1; + return res; + }; + return Stringizer() + readString("ProductName") + " " + readString("DisplayVersion") + " (" + readString("CurrentVersion") + ", " + readUint("CurrentMajorVersionNumber") + "." + readUint("CurrentMinorVersionNumber") + ", " + readString("CurrentBuildNumber") + ", " + readString("EditionID") + ", " + readString("InstallationType") + ")"; +#else + std::string name = getFile("/etc/os-release"); + name = grepLine(name, "PRETTY_NAME"); + String n = name.c_str(); + split(n, "="); + n = replace(n, "\"", ""); + std::string kernel = getFile("/proc/sys/kernel/osrelease"); + return Stringizer() + n + ", kernel: " + trim(String(kernel.c_str())); #endif + } + catch (...) + { + return ""; + } } String userName() { + try + { #ifdef CAGE_SYSTEM_WINDOWS - char buf[String::MaxLength]; - buf[0] = 0; - DWORD siz = String::MaxLength - 1; - if (!GetUserName(buf, &siz)) - CAGE_THROW_ERROR(SystemError, "GetUserName", GetLastError()); - return buf; + char buf[String::MaxLength]; + buf[0] = 0; + DWORD siz = String::MaxLength - 1; + if (!GetUserName(buf, &siz)) + CAGE_THROW_ERROR(SystemError, "GetUserName", GetLastError()); + return buf; #else - Holder prg = newProcess(String("whoami")); - return prg->readLine(); + const char *name = getenv("USER"); + if (!name) + name = getenv("LOGNAME"); + return name; #endif + } + catch (...) + { + return ""; + } } String hostName() { + try + { #ifdef CAGE_SYSTEM_WINDOWS - char buf[String::MaxLength]; - buf[0] = 0; - DWORD siz = String::MaxLength - 1; - if (!GetComputerName(buf, &siz)) - CAGE_THROW_ERROR(SystemError, "GetComputerName", GetLastError()); - return buf; + char buf[String::MaxLength]; + buf[0] = 0; + DWORD siz = String::MaxLength - 1; + if (!GetComputerName(buf, &siz)) + CAGE_THROW_ERROR(SystemError, "GetComputerName", GetLastError()); + return buf; #else - Holder prg = newProcess(String("hostname")); - return prg->readLine(); + return trim(String(getFile("/proc/sys/kernel/hostname").c_str())); #endif + } + catch (...) + { + return ""; + } } String processorName() { + try + { #ifdef CAGE_SYSTEM_WINDOWS - // https://vcpptips.wordpress.com/2012/12/30/how-to-get-the-cpu-name/ - sint32 CPUInfo[4] = { -1 }; - __cpuid(CPUInfo, 0x80000000); - uint32 nExIds = CPUInfo[0]; - char CPUBrandString[0x40]; - memset(CPUBrandString, 0, sizeof(CPUBrandString)); - for (int i = 0; i < 3; i++) - { - if (0x80000002 + i > nExIds) - break; - __cpuid(CPUInfo, 0x80000002 + i); - memcpy(CPUBrandString + (16 * i), CPUInfo, sizeof(CPUInfo)); - } - return CPUBrandString; + // https://vcpptips.wordpress.com/2012/12/30/how-to-get-the-cpu-name/ + sint32 CPUInfo[4] = { -1 }; + __cpuid(CPUInfo, 0x80000000); + uint32 nExIds = CPUInfo[0]; + char CPUBrandString[0x40]; + memset(CPUBrandString, 0, sizeof(CPUBrandString)); + for (int i = 0; i < 3; i++) + { + if (0x80000002 + i > nExIds) + break; + __cpuid(CPUInfo, 0x80000002 + i); + memcpy(CPUBrandString + (16 * i), CPUInfo, sizeof(CPUInfo)); + } + return CPUBrandString; #else - Holder prg = newProcess(String("cat /proc/cpuinfo | grep -m 1 'model name' | cut -d: -f2-")); - return trim(prg->readLine()); + std::string cpu = getFile("/proc/cpuinfo"); + cpu = grepLine(cpu, "model name"); + String c = cpu.c_str(); + split(c, ":"); + c = trim(c); + return c; #endif + } + catch (...) + { + return ""; + } } uint64 processorClockSpeed() { -#ifdef CAGE_SYSTEM_WINDOWS - // is there any better way than using CallNtPowerInformation? - struct PPI - { - ULONG Number; - ULONG MaxMhz; - ULONG CurrentMhz; - ULONG MhzLimit; - ULONG MaxIdleState; - ULONG CurrentIdleState; - } ppi[32]; - memset(&ppi, 0, sizeof(ppi)); - auto ret = CallNtPowerInformation(ProcessorInformation, nullptr, 0, &ppi, sizeof(ppi)); - if (ret != 0) - CAGE_THROW_ERROR(SystemError, "CallNtPowerInformation", ret); - return ppi[0].MaxMhz * uint64(1000000); -#else try { - detail::OverrideBreakpoint ob; - Holder prg = newProcess(String("cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq")); - return toUint32(prg->readLine()) * 1000; +#ifdef CAGE_SYSTEM_WINDOWS + // is there any better way than using CallNtPowerInformation? + struct PPI + { + ULONG Number; + ULONG MaxMhz; + ULONG CurrentMhz; + ULONG MhzLimit; + ULONG MaxIdleState; + ULONG CurrentIdleState; + } ppi[32]; + memset(&ppi, 0, sizeof(ppi)); + auto ret = CallNtPowerInformation(ProcessorInformation, nullptr, 0, &ppi, sizeof(ppi)); + if (ret != 0) + CAGE_THROW_ERROR(SystemError, "CallNtPowerInformation", ret); + return ppi[0].MaxMhz * uint64(1000000); +#else + std::string cpu = getFile("/proc/cpuinfo"); + cpu = grepLine(cpu, "cpu MHz"); + String c = cpu.c_str(); + split(c, ":"); + c = trim(c); + return toDouble(c) * 1'000'000; +#endif } - catch (const cage::Exception &) + catch (...) { - // When the cpufreq driver is not loaded (file above does not exist), the CPU should be running on full speed + return 0; } - - Holder prg = newProcess(String("cat /proc/cpuinfo | grep -m 1 'cpu MHz' | cut -d: -f2-")); - return numeric_cast(toDouble(trim(prg->readLine())) * 1e6); -#endif } uint64 memoryCapacity() { + try + { #ifdef CAGE_SYSTEM_WINDOWS - MEMORYSTATUSEX m; - m.dwLength = sizeof(m); - if (!GlobalMemoryStatusEx(&m)) - CAGE_THROW_ERROR(SystemError, "GlobalMemoryStatusEx", GetLastError()); - return m.ullTotalPhys; + MEMORYSTATUSEX m; + m.dwLength = sizeof(m); + if (!GlobalMemoryStatusEx(&m)) + CAGE_THROW_ERROR(SystemError, "GlobalMemoryStatusEx", GetLastError()); + return m.ullTotalPhys; #else - Holder prg = newProcess(String("cat /proc/meminfo | grep -m 1 'MemTotal' | awk '{print $2}'")); - return toUint64(prg->readLine()) * 1024; + std::string mem = getFile("/proc/meminfo"); + mem = grepLine(mem, "MemTotal"); + String c = mem.c_str(); + split(c, ":"); + c = trim(c); + c = split(c); // split kB + c = trim(c); + return toUint64(c) * 1024; #endif + } + catch (...) + { + return 0; + } } uint64 memoryAvailable() { -#ifdef CAGE_SYSTEM_WINDOWS - MEMORYSTATUSEX m; - m.dwLength = sizeof(m); - if (!GlobalMemoryStatusEx(&m)) - CAGE_THROW_ERROR(SystemError, "GlobalMemoryStatusEx", GetLastError()); - return m.ullAvailPhys; -#else try { - detail::OverrideBreakpoint ob; - Holder prg = newProcess(String("cat /proc/meminfo | grep -m 1 'MemAvailable' | awk '{print $2}'")); - return toUint64(prg->readLine()) * 1024; +#ifdef CAGE_SYSTEM_WINDOWS + MEMORYSTATUSEX m; + m.dwLength = sizeof(m); + if (!GlobalMemoryStatusEx(&m)) + CAGE_THROW_ERROR(SystemError, "GlobalMemoryStatusEx", GetLastError()); + return m.ullAvailPhys; +#else + std::string mem = getFile("/proc/meminfo"); + mem = grepLine(mem, "MemAvailable"); + String c = mem.c_str(); + split(c, ":"); + c = trim(c); + c = split(c); // split kB + c = trim(c); + return toUint64(c) * 1024; +#endif } - catch (const cage::Exception &) + catch (...) { - // On some systems the "MemAvailable" is not present, in which case continue to look for "MemFree" + return 0; } - - Holder prg = newProcess(String("cat /proc/meminfo | grep -m 1 'MemFree' | awk '{print $2}'")); - return toUint64(prg->readLine()) * 1024; -#endif } uint64 memoryUsed() { + try + { #ifdef CAGE_SYSTEM_WINDOWS - PROCESS_MEMORY_COUNTERS m; - if (GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m)) == 0) - CAGE_THROW_ERROR(SystemError, "GetProcessMemoryInfo", GetLastError()); - return m.WorkingSetSize; + PROCESS_MEMORY_COUNTERS m; + if (GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m)) == 0) + CAGE_THROW_ERROR(SystemError, "GetProcessMemoryInfo", GetLastError()); + return m.WorkingSetSize; #else - Holder prg = newProcess({ Stringizer() + "cat /proc/" + currentProcessId() + "/status | grep -m 1 'VmRSS' | awk '{print $2}'" }); - return toUint64(prg->readLine()) * 1024; + std::string mem = getFile(Stringizer() + "/proc/" + currentProcessId() + "/status"); + mem = grepLine(mem, "VmRSS"); + String c = mem.c_str(); + split(c); + c = trim(c); + c = split(c); // split kB + c = trim(c); + return toUint64(c) * 1024; #endif + } + catch (...) + { + return 0; + } } } diff --git a/sources/test-core/systemInformation.cpp b/sources/test-core/systemInformation.cpp index cc3350d9..3cdb9a91 100644 --- a/sources/test-core/systemInformation.cpp +++ b/sources/test-core/systemInformation.cpp @@ -48,7 +48,7 @@ void testSystemInformation() h.clear(); const uint64 c = memoryUsed() / 1024 / 1024; CAGE_LOG(SeverityEnum::Info, "info", Stringizer() + "a: " + a + ", b: " + b + ", c: " + c + " MB"); - CAGE_TEST(a > 10); + CAGE_TEST(a > 5); CAGE_TEST(b > a + 10); } }