From 7e4e14dde5fbfade46311fbf75386d5371062d7d Mon Sep 17 00:00:00 2001
From: gcontini <1121667+gcontini@users.noreply.github.com>
Date: 周六, 24 10月 2020 19:59:33 +0800
Subject: [PATCH] review of disk strategy linux

---
 src/templates/licensecc_properties.h.in               |   20 +
 .gitignore                                            |    1 
 src/library/hw_identifier/identification_strategy.cpp |    7 
 test/library/os_linux_test.cpp                        |   67 ++++-
 src/library/os/os.h                                   |   18 -
 src/inspector/inspector.cpp                           |   26 +
 src/library/os/linux/os_linux.cpp                     |  292 ++++++++++++++++----------
 doc/usage/issue-licenses.md                           |    4 
 doc/index.rst                                         |    4 
 src/library/os/windows/os_win.cpp                     |   61 ++---
 doc/conf.py                                           |    1 
 /dev/null                                             |    0 
 src/library/hw_identifier/disk_strategy.cpp           |   77 +++----
 src/library/LicenseReader.cpp                         |    2 
 .travis.yml                                           |    2 
 doc/usage/Hardware-identifiers.rst                    |   48 +++
 test/functional/hw_identifier_it_test.cpp             |   19 -
 src/library/hw_identifier/disk_strategy.hpp           |    4 
 18 files changed, 380 insertions(+), 273 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6728aa5..7e97712 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,3 +36,4 @@
 **/CMakeCache.txt
 **/CMakeFiles
 /CMakeSettings.json
+/.venv/
diff --git a/.travis.yml b/.travis.yml
index 2b5e856..370681f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -278,7 +278,7 @@
              - doxygen
              - graphviz
      before_script: 
-        - pip3 install setuptools sphinx sphinx_rtd_theme breathe sphinx-markdown-tables recommonmark sphinx-rtd-theme sphinx-sitemap sphinxemoji
+        - pip3 install setuptools sphinx sphinx_rtd_theme breathe sphinx-markdown-tables recommonmark sphinx-sitemap sphinxemoji
         - cd build && cmake -DCMAKE_INSTALL_PREFIX=../../install ..
      script:
         - make documentation
diff --git a/build/.gitkeep b/build/.gitkeep
deleted file mode 100644
index e69de29..0000000
--- a/build/.gitkeep
+++ /dev/null
diff --git a/doc/conf.py b/doc/conf.py
index 7e4e7ed..1b14e55 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -39,6 +39,7 @@
 
 # Breathe Configuration
 breathe_default_project = "licensecc"
+breathe_domain_by_extension = {"h" : "cpp"}
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
diff --git a/doc/index.rst b/doc/index.rst
index c711991..2eeec3e 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -44,7 +44,7 @@
 *******************
 The software is made by 4 main sub-components:
 
-* ``licensecc``    : the C++ library with a C api (the part you have to integrate in your software) with minimal (or no) external dependencies. This is the project you're currently looking at.
+* `licensecc`    : the C++ library with a C api (the part you have to integrate in your software) with minimal (or no) external dependencies. This is the project you're currently looking at.
 * ``lccinspector`` : a license debugger to be sent to the final customer to diagnose licensing problems or for calculating the hardware id before issuing the license.
 * ``lccgen``       : a license generator (github project `lcc-license-generator`_ ) to initialize the library and generate the licenses.
 * ``examples``     : usage samples (github project `examples <https://github.com/open-license-manager/examples>`_ ).
@@ -119,7 +119,7 @@
 
 How to use
 **************
-The `examples`_ repository shows various ways to integrate ``licensecc`` into your project.
+The `examples`_ repository shows various ways to integrate `licensecc` into your project.
 
 .. _examples: https://github.com/open-license-manager/examples 
 
diff --git a/doc/usage/Hardware-identifiers.rst b/doc/usage/Hardware-identifiers.rst
index 414ef00..f43896a 100644
--- a/doc/usage/Hardware-identifiers.rst
+++ b/doc/usage/Hardware-identifiers.rst
@@ -44,16 +44,48 @@
 For instance if containers are used to avoid to pollute the external distribution it makes perfect sense to have an 
 hardware identifier, if users are running dockers in a kubernetes cluster in the cloud it makes no sense at all.
 
-************************
-Identifier Generation
-************************
-`Licensecc` is able to identify which virtual environment the user is running in and select the appropriate generation
-strategy. Below the identifier generation workflow used by the :ref:`identify_pc <api/public_api:Public api>` method. 
+*************************************************
+Hardware Identifier Generation
+*************************************************
+
+The licensed application will call the api method :ref:`identify_pc <api/public_api:Public api>` to generate an hardware 
+identifier and print it out to the user, the user then will contact the software licensor to get an appropriate license.
+
+The licensed application can either decide an identification strategy by passing it in the ``identify_pc`` parameter ``hw_id_method``
+(see: :cpp:enum:`LCC_API_HW_IDENTIFICATION_STRATEGY` ) or let `licensecc` automatically choose how to generate the 
+identifier (by passing `hw_id_method=STRATEGY_DEFAULT`).   
+In this case `licensecc` is able to identify which virtual environment the user is running in and select the appropriate generation
+strategy. 
+
+Below the full identifier generation workflow used by the :ref:`identify_pc <api/public_api:Public api>` method. 
 
 .. figure:: ../_static/pc-id-selection.png
 
 
-First of all it takes in account the application specified parameter 
-If the licensed software uses `STRATEGY_DEFAULT` and the strategy generates an unstable identifier it is possible to ask the user to 
-set the environemnt variable.
+Default identifier generation (implementation details)
+=======================================================
 
