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