| /** | 
 |  * | 
 |  * Licensed to the Apache Software Foundation (ASF) under one or more | 
 |  * contributor license agreements.  See the NOTICE file distributed with | 
 |  * this work for additional information regarding copyright ownership. | 
 |  * The ASF licenses this file to You under the Apache License, Version 2.0 | 
 |  * (the "License"); you may not use this file except in compliance with | 
 |  * the License.  You may obtain a copy of the License at | 
 |  * | 
 |  *     http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include "utils/OsUtils.h" | 
 |  | 
 | #include <iostream> | 
 | #include <map> | 
 |  | 
 | #include "utils/gsl.h" | 
 | #include "Exception.h" | 
 |  | 
 | #ifdef __linux__ | 
 | #include <sys/sysinfo.h> | 
 | #include <cstdlib> | 
 | #include <optional> | 
 | #include <sstream> | 
 | #endif | 
 |  | 
 | #ifdef _WIN32 | 
 | #ifndef WIN32_LEAN_AND_MEAN | 
 | #define WIN32_LEAN_AND_MEAN | 
 | #endif | 
 | #include <Windows.h> | 
 | #include <sddl.h> | 
 | #include <psapi.h> | 
 | #include <winsock2.h> | 
 | #include <vector> | 
 | #include <algorithm> | 
 | #include <WS2tcpip.h> | 
 | #pragma comment(lib, "Ws2_32.lib") | 
 | #else | 
 | #include <sys/utsname.h> | 
 | #include <pwd.h> | 
 | #include <sys/types.h> | 
 | #include <arpa/inet.h> | 
 | #include <unistd.h> | 
 | #include <fstream> | 
 | #include <cstring> | 
 | #endif | 
 |  | 
 | #ifdef __APPLE__ | 
 | #include <mach/mach.h> | 
 | #include <sys/sysctl.h> | 
 | #endif | 
 |  | 
 | namespace org::apache::nifi::minifi::utils { | 
 |  | 
 | #ifdef _WIN32 | 
 | /* | 
 |  These are common translations for SIDs in windows | 
 |  */ | 
 | std::string OsUtils::resolve_common_identifiers(const std::string &id) { | 
 |   static std::map<std::string, std::string> nameMap; | 
 |   if (nameMap.empty()) { | 
 |     nameMap["S-1-0"] = "Null Authority"; | 
 |     nameMap["S-1-0-0"] = "Nobody"; | 
 |     nameMap["S-1-1-0"] = "Everyone"; | 
 |     nameMap["S-1-2"] = "Local Authority"; | 
 |     nameMap["S-1-2-0"] = "Local"; | 
 |     nameMap["S-1-2-1"] = "Console Logon"; | 
 |     nameMap["S-1-3-0"] = "Creator Owner"; | 
 |     nameMap["S-1-3-1"] = "Creator Group"; | 
 |   } | 
 |   auto name = nameMap.find(id); | 
 |   if (name != std::end(nameMap)) { | 
 |     return name->second; | 
 |   } | 
 |   return ""; | 
 | } | 
 | #endif | 
 |  | 
 | std::string OsUtils::userIdToUsername(const std::string &uid) { | 
 |   std::string name; | 
 |   name = uid; | 
 |   if (!name.empty()) { | 
 | #ifdef _WIN32 | 
 |     const auto resolved_name = resolve_common_identifiers(name); | 
 |     if (!resolved_name.empty()) { | 
 |       return resolved_name; | 
 |     } | 
 |     // First call to LookupAccountSid to get the buffer sizes. | 
 |     PSID pSidOwner = NULL; | 
 |     const auto guard_pSidOwner = gsl::finally([&pSidOwner]() { if (pSidOwner != NULL) { LocalFree(pSidOwner); } }); | 
 |     if (ConvertStringSidToSidA(name.c_str(), &pSidOwner)) { | 
 |       SID_NAME_USE sidType = SidTypeUnknown; | 
 |       DWORD windowsAccountNameSize = 0, dwwindowsDomainSize = 0; | 
 |       /* | 
 |        We can use a unique ptr with a deleter here but some of the calls | 
 |        below require we use global alloc -- so a global deleter to call GlobalFree | 
 |        won't buy us a ton unless we anticipate requiring more of this. If we do | 
 |        I suggest we break this out until a subset of OsUtils into our own convenience functions. | 
 |        */ | 
 |       LPTSTR windowsDomain = NULL; | 
 |       LPTSTR windowsAccount = NULL; | 
 |  | 
 |       /* | 
 |        The first call will be to obtain sizes for domain and account, | 
 |        after which we will allocate the memory and free it after. | 
 |        In some cases youc an replace GlobalAlloc with | 
 |        */ | 
 |       LookupAccountSid(NULL /** local computer **/, pSidOwner, | 
 |           windowsAccount, | 
 |           (LPDWORD)&windowsAccountNameSize, | 
 |           windowsDomain, | 
 |           (LPDWORD)&dwwindowsDomainSize, | 
 |           &sidType); | 
 |  | 
 |       if (windowsAccountNameSize > 0) { | 
 |         windowsAccount = (LPTSTR)GlobalAlloc( | 
 |             GMEM_FIXED, | 
 |             windowsAccountNameSize); | 
 |  | 
 |         if (dwwindowsDomainSize > 0) { | 
 |           windowsDomain = (LPTSTR)GlobalAlloc( | 
 |               GMEM_FIXED, | 
 |               dwwindowsDomainSize); | 
 |         } | 
 |  | 
 |         if (LookupAccountSid( | 
 |                 NULL, | 
 |                 pSidOwner, | 
 |                 windowsAccount, | 
 |                 (LPDWORD)&windowsAccountNameSize, | 
 |                 windowsDomain, | 
 |                 (LPDWORD)&dwwindowsDomainSize, | 
 |                 &sidType)) { | 
 |           if (dwwindowsDomainSize > 0) { | 
 |             std::string domain = std::string(windowsDomain); | 
 |             name = domain + "\\"; | 
 |             name += std::string(windowsAccount); | 
 |           } else { | 
 |             name = std::string(windowsAccount); | 
 |           } | 
 |         } | 
 |         GlobalFree(windowsAccount); | 
 |         GlobalFree(windowsDomain); | 
 |       } | 
 |     } | 
 | #else | 
 |     auto ptr = name.c_str(); | 
 |     char *end = nullptr;  // it will be unused | 
 |     uid_t ret = std::strtol(ptr, &end, 10); | 
 |     if (ret > 0) { | 
 |       struct passwd pass; | 
 |       struct passwd *result; | 
 |       char localbuf[1024]; | 
 |       if (!getpwuid_r(ret, &pass, localbuf, sizeof localbuf, &result)) { | 
 |         name = pass.pw_name; | 
 |       } | 
 |     } | 
 | #endif | 
 |   } | 
 |   return name; | 
 | } | 
 |  | 
 | int64_t OsUtils::getCurrentProcessPhysicalMemoryUsage() { | 
 | #if defined(__linux__) | 
 |   static const std::string resident_set_size_prefix = "VmRSS:"; | 
 |   std::ifstream status_file("/proc/self/status"); | 
 |   std::string line; | 
 |  | 
 |   while (std::getline(status_file, line)) { | 
 |     if (line.rfind(resident_set_size_prefix, 0) == 0) { | 
 |       std::istringstream resident_set_size_value(line.substr(resident_set_size_prefix.length())); | 
 |       uint64_t memory_usage_in_kBytes; | 
 |       resident_set_size_value >> memory_usage_in_kBytes; | 
 |       return memory_usage_in_kBytes * 1024; | 
 |     } | 
 |   } | 
 |  | 
 |   return -1; | 
 | #elif defined(__APPLE__) | 
 |   task_basic_info tInfo; | 
 |   mach_msg_type_number_t tInfoCount = TASK_BASIC_INFO_COUNT; | 
 |   if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&tInfo, &tInfoCount)) | 
 |     return -1; | 
 |   return tInfo.resident_size; | 
 | #elif defined(WIN32) | 
 |   PROCESS_MEMORY_COUNTERS pmc; | 
 |   if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) | 
 |     return -1; | 
 |   return pmc.WorkingSetSize; | 
 | #else | 
 | #warning "Unsupported platform" | 
 |   return -1; | 
 | #endif | 
 | } | 
 |  | 
 | int64_t OsUtils::getCurrentProcessId() { | 
 | #ifdef WIN32 | 
 |   return int64_t{GetCurrentProcessId()}; | 
 | #else | 
 |   return int64_t{getpid()}; | 
 | #endif | 
 | } | 
 |  | 
 | int64_t OsUtils::getSystemPhysicalMemoryUsage() { | 
 | #if defined(__linux__) | 
 |   const std::string available_memory_prefix = "MemAvailable:"; | 
 |   const std::string total_memory_prefix = "MemTotal:"; | 
 |   std::ifstream meminfo_file("/proc/meminfo"); | 
 |   std::string line; | 
 |  | 
 |   std::optional<uint64_t> total_memory_kByte; | 
 |   std::optional<uint64_t> available_memory_kByte; | 
 |   while ((!total_memory_kByte.has_value() || !available_memory_kByte.has_value()) && std::getline(meminfo_file, line)) { | 
 |     if (line.rfind(total_memory_prefix, 0) == 0) { | 
 |       std::istringstream total_memory_line(line.substr(total_memory_prefix.length())); | 
 |       total_memory_kByte.emplace(0); | 
 |       total_memory_line >> total_memory_kByte.value(); | 
 |     } else if (line.rfind(available_memory_prefix, 0) == 0) { | 
 |       std::istringstream available_memory_line(line.substr(available_memory_prefix.length())); | 
 |       available_memory_kByte.emplace(0); | 
 |       available_memory_line >> available_memory_kByte.value(); | 
 |     } | 
 |   } | 
 |   if (total_memory_kByte.has_value() && available_memory_kByte.has_value()) | 
 |     return (gsl::narrow<int64_t>(total_memory_kByte.value()) - gsl::narrow<int64_t>(available_memory_kByte.value())) * 1024; | 
 |  | 
 |   return -1; | 
 | #elif defined(__APPLE__) | 
 |   vm_size_t page_size; | 
 |   mach_port_t mach_port = mach_host_self(); | 
 |   vm_statistics64_data_t vm_stats; | 
 |   mach_msg_type_number_t count = sizeof(vm_stats) / sizeof(natural_t); | 
 |   if (KERN_SUCCESS == host_page_size(mach_port, &page_size) && | 
 |       KERN_SUCCESS == host_statistics64(mach_port, HOST_VM_INFO, | 
 |                                       (host_info64_t)&vm_stats, &count)) { | 
 |       uint64_t physical_memory_used = ((int64_t)vm_stats.active_count + | 
 |                                (int64_t)vm_stats.wire_count) *  (int64_t)page_size; | 
 |       return physical_memory_used; | 
 |   } | 
 |   return -1; | 
 | #elif defined(WIN32) | 
 |   MEMORYSTATUSEX memory_info; | 
 |   memory_info.dwLength = sizeof(MEMORYSTATUSEX); | 
 |   GlobalMemoryStatusEx(&memory_info); | 
 |   DWORDLONG physical_memory_used = memory_info.ullTotalPhys - memory_info.ullAvailPhys; | 
 |   return physical_memory_used; | 
 | #else | 
 | #warning "Unsupported platform" | 
 |   return -1; | 
 | #endif | 
 | } | 
 |  | 
 | int64_t OsUtils::getSystemTotalPhysicalMemory() { | 
 | #if defined(__linux__) | 
 |   struct sysinfo memory_info{}; | 
 |   sysinfo(&memory_info); | 
 |   uint64_t total_physical_memory = memory_info.totalram; | 
 |   total_physical_memory *= memory_info.mem_unit; | 
 |   return gsl::narrow<int64_t>(total_physical_memory); | 
 | #elif defined(__APPLE__) | 
 |   int mib[2]; | 
 |   int64_t total_physical_memory = 0; | 
 |   mib[0] = CTL_HW; | 
 |   mib[1] = HW_MEMSIZE; | 
 |   size_t length = sizeof(int64_t); | 
 |   sysctl(mib, 2, &total_physical_memory, &length, NULL, 0); | 
 |   return total_physical_memory; | 
 | #elif defined(WIN32) | 
 |   MEMORYSTATUSEX memory_info; | 
 |   memory_info.dwLength = sizeof(MEMORYSTATUSEX); | 
 |   GlobalMemoryStatusEx(&memory_info); | 
 |   DWORDLONG total_physical_memory = memory_info.ullTotalPhys; | 
 |   return total_physical_memory; | 
 | #else | 
 | #warning "Unsupported platform" | 
 |   return -1; | 
 | #endif | 
 | } | 
 |  | 
 | #ifdef WIN32 | 
 | int64_t OsUtils::getTotalPagingFileSize() { | 
 |   MEMORYSTATUSEX memory_info; | 
 |   memory_info.dwLength = sizeof(MEMORYSTATUSEX); | 
 |   GlobalMemoryStatusEx(&memory_info); | 
 |   DWORDLONG total_paging_file_size = memory_info.ullTotalPageFile; | 
 |   return total_paging_file_size; | 
 | } | 
 |  | 
 | std::error_code OsUtils::windowsErrorToErrorCode(DWORD error_code) { | 
 |   return {gsl::narrow_cast<int>(error_code), std::system_category()}; | 
 | } | 
 | #endif | 
 |  | 
 | std::string OsUtils::getMachineArchitecture() { | 
 | #if defined(WIN32) | 
 |   SYSTEM_INFO system_information; | 
 |   GetNativeSystemInfo(&system_information); | 
 |   switch (system_information.wProcessorArchitecture) { | 
 |     case PROCESSOR_ARCHITECTURE_INTEL: | 
 |       return "x32"; | 
 |     case PROCESSOR_ARCHITECTURE_AMD64: | 
 |       return "x64"; | 
 |     case PROCESSOR_ARCHITECTURE_ARM: | 
 |       return "arm32"; | 
 |     case PROCESSOR_ARCHITECTURE_ARM64: | 
 |       return "arm64"; | 
 |     case PROCESSOR_ARCHITECTURE_IA64: | 
 |       return "x64"; | 
 |     default: | 
 |       return "unknown"; | 
 |   } | 
 | #else | 
 |   utsname buf; | 
 |   if (uname(&buf) == -1) | 
 |     return "unknown"; | 
 |   else | 
 |     return buf.machine; | 
 | #endif | 
 |  | 
 |   return "unknown"; | 
 | } | 
 |  | 
 | std::optional<std::string> OsUtils::getHostName() { | 
 |   char hostname[1024]; | 
 |   hostname[1023] = '\0'; | 
 |   if (gethostname(hostname, 1023) != 0) { | 
 |     return std::nullopt; | 
 |   } | 
 |   return {hostname}; | 
 | } | 
 |  | 
 | std::optional<double> OsUtils::getSystemLoadAverage() { | 
 | #ifndef WIN32 | 
 |   double load_avg[1]; | 
 |   auto numSamples = getloadavg(load_avg, 1); | 
 |   if (numSamples == -1) { | 
 |     return std::nullopt; | 
 |   } | 
 |   return load_avg[0]; | 
 | #else | 
 |   return std::nullopt; | 
 | #endif | 
 | } | 
 |  | 
 | }  // namespace org::apache::nifi::minifi::utils |