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