reset handle after closing db handle
[platform/core/multimedia/media-server.git] / lib / media-util-db.c
1 /*
2  * Media Utility
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Yong Yeon Kim <yy9875.kim@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <sys/wait.h>
25
26 #include <dlfcn.h>
27
28 #include <unicode/utypes.h>
29 #include <unicode/ucol.h>
30 #include <unicode/uiter.h>
31 #include <unicode/ustring.h>
32 #include <vconf.h>
33
34 #include "media-server-ipc.h"
35 #include "media-util-dbg.h"
36 #include "media-util-internal.h"
37 #include "media-util.h"
38
39 #define BATCH_START "BEGIN"
40 #define BATCH_END "COMMIT"
41
42 static int __media_db_request_recovery(uid_t uid);
43
44 static int __media_db_busy_handler(void *pData, int count)
45 {
46         usleep(50000);
47
48         MSAPI_DBG("media_db_busy_handler called : %d", count);
49
50         return 200 - count;
51 }
52
53 /* The collating function must return an integer that is negative, zero or positive */
54 static int __media_db_collate_icu_8(void *ucol, int str1_len, const void *str1, int str2_len, const void *str2)
55 {
56         UCharIterator uiter1, uiter2;
57         UErrorCode error = U_ZERO_ERROR;
58
59         uiter_setUTF8(&uiter1, (const char *) str1, str1_len);
60         uiter_setUTF8(&uiter2, (const char *) str2, str2_len);
61
62         UCollationResult result = ucol_strcollIter((UCollator *) ucol, &uiter1, &uiter2, &error);
63         if (U_FAILURE(error)) {
64                 MSAPI_DBG_ERR("ucol_strcollIter error: %d", error);
65                 return -1;
66         }
67
68         return result;
69 }
70
71 static void __media_db_collation_cb(void* pArg, sqlite3* handle, int charset, const char* name)
72 {
73         int ret = MS_MEDIA_ERR_NONE;
74         UErrorCode status = U_ZERO_ERROR;
75         const char* locale = NULL;
76         char *lang = NULL;
77         UCollator* ucol = NULL;
78
79         if (handle == NULL || !MS_STRING_VALID(name)) {
80                 MSAPI_DBG_ERR("Input parameter is NULL");
81                 return;
82         }
83
84         if (charset == SQLITE_UTF8 && !sqlite3_stricmp(name, "localized")) {
85                 lang = vconf_get_str(VCONFKEY_LANGSET);
86                 /* get current locale */
87                 if (lang) {
88                         uloc_setDefault(lang, &status);
89                         MS_SAFE_FREE(lang);
90                 } else {
91                         MSAPI_DBG_ERR("Fail to get current language vconf");
92                         return;
93                 }
94                 locale = uloc_getDefault();
95                 if (locale == NULL) {
96                         MSAPI_DBG_ERR("Fail to get current locale");
97                         return;
98                 }
99                 MSAPI_DBG_INFO("locale : %s", locale);
100
101                 ucol = ucol_open(locale, &status);
102                 if (status == U_USING_DEFAULT_WARNING) {
103                         MSAPI_DBG("ucol_open success with default collate option");
104                 } else if (U_FAILURE(status)) {
105                         MSAPI_DBG_ERR("ucol_open fail : %d", status);
106                         return;
107                 }
108
109                 ucol_setStrength(ucol, UCOL_SECONDARY); /* NOTICE : MCD sets UCOL_PRIMARY */
110                 if (U_FAILURE(status)) {
111                         MSAPI_DBG_ERR("ucol_setStrength fail : %d", status);
112                         return;
113                 }
114
115                 ret = sqlite3_create_collation_v2(handle, name, SQLITE_UTF8, ucol, __media_db_collate_icu_8, (void *)ucol_close);
116                 if (ret != SQLITE_OK) {
117                         MSAPI_DBG_ERR("sqlite3_create_collation_v2 fail : %d", ret);
118                         ucol_close(ucol);
119                 } else {
120                         MSAPI_DBG("sqlite3_create_collation_v2 success");
121                 }
122         } else {
123                 MSAPI_DBG_ERR("No matching collator for %s", name);
124         }
125 }
126
127 static int __media_db_connect_db_with_handle(sqlite3 **db_handle, uid_t uid, bool need_write)
128 {
129         int ret = SQLITE_OK;
130         char *db_path = NULL;
131         char *sql = NULL;
132         MSAPI_DBG_ERR("need_write[%d]", need_write);
133         ret = ms_user_get_media_db_path(uid, &db_path);
134         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, MS_MEDIA_ERR_DB_INTERNAL, "ms_user_get_media_db_path failed");
135
136         /*Connect DB*/
137         if (need_write)
138                 ret = sqlite3_open_v2(db_path, db_handle, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
139         else
140                 ret = sqlite3_open_v2(db_path, db_handle, SQLITE_OPEN_READONLY, NULL);
141
142         if (SQLITE_OK != ret) {
143                 MSAPI_DBG_ERR("error when db open path[%s],ret[%d]", db_path, ret);
144                 g_free(db_path);
145                 *db_handle = NULL;
146                 return MS_MEDIA_ERR_DB_INTERNAL;
147         }
148         g_free(db_path);
149
150         if (*db_handle == NULL) {
151                 MSAPI_DBG_ERR("*db_handle is NULL");
152                 return MS_MEDIA_ERR_DB_INTERNAL;
153         }
154
155         /*Register busy handler*/
156         ret = sqlite3_busy_handler(*db_handle, __media_db_busy_handler, NULL);
157         if (SQLITE_OK != ret) {
158                 if (*db_handle)
159                         MSAPI_DBG_ERR("[error when register busy handler] %s", sqlite3_errmsg(*db_handle));
160
161                 sqlite3_close_v2(*db_handle);
162                 *db_handle = NULL;
163
164                 return MS_MEDIA_ERR_DB_INTERNAL;
165         }
166
167         /*For TV internal space issue, change TRUNCATE to OFF */
168         sql = sqlite3_mprintf("%s", "PRAGMA journal_mode = OFF");
169         ret = sqlite3_exec(*db_handle, sql, NULL, NULL, NULL);
170         MS_SQL_SAFE_FREE(sql);
171         if (SQLITE_OK != ret) {
172                 if (*db_handle)
173                         MSAPI_DBG_ERR("[error when change the journal mode] %s", sqlite3_errmsg(*db_handle));
174
175                 sqlite3_close_v2(*db_handle);
176                 *db_handle = NULL;
177
178                 if (ret == SQLITE_CORRUPT) {
179                         MSAPI_DBG_ERR("MEDIA DB IS CORRUPTED");
180                         return MS_MEDIA_ERR_DB_CORRUPT;
181                 }
182
183                 return MS_MEDIA_ERR_DB_INTERNAL;
184         }
185
186         /* Set for localized collate */
187         sqlite3_collation_needed(*db_handle, NULL, __media_db_collation_cb);
188         MSAPI_DBG_ERR("Finish");
189         return MS_MEDIA_ERR_NONE;
190 }
191
192 extern char MEDIA_IPC_PATH[][70];
193 #define MAX_RETRY_COUNT 3
194
195 static int __media_db_request_update_tcp(ms_msg_type_e msg_type, const char *request_msg, uid_t uid)
196 {
197         int ret = MS_MEDIA_ERR_NONE;
198         int sockfd = -1;
199         struct sockaddr_un serv_addr;
200         int retry_count = 0;
201
202         MSAPI_RETVM_IF(!ms_ipc_is_valid_msg(request_msg), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid request_msg");
203
204         ms_comm_msg_s send_msg;
205         memset((void *)&send_msg, 0, sizeof(ms_comm_msg_s));
206
207         send_msg.msg_type = msg_type;
208         SAFE_STRLCPY(send_msg.msg, request_msg, sizeof(send_msg.msg));
209         send_msg.uid = uid;
210
211         /*Create Socket*/
212         ret = ms_ipc_create_client_socket(MS_TIMEOUT_SEC_10, &sockfd);
213         MSAPI_RETV_IF(ret != MS_MEDIA_ERR_NONE, ret);
214
215         /*Set server Address*/
216         memset(&serv_addr, 0, sizeof(serv_addr));
217         serv_addr.sun_family = AF_UNIX;
218         SAFE_STRLCPY(serv_addr.sun_path, tzplatform_mkpath(TZ_SYS_RUN, MEDIA_IPC_PATH[MS_DB_UPDATE_PORT]), sizeof(serv_addr.sun_path));
219
220         /* Connecting to the media db server */
221         if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
222                 MSAPI_DBG_STRERROR("connect error");
223                 close(sockfd);
224                 if (errno == EACCES)
225                         return MS_MEDIA_ERR_PERMISSION_DENIED;
226                 else
227                         return MS_MEDIA_ERR_IPC;
228         }
229
230         /* Send request */
231         if (send(sockfd, &send_msg, sizeof(send_msg), 0) != sizeof(send_msg)) {
232                 MSAPI_DBG_STRERROR("send failed");
233                 close(sockfd);
234                 return MS_MEDIA_ERR_IPC;
235         }
236
237         /*Receive Response*/
238         int recv_msg_size = -1;
239         int recv_msg = -1;
240 RETRY:
241         if ((recv_msg_size = recv(sockfd, &recv_msg, sizeof(recv_msg), 0)) < 0) {
242                 MSAPI_DBG_STRERROR("recv failed");
243
244                 if (errno == EINTR || errno == EWOULDBLOCK) {
245                         if (retry_count < MAX_RETRY_COUNT) {
246                                 MSAPI_DBG_ERR("TIME OUT[%d]", retry_count);
247                                 retry_count++;
248                                 goto RETRY;
249                         }
250                 }
251                 close(sockfd);
252                 return MS_MEDIA_ERR_IPC;
253         }
254
255         MSAPI_DBG("RECEIVE OK [%d]", recv_msg);
256         ret = recv_msg;
257
258         close(sockfd);
259
260         return ret;
261 }
262
263 #define RETRY_CNT 9
264 #define SLEEP_TIME 1000 * 1000
265 static int __media_db_update_directly(sqlite3 *db_handle, const char *sql_str)
266 {
267         int ret = MS_MEDIA_ERR_NONE;
268         char *zErrMsg = NULL;
269         int retry_count = 0;
270
271 EXEC_RETRY:
272         ret = sqlite3_exec(db_handle, sql_str, NULL, NULL, &zErrMsg);
273
274         if (SQLITE_OK != ret) {
275                 MSAPI_ERR_SLOG("Error[%s],Query[%s]", zErrMsg, sql_str);
276                 MS_SQL_SAFE_FREE(zErrMsg);
277                 if (ret == SQLITE_BUSY) {
278                         ret = MS_MEDIA_ERR_DB_BUSY_FAIL;
279                 } else if (ret == SQLITE_CONSTRAINT) {
280                         ret = MS_MEDIA_ERR_DB_CONSTRAINT_FAIL;
281                 } else if (ret == SQLITE_FULL) {
282                         ret = MS_MEDIA_ERR_DB_FULL_FAIL;
283                 } else if (ret == SQLITE_LOCKED) {
284                         if (retry_count < RETRY_CNT) {
285                                 MSAPI_DBG_ERR("Locked retry[%d]", retry_count);
286                                 retry_count++;
287                                 usleep(SLEEP_TIME);
288                                 goto EXEC_RETRY;
289                         }
290                         ret = MS_MEDIA_ERR_DB_INTERNAL;
291                 } else {
292                         ret = MS_MEDIA_ERR_DB_INTERNAL;
293                 }
294         }
295
296         return ret;
297 }
298
299 int media_db_check_integrity(sqlite3 *handle)
300 {
301         MSAPI_RETVM_IF(handle == NULL, MS_MEDIA_ERR_INVALID_PARAMETER, "Handle is NULL");
302
303         int ret = 0;
304         sqlite3_stmt *stmt = NULL;
305         const char integrity_check_query[] = "PRAGMA integrity_check";
306
307         ret = sqlite3_prepare_v2(handle, integrity_check_query, strlen(integrity_check_query), &stmt, NULL);
308         if (ret != SQLITE_OK) {
309                 MSAPI_DBG_ERR("prepare error, ret = %d, error = %s", ret, sqlite3_errmsg(handle));
310                 return MS_MEDIA_ERR_DB_CORRUPT;
311         }
312
313         ret = sqlite3_step(stmt);
314         if (ret != SQLITE_ROW) {
315                 MSAPI_DBG_ERR("integrity_check failed in step");
316                 sqlite3_finalize(stmt);
317                 return MS_MEDIA_ERR_DB_CORRUPT;
318         }
319
320         char* check_result = (char*) sqlite3_column_text(stmt, 0);
321         if (check_result == NULL || strncmp(check_result, "ok", strlen(check_result))) {
322                 MSAPI_DBG_ERR("integrity_check failed - result(%s)\n", check_result);
323                 sqlite3_finalize(stmt);
324                 return MS_MEDIA_ERR_DB_CORRUPT;
325         }
326         sqlite3_finalize(stmt);
327
328         return MS_MEDIA_ERR_NONE;
329 }
330
331 int media_db_connect(sqlite3 **handle, uid_t uid, bool need_write)
332 {
333         int ret = MS_MEDIA_ERR_NONE;
334         sqlite3 * db_handle = NULL;
335         int retry_cnt = 0;
336
337         MSAPI_DBG_FUNC();
338
339 RETRY_CONN:
340         ret = __media_db_connect_db_with_handle(&db_handle, uid, need_write);
341         if (ret != MS_MEDIA_ERR_NONE) {
342                 if (ret == MS_MEDIA_ERR_DB_CORRUPT && retry_cnt == 0) {
343                         retry_cnt++;
344
345                         ret = __media_db_request_recovery(uid);
346                         if (ret == MS_MEDIA_ERR_NONE)
347                                 goto RETRY_CONN;
348                         else
349                                 return MS_MEDIA_ERR_DB_CORRUPT;
350                 } else {
351                         return ret;
352                 }
353         }
354
355         *handle = db_handle;
356         return MS_MEDIA_ERR_NONE;
357 }
358
359 void media_db_disconnect(sqlite3 *handle)
360 {
361         MSAPI_DBG_FUNC();
362
363         if (handle) {
364                 sqlite3_close_v2(handle);
365                 handle = NULL;
366         }
367 }
368
369 int media_db_request_update_db(const char *query_str, uid_t uid)
370 {
371         int ret = MS_MEDIA_ERR_NONE;
372
373         MSAPI_DBG_FUNC();
374
375         MSAPI_RETVM_IF(!MS_STRING_VALID(query_str), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid Query");
376
377         ret = __media_db_request_update_tcp(MS_MSG_DB_UPDATE, query_str, uid);
378         if (ret != MS_MEDIA_ERR_NONE)
379                 MSAPI_DBG_ERR("__media_db_request_update_tcp failed : %d", ret);
380
381         return ret;
382 }
383
384 int media_db_update_db_direct(const char *query_str, uid_t uid)
385 {
386         int ret = MS_MEDIA_ERR_NONE;
387         sqlite3 *handle = NULL;
388
389         MSAPI_DBG_FUNC();
390
391         MSAPI_RETVM_IF(!MS_STRING_VALID(query_str), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid Query");
392
393         ret = media_db_connect(&handle, uid, true);
394         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "Connect failed");
395
396         ret = __media_db_update_directly(handle, query_str);
397         if (ret != MS_MEDIA_ERR_NONE)
398                 MSAPI_DBG_ERR("Query failed");
399
400         media_db_disconnect(handle);
401
402         return ret;
403 }
404
405 static int __media_db_request_recovery(uid_t uid)
406 {
407         int ret = MS_MEDIA_ERR_NONE;
408         int sockfd = -1;
409         struct sockaddr_un serv_addr;
410         int retry_count = 0;
411         char *db_path = NULL;
412
413         ret = ms_user_get_media_db_path(uid, &db_path);
414         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, MS_MEDIA_ERR_INVALID_PARAMETER, "ms_user_get_media_db_path failed");
415
416         if (!ms_ipc_is_valid_msg(db_path)) {
417                 g_free(db_path);
418                 return MS_MEDIA_ERR_INVALID_PARAMETER;
419         }
420
421         ms_comm_msg_s send_msg;
422         memset((void *)&send_msg, 0, sizeof(ms_comm_msg_s));
423
424         send_msg.msg_type = MS_MSG_MEDIA_DB_MALFORMED;
425         SAFE_STRLCPY(send_msg.msg, db_path, sizeof(send_msg.msg));
426         g_free(db_path);
427         send_msg.uid = uid;
428
429         /*Create Socket*/
430         ret = ms_ipc_create_client_socket(MS_TIMEOUT_SEC_10, &sockfd);
431         MSAPI_RETV_IF(ret != MS_MEDIA_ERR_NONE, ret);
432
433         /*Set server Address*/
434         memset(&serv_addr, 0, sizeof(serv_addr));
435         serv_addr.sun_family = AF_UNIX;
436         /*      MSAPI_DBG_SLOG("%s", MEDIA_IPC_PATH[port]); */
437         SAFE_STRLCPY(serv_addr.sun_path, MEDIA_IPC_PATH[MS_SCANNER_PORT], sizeof(serv_addr.sun_path));
438
439         /* Connecting to the media db server */
440         if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
441                 MSAPI_DBG_STRERROR("connect error");
442                 close(sockfd);
443                 return MS_MEDIA_ERR_IPC;
444         }
445
446         /* Send request */
447         if (send(sockfd, &send_msg, sizeof(send_msg), 0) != sizeof(send_msg)) {
448                 MSAPI_DBG_STRERROR("send failed");
449                 close(sockfd);
450                 return MS_MEDIA_ERR_IPC;
451         }
452
453         /*Receive Response*/
454         int recv_msg_size = -1;
455         ms_comm_msg_s recv_msg;
456 RETRY:
457         if ((recv_msg_size = recv(sockfd, &recv_msg, sizeof(recv_msg), 0)) < 0) {
458                 MSAPI_DBG_STRERROR("recv failed");
459
460                 if (errno == EINTR || errno == EWOULDBLOCK) {
461                         if (retry_count < MAX_RETRY_COUNT) {
462                                 MSAPI_DBG_ERR("TIME OUT[%d]", retry_count);
463                                 retry_count++;
464                                 goto RETRY;
465                         }
466                 }
467                 close(sockfd);
468                 return MS_MEDIA_ERR_IPC;
469         }
470
471         MSAPI_DBG("RECEIVE OK [%d]", recv_msg.result);
472         ret = recv_msg.result;
473
474         close(sockfd);
475
476         return ret;
477 }
478
479 int media_db_get_result(sqlite3 *handle, char *sql_str, sqlite3_stmt **stmt)
480 {
481         int err = -1;
482
483         MSAPI_RETVM_IF(sql_str == NULL, MS_MEDIA_ERR_INVALID_PARAMETER, "invalid query");
484         if (handle == NULL) {
485                 MSAPI_DBG_ERR("handle is NULL");
486                 MS_SQL_SAFE_FREE(sql_str);
487                 return MS_MEDIA_ERR_INVALID_PARAMETER;
488         }
489
490         MSAPI_DBG_SLOG("[SQL query] : %s", sql_str);
491
492         err = sqlite3_prepare_v2(handle, sql_str, -1, stmt, NULL);
493         MS_SQL_SAFE_FREE(sql_str);
494
495         if (err != SQLITE_OK) {
496                 MSAPI_DBG_ERR("prepare error %d[%s]", err, sqlite3_errmsg(handle));
497                 if (err == SQLITE_CORRUPT)
498                         return MS_MEDIA_ERR_DB_CORRUPT;
499
500                 return MS_MEDIA_ERR_DB_INTERNAL;
501         }
502
503         return MS_MEDIA_ERR_NONE;
504 }