14d8d5770STom Joseph #include "watch.hpp"
24d8d5770STom Joseph
34d8d5770STom Joseph #include <sys/inotify.h>
44d8d5770STom Joseph #include <unistd.h>
54d8d5770STom Joseph
64d8d5770STom Joseph #include <cstddef>
74d8d5770STom Joseph #include <cstring>
84d8d5770STom Joseph #include <filesystem>
94d8d5770STom Joseph #include <stdexcept>
104d8d5770STom Joseph #include <string>
114d8d5770STom Joseph
124d8d5770STom Joseph namespace pldm
134d8d5770STom Joseph {
144d8d5770STom Joseph
154d8d5770STom Joseph namespace fw_update
164d8d5770STom Joseph {
174d8d5770STom Joseph
184d8d5770STom Joseph // using namespace phosphor::logging;
194d8d5770STom Joseph using namespace std::string_literals;
204d8d5770STom Joseph namespace fs = std::filesystem;
214d8d5770STom Joseph
Watch(sd_event * loop,std::function<int (std::string &)> imageCallback)224d8d5770STom Joseph Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) :
234d8d5770STom Joseph imageCallback(imageCallback)
244d8d5770STom Joseph {
254d8d5770STom Joseph // Check if IMAGE DIR exists.
264d8d5770STom Joseph fs::path imgDirPath("/tmp/images");
274d8d5770STom Joseph if (!fs::is_directory(imgDirPath))
284d8d5770STom Joseph {
294d8d5770STom Joseph fs::create_directories(imgDirPath);
304d8d5770STom Joseph }
314d8d5770STom Joseph
324d8d5770STom Joseph fd = inotify_init1(IN_NONBLOCK);
334d8d5770STom Joseph if (-1 == fd)
344d8d5770STom Joseph {
354d8d5770STom Joseph // Store a copy of errno, because the string creation below will
364d8d5770STom Joseph // invalidate errno due to one more system calls.
374d8d5770STom Joseph auto error = errno;
38*16c2a0a0SPatrick Williams throw std::runtime_error(
39*16c2a0a0SPatrick Williams "inotify_init1 failed, errno="s + std::strerror(error));
404d8d5770STom Joseph }
414d8d5770STom Joseph
424d8d5770STom Joseph wd = inotify_add_watch(fd, "/tmp/images", IN_CLOSE_WRITE);
434d8d5770STom Joseph if (-1 == wd)
444d8d5770STom Joseph {
454d8d5770STom Joseph auto error = errno;
464d8d5770STom Joseph close(fd);
47*16c2a0a0SPatrick Williams throw std::runtime_error(
48*16c2a0a0SPatrick Williams "inotify_add_watch failed, errno="s + std::strerror(error));
494d8d5770STom Joseph }
504d8d5770STom Joseph
514d8d5770STom Joseph auto rc = sd_event_add_io(loop, nullptr, fd, EPOLLIN, callback, this);
524d8d5770STom Joseph if (0 > rc)
534d8d5770STom Joseph {
54*16c2a0a0SPatrick Williams throw std::runtime_error(
55*16c2a0a0SPatrick Williams "failed to add to event loop, rc="s + std::strerror(-rc));
564d8d5770STom Joseph }
574d8d5770STom Joseph }
584d8d5770STom Joseph
~Watch()594d8d5770STom Joseph Watch::~Watch()
604d8d5770STom Joseph {
614d8d5770STom Joseph if (-1 != fd)
624d8d5770STom Joseph {
634d8d5770STom Joseph if (-1 != wd)
644d8d5770STom Joseph {
654d8d5770STom Joseph inotify_rm_watch(fd, wd);
664d8d5770STom Joseph }
674d8d5770STom Joseph close(fd);
684d8d5770STom Joseph }
694d8d5770STom Joseph }
704d8d5770STom Joseph
callback(sd_event_source *,int fd,uint32_t revents,void * userdata)714d8d5770STom Joseph int Watch::callback(sd_event_source* /* s */, int fd, uint32_t revents,
724d8d5770STom Joseph void* userdata)
734d8d5770STom Joseph {
744d8d5770STom Joseph if (!(revents & EPOLLIN))
754d8d5770STom Joseph {
764d8d5770STom Joseph return 0;
774d8d5770STom Joseph }
784d8d5770STom Joseph
794d8d5770STom Joseph constexpr auto maxBytes = 1024;
804d8d5770STom Joseph uint8_t buffer[maxBytes];
814d8d5770STom Joseph auto bytes = read(fd, buffer, maxBytes);
824d8d5770STom Joseph if (0 > bytes)
834d8d5770STom Joseph {
844d8d5770STom Joseph auto error = errno;
85*16c2a0a0SPatrick Williams throw std::runtime_error(
86*16c2a0a0SPatrick Williams "failed to read inotify event, errno="s + std::strerror(error));
874d8d5770STom Joseph }
884d8d5770STom Joseph
894d8d5770STom Joseph auto offset = 0;
904d8d5770STom Joseph while (offset < bytes)
914d8d5770STom Joseph {
924d8d5770STom Joseph auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
934d8d5770STom Joseph if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
944d8d5770STom Joseph {
954d8d5770STom Joseph auto tarballPath = std::string{"/tmp/images"} + '/' + event->name;
964d8d5770STom Joseph auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
974d8d5770STom Joseph if (rc < 0)
984d8d5770STom Joseph {
994d8d5770STom Joseph // log<level::ERR>("Error processing image",
1004d8d5770STom Joseph // entry("IMAGE=%s", tarballPath.c_str()));
1014d8d5770STom Joseph }
1024d8d5770STom Joseph }
1034d8d5770STom Joseph
1044d8d5770STom Joseph offset += offsetof(inotify_event, name) + event->len;
1054d8d5770STom Joseph }
1064d8d5770STom Joseph
1074d8d5770STom Joseph return 0;
1084d8d5770STom Joseph }
1094d8d5770STom Joseph
1104d8d5770STom Joseph } // namespace fw_update
1114d8d5770STom Joseph } // namespace pldm
112