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