1 #include "watch.hpp" 2 3 #include "xyz/openbmc_project/Common/error.hpp" 4 5 #include <phosphor-logging/elog-errors.hpp> 6 #include <phosphor-logging/lg2.hpp> 7 8 #include <span> 9 10 namespace phosphor 11 { 12 namespace dump 13 { 14 namespace inotify 15 { 16 17 using namespace std::string_literals; 18 using namespace phosphor::logging; 19 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 20 21 Watch::~Watch() 22 { 23 if ((fd() >= 0) && (wd >= 0)) 24 { 25 inotify_rm_watch(fd(), wd); 26 } 27 } 28 29 Watch::Watch(const EventPtr& eventObj, const int flags, const uint32_t mask, 30 const uint32_t events, const std::filesystem::path& path, 31 UserType userFunc) : 32 flags(flags), mask(mask), events(events), path(path), fd(inotifyInit()), 33 userFunc(userFunc) 34 { 35 // Check if watch DIR exists. 36 if (!std::filesystem::is_directory(path)) 37 { 38 lg2::error("Watch directory doesn't exist, DIR: {DIRECTORY}", 39 "DIRECTORY", path); 40 elog<InternalFailure>(); 41 } 42 43 wd = inotify_add_watch(fd(), path.c_str(), mask); 44 if (-1 == wd) 45 { 46 auto error = errno; 47 lg2::error( 48 "Error occurred during the inotify_add_watch call, errno: {ERRNO}", 49 "ERRNO", error); 50 elog<InternalFailure>(); 51 } 52 53 auto rc = 54 sd_event_add_io(eventObj.get(), nullptr, fd(), events, callback, this); 55 if (0 > rc) 56 { 57 // Failed to add to event loop 58 lg2::error("Error occurred during the sd_event_add_io call, rc: {RC}", 59 "RC", rc); 60 elog<InternalFailure>(); 61 } 62 } 63 64 int Watch::inotifyInit() 65 { 66 auto fd = inotify_init1(flags); 67 68 if (-1 == fd) 69 { 70 auto error = errno; 71 lg2::error("Error occurred during the inotify_init1, errno: {ERRNO}", 72 "ERRNO", error); 73 elog<InternalFailure>(); 74 } 75 76 return fd; 77 } 78 79 int Watch::callback(sd_event_source*, int fd, uint32_t revents, void* userdata) 80 { 81 auto userData = static_cast<Watch*>(userdata); 82 83 if ((revents & userData->events) == 0U) 84 { 85 return 0; 86 } 87 88 // Maximum inotify events supported in the buffer 89 constexpr auto maxBytes = sizeof(struct inotify_event) + NAME_MAX + 1; 90 uint8_t buffer[maxBytes]; 91 92 std::span<char> bufferSpan(reinterpret_cast<char*>(buffer), maxBytes); 93 auto bytes = read(fd, bufferSpan.data(), bufferSpan.size()); 94 if (0 > bytes) 95 { 96 // Failed to read inotify event 97 // Report error and return 98 auto error = errno; 99 lg2::error("Error occurred during the read, errno: {ERRNO}", "ERRNO", 100 error); 101 report<InternalFailure>(); 102 return 0; 103 } 104 105 auto offset = 0; 106 107 UserMap userMap; 108 109 while (offset < bytes) 110 { 111 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]); 112 auto mask = event->mask & userData->mask; 113 114 if (mask != 0U) 115 { 116 userMap.emplace((userData->path / event->name), mask); 117 } 118 119 offset += offsetof(inotify_event, name) + event->len; 120 } 121 122 // Call user call back function in case valid data in the map 123 if (!userMap.empty()) 124 { 125 userData->userFunc(userMap); 126 } 127 128 return 0; 129 } 130 131 } // namespace inotify 132 } // namespace dump 133 } // namespace phosphor 134