From fda76a82b93c7dd9e513ff64334dd6117a134230 Mon Sep 17 00:00:00 2001 From: Gabriele Contini <contini.mailing@gmail.com> Date: 周六, 25 4月 2020 21:01:33 +0800 Subject: [PATCH] first docker & vm detection --- src/library/os/linux/execution_environment.cpp | 50 +--- src/library/os/execution_environment_common.cpp | 81 +++++- src/library/hw_identifier/hw_identifier_facade.cpp | 15 - test/library/os_linux_test.cpp | 6 src/library/os/linux/dmi_info.cpp | 35 +++ src/inspector/inspector.cpp | 43 ++- src/library/hw_identifier/hw_identifier.hpp | 18 - test/library/hw_identifier/hw_identifier_test.cpp | 6 src/library/os/linux/os_linux.cpp | 21 - test/library/os/execution_environment_test.cpp | 8 src/library/os/CMakeLists.txt | 15 src/library/os/windows/execution_environment.cpp | 82 ++---- src/library/hw_identifier/hw_identifier.cpp | 13 - src/library/os/windows/dmi_info.cpp | 26 ++ /dev/null | 45 ---- src/library/os/cpu_info.hpp | 5 src/library/os/execution_environment.hpp | 39 +-- src/library/licensecc.cpp | 21 + .travis.yml | 13 src/library/os/dmi_info.hpp | 32 ++ src/library/hw_identifier/default_strategy.cpp | 8 include/licensecc/datatypes.h | 25 ++ include/licensecc/licensecc.h | 8 src/library/base/base64.cpp | 2 24 files changed, 315 insertions(+), 302 deletions(-) diff --git a/.travis.yml b/.travis.yml index 41ee6ad..ef5ebe0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -134,10 +134,10 @@ - p7zip-full before_script: - cd build - - wget -c https://github.com/boostorg/boost/archive/boost-1.71.0.tar.gz - - tar xzf boost-1.71.0.tar.gz + - wget -c https://dl.bintray.com/boostorg/release/1.71.0/source/boost_1_71_0.tar.bz2 + - tar xjf boost_1_71_0.tar.bz2 - sudo ln -s /usr/bin/x86_64-w64-mingw32-g++ /usr/local/bin/g++-mingw - - cd boost-boost-1.71.0 + - cd boost_1_71_0 - ./bootstrap.sh - travis_wait 30 ./b2 toolset=gcc-mingw target-os=windows address-model=64 --with-date_time --with-test --with-filesystem --with-program_options --with-regex --with-serialization --with-system runtime-link=static --prefix=./dist release install - cd .. @@ -177,11 +177,10 @@ echo "Boost already installed" else echo "Boost not cached, compiling it" - wget -q https://github.com/boostorg/boost/archive/boost-1.68.0.tar.gz + wget -q https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.7z echo "Boost downloaded" - 7z x boost-1.68.0.tar.gz - 7z x boost-1.68.0.tar - cd "boost-boost-1.68.0" + travis_wait 20 7z x boost_1_68_0.7z -oC:/local + cd "C:/local/boost_1_68_0" ./bootstrap.bat gcc travis_wait 40 ./b2.exe -d0 --with-date_time --with-test --with-filesystem --with-program_options --with-regex --with-serialization --with-system runtime-link=static toolset=gcc --prefix=${TRAVIS_BUILD_DIR}/boost-mingw install echo "Boost installed" diff --git a/include/licensecc/datatypes.h b/include/licensecc/datatypes.h index 5e80ee6..f99e232 100644 --- a/include/licensecc/datatypes.h +++ b/include/licensecc/datatypes.h @@ -126,6 +126,31 @@ int license_version; // license file version } LicenseInfo; +typedef enum { BARE_TO_METAL, VMWARE, VIRTUALBOX, V_XEN, KVM, HV, V_OTHER } LCC_API_VIRTUALIZATION_DETAIL; + +typedef enum { + PROV_UNKNOWN = 0, + ON_PREMISE = 1, + GOOGLE_CLOUD = 2, + AZURE_CLOUD = 3, + AWS = 4, + /** + * "/sys/class/dmi/id/bios_vendor" SeaBIOS + * "/sys/class/dmi/id/sys_vendor" Alibaba Cloud + * modalias + * "dmi:bvnSeaBIOS:bvrrel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org:bd04/01/2014:svnAlibabaCloud:pnAlibabaCloudECS:pvrpc-i440fx-2.1:cvnAlibabaCloud:ct1:cvrpc-i440fx-2.1:" + */ + ALI_CLOUD = 5 +} LCC_API_CLOUD_PROVIDER; + +typedef enum { NONE, CONTAINER, VM } LCC_API_VIRTUALIZATION_SUMMARY; + +typedef struct { + LCC_API_CLOUD_PROVIDER cloud_provider; + LCC_API_VIRTUALIZATION_SUMMARY virtualization; + LCC_API_VIRTUALIZATION_DETAIL virtualization_detail; +} ExecutionEnvironmentInfo; + #ifdef __cplusplus } #endif diff --git a/include/licensecc/licensecc.h b/include/licensecc/licensecc.h index dc273bd..deea67e 100644 --- a/include/licensecc/licensecc.h +++ b/include/licensecc/licensecc.h @@ -11,8 +11,6 @@ extern "C" { #endif -#include <licensecc_properties.h> - #include "datatypes.h" /** @@ -39,15 +37,17 @@ * wiki for more informations. * @param identifier_out[out] buffer where the identification string will be placed. * @param identifier_out[in-out] size of the buffer where the identification string will be placed. + * @param execution_environment_info[out] if not null will contain the informations about the execution environment. */ -bool identify_pc(LCC_API_HW_IDENTIFICATION_STRATEGY hw_id_method, char* identifier_out, size_t* buf_size); +bool identify_pc(LCC_API_HW_IDENTIFICATION_STRATEGY hw_id_method, char* identifier_out, size_t* buf_size, + ExecutionEnvironmentInfo* execution_environment_info); /** * This method is used to request the use of one license for a product. * In case of local license it's used to check if the product is licensed. * * @return ::LICENSE_OK(0) if successful. Other values if there are errors. - * + * * @param callerInformation[in] * a vendor defined string containing the name of the product we want to request. * @param licenseLocation[in] otpional, can be NULL. diff --git a/src/inspector/inspector.cpp b/src/inspector/inspector.cpp index af9e61c..dd44f76 100644 --- a/src/inspector/inspector.cpp +++ b/src/inspector/inspector.cpp @@ -4,7 +4,7 @@ #include <licensecc/licensecc.h> #include <fstream> #include "../library/os/cpu_info.hpp" -#include "../library/os/execution_environment.hpp" +#include "../library/os/dmi_info.hpp" using namespace std; using namespace license::os; @@ -23,8 +23,10 @@ {HV, "Microsoft Hypervisor"}, {V_OTHER, "Other type of vm"}}; -const unordered_map<int, string> descByVirt = { - {VIRTUALIZATION::NONE, "No virtualization"}, {VIRTUALIZATION::VM, "VM"}, {VIRTUALIZATION::CONTAINER, "Container"}}; +const unordered_map<LCC_API_VIRTUALIZATION_SUMMARY, string> descByVirt = { + {LCC_API_VIRTUALIZATION_SUMMARY::NONE, "No virtualization"}, + {LCC_API_VIRTUALIZATION_SUMMARY::VM, "VM"}, + {LCC_API_VIRTUALIZATION_SUMMARY::CONTAINER, "Container"}}; const unordered_map<int, string> stringByEventType = { {LICENSE_OK, "OK "}, @@ -53,31 +55,32 @@ } int main(int argc, char* argv[]) { - license::os::CpuInfo cpu; - cout << "Cpu Vendor :" << cpu.vendor() << endl; - cout << "Cpu Brand :" << cpu.brand() << endl; - cout << "Cpu is hypervis.:" << cpu.cpu_virtual() << endl; - cout << "Cpu model :0x" << std::hex << ((long)cpu.model()) << std::dec << endl; - cout << "Virt. detail cpu:" << descByVirtDetail.find(cpu.virtualization_details())->second << endl <<endl; - ExecutionEnvironment execEnv; - cout << "Running in cloud:" << execEnv.is_cloud() << endl; - cout << "Docker :" << execEnv.is_docker() << endl; - cout << "other container :" << execEnv.is_container() << endl; - cout << "Virtualiz. class:" << descByVirt.find(execEnv.getVirtualization())->second << endl; - - cout << "Bios vendor :" << execEnv.bios_vendor() << endl; - cout << "Bios description:" << execEnv.bios_description() << endl; - cout << "System vendor :" << execEnv.sys_vendor() << endl <<endl; - char hw_identifier[LCC_API_PC_IDENTIFIER_SIZE + 1]; size_t bufSize = LCC_API_PC_IDENTIFIER_SIZE + 1; + ExecutionEnvironmentInfo exec_env_info; for (const auto& x : stringByStrategyId) { - if (identify_pc(static_cast<LCC_API_HW_IDENTIFICATION_STRATEGY>(x.first), hw_identifier, &bufSize)) { + if (identify_pc(static_cast<LCC_API_HW_IDENTIFICATION_STRATEGY>(x.first), hw_identifier, &bufSize, + &exec_env_info)) { std::cout << x.second << ':' << hw_identifier << std::endl; } else { std::cout << x.second << ": NA" << endl; } } + cout << "Virtualiz. class :" << descByVirt.find(exec_env_info.virtualization)->second << endl; + cout << "Virtualiz. detail:" << descByVirtDetail.find(exec_env_info.virtualization_detail)->second << endl; + cout << "Cloud provider :" << exec_env_info.cloud_provider << endl << "=============" << endl; + ; + license::os::CpuInfo cpu; + cout << "Cpu Vendor :" << cpu.vendor() << endl; + cout << "Cpu Brand :" << cpu.brand() << endl; + cout << "Cpu hypervisor :" << cpu.is_hypervisor_set() << endl; + cout << "Cpu model :0x" << std::hex << ((long)cpu.model()) << std::dec << endl; + license::os::DmiInfo dmi_info; + + cout << "Bios vendor :" << dmi_info.bios_vendor() << endl; + cout << "Bios description:" << dmi_info.bios_description() << endl; + cout << "System vendor :" << dmi_info.sys_vendor() << endl << endl; + if (argc == 2) { const string fname(argv[1]); diff --git a/src/library/base/base64.cpp b/src/library/base/base64.cpp index f508d4a..2245be1 100644 --- a/src/library/base/base64.cpp +++ b/src/library/base/base64.cpp @@ -39,7 +39,7 @@ }; // This array has 255 elements // review api -void add_CR_if_needed(string& encodeBuffer, int lineLenght) { +static void add_CR_if_needed(string& encodeBuffer, int lineLenght) { if (lineLenght > 0 && ((encodeBuffer.size() + 1) % lineLenght) == 0) { encodeBuffer += '\n'; } diff --git a/src/library/hw_identifier/default_strategy.cpp b/src/library/hw_identifier/default_strategy.cpp index b4ab755..2ca1aa4 100644 --- a/src/library/hw_identifier/default_strategy.cpp +++ b/src/library/hw_identifier/default_strategy.cpp @@ -14,16 +14,16 @@ namespace hw_identifier { static vector<LCC_API_HW_IDENTIFICATION_STRATEGY> available_strategies() { - os::ExecutionEnvironment exec; - os::VIRTUALIZATION virtualization = exec.getVirtualization(); + const os::ExecutionEnvironment exec; + LCC_API_VIRTUALIZATION_SUMMARY virtualization = exec.virtualization(); vector<LCC_API_HW_IDENTIFICATION_STRATEGY> strategy_to_try; - if (virtualization == os::CONTAINER) { + if (virtualization == LCC_API_VIRTUALIZATION_SUMMARY::CONTAINER) { if (exec.is_docker()) { strategy_to_try = LCC_DOCKER_STRATEGIES; } else { strategy_to_try = LCC_LXC_STRATEGIES; } - } else if (virtualization == os::VM) { + } else if (virtualization == LCC_API_VIRTUALIZATION_SUMMARY::VM) { if (exec.is_cloud()) { strategy_to_try = LCC_CLOUD_STRATEGIES; } else { diff --git a/src/library/hw_identifier/hw_identifier.cpp b/src/library/hw_identifier/hw_identifier.cpp index 405310e..2b14c3e 100644 --- a/src/library/hw_identifier/hw_identifier.cpp +++ b/src/library/hw_identifier/hw_identifier.cpp @@ -47,19 +47,6 @@ } } -void HwIdentifier::set_virtual_environment(os::VIRTUALIZATION virt) { - // 110000 0x30 - m_data[0] = (m_data[0] & ~0x30) | virt << 4; -} - -void HwIdentifier::set_virtualization(os::VIRTUALIZATION_DETAIL virtualization_detail) { - m_data[0] = (m_data[0] & ~0x0F) | virtualization_detail; -} - -void HwIdentifier::set_cloud_provider(os::CLOUD_PROVIDER cloud_provider) { - m_data[0] = (m_data[0] & ~0x0F) | cloud_provider | 0x08; -} - void HwIdentifier::set_data(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>& data) { m_data[1] = (m_data[1] & (~0x1f)) | (data[0] & 0x1f); for (int i = 1; i < HW_IDENTIFIER_PROPRIETARY_DATA; i++) { diff --git a/src/library/hw_identifier/hw_identifier.hpp b/src/library/hw_identifier/hw_identifier.hpp index c2738b9..73b3fc8 100644 --- a/src/library/hw_identifier/hw_identifier.hpp +++ b/src/library/hw_identifier/hw_identifier.hpp @@ -20,7 +20,7 @@ namespace license { namespace hw_identifier { -#define HW_IDENTIFIER_PROPRIETARY_DATA 8 +#define HW_IDENTIFIER_PROPRIETARY_DATA 7 /** * data[0] @@ -28,16 +28,9 @@ * * if bit 7 = 0 * bit 6 = environment variable was used to generate pc_id - * bit 5-4 = execution environment information (0=BARE_TO_METAL,1=VM,2=CONTAINER) - * bit 3 = 0 on premise vm 1 = cloud - * if on premise vm bits 2-1-0 are virtualization technology - * if cloud vm bits 2-1-0 identify cloud provider - * - * if bit 7 = 1 hardware identifier is used to enable some flag that we don't want to show openly in the license - * bit 6 = 1 enable magic file/registry key - * ---- - * data[1] bit 7-6-5 define identification strategy. - * data[1] bits 4-0, data[2-8] are hardware identifier proprietary strategy data. + * bit 5-4-3 define identification strategy. + * bit 2-1-0 unused (crc?) + * data[1-7] are hardware identifier proprietary strategy data. */ class HwIdentifier { @@ -53,9 +46,6 @@ void set_identification_strategy(LCC_API_HW_IDENTIFICATION_STRATEGY strategy); LCC_API_HW_IDENTIFICATION_STRATEGY get_identification_strategy() const; void set_use_environment_var(bool use_env_var); - void set_virtual_environment(os::VIRTUALIZATION virtualization); - void set_virtualization(os::VIRTUALIZATION_DETAIL virtualization_detail); - void set_cloud_provider(os::CLOUD_PROVIDER cloud_provider); void set_data(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> &data); bool data_match(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> &data) const; std::string print() const; diff --git a/src/library/hw_identifier/hw_identifier_facade.cpp b/src/library/hw_identifier/hw_identifier_facade.cpp index 0b834db..a64ba58 100644 --- a/src/library/hw_identifier/hw_identifier_facade.cpp +++ b/src/library/hw_identifier/hw_identifier_facade.cpp @@ -12,8 +12,6 @@ #include "../base/base.h" #include "../base/logger.h" -#include "../os/cpu_info.hpp" -#include "../os/execution_environment.hpp" #include "identification_strategy.hpp" #include "hw_identifier.hpp" @@ -56,19 +54,6 @@ FUNCTION_RETURN result = strategy_ptr->generate_pc_id(pc_id); if (result != FUNC_RET_OK) { throw logic_error("strategy " + to_string(strategy_ptr->identification_strategy()) + " failed"); - } - os::ExecutionEnvironment exec; - os::VIRTUALIZATION virtualization = exec.getVirtualization(); - pc_id.set_virtual_environment(virtualization); - pc_id.set_use_environment_var(use_env_var); - if (virtualization != os::NONE) { - bool isCloud = exec.is_cloud(); - if (isCloud) { - pc_id.set_cloud_provider(exec.getCloudProvider()); - } else { - os::CpuInfo cpu; - pc_id.set_virtualization(cpu.virtualization_details()); - } } return pc_id.print(); } diff --git a/src/library/licensecc.cpp b/src/library/licensecc.cpp index 7736df2..dd377e1 100644 --- a/src/library/licensecc.cpp +++ b/src/library/licensecc.cpp @@ -19,31 +19,37 @@ #include "base/logger.h" #include "hw_identifier/hw_identifier_facade.hpp" +#include "os/execution_environment.hpp" #include "limits/license_verifier.hpp" #include "base/StringUtils.h" #include "LicenseReader.hpp" using namespace std; - void print_error(char out_buffer[LCC_API_ERROR_BUFFER_SIZE], LicenseInfo* licenseInfo) {} -bool identify_pc(LCC_API_HW_IDENTIFICATION_STRATEGY pc_id_method, char* chbuffer, size_t* bufSize) { +bool identify_pc(LCC_API_HW_IDENTIFICATION_STRATEGY pc_id_method, char* chbuffer, size_t* bufSize, + ExecutionEnvironmentInfo* execution_environment_info) { bool result = false; if (*bufSize > LCC_API_PC_IDENTIFIER_SIZE && chbuffer != nullptr) { try { - string pc_id = license::hw_identifier::HwIdentifierFacade::generate_user_pc_signature(pc_id_method); + const string pc_id = license::hw_identifier::HwIdentifierFacade::generate_user_pc_signature(pc_id_method); strncpy(chbuffer, pc_id.c_str(), *bufSize); result = true; } catch (const std::exception& ex) { LOG_ERROR("Error calculating hw_identifier: %s", ex.what()); #ifdef _DEBUG - cout - << "Error occurred: " << ex.what() << std::endl; + cout << "Error occurred: " << ex.what() << std::endl; #endif } } else { *bufSize = LCC_API_PC_IDENTIFIER_SIZE + 1; + } + if (execution_environment_info != nullptr) { + const license::os::ExecutionEnvironment exec_env; + execution_environment_info->cloud_provider = exec_env.cloud_provider(); + execution_environment_info->virtualization = exec_env.virtualization(); + execution_environment_info->virtualization_detail = exec_env.virtualization_detail(); } return result; } @@ -64,8 +70,8 @@ } } -LCC_EVENT_TYPE acquire_license(const CallerInformations* callerInformation, - const LicenseLocation* licenseLocation, LicenseInfo* license_out) { +LCC_EVENT_TYPE acquire_license(const CallerInformations* callerInformation, const LicenseLocation* licenseLocation, + LicenseInfo* license_out) { const license::LicenseReader lr = license::LicenseReader(licenseLocation); vector<license::FullLicenseInfo> licenses; string project; @@ -129,4 +135,3 @@ LCC_EVENT_TYPE confirm_license(char* product, LicenseLocation licenseLocation) { return LICENSE_OK; } LCC_EVENT_TYPE release_license(char* product, LicenseLocation licenseLocation) { return LICENSE_OK; } - diff --git a/src/library/os/CMakeLists.txt b/src/library/os/CMakeLists.txt index 7244e0d..1613ea6 100644 --- a/src/library/os/CMakeLists.txt +++ b/src/library/os/CMakeLists.txt @@ -4,16 +4,18 @@ openssl/signature_verifier.cpp execution_environment_common.cpp linux/execution_environment.cpp - cpu_info_common.cpp linux/cpu_info.cpp + linux/dmi_info.cpp linux/network.cpp linux/os_linux.cpp) ELSE(UNIX) #windows and openssl add_library(os OBJECT - cpu_info_common.cpp windows/cpu_info.cpp + windows/cpu_info.cpp + windows/dmi_info.cpp openssl/signature_verifier.cpp - execution_environment_common.cpp windows/execution_environment.cpp + execution_environment_common.cpp + windows/execution_environment.cpp windows/isvm/Native.cpp windows/isvm/BIOSReader.cpp windows/os_win.cpp @@ -23,10 +25,11 @@ ELSE(UNIX OR OPENSSL_FOUND) #windows no openssl add_library(os OBJECT - cpu_info_common.cpp - windows/cpu_info.cpp + windows/cpu_info.cpp + windows/dmi_info.cpp windows/signature_verifier.cpp - execution_environment_common.cpp windows/execution_environment.cpp + execution_environment_common.cpp + windows/execution_environment.cpp windows/isvm/Native.cpp windows/isvm/BIOSReader.cpp windows/os_win.cpp diff --git a/src/library/os/cpu_info.hpp b/src/library/os/cpu_info.hpp index a35de10..c837493 100644 --- a/src/library/os/cpu_info.hpp +++ b/src/library/os/cpu_info.hpp @@ -10,14 +10,12 @@ #include <string> namespace license { namespace os { -typedef enum { BARE_TO_METAL, VMWARE, VIRTUALBOX, V_XEN, KVM, HV, V_OTHER } VIRTUALIZATION_DETAIL; /** * Cpu informations */ class CpuInfo { private: - bool is_hypervisor_set() const; const std::string m_vendor; const std::string m_brand; public: @@ -27,11 +25,10 @@ * Detect Virtual machine using hypervisor bit or the cpu vendor name. * @return true if the cpu is detected to be a virtual cpu */ - bool cpu_virtual() const; uint32_t model() const; + bool is_hypervisor_set() const; const std::string& vendor() const { return m_vendor; } const std::string& brand() const { return m_brand; } - VIRTUALIZATION_DETAIL virtualization_details() const; }; } // namespace os diff --git a/src/library/os/cpu_info_common.cpp b/src/library/os/cpu_info_common.cpp deleted file mode 100644 index 1ddf5ba..0000000 --- a/src/library/os/cpu_info_common.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * cpu_info_common.cpp - * - * Created on: Jan 19, 2020 - * Author: GC - */ -#include <unordered_map> -#include "cpu_info.hpp" - -namespace license { -namespace os { -using namespace std; - -const unordered_map<string, VIRTUALIZATION_DETAIL> virtual_cpu_names{ - {"bhyve bhyve ", V_OTHER}, {"KVMKVMKVM", KVM}, {"Microsoft Hv", HV}, - {" lrpepyh vr", HV}, {"prl hyperv ", V_OTHER}, {"VMwareVMware", VMWARE}, - {"XenVMMXenVMM", V_XEN}, {"ACRNACRNACRN", V_OTHER}, {"VBoxVBoxVBox", VIRTUALBOX}}; - -/** - * Detect Virtual machine using hypervisor bit. - * @return true if the cpu hypervisor bit is set to 1 - */ -bool CpuInfo::cpu_virtual() const { - bool is_virtual = is_hypervisor_set(); - if (!is_virtual) { - string cpu_vendor = vendor(); - auto it = virtual_cpu_names.find(cpu_vendor); - is_virtual = (it != virtual_cpu_names.end()); - } - return is_virtual; -} - -VIRTUALIZATION_DETAIL CpuInfo::virtualization_details() const { - string cpu_vendor = vendor(); - auto it = virtual_cpu_names.find(cpu_vendor); - VIRTUALIZATION_DETAIL result = BARE_TO_METAL; - if (it != virtual_cpu_names.end()) { - result = it->second; - } else if (is_hypervisor_set()) { - result = (VIRTUALIZATION_DETAIL)V_OTHER; - } - return result; -} -} // namespace os -} // namespace license diff --git a/src/library/os/dmi_info.hpp b/src/library/os/dmi_info.hpp new file mode 100644 index 0000000..94c7a3c --- /dev/null +++ b/src/library/os/dmi_info.hpp @@ -0,0 +1,32 @@ +/* + * dmi_info.hpp + * + * Created on: Apr 24, 2020 + * Author: devel + */ + +#ifndef SRC_LIBRARY_OS_DMI_INFO_HPP_ +#define SRC_LIBRARY_OS_DMI_INFO_HPP_ + +#include <string> + +namespace license { +namespace os { +class DmiInfo { +private: + std::string m_sys_vendor; + std::string m_bios_vendor; + std::string m_bios_description; + +public: + DmiInfo(); + virtual ~DmiInfo(){}; + const std::string& bios_vendor() const { return m_bios_vendor; }; + const std::string& sys_vendor() const { return m_sys_vendor; }; + const std::string& bios_description() const { return m_bios_description; }; +}; + +} // namespace os +} /* namespace license */ + +#endif /* SRC_LIBRARY_OS_DMI_INFO_HPP_ */ diff --git a/src/library/os/execution_environment.hpp b/src/library/os/execution_environment.hpp index 97172e4..f52f8db 100644 --- a/src/library/os/execution_environment.hpp +++ b/src/library/os/execution_environment.hpp @@ -9,6 +9,9 @@ #define SRC_LIBRARY_OS_VIRTUALIZATION_HPP_ #include <string> +#include <licensecc/datatypes.h> +#include "dmi_info.hpp" +#include "cpu_info.hpp" namespace license { namespace os { @@ -19,42 +22,24 @@ "VMware", "Microsoft Corporation", "Virtual Machine", "innotek GmbH", "PowerVM", "Bochs", "KVM"}; */ -typedef enum { NONE, CONTAINER, VM } VIRTUALIZATION; - -typedef enum { - PROV_UNKNOWN, - ON_PREMISE, - GOOGLE_CLOUD, - AZURE_CLOUD, - AWS, - /** - * "/sys/class/dmi/id/bios_vendor" SeaBIOS - * "/sys/class/dmi/id/sys_vendor" Alibaba Cloud - * modalias - * "dmi:bvnSeaBIOS:bvrrel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org:bd04/01/2014:svnAlibabaCloud:pnAlibabaCloudECS:pvrpc-i440fx-2.1:cvnAlibabaCloud:ct1:cvrpc-i440fx-2.1:" - */ - ALI_CLOUD -} CLOUD_PROVIDER; +enum CONTAINER_TYPE { NONE, DOCKER, LXC }; class ExecutionEnvironment { private: - std::string m_sys_vendor; - std::string m_bios_vendor; - std::string m_bios_description; + const CpuInfo m_cpu_info; + const DmiInfo m_dmi_info; + const CONTAINER_TYPE m_container_type; public: ExecutionEnvironment(); ~ExecutionEnvironment(){}; - VIRTUALIZATION getVirtualization() const; + LCC_API_VIRTUALIZATION_SUMMARY virtualization() const; bool is_cloud() const; - bool is_docker() const; + bool is_docker() const { return m_container_type != DOCKER; } // detect if it's a kind of container technology (docker or lxc) - bool is_container() const; - CLOUD_PROVIDER getCloudProvider() const; - const std::string& bios_vendor() const { return m_bios_vendor; }; - const std::string& sys_vendor() const { return m_sys_vendor; }; - const std::string& bios_description() const { return m_bios_description; }; - // VIRTUALIZATION_DETAIL getVirtualizationDetail() const; //as reported by the bios + bool is_container() const { return m_container_type != NONE; } + LCC_API_CLOUD_PROVIDER cloud_provider() const; + LCC_API_VIRTUALIZATION_DETAIL virtualization_detail() const; }; } // namespace os diff --git a/src/library/os/execution_environment_common.cpp b/src/library/os/execution_environment_common.cpp index 06f5c56..5f8d1bf 100644 --- a/src/library/os/execution_environment_common.cpp +++ b/src/library/os/execution_environment_common.cpp @@ -8,6 +8,7 @@ #include <string.h> #include <unordered_map> #include <array> +#include <licensecc/datatypes.h> #include "../base/base.h" #include "cpu_info.hpp" @@ -17,39 +18,83 @@ namespace os { using namespace std; -VIRTUALIZATION ExecutionEnvironment::getVirtualization() const { - VIRTUALIZATION result; - CpuInfo cpuInfo; +const unordered_map<string, LCC_API_VIRTUALIZATION_DETAIL> virtual_cpu_names{ + {"bhyve bhyve ", V_OTHER}, {"KVM", KVM}, {"MICROSOFT", HV}, {" lrpepyh vr", HV}, + {"prl hyperv ", V_OTHER}, {"VMWARE", VMWARE}, {"XenVMMXenVMM", V_XEN}, {"ACRNACRNACRN", V_OTHER}, + {"VBOX", VIRTUALBOX}}; + +const unordered_map<string, LCC_API_VIRTUALIZATION_DETAIL> vm_vendors{{"VMWARE", VMWARE}, + {"MICROSOFT", HV}, + {"VITRUAL MACHINE", V_OTHER}, + {"INNOTEK GMBH", V_OTHER}, + {"POWERVM", V_OTHER}, + {"BOCHS", V_OTHER}, + {"KVM", KVM}}; + +static LCC_API_VIRTUALIZATION_DETAIL find_in_map(const unordered_map<string, LCC_API_VIRTUALIZATION_DETAIL>& map, const string& data) { + for (auto it : map) { + if (data.find(it.first) != string::npos) { + return it.second; + } + } + return BARE_TO_METAL; +} + +LCC_API_VIRTUALIZATION_SUMMARY ExecutionEnvironment::virtualization() const { + LCC_API_VIRTUALIZATION_SUMMARY result; bool isContainer = is_container(); if (isContainer) { - result = CONTAINER; - } else if (cpuInfo.cpu_virtual() || is_cloud()) { - result = VM; + result = LCC_API_VIRTUALIZATION_SUMMARY::CONTAINER; + } else if (virtualization_detail() != BARE_TO_METAL || is_cloud()) { + result = LCC_API_VIRTUALIZATION_SUMMARY::VM; } else { - result = NONE; + result = LCC_API_VIRTUALIZATION_SUMMARY::NONE; + } + return result; +} + +LCC_API_VIRTUALIZATION_DETAIL ExecutionEnvironment::virtualization_detail() const { + LCC_API_VIRTUALIZATION_DETAIL result = BARE_TO_METAL; + const string bios_description = m_dmi_info.bios_description(); + const string bios_vendor = m_dmi_info.bios_vendor(); + const string sys_vendor = m_dmi_info.sys_vendor(); + if ((result = find_in_map(vm_vendors, bios_description)) == BARE_TO_METAL) { + if ((result = find_in_map(vm_vendors, bios_vendor)) == BARE_TO_METAL) { + if ((result = find_in_map(vm_vendors, sys_vendor)) == BARE_TO_METAL) { + if ((result = find_in_map(virtual_cpu_names, m_cpu_info.vendor())) == BARE_TO_METAL) { + result = find_in_map(virtual_cpu_names, m_cpu_info.brand()); + } + } + } + } + if (result == BARE_TO_METAL && m_cpu_info.is_hypervisor_set()) { + result = V_OTHER; } return result; } bool ExecutionEnvironment::is_cloud() const { - CLOUD_PROVIDER prov = getCloudProvider(); + const LCC_API_CLOUD_PROVIDER prov = cloud_provider(); return prov != ON_PREMISE && prov != PROV_UNKNOWN; } // TODO test and azure -CLOUD_PROVIDER ExecutionEnvironment::getCloudProvider() const { - CLOUD_PROVIDER result = PROV_UNKNOWN; - if (m_bios_description.size() > 0 || m_bios_vendor.size() > 0 || m_sys_vendor.size() > 0) { - if (m_bios_vendor.find("SEABIOS") != string::npos || m_bios_description.find("ALIBABA") != string::npos || - m_sys_vendor.find("ALIBABA") != string::npos) { +LCC_API_CLOUD_PROVIDER ExecutionEnvironment::cloud_provider() const { + LCC_API_CLOUD_PROVIDER result = PROV_UNKNOWN; + const string bios_description = m_dmi_info.bios_description(); + const string bios_vendor = m_dmi_info.bios_vendor(); + const string sys_vendor = m_dmi_info.sys_vendor(); + if (bios_description.size() > 0 || bios_vendor.size() > 0 || sys_vendor.size() > 0) { + if (bios_vendor.find("SEABIOS") != string::npos || bios_description.find("ALIBABA") != string::npos || + sys_vendor.find("ALIBABA") != string::npos) { result = ALI_CLOUD; - } else if (m_sys_vendor.find("GOOGLE") != string::npos || m_bios_description.find("GOOGLE") != string::npos) { + } else if (sys_vendor.find("GOOGLE") != string::npos || bios_description.find("GOOGLE") != string::npos) { result = GOOGLE_CLOUD; - } else if (m_bios_vendor.find("AWS") != string::npos || m_bios_description.find("AMAZON") != string::npos || - m_sys_vendor.find("AWS") != string::npos) { + } else if (bios_vendor.find("AWS") != string::npos || bios_description.find("AMAZON") != string::npos || + sys_vendor.find("AWS") != string::npos) { result = AWS; - } else if (m_bios_description.find("HP-COMPAQ") != string::npos || m_bios_description.find("ASUS") || - m_bios_description.find("DELL")) { + } else if (bios_description.find("HP-COMPAQ") != string::npos || bios_description.find("ASUS") || + bios_description.find("DELL")) { result = ON_PREMISE; } } diff --git a/src/library/os/linux/dmi_info.cpp b/src/library/os/linux/dmi_info.cpp new file mode 100644 index 0000000..c5d388d --- /dev/null +++ b/src/library/os/linux/dmi_info.cpp @@ -0,0 +1,35 @@ + +#include "../../base/file_utils.hpp" +#include "../../base/StringUtils.h" + +#include "../dmi_info.hpp" + +namespace license { +namespace os { + +DmiInfo::DmiInfo() { + try { + m_bios_vendor = toupper_copy(trim_copy(get_file_contents("/sys/class/dmi/id/sys_vendor", 256))); + + } catch (...) { + } + try { + m_bios_description = toupper_copy(trim_copy(get_file_contents("/sys/class/dmi/id/modalias", 256))); + char last_char = m_bios_description[m_bios_description.length() - 1]; + if (last_char == '\r' || last_char == '\n') { + m_bios_description = m_bios_description.erase(m_bios_description.length() - 1); + } + } catch (...) { + } + try { + m_sys_vendor = get_file_contents("/sys/class/dmi/id/sys_vendor", 256); + char last_char = m_sys_vendor[m_sys_vendor.length() - 2]; + if (last_char == '\r' || last_char == '\n') { + m_sys_vendor = m_sys_vendor.erase(m_sys_vendor.length() - 1); + } + } catch (...) { + } +} + +} // namespace os +} // namespace license diff --git a/src/library/os/linux/execution_environment.cpp b/src/library/os/linux/execution_environment.cpp index 1f14d62..7df96e9 100644 --- a/src/library/os/linux/execution_environment.cpp +++ b/src/library/os/linux/execution_environment.cpp @@ -25,7 +25,7 @@ using namespace std; // 0=NO 1=Docker/2=Lxc -static int checkContainerProc() { +static CONTAINER_TYPE checkContainerProc() { // in docer /proc/self/cgroups contains the "docker" or "lxc" string // https://stackoverflow.com/questions/23513045/how-to-check-if-a-process-is-running-inside-docker-container char path[MAX_PATH] = {0}; @@ -40,11 +40,11 @@ char *line = NULL; size_t len = 0; ssize_t read; - int result = 0; + CONTAINER_TYPE result = NONE; fp = fopen(proc_path, "r"); if (fp == NULL) { - return 0; + return NONE; } while ((read = getline(&line, &len, fp)) != -1 && result == 0) { @@ -52,10 +52,10 @@ // printf("Retrieved line of length %zu:\n", read); // printf("%s", line); if (strstr(line, "docker") != NULL) { - result = 1; + result = DOCKER; } if (strstr(line, "lxc") != NULL) { - result = 2; + result = LXC; } } @@ -65,17 +65,17 @@ } // 0=NO 1=Docker/2=Lxc -static int checkSystemdContainer() { +static CONTAINER_TYPE checkSystemdContainer() { ifstream systemd_container("/var/run/systemd/container"); - int result = 0; + CONTAINER_TYPE result = NONE; if (systemd_container.good()) { - result = 1; + result = DOCKER; for (string line; getline(systemd_container, line);) { if (line.find("docker") != string::npos) { - result = 1; + result = DOCKER; break; } else if (line.find("lxc") != string::npos) { - result = 2; + result = LXC; break; } } @@ -83,33 +83,15 @@ return result; } -ExecutionEnvironment::ExecutionEnvironment() { - try { - m_bios_vendor = toupper_copy(trim_copy(get_file_contents("/sys/class/dmi/id/sys_vendor", 256))); - - } catch (...) { +static CONTAINER_TYPE get_container_type() { + CONTAINER_TYPE result = checkContainerProc(); + if (result == NONE) { + result = checkSystemdContainer(); } - try { - m_bios_description = toupper_copy(trim_copy(get_file_contents("/sys/class/dmi/id/modalias", 256))); - char last_char = m_bios_description[m_bios_description.length() - 1]; - if (last_char == '\r' || last_char == '\n') { - m_bios_description = m_bios_description.erase(m_bios_description.length() - 1); - } - } catch (...) { - } - try { - m_sys_vendor = get_file_contents("/sys/class/dmi/id/sys_vendor", 256); - char last_char = m_sys_vendor[m_sys_vendor.length() - 2]; - if (last_char == '\r' || last_char == '\n') { - m_sys_vendor = m_sys_vendor.erase(m_sys_vendor.length() - 1); - } - } catch (...) { - } + return result; } -bool ExecutionEnvironment::is_container() const { return (checkContainerProc() != 0 || checkSystemdContainer() != 0); } - -bool ExecutionEnvironment::is_docker() const { return (checkContainerProc() == 1 || checkSystemdContainer() == 1); } +ExecutionEnvironment::ExecutionEnvironment() : m_container_type(get_container_type()) {} } // namespace os } // namespace license diff --git a/src/library/os/linux/os_linux.cpp b/src/library/os/linux/os_linux.cpp index 57fb028..d934623 100644 --- a/src/library/os/linux/os_linux.cpp +++ b/src/library/os/linux/os_linux.cpp @@ -175,27 +175,6 @@ return result; } -static void _getCpuid(unsigned int *p, unsigned int ax) { - __asm __volatile( - "movl %%ebx, %%esi\n\t" - "cpuid\n\t" - "xchgl %%ebx, %%esi" - : "=a"(p[0]), "=S"(p[1]), "=c"(p[2]), "=d"(p[3]) - : "0"(ax)); -} - -FUNCTION_RETURN getCpuId(unsigned char identifier[6]) { - unsigned int i; - unsigned int cpuinfo[4] = {0, 0, 0, 0}; - _getCpuid(cpuinfo, 0); - for (i = 0; i < 3; i++) { - identifier[i * 2] = cpuinfo[i] & 0xFF; - identifier[i * 2 + 1] = (cpuinfo[i] & 0xFF00) >> 8; - } - return FUNC_RET_OK; -} - - FUNCTION_RETURN getMachineName(unsigned char identifier[6]) { static struct utsname u; diff --git a/src/library/os/windows/dmi_info.cpp b/src/library/os/windows/dmi_info.cpp new file mode 100644 index 0000000..0b9103a --- /dev/null +++ b/src/library/os/windows/dmi_info.cpp @@ -0,0 +1,26 @@ +/* + * dmi_info.cpp + * + * Created on: Apr 24, 2020 + * Author: devel + */ + +#include <windows.h> +#include "isvm/BIOSReader.h" +#include "isvm/Native.h" +#include "../../base/StringUtils.h" +#include "../dmi_info.hpp" + +namespace license { +namespace os { +DmiInfo::DmiInfo() { + if (InitEntryPoints()) { + BIOSReader reader; + SystemInformation info = reader.readSystemInfo(); + m_sys_vendor = toupper_copy(info.Manufacturer); + m_bios_vendor = toupper_copy(info.ProductName); + m_bios_description = toupper_copy(info.SysVersion) + toupper_copy(info.family); + } +} +} +} /* namespace license */ diff --git a/src/library/os/windows/execution_environment.cpp b/src/library/os/windows/execution_environment.cpp index 3e65bc8..50a255e 100644 --- a/src/library/os/windows/execution_environment.cpp +++ b/src/library/os/windows/execution_environment.cpp @@ -11,10 +11,8 @@ #include <stdio.h> #include <string> -#include "isvm/BIOSReader.h" -#include "isvm/Native.h" #include "../../base/base.h" -#include "../../base/StringUtils.h" + #include "../cpu_info.hpp" #include "../execution_environment.hpp" @@ -22,65 +20,47 @@ namespace os { using namespace std; -ExecutionEnvironment::ExecutionEnvironment() { - if (InitEntryPoints()) { - BIOSReader reader; - SystemInformation info = reader.readSystemInfo(); - m_sys_vendor = toupper_copy(info.Manufacturer); - m_bios_vendor = toupper_copy(info.ProductName); - m_bios_description = toupper_copy(info.SysVersion) + toupper_copy(info.family); - } -} +ExecutionEnvironment::ExecutionEnvironment() : m_container_type(CONTAINER_TYPE::NONE) {} #define MAX_UNITS 20 -int wine_container() { -DWORD fileMaxLen; -size_t ndrives = 0; -DWORD fileFlags; -char volName[MAX_PATH], fileSysName[MAX_PATH]; -DWORD volSerial = 0; -const DWORD dwSize = MAX_PATH; -char szLogicalDrives[MAX_PATH] = {0}; +CONTAINER_TYPE wine_container() { + size_t ndrives = 0; + const DWORD dwSize = MAX_PATH; + char szLogicalDrives[MAX_PATH] = {0}; -int result = 0; -const DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives); - -if (dwResult > 0 && dwResult <= MAX_PATH) { - char* szSingleDrive = szLogicalDrives; - while (*szSingleDrive && ndrives < MAX_UNITS) { - // get the next drive - UINT driveType = GetDriveType(szSingleDrive); - if (driveType == DRIVE_FIXED) { - string name = szSingleDrive + string("/var/run/systemd/container"); - try { - ifstream systemd_container(name); - if (systemd_container.good()) { - result = 1; - for (string line; getline(systemd_container, line);) { - if (line.find("docker") != string::npos) { - result = 1; - break; - } else if (line.find("lxc") != string::npos) { - result = 2; - break; + CONTAINER_TYPE result = CONTAINER_TYPE::NONE; + const DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives); + + //FIXME! this code missed the increment in the loop... + if (dwResult > 0 && dwResult <= MAX_PATH) { + char* szSingleDrive = szLogicalDrives; + while (*szSingleDrive && ndrives < MAX_UNITS) { + // get the next drive + UINT driveType = GetDriveType(szSingleDrive); + if (driveType == DRIVE_FIXED) { + string name = szSingleDrive + string("/var/run/systemd/container"); + try { + ifstream systemd_container(name); + if (systemd_container.good()) { + result = CONTAINER_TYPE::DOCKER; + for (string line; getline(systemd_container, line);) { + if (line.find("docker") != string::npos) { + result = CONTAINER_TYPE::DOCKER; + break; + } else if (line.find("lxc") != string::npos) { + result = CONTAINER_TYPE::LXC; + break; + } } } + } catch (...) { + // no problem,we're just guessing } - } catch (...) { - //no problem,we're just guessing } } } -} return result; } -bool ExecutionEnvironment::is_docker() const { - // let's check we're not in linux under wine ;) ... -//int cont = wine_container(); - return false; -} -//TODO -bool ExecutionEnvironment::is_container() const { return is_docker(); } } // namespace os } // namespace license diff --git a/test/library/hw_identifier/hw_identifier_test.cpp b/test/library/hw_identifier/hw_identifier_test.cpp index 28db0c1..23ae22c 100644 --- a/test/library/hw_identifier/hw_identifier_test.cpp +++ b/test/library/hw_identifier/hw_identifier_test.cpp @@ -28,7 +28,7 @@ * Test get and set and compare hardware identifier data */ BOOST_AUTO_TEST_CASE(set_and_compare_data) { - array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0xFF, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42}; + array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0xFF, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42}; HwIdentifier pc_id; pc_id.set_data(data); data[0] = data[0] & 0x1f; @@ -38,7 +38,7 @@ * Test get and set and compare hardware identifier data */ BOOST_AUTO_TEST_CASE(compare_wrong_data) { - array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42}; + array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42}; HwIdentifier pc_id; pc_id.set_data(data); data[4] = 0; @@ -49,7 +49,7 @@ * Print a hardware identifier and read it from the same string, check the data matches */ BOOST_AUTO_TEST_CASE(print_and_read) { - array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42}; + array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42}; HwIdentifier pc_id; pc_id.set_data(data); pc_id.set_identification_strategy(LCC_API_HW_IDENTIFICATION_STRATEGY::STRATEGY_ETHERNET); diff --git a/test/library/os/execution_environment_test.cpp b/test/library/os/execution_environment_test.cpp index b604d11..dba290f 100644 --- a/test/library/os/execution_environment_test.cpp +++ b/test/library/os/execution_environment_test.cpp @@ -23,19 +23,19 @@ os::ExecutionEnvironment exec_env; bool docker = false; if (env != nullptr) { - os::VIRTUALIZATION virt = exec_env.getVirtualization(); + LCC_API_VIRTUALIZATION_SUMMARY virt = exec_env.virtualization(); if (strcmp(env, "CONTAINER") == 0 || (docker = (strcmp(env, "DOCKER") == 0))) { - BOOST_CHECK_MESSAGE(virt == VIRTUALIZATION::CONTAINER, "container detected"); + BOOST_CHECK_MESSAGE(virt == LCC_API_VIRTUALIZATION_SUMMARY::CONTAINER, "container detected"); BOOST_CHECK_MESSAGE(exec_env.is_container(), "container detected"); if (docker) { BOOST_CHECK_MESSAGE(exec_env.is_docker(), "docker detected"); } } else if (strcmp(env, "VM") == 0) { - BOOST_CHECK_MESSAGE(virt == VIRTUALIZATION::VM, "VM detected"); + BOOST_CHECK_MESSAGE(virt == LCC_API_VIRTUALIZATION_SUMMARY::VM, "VM detected"); BOOST_CHECK_MESSAGE(!exec_env.is_container(), "VM is not a container"); BOOST_CHECK_MESSAGE(!exec_env.is_docker(), "VM is not a docker"); } else if (strcmp(env, "NONE") == 0) { - BOOST_CHECK_EQUAL(virt, VIRTUALIZATION::NONE); + BOOST_CHECK_EQUAL(virt, LCC_API_VIRTUALIZATION_SUMMARY::NONE); BOOST_CHECK_MESSAGE(!exec_env.is_container(), "not a container"); BOOST_CHECK_MESSAGE(!exec_env.is_docker(), "not a docker"); } else { diff --git a/test/library/os_linux_test.cpp b/test/library/os_linux_test.cpp index 527da44..510d50f 100644 --- a/test/library/os_linux_test.cpp +++ b/test/library/os_linux_test.cpp @@ -16,8 +16,8 @@ BOOST_AUTO_TEST_CASE(read_disk_id) { os::ExecutionEnvironment exec_env; - os::VIRTUALIZATION virt = exec_env.getVirtualization(); - if (virt == VIRTUALIZATION::NONE || virt == VIRTUALIZATION::VM) { + LCC_API_VIRTUALIZATION_SUMMARY virt = exec_env.virtualization(); + if (virt == LCC_API_VIRTUALIZATION_SUMMARY::NONE || virt == LCC_API_VIRTUALIZATION_SUMMARY::VM) { DiskInfo *diskInfos = NULL; size_t disk_info_size = 0; FUNCTION_RETURN result = getDiskInfos(NULL, &disk_info_size); @@ -30,7 +30,7 @@ BOOST_CHECK_GT(mstrnlen_s(diskInfos[0].label, sizeof diskInfos[0].label), 0); BOOST_CHECK_GT(diskInfos[0].disk_sn[0], 0); free(diskInfos); - } else if (virt == VIRTUALIZATION::CONTAINER) { + } else if (virt == LCC_API_VIRTUALIZATION_SUMMARY::CONTAINER) { // docker or lxc diskInfo is not meaningful DiskInfo *diskInfos = NULL; size_t disk_info_size = 0; -- Gitblit v1.9.1