Find P10 OCCs by looking in /dev

Find the exact OCCs present in the system by looking for the OCC devices
in /dev.  They look like /dev/occ1, /dev/occ2, etc.  The /dev/occ1 entry
will translate to Status object /org/open_power/control/occ0.

In order to handle the case where the application starts before all
devices show up, keep checking until at least 10 seconds have gone by
without a new device showing up (with at least one device present).

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I42289d55a6266d710b313af0a49070eeacccd725
diff --git a/occ_manager.cpp b/occ_manager.cpp
index 69f01ea..04276b9 100644
--- a/occ_manager.cpp
+++ b/occ_manager.cpp
@@ -6,6 +6,7 @@
 #include "occ_dbus.hpp"
 #include "utils.hpp"
 
+#include <chrono>
 #include <cmath>
 #include <experimental/filesystem>
 #include <phosphor-logging/elog-errors.hpp>
@@ -50,12 +51,62 @@
 
 void Manager::findAndCreateObjects()
 {
+#ifndef POWER10
     for (auto id = 0; id < MAX_CPUS; ++id)
     {
         // Create one occ per cpu
         auto occ = std::string(OCC_NAME) + std::to_string(id);
         createObjects(occ);
     }
+#else
+    // Create the OCCs based on on the /dev/occX devices
+    auto occs = findOCCsInDev();
+
+    if (occs.empty() || (prevOCCSearch.size() != occs.size()))
+    {
+        // Something changed or no OCCs yet, try again in 10s.
+        // Note on the first pass prevOCCSearch will be empty,
+        // so there will be at least one delay to give things
+        // a chance to settle.
+        prevOCCSearch = occs;
+
+        using namespace std::literals::chrono_literals;
+        discoverTimer->restartOnce(10s);
+    }
+    else
+    {
+        discoverTimer.reset();
+
+        // createObjects requires OCC0 first.
+        std::sort(occs.begin(), occs.end());
+
+        for (auto id : occs)
+        {
+            createObjects(std::string(OCC_NAME) + std::to_string(id));
+        }
+    }
+#endif
+}
+
+std::vector<int> Manager::findOCCsInDev()
+{
+    std::vector<int> occs;
+    std::regex expr{R"(occ(\d+)$)"};
+
+    for (auto& file : fs::directory_iterator("/dev"))
+    {
+        std::smatch match;
+        std::string path{file.path().string()};
+        if (std::regex_search(path, match, expr))
+        {
+            auto num = std::stoi(match[1].str());
+
+            // /dev numbering starts at 1, ours starts at 0.
+            occs.push_back(num - 1);
+        }
+    }
+
+    return occs;
 }
 
 int Manager::cpuCreated(sdbusplus::message::message& msg)