Implementation of create interface.

Both the external and internal Dump managers define "Create"
interfaces. This commit implements these.

Change-Id: If857ec6ea7267fd72e9b420e6b44fa68b6abab66
Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index 30d5a88..72401e1 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,10 @@
 # Build these headers, don't install them
 noinst_HEADERS = \
 	dump_entry.hpp \
-	dump_watch.hpp
+	dump_watch.hpp \
+	dump_internal.hpp \
+	dump_manager.hpp \
+	dump_utils.hpp
 
 nobase_nodist_include_HEADERS = \
 	xyz/openbmc_project/Dump/Monitor/error.hpp \
@@ -16,7 +19,9 @@
 phosphor_dump_manager_SOURCES = \
 	dump_manager_main.cpp \
 	dump_entry.cpp \
-	xyz/openbmc_project/Dump/Internal/Create/server.cpp
+	dump_manager.cpp \
+	xyz/openbmc_project/Dump/Internal/Create/server.cpp \
+	xyz/openbmc_project/Dump/Monitor/error.cpp
 
 phosphor_dump_monitor_SOURCES = \
 	dump_watch_main.cpp \
@@ -35,7 +40,8 @@
 phosphor_dump_manager_LDADD = \
 	$(PHOSPHOR_DBUS_INTERFACES_LIBS) \
 	$(SDBUSPLUS_LIBS) \
-	$(PHOSPHOR_LOGGING_LIBS)
+	$(PHOSPHOR_LOGGING_LIBS) \
+	-lstdc++fs
 
 phosphor_dump_monitor_LDADD = \
 	$(PHOSPHOR_DBUS_INTERFACES_LIBS) \
diff --git a/configure.ac b/configure.ac
index 985624c..0807a82 100644
--- a/configure.ac
+++ b/configure.ac
@@ -51,5 +51,19 @@
 AS_IF([test "x$CORE_FILE_DIR" == "x"], [CORE_FILE_DIR="/var/lib/systemd/coredump"])
 AC_DEFINE_UNQUOTED([CORE_FILE_DIR], ["$CORE_FILE_DIR"], [Directory where core dumps are placed])
 
+AC_ARG_VAR(OBJ_INTERNAL, [Internal Dump manager Dbus object path])
+AS_IF([test "x$OBJ_INTERNAL" == "x"], [OBJ_INTERNAL="/xyz/openbmc_project/dump/internal/manager"])
+AC_DEFINE_UNQUOTED([OBJ_INTERNAL], ["$OBJ_INTERNAL"], [Internal Dump manager Dbus object path])
+
+AC_ARG_VAR(OBJ_ENTRY, [The dump entry DBus object path.])
+AS_IF([test "x$OBJ_ENTRY" == "x"], [OBJ_ENTRY="/xyz/openbmc_project/dump/entry"])
+AC_DEFINE_UNQUOTED([OBJ_ENTRY], ["$OBJ_ENTRY"], [The dump entry DBus object path])
+
+# TODO openbmc/openbmc#1795
+# Change the path to Dump Partition path.
+AC_ARG_VAR(BMC_DUMP_FILE_DIR, [Directory where bmc dumps are placed])
+AS_IF([test "x$BMC_DUMP_FILE_DIR" == "x"], [BMC_DUMP_FILE_DIR="/tmp"])
+AC_DEFINE_UNQUOTED([BMC_DUMP_FILE_DIR], ["$BMC_DUMP_FILE_DIR"], [Directory where bmc dumps are placed])
+
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
diff --git a/dump_entry.cpp b/dump_entry.cpp
index 75c1358..373d8e4 100644
--- a/dump_entry.cpp
+++ b/dump_entry.cpp
@@ -1,17 +1,25 @@
 #include "dump_entry.hpp"
