blob: 60f18fc4cfab69ab7c0ef26bb3a2c27d87426e39 [file] [log] [blame]
Tom Joseph4d8d5772021-08-17 07:35:05 -07001#include "watch.hpp"
2
3#include <sys/inotify.h>
4#include <unistd.h>
5
6#include <cstddef>
7#include <cstring>
8#include <filesystem>
9#include <stdexcept>
10#include <string>
11
12namespace pldm
13{
14
15namespace fw_update
16{
17
18// using namespace phosphor::logging;
19using namespace std::string_literals;
20namespace fs = std::filesystem;
21
22Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) :
23 imageCallback(imageCallback)
24{
25 // Check if IMAGE DIR exists.
26 fs::path imgDirPath("/tmp/images");
27 if (!fs::is_directory(imgDirPath))
28 {
29 fs::create_directories(imgDirPath);
30 }
31
32 fd = inotify_init1(IN_NONBLOCK);
33 if (-1 == fd)
34 {
35 // Store a copy of errno, because the string creation below will
36 // invalidate errno due to one more system calls.
37 auto error = errno;
Patrick Williams16c2a0a2024-08-16 15:20:59 -040038 throw std::runtime_error(
39 "inotify_init1 failed, errno="s + std::strerror(error));
Tom Joseph4d8d5772021-08-17 07:35:05 -070040 }
41
42 wd = inotify_add_watch(fd, "/tmp/images", IN_CLOSE_WRITE);
43 if (-1 == wd)
44 {
45 auto error = errno;
46 close(fd);
Patrick Williams16c2a0a2024-08-16 15:20:59 -040047 throw std::runtime_error(
48 "inotify_add_watch failed, errno="s + std::strerror(error));
Tom Joseph4d8d5772021-08-17 07:35:05 -070049 }
50
51 auto rc = sd_event_add_io(loop, nullptr, fd, EPOLLIN, callback, this);
52 if (0 > rc)
53 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -040054 throw std::runtime_error(
55 "failed to add to event loop, rc="s + std::strerror(-rc));
Tom Joseph4d8d5772021-08-17 07:35:05 -070056 }
57}
58
59Watch::~Watch()
60{
61 if (-1 != fd)
62 {
63 if (-1 != wd)
64 {
65 inotify_rm_watch(fd, wd);
66 }
67 close(fd);
68 }
69}
70
71int Watch::callback(sd_event_source* /* s */, int fd, uint32_t revents,
72 void* userdata)
73{
74 if (!(revents & EPOLLIN))
75 {
76 return 0;
77 }
78
79 constexpr auto maxBytes = 1024;
80 uint8_t buffer[maxBytes];
81 auto bytes = read(fd, buffer, maxBytes);
82 if (0 > bytes)
83 {
84 auto error = errno;
Patrick Williams16c2a0a2024-08-16 15:20:59 -040085 throw std::runtime_error(
86 "failed to read inotify event, errno="s + std::strerror(error));
Tom Joseph4d8d5772021-08-17 07:35:05 -070087 }
88
89 auto offset = 0;
90 while (offset < bytes)
91 {
92 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
93 if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
94 {
95 auto tarballPath = std::string{"/tmp/images"} + '/' + event->name;
96 auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
97 if (rc < 0)
98 {
99 // log<level::ERR>("Error processing image",
100 // entry("IMAGE=%s", tarballPath.c_str()));
101 }
102 }
103
104 offset += offsetof(inotify_event, name) + event->len;
105 }
106
107 return 0;
108}
109
110} // namespace fw_update
111} // namespace pldm