#include #include #include #include #include #include #include #include #include "config.h" #include "watch.hpp" #include "image_manager.hpp" namespace phosphor { namespace software { namespace manager { using namespace phosphor::logging; using namespace std::string_literals; namespace fs = std::experimental::filesystem; Watch::Watch(sd_event* loop, std::function imageCallback) : imageCallback( imageCallback) { // Check if IMAGE DIR exists. fs::path imgDirPath(IMG_UPLOAD_DIR); if (!fs::is_directory(imgDirPath)) { log("ERROR No Image Dir", entry("IMAGEDIR=%s", IMG_UPLOAD_DIR)); throw std::runtime_error( "No Image Dir, IMAGEDIR=" + std::string{IMG_UPLOAD_DIR}); } fd = inotify_init1(IN_NONBLOCK); if (-1 == fd) { // Store a copy of errno, because the string creation below will // invalidate errno due to one more system calls. auto error = errno; throw std::runtime_error( "inotify_init1 failed, errno="s + std::strerror(error)); } wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE); if (-1 == wd) { auto error = errno; close(fd); throw std::runtime_error( "inotify_add_watch failed, errno="s + std::strerror(error)); } auto rc = sd_event_add_io(loop, nullptr, fd, EPOLLIN, callback, this); if (0 > rc) { throw std::runtime_error( "failed to add to event loop, rc="s + std::strerror(-rc)); } } Watch::~Watch() { if ((-1 != fd) && (-1 != wd)) { inotify_rm_watch(fd, wd); close(fd); } } int Watch::callback(sd_event_source* s, int fd, uint32_t revents, void* userdata) { if (!(revents & EPOLLIN)) { return 0; } constexpr auto maxBytes = 1024; uint8_t buffer[maxBytes]; auto bytes = read(fd, buffer, maxBytes); if (0 > bytes) { auto error = errno; throw std::runtime_error( "failed to read inotify event, errno="s + std::strerror(error)); } auto offset = 0; while (offset < bytes) { auto event = reinterpret_cast(&buffer[offset]); if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR)) { auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name; auto rc = static_cast(userdata)->imageCallback(tarballPath); if (rc < 0) { log("Error processing image", entry("IMAGE=%s", tarballPath)); } } offset += offsetof(inotify_event, name) + event->len; } return 0; } } // namespace manager } // namespace software } // namespace phosphor