blob: c1ac7897f5064e096096078e5c641292fcc3650e [file] [log] [blame]
Marri Devender Raoffad1ef2019-06-03 04:54:12 -05001#include "watch.hpp"
2
3#include <sys/inotify.h>
4#include <unistd.h>
5
6#include <cstring>
7#include <filesystem>
8#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/elog.hpp>
10#include <xyz/openbmc_project/Common/error.hpp>
11namespace phosphor
12{
13namespace certs
14{
15using namespace phosphor::logging;
16namespace fs = std::filesystem;
17using InternalFailure =
18 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
19
20Watch::Watch(sdeventplus::Event& event, std::string& certFile, Callback cb) :
21 event(event), callback(cb)
22{
23 // get parent directory of certificate file to watch
24 fs::path path = std::move(fs::path(certFile).parent_path());
25 try
26 {
27 if (!fs::exists(path))
28 {
29 fs::create_directories(path);
30 }
31 }
32 catch (fs::filesystem_error& e)
33 {
34 log<level::ERR>("Failed to create directory", entry("ERR=%s", e.what()),
35 entry("DIRECTORY=%s", path.c_str()));
36 elog<InternalFailure>();
37 }
38 watchDir = path;
39 watchFile = fs::path(certFile).filename();
40 startWatch();
41}
42
43Watch::~Watch()
44{
45 stopWatch();
46}
47
48void Watch::startWatch()
49{
50 // stop any existing watch
51 stopWatch();
52
53 fd = inotify_init1(IN_NONBLOCK);
54 if (-1 == fd)
55 {
56 log<level::ERR>("inotify_init1 failed,",
57 entry("ERR=%s", std::strerror(errno)));
58 elog<InternalFailure>();
59 }
60 wd = inotify_add_watch(fd, watchDir.c_str(), IN_CLOSE_WRITE);
61 if (-1 == wd)
62 {
63 close(fd);
64 log<level::ERR>("inotify_add_watch failed,",
65 entry("ERR=%s", std::strerror(errno)),
66 entry("WATCH=%s", watchDir.c_str()));
67 elog<InternalFailure>();
68 }
69
70 ioPtr = std::make_unique<sdeventplus::source::IO>(
71 event, fd, EPOLLIN,
72 [this](sdeventplus::source::IO&, int fd, uint32_t revents) {
73 const int size = sizeof(struct inotify_event) + NAME_MAX + 1;
74 std::array<char, size> buffer;
75 int length = read(fd, buffer.data(), buffer.size());
76 if (length >= static_cast<int>(sizeof(struct inotify_event)))
77 {
78 struct inotify_event* notifyEvent =
79 reinterpret_cast<struct inotify_event*>(&buffer[0]);
80 if (notifyEvent->len)
81 {
82 if (watchFile == notifyEvent->name)
83 {
84 callback();
85 }
86 }
87 }
88 else
89 {
90 log<level::ERR>("Failed to read inotify event");
91 }
92 });
93}
94
95void Watch::stopWatch()
96{
97 if (-1 != fd)
98 {
99 if (-1 != wd)
100 {
101 inotify_rm_watch(fd, wd);
102 }
103 close(fd);
104 }
105 if (ioPtr)
106 {
107 ioPtr.reset();
108 }
109}
110
111} // namespace certs
112} // namespace phosphor