Translate Udev Event path to a generic path

Given Udev event generated path is translated into sys bus path - as the json will
have the sys/bus path.

Test:
-> Translation successful for all frus including frus behind muxes.
-> If the system vpd is triggered by udev event, then the execution stops as
the system vpd will already be parsed via system-vpd.service.

Few Reasons why we translate the path to a generic path:
	-> Each i2c bus is memory mapped to a certain address in ASPEED.
	   In future if there are any architectural changes in the kernel, we need to
	   make changes to the JSON accordingly.
	-> Also in future if the system runs on a different ASPEED, we need to
	   update the JSON accordingly.
	-> This generic /sys/bus path represents the system wiring and doesnot rely on
	   how the busses are memory mapped.
	-> Also for call out based events, generic path is expected than the udev event path.

Sample Udev Event i2c path : "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0050/8-00500/nvmem"
Which gets translated to /sys/bus/ path as : "/sys/bus/i2c/drivers/at24/8-0050/eeprom"

Sample Udev Event spi path : "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/fsi-master/fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/slave@03:00/01:03:00:04/spi_master/spi6/spi6.0/spi6.00/nvmem"
Which gets translated to /sys/bus/ path as : "/sys/bus/spi/drivers/at25/spi6.0/eeprom"

Sample Udev Event i2c path for frus behind mux : "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a300.i2c-bus/i2c-5/i2c-24/24-0051/24-00510/nvmem"
Which gets translated to generic path as /sys/bus/i2c/drivers/at24/24-0051/eeprom

Tested on simics:

<the inventory json should have generic eeprom paths for all frus>

root@rainier:/tmp# ./ibm-read-vpd-UG -f /sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/fsi-master/fsi0/slave@00:00/00:00:00:04/spi_master/spi12/spi12.0/spi12.00/nvmem
the path after translation : /sys/bus/spi/drivers/at25/spi12.0/eeprom

root@rainier:/tmp# ./ibm-read-vpd-UG -f /sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem
the path after translation : /sys/bus/i2c/drivers/at24/8-0051/eeprom

root@rainier:/tmp# ./ibm-read-vpd-UG -f /sys/bus/i2c/drivers/at24/8-0051/8-00510/nvmem
the path after translation : /sys/bus/i2c/drivers/at24/8-0051/eeprom

Signed-off-by: PriyangaRamasamy <priyanga24@in.ibm.com>
Change-Id: I6d5995a85ef15e63d2d0b6f054fb0bf14a2b756c
diff --git a/ibm_vpd_utils.cpp b/ibm_vpd_utils.cpp
index 15e3116..3c7304f 100644
--- a/ibm_vpd_utils.cpp
+++ b/ibm_vpd_utils.cpp
@@ -11,6 +11,7 @@
 #include <nlohmann/json.hpp>
 #include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/log.hpp>
+#include <regex>
 #include <sdbusplus/server.hpp>
 #include <sstream>
 #include <vector>
@@ -420,5 +421,71 @@
     return jsonPath;
 }
 
+void udevToGenericPath(string& file)
+{
+    // Sample udevEvent i2c path :
+    // "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem"
+    // find if the path contains the word i2c in it.
+    if (file.find("i2c") != string::npos)
+    {
+        string i2cBusAddr{};
+
+        // Every udev i2c path should have the common pattern
+        // "i2c-bus_number/bus_number-vpd_address". Search for
+        // "bus_number-vpd_address".
+        regex i2cPattern("((i2c)-[0-9]+\\/)([0-9]+-[0-9]{4})");
+        smatch match;
+        if (regex_search(file, match, i2cPattern))
+        {
+            i2cBusAddr = match.str(3);
+        }
+        else
+        {
+            cerr << "The given udev path < " << file
+                 << " > doesn't match the required pattern. Skipping VPD "
+                    "collection."
+                 << endl;
+            exit(EXIT_SUCCESS);
+        }
+        // Forming the generic file path
+        file = i2cPathPrefix + i2cBusAddr + "/eeprom";
+    }
+    // Sample udevEvent spi path :
+    // "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/fsi-master/fsi0/slave@00:00/00:00:00:04/spi_master/spi2/spi2.0/spi2.00/nvmem"
+    // find if the path contains the word spi in it.
+    else if (file.find("spi") != string::npos)
+    {
+        // Every udev spi path will have common pattern "spi<Digit>/", which
+        // describes the spi bus number at which the fru is connected; Followed
+        // by a slash following the vpd address of the fru. Taking the above
+        // input as a common key, we try to search for the pattern "spi<Digit>/"
+        // using regular expression.
+        regex spiPattern("((spi)[0-9]+)(\\/)");
+        string spiBus{};
+        smatch match;
+        if (regex_search(file, match, spiPattern))
+        {
+            spiBus = match.str(1);
+        }
+        else
+        {
+            cerr << "The given udev path < " << file
+                 << " > doesn't match the required pattern. Skipping VPD "
+                    "collection."
+                 << endl;
+            exit(EXIT_SUCCESS);
+        }
+        // Forming the generic path
+        file = spiPathPrefix + spiBus + ".0/eeprom";
+    }
+    else
+    {
+        cerr << "\n The given EEPROM path < " << file
+             << " > is not valid. It's neither I2C nor "
+                "SPI path. Skipping VPD collection.."
+             << endl;
+        exit(EXIT_SUCCESS);
+    }
+}
 } // namespace vpd
 } // namespace openpower
\ No newline at end of file