Collect ramoops data into BMC dump

- Add ramoops file monitor and support to enable ramoops data
  collection for kernel dump.

- Systemd will collect ramoops data and write it into
  /var/lib/systemd/pstore when a system kernel oops/panics.

- Today, need to grab everything in that directory, put it in a dump
  and then delete everything in that directory.

Tested:
- Simulate a kernel panic by creating similar data in the expected
  location.
  `dmesg > /var/lib/systemd/pstore/dmesg1.txt`
  `dmesg > /var/lib/systemd/pstore/dmesg2.txt`
  `dmesg > /var/lib/systemd/pstore/dmesg3.txt`
  `dmesg > /var/lib/systemd/pstore/dmesg4.txt`

  tar -tvf obmcdump_1_248.tar.xz:

  drwxr-xr-x 0/0         0 1970-01-01 00:01:32 obmcdump_1_248/
  -rw-r--r-- 0/0     21239 1970-01-01 00:01:32 obmcdump_1_248/dmesg1.txt
  -rw-r--r-- 0/0     21239 1970-01-01 00:01:32 obmcdump_1_248/dmesg2.txt
  -rw-r--r-- 0/0     21239 1970-01-01 00:01:32 obmcdump_1_248/dmesg3.txt
  -rw-r--r-- 0/0     21239 1970-01-01 00:01:32 obmcdump_1_248/dmesg4.txt
  -rw-r--r-- 0/0       162 1970-01-01 00:01:32 obmcdump_1_248/dreport.log
  -rw-r--r-- 0/0       294 1970-01-01 00:01:31 obmcdump_1_248/os-release
  -rw-r--r-- 0/0       278 1970-01-01 00:01:31 obmcdump_1_248/summary.log

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I05bca408f4dcc2b62350104a0c5f757d740dde22
diff --git a/dump_manager_bmc.hpp b/dump_manager_bmc.hpp
index 7a94889..604012b 100644
--- a/dump_manager_bmc.hpp
+++ b/dump_manager_bmc.hpp
@@ -37,7 +37,8 @@
     {Type::ApplicationCored, "core"},
     {Type::UserRequested, "user"},
     {Type::InternalFailure, "elog"},
