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