blob: 208d8184305f46a5e93de91eb8d39c5c95f7b5c0 [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;
38 throw std::runtime_error("inotify_init1 failed, errno="s +
39 std::strerror(error));
40 }
41
42 wd = inotify_add_watch(fd, "/tmp/images", IN_CLOSE_WRITE);
43 if (-1 == wd)
44 {
45 auto error = errno;
46 close(fd);
47 throw std::runtime_error("inotify_add_watch failed, errno="s +
48 std::strerror(error));
49 }
50
51 auto rc = sd_event_add_io(loop, nullptr, fd, EPOLLIN, callback, this);
52 if (0 > rc)
53 {
54 throw std::runtime_error("failed to add to event loop, rc="s +
55 std::strerror(-rc));
56 }
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;
85 throw std::runtime_error("failed to read inotify event, errno="s +
86 std::strerror(error));
87 }
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