-    {Type::Checkstop, "checkstop"}};
+    {Type::Checkstop, "checkstop"},
+    {Type::Ramoops, "ramoops"}};
 
 /** @class Manager
  *  @brief OpenBMC Dump  manager implementation.
diff --git a/meson.build b/meson.build
index e1b06b7..fcb3004 100644
--- a/meson.build
+++ b/meson.build
@@ -62,6 +62,8 @@
                     )
 conf_data.set_quoted('BMC_DUMP_PATH', get_option('BMC_DUMP_PATH'),
                      description : 'Directory where bmc dumps are placed')
+conf_data.set_quoted('SYSTEMD_PSTORE_PATH', get_option('SYSTEMD_PSTORE_PATH'),
+                     description : 'Path to the systemd pstore directory')
 conf_data.set('BMC_DUMP_MAX_SIZE', get_option('BMC_DUMP_MAX_SIZE'),
                description : 'Maximum size of one bmc dump in kilo bytes'
              )
@@ -163,6 +165,22 @@
 
 phosphor_dump_monitor_incdir = []
 
+phosphor_ramoops_monitor_sources = [
+        'ramoops_manager.cpp',
+        'ramoops_manager_main.cpp',
+        'watch.cpp'
+    ]
+
+phosphor_ramoops_monitor_dependency = [
+        phosphor_dbus_interfaces,
+        phosphor_logging,
+        cppfs
+    ]
+
+phosphor_ramoops_monitor_install = true
+
+phosphor_ramoops_monitor_incdir = []
+
 executables = [[ 'phosphor-dump-manager',
                   phosphor_dump_manager_sources,
                   phosphor_dump_manager_dependency,
@@ -174,6 +192,12 @@
                   phosphor_dump_monitor_dependency,
                   phosphor_dump_monitor_install,
                   phosphor_dump_monitor_incdir
+               ],
+               [ 'phosphor-ramoops-monitor',
+                  phosphor_ramoops_monitor_sources,
+                  phosphor_ramoops_monitor_dependency,
+                  phosphor_ramoops_monitor_install,
+                  phosphor_ramoops_monitor_incdir
                ]
               ]
 
diff --git a/meson_options.txt b/meson_options.txt
index de4a7ee..93c8fc4 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -63,6 +63,11 @@
         description : 'Directory where bmc dumps are placed'
       )
 
+option('SYSTEMD_PSTORE_PATH', type : 'string',
+        value : '/var/lib/systemd/pstore/',
+        description : 'Path to the systemd pstore directory'
+)
+
 option('BMC_DUMP_MAX_SIZE', type : 'integer',
         value : 200,
         description : 'Maximum size of one bmc dump in kilo bytes'
diff --git a/ramoops_manager.cpp b/ramoops_manager.cpp
new file mode 100644
index 0000000..a9f15c3
--- /dev/null
+++ b/ramoops_manager.cpp
@@ -0,0 +1,75 @@
+#include "config.h"
+
+#include "ramoops_manager.hpp"
+
+#include <sdbusplus/exception.hpp>
+
+namespace phosphor
+{
+namespace dump
+{
+namespace ramoops
+{
+
+Manager::Manager(const std::string& filePath)
+{
+    std::vector<std::string> files;
+    files.push_back(filePath);
+
+    createHelper(files);
+}
+
+void Manager::createHelper(const std::vector<std::string>& files)
+{
+    if (files.empty())
+    {
+        return;
+    }
+
+    constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
+    constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
+    constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
+    constexpr auto IFACE_INTERNAL("xyz.openbmc_project.Dump.Internal.Create");
+    constexpr auto RAMOOPS =
+        "xyz.openbmc_project.Dump.Internal.Create.Type.Ramoops";
+
+    auto b = sdbusplus::bus::new_default();
+    auto mapper = b.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
+                                    MAPPER_INTERFACE, "GetObject");
+    mapper.append(OBJ_INTERNAL, std::set<std::string>({IFACE_INTERNAL}));
+
+    auto mapperResponseMsg = b.call(mapper);
+    if (mapperResponseMsg.is_method_error())
+    {
+        log<level::ERR>("Error in mapper call");
+        return;
+    }
+
+    std::map<std::string, std::set<std::string>> mapperResponse;
+    try
+    {
+        mapperResponseMsg.read(mapperResponse);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        log<level::ERR>(
+            "Failed to parse dump create message", entry("ERROR=%s", e.what()),
+            entry("REPLY_SIG=%s", mapperResponseMsg.get_signature()));
+        return;
+    }
+    if (mapperResponse.empty())
+    {
+        log<level::ERR>("Error reading mapper response");
+        return;
+    }
+
+    const auto& host = mapperResponse.cbegin()->first;
+    auto m =
+        b.new_method_call(host.c_str(), OBJ_INTERNAL, IFACE_INTERNAL, "Create");
+    m.append(RAMOOPS, files);
+    b.call_noreply(m);
+}
+
+} // namespace ramoops
+} // namespace dump
+} // namespace phosphor
diff --git a/ramoops_manager.hpp b/ramoops_manager.hpp
new file mode 100644
index 0000000..7982bce
--- /dev/null
+++ b/ramoops_manager.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "config.h"
+
+#include <phosphor-logging/log.hpp>
+
+#include <filesystem>
+#include <string>
+#include <vector>
+
+namespace fs = std::filesystem;
+using namespace phosphor::logging;
+
+namespace phosphor
+{
+namespace dump
+{
+namespace ramoops
+{
+
+/** @class Manager
+ *  @brief OpenBMC Core manager implementation.
+ */
+class Manager
+{
+  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 create ramoops
+     *  @param[in] filePath - Path where the ramoops are stored.
+     */
+    Manager(const std::string& filePath);
+
+  private:
+    /** @brief Helper function for initiating dump request using
+     *         D-bus internal create interface.
+     *  @param [in] files - ramoops files list
+     */
+    void createHelper(const std::vector<std::string>& files);
+};
+
+} // namespace ramoops
+} // namespace dump
+} // namespace phosphor
diff --git a/ramoops_manager_main.cpp b/ramoops_manager_main.cpp
new file mode 100644
index 0000000..6a06386
--- /dev/null
+++ b/ramoops_manager_main.cpp
@@ -0,0 +1,20 @@
+#include "config.h"
+
+#include "ramoops_manager.hpp"
+
+#include <phosphor-logging/elog-errors.hpp>
+
+int main()
+{
+    fs::path filePath(SYSTEMD_PSTORE_PATH);
+    if (!fs::exists(filePath))
+    {
+        log<level::ERR>("Pstore file path is not exists",
+                        entry("FILE_PATH = %s", SYSTEMD_PSTORE_PATH));
+        return EXIT_FAILURE;
+    }
+
+    phosphor::dump::ramoops::Manager manager(SYSTEMD_PSTORE_PATH);
+
+    return EXIT_SUCCESS;
+}
diff --git a/tools/dreport.d/dreport b/tools/dreport.d/dreport
index d831191..3009b80 100755
--- a/tools/dreport.d/dreport
+++ b/tools/dreport.d/dreport
@@ -44,6 +44,7 @@
 declare -rx TYPE_CORE="core"
 declare -rx TYPE_ELOG="elog"
 declare -rx TYPE_CHECKSTOP="checkstop"
