blob: 2212e01a3669d9224473f0907381c120fc48e383 [file] [log] [blame]
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -05001#include <stdexcept>
2#include <cstddef>
3#include <cstring>
4#include <string>
5#include <sys/inotify.h>
6#include <unistd.h>
7#include <experimental/filesystem>
8#include <phosphor-logging/log.hpp>
9#include "config.h"
10#include "watch.hpp"
Gunnar Mills2badd7a2017-09-20 12:51:28 -050011#include "item_updater.hpp"
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050012
13namespace openpower
14{
15namespace software
16{
17namespace updater
18{
19
20using namespace phosphor::logging;
21namespace fs = std::experimental::filesystem;
22
23Watch::Watch(sd_event* loop,
24 std::function<void(std::string&)> functionalCallback) :
25 functionalCallback(functionalCallback),
26 fd(inotifyInit())
27
28{
29 // Create PNOR_ACTIVE_PATH if doesn't exist.
30 if (!fs::is_directory(PNOR_ACTIVE_PATH))
31 {
32 fs::create_directories(PNOR_ACTIVE_PATH);
33 }
34
35 wd = inotify_add_watch(fd(), PNOR_ACTIVE_PATH, IN_CREATE);
36 if (-1 == wd)
37 {
38 auto error = errno;
39 throw std::system_error(error,
40 std::generic_category(),
41 "Error occurred during the inotify_init1");
42 }
43
44 decltype(eventSource.get()) sourcePtr = nullptr;
45 auto rc = sd_event_add_io(loop,
46 &sourcePtr,
47 fd(),
48 EPOLLIN,
49 callback,
50 this);
51
52 eventSource.reset(sourcePtr);
53
54 if (0 > rc)
55 {
56 throw std::system_error(-rc,
57 std::generic_category(),
58 "Error occurred during the inotify_init1");
59 }
60}
61
62Watch::~Watch()
63{
64 if ((-1 != fd()) && (-1 != wd))
65 {
66 inotify_rm_watch(fd(), wd);
67 }
68}
69
70int Watch::callback(sd_event_source* s,
71 int fd,
72 uint32_t revents,
73 void* userdata)
74{
75 if (!(revents & EPOLLIN))
76 {
77 return 0;
78 }
79
80 constexpr auto maxBytes = 1024;
81 uint8_t buffer[maxBytes];
82 auto bytes = read(fd, buffer, maxBytes);
83 if (0 > bytes)
84 {
85 auto error = errno;
86 throw std::system_error(error,
87 std::generic_category(),
88 "failed to read inotify event");
89 }
90
91 auto offset = 0;
92 while (offset < bytes)
93 {
94 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
95 // Update the functional association on a RO
96 // active image symlink change
97 fs::path path(PNOR_ACTIVE_PATH);
98 path /= event->name;
99 if (fs::equivalent(path, PNOR_RO_ACTIVE_PATH))
100 {
Gunnar Mills2badd7a2017-09-20 12:51:28 -0500101 auto id = ItemUpdater::determineId(path);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -0500102 auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
103
104 static_cast<Watch*>(userdata)->functionalCallback(objPath);
105 }
106 offset += offsetof(inotify_event, name) + event->len;
107 }
108
109 return 0;
110}
111
112int Watch::inotifyInit()
113{
114 auto fd = inotify_init1(IN_NONBLOCK);
115
116 if (-1 == fd)
117 {
118 auto error = errno;
119 throw std::system_error(error,
120 std::generic_category(),
121 "Error occurred during the inotify_init1");
122 }
123
124 return fd;
125}
126
127} // namespace updater
128} // namespace software
129} // namespace openpower