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