+declare -rx TYPE_RAMOOPS="ramoops"
 declare -rx SUMMARY_LOG="summary.log"
 declare -rx DREPORT_LOG="dreport.log"
 declare -rx TMP_DIR="/tmp"
@@ -91,6 +92,9 @@
             log_summary "Core: $optional_path"
             set_core_pid
             ;;
+        $TYPE_RAMOOPS)
+            log_summary "Ramoops: $optional_path"
+            ;;
         $TYPE_ELOG)
             log_summary "ELOG: $optional_path"
             elog_id=$(basename "$optional_path")
@@ -198,6 +202,7 @@
     if [[ ! ($dump_type = $TYPE_USER || \
              $dump_type = $TYPE_CORE || \
              $dump_type = $TYPE_ELOG || \
+             $dump_type = $TYPE_RAMOOPS || \
              $dump_type = $TYPE_CHECKSTOP) ]]; then
        log_error "Invalid -type, Only summary log is available"
        dump_type=$SUMMARY_DUMP
diff --git a/tools/dreport.d/plugins.d/osrelease b/tools/dreport.d/plugins.d/osrelease
index 7cf9a43..00cb22c 100644
--- a/tools/dreport.d/plugins.d/osrelease
+++ b/tools/dreport.d/plugins.d/osrelease
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# config: 1234 1
+# config: 12345 1
 # @brief: Collect OS release information.
 #
 
diff --git a/tools/dreport.d/plugins.d/ramoops b/tools/dreport.d/plugins.d/ramoops
new file mode 100644
index 0000000..66324f0
--- /dev/null
+++ b/tools/dreport.d/plugins.d/ramoops
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# config: 5 1
+# @brief: Move the ramoops data file to the dreport packaging.
+#
+
+. $DREPORT_INCLUDE/functions
+
+desc="Ramoops file"
+
+for path in ${optional_path}/*
+do
+    if [ -f $path ]; then
+        # Remove the file from path after successful copy
+        if add_copy_file "$path" "$desc"; then
+            rm "$path"
+        fi
+    fi
+done
diff --git a/tools/dreport.d/sample.conf b/tools/dreport.d/sample.conf
index 45f5e59..9490d05 100644
--- a/tools/dreport.d/sample.conf
+++ b/tools/dreport.d/sample.conf
@@ -9,3 +9,4 @@
 2: user
 3: elog
 4: checkstop
+5: ramoops
diff --git a/xyz/openbmc_project/Dump/Internal/Create.interface.yaml b/xyz/openbmc_project/Dump/Internal/Create.interface.yaml
index ddb405f..1f4ee4f 100644
--- a/xyz/openbmc_project/Dump/Internal/Create.interface.yaml
+++ b/xyz/openbmc_project/Dump/Internal/Create.interface.yaml
@@ -37,5 +37,8 @@
         - name: Checkstop
           description: >
               Dump triggered due to Checkstop type error commit.
+        - name: Ramoops
+          description: >
+              Dump triggered due to Ramoops type error commit.
 
 # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4