FruDevice: improve boot

i2c-devices changing is not very common after boot,
since we are scanning everything during boot, we end
up rescanning everything multiple times. Just rescan
the newly added busses instead.

Tested: ipmitool sensor list and ipmitool fru list
looked normal

Change-Id: I52d6647ac3bcee6b192539d512d21edc315e85f7
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/src/FruDevice.cpp b/src/FruDevice.cpp
index 22ad48b..d593c30 100644
--- a/src/FruDevice.cpp
+++ b/src/FruDevice.cpp
@@ -259,6 +259,16 @@
     return read(fd, buf, len);
 }
 
+static int busStrToInt(const std::string& busName)
+{
+    auto findBus = busName.rfind("-");
+    if (findBus == std::string::npos)
+    {
+        return -1;
+    }
+    return std::stoi(busName.substr(findBus + 1));
+}
+
 static int getRootBus(size_t bus)
 {
     auto ec = std::error_code();
@@ -691,15 +701,13 @@
 {
     for (auto& i2cBus : i2cBuses)
     {
-        auto busnum = i2cBus.string();
-        auto lastDash = busnum.rfind(std::string("-"));
-        // delete everything before dash inclusive
-        if (lastDash != std::string::npos)
-        {
-            busnum.erase(0, lastDash + 1);
-        }
+        int bus = busStrToInt(i2cBus);
 
-        auto bus = std::stoi(busnum);
+        if (bus < 0)
+        {
+            std::cerr << "Cannot translate " << i2cBus << " to int\n";
+            continue;
+        }
         if (busBlacklist.find(bus) != busBlacklist.end())
         {
             continue; // skip previously failed busses
@@ -1304,19 +1312,9 @@
     BusMap& busmap, uint8_t busNum,
     boost::container::flat_map<
         std::pair<size_t, size_t>,
-        std::shared_ptr<sdbusplus::asio::dbus_interface>>& dbusInterfaceMap)
+        std::shared_ptr<sdbusplus::asio::dbus_interface>>& dbusInterfaceMap,
+    bool dbusCall)
 {
-    fs::path busPath = fs::path("/dev/i2c-" + std::to_string(busNum));
-    if (!fs::exists(busPath))
-    {
-        std::cerr << "Unable to access i2c bus " << static_cast<int>(busNum)
-                  << "\n";
-        throw std::invalid_argument("Invalid Bus.");
-    }
-
-    std::vector<fs::path> i2cBuses;
-    i2cBuses.emplace_back(busPath);
-
     for (auto& [pair, interface] : foundDevices)
     {
         if (pair.first == static_cast<size_t>(busNum))
@@ -1326,6 +1324,21 @@
         }
     }
 
+    fs::path busPath = fs::path("/dev/i2c-" + std::to_string(busNum));
+    if (!fs::exists(busPath))
+    {
+        if (dbusCall)
+        {
+            std::cerr << "Unable to access i2c bus " << static_cast<int>(busNum)
+                      << "\n";
+            throw std::invalid_argument("Invalid Bus.");
+        }
+        return;
+    }
+
+    std::vector<fs::path> i2cBuses;
+    i2cBuses.emplace_back(busPath);
+
     auto scan = std::make_shared<FindDevicesWithCallback>(
         i2cBuses, busmap, [busNum, &busmap, &dbusInterfaceMap]() {
             for (auto& busIface : dbusInterfaceMap)
@@ -1441,7 +1454,7 @@
                            [&]() { rescanBusses(busMap, dbusInterfaceMap); });
 
     iface->register_method("ReScanBus", [&](uint8_t bus) {
-        rescanOneBus(busMap, bus, dbusInterfaceMap);
+        rescanOneBus(busMap, bus, dbusInterfaceMap, true);
     });
 
     iface->register_method("GetRawFru", getFruInfo);
@@ -1503,7 +1516,6 @@
                 return;
             }
             pendingBuffer += std::string(readBuffer.data(), bytes_transferred);
-            bool devChange = false;
             while (pendingBuffer.size() > sizeof(inotify_event))
             {
                 const inotify_event* iEvent =
@@ -1514,19 +1526,23 @@
                     case IN_CREATE:
                     case IN_MOVED_TO:
                     case IN_DELETE:
-                        if (boost::starts_with(std::string(iEvent->name),
-                                               "i2c"))
+                        std::string name(iEvent->name);
+                        if (boost::starts_with(name, "i2c"))
                         {
-                            devChange = true;
+                            int bus = busStrToInt(name);
+                            if (bus < 0)
+                            {
+                                std::cerr << "Could not parse bus " << name
+                                          << "\n";
+                                continue;
+                            }
+                            rescanOneBus(busMap, static_cast<uint8_t>(bus),
+                                         dbusInterfaceMap, false);
                         }
                 }
 
                 pendingBuffer.erase(0, sizeof(inotify_event) + iEvent->len);
             }
-            if (devChange)
-            {
-                rescanBusses(busMap, dbusInterfaceMap);
-            }
 
             dirWatch.async_read_some(boost::asio::buffer(readBuffer),
                                      watchI2cBusses);