From 50e2fa22298de13fd731488306d2cbd0081730d8 Mon Sep 17 00:00:00 2001
From: Sathvika Vasireddy <sv@linux.ibm.com>
Date: Fri, 10 Feb 2023 14:55:41 +0530
Subject: [PATCH] lsvpd: Fill firmware information by recursively looking for
 firmware specific files within sysfs ID

Patch-mainline: expected in v1.7.15
Git-commit: 50e2fa22298de13fd731488306d2cbd0081730d8

Currently, fillFirmware() is filling firmware information based on the
classNode value of a given component. It then looks for firmware specific
sysfs files (fw_version, fwrev, firmware_rev), within the classNode path,
to set firmware fields accordingly. For components that do not have a
classNode value, fillFirmware() does not look for firmware information
within the sysfs firmware files, and hence does not set firmware fields.

This patch recursively looks for sysfs firmware files within the ID path of
a component, and sets the firmware fields accordingly, if not already set.

Reported-by: Borislav Stoymirski <borislav.stoymirski@bg.ibm.com>
Signed-off-by: Sathvika Vasireddy <sv@linux.ibm.com>
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.ibm.com>
Tested-by: Borislav Stoymirski <borislav.stoymirski@bg.ibm.com>
---
 src/include/icollector.hpp                    | 19 ++++++++++
 src/internal/sys_interface/icollector.cpp     | 35 +++++++++++++++++++
 .../sys_interface/sysfstreecollector.cpp      | 21 +++++++++++
 3 files changed, 75 insertions(+)

diff --git a/src/include/icollector.hpp b/src/include/icollector.hpp
index 894dd99..392632f 100644
--- a/src/include/icollector.hpp
+++ b/src/include/icollector.hpp
@@ -116,6 +116,25 @@ namespace lsvpd
 			virtual ~ICollector( ){}
 
 			protected:
+				/** Recursively search for attrName within a given path.
+				 *
+				 * @param path
+				 *   Directory path to search for filename.
+				 *
+				 * @param attrName
+				 *   Filename to search for.
+				 *
+				 * @return
+				 *   Path in which attrName file exists.
+				 *
+				 *   If attrName is fwrev, and is found at
+				 *   /sys/devices/pci0020:01/0020:01:00.1/host4/scsi_host/host4/fwrev,
+				 *   searchFile() will return
+				 *   /sys/devices/pci0020:01/0020:01:00.1/host4/scsi_host/host4.
+				 */
+				string searchFile( const string& path,
+						const string& attrName );
+
 				string getAttrValue( const string& path,
 					const string& attrName );
 
diff --git a/src/internal/sys_interface/icollector.cpp b/src/internal/sys_interface/icollector.cpp
index 5c4dccc..7586fe8 100644
--- a/src/internal/sys_interface/icollector.cpp
+++ b/src/internal/sys_interface/icollector.cpp
@@ -32,11 +32,46 @@
 #include <fstream>
 #include <cstring>
 #include <bitset>
+#include <iostream>
+#include <dirent.h>
+#include <string.h>
 
 using namespace std;
 
 namespace lsvpd
 {
+
+	string ICollector::searchFile( const string& path, const string& attrName )
+	{
+		DIR *dir;
+		struct dirent *entry;
+
+		if ((dir = opendir(path.c_str())) == NULL)
+			return "";
+
+		while ((entry = readdir(dir)) != NULL) {
+			if (entry->d_type == DT_DIR) {
+				// Found a directory, but ignore . and ..
+				if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+					continue;
+				string newPath = path + "/" + entry->d_name;
+				string result = searchFile(newPath, attrName);
+				if (result != "") {
+					closedir(dir);
+					return result;
+				}
+			}
+			else {
+				if (entry->d_name == attrName) {
+					closedir(dir);
+					return path;
+				}
+			}
+		}
+		closedir(dir);
+		return "";
+	}
+
 	/**
 	 * Read a device attribute, given dev path and attribute name
 	 * @var path Full path to device in sysfs
diff --git a/src/internal/sys_interface/sysfstreecollector.cpp b/src/internal/sys_interface/sysfstreecollector.cpp
index c5eb71d..03eb7da 100644
--- a/src/internal/sys_interface/sysfstreecollector.cpp
+++ b/src/internal/sys_interface/sysfstreecollector.cpp
@@ -1837,6 +1837,10 @@ ERROR:
 
 	void SysFSTreeCollector::fillFirmware( Component* fillMe )
 	{
+		string result = "";
+		string path = fillMe->getID();
+		const string firmwareAttributes[] = {"fw_version", "firmware_rev"};
+		const size_t firmwareAttributesSize = sizeof(firmwareAttributes) / sizeof(firmwareAttributes[0]);
 		string classNode = fillMe->getClassNode();
 		if (classNode.length() > 0) {
 			fillMe->mFirmwareVersion.setValue( getAttrValue( classNode,
@@ -1848,6 +1852,23 @@ ERROR:
 			fillMe->mFirmwareVersion.setValue( getAttrValue( classNode,
 					"firmware_rev" ), 30, __FILE__, __LINE__ );
 		}
+
+		if (fillMe->mFirmwareLevel.dataValue.empty()) {
+			result = searchFile(path, "fwrev");
+			if (!result.empty()) {
+				fillMe->mFirmwareLevel.setValue( getAttrValue( result,
+							"fwrev" ), 30, __FILE__, __LINE__ );
+			}
+		}
+
+		for (size_t i = 0; i < firmwareAttributesSize && fillMe->mFirmwareVersion.dataValue.empty(); i++) {
+			result = searchFile(path, firmwareAttributes[i]);
+			if (!result.empty()) {
+				fillMe->mFirmwareVersion.setValue( getAttrValue( result,
+							firmwareAttributes[i]), 30, __FILE__, __LINE__ );
+				break;
+			}
+		}
 	}
 
 	string SysFSTreeCollector::resolveClassPath( const string& path )
-- 
2.41.0

