2 * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "abstract_db_handler.hh"
22 #include <sys/sysmacros.h>
23 #include <sys/types.h>
24 #include <tzplatform_config.h>
29 #include "db_handle_provider.hh"
30 #include "pkgmgr-info.h"
31 #include "pkgmgrinfo_debug.h"
32 #include "pkgmgrinfo_private.h"
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 */
39 int __readdb_busy_handler(void *data, int count) {
40 if (count < BUSY_WAITING_MAX) {
41 usleep(BUSY_WAITING_USEC);
44 /* sqlite3_prepare_v2 will return SQLITE_BUSY */
49 int __open_read_db(const char *path, sqlite3 **db, int flags) {
52 ret = sqlite3_open_v2(path, db, flags, NULL);
53 if (ret != SQLITE_OK) {
54 sqlite3_close_v2(*db);
58 ret = sqlite3_busy_handler(*db, __readdb_busy_handler, NULL);
59 if (ret != SQLITE_OK) {
60 _LOGE("failed to register busy handler: %s",
62 sqlite3_close_v2(*db);
69 constexpr const char RESOURCED_BUS_NAME[] = "org.tizen.resourced";
70 constexpr const char RESOURCED_PROC_PATH[] = "/Org/Tizen/ResourceD/Process";
71 constexpr const char RESOURCED_PROC_INTERFACE[] = "org.tizen.resourced.process";
72 constexpr const char RESOURCED_PROC_METHOD[] = "ProcExclude";
74 // This should be removed when the client server structure is complete
75 void __send_wakeup_signal_to_resourced(pid_t pid) {
77 GDBusConnection *conn;
81 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
83 _LOGE("Failed to connect to dbus: %s", error->message);
88 proxy = g_dbus_proxy_new_sync(conn,
89 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
90 NULL, RESOURCED_BUS_NAME,
91 RESOURCED_PROC_PATH, RESOURCED_PROC_INTERFACE,
94 _LOGE("failed to get proxy object: %s", error->message);
100 reply = g_dbus_proxy_call_sync(proxy, RESOURCED_PROC_METHOD,
101 g_variant_new("(si)", "wakeup", pid),
102 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
104 _LOGE("failed to get reply from resourced");
106 _LOGE("failed to send request: %s", error->message);
110 g_object_unref(proxy);
111 g_object_unref(conn);
114 void __check_db_lock(const char *dbpath) {
122 unsigned long long ino;
123 char cmdline[BUFSIZE];
127 if (stat(dbpath, &sb) == -1) {
128 _LOGE("get db file(%s) status failed: %d", dbpath, errno);
132 fp = fopen("/proc/locks", "r");
134 _LOGE("Failed to open lock info: %d", errno);
138 while (fscanf(fp, "%*s %*s %*s %5s %d %x:%x:%llu %*s %*s",
139 type, &pid, &maj, &min, &ino) != EOF) {
140 if (maj != major(sb.st_dev) || min != minor(sb.st_dev) ||
141 ino != sb.st_ino || pid == getpid() ||
142 strcasecmp(type, "WRITE"))
145 snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
146 fp_cmdline = fopen(cmdline, "r");
148 if (fp_cmdline != NULL) {
149 len = fread(name, sizeof(char), sizeof(name) - 1,
152 if (name[len - 1] == '\n')
153 name[len - 1] = '\0';
160 _LOGE("%s (%d) has lock on pkgmgr db(%s)!", name, pid, dbpath);
161 __send_wakeup_signal_to_resourced(pid);
167 int __writedb_busy_handler(void *data, int count) {
168 if (count < (BUSY_WAITING_MAX / 2)) {
169 usleep(BUSY_WAITING_USEC);
171 } else if (count == (BUSY_WAITING_MAX / 2)) {
172 __check_db_lock((const char *)data);
173 usleep(BUSY_WAITING_USEC);
175 } else if (count < BUSY_WAITING_MAX) {
176 usleep(BUSY_WAITING_USEC);
179 /* sqlite3_prepare_v2 will return SQLITE_BUSY */
184 int __open_write_db(uid_t uid, const char* path,
185 sqlite3** db, int flags) {
188 ret = sqlite3_open_v2(path, db, flags, NULL);
189 if (ret != SQLITE_OK) {
190 sqlite3_close_v2(*db);
194 ret = sqlite3_busy_handler(*db, __writedb_busy_handler,
195 reinterpret_cast<void*>(const_cast<char*>(path)));
196 if (ret != SQLITE_OK) {
197 _LOGE("failed to register busy handler: %s",
198 sqlite3_errmsg(*db));
199 sqlite3_close_v2(*db);
203 ret = sqlite3_exec(*db, "PRAGMA foreign_keys=ON", NULL, NULL, NULL);
204 if (ret != SQLITE_OK) {
205 _LOGE("failed to enable foreign key support: %s",
206 sqlite3_errmsg(*db));
207 sqlite3_close_v2(*db);
214 int __open_create_db(uid_t uid, const char* path,
215 sqlite3** db, int flags) {
218 ret = sqlite3_open_v2(path, db, flags, NULL);
219 if (ret != SQLITE_OK) {
220 sqlite3_close_v2(*db);
224 ret = sqlite3_busy_handler(*db, __writedb_busy_handler,
225 reinterpret_cast<void*>(const_cast<char*>(path)));
226 if (ret != SQLITE_OK) {
227 _LOGE("failed to register busy handler: %s",
228 sqlite3_errmsg(*db));
229 sqlite3_close_v2(*db);
236 uid_t ConvertUID(uid_t uid) {
237 if (uid < REGULAR_USER)
238 return tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
245 namespace pkgmgr_server {
248 std::shared_timed_mutex AbstractDBHandler::lock_;
250 AbstractDBHandler::AbstractDBHandler(uid_t uid, int pid) {
255 AbstractDBHandler::~AbstractDBHandler() {
256 for (auto& db_handle : db_handle_list_)
257 sqlite3_close_v2(db_handle.first);
260 std::vector<std::pair<std::string, uid_t>> AbstractDBHandler::GetDBPath() {
261 std::vector<std::pair<std::string, uid_t>> db_path;
262 if (db_type_ == pkgmgr_common::DBType::DB_TYPE_FILE_PKGDB)
263 db_path = DBHandleProvider::GetInst(uid_).GetParserDBPath(pid_,
264 op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE);
265 else if (db_type_ == pkgmgr_common::DBType::DB_TYPE_FILE_CERTDB)
266 db_path.emplace_back(
267 std::make_pair(DBHandleProvider::GetInst(uid_).GetCertDBPath(pid_,
268 op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE), uid_));
273 bool AbstractDBHandler::Connect() {
274 if (db_type_ == pkgmgr_common::DBType::DB_TYPE_NONE || op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_NONE) {
278 auto dbpath_list = GetDBPath();
281 for (auto& dbpath : dbpath_list) {
282 if (op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_READ) {
283 ret = __open_read_db(dbpath.first.c_str(), &db, SQLITE_OPEN_READONLY |
285 } else if (op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE) {
286 if (ConvertUID(dbpath.second) != ConvertUID(uid_))
288 ret = __open_write_db(uid_, dbpath.first.c_str(), &db,
289 SQLITE_OPEN_READWRITE);
291 if (ConvertUID(dbpath.second) != ConvertUID(uid_))
294 if (access(dbpath.first.c_str(), F_OK) != -1) {
295 _LOGE("Database for user %d is already exists", uid_);
298 ret = __open_create_db(uid_, dbpath.first.c_str(), &db,
299 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
302 if (ret != SQLITE_OK)
305 db_handle_list_.emplace_back(std::make_pair(db, dbpath.second));
311 void AbstractDBHandler::ClearDBHandle() {
312 for (auto db_handle : db_handle_list_)
313 sqlite3_close_v2(db_handle.first);
315 db_handle_list_.clear();
318 std::vector<std::pair<sqlite3*, uid_t>> AbstractDBHandler::GetConnection() {
319 return db_handle_list_;
322 void AbstractDBHandler::SetOpType(pkgmgr_common::DBOperationType type) {
326 const std::string& AbstractDBHandler::GetLocale() { return locale_; }
328 int AbstractDBHandler::GetPID() { return pid_; }
330 uid_t AbstractDBHandler::GetUID() { return uid_; }
332 void AbstractDBHandler::SetLocale(std::string locale) {
333 locale_ = std::move(locale);
336 void AbstractDBHandler::SetDBType(pkgmgr_common::DBType type) { db_type_ = type; }
338 pkgmgr_common::DBOperationType AbstractDBHandler::GetOpType() {
342 } // namespace database
343 } // namespace pkgmgr_server