+This section describes the inner working of the default hardware identifer strategy.
+
+When the licensed software calls :ref:`identify_pc <api/public_api:Public api>` with :cpp:enumerator:`LCC_API_HW_IDENTIFICATION_STRATEGY::STRATEGY_DEFAULT` 
+the identifier generation will follow these steps:
+
+ - It will first look to the environment variable ``IDENTIFICATION_STRATEGY``. If set it will use the identification strategy in that variable.
+ - It will try to determine which virtual environment the licensed software is running in. 
+    * If no virtual environment found it will use the strategies in :c:macro:`LCC_BARE_TO_METAL_STRATEGIES`, it will try them one by one until the first one succeeds.
+    * If it detects it's running in a Virtual Machine it will try the strategies in :c:macro:`LCC_VM_STRATEGIES`, it will try them one by one until the first one succeeds.
+
+if you're interested in implementing your own hardware identification strategy you can have a look to the library
+ :ref:`extension points <api/extend:Tweak hardware signature generator>`.
+
+.. TIP:
+
+    If `licensecc` is generating a bad hardware identifier (eg. 'AAAA-AAAA-AAAA') software licensor can ask the user 
+    to set the environment variable ``IDENTIFICATION_STRATEGY`` and try again. Or he can send the user the `lccinspector`
+    to generate all the possible identifiers for that machine.
+
+
+.. NOTE::
+    
+    `licensecc` will try to validate the identifier using the same strategy that was used to generate it, regardless  
+    of what is the default method now in use. eg: disk identifiers will always be validated by ``DiskStrategy``.
diff --git a/doc/usage/issue-licenses.md b/doc/usage/issue-licenses.md
index 6bc5dc9..b977bbe 100644
--- a/doc/usage/issue-licenses.md
+++ b/doc/usage/issue-licenses.md
@@ -40,7 +40,7 @@
 
 ```
 cd projects/DEFAULT #(or whatever your project name is) 
-lcc license issue --client-signature XXXX-XXXX-XXXX-XXXX -o licenses/{license-file-name}.lic
+lcc license issue --client-signature XXXX-XXXX-XXXX -o licenses/{license-file-name}.lic
 ```
 usually this command is issued in the host machine where you compiled `licensecc`
 
@@ -52,7 +52,7 @@
 |base64,b          | the license is encoded for inclusion in environment variables                                |
 |valid-from        | Specify the start of the validity for this license. Format YYYY-MM-DD. If not specified defaults to today. |
 |valid-to          | The expire date for this license. Format YYYY-MM-DD. If not specified the license won't expire |
-|client-signature  | The signature of the hardware where the licensed software will run. It should be in the format XXXX-XXXX-XXXX-XXXX. If not specified the license won't be linked to a specific pc. |
+|client-signature  | The signature of the hardware where the licensed software will run. It should be in the format XXXX-XXXX-XXXX. If not specified the license won't be linked to a specific pc. |
 |output-file-name  | License output file path.                                                                    |
 |extra-data        | Application specific data. They'll be returned when calling the `acquire_license` method   |
 |feature-names     | Comma separated list of features to license. See `multi-feature` discussion.               |
diff --git a/src/inspector/inspector.cpp b/src/inspector/inspector.cpp
index 40cd281..640071d 100644
--- a/src/inspector/inspector.cpp
+++ b/src/inspector/inspector.cpp
@@ -10,15 +10,13 @@
 #include "../library/os/dmi_info.hpp"
 #include "../library/os/cpu_info.hpp"
 #include "../library/os/dmi_info.hpp"
+#include "../library/os/network.hpp"
 
 using namespace std;
 using namespace license::os;
 
