blob: cabfd7957c84ec7b7030db249c18326bd915765f [file] [log] [blame]
Gunnar Millsb0ce9962018-09-07 13:39:10 -05001#include "config.h"
2
3#include "watch.hpp"
4
5#include "image_manager.hpp"
6
Deepak Kodihalli059e2332017-04-12 06:40:53 -05007#include <sys/inotify.h>
8#include <unistd.h>
Gunnar Millsb0ce9962018-09-07 13:39:10 -05009
Patrick Williamsc9bb6422021-08-27 06:18:35 -050010#include <phosphor-logging/lg2.hpp>
Adriana Kobylak58aa7502020-06-08 11:12:11 -050011
Gunnar Millsb0ce9962018-09-07 13:39:10 -050012#include <cstddef>
13#include <cstring>
Adriana Kobylakc98d9122020-05-05 10:36:01 -050014#include <filesystem>
Gunnar Millsb0ce9962018-09-07 13:39:10 -050015#include <stdexcept>
16#include <string>
George Liu44b9fef2023-02-07 14:31:32 +080017#include <system_error>
Deepak Kodihalli059e2332017-04-12 06:40:53 -050018
19namespace phosphor
20{
21namespace software
22{
23namespace manager
24{
25
Patrick Williamsc9bb6422021-08-27 06:18:35 -050026PHOSPHOR_LOG2_USING;
Deepak Kodihalli059e2332017-04-12 06:40:53 -050027using namespace std::string_literals;
Adriana Kobylakc98d9122020-05-05 10:36:01 -050028namespace fs = std::filesystem;
Deepak Kodihalli059e2332017-04-12 06:40:53 -050029
Adriana Kobylak2285fe02018-02-27 15:36:59 -060030Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) :
31 imageCallback(imageCallback)
Deepak Kodihalli059e2332017-04-12 06:40:53 -050032{
Gunnar Mills4e48fd52017-04-28 09:53:02 -050033 // Check if IMAGE DIR exists.
George Liu44b9fef2023-02-07 14:31:32 +080034 std::error_code ec;
Gunnar Mills4e48fd52017-04-28 09:53:02 -050035 fs::path imgDirPath(IMG_UPLOAD_DIR);
George Liu44b9fef2023-02-07 14:31:32 +080036 if (!fs::is_directory(imgDirPath, ec))
Gunnar Mills4e48fd52017-04-28 09:53:02 -050037 {
George Liu44b9fef2023-02-07 14:31:32 +080038 fs::create_directories(imgDirPath, ec);
Gunnar Mills4e48fd52017-04-28 09:53:02 -050039 }
40
Deepak Kodihalli059e2332017-04-12 06:40:53 -050041 fd = inotify_init1(IN_NONBLOCK);
42 if (-1 == fd)
43 {
44 // Store a copy of errno, because the string creation below will
45 // invalidate errno due to one more system calls.
46 auto error = errno;
Adriana Kobylak2285fe02018-02-27 15:36:59 -060047 throw std::runtime_error("inotify_init1 failed, errno="s +
48 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050049 }
50
Gunnar Mills368cfcb2017-04-27 16:13:17 -050051 wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE);
Deepak Kodihalli059e2332017-04-12 06:40:53 -050052 if (-1 == wd)
53 {
54 auto error = errno;
55 close(fd);
Adriana Kobylak2285fe02018-02-27 15:36:59 -060056 throw std::runtime_error("inotify_add_watch failed, errno="s +
57 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050058 }
59
Adriana Kobylak2285fe02018-02-27 15:36:59 -060060 auto rc = sd_event_add_io(loop, nullptr, fd, EPOLLIN, callback, this);
Deepak Kodihalli059e2332017-04-12 06:40:53 -050061 if (0 > rc)
62 {
Adriana Kobylak2285fe02018-02-27 15:36:59 -060063 throw std::runtime_error("failed to add to event loop, rc="s +
64 std::strerror(-rc));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050065 }
66}
67
68Watch::~Watch()
69{
Vernon Mauery8ff0ee52018-05-10 16:19:16 -070070 if (-1 != fd)
Deepak Kodihalli059e2332017-04-12 06:40:53 -050071 {
Vernon Mauery8ff0ee52018-05-10 16:19:16 -070072 if (-1 != wd)
73 {
74 inotify_rm_watch(fd, wd);
75 }
Deepak Kodihalli059e2332017-04-12 06:40:53 -050076 close(fd);
77 }
78}
79
Adriana Kobylak292159f2020-05-05 09:25:55 -050080int Watch::callback(sd_event_source* /* s */, int fd, uint32_t revents,
Deepak Kodihalli059e2332017-04-12 06:40:53 -050081 void* userdata)
82{
83 if (!(revents & EPOLLIN))
84 {
85 return 0;
86 }
87
88 constexpr auto maxBytes = 1024;
89 uint8_t buffer[maxBytes];
90 auto bytes = read(fd, buffer, maxBytes);
91 if (0 > bytes)
92 {
93 auto error = errno;
Adriana Kobylak2285fe02018-02-27 15:36:59 -060094 throw std::runtime_error("failed to read inotify event, errno="s +
95 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050096 }
97
98 auto offset = 0;
99 while (offset < bytes)
100 {
101 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
Gunnar Mills368cfcb2017-04-27 16:13:17 -0500102 if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500103 {
Gunnar Mills3027bba2017-04-27 15:49:03 -0500104 auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name;
105 auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
Gunnar Millse91d3212017-04-19 15:42:47 -0500106 if (rc < 0)
107 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500108 error("Error ({RC}) processing image {IMAGE}", "RC", rc,
109 "IMAGE", tarballPath);
Gunnar Millse91d3212017-04-19 15:42:47 -0500110 }
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500111 }
112
113 offset += offsetof(inotify_event, name) + event->len;
114 }
115
116 return 0;
117}
118
119} // namespace manager
120} // namespace software
121} // namespace phosphor