blob: ee215c239611a3b2eb46bd74c05bbb05848709f8 [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
20#include <chrono>
21#include <filesystem>
22#include <fstream>
23#include <phosphor-logging/log.hpp>
24
25namespace openpower
26{
27namespace pels
28{
29
30namespace fs = std::filesystem;
31using namespace phosphor::logging;
32
33constexpr uint32_t startingLogID = 1;
34constexpr uint32_t bmcLogIDPrefix = 0x50000000;
35
36namespace detail
37{
38
39uint32_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
45uint32_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
59uint32_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 Kumarf380c512021-11-19 06:07:31 -060067 checkFileForZeroData(idFilename);
Matt Spinlerdf13bdb2019-07-10 16:54:13 -050068 }
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 Kumarf380c512021-11-19 06:07:31 -0600112void 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 Spinlerdf13bdb2019-07-10 16:54:13 -0500133} // namespace pels
134} // namespace openpower