/*
- * Copyright (c) 2019-2022 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2019-2023 Samsung Electronics Co., Ltd. All rights reserved.
*
* This file is licensed under the terms of MIT License or the Apache License
* Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details.
// For database placed in "$f" the filename is ("$f" DB_RECOVERED_SUFFIX).
#define DB_RECOVERED_SUFFIX "-recovered"
#define DB_JOURNAL_SUFFIX "-journal"
+#define DB_FAILED_COPY_SUFFIX "-failed"
#define DB_OK_MARKER "/tmp/.security-manager.db.ok"
if (unlikely(SQLITE_OK != sqlite3_close(db)))
fail("closing db failed");
+ // WARNING: dbPath memory has been made invalid due to tzplatform_mkpath* using a shared scratch buffer
+ // restore dbPath (now points to the copy stored in pkgsInfo)
+ pkgsInfo.t[dbPathLen] = '\0';
+ dbPath = pkgsInfo.t;
+
+ // copy the failed DB to proper path for further investigation
+ // this operation can fail for any reason - but it should not stop
+ // rules-loader from continuing the operation to fix the db
+ // hence "strange" silence in case of any error below
+ int oldFd = open(dbPath, O_RDONLY);
+ acpy(pkgsInfo.t + dbPathLen, DB_FAILED_COPY_SUFFIX);
+ int newFd = open(pkgsInfo.t, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (oldFd >=0 && newFd >= 0) {
+ // get the size of failed DB
+ struct stat failedSt;
+ if (!fstat(oldFd, &failedSt)) {
+ // perform actual copy
+ while (failedSt.st_size) {
+ auto r = sendfile(newFd, oldFd, nullptr, failedSt.st_size);
+ if (unlikely(r <= 0))
+ break;
+ failedSt.st_size -= r;
+ }
+ }
+ // we can safely close the descriptors
+ close(oldFd);
+ close(newFd);
+ }
+
// retrieve fallback database file path
- // WARNING: dbPath memory has been made invalid (will restore later) due to tzplatform_mkpath* using a shared scratch buffer
char const *fallbackPath = getFallbackPath();
// open the fallback database regular file and get its size
// dbPath : to open the database
// dbPath + DB_RECOVERED_SUFFIX : to remove/create the "database recovery attempted" marker file
// dbPath + DB_JOURNAL_SUFFIX : to potentially truncate the journal file when overwriting database with fallback
+ // dbPath + DB_FAILED_COPY_SUFFIX : to create DB file backup in case it was discovered to be corrupted
//
// the pkgsInfo tape memory is used to store these names (the tape is otherwise unused during database bringup)
- const auto maxFilenameSize = dbPathLen + max(sizeof DB_RECOVERED_SUFFIX, sizeof DB_JOURNAL_SUFFIX);
+ const auto maxFilenameSize = dbPathLen + max(sizeof DB_RECOVERED_SUFFIX, max(sizeof DB_JOURNAL_SUFFIX, sizeof DB_FAILED_COPY_SUFFIX));
// adjust the pkgsInfo tape size if needed to accommodate filename size
if (unlikely(maxFilenameSize > pkgsInfo.reserved))
pkgsInfo.reserved = align(maxFilenameSize, underlying(pageSize));
std::string caseName(boost::unit_test::framework::current_test_case().p_name);
return prefix + std::to_string(i) + "_" + caseName;
}
-void testMarkerFile(const char *f, bool present) {
+void testMarkerFile(const char *f, bool present, bool check_empty = true) {
struct stat st;
if (lstat(f, &st)) {
if (ENOENT != errno) BOOST_FAIL("marker file (" << f << ") lstat failed");
} else {
if (!present) BOOST_FAIL("marker file (" << f << ") exists");
if (!S_ISREG(st.st_mode)) BOOST_FAIL("marker file (" << f << ") not a regular file");
- if (st.st_size) BOOST_FAIL("marker file (" << f << ") not empty");
+ if (check_empty && st.st_size) BOOST_FAIL("marker file (" << f << ") not empty");
}
}
void checkMarker(PrivilegeDBFixture::Marker marker) {
const auto broken = marker != PrivilegeDBFixture::Marker::standard;
testMarkerFile(TEST_DB_OK_MARKER, !broken);
testMarkerFile(TEST_DB_PATH DB_RECOVERED_SUFFIX, broken);
+ testMarkerFile(TEST_DB_PATH DB_FAILED_COPY_SUFFIX, broken, !broken);
if (underlying(marker)) {
struct stat st;
BOOST_REQUIRE(!lstat(TEST_DB_PATH, &st));
TEST_DB_PATH,
TEST_DB_PATH DB_JOURNAL_SUFFIX,
TEST_DB_PATH DB_RECOVERED_SUFFIX,
+ TEST_DB_PATH DB_FAILED_COPY_SUFFIX,
TEST_PRIVILEGE_FALLBACK_DB_PATH,
TEST_DB_OK_MARKER,
};
checkMarker(PostMgrMarker::unchanged == postMgr ? preMgr : Marker::fallback);
}
+
PrivilegeDBFixture::~PrivilegeDBFixture()
{
delete testPrivDb;