#include "ctsvc_schema_recovery.h"
#include "ctsvc_db_schema.h"
-/* Additional Error */
-enum {
- CTSVC_ERR_NO_DB_FILE = -10000,
- CTSVC_ERR_NO_TABLE,
-};
-
-static inline int __ctsvc_server_check_db_file(void)
+static inline bool __ctsvc_server_db_file_exist(void)
{
int fd = open(CTSVC_DB_PATH, O_RDONLY);
- RETVM_IF(-1 == fd, CTSVC_ERR_NO_DB_FILE, "DB file is not exist");
+ RETVM_IF(-1 == fd, false, "DB file does not exist");
close(fd);
- return CONTACTS_ERROR_NONE;
+ return true;
}
static inline int __ctsvc_server_remake_db_file()
return CONTACTS_ERROR_NONE;
}
-static bool need_to_remove = false;
-static int __integrity_callback(void *pid, int argc, char **argv, char **notUsed2)
+static int __integrity_callback(void *user_data, int ncol, char **cols, char **name)
{
CTS_FN_CALL;
- if (NULL == argv || NULL == argv[0]) {
- ERR("Invalid parameter");
- need_to_remove = true;
- return -1;
- }
+ RETV_IF(0 == ncol, CONTACTS_ERROR_DB);
+ RETV_IF(NULL == cols, CONTACTS_ERROR_DB);
- if (0 != strcmp(argv[0], "ok")) {
- ERR("integrity_check() Fail(argv[%s])", argv[0]);
- need_to_remove = true;
- return -1;
+ if (0 != strcmp(cols[0], "ok")) {
+ ERR("integrity_check Fail(%s)", cols[0]);
+ return CONTACTS_ERROR_DB;
}
- DBG("integrity_check done");
return 0;
}
-static int __ctsvc_server_check_db_integrity(void)
+static bool __ctsvc_server_check_db_table(sqlite3 *db)
{
CTS_FN_CALL;
- int ret = 0;
- sqlite3 *db = NULL;
+ int ret;
cts_stmt stmt = NULL;
- int sqlite_error = SQLITE_OK;
- ret = ctsvc_server_db_open(&db, &sqlite_error);
- if (CONTACTS_ERROR_NONE != ret) {
+ do {
+ /* check if table is missing */
+ const char *query = "SELECT count(*) FROM sqlite_master WHERE type='table'"
+ " AND name IN ('"CTS_TABLE_PERSONS"','"CTS_TABLE_ADDRESSBOOKS"','"CTS_TABLE_CONTACTS"',"
+ "'"CTS_TABLE_DELETEDS"','"CTS_TABLE_VERSION"','"CTS_TABLE_SDN"','"CTS_TABLE_DATA"',"
+ "'"CTS_TABLE_GROUPS"','"CTS_TABLE_GROUP_DELETEDS"','"CTS_TABLE_GROUP_RELATIONS"',"
+ "'"CTS_TABLE_SPEEDDIALS"','"CTS_TABLE_FAVORITES"','"CTS_TABLE_SIM_INFO"',"
+ "'"CTS_TABLE_PHONELOGS"','"CTS_TABLE_PHONELOG_STAT"','"CTS_TABLE_CONTACT_STAT"',"
+ "'"CTS_TABLE_ACTIVITIES"','"CTS_TABLE_ACTIVITY_PHOTOS"','"CTS_TABLE_SEARCH_INDEX"',"
+ "'"CTS_TABLE_NAME_LOOKUP"','"CTS_TABLE_PHONE_LOOKUP"','"CTS_TABLE_MY_PROFILES"')";
+ ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+ if (SQLITE_OK != ret) {
+ /* LCOV_EXCL_START */
+ ERR("sqlite3_prepare_v2() Fail(%s)", sqlite3_errstr(ret));
+ break;
+ /* LCOV_EXCL_STOP */
+ }
+
+ ret = sqlite3_step(stmt);
+ if (SQLITE_ROW != ret) {
+ /* LCOV_EXCL_START */
+ ERR("sqlite3_step() Fail(%s)", sqlite3_errstr(ret));
+ sqlite3_finalize(stmt);
+ break;
+ /* LCOV_EXCL_STOP */
+ }
+ }while (0);
+
+ switch (ret) {
+ case SQLITE_ROW:
+ break;
+ case SQLITE_DONE:
+ case SQLITE_BUSY:
+ case SQLITE_LOCKED:
+ case SQLITE_FULL:
+ case SQLITE_CONSTRAINT:
+ case SQLITE_NOMEM:
/* LCOV_EXCL_START */
- ERR("ctsvc_server_db_open() Fail(%d), sqlite_error(%d)", ret, sqlite_error);
- if (SQLITE_ERROR == sqlite_error ||SQLITE_CORRUPT == sqlite_error ||SQLITE_NOTADB == sqlite_error)
- return -1;
- else
- return 0;
+ // It's not critical. It can be ignored
+ INFO("False Positive(err = [%d]%s)", ret, sqlite3_errstr(ret));
+ return true;
/* LCOV_EXCL_STOP */
- }
-
- ret = sqlite3_exec(db, "pragma integrity_check", __integrity_callback, NULL, NULL);
- if (true == need_to_remove || SQLITE_ERROR == ret || SQLITE_CORRUPT == ret || SQLITE_NOTADB == ret) {
+ case SQLITE_IOERR:
+ case SQLITE_CORRUPT:
+ default:
/* LCOV_EXCL_START */
- ERR("need_to_remove [%s], ret [%d]", need_to_remove ? "true" : "false", ret);
- need_to_remove = false;
- return -1;
+ ERR("Critical Error(%d:%s)", ret, sqlite3_errstr(ret));
+ ctsvc_server_db_close();
+ return false;
/* LCOV_EXCL_STOP */
}
- /* check if table is missing */
- const char *query = "SELECT count(*) FROM sqlite_master WHERE type='table'"
- " AND name IN ('persons','addressbooks','contacts','contact_deleteds','cts_version' ,"
- "'sdn','data','groups','group_deleteds','group_relations','speeddials','favorites','sim_info',"
- "'phonelogs','phonelog_stat','contact_stat','activities','activity_photos','search_index','name_lookup','phone_lookup','my_profiles')";
- ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
- if (SQLITE_OK != ret) {
+ int get_count = sqlite3_column_int(stmt, 0);
+ sqlite3_finalize(stmt);
+
+ if (get_count != CTS_SCHEMA_TABLE_TOTAL) {
/* LCOV_EXCL_START */
- ERR("sqlite3_qlite3_prepare_v2() Fail(%d)", ret);
- if (SQLITE_ERROR == ret ||SQLITE_CORRUPT == ret ||SQLITE_NOTADB == ret)
- return -1;
- else
- return 0;
+ ERR("Table is missing(expected(%d) but result(%d)", CTS_SCHEMA_TABLE_TOTAL, get_count);
+ ctsvc_server_db_close();
+ return false;
/* LCOV_EXCL_STOP */
}
- ret = sqlite3_step(stmt);
- if (SQLITE_ROW != ret) {
+ return true;
+}
+
+static bool __ctsvc_server_check_db()
+{
+ CTS_FN_CALL;
+ int ret;
+ sqlite3 *db = NULL;
+ int sqlite_error = SQLITE_OK;
+
+ ret = ctsvc_server_db_open(&db, &sqlite_error);
+ if (CONTACTS_ERROR_NONE != ret) {
/* LCOV_EXCL_START */
- ERR("sqlite3_step() Fail(%d)", ret);
- sqlite3_finalize(stmt);
- if (SQLITE_ERROR == ret ||SQLITE_CORRUPT == ret ||SQLITE_NOTADB == ret)
- return -1;
- else
- return 0;
+ INFO("ctsvc_server_db_open() Fail(%d), sqlite_error(%s)", ret, sqlite3_errstr(sqlite_error));
+
+ if (SQLITE_BUSY == sqlite_error || SQLITE_NOMEM == sqlite_error) {
+ INFO("it's not critical enough to clear the db.");
+ return true;
+ }
+ ctsvc_server_db_close();
+ return false;
/* LCOV_EXCL_STOP */
}
- int get_count = sqlite3_column_int(stmt, 0);
- sqlite3_finalize(stmt);
-
- if (get_count != CTS_SCHEMA_TABLE_TOTAL) {
+ ret = sqlite3_exec(db, "pragma integrity_check", __integrity_callback, NULL, NULL);
+ if (SQLITE_ABORT == ret) {
/* LCOV_EXCL_START */
- ERR("Table is missing(expected(%d) but result(%d)", CTS_SCHEMA_TABLE_TOTAL, get_count);
- return -1;
+ ERR("integrity_check Fail()");
+ ctsvc_server_db_close();
+ return false;
/* LCOV_EXCL_STOP */
}
- return 0;
+ return __ctsvc_server_check_db_table(db);
}
-int ctsvc_server_check_schema(void)
+static void __ctsvc_server_backup_file()
{
- if (CONTACTS_ERROR_NONE != __ctsvc_server_check_db_file()
- || 0 != __ctsvc_server_check_db_integrity())
- {
- ERR("Need to remove and remake db files");
-
- ctsvc_server_db_close();
+ int i;
+ const int MAX_BACKUP = 4;
+ char new_path[CTSVC_PATH_MAX_LEN];
+ for (i = 0; i < MAX_BACKUP; i++) {
+ snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_PATH, i);
+ if (-1 == access(new_path, F_OK))
+ break;
+ }
- if (remove(CTSVC_DB_SHM_FILE) != 0)
- ERR("Failed to remove CTSVC_DB_SHM_FILE");
- if (remove(CTSVC_DB_WAL_FILE) != 0)
- ERR("Failed to remove CTSVC_DB_WAL_FILE");
- if (remove(CTSVC_DB_PATH) !=0)
- ERR("Failed to remove CTSVC_DB_PATH");
+ if (rename(CTSVC_DB_PATH, new_path))
+ ERR("rename(%s) Fail(%d)", new_path, errno);
+ snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_SHM_PATH, i);
+ if (rename(CTSVC_DB_SHM_PATH, new_path))
+ ERR("rename(%s) Fail(%d)", new_path, errno);
+ snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_WAL_PATH, i);
+ if (rename(CTSVC_DB_WAL_PATH, new_path))
+ ERR("rename(%s) Fail(%d)", new_path, errno);
+
+ i = (i + 1) % MAX_BACKUP;
+ snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_PATH, i);
+ if (0 == access(new_path, F_OK)) {
+ remove(new_path);
+ snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_SHM_PATH, i);
+ remove(new_path);
+ snprintf(new_path, sizeof(new_path), "%s%d", CTSVC_DB_WAL_PATH, i);
+ remove(new_path);
+ }
+}
+int ctsvc_server_check_schema(void)
+{
+ if (false == __ctsvc_server_db_file_exist()) {
+ ERR("Need to remake db files");
+ __ctsvc_server_remake_db_file();
+ } else if (false == __ctsvc_server_check_db()) {
+ ERR("Need to backup and remake db files");
+ __ctsvc_server_backup_file();
__ctsvc_server_remake_db_file();
}