Fix loading json file causing coredump
If the json file is damaged, when the process is running and
deserializing, a coredump will occur and a cereal::RapidJSONException
will be thrown.
Error message:
```
terminate called after throwing an instance of'cereal::RapidJSONException'
what(): rapidjson internal assertion failure: IsObject()
```
Add try-catch to catch the exception, and when the exception occurs,
we need to re-serialize the json file and record the log.
Tested: Use broken json file and restart the process
hosphor-srvcfg-manager[753]: Failed to load json file, need to rewrite,
ERROR = rapidjson internal assertion failure: IsObject(),
file path = /etc/srvcfg-mgr.json
Also, we can seen a bad json file in `/tmp`, like this:
/tmp/srvcfg-mgr.json.bad
Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I996e9e32f87c25d584a3b5912334d1a137b55b6c
diff --git a/src/main.cpp b/src/main.cpp
index 5723de2..2d7a4b0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -31,6 +31,7 @@
static bool unitQueryStarted = false;
static constexpr const char* srvCfgMgrFile = "/etc/srvcfg-mgr.json";
+static constexpr const char* tmpFileBad = "/tmp/srvcfg-mgr.json.bad";
// Base service name list. All instance of these services and
// units(service/socket) will be managed by this daemon.
@@ -158,26 +159,51 @@
bool jsonExist = std::filesystem::exists(srvCfgMgrFile);
if (jsonExist)
{
- std::ifstream file(srvCfgMgrFile);
- cereal::JSONInputArchive archive(file);
- MonitorListMap savedMonitorList;
- archive(savedMonitorList);
-
- // compare the unit list read from systemd1 and the save list.
- MonitorListMap diffMap;
- std::set_difference(begin(unitsToMonitor), end(unitsToMonitor),
- begin(savedMonitorList), end(savedMonitorList),
- std::inserter(diffMap, begin(diffMap)));
- for (auto& unitIt : diffMap)
+ try
{
- auto it = savedMonitorList.find(unitIt.first);
- if (it == savedMonitorList.end())
+ std::ifstream file(srvCfgMgrFile);
+ cereal::JSONInputArchive archive(file);
+ MonitorListMap savedMonitorList;
+ archive(savedMonitorList);
+
+ // compare the unit list read from systemd1 and the save list.
+ MonitorListMap diffMap;
+ std::set_difference(begin(unitsToMonitor), end(unitsToMonitor),
+ begin(savedMonitorList), end(savedMonitorList),
+ std::inserter(diffMap, begin(diffMap)));
+ for (auto& unitIt : diffMap)
{
- savedMonitorList.insert(unitIt);
- updateRequired = true;
+ auto it = savedMonitorList.find(unitIt.first);
+ if (it == savedMonitorList.end())
+ {
+ savedMonitorList.insert(unitIt);
+ updateRequired = true;
+ }
}
+ unitsToMonitor = savedMonitorList;
}
- unitsToMonitor = savedMonitorList;
+ catch (const std::exception& e)
+ {
+ lg2::error(
+ "Failed to load {FILEPATH} file, need to rewrite: {ERROR}.",
+ "FILEPATH", srvCfgMgrFile, "ERROR", e);
+
+ // The "bad" files need to be moved to /tmp/ so that we can try to
+ // find out the cause of the file corruption. If we encounter this
+ // failure multiple times, we will only overwrite it to ensure that
+ // we don't accidentally fill up /tmp/.
+ std::error_code ec;
+ std::filesystem::copy_file(
+ srvCfgMgrFile, tmpFileBad,
+ std::filesystem::copy_options::overwrite_existing, ec);
+ if (ec)
+ {
+ lg2::error("Failed to copy {SRCFILE} file to {DSTFILE}.",
+ "SRCFILE", srvCfgMgrFile, "DSTFILE", tmpFileBad);
+ }
+
+ updateRequired = true;
+ }
}
if (!jsonExist || updateRequired)
{