blob: e46b8aab5e73b15f1f43432e26eec22a9449eed3 [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
10#include <cstddef>
11#include <cstring>
Gunnar Mills4e48fd52017-04-28 09:53:02 -050012#include <experimental/filesystem>
Deepak Kodihalli059e2332017-04-12 06:40:53 -050013#include <phosphor-logging/log.hpp>
Gunnar Millsb0ce9962018-09-07 13:39:10 -050014#include <stdexcept>
15#include <string>
Deepak Kodihalli059e2332017-04-12 06:40:53 -050016
17namespace phosphor
18{
19namespace software
20{
21namespace manager
22{
23
Gunnar Millse91d3212017-04-19 15:42:47 -050024using namespace phosphor::logging;
Deepak Kodihalli059e2332017-04-12 06:40:53 -050025using namespace std::string_literals;
Gunnar Mills4e48fd52017-04-28 09:53:02 -050026namespace fs = std::experimental::filesystem;
Deepak Kodihalli059e2332017-04-12 06:40:53 -050027
Adriana Kobylak2285fe02018-02-27 15:36:59 -060028Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) :
29 imageCallback(imageCallback)
Deepak Kodihalli059e2332017-04-12 06:40:53 -050030{
Gunnar Mills4e48fd52017-04-28 09:53:02 -050031 // Check if IMAGE DIR exists.
32 fs::path imgDirPath(IMG_UPLOAD_DIR);
33 if (!fs::is_directory(imgDirPath))
34 {
Gunnar Mills7e1abfc2017-11-09 15:43:50 -060035 fs::create_directories(imgDirPath);
Gunnar Mills4e48fd52017-04-28 09:53:02 -050036 }
37
Deepak Kodihalli059e2332017-04-12 06:40:53 -050038 fd = inotify_init1(IN_NONBLOCK);
39 if (-1 == fd)
40 {
41 // Store a copy of errno, because the string creation below will
42 // invalidate errno due to one more system calls.
43 auto error = errno;
Adriana Kobylak2285fe02018-02-27 15:36:59 -060044 throw std::runtime_error("inotify_init1 failed, errno="s +
45 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050046 }
47
Gunnar Mills368cfcb2017-04-27 16:13:17 -050048 wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE);
Deepak Kodihalli059e2332017-04-12 06:40:53 -050049 if (-1 == wd)
50 {
51 auto error = errno;
52 close(fd);
Adriana Kobylak2285fe02018-02-27 15:36:59 -060053 throw std::runtime_error("inotify_add_watch failed, errno="s +
54 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050055 }
56
Adriana Kobylak2285fe02018-02-27 15:36:59 -060057 auto rc = sd_event_add_io(loop, nullptr, fd, EPOLLIN, callback, this);
Deepak Kodihalli059e2332017-04-12 06:40:53 -050058 if (0 > rc)
59 {
Adriana Kobylak2285fe02018-02-27 15:36:59 -060060 throw std::runtime_error("failed to add to event loop, rc="s +
61 std::strerror(-rc));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050062 }
63}
64
65Watch::~Watch()
66{
Vernon Mauery8ff0ee52018-05-10 16:19:16 -070067 if (-1 != fd)
Deepak Kodihalli059e2332017-04-12 06:40:53 -050068 {
Vernon Mauery8ff0ee52018-05-10 16:19:16 -070069 if (-1 != wd)
70 {
71 inotify_rm_watch(fd, wd);
72 }
Deepak Kodihalli059e2332017-04-12 06:40:53 -050073 close(fd);
74 }
75}
76
Adriana Kobylak2285fe02018-02-27 15:36:59 -060077int Watch::callback(sd_event_source* s, int fd, uint32_t revents,
Deepak Kodihalli059e2332017-04-12 06:40:53 -050078 void* userdata)
79{
80 if (!(revents & EPOLLIN))
81 {
82 return 0;
83 }
84
85 constexpr auto maxBytes = 1024;
86 uint8_t buffer[maxBytes];
87 auto bytes = read(fd, buffer, maxBytes);
88 if (0 > bytes)
89 {
90 auto error = errno;
Adriana Kobylak2285fe02018-02-27 15:36:59 -060091 throw std::runtime_error("failed to read inotify event, errno="s +
92 std::strerror(error));
Deepak Kodihalli059e2332017-04-12 06:40:53 -050093 }
94
95 auto offset = 0;
96 while (offset < bytes)
97 {
98 auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
Gunnar Mills368cfcb2017-04-27 16:13:17 -050099 if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500100 {
Gunnar Mills3027bba2017-04-27 15:49:03 -0500101 auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name;
102 auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
Gunnar Millse91d3212017-04-19 15:42:47 -0500103 if (rc < 0)
104 {
105 log<level::ERR>("Error processing image",
Adriana Kobylak596466b2018-02-13 14:48:53 -0600106 entry("IMAGE=%s", tarballPath.c_str()));
Gunnar Millse91d3212017-04-19 15:42:47 -0500107 }
Deepak Kodihalli059e2332017-04-12 06:40:53 -0500108 }
109
110 offset += offsetof(inotify_event, name) + event->len;
111 }
112
113 return 0;
114}
115
116} // namespace manager
117} // namespace software
118} // namespace phosphor