| Matt Spinler | 711d51d | 2019-11-06 09:36:51 -0600 | [diff] [blame] | 1 | /** | 
|  | 2 | * Copyright © 2019 IBM Corporation | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
| Matt Spinler | df13bdb | 2019-07-10 16:54:13 -0500 | [diff] [blame] | 16 | #include "log_id.hpp" | 
|  | 17 |  | 
|  | 18 | #include "paths.hpp" | 
|  | 19 |  | 
|  | 20 | #include <chrono> | 
|  | 21 | #include <filesystem> | 
|  | 22 | #include <fstream> | 
|  | 23 | #include <phosphor-logging/log.hpp> | 
|  | 24 |  | 
|  | 25 | namespace openpower | 
|  | 26 | { | 
|  | 27 | namespace pels | 
|  | 28 | { | 
|  | 29 |  | 
|  | 30 | namespace fs = std::filesystem; | 
|  | 31 | using namespace phosphor::logging; | 
|  | 32 |  | 
|  | 33 | constexpr uint32_t startingLogID = 1; | 
|  | 34 | constexpr uint32_t bmcLogIDPrefix = 0x50000000; | 
|  | 35 |  | 
|  | 36 | namespace detail | 
|  | 37 | { | 
|  | 38 |  | 
|  | 39 | uint32_t addLogIDPrefix(uint32_t id) | 
|  | 40 | { | 
|  | 41 | // If redundant BMCs are ever a thing, may need a different prefix. | 
|  | 42 | return (id & 0x00FFFFFF) | bmcLogIDPrefix; | 
|  | 43 | } | 
|  | 44 |  | 
|  | 45 | uint32_t getTimeBasedLogID() | 
|  | 46 | { | 
|  | 47 | using namespace std::chrono; | 
|  | 48 |  | 
|  | 49 | // Use 3 bytes of the nanosecond count since the epoch. | 
|  | 50 | uint32_t id = | 
|  | 51 | duration_cast<nanoseconds>(system_clock::now().time_since_epoch()) | 
|  | 52 | .count(); | 
|  | 53 |  | 
|  | 54 | return addLogIDPrefix(id); | 
|  | 55 | } | 
|  | 56 |  | 
|  | 57 | } // namespace detail | 
|  | 58 |  | 
|  | 59 | uint32_t generatePELID() | 
|  | 60 | { | 
|  | 61 | // Note: there isn't a need to be thread safe. | 
|  | 62 |  | 
|  | 63 | static std::string idFilename; | 
|  | 64 | if (idFilename.empty()) | 
|  | 65 | { | 
|  | 66 | idFilename = getPELIDFile(); | 
| Sumit Kumar | f380c51 | 2021-11-19 06:07:31 -0600 | [diff] [blame] | 67 | checkFileForZeroData(idFilename); | 
| Matt Spinler | df13bdb | 2019-07-10 16:54:13 -0500 | [diff] [blame] | 68 | } | 
|  | 69 |  | 
|  | 70 | uint32_t id = 0; | 
|  | 71 |  | 
|  | 72 | if (!fs::exists(idFilename)) | 
|  | 73 | { | 
|  | 74 | auto path = fs::path(idFilename).parent_path(); | 
|  | 75 | if (!fs::exists(path)) | 
|  | 76 | { | 
|  | 77 | fs::create_directories(path); | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | id = startingLogID; | 
|  | 81 | } | 
|  | 82 | else | 
|  | 83 | { | 
|  | 84 | std::ifstream idFile{idFilename}; | 
|  | 85 | idFile >> id; | 
|  | 86 | if (idFile.fail()) | 
|  | 87 | { | 
|  | 88 | // Just make up an ID | 
|  | 89 | log<level::ERR>("Unable to read PEL ID File!"); | 
|  | 90 | return detail::getTimeBasedLogID(); | 
|  | 91 | } | 
|  | 92 | } | 
|  | 93 |  | 
|  | 94 | // Wrapping shouldn't be a problem, but check anyway | 
|  | 95 | if (id == 0x00FFFFFF) | 
|  | 96 | { | 
|  | 97 | id = startingLogID; | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | std::ofstream idFile{idFilename}; | 
|  | 101 | idFile << (id + 1); | 
|  | 102 | if (idFile.fail()) | 
|  | 103 | { | 
|  | 104 | // Just make up an ID so we don't reuse one next time | 
|  | 105 | log<level::ERR>("Unable to write PEL ID File!"); | 
|  | 106 | return detail::getTimeBasedLogID(); | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | return detail::addLogIDPrefix(id); | 
|  | 110 | } | 
|  | 111 |  | 
| Sumit Kumar | f380c51 | 2021-11-19 06:07:31 -0600 | [diff] [blame] | 112 | void checkFileForZeroData(const std::string& filename) | 
|  | 113 | { | 
|  | 114 | if (fs::exists(filename)) | 
|  | 115 | { | 
|  | 116 | char ch; | 
|  | 117 |  | 
|  | 118 | std::ifstream rf{filename, std::ios::binary}; | 
|  | 119 | rf.read(&ch, sizeof(ch)); | 
|  | 120 | while (ch == '\0') | 
|  | 121 | { | 
|  | 122 | if (rf.eof()) | 
|  | 123 | { | 
|  | 124 | fs::remove(filename); | 
|  | 125 | log<level::WARNING>( | 
|  | 126 | "PEL ID file seems corrupted. Deleting it."); | 
|  | 127 | break; | 
|  | 128 | } | 
|  | 129 | rf.read(&ch, sizeof(ch)); | 
|  | 130 | } | 
|  | 131 | } | 
|  | 132 | } | 
| Matt Spinler | df13bdb | 2019-07-10 16:54:13 -0500 | [diff] [blame] | 133 | } // namespace pels | 
|  | 134 | } // namespace openpower |