Implement pkgmgrinfo_pkginfo_set_installed_storage
[platform/core/appfw/pkgmgr-info.git] / src / common / 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 <sys/stat.h>
21 #include <sys/types.h>
22 #include <sys/sysmacros.h>
23 #include <stdlib.h>
24 #include <tzplatform_config.h>
25
26 #include <string>
27
28 #include "pkgmgr-info.h"
29 #include "pkgmgrinfo_debug.h"
30 #include "pkgmgrinfo_private.h"
31
32 namespace {
33
34 const char kMemoryDBPrefix[] = "file:memdb_";
35 const char kMemoryDBPostFix[] = "?mode=memory&cache=shared";
36
37 uid_t ConvertUID(uid_t uid) {
38   if (uid < REGULAR_USER)
39     return tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
40   else
41     return uid;
42 }
43
44 #define BUSY_WAITING_USEC (1000000 / 10 / 2) /* 0.05 sec */
45 #define BUSY_WAITING_MAX 100 /* wait for max 5 sec */
46
47 static int __readdb_busy_handler(void *data, int count) {
48   if (count < BUSY_WAITING_MAX) {
49     usleep(BUSY_WAITING_USEC);
50     return 1;
51   } else {
52     /* sqlite3_prepare_v2 will return SQLITE_BUSY */
53     return 0;
54   }
55 }
56
57 int __open_read_db(const char *path, sqlite3 **db, int flags) {
58   int ret;
59
60   ret = sqlite3_open_v2(path, db, flags, NULL);
61   if (ret != SQLITE_OK) {
62     sqlite3_close_v2(*db);
63     return ret;
64   }
65
66   ret = sqlite3_busy_handler(*db, __readdb_busy_handler, NULL);
67   if (ret != SQLITE_OK) {
68     _LOGE("failed to register busy handler: %s",
69         sqlite3_errmsg(*db));
70     sqlite3_close_v2(*db);
71     return ret;
72   }
73
74   return ret;
75 }
76
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) {
83   GError *error = NULL;
84   GDBusConnection *conn;
85   GDBusProxy *proxy;
86   GVariant *reply;
87
88   conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
89   if (conn == NULL) {
90     _LOGE("Failed to connect to dbus: %s", error->message);
91     g_error_free(error);
92     return;
93   }
94
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,
99       NULL, &error);
100   if (proxy == NULL) {
101     _LOGE("failed to get proxy object: %s", error->message);
102     g_error_free(error);
103     g_object_unref(conn);
104     return;
105   }
106
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);
110   if (reply == NULL)
111     _LOGE("failed to get reply from resourced");
112   if (error) {
113     _LOGE("failed to send request: %s", error->message);
114     g_error_free(error);
115   }
116
117   g_object_unref(proxy);
118   g_object_unref(conn);
119 }
120
121 static void __check_db_lock(const char *dbpath) {
122   FILE *fp;
123   FILE *fp_cmdline;
124   struct stat sb;
125   char type[BUFSIZE];
126   int pid;
127   unsigned int maj;
128   unsigned int min;
129   unsigned long long ino;
130   char cmdline[BUFSIZE];
131   char name[BUFSIZE];
132   size_t len;
133
134   if (stat(dbpath, &sb) == -1) {
135     _LOGE("get db file(%s) status failed: %d", dbpath, errno);
136     return;
137   }
138
139   fp = fopen("/proc/locks", "r");
140   if (fp == NULL) {
141     _LOGE("Failed to open lock info: %d", errno);
142     return;
143   }
144
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"))
150       continue;
151
152     snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
153     fp_cmdline = fopen(cmdline, "r");
154     name[0] = '\0';
155     if (fp_cmdline != NULL) {
156       len = fread(name, sizeof(char), sizeof(name) - 1,
157           fp_cmdline);
158       if (len > 0) {
159         if (name[len - 1] == '\n')
160           name[len - 1] = '\0';
161         else
162           name[len] = '\0';
163       }
164       fclose(fp_cmdline);
165     }
166
167     _LOGE("%s (%d) has lock on pkgmgr db(%s)!", name, pid, dbpath);
168     __send_wakeup_signal_to_resourced(pid);
169   }
170
171   fclose(fp);
172 }
173
174 static int __writedb_busy_handler(void *data, int count) {
175   if (count < (BUSY_WAITING_MAX / 2)) {
176     usleep(BUSY_WAITING_USEC);
177     return 1;
178   } else if (count == (BUSY_WAITING_MAX / 2)) {
179     __check_db_lock((const char *)data);
180     usleep(BUSY_WAITING_USEC);
181     return 1;
182   } else if (count < BUSY_WAITING_MAX) {
183     usleep(BUSY_WAITING_USEC);
184     return 1;
185   } else {
186     /* sqlite3_prepare_v2 will return SQLITE_BUSY */
187     return 0;
188   }
189 }
190
191 static int __open_write_db(uid_t uid, const char *path, sqlite3 **db, int flags) {
192   int ret;
193
194   ret = sqlite3_open_v2(path, db, flags, NULL);
195   if (ret != SQLITE_OK) {
196     sqlite3_close_v2(*db);
197     return ret;
198   }
199
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);
205     return ret;
206   }
207
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);
213     return ret;
214   }
215
216   return ret;
217 }
218
219 }  // namespace
220
221 namespace pkgmgr_common {
222 namespace database {
223
224 AbstractDBHandler::AbstractDBHandler(uid_t uid) { uid_ = uid; }
225
226 AbstractDBHandler::~AbstractDBHandler() {
227   // Is this necessary?
228   sqlite3_close(db_);
229 }
230
231 std::string AbstractDBHandler::GetDBPath() {
232   std::string db_path;
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_);
239     if (!tmp_dbpath)
240       return "";
241     db_path = tmp_dbpath;
242     free(tmp_dbpath);
243   } else if (db_type_ == DB_TYPE_FILE_CERTDB) {
244     char *tmp_dbpath = getUserPkgCertDBPath();
245     if (!tmp_dbpath)
246       return "";
247     db_path = tmp_dbpath;
248     free(tmp_dbpath);
249   }
250
251   return db_path;
252 }
253
254 bool AbstractDBHandler::Connect() {
255   if (db_type_ == DB_TYPE_NONE || op_type_ == OPERATION_TYPE_NONE) {
256     // error log
257     return false;
258   }
259   std::string db_path = GetDBPath();
260   int flag = 0;
261   int ret = 0;
262   if (op_type_ == OPERATION_TYPE_READ)
263     ret = __open_read_db(db_path.c_str(), &db_, SQLITE_OPEN_READONLY);
264   else
265     ret = __open_write_db(uid_, db_path.c_str(), &db_,
266         SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
267
268   if (ret != SQLITE_OK) {
269     // error log
270     return false;
271   }
272   return true;
273 }
274
275 sqlite3* AbstractDBHandler::GetConnection() { return db_; }
276
277 void AbstractDBHandler::SetOpType(OperationType type) {
278   op_type_ = type;
279 }
280
281 std::string AbstractDBHandler::GetLocale() { return locale_; }
282
283 void AbstractDBHandler::SetLocale(const std::string& locale) {
284   locale_ = locale;
285 }
286
287 void AbstractDBHandler::SetDBType(DBType type) { db_type_ = type; }
288
289 AbstractDBHandler::OperationType AbstractDBHandler::GetOpType() { return op_type_; }
290
291 }  // namespace database
292 }  // namespace pkgmgr_common