blob: 1b68fd1cfd2b5ae10d7da326b5c658276c3cbff6 [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>
Brad Bishop9f44c992020-11-06 14:48:46 -050014#include <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;
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050027
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.
Brad Bishop9f44c992020-11-06 14:48:46 -050035 if (!std::filesystem::is_directory(PNOR_ACTIVE_PATH))
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050036 {
Brad Bishop9f44c992020-11-06 14:48:46 -050037 std::filesystem::create_directories(PNOR_ACTIVE_PATH);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050038 }
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
Brad Bishopc8f22502020-11-06 14:42:09 -050068int Watch::callback(sd_event_source*, int fd, uint32_t revents, void* userdata)
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050069{
70 if (!(revents & EPOLLIN))
71 {
72 return 0;
73 }
74
75 constexpr auto maxBytes = 1024;
76 uint8_t buffer[maxBytes];
77 auto bytes = read(fd, buffer, maxBytes);
78 if (0 > bytes)
79 {
80 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060081 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050082 "failed to read inotify event");
83 }
84
85 auto offset = 0;
86 while (offset < bytes)
87 {
88 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
89 // Update the functional association on a RO
90 // active image symlink change
Brad Bishop9f44c992020-11-06 14:48:46 -050091 std::filesystem::path path(PNOR_ACTIVE_PATH);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050092 path /= event->name;
Brad Bishop9f44c992020-11-06 14:48:46 -050093 if (std::filesystem::equivalent(path, PNOR_RO_ACTIVE_PATH))
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050094 {
Lei YUbee51402019-02-26 11:36:34 +080095 auto id = ItemUpdaterUbi::determineId(path);
Lei YUf3ce4332019-02-21 14:09:49 +080096 static_cast<Watch*>(userdata)->functionalCallback(id);
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -050097 }
98 offset += offsetof(inotify_event, name) + event->len;
99 }
100
101 return 0;
102}
103
104int Watch::inotifyInit()
105{
106 auto fd = inotify_init1(IN_NONBLOCK);
107
108 if (-1 == fd)
109 {
110 auto error = errno;
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600111 throw std::system_error(error, std::generic_category(),
Gunnar Mills6bd6d7b2017-09-18 09:22:36 -0500112 "Error occurred during the inotify_init1");
113 }
114
115 return fd;
116}
117
118} // namespace updater
119} // namespace software
120} // namespace openpower