+#include "dump_manager.hpp"
+
+#include <phosphor-logging/log.hpp>
 
 namespace phosphor
 {
 namespace dump
 {
 
-Entry::Entry(sdbusplus::bus::bus& bus, const char* obj): EntryIfaces(bus, obj)
-{
-}
-
+using namespace phosphor::logging;
 
 void Entry::delete_()
 {
+    //Delete Dump file from Permanent location
+    if (!fs::remove(file))
+    {
+        log<level::INFO>("Dump file doesn't exist.",
+                         entry("Name=%s", file.c_str()));
+    }
+    // Remove Dump entry D-bus object
+    parent.erase(id);
 }
 
 } // namespace dump
diff --git a/dump_entry.hpp b/dump_entry.hpp
index d276f0d..2942704 100644
--- a/dump_entry.hpp
+++ b/dump_entry.hpp
@@ -1,6 +1,10 @@
 #pragma once
 
+#include <experimental/filesystem>
+
+#include <sdbusplus/bus.hpp>
 #include <sdbusplus/server/object.hpp>
+
 #include "xyz/openbmc_project/Dump/Entry/server.hpp"
 #include "xyz/openbmc_project/Object/Delete/server.hpp"
 #include "xyz/openbmc_project/Time/EpochTime/server.hpp"
@@ -18,6 +22,10 @@
                     sdbusplus::xyz::openbmc_project::Object::server::Delete,
                     sdbusplus::xyz::openbmc_project::Time::server::EpochTime>;
 
+namespace fs = std::experimental::filesystem;
+
+class Manager;
+
 /** @class Entry
  *  @brief OpenBMC Dump Entry implementation.
  *  @details A concrete implementation for the
@@ -31,18 +39,49 @@
         Entry& operator=(const Entry&) = delete;
         Entry(Entry&&) = delete;
         Entry& operator=(Entry&&) = delete;
-        virtual ~Entry() = default;
+        ~Entry() = default;
 
         /** @brief Constructor for the Dump Entry Object
          *  @param[in] bus - Bus to attach to.
-         *  @param[in] obj - Object path to attach to
+         *  @param[in] objPath - Object path to attach to
+         *  @param[in] dumpId - Dump id.
+         *  @param[in] timeStamp - Dump creation timestamp
+         *             since the epoch.
+         *  @param[in] fileSize - Dump file size in bytes.
+         *  @param[in] file - Dump file name.
+         *  @param[in] parent - The dump entry's parent.
          */
-        Entry(sdbusplus::bus::bus& bus, const char* obj);
+        Entry(sdbusplus::bus::bus& bus,
+              const std::string& objPath,
+              uint32_t dumpId,
+              uint64_t timeStamp,
+              uint64_t fileSize,
+              const fs::path& file,
+              Manager& parent):
+            EntryIfaces(bus, objPath.c_str(), true),
+            file(file),
+            parent(parent),
+            id(dumpId)
+        {
+            size(fileSize);
+            elapsed(timeStamp);
+            // Emit deferred signal.
+            this->emit_object_added();
+        };
 
         /** @brief Delete this d-bus object.
          */
         void delete_() override ;
 
+    private:
+        /** @Dump file name */
+        fs::path file;
+
+        /** @brief This entry's parent */
+        Manager& parent;
+
+        /** @brief This entry's id */
+        uint32_t id;
 };
 
 } // namespace dump
