blob: fd2cad22418b4ee7a99a0265ad8629067f3b5b95 [file] [log] [blame]
Gunnar Millsf6ed5892018-09-07 17:08:02 -05001#include "config.h"
2
3#include "watch.hpp"
4
Lei YUbee51402019-02-26 11:36:34 +08005#include "item_updater_ubi.hpp"
Gunnar Millsf6ed5892018-09-07 17:08:02 -05006
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -05007#include <sys/inotify.h>
8#include <unistd.h>
Gunnar Millsf6ed5892018-09-07 17:08:02 -05009
Brad Bishop8facccf2020-11-04 09:44:58 -050010#include <phosphor-logging/log.hpp>
11
Gunnar Millsf6ed5892018-09-07 17:08:02 -050012#include <cstddef>
13#include <cstring>
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050014#include <experimental/filesystem>
Gunnar Millsf6ed5892018-09-07 17:08:02 -050015#include <functional>
Gunnar Millsf6ed5892018-09-07 17:08:02 -050016#include <stdexcept>
17#include <string>
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050018
19namespace openpower
20{
21namespace software
22{
23namespace updater
24{
25
26using namespace phosphor::logging;
27namespace fs = std::experimental::filesystem;
28
29Watch::Watch(sd_event* loop,
Lei YUf3ce4332019-02-21 14:09:49 +080030 std::function<void(const std::string&)> functionalCallback) :
Adriana Kobylak70dcb632018-02-27 15:46:52 -060031 functionalCallback(functionalCallback),
32 fd(inotifyInit())
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050033
34{
35 // Create PNOR_ACTIVE_PATH if doesn't exist.
36 if (!fs::is_directory(PNOR_ACTIVE_PATH))
37 {
38 fs::create_directories(PNOR_ACTIVE_PATH);
39 }
40
41 wd = inotify_add_watch(fd(), PNOR_ACTIVE_PATH, IN_CREATE);
42 if (-1 == wd)
43 {
44 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060045 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050046 "Error occurred during the inotify_init1");
47 }
48
49 decltype(eventSource.get()) sourcePtr = nullptr;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060050 auto rc = sd_event_add_io(loop, &sourcePtr, fd(), EPOLLIN, callback, this);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050051
52 eventSource.reset(sourcePtr);
53
54 if (0 > rc)
55 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -060056 throw std::system_error(-rc, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050057 "Error occurred during the inotify_init1");
58 }
59}
60
61Watch::~Watch()
62{
63 if ((-1 != fd()) && (-1 != wd))
64 {
65 inotify_rm_watch(fd(), wd);
66 }
67}
68
Adriana Kobylak70dcb632018-02-27 15:46:52 -060069int Watch::callback(sd_event_source* s, int fd, uint32_t revents,
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050070 void* userdata)
71{
72 if (!(revents & EPOLLIN))
73 {
74 return 0;
75 }
76
77 constexpr auto maxBytes = 1024;
78 uint8_t buffer[maxBytes];
79 auto bytes = read(fd, buffer, maxBytes);
80 if (0 > bytes)
81 {
82 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060083 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050084 "failed to read inotify event");
85 }
86
87 auto offset = 0;
88 while (offset < bytes)
89 {
90 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
91 // Update the functional association on a RO
92 // active image symlink change
93 fs::path path(PNOR_ACTIVE_PATH);
94 path /= event->name;
95 if (fs::equivalent(path, PNOR_RO_ACTIVE_PATH))
96 {
Lei YUbee51402019-02-26 11:36:34 +080097 auto id = ItemUpdaterUbi::determineId(path);
Lei YUf3ce4332019-02-21 14:09:49 +080098 static_cast<Watch*>(userdata)->functionalCallback(id);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050099 }
100 offset += offsetof(inotify_event, name) + event->len;
101 }
102
103 return 0;
104}
105
106int Watch::inotifyInit()
107{
108 auto fd = inotify_init1(IN_NONBLOCK);
109
110 if (-1 == fd)
111 {
112 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600113 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -0500114 "Error occurred during the inotify_init1");
115 }
116
117 return fd;
118}
119
120} // namespace updater
121} // namespace software
122} // namespace openpower