blob: 38887d40233071613a0c38f50316989b6bbaffa0 [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>
Deepak Kodihalli059e2332017-04-12 06:40:53 -050017
18namespace phosphor
19{
20namespace software
21{
22namespace manager
23{
24
Patrick Williamsc9bb6422021-08-27 06:18:35 -050025PHOSPHOR_LOG2_USING;
Deepak Kodihalli059e2332017-04-12 06:40:53 -050026using namespace std::string_literals;
Adriana Kobylakc98d9122020-05-05 10:36:01 -050027namespace fs = std::filesystem;
Deepak Kodihalli059e2332017-04-12 06:40:53 -050028
Adriana Kobylak2285fe02018-02-27 15:36:59 -060029Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) :
30 imageCallback(imageCallback)
Deepak Kodihalli059e2332017-04-12 06:40:53 -050031{
Gunnar Mills4e48fd52017-04-28 09:53:02 -050032 // Check if IMAGE DIR exists.
33 fs::path imgDirPath(IMG_UPLOAD_DIR);
34 if (!fs::is_directory(imgDirPath))
35 {
Gunnar Mills7e1abfc2017-11-09 15:43:50 -060036 fs::create_directories(imgDirPath);
Gunnar Mills4e48fd52017-04-28 09:53:02 -050037 }
38
Deepak Kodihalli059e2332017-04-12 06:40:53 -050039 fd = inotify_init1(IN_NONBLOCK);
40 if (-1 == fd)
41 {
42 // Store a copy of errno, because the string creation below will
43 // invalidate errno due to one more system calls.
44 auto error = errno;
Adriana Kobylak2285fe02018-02-27 15:36:59 -060045 throw std::runtime_error("inotify_init1 failed, errno="s +
46 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050047 }
48
Gunnar Mills368cfcb2017-04-27 16:13:17 -050049 wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE);
Deepak Kodihalli059e2332017-04-12 06:40:53 -050050 if (-1 == wd)
51 {
52 auto error = errno;
53 close(fd);
Adriana Kobylak2285fe02018-02-27 15:36:59 -060054 throw std::runtime_error("inotify_add_watch failed, errno="s +
55 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050056 }
57
Adriana Kobylak2285fe02018-02-27 15:36:59 -060058 auto rc = sd_event_add_io(loop, nullptr, fd, EPOLLIN, callback, this);
Deepak Kodihalli059e2332017-04-12 06:40:53 -050059 if (0 > rc)
60 {
Adriana Kobylak2285fe02018-02-27 15:36:59 -060061 throw std::runtime_error("failed to add to event loop, rc="s +
62 std::strerror(-rc));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050063 }
64}
65
66Watch::~Watch()
67{
Vernon Mauery8ff0ee52018-05-10 16:19:16 -070068 if (-1 != fd)
Deepak Kodihalli059e2332017-04-12 06:40:53 -050069 {
Vernon Mauery8ff0ee52018-05-10 16:19:16 -070070 if (-1 != wd)
71 {
72 inotify_rm_watch(fd, wd);
73 }
Deepak Kodihalli059e2332017-04-12 06:40:53 -050074 close(fd);
75 }
76}
77
Adriana Kobylak292159f2020-05-05 09:25:55 -050078int Watch::callback(sd_event_source* /* s */, int fd, uint32_t revents,
Deepak Kodihalli059e2332017-04-12 06:40:53 -050079 void* userdata)
80{
81 if (!(revents & EPOLLIN))
82 {
83 return 0;
84 }
85
86 constexpr auto maxBytes = 1024;
87 uint8_t buffer[maxBytes];
88 auto bytes = read(fd, buffer, maxBytes);
89 if (0 > bytes)
90 {
91 auto error = errno;
Adriana Kobylak2285fe02018-02-27 15:36:59 -060092 throw std::runtime_error("failed to read inotify event, errno="s +
93 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050094 }
95
96 auto offset = 0;
97 while (offset < bytes)
98 {
99 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
Gunnar Mills368cfcb2017-04-27 16:13:17 -0500100 if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500101 {
Gunnar Mills3027bba2017-04-27 15:49:03 -0500102 auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name;
103 auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
Gunnar Millse91d3212017-04-19 15:42:47 -0500104 if (rc < 0)
105 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500106 error("Error ({RC}) processing image {IMAGE}", "RC", rc,
107 "IMAGE", tarballPath);
Gunnar Millse91d3212017-04-19 15:42:47 -0500108 }
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500109 }
110
111 offset += offsetof(inotify_event, name) + event->len;
112 }
113
114 return 0;
115}
116
117} // namespace manager
118} // namespace software
119} // namespace phosphor