Check validity of database
[platform/core/connectivity/stc-manager.git] / src / database / db-common.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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  */
16
17 #include <errno.h>
18 #include <sys/stat.h>
19
20 #include "stc-db.h"
21 #include "db-internal.h"
22 #include "table-statistics.h"
23 #include "table-restrictions.h"
24 #include "table-counters.h"
25 #include "table-firewall.h"
26
27 #define SQLITE_BUSY_TIMEOUT 500000
28
29 static sqlite3 *database;
30
31 //LCOV_EXCL_START
32 static int __stc_db_busy(void *user, int attempts)
33 {
34         __STC_LOG_FUNC_ENTER__;
35         STC_LOGE("DB locked by another process, attempts number %d",
36                  attempts);
37
38         usleep(SQLITE_BUSY_TIMEOUT); /* wait for a half second*/
39         __STC_LOG_FUNC_EXIT__;
40         return 1;
41 }
42
43 static gboolean __stc_db_restore(const char *src, const char *dst)
44 {
45         gchar *buf = NULL;
46         gsize length = 0;
47         GError *error = NULL;
48         gboolean result;
49
50         result = g_file_get_contents(src, &buf, &length, &error);
51         if (result != TRUE) {
52                 STC_LOGE("Failed to read [%s]", error->message);
53                 g_error_free(error);
54                 return result;
55         }
56
57         result = g_file_set_contents(dst, buf, length, &error);
58         if (result != TRUE) {
59                 STC_LOGE("Failed to write [%s]", error->message);
60                 g_error_free(error);
61                 g_free(buf);
62                 return result;
63         }
64
65         STC_LOGD("Successfully restored database");
66         g_free(buf);
67
68         return result;
69 }
70
71 static gboolean __stc_db_table_init()
72 {
73         EXEC(STC_ERROR_NONE, table_statistics_prepare(database));
74         EXEC(STC_ERROR_NONE, table_restrictions_prepare(database));
75         EXEC(STC_ERROR_NONE, table_counters_prepare(database));
76         EXEC(STC_ERROR_NONE, table_firewall_prepare(database));
77         EXEC(STC_ERROR_NONE, stc_init_db_guard());
78
79         return true;
80 }
81
82 static int __stc_db_open(void)
83 {
84         int ret = 0;
85
86         ret = sqlite3_open(DATABASE_FULL_PATH, &database);
87         if (ret != SQLITE_OK) {
88                 STC_LOGD("Failed to open database [%s]", sqlite3_errmsg(database));
89                 return STC_ERROR_DB_FAILED;
90         }
91
92         STC_LOGD("Successfully opened database");
93         return ret;
94 }
95
96 static int __stc_db_exec(char *sql, void *cb)
97 {
98         int ret;
99         char *error = NULL;
100
101         if (database == NULL)
102                 return STC_ERROR_DB_FAILED;
103
104         ret = sqlite3_exec(database, sql, cb, 0, &error);
105         if (ret != SQLITE_OK) {
106                 STC_LOGE("Failed to execute sql [%d:%s]", ret, error);
107                 sqlite3_free(error);
108                 sqlite3_close(database);
109                 database = NULL;
110                 __STC_LOG_FUNC_EXIT__;
111                 return STC_ERROR_DB_FAILED;
112         }
113
114         return STC_ERROR_NONE;
115 }
116
117 static int __stc_db_integrity_cb(void *err, int count, char **data, char **columns)
118 {
119         STC_LOGD("%s [%s]", columns[0], data[0] ? data[0] : "null");
120
121         if (!g_strcmp0(columns[0], "integrity_check") && !g_strcmp0(data[0], "ok"))
122                 return SQLITE_OK;
123
124         return SQLITE_ERROR;
125 }
126
127 static int __stc_db_check_integrity(void)
128 {
129         int ret;
130         char *sql = NULL;
131
132         sql = sqlite3_mprintf("PRAGMA integrity_check");
133         ret = __stc_db_exec(sql, __stc_db_integrity_cb);
134         if (ret == STC_ERROR_NONE)
135                 STC_LOGD("Successfully checked integrity");
136
137         sqlite3_free(sql);
138
139         return ret;
140 }
141
142 static int __stc_db_set_locking_mode(void)
143 {
144         int ret;
145         char *sql = NULL;
146
147         sql = sqlite3_mprintf("PRAGMA locking_mode = NORMAL");
148         ret = __stc_db_exec(sql, NULL);
149         if (ret == STC_ERROR_NONE)
150                 STC_LOGD("Successfully set locking mode");
151
152         sqlite3_free(sql);
153
154         return ret;
155 }
156
157 static int __stc_db_stat(void)
158 {
159         struct stat db_stat = { 0 };
160
161         if (stat(DATABASE_FULL_PATH, &db_stat)) {
162                 STC_LOGD("Db restoration is required [no file]");
163                 return STC_ERROR_DB_FAILED;
164         } else if (db_stat.st_size == 0) {
165                 STC_LOGD("Db restoration is required [size is zero]");
166                 return STC_ERROR_DB_FAILED;
167         }
168
169         return STC_ERROR_NONE;
170 }
171
172 static int __stc_db_verify(void)
173 {
174         ret_value_msg_if(__stc_db_check_integrity() != STC_ERROR_NONE,
175                 STC_ERROR_DB_FAILED, "Failed to check integrity");
176
177         ret_value_msg_if(__stc_db_set_locking_mode() != STC_ERROR_NONE,
178                 STC_ERROR_DB_FAILED, "Failed to set locking mode");
179
180         return STC_ERROR_NONE;
181 }
182
183 //LCOV_EXCL_STOP
184 stc_error_e stc_db_initialize_once()
185 {
186         __STC_LOG_FUNC_ENTER__;
187         int retry_count = MAX_DB_RETRY_COUNT;
188
189         if (database != NULL) {
190                 __STC_LOG_FUNC_EXIT__;
191                 return STC_ERROR_NONE;
192         }
193
194         if (__stc_db_stat() != STC_ERROR_NONE) {
195                 if (!__stc_db_restore(DATABASE_BACKUP_PATH, DATABASE_FULL_PATH)) {
196                         __STC_LOG_FUNC_EXIT__;
197                         return STC_ERROR_DB_FAILED;
198                 }
199         }
200
201         do {
202                 if (__stc_db_open() == SQLITE_OK) {
203                         if (__stc_db_verify() == STC_ERROR_NONE) {
204                                 STC_LOGD("Successfully verified database");
205                                 break;
206                         } else {
207                                 __stc_db_restore(DATABASE_BACKUP_PATH, DATABASE_FULL_PATH);
208                         }
209                 }
210                 usleep(MAX_USLEEP_TIMEOUT);
211                 STC_LOGD("Retry opening database [%d]", MAX_DB_RETRY_COUNT - retry_count + 1);
212         } while (retry_count--);
213
214         if (retry_count == 0) {
215                 STC_LOGE("Failed to initialize database");
216                 sqlite3_close(database);
217                 database = NULL;
218                 __STC_LOG_FUNC_EXIT__;
219                 return STC_ERROR_DB_FAILED;
220         }
221
222         /* Set how many times we'll repeat our attempts for sqlite_step */
223         if (sqlite3_busy_handler(database, __stc_db_busy, NULL) != SQLITE_OK)
224                 STC_LOGE("Couldn't set busy handler!");
225
226         STC_LOGD("Successfully initialize database");
227         __STC_LOG_FUNC_EXIT__;
228         return STC_ERROR_NONE;
229 }
230
231 //LCOV_EXCL_START
232 sqlite3 *stc_db_get_database(void)
233 {
234         if (database == NULL)
235                 stc_db_initialize_once();
236
237         return database;
238 }
239 //LCOV_EXCL_STOP
240
241 stc_error_e stc_db_initialize(void)
242 {
243         __STC_LOG_FUNC_ENTER__;
244         int ret;
245         int retry_count = MAX_DB_RETRY_COUNT;
246         database = NULL;
247
248         do {
249                 stc_db_initialize_once();
250                 ret = __stc_db_table_init();
251                 if (ret) {
252                         STC_LOGD("Successfully initialize database");
253                         break;
254                 } else {
255                         __stc_db_restore(DATABASE_BACKUP_PATH, DATABASE_FULL_PATH);
256                         sqlite3_close(database);
257                         database = NULL;
258                 }
259                 STC_LOGD("Retry init database [%d]", MAX_DB_RETRY_COUNT - retry_count + 1);
260         } while (retry_count--);
261
262         __STC_LOG_FUNC_EXIT__;
263         return STC_ERROR_NONE;
264 }
265
266 gboolean stc_db_deinitialize(void)
267 {
268         __STC_LOG_FUNC_ENTER__;
269         if (database == NULL) {
270                 __STC_LOG_FUNC_EXIT__;
271                 return TRUE;
272         }
273
274         table_statistics_finalize();
275         table_restrictions_finalize();
276         table_counters_finalize();
277         table_firewall_finalize();
278         sqlite3_close(database);
279
280         __STC_LOG_FUNC_EXIT__;
281         return TRUE;
282 }