| #include "watch.hpp" | 
 |  | 
 | #include <xyz/openbmc_project/Common/error.hpp> | 
 | #include <phosphor-logging/log.hpp> | 
 | #include <phosphor-logging/elog-errors.hpp> | 
 |  | 
 | #include <sys/inotify.h> | 
 | #include <errno.h> | 
 |  | 
 | namespace phosphor | 
 | { | 
 | namespace network | 
 | { | 
 | namespace inotify | 
 | { | 
 |  | 
 | using namespace phosphor::logging; | 
 | using namespace sdbusplus::xyz::openbmc_project::Common::Error; | 
 |  | 
 | Watch::Watch(phosphor::network::EventPtr& eventPtr, | 
 |              fs::path path, | 
 |              UserCallBack userFunc, | 
 |              int flags, | 
 |              uint32_t mask, | 
 |              uint32_t events) : | 
 |     path(path), | 
 |     userFunc(userFunc), | 
 |     flags(flags), | 
 |     mask(mask), | 
 |     events(events), | 
 |     fd(inotifyInit()) | 
 | { | 
 |     // Check if watch file exists | 
 |     // This is supposed to be there always | 
 |     if (!fs::is_regular_file(path)) | 
 |     { | 
 |         log<level::ERR>("Watch file doesn't exist", | 
 |                         entry("FILE=%s", path.c_str())); | 
 |         elog<InternalFailure>(); | 
 |     } | 
 |  | 
 |     auto dirPath = path.parent_path(); | 
 |     wd = inotify_add_watch(fd(), dirPath.c_str(), mask); | 
 |     if (wd == -1) | 
 |     { | 
 |         log<level::ERR>("Error from inotify_add_watch", | 
 |                         entry("ERRNO=%d", errno)); | 
 |         elog<InternalFailure>(); | 
 |     } | 
 |  | 
 |     // Register the fd with sd_event infrastructure and setup a | 
 |     // callback handler to be invoked on events | 
 |     auto rc = sd_event_add_io(eventPtr.get(), | 
 |                               nullptr, | 
 |                               fd(), | 
 |                               events, | 
 |                               Watch::processEvents, | 
 |                               this); | 
 |     if (rc < 0) | 
 |     { | 
 |         // Failed to add to event loop | 
 |         log<level::ERR>("Error registering with sd_event_add_io", | 
 |                         entry("RC=%d", rc)); | 
 |         elog<InternalFailure>(); | 
 |     } | 
 | } | 
 |  | 
 | int Watch::inotifyInit() | 
 | { | 
 |     auto fd = inotify_init1(flags); | 
 |     if (fd < 0) | 
 |     { | 
 |         log<level::ERR>("Error from inotify_init1", | 
 |                         entry("ERRNO=%d", errno)); | 
 |         elog<InternalFailure>(); | 
 |     } | 
 |     return fd; | 
 | } | 
 |  | 
 | int Watch::processEvents(sd_event_source* eventSource, | 
 |                          int fd, | 
 |                          uint32_t retEvents, | 
 |                          void* userData) | 
 | { | 
 |     auto watch = static_cast<Watch*>(userData); | 
 |  | 
 |     // Not the ones we are interested in | 
 |     if (!(retEvents & watch->events)) | 
 |     { | 
 |         return 0; | 
 |     } | 
 |  | 
 |     // Buffer size to be used while reading events. | 
 |     // per inotify(7), below number should be fine for reading | 
 |     // at-least one event | 
 |     constexpr auto maxBytes = sizeof(struct inotify_event) + NAME_MAX + 1; | 
 |     uint8_t eventData[maxBytes]{}; | 
 |  | 
 |     auto bytes = read(fd, eventData, maxBytes); | 
 |     if (bytes <= 0) | 
 |     { | 
 |         // Failed to read inotify event data | 
 |         // Report error and return | 
 |         log<level::ERR>("Error reading inotify event", | 
 |                         entry("ERRNO=%d", errno)); | 
 |         report<InternalFailure>(); | 
 |         return 0; | 
 |     } | 
 |  | 
 |     auto offset = 0; | 
 |     auto stateFile = watch->path.filename(); | 
 |     while (offset < bytes) | 
 |     { | 
 |         auto event = reinterpret_cast<inotify_event*>(&eventData[offset]); | 
 |  | 
 |         // Filter the interesting ones | 
 |         auto mask = event->mask & watch->mask; | 
 |         if (mask) | 
 |         { | 
 |             if((event->len > 0) && | 
 |                (strstr(event->name, stateFile.string().c_str()))) | 
 |             { | 
 |                 if (watch->userFunc) | 
 |                 { | 
 |                     watch->userFunc(watch->path); | 
 |                 } | 
 |                 // Found the event of interest | 
 |                 break; | 
 |             } | 
 |         } | 
 |         // Move past this entry | 
 |         offset += offsetof(inotify_event, name) + event->len; | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | } // namespace inotify | 
 | } // namespace network | 
 | } // namespace phosphor |