1f18bf836SPatrick Venture #include "config.h"
2f18bf836SPatrick Venture 
3f18bf836SPatrick Venture #include "log_manager.hpp"
4f18bf836SPatrick Venture 
5f18bf836SPatrick Venture #include "elog_entry.hpp"
6f18bf836SPatrick Venture #include "elog_meta.hpp"
7f18bf836SPatrick Venture #include "elog_serialize.hpp"
8f18bf836SPatrick Venture 
95f4247f0SAdriana Kobylak #include <poll.h>
105f4247f0SAdriana Kobylak #include <sys/inotify.h>
111db1bd35SAdriana Kobylak #include <systemd/sd-bus.h>
12d311bc8dSAdriana Kobylak #include <systemd/sd-journal.h>
135f4247f0SAdriana Kobylak #include <unistd.h>
14f18bf836SPatrick Venture 
15f18bf836SPatrick Venture #include <chrono>
16f18bf836SPatrick Venture #include <cstdio>
17f18bf836SPatrick Venture #include <fstream>
18f18bf836SPatrick Venture #include <future>
19f18bf836SPatrick Venture #include <iostream>
202bb15195SSaqib Khan #include <phosphor-logging/log.hpp>
21f18bf836SPatrick Venture #include <sdbusplus/vtable.hpp>
22f18bf836SPatrick Venture #include <set>
23f18bf836SPatrick Venture #include <string>
24f18bf836SPatrick Venture #include <vector>
25a87c157cSDeepak Kodihalli 
26a87c157cSDeepak Kodihalli using namespace phosphor::logging;
275f4247f0SAdriana Kobylak using namespace std::chrono;
28a87c157cSDeepak Kodihalli extern const std::map<metadata::Metadata,
29f18bf836SPatrick Venture                       std::function<metadata::associations::Type>>
30f18bf836SPatrick Venture     meta;
311db1bd35SAdriana Kobylak 
328f7941edSAdriana Kobylak namespace phosphor
338f7941edSAdriana Kobylak {
348f7941edSAdriana Kobylak namespace logging
358f7941edSAdriana Kobylak {
3605aae8bcSNagaraju Goruganti namespace internal
3705aae8bcSNagaraju Goruganti {
386fd9dc48SDeepak Kodihalli inline auto getLevel(const std::string& errMsg)
396fd9dc48SDeepak Kodihalli {
406fd9dc48SDeepak Kodihalli     auto reqLevel = Entry::Level::Error; // Default to Error
416fd9dc48SDeepak Kodihalli 
426fd9dc48SDeepak Kodihalli     auto levelmap = g_errLevelMap.find(errMsg);
43f8a5a797SNagaraju Goruganti     if (levelmap != g_errLevelMap.end())
44f8a5a797SNagaraju Goruganti     {
456fd9dc48SDeepak Kodihalli         reqLevel = static_cast<Entry::Level>(levelmap->second);
46f8a5a797SNagaraju Goruganti     }
47f8a5a797SNagaraju Goruganti 
486fd9dc48SDeepak Kodihalli     return reqLevel;
496fd9dc48SDeepak Kodihalli }
506fd9dc48SDeepak Kodihalli 
51477b731aSNagaraju Goruganti int Manager::getRealErrSize()
52477b731aSNagaraju Goruganti {
53477b731aSNagaraju Goruganti     return realErrors.size();
54477b731aSNagaraju Goruganti }
55477b731aSNagaraju Goruganti 
56477b731aSNagaraju Goruganti int Manager::getInfoErrSize()
57477b731aSNagaraju Goruganti {
58477b731aSNagaraju Goruganti     return infoErrors.size();
59477b731aSNagaraju Goruganti }
60477b731aSNagaraju Goruganti 
616fd9dc48SDeepak Kodihalli void Manager::commit(uint64_t transactionId, std::string errMsg)
626fd9dc48SDeepak Kodihalli {
636fd9dc48SDeepak Kodihalli     auto level = getLevel(errMsg);
646fd9dc48SDeepak Kodihalli     _commit(transactionId, std::move(errMsg), level);
656fd9dc48SDeepak Kodihalli }
666fd9dc48SDeepak Kodihalli 
676fd9dc48SDeepak Kodihalli void Manager::commitWithLvl(uint64_t transactionId, std::string errMsg,
686fd9dc48SDeepak Kodihalli                             uint32_t errLvl)
696fd9dc48SDeepak Kodihalli {
706fd9dc48SDeepak Kodihalli     _commit(transactionId, std::move(errMsg),
716fd9dc48SDeepak Kodihalli             static_cast<Entry::Level>(errLvl));
726fd9dc48SDeepak Kodihalli }
736fd9dc48SDeepak Kodihalli 
746fd9dc48SDeepak Kodihalli void Manager::_commit(uint64_t transactionId, std::string&& errMsg,
756fd9dc48SDeepak Kodihalli                       Entry::Level errLvl)
766fd9dc48SDeepak Kodihalli {
776fd9dc48SDeepak Kodihalli     if (errLvl < Entry::sevLowerLimit)
78f8a5a797SNagaraju Goruganti     {
79e4b0b771SNagaraju Goruganti         if (realErrors.size() >= ERROR_CAP)
807656fba3SMarri Devender Rao         {
81e4b0b771SNagaraju Goruganti             erase(realErrors.front());
827656fba3SMarri Devender Rao         }
83f8a5a797SNagaraju Goruganti     }
84f8a5a797SNagaraju Goruganti     else
85f8a5a797SNagaraju Goruganti     {
86f8a5a797SNagaraju Goruganti         if (infoErrors.size() >= ERROR_INFO_CAP)
87f8a5a797SNagaraju Goruganti         {
88f8a5a797SNagaraju Goruganti             erase(infoErrors.front());
89f8a5a797SNagaraju Goruganti         }
90f8a5a797SNagaraju Goruganti     }
917298dc23SAdriana Kobylak     constexpr const auto transactionIdVar = "TRANSACTION_ID";
9227c87d92SAdriana Kobylak     // Length of 'TRANSACTION_ID' string.
936721899bSAdriana Kobylak     constexpr const auto transactionIdVarSize = strlen(transactionIdVar);
9427c87d92SAdriana Kobylak     // Length of 'TRANSACTION_ID=' string.
9527c87d92SAdriana Kobylak     constexpr const auto transactionIdVarOffset = transactionIdVarSize + 1;
961db1bd35SAdriana Kobylak 
975f4247f0SAdriana Kobylak     // Flush all the pending log messages into the journal
985f4247f0SAdriana Kobylak     journalSync();
99cfd9a7ddSAdriana Kobylak 
100d311bc8dSAdriana Kobylak     sd_journal* j = nullptr;
1018f7941edSAdriana Kobylak     int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
102d311bc8dSAdriana Kobylak     if (rc < 0)
103d311bc8dSAdriana Kobylak     {
104f18bf836SPatrick Venture         logging::log<logging::level::ERR>(
105f18bf836SPatrick Venture             "Failed to open journal",
106d311bc8dSAdriana Kobylak             logging::entry("DESCRIPTION=%s", strerror(-rc)));
1078f7941edSAdriana Kobylak         return;
108d311bc8dSAdriana Kobylak     }
109d311bc8dSAdriana Kobylak 
1107298dc23SAdriana Kobylak     std::string transactionIdStr = std::to_string(transactionId);
111d722b3aaSAdriana Kobylak     std::set<std::string> metalist;
112d722b3aaSAdriana Kobylak     auto metamap = g_errMetaMap.find(errMsg);
113d722b3aaSAdriana Kobylak     if (metamap != g_errMetaMap.end())
114d722b3aaSAdriana Kobylak     {
115d722b3aaSAdriana Kobylak         metalist.insert(metamap->second.begin(), metamap->second.end());
116d722b3aaSAdriana Kobylak     }
1177298dc23SAdriana Kobylak 
118db18ebe0SJayanth Othayoth     // Add _PID field information in AdditionalData.
119db18ebe0SJayanth Othayoth     metalist.insert("_PID");
120db18ebe0SJayanth Othayoth 
1217a33ee40STom Joseph     std::vector<std::string> additionalData;
1229aa7d789SAdriana Kobylak 
123d311bc8dSAdriana Kobylak     // Read the journal from the end to get the most recent entry first.
124d311bc8dSAdriana Kobylak     // The result from the sd_journal_get_data() is of the form VARIABLE=value.
125d311bc8dSAdriana Kobylak     SD_JOURNAL_FOREACH_BACKWARDS(j)
126d311bc8dSAdriana Kobylak     {
127d311bc8dSAdriana Kobylak         const char* data = nullptr;
128d311bc8dSAdriana Kobylak         size_t length = 0;
129d311bc8dSAdriana Kobylak 
1307298dc23SAdriana Kobylak         // Look for the transaction id metadata variable
1317298dc23SAdriana Kobylak         rc = sd_journal_get_data(j, transactionIdVar, (const void**)&data,
1327298dc23SAdriana Kobylak                                  &length);
133d311bc8dSAdriana Kobylak         if (rc < 0)
134d311bc8dSAdriana Kobylak         {
135fbe8872eSAdriana Kobylak             // This journal entry does not have the TRANSACTION_ID
136fbe8872eSAdriana Kobylak             // metadata variable.
137d311bc8dSAdriana Kobylak             continue;
138d311bc8dSAdriana Kobylak         }
1397298dc23SAdriana Kobylak 
14027c87d92SAdriana Kobylak         // journald does not guarantee that sd_journal_get_data() returns NULL
14127c87d92SAdriana Kobylak         // terminated strings, so need to specify the size to use to compare,
14227c87d92SAdriana Kobylak         // use the returned length instead of anything that relies on NULL
14327c87d92SAdriana Kobylak         // terminators like strlen().
14427c87d92SAdriana Kobylak         // The data variable is in the form of 'TRANSACTION_ID=1234'. Remove
14527c87d92SAdriana Kobylak         // the TRANSACTION_ID characters plus the (=) sign to do the comparison.
14627c87d92SAdriana Kobylak         // 'data + transactionIdVarOffset' will be in the form of '1234'.
14727c87d92SAdriana Kobylak         // 'length - transactionIdVarOffset' will be the length of '1234'.
14827c87d92SAdriana Kobylak         if ((length <= (transactionIdVarOffset)) ||
149f18bf836SPatrick Venture             (transactionIdStr.compare(0, transactionIdStr.size(),
15027c87d92SAdriana Kobylak                                       data + transactionIdVarOffset,
15127c87d92SAdriana Kobylak                                       length - transactionIdVarOffset) != 0))
152d311bc8dSAdriana Kobylak         {
153fbe8872eSAdriana Kobylak             // The value of the TRANSACTION_ID metadata is not the requested
154fbe8872eSAdriana Kobylak             // transaction id number.
155d311bc8dSAdriana Kobylak             continue;
156d311bc8dSAdriana Kobylak         }
157d311bc8dSAdriana Kobylak 
158fbe8872eSAdriana Kobylak         // Search for all metadata variables in the current journal entry.
159fbe8872eSAdriana Kobylak         for (auto i = metalist.cbegin(); i != metalist.cend();)
160fbe8872eSAdriana Kobylak         {
161f18bf836SPatrick Venture             rc = sd_journal_get_data(j, (*i).c_str(), (const void**)&data,
162f18bf836SPatrick Venture                                      &length);
163fbe8872eSAdriana Kobylak             if (rc < 0)
164fbe8872eSAdriana Kobylak             {
165fbe8872eSAdriana Kobylak                 // Metadata variable not found, check next metadata variable.
166fbe8872eSAdriana Kobylak                 i++;
167fbe8872eSAdriana Kobylak                 continue;
168fbe8872eSAdriana Kobylak             }
169fbe8872eSAdriana Kobylak 
170fbe8872eSAdriana Kobylak             // Metadata variable found, save it and remove it from the set.
171fbe8872eSAdriana Kobylak             additionalData.emplace_back(data, length);
172fbe8872eSAdriana Kobylak             i = metalist.erase(i);
173fbe8872eSAdriana Kobylak         }
174fbe8872eSAdriana Kobylak         if (metalist.empty())
175fbe8872eSAdriana Kobylak         {
176fbe8872eSAdriana Kobylak             // All metadata variables found, break out of journal loop.
1779aa7d789SAdriana Kobylak             break;
1789aa7d789SAdriana Kobylak         }
179fbe8872eSAdriana Kobylak     }
180fbe8872eSAdriana Kobylak     if (!metalist.empty())
181d311bc8dSAdriana Kobylak     {
182fbe8872eSAdriana Kobylak         // Not all the metadata variables were found in the journal.
183fbe8872eSAdriana Kobylak         for (auto& metaVarStr : metalist)
184fbe8872eSAdriana Kobylak         {
185f18bf836SPatrick Venture             logging::log<logging::level::INFO>(
186f18bf836SPatrick Venture                 "Failed to find metadata",
1877298dc23SAdriana Kobylak                 logging::entry("META_FIELD=%s", metaVarStr.c_str()));
188d311bc8dSAdriana Kobylak         }
189d311bc8dSAdriana Kobylak     }
190d311bc8dSAdriana Kobylak 
191d311bc8dSAdriana Kobylak     sd_journal_close(j);
192d311bc8dSAdriana Kobylak 
1934ea7f312SAdriana Kobylak     // Create error Entry dbus object
1944ea7f312SAdriana Kobylak     entryId++;
1956fd9dc48SDeepak Kodihalli     if (errLvl >= Entry::sevLowerLimit)
196f8a5a797SNagaraju Goruganti     {
197f8a5a797SNagaraju Goruganti         infoErrors.push_back(entryId);
198f8a5a797SNagaraju Goruganti     }
199e4b0b771SNagaraju Goruganti     else
200e4b0b771SNagaraju Goruganti     {
201e4b0b771SNagaraju Goruganti         realErrors.push_back(entryId);
202e4b0b771SNagaraju Goruganti     }
203c5f0bbd9SAdriana Kobylak     auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
204f18bf836SPatrick Venture                   std::chrono::system_clock::now().time_since_epoch())
205f18bf836SPatrick Venture                   .count();
206f18bf836SPatrick Venture     auto objPath = std::string(OBJ_ENTRY) + '/' + std::to_string(entryId);
207a87c157cSDeepak Kodihalli 
20835b46379SDeepak Kodihalli     AssociationList objects{};
209a87c157cSDeepak Kodihalli     processMetadata(errMsg, additionalData, objects);
210a87c157cSDeepak Kodihalli 
211f18bf836SPatrick Venture     auto e = std::make_unique<Entry>(busLog, objPath, entryId,
212c5f0bbd9SAdriana Kobylak                                      ms, // Milliseconds since 1970
213f18bf836SPatrick Venture                                      errLvl, std::move(errMsg),
21435b46379SDeepak Kodihalli                                      std::move(additionalData),
215f18bf836SPatrick Venture                                      std::move(objects), fwVersion, *this);
21672654f10SDeepak Kodihalli     serialize(*e);
21772654f10SDeepak Kodihalli     entries.insert(std::make_pair(entryId, std::move(e)));
2181db1bd35SAdriana Kobylak }
2191db1bd35SAdriana Kobylak 
220a87c157cSDeepak Kodihalli void Manager::processMetadata(const std::string& errorName,
221a87c157cSDeepak Kodihalli                               const std::vector<std::string>& additionalData,
222a87c157cSDeepak Kodihalli                               AssociationList& objects) const
223a87c157cSDeepak Kodihalli {
224a87c157cSDeepak Kodihalli     // additionalData is a list of "metadata=value"
225a87c157cSDeepak Kodihalli     constexpr auto separator = '=';
226*34438968SPatrick Venture     for (const auto& entryItem : additionalData)
227a87c157cSDeepak Kodihalli     {
228*34438968SPatrick Venture         auto found = entryItem.find(separator);
229a87c157cSDeepak Kodihalli         if (std::string::npos != found)
230a87c157cSDeepak Kodihalli         {
231*34438968SPatrick Venture             auto metadata = entryItem.substr(0, found);
232a87c157cSDeepak Kodihalli             auto iter = meta.find(metadata);
233a87c157cSDeepak Kodihalli             if (meta.end() != iter)
234a87c157cSDeepak Kodihalli             {
235a87c157cSDeepak Kodihalli                 (iter->second)(metadata, additionalData, objects);
236a87c157cSDeepak Kodihalli             }
237a87c157cSDeepak Kodihalli         }
238a87c157cSDeepak Kodihalli     }
239a87c157cSDeepak Kodihalli }
240a87c157cSDeepak Kodihalli 
24199a8549eSDeepak Kodihalli void Manager::erase(uint32_t entryId)
24299a8549eSDeepak Kodihalli {
243*34438968SPatrick Venture     auto entryFound = entries.find(entryId);
244*34438968SPatrick Venture     if (entries.end() != entryFound)
24599a8549eSDeepak Kodihalli     {
2463388799dSDeepak Kodihalli         // Delete the persistent representation of this error.
2473388799dSDeepak Kodihalli         fs::path errorPath(ERRLOG_PERSIST_PATH);
2488959efcbSMarri Devender Rao         errorPath /= std::to_string(entryId);
2493388799dSDeepak Kodihalli         fs::remove(errorPath);
250e4b0b771SNagaraju Goruganti 
251f18bf836SPatrick Venture         auto removeId = [](std::list<uint32_t>& ids, uint32_t id) {
252e4b0b771SNagaraju Goruganti             auto it = std::find(ids.begin(), ids.end(), id);
253e4b0b771SNagaraju Goruganti             if (it != ids.end())
254e4b0b771SNagaraju Goruganti             {
255e4b0b771SNagaraju Goruganti                 ids.erase(it);
256e4b0b771SNagaraju Goruganti             }
257e4b0b771SNagaraju Goruganti         };
258*34438968SPatrick Venture         if (entryFound->second->severity() >= Entry::sevLowerLimit)
259f8a5a797SNagaraju Goruganti         {
260e4b0b771SNagaraju Goruganti             removeId(infoErrors, entryId);
261f8a5a797SNagaraju Goruganti         }
262e4b0b771SNagaraju Goruganti         else
263e4b0b771SNagaraju Goruganti         {
264e4b0b771SNagaraju Goruganti             removeId(realErrors, entryId);
265f8a5a797SNagaraju Goruganti         }
266*34438968SPatrick Venture         entries.erase(entryFound);
26799a8549eSDeepak Kodihalli     }
2688959efcbSMarri Devender Rao     else
2698959efcbSMarri Devender Rao     {
2708959efcbSMarri Devender Rao         logging::log<level::ERR>("Invalid entry ID to delete",
2718959efcbSMarri Devender Rao                                  logging::entry("ID=%d", entryId));
2728959efcbSMarri Devender Rao     }
27399a8549eSDeepak Kodihalli }
27499a8549eSDeepak Kodihalli 
27572654f10SDeepak Kodihalli void Manager::restore()
27672654f10SDeepak Kodihalli {
277f18bf836SPatrick Venture     auto sanity = [](const auto& id, const auto& restoredId) {
278979ed1ccSMarri Devender Rao         return id == restoredId;
279979ed1ccSMarri Devender Rao     };
28072654f10SDeepak Kodihalli     std::vector<uint32_t> errorIds;
28172654f10SDeepak Kodihalli 
28272654f10SDeepak Kodihalli     fs::path dir(ERRLOG_PERSIST_PATH);
28372654f10SDeepak Kodihalli     if (!fs::exists(dir) || fs::is_empty(dir))
28472654f10SDeepak Kodihalli     {
28572654f10SDeepak Kodihalli         return;
28672654f10SDeepak Kodihalli     }
28772654f10SDeepak Kodihalli 
28872654f10SDeepak Kodihalli     for (auto& file : fs::directory_iterator(dir))
28972654f10SDeepak Kodihalli     {
29072654f10SDeepak Kodihalli         auto id = file.path().filename().c_str();
29172654f10SDeepak Kodihalli         auto idNum = std::stol(id);
29272654f10SDeepak Kodihalli         auto e = std::make_unique<Entry>(
293f18bf836SPatrick Venture             busLog, std::string(OBJ_ENTRY) + '/' + id, idNum, *this);
29472654f10SDeepak Kodihalli         if (deserialize(file.path(), *e))
29572654f10SDeepak Kodihalli         {
296979ed1ccSMarri Devender Rao             // validate the restored error entry id
297979ed1ccSMarri Devender Rao             if (sanity(static_cast<uint32_t>(idNum), e->id()))
298979ed1ccSMarri Devender Rao             {
29972654f10SDeepak Kodihalli                 e->emit_object_added();
300f8a5a797SNagaraju Goruganti                 if (e->severity() >= Entry::sevLowerLimit)
301f8a5a797SNagaraju Goruganti                 {
302f8a5a797SNagaraju Goruganti                     infoErrors.push_back(idNum);
303f8a5a797SNagaraju Goruganti                 }
304e4b0b771SNagaraju Goruganti                 else
305e4b0b771SNagaraju Goruganti                 {
306e4b0b771SNagaraju Goruganti                     realErrors.push_back(idNum);
307e4b0b771SNagaraju Goruganti                 }
308979ed1ccSMarri Devender Rao 
30972654f10SDeepak Kodihalli                 entries.insert(std::make_pair(idNum, std::move(e)));
31072654f10SDeepak Kodihalli                 errorIds.push_back(idNum);
31172654f10SDeepak Kodihalli             }
312979ed1ccSMarri Devender Rao             else
313979ed1ccSMarri Devender Rao             {
314979ed1ccSMarri Devender Rao                 logging::log<logging::level::ERR>(
315979ed1ccSMarri Devender Rao                     "Failed in sanity check while restoring error entry. "
316979ed1ccSMarri Devender Rao                     "Ignoring error entry",
317979ed1ccSMarri Devender Rao                     logging::entry("ID_NUM=%d", idNum),
318979ed1ccSMarri Devender Rao                     logging::entry("ENTRY_ID=%d", e->id()));
319979ed1ccSMarri Devender Rao             }
320979ed1ccSMarri Devender Rao         }
32172654f10SDeepak Kodihalli     }
32272654f10SDeepak Kodihalli 
32337af9bacSVishwanatha Subbanna     if (!errorIds.empty())
32437af9bacSVishwanatha Subbanna     {
32572654f10SDeepak Kodihalli         entryId = *(std::max_element(errorIds.begin(), errorIds.end()));
32672654f10SDeepak Kodihalli     }
32737af9bacSVishwanatha Subbanna }
32872654f10SDeepak Kodihalli 
3295f4247f0SAdriana Kobylak void Manager::journalSync()
3305f4247f0SAdriana Kobylak {
3315f4247f0SAdriana Kobylak     bool syncRequested = false;
3325f4247f0SAdriana Kobylak     auto fd = -1;
3335f4247f0SAdriana Kobylak     auto rc = -1;
3345f4247f0SAdriana Kobylak     auto wd = -1;
3355f4247f0SAdriana Kobylak     auto bus = sdbusplus::bus::new_default();
3365f4247f0SAdriana Kobylak 
3375f4247f0SAdriana Kobylak     auto start =
3385f4247f0SAdriana Kobylak         duration_cast<microseconds>(steady_clock::now().time_since_epoch())
3395f4247f0SAdriana Kobylak             .count();
3405f4247f0SAdriana Kobylak 
3415f4247f0SAdriana Kobylak     constexpr auto maxRetry = 2;
3425f4247f0SAdriana Kobylak     for (int i = 0; i < maxRetry; i++)
3435f4247f0SAdriana Kobylak     {
3445f4247f0SAdriana Kobylak         // Read timestamp from synced file
3455f4247f0SAdriana Kobylak         constexpr auto syncedPath = "/run/systemd/journal/synced";
3465f4247f0SAdriana Kobylak         std::ifstream syncedFile(syncedPath);
3475f4247f0SAdriana Kobylak         if (syncedFile.fail())
3485f4247f0SAdriana Kobylak         {
3497d111a85SAdriana Kobylak             // If the synced file doesn't exist, a sync request will create it.
3507d111a85SAdriana Kobylak             if (errno != ENOENT)
3517d111a85SAdriana Kobylak             {
3525f4247f0SAdriana Kobylak                 log<level::ERR>("Failed to open journal synced file",
3535f4247f0SAdriana Kobylak                                 entry("FILENAME=%s", syncedPath),
3545f4247f0SAdriana Kobylak                                 entry("ERRNO=%d", errno));
3555f4247f0SAdriana Kobylak                 return;
3565f4247f0SAdriana Kobylak             }
3577d111a85SAdriana Kobylak         }
3587d111a85SAdriana Kobylak         else
3597d111a85SAdriana Kobylak         {
3607d111a85SAdriana Kobylak             // Only read the synced file if it exists.
3615f4247f0SAdriana Kobylak             // See if a sync happened by now
3625f4247f0SAdriana Kobylak             std::string timestampStr;
3635f4247f0SAdriana Kobylak             std::getline(syncedFile, timestampStr);
3645f4247f0SAdriana Kobylak             auto timestamp = stoll(timestampStr);
3655f4247f0SAdriana Kobylak             if (timestamp >= start)
3665f4247f0SAdriana Kobylak             {
3675f4247f0SAdriana Kobylak                 return;
3685f4247f0SAdriana Kobylak             }
3697d111a85SAdriana Kobylak         }
3705f4247f0SAdriana Kobylak 
3715f4247f0SAdriana Kobylak         // Let's ask for a sync, but only once
3725f4247f0SAdriana Kobylak         if (!syncRequested)
3735f4247f0SAdriana Kobylak         {
3745f4247f0SAdriana Kobylak             syncRequested = true;
3755f4247f0SAdriana Kobylak 
3765f4247f0SAdriana Kobylak             constexpr auto JOURNAL_UNIT = "systemd-journald.service";
3775f4247f0SAdriana Kobylak             auto signal = SIGRTMIN + 1;
3785f4247f0SAdriana Kobylak 
3795f4247f0SAdriana Kobylak             auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
3805f4247f0SAdriana Kobylak                                               SYSTEMD_INTERFACE, "KillUnit");
3815f4247f0SAdriana Kobylak             method.append(JOURNAL_UNIT, "main", signal);
3825f4247f0SAdriana Kobylak             bus.call(method);
3835f4247f0SAdriana Kobylak             if (method.is_method_error())
3845f4247f0SAdriana Kobylak             {
3855f4247f0SAdriana Kobylak                 log<level::ERR>("Failed to kill journal service");
3865f4247f0SAdriana Kobylak                 return;
3875f4247f0SAdriana Kobylak             }
3885f4247f0SAdriana Kobylak             continue;
3895f4247f0SAdriana Kobylak         }
3905f4247f0SAdriana Kobylak 
3915f4247f0SAdriana Kobylak         // Let's install the inotify watch, if we didn't do that yet. This watch
3925f4247f0SAdriana Kobylak         // monitors the syncedFile for when journald updates it with a newer
3935f4247f0SAdriana Kobylak         // timestamp. This means the journal has been flushed.
3945f4247f0SAdriana Kobylak         if (fd < 0)
3955f4247f0SAdriana Kobylak         {
3965f4247f0SAdriana Kobylak             fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
3975f4247f0SAdriana Kobylak             if (fd < 0)
3985f4247f0SAdriana Kobylak             {
3995f4247f0SAdriana Kobylak                 log<level::ERR>("Failed to create inotify watch",
4005f4247f0SAdriana Kobylak                                 entry("ERRNO=%d", errno));
4015f4247f0SAdriana Kobylak                 return;
4025f4247f0SAdriana Kobylak             }
4035f4247f0SAdriana Kobylak 
4045f4247f0SAdriana Kobylak             constexpr auto JOURNAL_RUN_PATH = "/run/systemd/journal";
4055f4247f0SAdriana Kobylak             wd = inotify_add_watch(fd, JOURNAL_RUN_PATH,
4065f4247f0SAdriana Kobylak                                    IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR);
4075f4247f0SAdriana Kobylak             if (wd < 0)
4085f4247f0SAdriana Kobylak             {
4095f4247f0SAdriana Kobylak                 log<level::ERR>("Failed to watch journal directory",
4105f4247f0SAdriana Kobylak                                 entry("PATH=%s", JOURNAL_RUN_PATH),
4115f4247f0SAdriana Kobylak                                 entry("ERRNO=%d", errno));
4125f4247f0SAdriana Kobylak                 close(fd);
4135f4247f0SAdriana Kobylak                 return;
4145f4247f0SAdriana Kobylak             }
4155f4247f0SAdriana Kobylak             continue;
4165f4247f0SAdriana Kobylak         }
4175f4247f0SAdriana Kobylak 
4185f4247f0SAdriana Kobylak         // Let's wait until inotify reports an event
4195f4247f0SAdriana Kobylak         struct pollfd fds = {
4205f4247f0SAdriana Kobylak             .fd = fd,
4215f4247f0SAdriana Kobylak             .events = POLLIN,
4225f4247f0SAdriana Kobylak         };
4235f4247f0SAdriana Kobylak         constexpr auto pollTimeout = 5; // 5 seconds
4245f4247f0SAdriana Kobylak         rc = poll(&fds, 1, pollTimeout * 1000);
4255f4247f0SAdriana Kobylak         if (rc < 0)
4265f4247f0SAdriana Kobylak         {
4275f4247f0SAdriana Kobylak             log<level::ERR>("Failed to add event", entry("ERRNO=%d", errno),
4285f4247f0SAdriana Kobylak                             entry("ERR=%s", strerror(-rc)));
4295f4247f0SAdriana Kobylak             inotify_rm_watch(fd, wd);
4305f4247f0SAdriana Kobylak             close(fd);
4315f4247f0SAdriana Kobylak             return;
4325f4247f0SAdriana Kobylak         }
4335f4247f0SAdriana Kobylak         else if (rc == 0)
4345f4247f0SAdriana Kobylak         {
4355f4247f0SAdriana Kobylak             log<level::INFO>("Poll timeout, no new journal synced data",
4365f4247f0SAdriana Kobylak                              entry("TIMEOUT=%d", pollTimeout));
4375f4247f0SAdriana Kobylak             break;
4385f4247f0SAdriana Kobylak         }
4395f4247f0SAdriana Kobylak 
4405f4247f0SAdriana Kobylak         // Read from the specified file descriptor until there is no new data,
4415f4247f0SAdriana Kobylak         // throwing away everything read since the timestamp will be read at the
4425f4247f0SAdriana Kobylak         // beginning of the loop.
4435f4247f0SAdriana Kobylak         constexpr auto maxBytes = 64;
4445f4247f0SAdriana Kobylak         uint8_t buffer[maxBytes];
4455f4247f0SAdriana Kobylak         while (read(fd, buffer, maxBytes) > 0)
4465f4247f0SAdriana Kobylak             ;
4475f4247f0SAdriana Kobylak     }
4485f4247f0SAdriana Kobylak 
4494a029f2fSAdriana Kobylak     if (fd != -1)
4504a029f2fSAdriana Kobylak     {
4514a029f2fSAdriana Kobylak         if (wd != -1)
4525f4247f0SAdriana Kobylak         {
4535f4247f0SAdriana Kobylak             inotify_rm_watch(fd, wd);
4544a029f2fSAdriana Kobylak         }
4555f4247f0SAdriana Kobylak         close(fd);
4565f4247f0SAdriana Kobylak     }
4575f4247f0SAdriana Kobylak 
4585f4247f0SAdriana Kobylak     return;
4595f4247f0SAdriana Kobylak }
4605f4247f0SAdriana Kobylak 
4611275bd13SMatt Spinler std::string Manager::readFWVersion()
4621275bd13SMatt Spinler {
4631275bd13SMatt Spinler     std::string version;
4641275bd13SMatt Spinler     std::ifstream versionFile{BMC_VERSION_FILE};
4651275bd13SMatt Spinler     std::string line;
4661275bd13SMatt Spinler     static constexpr auto VERSION_ID = "VERSION_ID=";
4671275bd13SMatt Spinler 
4681275bd13SMatt Spinler     while (std::getline(versionFile, line))
4691275bd13SMatt Spinler     {
4701275bd13SMatt Spinler         if (line.find(VERSION_ID) != std::string::npos)
4711275bd13SMatt Spinler         {
4721275bd13SMatt Spinler             auto pos = line.find_first_of('"') + 1;
4731275bd13SMatt Spinler             version = line.substr(pos, line.find_last_of('"') - pos);
4741275bd13SMatt Spinler             break;
4751275bd13SMatt Spinler         }
4761275bd13SMatt Spinler     }
4771275bd13SMatt Spinler 
4781275bd13SMatt Spinler     if (version.empty())
4791275bd13SMatt Spinler     {
4801275bd13SMatt Spinler         log<level::ERR>("Unable to read BMC firmware version");
4811275bd13SMatt Spinler     }
4821275bd13SMatt Spinler 
4831275bd13SMatt Spinler     return version;
4841275bd13SMatt Spinler }
4851275bd13SMatt Spinler 
48605aae8bcSNagaraju Goruganti } // namespace internal
4878f7941edSAdriana Kobylak } // namespace logging
488f18bf836SPatrick Venture } // namespace phosphor
489