Fix static analysis issues
[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 "utils/logging.hh"
31
32 #include "pkgmgr-info.h"
33 #include "pkgmgrinfo_debug.h"
34 #include "pkgmgrinfo_private.h"
35
36 namespace {
37
38 constexpr useconds_t BUSY_WAITING_USEC = (1000000 / 10 / 2); /* 0.05 sec */
39 constexpr int BUSY_WAITING_MAX = 100; /* wait for max 5 sec */
40
41 int __readdb_busy_handler(void *data, int count) {
42   if (count < BUSY_WAITING_MAX) {
43     usleep(BUSY_WAITING_USEC);
44     return 1;
45   } else {
46     /* sqlite3_prepare_v2 will return SQLITE_BUSY */
47     return 0;
48   }
49 }
50
51 int __open_read_db(const char *path, sqlite3 **db) {
52   int ret;
53
54   ret = sqlite3_open_v2(path, db,
55       SQLITE_OPEN_READONLY | SQLITE_OPEN_URI, NULL);
56   if (ret != SQLITE_OK) {
57     sqlite3_close_v2(*db);
58     return ret;
59   }
60
61   ret = sqlite3_busy_handler(*db, __readdb_busy_handler, NULL);
62   if (ret != SQLITE_OK) {
63     LOG(ERROR) << "failed to register busy handler:" << sqlite3_errmsg(*db);
64     sqlite3_close_v2(*db);
65     return ret;
66   }
67
68   return ret;
69 }
70
71 constexpr const char RESOURCED_BUS_NAME[] = "org.tizen.resourced";
72 constexpr const char RESOURCED_PROC_PATH[] = "/Org/Tizen/ResourceD/Process";
73 constexpr const char RESOURCED_PROC_INTERFACE[] = "org.tizen.resourced.process";
74 constexpr const char RESOURCED_PROC_METHOD[] = "ProcExclude";
75
76 int __writedb_busy_handler(void *data, int count) {
77   if (count < (BUSY_WAITING_MAX / 2)) {
78     usleep(BUSY_WAITING_USEC);
79     return 1;
80   } else if (count < BUSY_WAITING_MAX) {
81     usleep(BUSY_WAITING_USEC);
82     return 1;
83   } else {
84     /* sqlite3_prepare_v2 will return SQLITE_BUSY */
85     return 0;
86   }
87 }
88
89 int __open_write_db(uid_t uid, const char* path,
90     sqlite3** db) {
91   int ret;
92
93   ret = sqlite3_open_v2(path, db, SQLITE_OPEN_READWRITE, NULL);
94   if (ret != SQLITE_OK) {
95     sqlite3_close_v2(*db);
96     return ret;
97   }
98
99   ret = sqlite3_busy_handler(*db, __writedb_busy_handler,
100       reinterpret_cast<void*>(const_cast<char*>(path)));
101   if (ret != SQLITE_OK) {
102     LOG(ERROR) << "failed to register busy handler:" << 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     LOG(ERROR) << "failed to enable foreign key support:"
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     LOG(ERROR) << "failed to register busy handler:" << sqlite3_errmsg(*db);
133     sqlite3_close_v2(*db);
134     return ret;
135   }
136
137   return ret;
138 }
139
140 static uid_t globaluser_uid = -1;
141
142 uid_t ConvertUID(uid_t uid) {
143   if (uid < REGULAR_USER) {
144     if (globaluser_uid == (uid_t)-1)
145       globaluser_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
146
147     return globaluser_uid;
148   } else {
149     return uid;
150   }
151 }
152
153 }  // namespace
154
155 namespace pkgmgr_server {
156 namespace database {
157
158 std::shared_mutex AbstractDBHandler::lock_;
159
160 AbstractDBHandler::~AbstractDBHandler() {
161   for (auto& db_handle : db_handle_list_)
162     sqlite3_close_v2(db_handle.first);
163 }
164
165 std::vector<std::pair<std::string, uid_t>> AbstractDBHandler::GetDBPath() {
166   std::vector<std::pair<std::string, uid_t>> db_path;
167   if (db_type_ == pkgmgr_common::DBType::DB_TYPE_FILE_PKGDB)
168     db_path = DBHandleProvider::GetInst(uid_).GetParserDBPath(pid_,
169         op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE);
170   else if (db_type_ == pkgmgr_common::DBType::DB_TYPE_FILE_CERTDB)
171     db_path.emplace_back(
172         std::make_pair(DBHandleProvider::GetInst(uid_).GetCertDBPath(pid_,
173             op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE),
174             uid_));
175
176   return db_path;
177 }
178
179 bool AbstractDBHandler::Connect() {
180   if (db_type_ == pkgmgr_common::DBType::DB_TYPE_NONE ||
181       op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_NONE) {
182     LOG(ERROR) << "Invalid parameter";
183     return false;
184   }
185
186   auto dbpath_list = GetDBPath();
187   sqlite3* db;
188   for (auto& dbpath : dbpath_list) {
189     int ret = 0;
190     if (op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_READ) {
191       ret = __open_read_db(dbpath.first.c_str(), &db);
192     } else if (
193         op_type_ == pkgmgr_common::DBOperationType::OPERATION_TYPE_WRITE) {
194       if (ConvertUID(dbpath.second) != ConvertUID(uid_))
195         continue;
196       ret = __open_write_db(uid_, dbpath.first.c_str(), &db);
197     } else {
198       if (ConvertUID(dbpath.second) != ConvertUID(uid_))
199         continue;
200
201       if (access(dbpath.first.c_str(), F_OK) != -1) {
202         LOG(ERROR) << "Database for user " << uid_ << " is already exists";
203         return false;
204       }
205       ret = __open_create_db(uid_, dbpath.first.c_str(), &db);
206     }
207
208     if (ret != SQLITE_OK)
209       return false;
210
211     db_handle_list_.emplace_back(std::make_pair(db, dbpath.second));
212   }
213
214   return true;
215 }
216
217 void AbstractDBHandler::ClearDBHandle() {
218   for (const auto& db_handle : db_handle_list_)
219     sqlite3_close_v2(db_handle.first);
220
221   db_handle_list_.clear();
222 }
223
224 std::vector<std::pair<sqlite3*, uid_t>> AbstractDBHandler::GetConnection() {
225   return db_handle_list_;
226 }
227
228 void AbstractDBHandler::SetOpType(pkgmgr_common::DBOperationType type) {
229   op_type_ = type;
230 }
231
232 const std::string& AbstractDBHandler::GetLocale() {
233   return locale_;
234 }
235
236 int AbstractDBHandler::GetPID() {
237   return pid_;
238 }
239
240 uid_t AbstractDBHandler::GetUID() {
241   return uid_;
242 }
243
244 void AbstractDBHandler::SetLocale(std::string locale) {
245   locale_ = std::move(locale);
246 }
247
248 void AbstractDBHandler::SetDBType(pkgmgr_common::DBType type) {
249   db_type_ = type;
250 }
251
252 pkgmgr_common::DBOperationType AbstractDBHandler::GetOpType() {
253   return op_type_;
254 }
255
256 uid_t AbstractDBHandler::GetDefaultUser() {
257   static uid_t default_user = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
258
259   return default_user;
260 }
261
262 }  // namespace database
263 }  // namespace pkgmgr_server