blob: ea00ef36c3dec86a4b5ce1e8a89f17b0289827ab [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
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 Spinlerdf13bdb2019-07-10 16:54:13 -050016#include "log_id.hpp"
17
18#include "paths.hpp"
19
Patrick Williams2544b412022-10-04 08:41:06 -050020#include <phosphor-logging/log.hpp>
21
Matt Spinlerdf13bdb2019-07-10 16:54:13 -050022#include <chrono>
23#include <filesystem>
24#include <fstream>
Matt Spinlerdf13bdb2019-07-10 16:54:13 -050025
26namespace openpower
27{
28namespace pels
29{
30
31namespace fs = std::filesystem;
32using namespace phosphor::logging;
33
34constexpr uint32_t startingLogID = 1;
35constexpr uint32_t bmcLogIDPrefix = 0x50000000;
36
37namespace detail
38{
39
40uint32_t addLogIDPrefix(uint32_t id)
41{
42 // If redundant BMCs are ever a thing, may need a different prefix.
43 return (id & 0x00FFFFFF) | bmcLogIDPrefix;
44}
45
46uint32_t getTimeBasedLogID()
47{
48 using namespace std::chrono;
49
50 // Use 3 bytes of the nanosecond count since the epoch.
51 uint32_t id =
52 duration_cast<nanoseconds>(system_clock::now().time_since_epoch())
53 .count();
54
55 return addLogIDPrefix(id);
56}
57
58} // namespace detail
59
60uint32_t generatePELID()
61{
62 // Note: there isn't a need to be thread safe.
63
64 static std::string idFilename;
65 if (idFilename.empty())
66 {
67 idFilename = getPELIDFile();
Sumit Kumarf380c512021-11-19 06:07:31 -060068 checkFileForZeroData(idFilename);
Matt Spinlerdf13bdb2019-07-10 16:54:13 -050069 }
70
71 uint32_t id = 0;
72
73 if (!fs::exists(idFilename))
74 {
75 auto path = fs::path(idFilename).parent_path();
76 if (!fs::exists(path))
77 {
78 fs::create_directories(path);
79 }
80
81 id = startingLogID;
82 }
83 else
84 {
85 std::ifstream idFile{idFilename};
86 idFile >> id;
87 if (idFile.fail())
88 {
89 // Just make up an ID
90 log<level::ERR>("Unable to read PEL ID File!");
91 return detail::getTimeBasedLogID();
92 }
93 }
94
95 // Wrapping shouldn't be a problem, but check anyway
96 if (id == 0x00FFFFFF)
97 {
98 id = startingLogID;
99 }
100
101 std::ofstream idFile{idFilename};
102 idFile << (id + 1);
103 if (idFile.fail())
104 {
105 // Just make up an ID so we don't reuse one next time
106 log<level::ERR>("Unable to write PEL ID File!");
107 return detail::getTimeBasedLogID();
108 }
109
110 return detail::addLogIDPrefix(id);
111}
112
Sumit Kumarf380c512021-11-19 06:07:31 -0600113void checkFileForZeroData(const std::string& filename)
114{
115 if (fs::exists(filename))
116 {
117 char ch;
118
119 std::ifstream rf{filename, std::ios::binary};
120 rf.read(&ch, sizeof(ch));
121 while (ch == '\0')
122 {
123 if (rf.eof())
124 {
125 fs::remove(filename);
126 log<level::WARNING>(
127 "PEL ID file seems corrupted. Deleting it.");
128 break;
129 }
130 rf.read(&ch, sizeof(ch));
131 }
132 }
133}
Matt Spinlerdf13bdb2019-07-10 16:54:13 -0500134} // namespace pels
135} // namespace openpower