diff --git a/dump_internal.hpp b/dump_internal.hpp
new file mode 100644
index 0000000..0688b78
--- /dev/null
+++ b/dump_internal.hpp
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/server/object.hpp>
+
+#include "xyz/openbmc_project/Dump/Internal/Create/server.hpp"
+
+namespace phosphor
+{
+namespace dump
+{
+namespace internal
+{
+
+using CreateIface = sdbusplus::server::object::object<
+          sdbusplus::xyz::openbmc_project::Dump::Internal::server::Create>;
+
+/** @class Manager
+ *  @brief Implementation for the
+ *         xyz.openbmc_project.Dump.Internal.Create DBus API.
+ */
+class Manager : public CreateIface
+{
+    public:
+        Manager() = delete;
+        Manager(const Manager&) = delete;
+        Manager& operator=(const Manager&) = delete;
+        Manager(Manager&&) = delete;
+        Manager& operator=(Manager&&) = delete;
+        virtual ~Manager() = default;
+
+        /** @brief Constructor to put object onto bus at a dbus path.
+         *  @param[in] bus - Bus to attach to.
+         *  @param[in] path - Path to attach at.
+         */
+        Manager(sdbusplus::bus::bus& bus, const char* path) :
+            CreateIface(bus, path) {};
+
+        /**  @brief Implementation for Create
+          *  Create BMC Dump based on the Dump type.
+          *
+          *  @param[in] type - Type of the Dump.
+          *  @param[in] fullPaths - List of absolute paths to the files
+          *             to be included as part of Dump package.
+          */
+        void create(
+            Type type,
+            std::vector<std::string> fullPaths) override;
+
+};
+
+} // namespace internal
+} // namespace dump
+} // namespace phosphor
diff --git a/dump_manager.cpp b/dump_manager.cpp
new file mode 100644
index 0000000..d0376a5
--- /dev/null
+++ b/dump_manager.cpp
@@ -0,0 +1,116 @@
+#include <unistd.h>
+
+#include <phosphor-logging/elog-errors.hpp>
+
+#include "dump_manager.hpp"
+#include "dump_internal.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+#include "config.h"
+
+namespace phosphor
+{
+namespace dump
+{
+
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+using namespace phosphor::logging;
+
+namespace internal
+{
+
+void Manager::create(
+    Type type,
+    std::vector<std::string> fullPaths)
+{
+    // TODO openbmc/openbmc#1795
+    // Add implementaion of internal create function.
+}
+
+} //namepsace internal
+
+uint32_t Manager::createDump()
+{
+    std::vector<std::string> paths;
+
+    return captureDump(Type::UserRequested, paths);
+}
+
+uint32_t Manager::captureDump(
+    Type type,
+    const std::vector<std::string>& fullPaths)
+{
+    pid_t pid = fork();
+
+    // TODO openbmc/openbmc#1795
+    // Add Dump location info.
+    if (pid == 0)
+    {
+        execl("/usr/bin/ffdc", "ffdc", nullptr);
+
+        //ffdc script execution is failed.
+        auto error = errno;
+        log<level::ERR>("Error occurred during ffdc function execution",
+                        entry("ERRNO=%d", error));
+        elog<InternalFailure>();
+    }
+    else if (pid > 0)
+    {
+        auto rc = sd_event_add_child(eventLoop.get(),
+                                     nullptr,
+                                     pid,
+                                     WEXITED | WSTOPPED,
+                                     callback,
+                                     nullptr);
+        if (0 > rc)
+        {
+            // Failed to add to event loop
+            log<level::ERR>("Error occurred during the sd_event_add_child call",
+                            entry("rc=%d", rc));
+            elog<InternalFailure>();
+        }
+    }
+    else
+    {
+        auto error = errno;
+        log<level::ERR>("Error occurred during fork",
+                        entry("ERRNO=%d", error));
+        elog<InternalFailure>();
+    }
+
+    return ++lastEntryId;
+}
+
+void Manager::createEntry(const fs::path& file)
+{
+    // TODO openbmc/openbmc#1795
+    // Get Dump ID and Epoch time from Dump file name.
+    // Validate the Dump file name.
+    auto id = lastEntryId;
+
+    //Get Epoch time.
+    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
+                  std::chrono::system_clock::now().time_since_epoch()).count();
+
+    // Entry Object path.
+    auto objPath =  fs::path(OBJ_ENTRY) / std::to_string(id);
+
+    auto size = fs::file_size(file);
+
+    entries.insert(std::make_pair(id,
+                                  std::make_unique<Entry>(
+                                      bus,
+                                      objPath.c_str(),
+                                      id,
+                                      ms,
+                                      size,
+                                      file,
+                                      *this)));
+}
+
+void Manager::erase(uint32_t entryId)
+{
+    entries.erase(entryId);
+}
+
+} //namespace dump
+} //namespace phosphor
diff --git a/dump_manager.hpp b/dump_manager.hpp
new file mode 100644
index 0000000..3bbcf3e
--- /dev/null
+++ b/dump_manager.hpp
@@ -0,0 +1,130 @@
+#pragma once
+
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/server/object.hpp>
+#include <xyz/openbmc_project/Dump/Create/server.hpp>
+#include <experimental/filesystem>
+
+#include "xyz/openbmc_project/Dump/Internal/Create/server.hpp"
+#include "dump_entry.hpp"
+
+namespace phosphor
+{
+namespace dump
+{
+namespace internal
+{
+
+class Manager;
+
+} // namespace internal
+
+namespace fs = std::experimental::filesystem;
+using Type =
+    sdbusplus::xyz::openbmc_project::Dump::Internal::server::Create::Type;
+
+using CreateIface = sdbusplus::server::object::object<
+                    sdbusplus::xyz::openbmc_project::Dump::server::Create>;
+
+/* Need a custom deleter for freeing up sd_event */
+struct EventDeleter
+{
+    void operator()(sd_event* event) const
+    {
+        event = sd_event_unref(event);
+    }
+};
+using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
+
+/** @class Manager
+ *  @brief OpenBMC Dump  manager implementation.
+ *  @details A concrete implementation for the
+ *  xyz.openbmc_project.Dump.Create DBus API.
+ */
+class Manager : public CreateIface
+{
+        friend class internal::Manager;
+        friend class Entry;
+
+    public:
+        Manager() = delete;
+        Manager(const Manager&) = default;
+        Manager& operator=(const Manager&) = delete;
+        Manager(Manager&&) = delete;
+        Manager& operator=(Manager&&) = delete;
+        virtual ~Manager() = default;
+
+        /** @brief Constructor to put object onto bus at a dbus path.
+         *  @param[in] bus - Bus to attach to.
+         *  @param[in] event - Dump manager sd_event loop.
+         *  @param[in] path - Path to attach at.
+         */
+        Manager(sdbusplus::bus::bus& bus,
+                const EventPtr& event, const char* path) :
+            CreateIface(bus, path),
+            bus(bus),
+            eventLoop(event.get()),
+            lastEntryId(0)
+        {}
+
+        /** @brief Implementation for CreateDump
+         *  Method to create Dump.
+         *
+         *  @return id - The Dump entry id number.
+         */
+        uint32_t createDump() override;
+
+    private:
+        /** @brief Create Dump entry d-bus object
+         *  @param[in] fullPath - Full path of the Dump file name
+         */
+        void createEntry(const fs::path& fullPath);
+
+        /**  @brief Capture BMC Dump based on the Dump type.
+          *  @param[in] type - Type of the Dump.
+          *  @param[in] fullPaths - List of absolute paths to the files
+          *             to be included as part of Dump package.
+          *  @return id - The Dump entry id number.
+          */
+        uint32_t captureDump(
+            Type type,
+            const std::vector<std::string>& fullPaths);
+
+        /** @brief Erase specified entry d-bus object
+          *
+          * @param[in] entryId - unique identifier of the entry
+          */
+        void erase(uint32_t entryId);
+
+        /** @brief sd_event_add_child callback
+          *
+          *  @param[in] s - event source
+          *  @param[in] si - signal info
+          *  @param[in] userdata - pointer to Watch object
+          *
+          *  @returns 0 on success, -1 on fail
+          */
+        static int callback(sd_event_source* s,
+                            const siginfo_t* si,
+                            void* userdata)
+        {
+            //No specific action required in
+            //the sd_event_add_child callback.
+            return 0;
+        }
+
+        /** @brief sdbusplus DBus bus connection. */
+        sdbusplus::bus::bus& bus;
+
+        /** @brief sdbusplus Dump event loop */
+        EventPtr eventLoop;
+
+        /** @brief Dump Entry dbus objects map based on entry id */
+        std::map<uint32_t, std::unique_ptr<Entry>> entries;
+
+        /** @brief Id of the last Dump entry */
+        uint32_t lastEntryId;
+};
+
+} // namespace dump
+} // namespace phosphor
diff --git a/dump_manager_main.cpp b/dump_manager_main.cpp
index 39398e7..cd1d83b 100644
--- a/dump_manager_main.cpp
+++ b/dump_manager_main.cpp
@@ -1,20 +1,51 @@
-#include <sdbusplus/bus.hpp>
-#include <sdbusplus/server/manager.hpp>
-#include "config.h"
+#include <phosphor-logging/elog-errors.hpp>
 
