Merge branch 'master' of github.sec.samsung.net:appfw/pkgmgr-info into tizen
[platform/core/appfw/pkgmgr-info.git] / src / server / database / abstract_db_handler.cc
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
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 "abstract_db_handler.hh"
18
19 #include <gio/gio.h>
20 #include <stdlib.h>
21 #include <sys/stat.h>
22 #include <sys/sysmacros.h>
23 #include <sys/types.h>
24 #include <tzplatform_config.h>
25
26 #include <string>
27 #include <vector>
28
29 #include "db_handle_provider.hh"
30 #include "pkgmgr-info.h"
31 #include "pkgmgrinfo_debug.h"
32 #include "pkgmgrinfo_private.h"
33
34 namespace {
35
36 constexpr useconds_t BUSY_WAITING_USEC = (1000000 / 10 / 2); /* 0.05 sec */
37 constexpr int BUSY_WAITING_MAX = 100; /* wait for max 5 sec */
38
39 int __readdb_busy_handler(void *data, int count) {
40   if (count < BUSY_WAITING_MAX) {
41     usleep(BUSY_WAITING_USEC);
42     return 1;
43   } else {
44     /* sqlite3_prepare_v2 will return SQLITE_BUSY */
45     return 0;
46   }
47 }
48
49 int __open_read_db(const char *path, sqlite3 **db) {
50   int ret;
51
52   ret = sqlite3_open_v2(path, db,
53       SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, NULL);
54   if (ret != SQLITE_OK) {
55     sqlite3_close_v2(*db);
56     return ret;
57   }
58
59   ret = sqlite3_busy_handler(*db, __readdb_busy_handler, NULL);
60   if (ret != SQLITE_OK) {
61     _LOGE("failed to register busy handler: %s",
62         sqlite3_errmsg(*db));
63     sqlite3_close_v2(*db);
64     return ret;
65   }
66
67   return ret;
68 }
69
70 constexpr const char RESOURCED_BUS_NAME[] = "org.tizen.resourced";
71 constexpr const char RESOURCED_PROC_PATH[] = "/Org/Tizen/ResourceD/Process";
72 constexpr const char RESOURCED_PROC_INTERFACE[] = "org.tizen.resourced.process";
73 constexpr const char RESOURCED_PROC_METHOD[] = "ProcExclude";
74
75 int __writedb_busy_handler(void *data, int count) {
76   if (count < (BUSY_WAITING_MAX / 2)) {
77     usleep(BUSY_WAITING_USEC);
78     return 1;
79   } else if (count < BUSY_WAITING_MAX) {
80     usleep(BUSY_WAITING_USEC);
81     return 1;
82   } else {
83     /* sqlite3_prepare_v2 will return SQLITE_BUSY */
84     return 0;
85   }
86 }
87
88 int __open_write_db(uid_t uid, const char* path,
89     sqlite3** db) {
90   int ret;
91
92   ret = sqlite3_open_v2(path, db, SQLITE_OPEN_READWRITE, NULL);
93   if (ret != SQLITE_OK) {
94     sqlite3_close_v2(*db);
95     return ret;
96   }
97
98   ret = sqlite3_busy_handler(*db, __writedb_busy_handler,
99       reinterpret_cast<void*>(const_cast<char*>(path)));
100   if (ret != SQLITE_OK) {
101     _LOGE("failed to register busy handler: %s",
102         sqlite3_errmsg(*db));
103     sqlite3_close_v2(*db);
104     return ret;
105   }
106
107   ret = sqlite3_exec(*db, "PRAGMA foreign_keys=ON", NULL, NULL, NULL);
108   if (ret != SQLITE_OK) {
109     _LOGE("failed to enable foreign key support: %s",
110         sqlite3_errmsg(*db));
111     sqlite3_close_v2(*db);
112     return ret;
113   }
114
115   return ret;
116 }
117
118 int __open_create_db(uid_t uid, const char* path,
119     sqlite3** db) {
120   int ret;
121
122   ret = sqlite3_open_v2(path, db,
123       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
124   if (ret != SQLITE_OK) {
125     sqlite3_close_v2(*db);
126     return ret;
127   }
128
129   ret = sqlite3_busy_handler(*db, __writedb_busy_handler,
130       reinterpret_cast<void*>(const_cast<char*>(path)));
131   if (ret != SQLITE_OK) {
132     _LOGE("failed to register busy handler: %s",
133         sqlite3_errmsg(*db));
134     sqlite3_close_v2(*db);
135     return ret;
136   }
137
138   return ret;
139 }
140
141 uid_t ConvertUID(uid_t uid) {
142   if (uid < REGULAR_USER)
143     return tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
144   else
145     return uid;
146 }
147
148 }  // namespace
149
150 namespace pkgmgr_server {
151 namespace database {
152
153 std::shared_timed_mutex AbstractDBHandler::lock_;
154
155 AbstractDBHandler::~AbstractDBHandler() {
156   for (auto& db_handle : db_handle_list_)
157     sqlite3_close_v2(db_handle.first);
158 }
159
160 std::vector<std::pair<std::string, uid_t>> AbstractDBHandler::GetDBPath() {
161   std::vector<std::pair<std::string, uid_t>> db_path;
162   if (db_type_ == pkgmgr_common::DBType::DB_TYPE_FILE_PKGDB)
163     db_path = DBHandleProvider::GetInst(uid_).GetParserDBPath(pid_,
164         op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE);
165   else if (db_type_ == pkgmgr_common::DBType::DB_TYPE_FILE_CERTDB)
166     db_path.emplace_back(
167         std::make_pair(DBHandleProvider::GetInst(uid_).GetCertDBPath(pid_,
168             op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE), uid_));
169
170   return db_path;
171 }
172
173 bool AbstractDBHandler::Connect() {
174   if (db_type_ == pkgmgr_common::DBType::DB_TYPE_NONE ||
175       op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_NONE) {
176     _LOGE("Invalid parameter");
177     return false;
178   }
179   auto dbpath_list = GetDBPath();
180   sqlite3* db;
181   for (auto& dbpath : dbpath_list) {
182     int ret = 0;
183     if (op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_READ) {
184       ret = __open_read_db(dbpath.first.c_str(), &db);
185     } else if (op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE) {
186       if (ConvertUID(dbpath.second) != ConvertUID(uid_))
187         continue;
188       ret = __open_write_db(uid_, dbpath.first.c_str(), &db);
189     } else {
190       if (ConvertUID(dbpath.second) != ConvertUID(uid_))
191         continue;
192
193       if (access(dbpath.first.c_str(), F_OK) != -1) {
194         _LOGE("Database for user %d is already exists", uid_);
195         return false;
196       }
197       ret = __open_create_db(uid_, dbpath.first.c_str(), &db);
198     }
199
200     if (ret != SQLITE_OK)
201       return false;
202
203     db_handle_list_.emplace_back(std::make_pair(db, dbpath.second));
204   }
205
206   return true;
207 }
208
209 void AbstractDBHandler::ClearDBHandle() {
210   for (auto db_handle : db_handle_list_)
211     sqlite3_close_v2(db_handle.first);
212
213   db_handle_list_.clear();
214 }
215
216 std::vector<std::pair<sqlite3*, uid_t>> AbstractDBHandler::GetConnection() {
217   return db_handle_list_;
218 }
219
220 void AbstractDBHandler::SetOpType(pkgmgr_common::DBOperationType type) {
221   op_type_ = type;
222 }
223
224 const std::string& AbstractDBHandler::GetLocale() {
225   return locale_;
226 }
227
228 int AbstractDBHandler::GetPID() {
229   return pid_;
230 }
231
232 uid_t AbstractDBHandler::GetUID() {
233   return uid_;
234 }
235
236 void AbstractDBHandler::SetLocale(std::string locale) {
237   locale_ = std::move(locale);
238 }
239
240 void AbstractDBHandler::SetDBType(pkgmgr_common::DBType type) {
241   db_type_ = type;
242 }
243
244 pkgmgr_common::DBOperationType AbstractDBHandler::GetOpType() {
245   return op_type_;
246 }
247
248 }  // namespace database
249 }  // namespace pkgmgr_server