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"
21 #include <sys/types.h>
22 #include <sys/sysmacros.h>
24 #include <tzplatform_config.h>
28 #include "pkgmgr-info.h"
29 #include "pkgmgrinfo_debug.h"
30 #include "pkgmgrinfo_private.h"
34 const char kMemoryDBPrefix[] = "file:memdb_";
35 const char kMemoryDBPostFix[] = "?mode=memory&cache=shared";
37 uid_t ConvertUID(uid_t uid) {
38 if (uid < REGULAR_USER)
39 return tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
44 #define BUSY_WAITING_USEC (1000000 / 10 / 2) /* 0.05 sec */
45 #define BUSY_WAITING_MAX 100 /* wait for max 5 sec */
47 static int __readdb_busy_handler(void *data, int count) {
48 if (count < BUSY_WAITING_MAX) {
49 usleep(BUSY_WAITING_USEC);
52 /* sqlite3_prepare_v2 will return SQLITE_BUSY */
57 int __open_read_db(const char *path, sqlite3 **db, int flags) {
60 ret = sqlite3_open_v2(path, db, flags, NULL);
61 if (ret != SQLITE_OK) {
62 sqlite3_close_v2(*db);
66 ret = sqlite3_busy_handler(*db, __readdb_busy_handler, NULL);
67 if (ret != SQLITE_OK) {
68 _LOGE("failed to register busy handler: %s",
70 sqlite3_close_v2(*db);
77 #define RESOURCED_BUS_NAME "org.tizen.resourced"
78 #define RESOURCED_PROC_PATH "/Org/Tizen/ResourceD/Process"
79 #define RESOURCED_PROC_INTERFACE "org.tizen.resourced.process"
80 #define RESOURCED_PROC_METHOD "ProcExclude"
81 // This should be removed when the client server structure is complete
82 static void __send_wakeup_signal_to_resourced(pid_t pid) {
84 GDBusConnection *conn;
88 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
90 _LOGE("Failed to connect to dbus: %s", error->message);
95 proxy = g_dbus_proxy_new_sync(conn,
96 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
97 NULL, RESOURCED_BUS_NAME,
98 RESOURCED_PROC_PATH, RESOURCED_PROC_INTERFACE,
101 _LOGE("failed to get proxy object: %s", error->message);
103 g_object_unref(conn);
107 reply = g_dbus_proxy_call_sync(proxy, RESOURCED_PROC_METHOD,
108 g_variant_new("(si)", "wakeup", pid),
109 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
111 _LOGE("failed to get reply from resourced");
113 _LOGE("failed to send request: %s", error->message);
117 g_object_unref(proxy);
118 g_object_unref(conn);
121 static void __check_db_lock(const char *dbpath) {
129 unsigned long long ino;
130 char cmdline[BUFSIZE];
134 if (stat(dbpath, &sb) == -1) {
135 _LOGE("get db file(%s) status failed: %d", dbpath, errno);
139 fp = fopen("/proc/locks", "r");
141 _LOGE("Failed to open lock info: %d", errno);
145 while (fscanf(fp, "%*s %*s %*s %5s %d %x:%x:%llu %*s %*s",
146 type, &pid, &maj, &min, &ino) != EOF) {
147 if (maj != major(sb.st_dev) || min != minor(sb.st_dev) ||
148 ino != sb.st_ino || pid == getpid() ||
149 strcasecmp(type, "WRITE"))
152 snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
153 fp_cmdline = fopen(cmdline, "r");
155 if (fp_cmdline != NULL) {
156 len = fread(name, sizeof(char), sizeof(name) - 1,
159 if (name[len - 1] == '\n')
160 name[len - 1] = '\0';
167 _LOGE("%s (%d) has lock on pkgmgr db(%s)!", name, pid, dbpath);
168 __send_wakeup_signal_to_resourced(pid);
174 static int __writedb_busy_handler(void *data, int count) {
175 if (count < (BUSY_WAITING_MAX / 2)) {
176 usleep(BUSY_WAITING_USEC);
178 } else if (count == (BUSY_WAITING_MAX / 2)) {
179 __check_db_lock((const char *)data);
180 usleep(BUSY_WAITING_USEC);
182 } else if (count < BUSY_WAITING_MAX) {
183 usleep(BUSY_WAITING_USEC);
186 /* sqlite3_prepare_v2 will return SQLITE_BUSY */
191 static int __open_write_db(uid_t uid, const char *path, sqlite3 **db, int flags) {
194 ret = sqlite3_open_v2(path, db, flags, NULL);
195 if (ret != SQLITE_OK) {
196 sqlite3_close_v2(*db);
200 ret = sqlite3_busy_handler(*db, __writedb_busy_handler, (void *)path);
201 if (ret != SQLITE_OK) {
202 _LOGE("failed to register busy handler: %s",
203 sqlite3_errmsg(*db));
204 sqlite3_close_v2(*db);
208 ret = sqlite3_exec(*db, "PRAGMA foreign_keys=ON", NULL, NULL, NULL);
209 if (ret != SQLITE_OK) {
210 _LOGE("failed to enable foreign key support: %s",
211 sqlite3_errmsg(*db));
212 sqlite3_close_v2(*db);
221 namespace pkgmgr_common {
224 AbstractDBHandler::AbstractDBHandler(uid_t uid) { uid_ = uid; }
226 AbstractDBHandler::~AbstractDBHandler() {
227 // Is this necessary?
231 std::string AbstractDBHandler::GetDBPath() {
233 if (db_type_ == DB_TYPE_MEMORY_PKGDB) {
234 db_path += kMemoryDBPrefix;
235 db_path += std::to_string(ConvertUID(uid_));
236 db_path += kMemoryDBPostFix;
237 } else if (db_type_ == DB_TYPE_FILE_PKGDB) {
238 char* tmp_dbpath = getUserPkgParserDBPathUID(uid_);
241 db_path = tmp_dbpath;
243 } else if (db_type_ == DB_TYPE_FILE_CERTDB) {
244 char *tmp_dbpath = getUserPkgCertDBPath();
247 db_path = tmp_dbpath;
254 bool AbstractDBHandler::Connect() {
255 if (db_type_ == DB_TYPE_NONE || op_type_ == OPERATION_TYPE_NONE) {
259 std::string db_path = GetDBPath();
262 if (op_type_ == OPERATION_TYPE_READ)
263 ret = __open_read_db(db_path.c_str(), &db_, SQLITE_OPEN_READONLY);
265 ret = __open_write_db(uid_, db_path.c_str(), &db_,
266 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
268 if (ret != SQLITE_OK) {
275 sqlite3* AbstractDBHandler::GetConnection() { return db_; }
277 void AbstractDBHandler::SetOpType(OperationType type) {
281 std::string AbstractDBHandler::GetLocale() { return locale_; }
283 void AbstractDBHandler::SetLocale(const std::string& locale) {
287 void AbstractDBHandler::SetDBType(DBType type) { db_type_ = type; }
289 } // namespace database
290 } // namespace pkgmgr_common