-int main(int argc, char *argv[])
+#include "xyz/openbmc_project/Common/error.hpp"
+#include "config.h"
+#include "dump_manager.hpp"
+#include "dump_internal.hpp"
+
+int main(int argc, char* argv[])
 {
     auto bus = sdbusplus::bus::new_default();
+    using namespace phosphor::logging;
+    using InternalFailure =
+        sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
+
+    sd_event* event = nullptr;
+    auto rc = sd_event_default(&event);
+    if (rc < 0)
+    {
+        log<level::ERR>("Error occurred during the sd_event_default",
+                        entry("rc=%d", rc));
+        report<InternalFailure>();
+        return rc;
+    }
+    phosphor::dump::EventPtr eventP{event};
+    event = nullptr;
 
     // Add sdbusplus ObjectManager for the 'root' path of the DUMP manager.
     sdbusplus::server::manager::manager objManager(bus, DUMP_OBJPATH);
-
     bus.request_name(DUMP_BUSNAME);
 
-    while(true)
+    try
     {
-        bus.process_discard();
-        bus.wait();
+        phosphor::dump::Manager manager(bus, eventP, DUMP_OBJPATH);
+        phosphor::dump::internal::Manager mgr(bus, OBJ_INTERNAL);
+        bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL);
+        auto rc = sd_event_loop(eventP.get());
+        if (rc < 0)
+        {
+            log<level::ERR>("Error occurred during the sd_event_loop",
+                            entry("rc=%d", rc));
+            elog<InternalFailure>();
+        }
+    }
+
+    catch (InternalFailure& e)
+    {
+        commit<InternalFailure>();
+        return -1;
     }
 
     return 0;
