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 13 namespace phosphor 14 { 15 namespace software 16 { 17 namespace manager 18 { 19 20 PHOSPHOR_LOG2_USING; 21 22 void SyncWatch::addInotifyWatch(const fs::path& path) 23 { 24 auto wd = 25 inotify_add_watch(inotifyFd, path.c_str(), IN_CLOSE_WRITE | IN_DELETE); 26 if (-1 == wd) 27 { 28 error("inotify_add_watch on {PATH} failed: {ERRNO}", "ERRNO", errno, 29 "PATH", path); 30 return; 31 } 32 33 fileMap[wd] = fs::path(path); 34 } 35 36 SyncWatch::SyncWatch(sd_event& loop, 37 std::function<int(int, fs::path&)> syncCallback) : 38 inotifyFd(-1), 39 syncCallback(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 auto syncfile = fs::path(SYNC_LIST_DIR_PATH) / SYNC_LIST_FILE_NAME; 57 if (fs::exists(syncfile)) 58 { 59 std::string line; 60 std::ifstream file(syncfile.c_str()); 61 while (std::getline(file, line)) 62 { 63 addInotifyWatch(line); 64 } 65 } 66 } 67 68 SyncWatch::~SyncWatch() 69 { 70 if (inotifyFd != -1) 71 { 72 close(inotifyFd); 73 } 74 } 75 76 int SyncWatch::callback(sd_event_source* /* s */, int fd, uint32_t revents, 77 void* userdata) 78 { 79 if (!(revents & EPOLLIN)) 80 { 81 return 0; 82 } 83 84 constexpr auto maxBytes = 1024; 85 uint8_t buffer[maxBytes]; 86 auto bytes = read(fd, buffer, maxBytes); 87 if (0 > bytes) 88 { 89 return 0; 90 } 91 92 auto syncWatch = static_cast<SyncWatch*>(userdata); 93 auto offset = 0; 94 while (offset < bytes) 95 { 96 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]); 97 98 // Watch was removed, re-add it if file still exists. 99 if (event->mask & IN_IGNORED) 100 { 101 if (fs::exists(syncWatch->fileMap[event->wd])) 102 { 103 syncWatch->addInotifyWatch(syncWatch->fileMap[event->wd]); 104 } 105 else 106 { 107 info("The inotify watch on {PATH} was removed", "PATH", 108 syncWatch->fileMap[event->wd]); 109 } 110 return 0; 111 } 112 113 // fileMap<wd, path> 114 auto rc = 115 syncWatch->syncCallback(event->mask, syncWatch->fileMap[event->wd]); 116 if (rc) 117 { 118 return rc; 119 } 120 121 offset += offsetof(inotify_event, name) + event->len; 122 } 123 124 return 0; 125 } 126 127 } // namespace manager 128 } // namespace software 129 } // namespace phosphor 130