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