diff --git a/dump_utils.hpp b/dump_utils.hpp
new file mode 100644
index 0000000..a71458c
--- /dev/null
+++ b/dump_utils.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+namespace phosphor
+{
+namespace dump
+{
+
+/** @struct CustomFd
+ *
+ *  RAII wrapper for file descriptor.
+ */
+struct CustomFd
+{
+    private:
+        /** @brief File descriptor */
+        int fd = -1;
+
+    public:
+        CustomFd() = delete;
+        CustomFd(const CustomFd&) = delete;
+        CustomFd& operator=(const CustomFd&) = delete;
+        CustomFd(CustomFd&&) = delete;
+        CustomFd& operator=(CustomFd&&) = delete;
+
+        /** @brief Saves File descriptor and uses it to do file operation
+          *
+          *  @param[in] fd - File descriptor
+          */
+        CustomFd(int fd) : fd(fd) {}
+
+        ~CustomFd()
+        {
+            if (fd >= 0)
+            {
+                close(fd);
+            }
+        }
+
+        int operator()() const
+        {
+            return fd;
+        }
+};
+
+} // namespace dump
+} // namespace phosphor
diff --git a/dump_watch.cpp b/dump_watch.cpp
index 6208466..12a6c73 100644
--- a/dump_watch.cpp
+++ b/dump_watch.cpp
@@ -1,33 +1,17 @@
-#include <stdexcept>
-#include <cstddef>
-#include <cstring>
-#include <string>
-#include <vector>
 #include <sys/inotify.h>
