1 #include "config.h" 2 3 #include "watch.hpp" 4 5 #include "item_updater_ubi.hpp" 6 7 #include <sys/inotify.h> 8 #include <unistd.h> 9 10 #include <phosphor-logging/log.hpp> 11 12 #include <cstddef> 13 #include <cstring> 14 #include <filesystem> 15 #include <functional> 16 #include <stdexcept> 17 #include <string> 18 19 namespace openpower 20 { 21 namespace software 22 { 23 namespace updater 24 { 25 26 using namespace phosphor::logging; 27 28 Watch::Watch(sd_event* loop, 29 std::function<void(const std::string&)> functionalCallback) : 30 functionalCallback(functionalCallback), 31 fd(inotifyInit()) 32 33 { 34 // Create PNOR_ACTIVE_PATH if doesn't exist. 35 if (!std::filesystem::is_directory(PNOR_ACTIVE_PATH)) 36 { 37 std::filesystem::create_directories(PNOR_ACTIVE_PATH); 38 } 39 40 wd = inotify_add_watch(fd(), PNOR_ACTIVE_PATH, IN_CREATE); 41 if (-1 == wd) 42 { 43 auto error = errno; 44 throw std::system_error(error, std::generic_category(), 45 "Error occurred during the inotify_init1"); 46 } 47 48 decltype(eventSource.get()) sourcePtr = nullptr; 49 auto rc = sd_event_add_io(loop, &sourcePtr, fd(), EPOLLIN, callback, this); 50 51 eventSource.reset(sourcePtr); 52 53 if (0 > rc) 54 { 55 throw std::system_error(-rc, std::generic_category(), 56 "Error occurred during the inotify_init1"); 57 } 58 } 59 60 Watch::~Watch() 61 { 62 if ((-1 != fd()) && (-1 != wd)) 63 { 64 inotify_rm_watch(fd(), wd); 65 } 66 } 67 68 int Watch::callback(sd_event_source*, int fd, uint32_t revents, void* userdata) 69 { 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; 81 throw std::system_error(error, std::generic_category(), 82 "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 91 std::filesystem::path path(PNOR_ACTIVE_PATH); 92 path /= event->name; 93 if (std::filesystem::equivalent(path, PNOR_RO_ACTIVE_PATH)) 94 { 95 auto id = ItemUpdaterUbi::determineId(path); 96 static_cast<Watch*>(userdata)->functionalCallback(id); 97 } 98 offset += offsetof(inotify_event, name) + event->len; 99 } 100 101 return 0; 102 } 103 104 int Watch::inotifyInit() 105 { 106 auto fd = inotify_init1(IN_NONBLOCK); 107 108 if (-1 == fd) 109 { 110 auto error = errno; 111 throw std::system_error(error, std::generic_category(), 112 "Error occurred during the inotify_init1"); 113 } 114 115 return fd; 116 } 117 118 } // namespace updater 119 } // namespace software 120 } // namespace openpower 121