blob: 9402057d6ab9b80609ce6d19959723541b7b7b79 [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) :
Adriana Kobylak70dcb632018-02-27 15:46:52 -060026 functionalCallback(functionalCallback),
27 fd(inotifyInit())
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050028
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;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060040 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050041 "Error occurred during the inotify_init1");
42 }
43
44 decltype(eventSource.get()) sourcePtr = nullptr;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060045 auto rc = sd_event_add_io(loop, &sourcePtr, fd(), EPOLLIN, callback, this);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050046
47 eventSource.reset(sourcePtr);
48
49 if (0 > rc)
50 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -060051 throw std::system_error(-rc, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050052 "Error occurred during the inotify_init1");
53 }
54}
55
56Watch::~Watch()
57{
58 if ((-1 != fd()) && (-1 != wd))
59 {
60 inotify_rm_watch(fd(), wd);
61 }
62}
63
Adriana Kobylak70dcb632018-02-27 15:46:52 -060064int Watch::callback(sd_event_source* s, int fd, uint32_t revents,
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050065 void* userdata)
66{
67 if (!(revents & EPOLLIN))
68 {
69 return 0;
70 }
71
72 constexpr auto maxBytes = 1024;
73 uint8_t buffer[maxBytes];
74 auto bytes = read(fd, buffer, maxBytes);
75 if (0 > bytes)
76 {
77 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060078 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050079 "failed to read inotify event");
80 }
81
82 auto offset = 0;
83 while (offset < bytes)
84 {
85 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
86 // Update the functional association on a RO
87 // active image symlink change
88 fs::path path(PNOR_ACTIVE_PATH);
89 path /= event->name;
90 if (fs::equivalent(path, PNOR_RO_ACTIVE_PATH))
91 {
Gunnar Mills2badd7a2017-09-20 12:51:28 -050092 auto id = ItemUpdater::determineId(path);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050093 auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
94
95 static_cast<Watch*>(userdata)->functionalCallback(objPath);
96 }
97 offset += offsetof(inotify_event, name) + event->len;
98 }
99
100 return 0;
101}
102
103int Watch::inotifyInit()
104{
105 auto fd = inotify_init1(IN_NONBLOCK);
106
107 if (-1 == fd)
108 {
109 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600110 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -0500111 "Error occurred during the inotify_init1");
112 }
113
114 return fd;
115}
116
117} // namespace updater
118} // namespace software
119} // namespace openpower