-#include <unistd.h>
+#include <experimental/filesystem>
+#include <phosphor-logging/elog-errors.hpp>
+#include <xyz/openbmc_project/Dump/Monitor/error.hpp>
+
 #include "config.h"
 #include "dump_watch.hpp"
-#include <experimental/filesystem>
-#include <phosphor-logging/log.hpp>
-#include <phosphor-logging/elog.hpp>
-#include <phosphor-logging/elog-errors.hpp>
 #include "elog-errors.hpp"
-#include <xyz/openbmc_project/Dump/Monitor/error.hpp>
 #include "xyz/openbmc_project/Common/error.hpp"
 
 namespace phosphor
 {
 namespace dump
 {
-
-CustomFd::~CustomFd()
-{
-    if (fd >= 0)
-    {
-        close(fd);
-    }
-}
-
 namespace inotify
 {
 
diff --git a/dump_watch.hpp b/dump_watch.hpp
index 3f7bceb..fdd301c 100644
--- a/dump_watch.hpp
+++ b/dump_watch.hpp
@@ -1,47 +1,16 @@
 #pragma once
 
-#include <map>
-#include <memory>
 #include <systemd/sd-event.h>
 #include <unistd.h>
+#include "dump_utils.hpp"
 
 namespace phosphor
 {
 namespace dump
 {
-
-/** @struct CustomFd
- *
- *  RAII wrapper for file descriptor.
- */
-struct CustomFd
-{
-    private:
-        /** @brief File descriptor */
-        int fd = -1;
-
-    public:
-        CustomFd(const CustomFd&) = delete;
-        CustomFd& operator=(const CustomFd&) = delete;
-        CustomFd(CustomFd&&) = delete;
-        CustomFd& operator=(CustomFd&&) = delete;
-
-        /** @brief Saves File descriptor and uses it to do file operation
-          *
-          *  @param[in] fd - File descriptor
-          */
-        CustomFd(int fd) : fd(fd) {}
-
-        ~CustomFd();
-
-        int operator()() const
-        {
-            return fd;
-        }
-};
-
 namespace inotify
 {
+
 /** @class Watch
  *
  *  @brief Adds inotify watch on core file directories.
diff --git a/dump_watch_main.cpp b/dump_watch_main.cpp
index 6c7d98b..d061ae1 100644
--- a/dump_watch_main.cpp
+++ b/dump_watch_main.cpp
@@ -1,11 +1,11 @@
-#include <exception>
 #include "dump_watch.hpp"
+#include "elog-errors.hpp"
+#include "xyz/openbmc_project/Dump/Monitor/error.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
 #include <phosphor-logging/log.hpp>
 #include <phosphor-logging/elog.hpp>
 #include <phosphor-logging/elog-errors.hpp>
-#include "elog-errors.hpp"
-#include <xyz/openbmc_project/Dump/Monitor/error.hpp>
-#include "xyz/openbmc_project/Common/error.hpp"
 
 int main(int argc, char* argv[])
 {
diff --git a/xyz/openbmc_project/Dump/Internal/Create.interface.yaml b/xyz/openbmc_project/Dump/Internal/Create.interface.yaml
index 4d3150b..46f2bce 100644
--- a/xyz/openbmc_project/Dump/Internal/Create.interface.yaml
+++ b/xyz/openbmc_project/Dump/Internal/Create.interface.yaml
@@ -29,6 +29,8 @@
         - name: ApplicationCored
           description: >
               Dump triggered due to application core.
-
+        - name: UserRequested
+          description: >
+              Dump triggered by the user.
 
 # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4