summaryrefslogtreecommitdiffstats
path: root/sync_watch.cpp
blob: c017716aa924c493073c5bcf9211db9ce9571c96 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "config.h"

#include "sync_watch.hpp"

#include <sys/inotify.h>
#include <unistd.h>

#include <experimental/filesystem>
#include <fstream>
#include <phosphor-logging/log.hpp>

namespace phosphor
{
namespace software
{
namespace manager
{

using namespace phosphor::logging;
namespace fs = std::experimental::filesystem;

SyncWatch::SyncWatch(sd_event& loop,
                     std::function<int(int, fs::path&)> syncCallback) :
    syncCallback(syncCallback)
{
    auto syncfile = fs::path(SYNC_LIST_DIR_PATH) / SYNC_LIST_FILE_NAME;
    if (fs::exists(syncfile))
    {
        std::string line;
        std::ifstream file(syncfile.c_str());
        while (std::getline(file, line))
        {
            auto fd = inotify_init1(IN_NONBLOCK);
            if (-1 == fd)
            {
                log<level::ERR>("inotify_init1 failed",
                                entry("ERRNO=%d", errno),
                                entry("FILENAME=%s", line.c_str()),
                                entry("SYNCFILE=%s", syncfile.c_str()));
                continue;
            }

            auto wd =
                inotify_add_watch(fd, line.c_str(), IN_CLOSE_WRITE | IN_DELETE);
            if (-1 == wd)
            {
                log<level::ERR>("inotify_add_watch failed",
                                entry("ERRNO=%d", errno),
                                entry("FILENAME=%s", line.c_str()),
                                entry("SYNCFILE=%s", syncfile.c_str()));
                close(fd);
                continue;
            }

            auto rc =
                sd_event_add_io(&loop, nullptr, fd, EPOLLIN, callback, this);
            if (0 > rc)
            {
                log<level::ERR>("failed to add to event loop",
                                entry("RC=%d", rc),
                                entry("FILENAME=%s", line.c_str()),
                                entry("SYNCFILE=%s", syncfile.c_str()));
                inotify_rm_watch(fd, wd);
                close(fd);
                continue;
            }

            fileMap[fd].insert(std::make_pair(wd, fs::path(line)));
        }
    }
}

SyncWatch::~SyncWatch()
{
    for (const auto& fd : fileMap)
    {
        for (const auto& wd : fd.second)
        {
            inotify_rm_watch(fd.first, wd.first);
        }
        close(fd.first);
    }
}

int SyncWatch::callback(sd_event_source* s, int fd, uint32_t revents,
                        void* userdata)
{
    if (!(revents & EPOLLIN))
    {
        return 0;
    }

    constexpr auto maxBytes = 1024;
    uint8_t buffer[maxBytes];
    auto bytes = read(fd, buffer, maxBytes);
    if (0 > bytes)
    {
        return 0;
    }

    auto syncWatch = static_cast<SyncWatch*>(userdata);
    auto offset = 0;
    while (offset < bytes)
    {
        auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);

        // fileMap<fd, std::map<wd, path>>
        auto it1 = syncWatch->fileMap.find(fd);
        if (it1 != syncWatch->fileMap.end())
        {
            auto it2 = it1->second.begin();
            auto rc = syncWatch->syncCallback(event->mask, it2->second);
            if (rc)
            {
                return rc;
            }
        }

        offset += offsetof(inotify_event, name) + event->len;
    }

    return 0;
}

} // namespace manager
} // namespace software
} // namespace phosphor
OpenPOWER on IntegriCloud