Merge branch 'tizen' of ssh://review.tizen.org:29418/platform/core/appfw/pkgmgr-info
[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, int flags) {
50   int ret;
51
52   ret = sqlite3_open_v2(path, db, flags, NULL);
53   if (ret != SQLITE_OK) {
54     sqlite3_close_v2(*db);
55     return ret;
56   }
57
58   ret = sqlite3_busy_handler(*db, __readdb_busy_handler, NULL);
59   if (ret != SQLITE_OK) {
60     _LOGE("failed to register busy handler: %s",
61         sqlite3_errmsg(*db));
62     sqlite3_close_v2(*db);
63     return ret;
64   }
65
66   return ret;
67 }
68
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";
73
74 // This should be removed when the client server structure is complete
75 void __send_wakeup_signal_to_resourced(pid_t pid) {
76   GError *error = NULL;
77   GDBusConnection *conn;
78   GDBusProxy *proxy;
79   GVariant *reply;
80
81   conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
82   if (conn == NULL) {
83     _LOGE("Failed to connect to dbus: %s", error->message);
84     g_error_free(error);
85     return;
86   }
87
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,
92       NULL, &error);
93   if (proxy == NULL) {
94     _LOGE("failed to get proxy object: %s", error->message);
95     g_error_free(error);
96     g_object_unref(conn);
97     return;
98   }
99
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);
103   if (reply == NULL)
104     _LOGE("failed to get reply from resourced");
105   if (error) {
106     _LOGE("failed to send request: %s", error->message);
107     g_error_free(error);
108   }
109
110   g_object_unref(proxy);
111   g_object_unref(conn);
112 }
113
114 void __check_db_lock(const char *dbpath) {
115   FILE *fp;
116   FILE *fp_cmdline;
117   struct stat sb;
118   char type[BUFSIZE];
119   int pid;
120   unsigned int maj;
121   unsigned int min;
122   unsigned long long ino;
123   char cmdline[BUFSIZE];
124   char name[BUFSIZE];
125   size_t len;
126
127   if (stat(dbpath, &sb) == -1) {
128     _LOGE("get db file(%s) status failed: %d", dbpath, errno);
129     return;
130   }
131
132   fp = fopen("/proc/locks", "r");
133   if (fp == NULL) {
134     _LOGE("Failed to open lock info: %d", errno);
135     return;
136   }
137
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"))
143       continue;
144
145     snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
146     fp_cmdline = fopen(cmdline, "r");
147     name[0] = '\0';
148     if (fp_cmdline != NULL) {
149       len = fread(name, sizeof(char), sizeof(name) - 1,
150           fp_cmdline);
151       if (len > 0) {
152         if (name[len - 1] == '\n')
153           name[len - 1] = '\0';
154         else
155           name[len] = '\0';
156       }
157       fclose(fp_cmdline);
158     }
159
160     _LOGE("%s (%d) has lock on pkgmgr db(%s)!", name, pid, dbpath);
161     __send_wakeup_signal_to_resourced(pid);
162   }
163
164   fclose(fp);
165 }
166
167 int __writedb_busy_handler(void *data, int count) {
168   if (count < (BUSY_WAITING_MAX / 2)) {
169     usleep(BUSY_WAITING_USEC);
170     return 1;
171   } else if (count == (BUSY_WAITING_MAX / 2)) {
172     __check_db_lock((const char *)data);
173     usleep(BUSY_WAITING_USEC);
174     return 1;
175   } else if (count < BUSY_WAITING_MAX) {
176     usleep(BUSY_WAITING_USEC);
177     return 1;
178   } else {
179     /* sqlite3_prepare_v2 will return SQLITE_BUSY */
180     return 0;
181   }
182 }
183
184 int __open_write_db(uid_t uid, const char* path,
185     sqlite3** db, int flags) {
186   int ret;
187
188   ret = sqlite3_open_v2(path, db, flags, NULL);
189   if (ret != SQLITE_OK) {
190     sqlite3_close_v2(*db);
191     return ret;
192   }
193
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);
200     return ret;
201   }
202
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);
208     return ret;
209   }
210
211   return ret;
212 }
213
214 int __open_create_db(uid_t uid, const char* path,
215     sqlite3** db, int flags) {
216   int ret;
217
218   ret = sqlite3_open_v2(path, db, flags, NULL);
219   if (ret != SQLITE_OK) {
220     sqlite3_close_v2(*db);
221     return ret;
222   }
223
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);
230     return ret;
231   }
232
233   return ret;
234 }
235
236 uid_t ConvertUID(uid_t uid) {
237   if (uid < REGULAR_USER)
238     return tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
239   else
240     return uid;
241 }
242
243 }  // namespace
244
245 namespace pkgmgr_server {
246 namespace database {
247
248 std::shared_timed_mutex AbstractDBHandler::lock_;
249
250 AbstractDBHandler::AbstractDBHandler(uid_t uid, int pid) {
251   uid_ = uid;
252   pid_ = pid;
253 }
254
255 AbstractDBHandler::~AbstractDBHandler() {
256   for (auto& db_handle : db_handle_list_)
257     sqlite3_close_v2(db_handle.first);
258 }
259
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_));
269
270   return db_path;
271 }
272
273 bool AbstractDBHandler::Connect() {
274   if (db_type_ == pkgmgr_common::DBType::DB_TYPE_NONE || op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_NONE) {
275     // error log
276     return false;
277   }
278   auto dbpath_list = GetDBPath();
279   int ret = 0;
280   sqlite3* db;
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 |
284           SQLITE_OPEN_URI);
285     } else if (op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE) {
286       if (ConvertUID(dbpath.second) != ConvertUID(uid_))
287         continue;
288       ret = __open_write_db(uid_, dbpath.first.c_str(), &db,
289           SQLITE_OPEN_READWRITE);
290     } else {
291       if (ConvertUID(dbpath.second) != ConvertUID(uid_))
292         continue;
293
294       if (access(dbpath.first.c_str(), F_OK) != -1) {
295         _LOGE("Database for user %d is already exists", uid_);
296         return false;
297       }
298       ret = __open_create_db(uid_, dbpath.first.c_str(), &db,
299           SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
300     }
301
302     if (ret != SQLITE_OK)
303       return false;
304
305     db_handle_list_.emplace_back(std::make_pair(db, dbpath.second));
306   }
307
308   return true;
309 }
310
311 void AbstractDBHandler::ClearDBHandle() {
312   for (auto db_handle : db_handle_list_)
313     sqlite3_close_v2(db_handle.first);
314
315   db_handle_list_.clear();
316 }
317
318 std::vector<std::pair<sqlite3*, uid_t>> AbstractDBHandler::GetConnection() {
319   return db_handle_list_;
320 }
321
322 void AbstractDBHandler::SetOpType(pkgmgr_common::DBOperationType type) {
323   op_type_ = type;
324 }
325
326 const std::string& AbstractDBHandler::GetLocale() { return locale_; }
327
328 int AbstractDBHandler::GetPID() { return pid_; }
329
330 uid_t AbstractDBHandler::GetUID() { return uid_; }
331
332 void AbstractDBHandler::SetLocale(std::string locale) {
333   locale_ = std::move(locale);
334 }
335
336 void AbstractDBHandler::SetDBType(pkgmgr_common::DBType type) { db_type_ = type; }
337
338 pkgmgr_common::DBOperationType AbstractDBHandler::GetOpType() {
339   return op_type_;
340 }
341
342 }  // namespace database
343 }  // namespace pkgmgr_server