-const map<int, string> stringByStrategyId = {{STRATEGY_DEFAULT, "DEFAULT"},
-											 {STRATEGY_ETHERNET, "MAC"},
-											 {STRATEGY_IP_ADDRESS, "IP"},
-											 {STRATEGY_DISK_NUM, "Disk1"},
-											 {STRATEGY_DISK_LABEL, "Disk2"}};
+const map<int, string> stringByStrategyId = {
+	{STRATEGY_DEFAULT, "DEFAULT"}, {STRATEGY_ETHERNET, "MAC"}, {STRATEGY_IP_ADDRESS, "IP"}, {STRATEGY_DISK, "Disk"}};
 
 const unordered_map<int, string> descByVirtDetail = {{BARE_TO_METAL, "No virtualization"},
 													 {VMWARE, "Vmware"},
@@ -98,6 +96,24 @@
 	cout << "Virtualiz. detail:" << descByVirtDetail.find(exec_env_info.virtualization_detail)->second << endl;
 	cout << "Cloud provider   :" << descByCloudProvider.find(exec_env_info.cloud_provider)->second << endl;
 
+	std::vector<license::os::OsAdapterInfo> adapterInfos;
+	FUNCTION_RETURN ret = license::os::getAdapterInfos(adapterInfos);
+	if (ret == FUNCTION_RETURN::FUNC_RET_OK) {
+		for (auto osAdapter : adapterInfos) {
+			cout << "Network adapter [" << osAdapter.id << "]: " << osAdapter.description << endl;
+			cout << "   ip address [" << static_cast<unsigned int>(osAdapter.ipv4_address[3]) << "-"
+				 << static_cast<unsigned int>(osAdapter.ipv4_address[2]) << "-"
+				 << static_cast<unsigned int>(osAdapter.ipv4_address[1]) << "-"
+				 << static_cast<unsigned int>(osAdapter.ipv4_address[0]) << "]" << endl;
+			cout << "   mac address [";
+			for (int i = 0; i < 8; i++) {
+				// print mac
+			}
+		}
+	} else {
+		cout << "problem in getting adapter informations:" << ret << endl;
+	}
+
 	license::os::CpuInfo cpu;
 	cout << "Cpu Vendor       :" << cpu.vendor() << endl;
 	cout << "Cpu Brand        :" << cpu.brand() << endl;
diff --git a/src/library/LicenseReader.cpp b/src/library/LicenseReader.cpp
index 6f46d91..4d2792c 100644
--- a/src/library/LicenseReader.cpp
+++ b/src/library/LicenseReader.cpp
@@ -80,7 +80,7 @@
 			 *  sw_version_to = (optional int)
 			 *  from_date = YYYY-MM-DD (optional)
 			 *  to_date  = YYYY-MM-DD (optional)
-			 *  client_signature = XXXX-XXXX-XXXX-XXXX (optional string 16)
+			 *  client_signature = XXXX-XXXX-XXXX (optional string 16)
 			 *  sig = XXXXXXXXXX (mandatory, 1024)
 			 *  application_data = xxxxxxxxx (optional string 16)
 			 */
diff --git a/src/library/hw_identifier/disk_strategy.cpp b/src/library/hw_identifier/disk_strategy.cpp
index 64142f7..5e50761 100644
--- a/src/library/hw_identifier/disk_strategy.cpp
+++ b/src/library/hw_identifier/disk_strategy.cpp
@@ -12,74 +12,63 @@
 namespace license {
 namespace hw_identifier {
 
-static FUNCTION_RETURN generate_disk_pc_id(vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> &v_disk_id,
-										   bool use_id) {
-	size_t disk_num = 0;
-	size_t available_disk_info = 0;
-	FUNCTION_RETURN result_diskinfos;
+static array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> generate_id_by_sn(const DiskInfo &disk_info) {
+	array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> a_disk_id;
+	a_disk_id.fill(0);
+	size_t size = min(a_disk_id.size(), sizeof(disk_info.disk_sn));
+	memcpy(&a_disk_id[0], disk_info.disk_sn, size);
 
-	result_diskinfos = getDiskInfos(nullptr, &disk_num);
+	return a_disk_id;
+}
+
+static array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> generate_id_by_label(const DiskInfo &disk_info) {
+	array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> a_disk_id;
+	a_disk_id.fill(0);
+	strncpy((char *)&a_disk_id[0], disk_info.label, a_disk_id.size() - 1);
+	return a_disk_id;
+}
+
+static FUNCTION_RETURN generate_disk_pc_id(vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> &v_disk_id) {
+	std::vector<DiskInfo> disk_infos;
+	FUNCTION_RETURN result_diskinfos = getDiskInfos(disk_infos);
 	if (result_diskinfos != FUNC_RET_OK && result_diskinfos != FUNC_RET_BUFFER_TOO_SMALL) {
 		return result_diskinfos;
 	}
-	if (disk_num == 0) {
+	if (disk_infos.size() == 0) {
 		return FUNC_RET_NOT_AVAIL;
 	}
-	size_t mem = disk_num * sizeof(DiskInfo);
-	DiskInfo *diskInfos = (DiskInfo *)malloc(mem);
-	if (diskInfos == nullptr) {
-		return FUNC_RET_NOT_AVAIL;
-	}
-	memset(diskInfos, 0, mem);
-	result_diskinfos = getDiskInfos(diskInfos, &disk_num);
 
-	if (result_diskinfos != FUNC_RET_OK) {
-		free(diskInfos);
-		return result_diskinfos;
-	}
-	for (unsigned int i = 0; i < disk_num; i++) {
-		char firstChar = use_id ? diskInfos[i].label[0] : diskInfos[i].disk_sn[0];
-		available_disk_info += firstChar == 0 ? 0 : 1;
-	}
-	if (available_disk_info == 0) {
-		free(diskInfos);
-		return FUNC_RET_NOT_AVAIL;
-	}
-	v_disk_id.reserve(available_disk_info);
+	v_disk_id.reserve(disk_infos.size() * 2);
 	for (int j = 0; j < 2; j++) {
-		int preferred = (j == 0 ? 1 : 0);
-		for (unsigned int i = 0; i < disk_num; i++) {
-			array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> a_disk_id;
-			a_disk_id.fill(0);
-			if (use_id) {
-				if (diskInfos[i].disk_sn[0] != 0 && diskInfos[i].preferred == preferred) {
-					size_t size = min(a_disk_id.size(), sizeof(&diskInfos[i].disk_sn));
-					memcpy(&a_disk_id[0], diskInfos[i].disk_sn, size);
+		bool preferred = (j == 0);
+		for (unsigned int i = 0; i < disk_infos.size(); i++) {
+			if (disk_infos[i].preferred == preferred) {
+				if (disk_infos[i].sn_initialized) {
+					array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> a_disk_id = generate_id_by_sn(disk_infos[i]);
 					v_disk_id.push_back(a_disk_id);
 				}
-			} else {
-				if (diskInfos[i].label[0] != 0 && diskInfos[i].preferred == preferred) {
-					strncpy((char *)&a_disk_id[0], diskInfos[i].label, a_disk_id.size() - 1);
-					v_disk_id.push_back(a_disk_id);
+				if (disk_infos[i].label_initialized) {
+					array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> l_disk_id = generate_id_by_label(disk_infos[i]);
+					v_disk_id.push_back(l_disk_id);
+				}
+				if (preferred) {
+					break;
 				}
 			}
 		}
 	}
-	free(diskInfos);
 	return FUNC_RET_OK;
 }
-
-DiskStrategy::DiskStrategy(bool use_id) : m_use_id(use_id) {}
 
 DiskStrategy::~DiskStrategy() {}
 
 LCC_API_HW_IDENTIFICATION_STRATEGY DiskStrategy::identification_strategy() const {
-	return m_use_id ? STRATEGY_DISK_NUM : STRATEGY_DISK_LABEL;
+	return LCC_API_HW_IDENTIFICATION_STRATEGY::STRATEGY_DISK;
 }
 
 std::vector<HwIdentifier> DiskStrategy::alternative_ids() const {
 	vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> data;
-	FUNCTION_RETURN result = generate_disk_pc_id(data, m_use_id);
+	FUNCTION_RETURN result = generate_disk_pc_id(data);
 	vector<HwIdentifier> identifiers;
 	if (result == FUNC_RET_OK) {
 		identifiers.reserve(data.size());
diff --git a/src/library/hw_identifier/disk_strategy.hpp b/src/library/hw_identifier/disk_strategy.hpp
index 33e3909..2ca990b 100644
--- a/src/library/hw_identifier/disk_strategy.hpp
+++ b/src/library/hw_identifier/disk_strategy.hpp
@@ -14,10 +14,8 @@
 namespace hw_identifier {
 
 class DiskStrategy : public IdentificationStrategy {
-private:
-	bool m_use_id;
 public:
-	DiskStrategy(bool use_id);
+	inline DiskStrategy(){};
 	virtual ~DiskStrategy();
 	virtual LCC_API_HW_IDENTIFICATION_STRATEGY identification_strategy() const;
 	virtual std::vector<HwIdentifier> alternative_ids() const;
diff --git a/src/library/hw_identifier/identification_strategy.cpp b/src/library/hw_identifier/identification_strategy.cpp
index 794b97b..ad9cf46 100644
--- a/src/library/hw_identifier/identification_strategy.cpp
+++ b/src/library/hw_identifier/identification_strategy.cpp
@@ -45,11 +45,8 @@
 		case STRATEGY_IP_ADDRESS:
 			result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new Ethernet(true)));
 			break;
-		case STRATEGY_DISK_NUM:
-			result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new DiskStrategy(true)));
-			break;
-		case STRATEGY_DISK_LABEL:
-			result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new DiskStrategy(false)));
+		case STRATEGY_DISK:
+			result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new DiskStrategy()));
 			break;
 		default:
 			throw logic_error("strategy not supported");
diff --git a/src/library/os/linux/os_linux.cpp b/src/library/os/linux/os_linux.cpp
index 45c2f61..d4c7cd7 100644
--- a/src/library/os/linux/os_linux.cpp
+++ b/src/library/os/linux/os_linux.cpp
@@ -3,7 +3,13 @@
 #include <stdio.h>
 #include <cerrno>
 #include <cstring>
+#include <iostream>
+#include <fstream>
+#include <unordered_map>
 #include <string>
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
 #include "../os.h"
 #include "../../base/logger.h"
 
@@ -14,6 +20,13 @@
 #include <valgrind/memcheck.h>
 #endif
 
+#ifdef USE_DISK_MODEL
+#define PARSE_ID_FUNC parse_disk_id
+#define ID_FOLDER "/dev/disk/by-id/"
+#else
+#define PARSE_ID_FUNC parseUUID
+#define ID_FOLDER "/dev/disk/by-uuid/"
+#endif
 #ifdef USE_DBUS
 #include <dbus-1.0/dbus/dbus.h>
 #endif
@@ -55,138 +68,197 @@
 	free(hexuuid);
 }
 
-#define MAX_UNITS 40
-FUNCTION_RETURN getDiskInfos(DiskInfo *diskInfos, size_t *disk_info_size) {
-	struct stat mount_stat, sym_stat;
-	/*static char discard[1024];
-	 char device[64], name[64], type[64];
-	 */
-	char cur_dir[MAX_PATH];
-	struct mntent *ent;
+static void parse_disk_id(const char *uuid, unsigned char *buffer_out, size_t out_size) {
+	unsigned int i;
+	size_t len = strlen(uuid);
+	memset(buffer_out, 0, out_size);
+	for (i = 0; i < len; i++) {
+		buffer_out[i % out_size] = buffer_out[i % out_size] ^ uuid[i];
+	}
+}
 
-	int maxDrives, currentDrive, i, drive_found;
-	__ino64_t *statDrives = NULL;
-	DiskInfo *tmpDrives = NULL;
-	FILE *aFile = NULL;
-	DIR *disk_by_uuid_dir = NULL, *disk_by_label = NULL;
+/**
+ * 	int id;
+	char device[MAX_PATH];
+	unsigned char disk_sn[8];
+	char label[255];
+	int preferred;
+ * @param blkidfile
+ * @param diskInfos_out
+ * @return
+ */
+
+static std::string getAttribute(const std::string &source, const std::string &attrName) {
+	std::string attr_namefull = attrName + "=\"";
+	std::size_t startpos = source.find(attr_namefull) + attr_namefull.size();
+	std::size_t endpos = source.find("\"", startpos);
+	return source.substr(startpos, endpos - startpos);
+}
+
+FUNCTION_RETURN parse_blkid(const std::string &blkid_file_content, std::vector<DiskInfo> &diskInfos_out) {
+	DiskInfo diskInfo;
+	int diskNum = 0;
+	for (std::size_t oldpos = 0, pos = 0; (pos = blkid_file_content.find("</device>", oldpos)) != std::string::npos;
+		 oldpos = pos + 1) {
+		std::string cur_dev = blkid_file_content.substr(oldpos, pos);
+		diskInfo.id = diskNum++;
+		std::string device = cur_dev.substr(cur_dev.find_last_of(">") + 1);
+		strncpy(diskInfo.device, device.c_str(), MAX_PATH);
+		std::string label = getAttribute(cur_dev, "PARTLABEL");
+		strncpy(diskInfo.label, label.c_str(), 255);
+		std::string disk_sn = getAttribute(cur_dev, "UUID");
+		parseUUID(disk_sn.c_str(), diskInfo.disk_sn, sizeof(diskInfo.disk_sn));
+		std::string disk_type = getAttribute(cur_dev, "TYPE");
+		// unlikely that somebody put the swap on a removable disk.
+		// this is a first rough guess on what can be a preferred disk for blkid devices
+		// just in case /etc/fstab can't be accessed or it is not up to date.
+		diskInfo.preferred = (disk_type == "swap");
+		diskInfos_out.push_back(diskInfo);
+	}
+	return FUNCTION_RETURN::FUNC_RET_OK;
+}
+
+#define BLKID_LOCATIONS {"/run/blkid/blkid.tab", "/etc/blkid.tab"};
+
+static FUNCTION_RETURN getDiskInfos_blkid(std::vector<DiskInfo> &diskInfos) {
+	const char *strs[] = BLKID_LOCATIONS;
+	bool can_read = false;
+	std::stringstream buffer;
+	for (int i = 0; i < sizeof(strs) / sizeof(const char *); i++) {
+		const char *location = strs[i];
+		std::ifstream t(location);
+		if (t.is_open()) {
+			buffer << t.rdbuf();
+			can_read = true;
+			break;
+		}
+	}
+	if (!can_read) {
+		return FUNCTION_RETURN::FUNC_RET_NOT_AVAIL;
+	}
+
+	return parse_blkid(buffer.str(), diskInfos);
+}
+
+#define MAX_UNITS 40
+FUNCTION_RETURN getDiskInfos_dev(std::vector<DiskInfo> &diskInfos) {
 	struct dirent *dir = NULL;
+	struct stat sym_stat;
 	FUNCTION_RETURN result;
 
-	if (diskInfos != NULL) {
-		maxDrives = *disk_info_size;
-		tmpDrives = diskInfos;
+	DIR *disk_by_uuid_dir = opendir(ID_FOLDER);
+	if (disk_by_uuid_dir == nullptr) {
+		LOG_DEBUG("Open " ID_FOLDER " fail");
 	} else {
-		maxDrives = MAX_UNITS;
-		tmpDrives = (DiskInfo *)malloc(sizeof(DiskInfo) * maxDrives);
-	}
-	memset(tmpDrives, 0, sizeof(DiskInfo) * maxDrives);
-	statDrives = (__ino64_t *)malloc(maxDrives * sizeof(__ino64_t));
-	memset(statDrives, 0, sizeof(__ino64_t) * maxDrives);
-
-	aFile = setmntent("/proc/mounts", "r");
-	if (aFile == NULL) {
-		/*proc not mounted*/
-		free(tmpDrives);
-		free(statDrives);
-		return FUNC_RET_ERROR;
-	}
-
-	currentDrive = 0;
-	while (NULL != (ent = getmntent(aFile)) && currentDrive < maxDrives) {
-		if ((strncmp(ent->mnt_type, "ext", 3) == 0 || strncmp(ent->mnt_type, "xfs", 3) == 0 ||
-			 strncmp(ent->mnt_type, "vfat", 4) == 0 || strncmp(ent->mnt_type, "ntfs", 4) == 0 ||
-			 strncmp(ent->mnt_type, "btr", 3) == 0) &&
-			ent->mnt_fsname != NULL && strncmp(ent->mnt_fsname, "/dev/", 5) == 0) {
-			if (stat(ent->mnt_fsname, &mount_stat) == 0) {
-				drive_found = -1;
-				for (i = 0; i < currentDrive; i++) {
-					if (statDrives[i] == mount_stat.st_ino) {
-						drive_found = i;
-					}
-				}
-				if (drive_found == -1) {
-					LOG_DEBUG("mntent fs:[%s],dir:[%s],inode:[%d]\n", ent->mnt_fsname, ent->mnt_dir,
-							  (unsigned long int)mount_stat.st_ino);
-					strncpy(tmpDrives[currentDrive].device, ent->mnt_fsname, 255 - 1);
-					statDrives[currentDrive] = mount_stat.st_ino;
-					drive_found = currentDrive;
-					currentDrive++;
-				}
-				if (strcmp(ent->mnt_dir, "/") == 0) {
-					strcpy(tmpDrives[drive_found].label, "root");
-					LOG_DEBUG("drive %s set to preferred\n", ent->mnt_fsname);
-					tmpDrives[drive_found].preferred = 1;
-				} else {
-					tmpDrives[drive_found].preferred = 0;
-				}
-			} else {
-				LOG_DEBUG("Error %s during stat of %s \n", std::strerror(errno), ent->mnt_fsname);
+		const std::string base_dir(ID_FOLDER "/");
+		while ((dir = readdir(disk_by_uuid_dir)) != nullptr && diskInfos.size() < MAX_UNITS) {
+			if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0 ||
+				strncmp(dir->d_name, "usb", 3) == 0) {
+				continue;
 			}
-		}
-	}
-	endmntent(aFile);
 
-	if (diskInfos == NULL) {
-		*disk_info_size = currentDrive;
-		free(tmpDrives);
-		result = (currentDrive > 0) ? FUNC_RET_OK : FUNC_RET_NOT_AVAIL;
-	} else if (*disk_info_size >= currentDrive) {
-		disk_by_uuid_dir = opendir("/dev/disk/by-uuid");
-		if (disk_by_uuid_dir == nullptr) {
-			LOG_WARN("Open /dev/disk/by-uuid fail");
-			free(statDrives);
-			return FUNC_RET_ERROR;
-		}
-		result = FUNC_RET_OK;
-		*disk_info_size = currentDrive;
-
-		while ((dir = readdir(disk_by_uuid_dir)) != nullptr) {
-			std::string cur_dir("/dev/disk/by-uuid/");
-			cur_dir += dir->d_name;
-
-			bool found = false;
+			std::string cur_dir = base_dir + dir->d_name;
 			if (stat(cur_dir.c_str(), &sym_stat) == 0) {
-				for (i = 0; i < currentDrive; i++) {
-					if (sym_stat.st_ino == statDrives[i]) {
-						found = true;
-						parseUUID(dir->d_name, tmpDrives[i].disk_sn, sizeof(tmpDrives[i].disk_sn));
-#ifndef NDEBUG
-						VALGRIND_CHECK_VALUE_IS_DEFINED(tmpDrives[i].device);
-						LOG_DEBUG("uuid %d %s %02x%02x%02x%02x", i, tmpDrives[i].device, tmpDrives[i].disk_sn[0],
-								  tmpDrives[i].disk_sn[1], tmpDrives[i].disk_sn[2], tmpDrives[i].disk_sn[3]);
-#endif
+				DiskInfo tmpDiskInfo;
+				tmpDiskInfo.id = sym_stat.st_ino;
+				ssize_t len = ::readlink(cur_dir.c_str(), tmpDiskInfo.device, sizeof(tmpDiskInfo.device) - 1);
+				if (len != -1) {
+					tmpDiskInfo.device[len] = '\0';
+					PARSE_ID_FUNC(dir->d_name, tmpDiskInfo.disk_sn, sizeof(tmpDiskInfo.disk_sn));
+					tmpDiskInfo.sn_initialized = true;
+					tmpDiskInfo.label_initialized = false;
+					tmpDiskInfo.preferred = false;
+					bool found = false;
+					for (auto diskInfo : diskInfos) {
+						if (tmpDiskInfo.id == diskInfo.id) {
+							found = true;
+							break;
+						}
 					}
-				}
-				if (!found) {
-					LOG_DEBUG("Drive [%s], num [%d] inode [%d] did not match any existing drive", cur_dir.c_str(),
-							  (unsigned long int)sym_stat.st_ino);
+					if (!found) {
+						diskInfos.push_back(tmpDiskInfo);
+					}
+				} else {
+					LOG_DEBUG("Error %s during readlink of %s", std::strerror(errno), cur_dir.c_str());
 				}
 			} else {
 				LOG_DEBUG("Error %s during stat of %s", std::strerror(errno), cur_dir.c_str());
 			}
 		}
 		closedir(disk_by_uuid_dir);
+	}
 
-		disk_by_label = opendir("/dev/disk/by-label");
-		if (disk_by_label != nullptr) {
-			while ((dir = readdir(disk_by_label)) != nullptr) {
-				strcpy(cur_dir, "/dev/disk/by-label/");
-				strcat(cur_dir, dir->d_name);
-				if (stat(cur_dir, &sym_stat) == 0) {
-					for (i = 0; i < currentDrive; i++) {
-						if (sym_stat.st_ino == statDrives[i]) {
-							strncpy(tmpDrives[i].label, dir->d_name, 255 - 1);
-							LOG_DEBUG("label %d %s %s", i, tmpDrives[i].label, tmpDrives[i].device);
-						}
+	result = diskInfos.size() > 0 ? FUNCTION_RETURN::FUNC_RET_OK : FUNCTION_RETURN::FUNC_RET_NOT_AVAIL;
+	const std::string label_dir("/dev/disk/by-label");
+	DIR *disk_by_label = opendir(label_dir.c_str());
+	if (disk_by_label != nullptr) {
+		while ((dir = readdir(disk_by_label)) != nullptr) {
+			if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
+				continue;
+			}
+			std::string cur_disk_label = label_dir + "/" + dir->d_name;
+			if (stat(cur_disk_label.c_str(), &sym_stat) == 0) {
+				bool found = false;
+				for (auto diskInfo : diskInfos) {
+					if (((int)sym_stat.st_ino) == diskInfo.id) {
+						strncpy(diskInfo.label, dir->d_name, 255 - 1);
+						diskInfo.label_initialized = true;
+						break;
 					}
 				}
+			} else {
+				LOG_DEBUG("Stat %s for fail:F %s", cur_disk_label, std::strerror(errno));
 			}
-			closedir(disk_by_label);
 		}
+		closedir(disk_by_label);
 	} else {
-		result = FUNC_RET_BUFFER_TOO_SMALL;
+		LOG_DEBUG("Open %s for reading disk labels fail", label_dir);
 	}
-	free(statDrives);
+
+	return result;
+}
+
+/**
+ * Try to determine removable devices: as a first guess removable devices doesn't have
+ * an entry in /etc/fstab
+ *
+ * @param diskInfos
+ */
+static void set_preferred_disks(std::vector<DiskInfo> &diskInfos) {
+	FILE *fstabFile = setmntent("/etc/fstab", "r");
+	if (fstabFile == nullptr) {
+		/*fstab not accessible*/
+		return;
+	}
+	struct mntent *ent;
+	while (nullptr != (ent = getmntent(fstabFile))) {
+		bool found = false;
+		for (auto disk_info : diskInfos) {
+			if (strcmp(ent->mnt_fsname, disk_info.device) == 0) {
+				disk_info.preferred = true;
+				break;
+			}
+		}
+	}
+	endmntent(fstabFile);
+	return;
+}
+
+/**
+ * First try to read disk_infos from /dev/disk/by-id folder, if fails try to use
+ * blkid cache to see what's in there, then try to exclude removable disks
+ * looking at /etc/fstab
+ * @param diskInfos_out vector used to output the disk informations
+ * @return
+ */
+FUNCTION_RETURN getDiskInfos(std::vector<DiskInfo> &disk_infos) {
+	FUNCTION_RETURN result = getDiskInfos_dev(disk_infos);
+	if (result != FUNCTION_RETURN::FUNC_RET_OK) {
+		result = getDiskInfos_blkid(disk_infos);
+	}
+	if (result == FUNCTION_RETURN::FUNC_RET_OK) {
+		set_preferred_disks(disk_infos);
+	}
 	return result;
 }
 
diff --git a/src/library/os/os.h b/src/library/os/os.h
index fa1862f..36a1c69 100644
--- a/src/library/os/os.h
+++ b/src/library/os/os.h
@@ -8,31 +8,32 @@
 #ifndef OS_DEPENDENT_HPP_
 #define OS_DEPENDENT_HPP_
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include <stddef.h>
 #include <string.h>
 #include <ctype.h>
 #include <sys/types.h>
 // definition of size_t
 #include <stdlib.h>
+#include <vector>
 #ifdef __unix__
 #include <unistd.h>
 #include <stdbool.h>
 #endif
+
+#include <licensecc/datatypes.h>
 #include "../base/base.h"
 
 typedef struct {
 	int id;
 	char device[MAX_PATH];
 	unsigned char disk_sn[8];
+	bool sn_initialized;
 	char label[255];
-	int preferred;
+	bool label_initialized;
+	bool preferred;
 } DiskInfo;
 
-FUNCTION_RETURN getDiskInfos(DiskInfo* diskInfos, size_t* disk_info_size);
+FUNCTION_RETURN getDiskInfos(std::vector<DiskInfo>& diskInfos);
 FUNCTION_RETURN getUserHomePath(char[MAX_PATH]);
 FUNCTION_RETURN getModuleName(char buffer[MAX_PATH]);
 FUNCTION_RETURN getMachineName(unsigned char identifier[6]);
@@ -56,7 +57,6 @@
  */
 FUNCTION_RETURN getOsSpecificIdentifier(unsigned char identifier[6]);
 
-// FUNCTION_RETURN verifySignature(const char* stringToVerify, const char* signatureB64);
 
 #ifdef _WIN32
 #define SETENV(VAR, VAL) _putenv_s(VAR, VAL);
@@ -64,10 +64,6 @@
 #else
 #define SETENV(VAR, VAL) setenv(VAR, VAL, 1);
 #define UNSETENV(P) unsetenv(P);
-#endif
-
-#ifdef __cplusplus
-}
 #endif
 
 #endif /* OS_DEPENDENT_HPP_ */
diff --git a/src/library/os/windows/os_win.cpp b/src/library/os/windows/os_win.cpp
index b6094da..cfa6b0d 100644
--- a/src/library/os/windows/os_win.cpp
+++ b/src/library/os/windows/os_win.cpp
@@ -21,77 +21,63 @@
 	return result;
 }
 
-//http://www.ok-soft-gmbh.com/ForStackOverflow/EnumMassStorage.c
-//http://stackoverflow.com/questions/3098696/same-code-returns-diffrent-result-on-windows7-32-bit-system
+// http://www.ok-soft-gmbh.com/ForStackOverflow/EnumMassStorage.c
+// http://stackoverflow.com/questions/3098696/same-code-returns-diffrent-result-on-windows7-32-bit-system
 #define MAX_UNITS 30
-//bug check return with diskinfos == null func_ret_ok
-FUNCTION_RETURN getDiskInfos(DiskInfo * diskInfos, size_t * disk_info_size) {
+// bug check return with diskinfos == null func_ret_ok
+FUNCTION_RETURN getDiskInfos(std::vector<DiskInfo>& diskInfos) {
 	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 };
-
+	char szLogicalDrives[MAX_PATH] = {0};
 
 	FUNCTION_RETURN return_value = FUNC_RET_NOT_AVAIL;
 	const DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
 
-	if (dwResult > 0 && dwResult <= MAX_PATH) {
+	if (dwResult > 0) {
 		return_value = FUNC_RET_OK;
 		char* szSingleDrive = szLogicalDrives;
 		while (*szSingleDrive && ndrives < MAX_UNITS) {
-
 			// get the next drive
 			UINT driveType = GetDriveType(szSingleDrive);
 			if (driveType == DRIVE_FIXED) {
-				BOOL success = GetVolumeInformation(szSingleDrive, volName, MAX_PATH,
-				                                    &volSerial, &fileMaxLen, &fileFlags, fileSysName,
-				                                    MAX_PATH);
+				BOOL success = GetVolumeInformation(szSingleDrive, volName, MAX_PATH, &volSerial, &fileMaxLen,
+													&fileFlags, fileSysName, MAX_PATH);
 				if (success) {
 					LOG_INFO("drive         : %s", szSingleDrive);
 					LOG_INFO("Volume Name   : %s", volName);
 					LOG_INFO("Volume Serial : 0x%x", volSerial);
 					LOG_DEBUG("Max file length : %d", fileMaxLen);
 					LOG_DEBUG("Filesystem      : %s", fileSysName);
-					if (diskInfos != NULL) {
-						if (ndrives < (int)*disk_info_size) {
-							diskInfos[ndrives].id = (int)ndrives;
-							strncpy(diskInfos[ndrives].device, volName,
-									min(std::size_t{MAX_PATH}, sizeof(volName)) - 1);
-							strncpy(diskInfos[ndrives].label, fileSysName,
-									min(sizeof(diskInfos[ndrives].label), sizeof(fileSysName)) - 1);
-							memcpy(diskInfos[ndrives].disk_sn, &volSerial, sizeof(DWORD));
-							diskInfos[ndrives].preferred = (szSingleDrive[0] == 'C');
-						} else {
-							return_value = FUNC_RET_BUFFER_TOO_SMALL;
-						}
-					}
+					DiskInfo diskInfo;
+					diskInfo.id = (int)ndrives;
+					strncpy(diskInfo.device, volName, min(std::size_t{MAX_PATH}, sizeof(volName)) - 1);
+					strncpy(diskInfo.label, fileSysName,
+							min(sizeof(diskInfos[ndrives].label), sizeof(fileSysName)) - 1);
+					memcpy(diskInfo.disk_sn, &volSerial, sizeof(DWORD));
+					diskInfo.preferred = (szSingleDrive[0] == 'C');
+					diskInfos.push_back(diskInfo);
 					ndrives++;
 				} else {
-					LOG_WARN("Unable to retrieve information of '%s'", szSingleDrive);
+					LOG_DEBUG("Unable to retrieve information of '%s'", szSingleDrive);
 				}
 			} else {
-				LOG_INFO("This volume is not fixed : %s, type: %d",	szSingleDrive);
+				LOG_DEBUG("This volume is not fixed : %s, type: %d", szSingleDrive);
 			}
-			szSingleDrive += strlen(szSingleDrive) + 1;
 		}
 	}
-	if (diskInfos == NULL || *disk_info_size == 0) {
-		if (ndrives > 0) {
-			return_value = FUNC_RET_OK;
-		} else {
-			return_value = FUNC_RET_NOT_AVAIL;
-			LOG_INFO("No fixed drive was detected");
-		}
-		*disk_info_size = ndrives;
+	if (diskInfos.size() > 0) {
+		return_value = FUNC_RET_OK;
 	} else {
-		*disk_info_size = min(ndrives, *disk_info_size);
+		return_value = FUNC_RET_NOT_AVAIL;
+		LOG_INFO("No fixed drive were detected");
 	}
+
 	return return_value;
 }
-
 
 FUNCTION_RETURN getModuleName(char buffer[MAX_PATH]) {
 	FUNCTION_RETURN result = FUNC_RET_OK;
@@ -101,4 +87,3 @@
 	}
 	return result;
 }
-
diff --git a/src/templates/licensecc_properties.h.in b/src/templates/licensecc_properties.h.in
index 15f6452..1dd89e8 100644
--- a/src/templates/licensecc_properties.h.in
+++ b/src/templates/licensecc_properties.h.in
@@ -78,8 +78,9 @@
 enum LCC_API_HW_IDENTIFICATION_STRATEGY {
 	/**
 	 * \brief Default strategy.
-	 *
-	 * This strategy try to detect which virtual environment the software is running in.
+	 * 
+	 * This strategy first checks the content of the environment variable `IDENTIFICATION_STRATEGY`. If the variable is defined it will use the 
+	 * strategy specified in there, if not defined it will try to detect which virtual environment the software is running in.
 	 *  - If no virtual environment is detected it will try the strategies defined in ::LCC_BARE_TO_METAL_STRATEGIES
 	 *  - If it detects the software is running in a virtual machine it will use ::LCC_VM_STRATEGIES
 	 *  - If it detects the software is running in a docker or in an LXC it will use ::LCC_DOCKER_STRATEGIES or
@@ -89,10 +90,15 @@
 	STRATEGY_DEFAULT = -1,
 	STRATEGY_ETHERNET = 0,
 	STRATEGY_IP_ADDRESS = 1,
-	STRATEGY_DISK_NUM = 2,
-	STRATEGY_DISK_LABEL = 3,
-	STRATEGY_MEMORY_CPU_SIZE = 4,
-	STRATEGY_HOST_NAME = 5,
+	STRATEGY_DISK = 2,
+	/**
+	* Not yet implemented
+	*/
+	STRATEGY_CPU_SIZE = 3,
+	/**
+	* Not yet implemented
+	*/
+	STRATEGY_HOST_NAME = 4,
 	STRATEGY_NONE = -2
 };
 
@@ -103,7 +109,7 @@
 /**
  * List the strategies used when no virtual envrionment is detected
  */
-#define LCC_BARE_TO_METAL_STRATEGIES { STRATEGY_ETHERNET, STRATEGY_DISK_LABEL, STRATEGY_NONE }
+#define LCC_BARE_TO_METAL_STRATEGIES { STRATEGY_DISK, STRATEGY_HOST_NAME, STRATEGY_NONE }
 /**
  * List the strategies used when the software is executing in a virtual machine
  */
diff --git a/test/functional/hw_identifier_it_test.cpp b/test/functional/hw_identifier_it_test.cpp
index 7f200ee..ae92cb5 100644
--- a/test/functional/hw_identifier_it_test.cpp
+++ b/test/functional/hw_identifier_it_test.cpp
@@ -49,23 +49,12 @@
 
 BOOST_AUTO_TEST_CASE(volid_lic_file) {
 	HwIdentifier identifier_out;
-	size_t disk_num;
-	FUNCTION_RETURN result_diskinfos = getDiskInfos(nullptr, &disk_num);
-	if ((result_diskinfos == FUNC_RET_BUFFER_TOO_SMALL || result_diskinfos == FUNC_RET_OK) && disk_num > 0) {
-		generate_and_verify_license(LCC_API_HW_IDENTIFICATION_STRATEGY::STRATEGY_DISK_NUM, "volid_lic_file");
+	vector<DiskInfo> diskInfos;
+	FUNCTION_RETURN result_diskinfos = getDiskInfos(diskInfos);
+	if ((result_diskinfos == FUNC_RET_BUFFER_TOO_SMALL || result_diskinfos == FUNC_RET_OK) && diskInfos.size() > 0) {
+		generate_and_verify_license(LCC_API_HW_IDENTIFICATION_STRATEGY::STRATEGY_DISK, "volid_lic_file");
 	} else {
 		BOOST_TEST_MESSAGE("No disk found skipping testing disk hardware identifier");
-	}
-}
-
-BOOST_AUTO_TEST_CASE(volume_name_lic_file) {
-	HwIdentifier identifier_out;
-	size_t disk_num;
-	FUNCTION_RETURN result_diskinfos = getDiskInfos(nullptr, &disk_num);
-	if ((result_diskinfos == FUNC_RET_BUFFER_TOO_SMALL || result_diskinfos == FUNC_RET_OK) && disk_num > 0) {
-		generate_and_verify_license(LCC_API_HW_IDENTIFICATION_STRATEGY::STRATEGY_DISK_LABEL, "volume_name_lic_file");
-	} else {
-		BOOST_TEST_MESSAGE("No disk found skipping testing volume name disk hardware identifier");
 	}
 }
 
diff --git a/test/library/os_linux_test.cpp b/test/library/os_linux_test.cpp
index b44beb4..3a481d6 100644
--- a/test/library/os_linux_test.cpp
+++ b/test/library/os_linux_test.cpp
@@ -9,39 +9,64 @@
 #include "../../src/library/os/os.h"
 #include "../../src/library/os/execution_environment.hpp"
 
+FUNCTION_RETURN parse_blkid(const std::string &blkid_file_content, std::vector<DiskInfo> &diskInfos_out);
+
 namespace license {
 namespace test {
 using namespace std;
-using namespace os;
+// using namespace os;
 
 BOOST_AUTO_TEST_CASE(read_disk_id) {
 	os::ExecutionEnvironment exec_env;
 	LCC_API_VIRTUALIZATION_SUMMARY virt = exec_env.virtualization();
+	vector<DiskInfo> disk_infos;
+	FUNCTION_RETURN result = getDiskInfos(disk_infos);
 	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);
 		BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
-		BOOST_CHECK_GT(disk_info_size, 0);
-		diskInfos = (DiskInfo*) malloc(sizeof(DiskInfo) * disk_info_size);
-		result = getDiskInfos(diskInfos, &disk_info_size);
-		BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
-		BOOST_CHECK_GT(mstrnlen_s(diskInfos[0].device, sizeof(diskInfos[0].device)), 0);
-		BOOST_CHECK_GT(mstrnlen_s(diskInfos[0].label, sizeof diskInfos[0].label), 0);
-		bool all_zero = true;
-		for (int i = 0; i < sizeof(diskInfos[0].disk_sn) && all_zero; i++) {
-			all_zero = (diskInfos[0].disk_sn[i] == 0);
+		BOOST_REQUIRE_MESSAGE(disk_infos.size() > 0, "Found some disk");
+		bool preferred_found = false;
+		bool uuid_found = false;
+		bool label_found = false;
+
+		for (auto disk_info : disk_infos) {
+			uuid_found |= disk_info.sn_initialized;
+			preferred_found |= disk_info.preferred;
+			label_found |= disk_info.label_initialized;
+
+			if (disk_info.sn_initialized) {
+				bool all_zero = true;
+				for (int i = 0; i < sizeof(disk_info.disk_sn) && all_zero; i++) {
+					all_zero = (disk_info.disk_sn[i] == 0);
+				}
+				BOOST_CHECK_MESSAGE(!all_zero, "disksn is not all zero");
+			}
 		}
-		BOOST_CHECK_MESSAGE(!all_zero, "disksn is not all zero");
-		free(diskInfos);
+		BOOST_CHECK_MESSAGE(uuid_found, "At least one UUID initialized");
+		BOOST_CHECK_MESSAGE(label_found, "At least one label found");
+		BOOST_CHECK_MESSAGE(preferred_found, "At least one standard 'root' file system");
 	} else if (virt == LCC_API_VIRTUALIZATION_SUMMARY::CONTAINER) {
-		// docker or lxc diskInfo is not meaningful
-		DiskInfo *diskInfos = NULL;
-		size_t disk_info_size = 0;
-		FUNCTION_RETURN result = getDiskInfos(NULL, &disk_info_size);
+		// in docker or lxc diskInfo is very likely not to find any good disk.
 		BOOST_CHECK_EQUAL(result, FUNC_RET_NOT_AVAIL);
+		BOOST_REQUIRE_MESSAGE(disk_infos.size() == 0, "Found no disk");
 	}
 }
 
-} // namespace test
-} // namespace license
+BOOST_AUTO_TEST_CASE(parse_blkid_file) {
+	const string blkid_content =
+		"<device DEVNO=\"0x0803\" TIME=\"1603155692.238672\" "
+		"UUID=\"baccfd49-5203-4e34-9b8b-a2bbaf9b4e24\" TYPE=\"swap\" PARTLABEL=\"Linux swap\" "
+		"PARTUUID=\"7d84b1a8-5492-4651-b720-61c723fb8c69\">/dev/sda3</device>"
+		"<device DEVNO=\"0x10302\" TIME=\"1603155692.253094\" UUID=\"d1b5b096-5e58-4e4f-af39-be12038c9bed\" "
+		"TYPE=\"ext4\" PARTLABEL=\"Linux filesystem\" PARTUUID=\"3d742821-3167-43fa-9f22-e9bea9a9ce64\">"
+		"/dev/nvme0n1p2</device>";
+	vector<DiskInfo> disk_infos;
+	FUNCTION_RETURN result = parse_blkid(blkid_content, disk_infos);
+	BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
+	BOOST_CHECK_MESSAGE(disk_infos.size() == 2, "Two disks found");
+	BOOST_CHECK_MESSAGE(string("Linux swap") == disk_infos[0].label, "Label parsed OK");
+	BOOST_CHECK_MESSAGE(string("/dev/sda3") == disk_infos[0].device, "device parsed");
+	BOOST_CHECK_MESSAGE(disk_infos[0].preferred, "Preferred found");
+}
+
+}  // namespace test
+}  // namespace license

--
Gitblit v1.9.1