1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation 3 4 #include "log_id.hpp" 5 6 #include "paths.hpp" 7 8 #include <phosphor-logging/lg2.hpp> 9 10 #include <chrono> 11 #include <filesystem> 12 #include <fstream> 13 14 namespace openpower 15 { 16 namespace pels 17 { 18 19 namespace fs = std::filesystem; 20 21 constexpr uint32_t startingLogID = 1; 22 constexpr uint32_t bmcLogIDPrefix = 0x50000000; 23 24 namespace detail 25 { 26 addLogIDPrefix(uint32_t id)27uint32_t addLogIDPrefix(uint32_t id) 28 { 29 // If redundant BMCs are ever a thing, may need a different prefix. 30 return (id & 0x00FFFFFF) | bmcLogIDPrefix; 31 } 32 getTimeBasedLogID()33uint32_t getTimeBasedLogID() 34 { 35 using namespace std::chrono; 36 37 // Use 3 bytes of the nanosecond count since the epoch. 38 uint32_t id = 39 duration_cast<nanoseconds>(system_clock::now().time_since_epoch()) 40 .count(); 41 42 return addLogIDPrefix(id); 43 } 44 45 } // namespace detail 46 generatePELID()47uint32_t generatePELID() 48 { 49 // Note: there isn't a need to be thread safe. 50 51 static std::string idFilename; 52 if (idFilename.empty()) 53 { 54 idFilename = getPELIDFile(); 55 checkFileForZeroData(idFilename); 56 } 57 58 uint32_t id = 0; 59 60 if (!fs::exists(idFilename)) 61 { 62 auto path = fs::path(idFilename).parent_path(); 63 if (!fs::exists(path)) 64 { 65 fs::create_directories(path); 66 } 67 68 id = startingLogID; 69 } 70 else 71 { 72 std::ifstream idFile{idFilename}; 73 idFile >> id; 74 if (idFile.fail()) 75 { 76 // Just make up an ID 77 lg2::error("Unable to read PEL ID File!"); 78 return detail::getTimeBasedLogID(); 79 } 80 } 81 82 // Wrapping shouldn't be a problem, but check anyway 83 if (id == 0x00FFFFFF) 84 { 85 id = startingLogID; 86 } 87 88 std::ofstream idFile{idFilename}; 89 idFile << (id + 1); 90 if (idFile.fail()) 91 { 92 // Just make up an ID so we don't reuse one next time 93 lg2::error("Unable to write PEL ID File!"); 94 return detail::getTimeBasedLogID(); 95 } 96 97 return detail::addLogIDPrefix(id); 98 } 99 checkFileForZeroData(const std::string & filename)100void checkFileForZeroData(const std::string& filename) 101 { 102 if (fs::exists(filename)) 103 { 104 char ch; 105 106 std::ifstream rf{filename, std::ios::binary}; 107 rf.read(&ch, sizeof(ch)); 108 while (ch == '\0') 109 { 110 if (rf.eof()) 111 { 112 fs::remove(filename); 113 lg2::warning("PEL ID file seems corrupted. Deleting it."); 114 break; 115 } 116 rf.read(&ch, sizeof(ch)); 117 } 118 } 119 } 120 } // namespace pels 121 } // namespace openpower 122