blob: 32853fad41660eadae053629ac8e8e44ed89b855 [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 }
Patrick Williams71957992021-10-06 14:42:52 -050032 catch (const fs::filesystem_error& e)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050033 {
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>(
Patrick Williams7e2797e2021-12-03 13:37:07 -060071 event, fd, EPOLLIN, [this](sdeventplus::source::IO&, int fd, uint32_t) {
Patrick Williams13eba412021-12-03 16:03:43 -060072 constexpr int size = sizeof(struct inotify_event) + NAME_MAX + 1;
73 std::array<char, size> buffer{};
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050074 int length = read(fd, buffer.data(), buffer.size());
75 if (length >= static_cast<int>(sizeof(struct inotify_event)))
76 {
77 struct inotify_event* notifyEvent =
78 reinterpret_cast<struct inotify_event*>(&buffer[0]);
79 if (notifyEvent->len)
80 {
81 if (watchFile == notifyEvent->name)
82 {
83 callback();
84 }
85 }
86 }
87 else
88 {
89 log<level::ERR>("Failed to read inotify event");
90 }
91 });
92}
93
94void Watch::stopWatch()
95{
96 if (-1 != fd)
97 {
98 if (-1 != wd)
99 {
100 inotify_rm_watch(fd, wd);
101 }
102 close(fd);
103 }
104 if (ioPtr)
105 {
106 ioPtr.reset();
107 }
108}
109
110} // namespace certs
111} // namespace phosphor