Initial commit for the Dump core file monitor infrastructure.

Add an inotify watch to the known core dump location.

Resolves openbmc/openbmc#1504

Change-Id: I0093c9f601d82917ca2efb53a4d47ed98f0eaa7f
Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
diff --git a/dump_watch.cpp b/dump_watch.cpp
new file mode 100644
index 0000000..6208466
--- /dev/null
+++ b/dump_watch.cpp
@@ -0,0 +1,159 @@
+#include <stdexcept>
+#include <cstddef>
+#include <cstring>
+#include <string>
+#include <vector>
+#include <sys/inotify.h>
+#include <unistd.h>
+#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
+{
+
+using namespace std::string_literals;
+using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Dump::Monitor::Error;
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+namespace fs = std::experimental::filesystem;
+
+Watch::~Watch()
+{
+    if ((fd() >= 0) && (wd >= 0))
+    {
+        inotify_rm_watch(fd(), wd);
+    }
+}
+
+Watch::Watch(sd_event* loop):
+    fd(inotifyInit())
+{
+    // Check if CORE DIR exists.
+    fs::path coreDirPath(CORE_FILE_DIR);
+    if (!fs::is_directory(coreDirPath))
+    {
+        namespace metadata = xyz::openbmc_project::Dump::Monitor;
+        elog<InvalidCorePath>(metadata::InvalidCorePath::PATH(CORE_FILE_DIR));
+    }
+
+    //Check for existing coredumps, Dump manager should handle this before
+    //starting the core monitoring.
+    //This is to handle coredumps created prior to Dump applications start,
+    //or missing coredump reporting due to Dump application crashs.
+    if (!fs::is_empty(coreDirPath))
+    {
+        //TODO openbmc/openbmc#1510 Enable Dump collection function here.
+    }
+
+    wd = inotify_add_watch(fd(), CORE_FILE_DIR, IN_CLOSE_WRITE);
+    if (-1 == wd)
+    {
+        auto error = errno;
+        log<level::ERR>("Error occurred during the inotify_add_watch call",
+                        entry("ERRNO=%s", strerror(error)));
+        elog<InternalFailure>();
+    }
+
+    auto rc = sd_event_add_io(loop,
+                              nullptr,
+                              fd(),
+                              EPOLLIN,
+                              callback,
+                              this);
+    if (0 > rc)
+    {
+        // Failed to add to event loop
+        auto error = errno;
+        log<level::ERR>("Error occurred during the sd_event_add_io call",
+                        entry("ERRNO=%s", strerror(error)));
+        elog<InternalFailure>();
+    }
+}
+
+int Watch::inotifyInit()
+{
+    auto fd = inotify_init1(IN_NONBLOCK);
+
+    if (-1 == fd)
+    {
+        auto error = errno;
+        log<level::ERR>("Error occurred during the inotify_init1",
+                        entry("ERRNO=%s", strerror(error)));
+        elog<InternalFailure>();
+    }
+
+    return fd;
+}
+
+int Watch::callback(sd_event_source* s,
+                    int fd,
+                    uint32_t revents,
+                    void* userdata)
+{
+    if (!(revents & EPOLLIN))
+    {
+        return 0;
+    }
+
+    //Maximum inotify events supported in the buffer
+    constexpr auto maxBytes = sizeof(struct inotify_event) + NAME_MAX + 1;
+    uint8_t buffer[maxBytes];
+
+    auto bytes = read(fd, buffer, maxBytes);
+    if (0 > bytes)
+    {
+        //Failed to read inotify event
+        //Report error and return
+        auto error = errno;
+        log<level::ERR>("Error occurred during the read",
+                        entry("ERRNO=%s", strerror(error)));
+        report<InternalFailure>();
+        return 0;
+    }
+
+    auto offset = 0;
+
+    std::vector<fs::path> corePaths;
+
+    while (offset < bytes)
+    {
+        auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
+        if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
+        {
+            corePaths.emplace_back(fs::path(CORE_FILE_DIR) / event->name);
+        }
+
+        offset += offsetof(inotify_event, name) + event->len;
+    }
+
+    // Generate new BMC Dump( Core dump Type) incase valid cores
+    if (!corePaths.empty())
+    {
+        //TODO openbmc/openbmc#1510 Enable Dump collection function here
+    }
+    return 0;
+}
+
+} // namespace inotify
+} // namespace dump
+} // namespace phosphor