From 33041ad25a6add7beace4a680ffaaf88c5c3948a Mon Sep 17 00:00:00 2001
From: gcontini <1121667+gcontini@users.noreply.github.com>
Date: 周日, 25 10月 2020 17:55:04 +0800
Subject: [PATCH] fix linux disk detection

---
 src/library/os/linux/os_linux.cpp |  189 ++++++++++++++++++++++++++++++-----------------
 1 files changed, 121 insertions(+), 68 deletions(-)

diff --git a/src/library/os/linux/os_linux.cpp b/src/library/os/linux/os_linux.cpp
index b23d1af..a5088f7 100644
--- a/src/library/os/linux/os_linux.cpp
+++ b/src/library/os/linux/os_linux.cpp
@@ -20,13 +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
+//#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
+//#endif
 #ifdef USE_DBUS
 #include <dbus-1.0/dbus/dbus.h>
 #endif
@@ -95,7 +95,8 @@
 	return source.substr(startpos, endpos - startpos);
 }
 
-FUNCTION_RETURN parse_blkid(const std::string &blkid_file_content, std::vector<DiskInfo> &diskInfos_out) {
+FUNCTION_RETURN parse_blkid(const std::string &blkid_file_content, std::vector<DiskInfo> &diskInfos_out,
+							std::unordered_map<std::string, int> &disk_by_uuid) {
 	DiskInfo diskInfo;
 	int diskNum = 0;
 	for (std::size_t oldpos = 0, pos = 0; (pos = blkid_file_content.find("</device>", oldpos)) != std::string::npos;
@@ -109,6 +110,7 @@
 		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");
+		disk_by_uuid.insert(std::pair<std::string, int>(disk_sn, diskInfo.id));
 		// 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.
@@ -120,7 +122,8 @@
 
 #define BLKID_LOCATIONS {"/run/blkid/blkid.tab", "/etc/blkid.tab"};
 
-static FUNCTION_RETURN getDiskInfos_blkid(std::vector<DiskInfo> &diskInfos) {
+static FUNCTION_RETURN getDiskInfos_blkid(std::vector<DiskInfo> &diskInfos,
+										  std::unordered_map<std::string, int> &disk_by_uuid) {
 	const char *strs[] = BLKID_LOCATIONS;
 	bool can_read = false;
 	std::stringstream buffer;
@@ -137,62 +140,21 @@
 		return FUNCTION_RETURN::FUNC_RET_NOT_AVAIL;
 	}
 
-	return parse_blkid(buffer.str(), diskInfos);
+	return parse_blkid(buffer.str(), diskInfos, disk_by_uuid);
 }
 
 #define MAX_UNITS 40
-FUNCTION_RETURN getDiskInfos_dev(std::vector<DiskInfo> &diskInfos) {
-	struct dirent *dir = NULL;
+
+static void read_disk_labels(std::vector<DiskInfo> &disk_infos) {
 	struct stat sym_stat;
-	FUNCTION_RETURN result;
+	struct dirent *dir;
 
-	DIR *disk_by_uuid_dir = opendir(ID_FOLDER);
-	if (disk_by_uuid_dir == nullptr) {
-		LOG_DEBUG("Open " ID_FOLDER " fail: %s", std::strerror(errno));
-	} else {
-		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;
-			}
-
-			std::string cur_dir = base_dir + dir->d_name;
-			if (stat(cur_dir.c_str(), &sym_stat) == 0) {
-				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("Found disk inode %d device %s, sn %s", sym_stat.st_ino, tmpDiskInfo.device,
-								  dir->d_name);
-						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);
-	}
-
-	result = diskInfos.size() > 0 ? FUNCTION_RETURN::FUNC_RET_OK : FUNCTION_RETURN::FUNC_RET_NOT_AVAIL;
-	const std::string label_dir("/dev/disk/by-label");
+	std::string label_dir("/dev/disk/by-label");
 	DIR *disk_by_label = opendir(label_dir.c_str());
+	if (disk_by_label == nullptr) {
+		label_dir = "/dev/disk/by-partlabel";
+		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) {
@@ -201,10 +163,12 @@
 			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) {
+				for (auto &diskInfo : disk_infos) {
+					if (((int)(sym_stat.st_ino)) == diskInfo.id) {
 						strncpy(diskInfo.label, dir->d_name, 255 - 1);
 						diskInfo.label_initialized = true;
+						LOG_DEBUG("Label for disk ino %d device %s, set to %s", sym_stat.st_ino, diskInfo.device,
+								  diskInfo.label);
 						break;
 					}
 				}
@@ -216,7 +180,68 @@
 	} else {
 		LOG_DEBUG("Open %s for reading disk labels fail: %s", label_dir.c_str(), std::strerror(errno));
 	}
+}
 
+FUNCTION_RETURN getDiskInfos_dev(std::vector<DiskInfo> &disk_infos,
+								 std::unordered_map<std::string, int> &disk_by_uuid) {
+	struct dirent *dir = NULL;
+	struct stat sym_stat;
+	FUNCTION_RETURN result;
+	char device_name[MAX_PATH];
+
+	DIR *disk_by_uuid_dir = opendir(ID_FOLDER);
+	if (disk_by_uuid_dir == nullptr) {
+		LOG_DEBUG("Open " ID_FOLDER " fail: %s", std::strerror(errno));
+	} else {
+		const std::string base_dir(ID_FOLDER "/");
+		while ((dir = readdir(disk_by_uuid_dir)) != nullptr && disk_infos.size() < MAX_UNITS) {
+			if (::strcmp(dir->d_name, ".") == 0 || ::strcmp(dir->d_name, "..") == 0 ||
+				::strncmp(dir->d_name, "usb", 3) == 0) {
+				continue;
+			}
+
+			std::string cur_dir = base_dir + dir->d_name;
+			if (stat(cur_dir.c_str(), &sym_stat) == 0) {
+				DiskInfo tmpDiskInfo;
+				tmpDiskInfo.id = sym_stat.st_ino;
+				ssize_t len = ::readlink(cur_dir.c_str(), device_name, MAX_PATH - 1);
+				if (len != -1) {
+					device_name[len] = '\0';
+					std::string device_name_s(device_name, len);
+					auto pos = device_name_s.find_last_of("/");
+					if (pos != std::string::npos) {
+						device_name_s = device_name_s.substr(pos + 1);
+					}
+					strncpy(tmpDiskInfo.device, device_name_s.c_str(), sizeof(tmpDiskInfo.device));
+					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 : disk_infos) {
+						if (tmpDiskInfo.id == diskInfo.id) {
+							found = true;
+							break;
+						}
+					}
+					disk_by_uuid.insert(std::pair<std::string, int>(std::string(dir->d_name), tmpDiskInfo.id));
+					if (!found) {
+						LOG_DEBUG("Found disk inode %d device %s, sn %s", sym_stat.st_ino, tmpDiskInfo.device,
+								  dir->d_name);
+						disk_infos.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);
+	}
+
+	result = disk_infos.size() > 0 ? FUNCTION_RETURN::FUNC_RET_OK : FUNCTION_RETURN::FUNC_RET_NOT_AVAIL;
+	read_disk_labels(disk_infos);
 	return result;
 }
 
@@ -226,7 +251,7 @@
  *
  * @param diskInfos
  */
-static void set_preferred_disks(std::vector<DiskInfo> &diskInfos) {
+static void set_preferred_disks(std::vector<DiskInfo> &diskInfos, std::unordered_map<std::string, int> &disk_by_uuid) {
 	FILE *fstabFile = setmntent("/etc/fstab", "r");
 	if (fstabFile == nullptr) {
 		/*fstab not accessible*/
@@ -235,10 +260,35 @@
 	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;
+		std::string device_name_s(ent->mnt_fsname);
+		if (strncmp("UUID=", ent->mnt_fsname, 5) == 0) {
+			// fstab entry is uuid
+			device_name_s = device_name_s.substr(5);
+			auto it = disk_by_uuid.find(device_name_s);
+			if (it != disk_by_uuid.end()) {
+				for (auto &disk_info : diskInfos) {
+					if (it->second == disk_info.id) {
+						disk_info.preferred = true;
+						LOG_DEBUG("Disk %d device %s set as preferred", disk_info.id, disk_info.device);
+						break;
+					}
+				}
+			} else {
+				LOG_DEBUG("fstab device %s found, but no corresponding diskInfo", ent->mnt_fsname);
+			}
+		} else {
+			// fstab entry is a device
+			auto pos = device_name_s.find_last_of("/");
+			if (pos != std::string::npos) {
+				device_name_s = device_name_s.substr(pos + 1);
+			}
+
+			for (auto disk_info : diskInfos) {
+				if (device_name_s == disk_info.device) {
+					disk_info.preferred = true;
+					LOG_DEBUG("Disk %d device %s set as preferred", disk_info.id, disk_info.device);
+					break;
+				}
 			}
 		}
 	}
@@ -247,19 +297,22 @@
 }
 
 /**
- * First try to read disk_infos from /dev/disk/by-id folder, if fails try to use
+ * First try to read disk_infos from /dev/disk/by-uuid 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);
+	std::unordered_map<std::string, int> disk_by_uuid;
+
+	FUNCTION_RETURN result = getDiskInfos_dev(disk_infos, disk_by_uuid);
+
 	if (result != FUNCTION_RETURN::FUNC_RET_OK) {
-		result = getDiskInfos_blkid(disk_infos);
+		result = getDiskInfos_blkid(disk_infos, disk_by_uuid);
 	}
 	if (result == FUNCTION_RETURN::FUNC_RET_OK) {
-		set_preferred_disks(disk_infos);
+		set_preferred_disks(disk_infos, disk_by_uuid);
 	}
 	return result;
 }

--
Gitblit v1.9.1