gpio-presence: Support for multiple iface assocs

This will allow additional interfaces to be specified
to associate with inventory items to allow for further
customization of inventory items.

Specifying property values for an interface added this way
is currently not supported.

Tested: Verified any given interface(s) is associated properly

Signed-off-by: Anthony Wilson <wilsonan@us.ibm.com>
Change-Id: I99e655b35120c82454a8851201218ec548ad9fe3
diff --git a/presence/argument.cpp b/presence/argument.cpp
index e256426..c0d0ee3 100644
--- a/presence/argument.cpp
+++ b/presence/argument.cpp
@@ -30,13 +30,14 @@
 const std::string ArgumentParser::trueString = "true"s;
 const std::string ArgumentParser::emptyString = ""s;
 
-const char* ArgumentParser::optionStr = "p:k:n:i:d:?h";
+const char* ArgumentParser::optionStr = "p:k:n:i:d:e:?h";
 const option ArgumentParser::options[] = {
     {"path", required_argument, nullptr, 'p'},
     {"key", required_argument, nullptr, 'k'},
     {"name", required_argument, nullptr, 'n'},
     {"inventory", required_argument, nullptr, 'i'},
     {"drivers", required_argument, nullptr, 'd'},
+    {"extra-ifaces", required_argument, nullptr, 'e'},
     {"help", no_argument, nullptr, 'h'},
     {0, 0, 0, 0},
 };
@@ -97,6 +98,12 @@
                  " of path,device pairs.  For example:\n";
     std::cerr << "                          "
                  "/sys/bus/i2c/drivers/some-driver,3-0068\n";
+    std::cerr << "  --extra-ifaces=<ifaces> List of interfaces to associate to"
+                 " inventory item\n";
+    std::cerr << "                          Format is a comma separated list"
+                 " of interfaces.         For example:\n";
+    std::cerr << "                          "
+                 "/xyz/openbmc_project/.../1,/xyz/openbmc_project/.../2\n";
     std::cerr << std::flush;
     exit(-1);
 }
diff --git a/presence/gpio_presence.cpp b/presence/gpio_presence.cpp
index 1671721..4326602 100644
--- a/presence/gpio_presence.cpp
+++ b/presence/gpio_presence.cpp
@@ -145,6 +145,11 @@
     invProp.emplace("Present", present);
     invProp.emplace("PrettyName", name);
     invIntf.emplace("xyz.openbmc_project.Inventory.Item", std::move(invProp));
+    // Add any extra interfaces we want to associate with the inventory item
+    for (auto& iface : ifaces)
+    {
+        invIntf.emplace(iface, PropertyMap());
+    }
     invObj.emplace(std::move(inventory), std::move(invIntf));
 
     return invObj;
diff --git a/presence/gpio_presence.hpp b/presence/gpio_presence.hpp
index 834a171..edd2d7a 100644
--- a/presence/gpio_presence.hpp
+++ b/presence/gpio_presence.hpp
@@ -18,6 +18,7 @@
 using Device = std::string;
 using Path = std::experimental::filesystem::path;
 using Driver = std::tuple<Device, Path>;
+using Interface = std::string;
 
 /** @class Presence
  *  @brief Responsible for determining and monitoring presence,
@@ -57,6 +58,8 @@
      *  @param[in] name      - Pretty name of the inventory item
      *  @param[in] event     - sd_event handler
      *  @param[in] drivers   - list of device drivers to bind and unbind
+     *  @param[in] ifaces    - list of extra interfaces to associate with the
+     *                         inventory item
      *  @param[in] handler   - IO callback handler. Defaults to one in this
      *                        class
      */
@@ -64,9 +67,11 @@
              const std::string& path, const unsigned int key,
              const std::string& name, EventPtr& event,
              const std::vector<Driver>& drivers,
+             const std::vector<Interface>& ifaces,
              sd_event_io_handler_t handler = Presence::processEvents) :
         Evdev(path, key, event, handler, true),
-        bus(bus), inventory(inventory), name(name), drivers(drivers)
+        bus(bus), inventory(inventory), name(name), drivers(drivers),
+        ifaces(ifaces)
     {
         determinePresence();
     }
@@ -122,6 +127,11 @@
     /** @brief  Vector of path and device tuples to bind/unbind*/
     const std::vector<Driver> drivers;
 
+    /** @brief  Vector of extra inventory interfaces to associate with the
+     *          inventory item
+     */
+    const std::vector<Interface> ifaces;
+
     /**
      * @brief Binds or unbinds drivers
      *
diff --git a/presence/main.cpp b/presence/main.cpp
index 16866d4..eace07e 100644
--- a/presence/main.cpp
+++ b/presence/main.cpp
@@ -64,6 +64,7 @@
     auto key = options["key"];
     auto path = options["path"];
     auto drivers = options["drivers"];
+    auto ifaces = options["extra-ifaces"];
     if (argc < 4)
     {
         std::cerr << "Too few arguments\n";
@@ -99,6 +100,19 @@
         }
     }
 
+    std::vector<Interface> ifaceList;
+
+    // Extra interfaces list is optional
+    if (ifaces != ArgumentParser::emptyString)
+    {
+        std::stringstream ss(ifaces);
+        Interface iface;
+        while (std::getline(ss, iface, ','))
+        {
+            ifaceList.push_back(iface);
+        }
+    }
+
     auto bus = sdbusplus::bus::new_default();
     auto rc = 0;
     sd_event* event = nullptr;
@@ -113,7 +127,7 @@
 
     auto name = options["name"];
     Presence presence(bus, inventory, path, std::stoul(key), name, eventP,
-                      driverList);
+                      driverList, ifaceList);
 
     while (true)
     {