blob: 192d3d9b9b19880aee43885c6d72f5890b85db3d [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,
Lei YUf3ce4332019-02-21 14:09:49 +080029 std::function<void(const 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);
Lei YUf3ce4332019-02-21 14:09:49 +080097 static_cast<Watch*>(userdata)->functionalCallback(id);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050098 }
99 offset += offsetof(inotify_event, name) + event->len;
100 }
101
102 return 0;
103}
104
105int Watch::inotifyInit()
106{
107 auto fd = inotify_init1(IN_NONBLOCK);
108
109 if (-1 == fd)
110 {
111 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600112 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -0500113 "Error occurred during the inotify_init1");
114 }
115
116 return fd;
117}
118
119} // namespace updater
120} // namespace software
121} // namespace openpower