1 #include "config.h" 2 3 #include "sync_watch.hpp" 4 5 #include <sys/inotify.h> 6 #include <unistd.h> 7 8 #include <phosphor-logging/lg2.hpp> 9 10 #include <filesystem> 11 #include <fstream> 12 #include <system_error> 13 14 namespace phosphor 15 { 16 namespace software 17 { 18 namespace manager 19 { 20 21 PHOSPHOR_LOG2_USING; 22 23 void SyncWatch::addInotifyWatch(const fs::path& path) 24 { 25 auto wd = 26 inotify_add_watch(inotifyFd, path.c_str(), IN_CLOSE_WRITE | IN_DELETE); 27 if (-1 == wd) 28 { 29 error("inotify_add_watch on {PATH} failed: {ERRNO}", "ERRNO", errno, 30 "PATH", path); 31 return; 32 } 33 34 fileMap[wd] = fs::path(path); 35 } 36 37 SyncWatch::SyncWatch(sd_event& loop, 38 std::function<int(int, fs::path&)> syncCallback) : 39 inotifyFd(-1), syncCallback(std::move(syncCallback)), loop(loop) 40 { 41 auto fd = inotify_init1(IN_NONBLOCK); 42 if (-1 == fd) 43 { 44 error("inotify_init1 failed: {ERRNO}", "ERRNO", errno); 45 return; 46 } 47 inotifyFd = fd; 48 49 auto rc = sd_event_add_io(&loop, nullptr, fd, EPOLLIN, callback, this); 50 if (0 > rc) 51 { 52 error("failed to add to event loop: {RC}", "RC", rc); 53 return; 54 } 55 56 std::error_code ec; 57 auto syncfile = fs::path(SYNC_LIST_DIR_PATH) / SYNC_LIST_FILE_NAME; 58 if (fs::exists(syncfile, ec)) 59 { 60 std::string line; 61 std::ifstream file(syncfile.c_str()); 62 while (std::getline(file, line)) 63 { 64 addInotifyWatch(line); 65 } 66 } 67 } 68 69 SyncWatch::~SyncWatch() 70 { 71 if (inotifyFd != -1) 72 { 73 close(inotifyFd); 74 } 75 } 76 77 int SyncWatch::callback(sd_event_source* /* s */, int fd, uint32_t revents, 78 void* userdata) 79 { 80 if (!(revents & EPOLLIN)) 81 { 82 return 0; 83 } 84 85 constexpr auto maxBytes = 1024; 86 uint8_t buffer[maxBytes]; 87 auto bytes = read(fd, buffer, maxBytes); 88 if (0 > bytes) 89 { 90 return 0; 91 } 92 93 auto syncWatch = static_cast<SyncWatch*>(userdata); 94 auto offset = 0; 95 while (offset < bytes) 96 { 97 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]); 98 99 // Watch was removed, re-add it if file still exists. 100 if (event->mask & IN_IGNORED) 101 { 102 std::error_code ec; 103 if (fs::exists(syncWatch->fileMap[event->wd], ec)) 104 { 105 syncWatch->addInotifyWatch(syncWatch->fileMap[event->wd]); 106 } 107 else 108 { 109 info("The inotify watch on {PATH} was removed", "PATH", 110 syncWatch->fileMap[event->wd]); 111 } 112 return 0; 113 } 114 115 // fileMap<wd, path> 116 auto rc = syncWatch->syncCallback(static_cast<int>(event->mask), 117 syncWatch->fileMap[event->wd]); 118 if (rc) 119 { 120 return rc; 121 } 122 123 offset += offsetof(inotify_event, name) + event->len; 124 } 125 126 return 0; 127 } 128 129 } // namespace manager 130 } // namespace software 131 } // namespace phosphor 132