blob: 35cbb15abbbc45b43766fc8897fcc5dc44f2a65d [file] [log] [blame]
Gunnar Millsf6ed5892018-09-07 17:08:02 -05001#include "config.h"
2
3#include "watch.hpp"
4
5#include "item_updater.hpp"
6
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -05007#include <sys/inotify.h>
8#include <unistd.h>
Gunnar Millsf6ed5892018-09-07 17:08:02 -05009
10#include <cstddef>
11#include <cstring>
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050012#include <experimental/filesystem>
Gunnar Millsf6ed5892018-09-07 17:08:02 -050013#include <functional>
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050014#include <phosphor-logging/log.hpp>
Gunnar Millsf6ed5892018-09-07 17:08:02 -050015#include <stdexcept>
16#include <string>
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050017
18namespace openpower
19{
20namespace software
21{
22namespace updater
23{
24
25using namespace phosphor::logging;
26namespace fs = std::experimental::filesystem;
27
28Watch::Watch(sd_event* loop,
29 std::function<void(std::string&)> functionalCallback) :
Adriana Kobylak70dcb632018-02-27 15:46:52 -060030 functionalCallback(functionalCallback),
31 fd(inotifyInit())
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050032
33{
34 // Create PNOR_ACTIVE_PATH if doesn't exist.
35 if (!fs::is_directory(PNOR_ACTIVE_PATH))
36 {
37 fs::create_directories(PNOR_ACTIVE_PATH);
38 }
39
40 wd = inotify_add_watch(fd(), PNOR_ACTIVE_PATH, IN_CREATE);
41 if (-1 == wd)
42 {
43 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060044 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050045 "Error occurred during the inotify_init1");
46 }
47
48 decltype(eventSource.get()) sourcePtr = nullptr;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060049 auto rc = sd_event_add_io(loop, &sourcePtr, fd(), EPOLLIN, callback, this);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050050
51 eventSource.reset(sourcePtr);
52
53 if (0 > rc)
54 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -060055 throw std::system_error(-rc, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050056 "Error occurred during the inotify_init1");
57 }
58}
59
60Watch::~Watch()
61{
62 if ((-1 != fd()) && (-1 != wd))
63 {
64 inotify_rm_watch(fd(), wd);
65 }
66}
67
Adriana Kobylak70dcb632018-02-27 15:46:52 -060068int Watch::callback(sd_event_source* s, int fd, uint32_t revents,
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050069 void* userdata)
70{
71 if (!(revents & EPOLLIN))
72 {
73 return 0;
74 }
75
76 constexpr auto maxBytes = 1024;
77 uint8_t buffer[maxBytes];
78 auto bytes = read(fd, buffer, maxBytes);
79 if (0 > bytes)
80 {
81 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060082 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050083 "failed to read inotify event");
84 }
85
86 auto offset = 0;
87 while (offset < bytes)
88 {
89 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
90 // Update the functional association on a RO
91 // active image symlink change
92 fs::path path(PNOR_ACTIVE_PATH);
93 path /= event->name;
94 if (fs::equivalent(path, PNOR_RO_ACTIVE_PATH))
95 {
Gunnar Mills2badd7a2017-09-20 12:51:28 -050096 auto id = ItemUpdater::determineId(path);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050097 auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
98
99 static_cast<Watch*>(userdata)->functionalCallback(objPath);
100 }
101 offset += offsetof(inotify_event, name) + event->len;
102 }
103
104 return 0;
105}
106
107int Watch::inotifyInit()
108{
109 auto fd = inotify_init1(IN_NONBLOCK);
110
111 if (-1 == fd)
112 {
113 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600114 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -0500115 "Error occurred during the inotify_init1");
116 }
117
118 return fd;
119}
120
121} // namespace updater
122} // namespace software
123} // namespace openpower