Attn: Refactor dbus calls for pel handling

Removed hard-coded system names and instead find system name by dbus
object path and interface. Add try/catch handling around dbus calls that
could throw exceptions.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I9cfe5fce858ba690fc9a7f0e61a4d249d5a1ef84
diff --git a/attn/attn_dbus.cpp b/attn/attn_dbus.cpp
new file mode 100644
index 0000000..72b637e
--- /dev/null
+++ b/attn/attn_dbus.cpp
@@ -0,0 +1,212 @@
+#include <attn_logging.hpp>
+
+#include <string>
+#include <vector>
+
+namespace attn
+{
+
+/**
+ * Create a dbus method
+ *
+ * Find the dbus service associated with the dbus object path and create
+ * a dbus method for calling the specified dbus interface and function.
+ *
+ * @param i_path - dbus object path
+ * @param i_interface - dbus method interface
+ * @param i_function - dbus interface function
+ * @param o_method - method that is created
+ * @return non-zero if error
+ *
+ **/
+int dbusMethod(const std::string& i_path, const std::string& i_interface,
+               const std::string& i_function,
+               sdbusplus::message::message& o_method)
+{
+    int rc = 1; // assume error
+
+    try
+    {
+        constexpr auto serviceFind   = "xyz.openbmc_project.ObjectMapper";
+        constexpr auto pathFind      = "/xyz/openbmc_project/object_mapper";
+        constexpr auto interfaceFind = "xyz.openbmc_project.ObjectMapper";
+        constexpr auto functionFind  = "GetObject";
+
+        auto bus = sdbusplus::bus::new_system(); // using system dbus
+
+        // method to find service from object path and object interface
+        auto method = bus.new_method_call(serviceFind, pathFind, interfaceFind,
+                                          functionFind);
+
+        // find the service for specified object path and interface
+        method.append(i_path.c_str());
+        method.append(std::vector<std::string>({i_interface}));
+        auto reply = bus.call(method);
+
+        // dbus call results
+        std::map<std::string, std::vector<std::string>> responseFindService;
+        reply.read(responseFindService);
+
+        // If we successfully found the service associated with the dbus object
+        // path and interface then create a method for the specified interface
+        // and function.
+        if (!responseFindService.empty())
+        {
+            auto service = responseFindService.begin()->first;
+
+            // return the method
+            o_method =
+                bus.new_method_call(service.c_str(), i_path.c_str(),
+                                    i_interface.c_str(), i_function.c_str());
+
+            rc = 0;
+        }
+        else
+        {
+            std::stringstream ss;
+            ss << "dbusMethod service not found:  " << i_path.c_str() << ", "
+               << i_interface.c_str();
+            trace<level::INFO>(ss.str().c_str());
+        }
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        std::stringstream ss;
+        ss << "dbusMethod exception:  " << e.what();
+        trace<level::INFO>(ss.str().c_str());
+    }
+
+    return rc;
+}
+
+/** @brief Create a PEL for the specified event type */
+uint32_t createPel(const std::string& i_event,
+                   std::map<std::string, std::string>& i_additional,
+                   const std::vector<util::FFDCTuple>& i_ffdc)
+{
+    // CreatePELWithFFDCFiles returns plid
+    int plid = 0;
+
+    // Need to provide pid when using create or create-with-ffdc methods
+    i_additional.emplace("_PID", std::to_string(getpid()));
+
+    // Sdbus call specifics
+    constexpr auto interface = "org.open_power.Logging.PEL";
+    constexpr auto function  = "CreatePELWithFFDCFiles";
+
+    sdbusplus::message::message method;
+
+    if (0 == dbusMethod(pathLogging, interface, function, method))
+    {
+        try
+        {
+            // append additional dbus call paramaters
+            method.append(i_event, levelPelError, i_additional, i_ffdc);
+
+            // using system dbus
+            auto bus      = sdbusplus::bus::new_system();
+            auto response = bus.call(method);
+
+            // reply will be tuple containing bmc log id, platform log id
+            std::tuple<uint32_t, uint32_t> reply = {0, 0};
+
+            // parse dbus reply
+            response.read(reply);
+            plid = std::get<1>(reply); // platform log id is tuple "second"
+        }
+        catch (const sdbusplus::exception::SdBusError& e)
+        {
+            std::stringstream ss;
+            ss << "createPel exception:  " << e.what();
+            trace<level::INFO>(ss.str().c_str());
+        }
+    }
+
+    return plid; // platform log id or 0
+}
+
+/** @brief Create a PEL from raw PEL data */
+void createPelRaw(const std::vector<uint8_t>& i_buffer)
+{
+    // Create FFDC file from buffer data
+    util::FFDCFile pelFile{util::FFDCFormat::Text};
+    auto fd = pelFile.getFileDescriptor();
+    write(fd, i_buffer.data(), i_buffer.size());
+    lseek(fd, 0, SEEK_SET);
+
+    auto filePath = pelFile.getPath(); // path to ffdc file
+
+    // Additional data for log
+    std::map<std::string, std::string> additional;
+    additional.emplace("RAWPEL", filePath.string());
+    additional.emplace("_PID", std::to_string(getpid()));
+
+    // dbus specifics
+    constexpr auto interface = "xyz.openbmc_project.Logging.Create";
+    constexpr auto function  = "Create";
+
+    sdbusplus::message::message method;
+
+    if (0 == dbusMethod(pathLogging, interface, function, method))
+    {
+        try
+        {
+            // append additional dbus call parameters
+            method.append(eventPelTerminate, levelPelError, additional);
+
+            // using system dbus, no reply
+            auto bus = sdbusplus::bus::new_system();
+            bus.call_noreply(method);
+        }
+        catch (const sdbusplus::exception::SdBusError& e)
+        {
+            std::stringstream ss;
+            ss << "createPelRaw exception:  " << e.what();
+            trace<level::INFO>(ss.str().c_str());
+        }
+    }
+}
+
+/** @brief Get file descriptor of exisitng PEL */
+int getPel(const uint32_t i_pelId)
+{
+    // GetPEL returns file descriptor (int)
+    int fd = -1;
+
+    // dbus specifics
+    constexpr auto interface = "org.open_power.Logging.PEL";
+    constexpr auto function  = "GetPEL";
+
+    sdbusplus::message::message method;
+
+    if (0 == dbusMethod(pathLogging, interface, function, method))
+    {
+        try
+        {
+            // additional dbus call parameters
+            method.append(i_pelId);
+
+            // using system dbus
+            auto bus      = sdbusplus::bus::new_system();
+            auto response = bus.call(method);
+
+            // reply will be a unix file descriptor
+            sdbusplus::message::unix_fd reply;
+
+            // parse dbus reply
+            response.read(reply);
+
+            fd = dup(reply); // need to copy (dup) the file descriptor
+        }
+        catch (const sdbusplus::exception::SdBusError& e)
+        {
+            std::stringstream ss;
+            ss << "getPel exception:  " << e.what();
+            trace<level::INFO>(ss.str().c_str());
+        }
+    }
+
+    return fd; // file descriptor or -1
+}
+
+} // namespace attn
diff --git a/attn/attn_dbus.hpp b/attn/attn_dbus.hpp
new file mode 100644
index 0000000..8f21fbe
--- /dev/null
+++ b/attn/attn_dbus.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <sdbusplus/bus.hpp>
+#include <util/ffdc_file.hpp>
+
+#include <string>
+
+namespace attn
+{
+
+/**
+ * Create a PEL for the specified event type
+ *
+ * The additional data provided in the map will be placed in a user data
+ * section of the PEL and may additionally contain key words to trigger
+ * certain behaviors by the backend logging code. Each set of data described
+ * in the vector of ffdc data will be placed in additional user data
+ * sections.
+ *
+ * @param  i_event - the event type
+ * @param  i_additional - map of additional data
+ * @param  i_ffdc - vector of ffdc data
+ * @return Platform log id or 0 if error
+ */
+uint32_t createPel(const std::string& i_event,
+                   std::map<std::string, std::string>& i_additional,
+                   const std::vector<util::FFDCTuple>& i_ffdc);
+
+/**
+ * Create a PEL from raw PEL data
+ *
+ * Create a PEL based on the pel defined in the data buffer specified.
+ *
+ * @param   i_buffer - buffer containing a raw PEL
+ */
+void createPelRaw(const std::vector<uint8_t>& i_buffer);
+
+/**
+ * Get file descriptor of exisitng PEL
+ *
+ * The backend logging code will search for a PEL having the provided pel id
+ * and return a file descriptor of a file containing this pel in raw form.
+ *
+ * @param  i_pelid - the PEL ID
+ * @return file descriptor or -1 if error
+ */
+int getPel(const uint32_t i_pelId);
+
+} // namespace attn
diff --git a/attn/attn_logging.cpp b/attn/attn_logging.cpp
index 78b72e8..70acaa4 100644
--- a/attn/attn_logging.cpp
+++ b/attn/attn_logging.cpp
@@ -1,5 +1,6 @@
 #include <unistd.h>
 
