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