blob: 62084665053724e7924124bff5338ae4264c9a2e [file] [log] [blame]
#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