blob: a8b4eebc5c862d5212e3533c2ab6899e860b24db [file] [log] [blame]
Adriana Kobylakb072d1b2018-04-24 11:37:21 -05001#include <experimental/filesystem>
2#include <fstream>
3#include <phosphor-logging/log.hpp>
4#include <sys/inotify.h>
5#include <unistd.h>
6#include "config.h"
7#include "sync_watch.hpp"
8
9namespace phosphor
10{
11namespace software
12{
13namespace manager
14{
15
16using namespace phosphor::logging;
17namespace fs = std::experimental::filesystem;
18
19SyncWatch::SyncWatch(sd_event& loop,
Adriana Kobylaka9074342018-05-08 11:52:44 -050020 std::function<int(int, fs::path&)> syncCallback) :
Adriana Kobylakb072d1b2018-04-24 11:37:21 -050021 syncCallback(syncCallback)
22{
23 auto syncfile = fs::path(SYNC_LIST_DIR_PATH) / SYNC_LIST_FILE_NAME;
24 if (fs::exists(syncfile))
25 {
26 std::string line;
27 std::ifstream file(syncfile.c_str());
28 while (std::getline(file, line))
29 {
30 auto fd = inotify_init1(IN_NONBLOCK);
31 if (-1 == fd)
32 {
33 log<level::ERR>("inotify_init1 failed",
34 entry("ERRNO=%d", errno),
35 entry("FILENAME=%s", line.c_str()),
36 entry("SYNCFILE=%s", syncfile.c_str()));
37 continue;
38 }
39
Adriana Kobylaka9074342018-05-08 11:52:44 -050040 auto wd =
41 inotify_add_watch(fd, line.c_str(), IN_CLOSE_WRITE | IN_DELETE);
Adriana Kobylakb072d1b2018-04-24 11:37:21 -050042 if (-1 == wd)
43 {
44 log<level::ERR>("inotify_add_watch failed",
45 entry("ERRNO=%d", errno),
46 entry("FILENAME=%s", line.c_str()),
47 entry("SYNCFILE=%s", syncfile.c_str()));
48 close(fd);
49 continue;
50 }
51
52 auto rc =
53 sd_event_add_io(&loop, nullptr, fd, EPOLLIN, callback, this);
54 if (0 > rc)
55 {
56 log<level::ERR>("failed to add to event loop",
57 entry("RC=%d", rc),
58 entry("FILENAME=%s", line.c_str()),
59 entry("SYNCFILE=%s", syncfile.c_str()));
60 inotify_rm_watch(fd, wd);
61 close(fd);
62 continue;
63 }
64
65 fileMap[fd].insert(std::make_pair(wd, fs::path(line)));
66 }
67 }
68}
69
70SyncWatch::~SyncWatch()
71{
72 for (const auto& fd : fileMap)
73 {
74 for (const auto& wd : fd.second)
75 {
76 inotify_rm_watch(fd.first, wd.first);
77 }
78 close(fd.first);
79 }
80}
81
82int SyncWatch::callback(sd_event_source* s, int fd, uint32_t revents,
83 void* userdata)
84{
Adriana Kobylaka9074342018-05-08 11:52:44 -050085 if (!(revents & EPOLLIN))
86 {
87 return 0;
88 }
89
90 constexpr auto maxBytes = 1024;
91 uint8_t buffer[maxBytes];
92 auto bytes = read(fd, buffer, maxBytes);
93 if (0 > bytes)
94 {
95 return 0;
96 }
97
98 auto syncWatch = static_cast<SyncWatch*>(userdata);
99 auto offset = 0;
100 while (offset < bytes)
101 {
102 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
103
104 // fileMap<fd, std::map<wd, path>>
105 auto it1 = syncWatch->fileMap.find(fd);
106 if (it1 != syncWatch->fileMap.end())
107 {
108 auto it2 = it1->second.begin();
109 auto rc = syncWatch->syncCallback(event->mask, it2->second);
110 if (rc)
111 {
112 return rc;
113 }
114 }
115
116 offset += offsetof(inotify_event, name) + event->len;
117 }
118
Adriana Kobylakb072d1b2018-04-24 11:37:21 -0500119 return 0;
120}
121
122} // namespace manager
123} // namespace software
124} // namespace phosphor