+#include <attn/attn_dbus.hpp>
 #include <attn/attn_logging.hpp>
 #include <attn/pel/pel_minimal.hpp>
 #include <phosphor-logging/log.hpp>
@@ -162,150 +163,6 @@
 }
 
 /**
- * Get file descriptor of exisitng PEL
- *
- * The backend logging code will search for a PEL having the provided PEL ID
- * and return a file descriptor to a file containing this PEL's  raw PEL data.
- *
- * @param  i_pelid - the PEL ID
- * @return file descriptor of file containing the raw PEL data
- */
-int getPelFd(uint32_t i_pelId)
-{
-    // GetPEL returns file descriptor (int)
-    int fd = -1;
-
-    // Get the PEL file descriptor
-    try
-    {
-        // Sdbus call specifics
-        constexpr auto service   = "xyz.openbmc_project.Logging";
-        constexpr auto path      = "/xyz/openbmc_project/logging";
-        constexpr auto interface = "org.open_power.Logging.PEL";
-        constexpr auto function  = "GetPEL";
-
-        auto bus    = sdbusplus::bus::new_default_system();
-        auto method = bus.new_method_call(service, path, interface, function);
-        method.append(i_pelId);
-
-        auto resp = bus.call(method);
-
-        sdbusplus::message::unix_fd msgFd;
-        resp.read(msgFd);
-        fd = dup(msgFd); // -1 if not found
-    }
-    catch (const sdbusplus::exception::SdBusError& e)
-    {
-        std::stringstream ss;
-        ss << "getPelFd: " << e.what();
-        trace<level::INFO>(ss.str().c_str());
-    }
-
-    // File descriptor or -1 if not found or call failed
-    return fd;
-}
-
-/**
- * Create a PEL for the specified event type
- *
- * The additional data provided in the map will be placed in a user data
- * section of the PEL and may additionally contain key words to trigger
- * certain behaviors by the backend logging code. Each set of data described
- * in the vector of ffdc data will be placed in additional user data sections.
- *
- * @param  i_event - the event type
- * @param  i_additional - map of additional data
- * @param  9_ffdc - vector of ffdc data
- * @return The created PEL's platform log-id
- */
-uint32_t createPel(std::string i_event,
-                   std::map<std::string, std::string> i_additional,
-                   std::vector<util::FFDCTuple> i_ffdc)
-{
-    // CreatePELWithFFDCFiles returns log-id and platform log-id
-    std::tuple<uint32_t, uint32_t> pelResp = {0, 0};
-
-    // Need to provide pid when using create or create-with-ffdc methods
-    i_additional.emplace("_PID", std::to_string(getpid()));
-
-    // Create the PEL
-    try
-    {
-        // Sdbus call specifics
-        constexpr auto level = "xyz.openbmc_project.Logging.Entry.Level.Error";
-        constexpr auto service   = "xyz.openbmc_project.Logging";
-        constexpr auto path      = "/xyz/openbmc_project/logging";
-        constexpr auto interface = "org.open_power.Logging.PEL";
-        constexpr auto function  = "CreatePELWithFFDCFiles";
-
-        auto bus    = sdbusplus::bus::new_default_system();
-        auto method = bus.new_method_call(service, path, interface, function);
-        method.append(i_event, level, i_additional, i_ffdc);
-
-        auto resp = bus.call(method);
-
-        resp.read(pelResp);
-    }
-    catch (const sdbusplus::exception::SdBusError& e)
-    {
-        std::stringstream ss;
-        ss << "createPel: " << e.what();
-        trace<level::INFO>(ss.str().c_str());
-    }
-
-    // pelResp<0> == log-id, pelResp<1> = platform log-id
-    return std::get<1>(pelResp);
-}
-
-/*
- * Create a PEL from raw PEL data
- *
- * The backend logging code will create a PEL based on the specified PEL data.
- *
- * @param   i_buffer - buffer containing a raw PEL
- */
-void createPelRaw(std::vector<uint8_t>& i_buffer)
-{
-    // Create FFDC file from buffer data
-    util::FFDCFile pelFile{util::FFDCFormat::Text};
-    auto fd = pelFile.getFileDescriptor();
-
-    write(fd, i_buffer.data(), i_buffer.size());
-    lseek(fd, 0, SEEK_SET);
-
-    auto filePath = pelFile.getPath();
-
-    // Additional data for log
-    std::map<std::string, std::string> additional;
-    additional.emplace("RAWPEL", filePath.string());
-    additional.emplace("_PID", std::to_string(getpid()));
-
-    // Create the PEL
-    try
-    {
-        // Sdbus call specifics
-        constexpr auto pelEvent = "xyz.open_power.Attn.Error.Terminate";
-        constexpr auto level = "xyz.openbmc_project.Logging.Entry.Level.Error";
-        constexpr auto service   = "xyz.openbmc_project.Logging";
-        constexpr auto path      = "/xyz/openbmc_project/logging";
-        constexpr auto interface = "xyz.openbmc_project.Logging.Create";
-        constexpr auto function  = "Create";
-
-        auto bus    = sdbusplus::bus::new_default_system();
-        auto method = bus.new_method_call(service, path, interface, function);
-        method.append(pelEvent, level, additional);
-
-        bus.call_noreply(method);
-    }
-    catch (const sdbusplus::exception::SdBusError& e)
-    {
-        std::stringstream ss;
-        ss << "createPelRaw: " << e.what();
-        trace<level::INFO>(ss.str().c_str());
-    }
-}
-
-/**
  * Create a PEL from an existing PEL
  *
  * Create a new PEL based on the specified raw PEL and submit the new PEL
@@ -452,7 +309,7 @@
         if (true == tiEvent)
         {
             // get file descriptor and size of information PEL
-            int pelFd = getPelFd(pelId);
+            int pelFd = getPel(pelId);
 
             // if PEL found, read into buffer
             if (-1 != pelFd)
diff --git a/attn/attn_logging.hpp b/attn/attn_logging.hpp
index edbc143..7e89555 100644
--- a/attn/attn_logging.hpp
+++ b/attn/attn_logging.hpp
@@ -10,6 +10,10 @@
 namespace attn
 {
 
+constexpr auto pathLogging   = "/xyz/openbmc_project/logging";
+constexpr auto levelPelError = "xyz.openbmc_project.Logging.Entry.Level.Error";
+constexpr auto eventPelTerminate = "xyz.open_power.Attn.Error.Terminate";
+
 /** @brief Logging level types */
 enum level
 {
diff --git a/attn/meson.build b/attn/meson.build
index d42289d..f6fdd56 100644
--- a/attn/meson.build
+++ b/attn/meson.build
@@ -25,9 +25,10 @@
 
 # Source files.
 attn_src = files(
+    'attention.cpp',
     'attn_common.cpp',
     'attn_config.cpp',
-    'attention.cpp',
+    'attn_dbus.cpp',
     'attn_handler.cpp',
     'attn_main.cpp',
     'attn_monitor.cpp',