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" 8*99c2b405SMatt Spinler #include "extensions.hpp" 9f18bf836SPatrick Venture 105f4247f0SAdriana Kobylak #include <poll.h> 115f4247f0SAdriana Kobylak #include <sys/inotify.h> 121db1bd35SAdriana Kobylak #include <systemd/sd-bus.h> 13d311bc8dSAdriana Kobylak #include <systemd/sd-journal.h> 145f4247f0SAdriana Kobylak #include <unistd.h> 15f18bf836SPatrick Venture 16*99c2b405SMatt Spinler #include <cassert> 17f18bf836SPatrick Venture #include <chrono> 18f18bf836SPatrick Venture #include <cstdio> 1930047bf9SPatrick Venture #include <cstring> 20f18bf836SPatrick Venture #include <fstream> 2130047bf9SPatrick Venture #include <functional> 22f18bf836SPatrick Venture #include <future> 23f18bf836SPatrick Venture #include <iostream> 2430047bf9SPatrick Venture #include <map> 252bb15195SSaqib Khan #include <phosphor-logging/log.hpp> 26f18bf836SPatrick Venture #include <sdbusplus/vtable.hpp> 27f18bf836SPatrick Venture #include <set> 28f18bf836SPatrick Venture #include <string> 29f18bf836SPatrick Venture #include <vector> 30a87c157cSDeepak Kodihalli 31a87c157cSDeepak Kodihalli using namespace phosphor::logging; 325f4247f0SAdriana Kobylak using namespace std::chrono; 33a87c157cSDeepak Kodihalli extern const std::map<metadata::Metadata, 34f18bf836SPatrick Venture std::function<metadata::associations::Type>> 35f18bf836SPatrick Venture meta; 361db1bd35SAdriana Kobylak 378f7941edSAdriana Kobylak namespace phosphor 388f7941edSAdriana Kobylak { 398f7941edSAdriana Kobylak namespace logging 408f7941edSAdriana Kobylak { 4105aae8bcSNagaraju Goruganti namespace internal 4205aae8bcSNagaraju Goruganti { 436fd9dc48SDeepak Kodihalli inline auto getLevel(const std::string& errMsg) 446fd9dc48SDeepak Kodihalli { 456fd9dc48SDeepak Kodihalli auto reqLevel = Entry::Level::Error; // Default to Error 466fd9dc48SDeepak Kodihalli 476fd9dc48SDeepak Kodihalli auto levelmap = g_errLevelMap.find(errMsg); 48f8a5a797SNagaraju Goruganti if (levelmap != g_errLevelMap.end()) 49f8a5a797SNagaraju Goruganti { 506fd9dc48SDeepak Kodihalli reqLevel = static_cast<Entry::Level>(levelmap->second); 51f8a5a797SNagaraju Goruganti } 52f8a5a797SNagaraju Goruganti 536fd9dc48SDeepak Kodihalli return reqLevel; 546fd9dc48SDeepak Kodihalli } 556fd9dc48SDeepak Kodihalli 56477b731aSNagaraju Goruganti int Manager::getRealErrSize() 57477b731aSNagaraju Goruganti { 58477b731aSNagaraju Goruganti return realErrors.size(); 59477b731aSNagaraju Goruganti } 60477b731aSNagaraju Goruganti 61477b731aSNagaraju Goruganti int Manager::getInfoErrSize() 62477b731aSNagaraju Goruganti { 63477b731aSNagaraju Goruganti return infoErrors.size(); 64477b731aSNagaraju Goruganti } 65477b731aSNagaraju Goruganti 666fd9dc48SDeepak Kodihalli void Manager::commit(uint64_t transactionId, std::string errMsg) 676fd9dc48SDeepak Kodihalli { 686fd9dc48SDeepak Kodihalli auto level = getLevel(errMsg); 696fd9dc48SDeepak Kodihalli _commit(transactionId, std::move(errMsg), level); 706fd9dc48SDeepak Kodihalli } 716fd9dc48SDeepak Kodihalli 726fd9dc48SDeepak Kodihalli void Manager::commitWithLvl(uint64_t transactionId, std::string errMsg, 736fd9dc48SDeepak Kodihalli uint32_t errLvl) 746fd9dc48SDeepak Kodihalli { 756fd9dc48SDeepak Kodihalli _commit(transactionId, std::move(errMsg), 766fd9dc48SDeepak Kodihalli static_cast<Entry::Level>(errLvl)); 776fd9dc48SDeepak Kodihalli } 786fd9dc48SDeepak Kodihalli 796fd9dc48SDeepak Kodihalli void Manager::_commit(uint64_t transactionId, std::string&& errMsg, 806fd9dc48SDeepak Kodihalli Entry::Level errLvl) 816fd9dc48SDeepak Kodihalli { 82*99c2b405SMatt Spinler if (!Extensions::disableDefaultLogCaps()) 83*99c2b405SMatt Spinler { 846fd9dc48SDeepak Kodihalli if (errLvl < Entry::sevLowerLimit) 85f8a5a797SNagaraju Goruganti { 86e4b0b771SNagaraju Goruganti if (realErrors.size() >= ERROR_CAP) 877656fba3SMarri Devender Rao { 88e4b0b771SNagaraju Goruganti erase(realErrors.front()); 897656fba3SMarri Devender Rao } 90f8a5a797SNagaraju Goruganti } 91f8a5a797SNagaraju Goruganti else 92f8a5a797SNagaraju Goruganti { 93f8a5a797SNagaraju Goruganti if (infoErrors.size() >= ERROR_INFO_CAP) 94f8a5a797SNagaraju Goruganti { 95f8a5a797SNagaraju Goruganti erase(infoErrors.front()); 96f8a5a797SNagaraju Goruganti } 97f8a5a797SNagaraju Goruganti } 98*99c2b405SMatt Spinler } 99*99c2b405SMatt Spinler 1007298dc23SAdriana Kobylak constexpr const auto transactionIdVar = "TRANSACTION_ID"; 10127c87d92SAdriana Kobylak // Length of 'TRANSACTION_ID' string. 10230047bf9SPatrick Venture constexpr const auto transactionIdVarSize = std::strlen(transactionIdVar); 10327c87d92SAdriana Kobylak // Length of 'TRANSACTION_ID=' string. 10427c87d92SAdriana Kobylak constexpr const auto transactionIdVarOffset = transactionIdVarSize + 1; 1051db1bd35SAdriana Kobylak 1065f4247f0SAdriana Kobylak // Flush all the pending log messages into the journal 1075f4247f0SAdriana Kobylak journalSync(); 108cfd9a7ddSAdriana Kobylak 109d311bc8dSAdriana Kobylak sd_journal* j = nullptr; 1108f7941edSAdriana Kobylak int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); 111d311bc8dSAdriana Kobylak if (rc < 0) 112d311bc8dSAdriana Kobylak { 113f18bf836SPatrick Venture logging::log<logging::level::ERR>( 114f18bf836SPatrick Venture "Failed to open journal", 115d311bc8dSAdriana Kobylak logging::entry("DESCRIPTION=%s", strerror(-rc))); 1168f7941edSAdriana Kobylak return; 117d311bc8dSAdriana Kobylak } 118d311bc8dSAdriana Kobylak 1197298dc23SAdriana Kobylak std::string transactionIdStr = std::to_string(transactionId); 120d722b3aaSAdriana Kobylak std::set<std::string> metalist; 121d722b3aaSAdriana Kobylak auto metamap = g_errMetaMap.find(errMsg); 122d722b3aaSAdriana Kobylak if (metamap != g_errMetaMap.end()) 123d722b3aaSAdriana Kobylak { 124d722b3aaSAdriana Kobylak metalist.insert(metamap->second.begin(), metamap->second.end()); 125d722b3aaSAdriana Kobylak } 1267298dc23SAdriana Kobylak 127db18ebe0SJayanth Othayoth // Add _PID field information in AdditionalData. 128db18ebe0SJayanth Othayoth metalist.insert("_PID"); 129db18ebe0SJayanth Othayoth 1307a33ee40STom Joseph std::vector<std::string> additionalData; 1319aa7d789SAdriana Kobylak 132d311bc8dSAdriana Kobylak // Read the journal from the end to get the most recent entry first. 133d311bc8dSAdriana Kobylak // The result from the sd_journal_get_data() is of the form VARIABLE=value. 134d311bc8dSAdriana Kobylak SD_JOURNAL_FOREACH_BACKWARDS(j) 135d311bc8dSAdriana Kobylak { 136d311bc8dSAdriana Kobylak const char* data = nullptr; 137d311bc8dSAdriana Kobylak size_t length = 0; 138d311bc8dSAdriana Kobylak 1397298dc23SAdriana Kobylak // Look for the transaction id metadata variable 1407298dc23SAdriana Kobylak rc = sd_journal_get_data(j, transactionIdVar, (const void**)&data, 1417298dc23SAdriana Kobylak &length); 142d311bc8dSAdriana Kobylak if (rc < 0) 143d311bc8dSAdriana Kobylak { 144fbe8872eSAdriana Kobylak // This journal entry does not have the TRANSACTION_ID 145fbe8872eSAdriana Kobylak // metadata variable. 146d311bc8dSAdriana Kobylak continue; 147d311bc8dSAdriana Kobylak } 1487298dc23SAdriana Kobylak 14927c87d92SAdriana Kobylak // journald does not guarantee that sd_journal_get_data() returns NULL 15027c87d92SAdriana Kobylak // terminated strings, so need to specify the size to use to compare, 15127c87d92SAdriana Kobylak // use the returned length instead of anything that relies on NULL 15227c87d92SAdriana Kobylak // terminators like strlen(). 15327c87d92SAdriana Kobylak // The data variable is in the form of 'TRANSACTION_ID=1234'. Remove 15427c87d92SAdriana Kobylak // the TRANSACTION_ID characters plus the (=) sign to do the comparison. 15527c87d92SAdriana Kobylak // 'data + transactionIdVarOffset' will be in the form of '1234'. 15627c87d92SAdriana Kobylak // 'length - transactionIdVarOffset' will be the length of '1234'. 15727c87d92SAdriana Kobylak if ((length <= (transactionIdVarOffset)) || 158f18bf836SPatrick Venture (transactionIdStr.compare(0, transactionIdStr.size(), 15927c87d92SAdriana Kobylak data + transactionIdVarOffset, 16027c87d92SAdriana Kobylak length - transactionIdVarOffset) != 0)) 161d311bc8dSAdriana Kobylak { 162fbe8872eSAdriana Kobylak // The value of the TRANSACTION_ID metadata is not the requested 163fbe8872eSAdriana Kobylak // transaction id number. 164d311bc8dSAdriana Kobylak continue; 165d311bc8dSAdriana Kobylak } 166d311bc8dSAdriana Kobylak 167fbe8872eSAdriana Kobylak // Search for all metadata variables in the current journal entry. 168fbe8872eSAdriana Kobylak for (auto i = metalist.cbegin(); i != metalist.cend();) 169fbe8872eSAdriana Kobylak { 170f18bf836SPatrick Venture rc = sd_journal_get_data(j, (*i).c_str(), (const void**)&data, 171f18bf836SPatrick Venture &length); 172fbe8872eSAdriana Kobylak if (rc < 0) 173fbe8872eSAdriana Kobylak { 174fbe8872eSAdriana Kobylak // Metadata variable not found, check next metadata variable. 175fbe8872eSAdriana Kobylak i++; 176fbe8872eSAdriana Kobylak continue; 177fbe8872eSAdriana Kobylak } 178fbe8872eSAdriana Kobylak 179fbe8872eSAdriana Kobylak // Metadata variable found, save it and remove it from the set. 180fbe8872eSAdriana Kobylak additionalData.emplace_back(data, length); 181fbe8872eSAdriana Kobylak i = metalist.erase(i); 182fbe8872eSAdriana Kobylak } 183fbe8872eSAdriana Kobylak if (metalist.empty()) 184fbe8872eSAdriana Kobylak { 185fbe8872eSAdriana Kobylak // All metadata variables found, break out of journal loop. 1869aa7d789SAdriana Kobylak break; 1879aa7d789SAdriana Kobylak } 188fbe8872eSAdriana Kobylak } 189fbe8872eSAdriana Kobylak if (!metalist.empty()) 190d311bc8dSAdriana Kobylak { 191fbe8872eSAdriana Kobylak // Not all the metadata variables were found in the journal. 192fbe8872eSAdriana Kobylak for (auto& metaVarStr : metalist) 193fbe8872eSAdriana Kobylak { 194f18bf836SPatrick Venture logging::log<logging::level::INFO>( 195f18bf836SPatrick Venture "Failed to find metadata", 1967298dc23SAdriana Kobylak logging::entry("META_FIELD=%s", metaVarStr.c_str())); 197d311bc8dSAdriana Kobylak } 198d311bc8dSAdriana Kobylak } 199d311bc8dSAdriana Kobylak 200d311bc8dSAdriana Kobylak sd_journal_close(j); 201d311bc8dSAdriana Kobylak 2024ea7f312SAdriana Kobylak // Create error Entry dbus object 2034ea7f312SAdriana Kobylak entryId++; 2046fd9dc48SDeepak Kodihalli if (errLvl >= Entry::sevLowerLimit) 205f8a5a797SNagaraju Goruganti { 206f8a5a797SNagaraju Goruganti infoErrors.push_back(entryId); 207f8a5a797SNagaraju Goruganti } 208e4b0b771SNagaraju Goruganti else 209e4b0b771SNagaraju Goruganti { 210e4b0b771SNagaraju Goruganti realErrors.push_back(entryId); 211e4b0b771SNagaraju Goruganti } 212c5f0bbd9SAdriana Kobylak auto ms = std::chrono::duration_cast<std::chrono::milliseconds>( 213f18bf836SPatrick Venture std::chrono::system_clock::now().time_since_epoch()) 214f18bf836SPatrick Venture .count(); 215f18bf836SPatrick Venture auto objPath = std::string(OBJ_ENTRY) + '/' + std::to_string(entryId); 216a87c157cSDeepak Kodihalli 21735b46379SDeepak Kodihalli AssociationList objects{}; 218a87c157cSDeepak Kodihalli processMetadata(errMsg, additionalData, objects); 219a87c157cSDeepak Kodihalli 220f18bf836SPatrick Venture auto e = std::make_unique<Entry>(busLog, objPath, entryId, 221c5f0bbd9SAdriana Kobylak ms, // Milliseconds since 1970 222f18bf836SPatrick Venture errLvl, std::move(errMsg), 22335b46379SDeepak Kodihalli std::move(additionalData), 224f18bf836SPatrick Venture std::move(objects), fwVersion, *this); 22572654f10SDeepak Kodihalli serialize(*e); 226*99c2b405SMatt Spinler 227*99c2b405SMatt Spinler doExtensionLogCreate(*e); 228*99c2b405SMatt Spinler 22972654f10SDeepak Kodihalli entries.insert(std::make_pair(entryId, std::move(e))); 2301db1bd35SAdriana Kobylak } 2311db1bd35SAdriana Kobylak 232*99c2b405SMatt Spinler void Manager::doExtensionLogCreate(const Entry& entry) 233*99c2b405SMatt Spinler { 234*99c2b405SMatt Spinler // Make the association <endpointpath>/<endpointtype> paths 235*99c2b405SMatt Spinler std::vector<std::string> assocs; 236*99c2b405SMatt Spinler for (const auto& [forwardType, reverseType, endpoint] : 237*99c2b405SMatt Spinler entry.associations()) 238*99c2b405SMatt Spinler { 239*99c2b405SMatt Spinler std::string e{endpoint}; 240*99c2b405SMatt Spinler e += '/' + reverseType; 241*99c2b405SMatt Spinler assocs.push_back(e); 242*99c2b405SMatt Spinler } 243*99c2b405SMatt Spinler 244*99c2b405SMatt Spinler for (auto& create : Extensions::getCreateFunctions()) 245*99c2b405SMatt Spinler { 246*99c2b405SMatt Spinler try 247*99c2b405SMatt Spinler { 248*99c2b405SMatt Spinler create(entry.message(), entry.id(), entry.timestamp(), 249*99c2b405SMatt Spinler entry.severity(), entry.additionalData(), assocs); 250*99c2b405SMatt Spinler } 251*99c2b405SMatt Spinler catch (std::exception& e) 252*99c2b405SMatt Spinler { 253*99c2b405SMatt Spinler log<level::ERR>("An extension's create function threw an exception", 254*99c2b405SMatt Spinler phosphor::logging::entry("ERROR=%s", e.what())); 255*99c2b405SMatt Spinler } 256*99c2b405SMatt Spinler } 257*99c2b405SMatt Spinler } 258*99c2b405SMatt Spinler 259a87c157cSDeepak Kodihalli void Manager::processMetadata(const std::string& errorName, 260a87c157cSDeepak Kodihalli const std::vector<std::string>& additionalData, 261a87c157cSDeepak Kodihalli AssociationList& objects) const 262a87c157cSDeepak Kodihalli { 263a87c157cSDeepak Kodihalli // additionalData is a list of "metadata=value" 264a87c157cSDeepak Kodihalli constexpr auto separator = '='; 26534438968SPatrick Venture for (const auto& entryItem : additionalData) 266a87c157cSDeepak Kodihalli { 26734438968SPatrick Venture auto found = entryItem.find(separator); 268a87c157cSDeepak Kodihalli if (std::string::npos != found) 269a87c157cSDeepak Kodihalli { 27034438968SPatrick Venture auto metadata = entryItem.substr(0, found); 271a87c157cSDeepak Kodihalli auto iter = meta.find(metadata); 272a87c157cSDeepak Kodihalli if (meta.end() != iter) 273a87c157cSDeepak Kodihalli { 274a87c157cSDeepak Kodihalli (iter->second)(metadata, additionalData, objects); 275a87c157cSDeepak Kodihalli } 276a87c157cSDeepak Kodihalli } 277a87c157cSDeepak Kodihalli } 278a87c157cSDeepak Kodihalli } 279a87c157cSDeepak Kodihalli 28099a8549eSDeepak Kodihalli void Manager::erase(uint32_t entryId) 28199a8549eSDeepak Kodihalli { 28234438968SPatrick Venture auto entryFound = entries.find(entryId); 28334438968SPatrick Venture if (entries.end() != entryFound) 28499a8549eSDeepak Kodihalli { 285*99c2b405SMatt Spinler for (auto& func : Extensions::getDeleteProhibitedFunctions()) 286*99c2b405SMatt Spinler { 287*99c2b405SMatt Spinler try 288*99c2b405SMatt Spinler { 289*99c2b405SMatt Spinler bool prohibited = false; 290*99c2b405SMatt Spinler func(entryId, prohibited); 291*99c2b405SMatt Spinler if (prohibited) 292*99c2b405SMatt Spinler { 293*99c2b405SMatt Spinler // Future work remains to throw an error here. 294*99c2b405SMatt Spinler return; 295*99c2b405SMatt Spinler } 296*99c2b405SMatt Spinler } 297*99c2b405SMatt Spinler catch (std::exception& e) 298*99c2b405SMatt Spinler { 299*99c2b405SMatt Spinler log<level::ERR>( 300*99c2b405SMatt Spinler "An extension's deleteProhibited function threw " 301*99c2b405SMatt Spinler "an exception", 302*99c2b405SMatt Spinler entry("ERROR=%s", e.what())); 303*99c2b405SMatt Spinler } 304*99c2b405SMatt Spinler } 305*99c2b405SMatt Spinler 3063388799dSDeepak Kodihalli // Delete the persistent representation of this error. 3073388799dSDeepak Kodihalli fs::path errorPath(ERRLOG_PERSIST_PATH); 3088959efcbSMarri Devender Rao errorPath /= std::to_string(entryId); 3093388799dSDeepak Kodihalli fs::remove(errorPath); 310e4b0b771SNagaraju Goruganti 311f18bf836SPatrick Venture auto removeId = [](std::list<uint32_t>& ids, uint32_t id) { 312e4b0b771SNagaraju Goruganti auto it = std::find(ids.begin(), ids.end(), id); 313e4b0b771SNagaraju Goruganti if (it != ids.end()) 314e4b0b771SNagaraju Goruganti { 315e4b0b771SNagaraju Goruganti ids.erase(it); 316e4b0b771SNagaraju Goruganti } 317e4b0b771SNagaraju Goruganti }; 31834438968SPatrick Venture if (entryFound->second->severity() >= Entry::sevLowerLimit) 319f8a5a797SNagaraju Goruganti { 320e4b0b771SNagaraju Goruganti removeId(infoErrors, entryId); 321f8a5a797SNagaraju Goruganti } 322e4b0b771SNagaraju Goruganti else 323e4b0b771SNagaraju Goruganti { 324e4b0b771SNagaraju Goruganti removeId(realErrors, entryId); 325f8a5a797SNagaraju Goruganti } 32634438968SPatrick Venture entries.erase(entryFound); 327*99c2b405SMatt Spinler 328*99c2b405SMatt Spinler for (auto& remove : Extensions::getDeleteFunctions()) 329*99c2b405SMatt Spinler { 330*99c2b405SMatt Spinler try 331*99c2b405SMatt Spinler { 332*99c2b405SMatt Spinler remove(entryId); 333*99c2b405SMatt Spinler } 334*99c2b405SMatt Spinler catch (std::exception& e) 335*99c2b405SMatt Spinler { 336*99c2b405SMatt Spinler log<level::ERR>("An extension's delete function threw an " 337*99c2b405SMatt Spinler "exception", 338*99c2b405SMatt Spinler entry("ERROR=%s", e.what())); 339*99c2b405SMatt Spinler } 340*99c2b405SMatt Spinler } 34199a8549eSDeepak Kodihalli } 3428959efcbSMarri Devender Rao else 3438959efcbSMarri Devender Rao { 3448959efcbSMarri Devender Rao logging::log<level::ERR>("Invalid entry ID to delete", 3458959efcbSMarri Devender Rao logging::entry("ID=%d", entryId)); 3468959efcbSMarri Devender Rao } 34799a8549eSDeepak Kodihalli } 34899a8549eSDeepak Kodihalli 34972654f10SDeepak Kodihalli void Manager::restore() 35072654f10SDeepak Kodihalli { 351f18bf836SPatrick Venture auto sanity = [](const auto& id, const auto& restoredId) { 352979ed1ccSMarri Devender Rao return id == restoredId; 353979ed1ccSMarri Devender Rao }; 35472654f10SDeepak Kodihalli std::vector<uint32_t> errorIds; 35572654f10SDeepak Kodihalli 35672654f10SDeepak Kodihalli fs::path dir(ERRLOG_PERSIST_PATH); 35772654f10SDeepak Kodihalli if (!fs::exists(dir) || fs::is_empty(dir)) 35872654f10SDeepak Kodihalli { 35972654f10SDeepak Kodihalli return; 36072654f10SDeepak Kodihalli } 36172654f10SDeepak Kodihalli 36272654f10SDeepak Kodihalli for (auto& file : fs::directory_iterator(dir)) 36372654f10SDeepak Kodihalli { 36472654f10SDeepak Kodihalli auto id = file.path().filename().c_str(); 36572654f10SDeepak Kodihalli auto idNum = std::stol(id); 36672654f10SDeepak Kodihalli auto e = std::make_unique<Entry>( 367f18bf836SPatrick Venture busLog, std::string(OBJ_ENTRY) + '/' + id, idNum, *this); 36872654f10SDeepak Kodihalli if (deserialize(file.path(), *e)) 36972654f10SDeepak Kodihalli { 370979ed1ccSMarri Devender Rao // validate the restored error entry id 371979ed1ccSMarri Devender Rao if (sanity(static_cast<uint32_t>(idNum), e->id())) 372979ed1ccSMarri Devender Rao { 37372654f10SDeepak Kodihalli e->emit_object_added(); 374f8a5a797SNagaraju Goruganti if (e->severity() >= Entry::sevLowerLimit) 375f8a5a797SNagaraju Goruganti { 376f8a5a797SNagaraju Goruganti infoErrors.push_back(idNum); 377f8a5a797SNagaraju Goruganti } 378e4b0b771SNagaraju Goruganti else 379e4b0b771SNagaraju Goruganti { 380e4b0b771SNagaraju Goruganti realErrors.push_back(idNum); 381e4b0b771SNagaraju Goruganti } 382979ed1ccSMarri Devender Rao 38372654f10SDeepak Kodihalli entries.insert(std::make_pair(idNum, std::move(e))); 38472654f10SDeepak Kodihalli errorIds.push_back(idNum); 38572654f10SDeepak Kodihalli } 386979ed1ccSMarri Devender Rao else 387979ed1ccSMarri Devender Rao { 388979ed1ccSMarri Devender Rao logging::log<logging::level::ERR>( 389979ed1ccSMarri Devender Rao "Failed in sanity check while restoring error entry. " 390979ed1ccSMarri Devender Rao "Ignoring error entry", 391979ed1ccSMarri Devender Rao logging::entry("ID_NUM=%d", idNum), 392979ed1ccSMarri Devender Rao logging::entry("ENTRY_ID=%d", e->id())); 393979ed1ccSMarri Devender Rao } 394979ed1ccSMarri Devender Rao } 39572654f10SDeepak Kodihalli } 39672654f10SDeepak Kodihalli 39737af9bacSVishwanatha Subbanna if (!errorIds.empty()) 39837af9bacSVishwanatha Subbanna { 39972654f10SDeepak Kodihalli entryId = *(std::max_element(errorIds.begin(), errorIds.end())); 40072654f10SDeepak Kodihalli } 40137af9bacSVishwanatha Subbanna } 40272654f10SDeepak Kodihalli 4035f4247f0SAdriana Kobylak void Manager::journalSync() 4045f4247f0SAdriana Kobylak { 4055f4247f0SAdriana Kobylak bool syncRequested = false; 4065f4247f0SAdriana Kobylak auto fd = -1; 4075f4247f0SAdriana Kobylak auto rc = -1; 4085f4247f0SAdriana Kobylak auto wd = -1; 4095f4247f0SAdriana Kobylak auto bus = sdbusplus::bus::new_default(); 4105f4247f0SAdriana Kobylak 4115f4247f0SAdriana Kobylak auto start = 4125f4247f0SAdriana Kobylak duration_cast<microseconds>(steady_clock::now().time_since_epoch()) 4135f4247f0SAdriana Kobylak .count(); 4145f4247f0SAdriana Kobylak 4155f4247f0SAdriana Kobylak constexpr auto maxRetry = 2; 4165f4247f0SAdriana Kobylak for (int i = 0; i < maxRetry; i++) 4175f4247f0SAdriana Kobylak { 4185f4247f0SAdriana Kobylak // Read timestamp from synced file 4195f4247f0SAdriana Kobylak constexpr auto syncedPath = "/run/systemd/journal/synced"; 4205f4247f0SAdriana Kobylak std::ifstream syncedFile(syncedPath); 4215f4247f0SAdriana Kobylak if (syncedFile.fail()) 4225f4247f0SAdriana Kobylak { 4237d111a85SAdriana Kobylak // If the synced file doesn't exist, a sync request will create it. 4247d111a85SAdriana Kobylak if (errno != ENOENT) 4257d111a85SAdriana Kobylak { 4265f4247f0SAdriana Kobylak log<level::ERR>("Failed to open journal synced file", 4275f4247f0SAdriana Kobylak entry("FILENAME=%s", syncedPath), 4285f4247f0SAdriana Kobylak entry("ERRNO=%d", errno)); 4295f4247f0SAdriana Kobylak return; 4305f4247f0SAdriana Kobylak } 4317d111a85SAdriana Kobylak } 4327d111a85SAdriana Kobylak else 4337d111a85SAdriana Kobylak { 4347d111a85SAdriana Kobylak // Only read the synced file if it exists. 4355f4247f0SAdriana Kobylak // See if a sync happened by now 4365f4247f0SAdriana Kobylak std::string timestampStr; 4375f4247f0SAdriana Kobylak std::getline(syncedFile, timestampStr); 43830047bf9SPatrick Venture auto timestamp = std::stoll(timestampStr); 4395f4247f0SAdriana Kobylak if (timestamp >= start) 4405f4247f0SAdriana Kobylak { 4415f4247f0SAdriana Kobylak return; 4425f4247f0SAdriana Kobylak } 4437d111a85SAdriana Kobylak } 4445f4247f0SAdriana Kobylak 4455f4247f0SAdriana Kobylak // Let's ask for a sync, but only once 4465f4247f0SAdriana Kobylak if (!syncRequested) 4475f4247f0SAdriana Kobylak { 4485f4247f0SAdriana Kobylak syncRequested = true; 4495f4247f0SAdriana Kobylak 4505f4247f0SAdriana Kobylak constexpr auto JOURNAL_UNIT = "systemd-journald.service"; 4515f4247f0SAdriana Kobylak auto signal = SIGRTMIN + 1; 4525f4247f0SAdriana Kobylak 4535f4247f0SAdriana Kobylak auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 4545f4247f0SAdriana Kobylak SYSTEMD_INTERFACE, "KillUnit"); 4555f4247f0SAdriana Kobylak method.append(JOURNAL_UNIT, "main", signal); 4565f4247f0SAdriana Kobylak bus.call(method); 4575f4247f0SAdriana Kobylak if (method.is_method_error()) 4585f4247f0SAdriana Kobylak { 4595f4247f0SAdriana Kobylak log<level::ERR>("Failed to kill journal service"); 4605f4247f0SAdriana Kobylak return; 4615f4247f0SAdriana Kobylak } 4625f4247f0SAdriana Kobylak continue; 4635f4247f0SAdriana Kobylak } 4645f4247f0SAdriana Kobylak 4655f4247f0SAdriana Kobylak // Let's install the inotify watch, if we didn't do that yet. This watch 4665f4247f0SAdriana Kobylak // monitors the syncedFile for when journald updates it with a newer 4675f4247f0SAdriana Kobylak // timestamp. This means the journal has been flushed. 4685f4247f0SAdriana Kobylak if (fd < 0) 4695f4247f0SAdriana Kobylak { 4705f4247f0SAdriana Kobylak fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); 4715f4247f0SAdriana Kobylak if (fd < 0) 4725f4247f0SAdriana Kobylak { 4735f4247f0SAdriana Kobylak log<level::ERR>("Failed to create inotify watch", 4745f4247f0SAdriana Kobylak entry("ERRNO=%d", errno)); 4755f4247f0SAdriana Kobylak return; 4765f4247f0SAdriana Kobylak } 4775f4247f0SAdriana Kobylak 4785f4247f0SAdriana Kobylak constexpr auto JOURNAL_RUN_PATH = "/run/systemd/journal"; 4795f4247f0SAdriana Kobylak wd = inotify_add_watch(fd, JOURNAL_RUN_PATH, 4805f4247f0SAdriana Kobylak IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR); 4815f4247f0SAdriana Kobylak if (wd < 0) 4825f4247f0SAdriana Kobylak { 4835f4247f0SAdriana Kobylak log<level::ERR>("Failed to watch journal directory", 4845f4247f0SAdriana Kobylak entry("PATH=%s", JOURNAL_RUN_PATH), 4855f4247f0SAdriana Kobylak entry("ERRNO=%d", errno)); 4865f4247f0SAdriana Kobylak close(fd); 4875f4247f0SAdriana Kobylak return; 4885f4247f0SAdriana Kobylak } 4895f4247f0SAdriana Kobylak continue; 4905f4247f0SAdriana Kobylak } 4915f4247f0SAdriana Kobylak 4925f4247f0SAdriana Kobylak // Let's wait until inotify reports an event 4935f4247f0SAdriana Kobylak struct pollfd fds = { 4945f4247f0SAdriana Kobylak .fd = fd, 4955f4247f0SAdriana Kobylak .events = POLLIN, 4965f4247f0SAdriana Kobylak }; 4975f4247f0SAdriana Kobylak constexpr auto pollTimeout = 5; // 5 seconds 4985f4247f0SAdriana Kobylak rc = poll(&fds, 1, pollTimeout * 1000); 4995f4247f0SAdriana Kobylak if (rc < 0) 5005f4247f0SAdriana Kobylak { 5015f4247f0SAdriana Kobylak log<level::ERR>("Failed to add event", entry("ERRNO=%d", errno), 5025f4247f0SAdriana Kobylak entry("ERR=%s", strerror(-rc))); 5035f4247f0SAdriana Kobylak inotify_rm_watch(fd, wd); 5045f4247f0SAdriana Kobylak close(fd); 5055f4247f0SAdriana Kobylak return; 5065f4247f0SAdriana Kobylak } 5075f4247f0SAdriana Kobylak else if (rc == 0) 5085f4247f0SAdriana Kobylak { 5095f4247f0SAdriana Kobylak log<level::INFO>("Poll timeout, no new journal synced data", 5105f4247f0SAdriana Kobylak entry("TIMEOUT=%d", pollTimeout)); 5115f4247f0SAdriana Kobylak break; 5125f4247f0SAdriana Kobylak } 5135f4247f0SAdriana Kobylak 5145f4247f0SAdriana Kobylak // Read from the specified file descriptor until there is no new data, 5155f4247f0SAdriana Kobylak // throwing away everything read since the timestamp will be read at the 5165f4247f0SAdriana Kobylak // beginning of the loop. 5175f4247f0SAdriana Kobylak constexpr auto maxBytes = 64; 5185f4247f0SAdriana Kobylak uint8_t buffer[maxBytes]; 5195f4247f0SAdriana Kobylak while (read(fd, buffer, maxBytes) > 0) 5205f4247f0SAdriana Kobylak ; 5215f4247f0SAdriana Kobylak } 5225f4247f0SAdriana Kobylak 5234a029f2fSAdriana Kobylak if (fd != -1) 5244a029f2fSAdriana Kobylak { 5254a029f2fSAdriana Kobylak if (wd != -1) 5265f4247f0SAdriana Kobylak { 5275f4247f0SAdriana Kobylak inotify_rm_watch(fd, wd); 5284a029f2fSAdriana Kobylak } 5295f4247f0SAdriana Kobylak close(fd); 5305f4247f0SAdriana Kobylak } 5315f4247f0SAdriana Kobylak 5325f4247f0SAdriana Kobylak return; 5335f4247f0SAdriana Kobylak } 5345f4247f0SAdriana Kobylak 5351275bd13SMatt Spinler std::string Manager::readFWVersion() 5361275bd13SMatt Spinler { 5371275bd13SMatt Spinler std::string version; 5381275bd13SMatt Spinler std::ifstream versionFile{BMC_VERSION_FILE}; 5391275bd13SMatt Spinler std::string line; 5401275bd13SMatt Spinler static constexpr auto VERSION_ID = "VERSION_ID="; 5411275bd13SMatt Spinler 5421275bd13SMatt Spinler while (std::getline(versionFile, line)) 5431275bd13SMatt Spinler { 5441275bd13SMatt Spinler if (line.find(VERSION_ID) != std::string::npos) 5451275bd13SMatt Spinler { 5461275bd13SMatt Spinler auto pos = line.find_first_of('"') + 1; 5471275bd13SMatt Spinler version = line.substr(pos, line.find_last_of('"') - pos); 5481275bd13SMatt Spinler break; 5491275bd13SMatt Spinler } 5501275bd13SMatt Spinler } 5511275bd13SMatt Spinler 5521275bd13SMatt Spinler if (version.empty()) 5531275bd13SMatt Spinler { 5541275bd13SMatt Spinler log<level::ERR>("Unable to read BMC firmware version"); 5551275bd13SMatt Spinler } 5561275bd13SMatt Spinler 5571275bd13SMatt Spinler return version; 5581275bd13SMatt Spinler } 5591275bd13SMatt Spinler 56005aae8bcSNagaraju Goruganti } // namespace internal 5618f7941edSAdriana Kobylak } // namespace logging 562f18bf836SPatrick Venture } // namespace phosphor 563