xref: /openbmc/pldm/fw-update/watch.cpp (revision 16c2a0a03e5daac77e204eb99e00711490fb6e26)
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