Add pkg update info features
[platform/core/appfw/pkgmgr-info.git] / src / pkgmgrinfo_updateinfo.c
1 /*
2  * pkgmgr-info
3  *
4  * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Junghyun Yeon(jungh.yeon@samsung.com>,
7  * Jongmyeong Ko(jongmyeong.ko@samsung.com>, Sangyoon Jang(s89.jang@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 #define _GNU_SOURCE
24 #include <stdlib.h>
25 #include <stdbool.h>
26 #include <ctype.h>
27
28 #include <sqlite3.h>
29 #include <glib.h>
30
31 #include "pkgmgrinfo_basic.h"
32 #include "pkgmgrinfo_private.h"
33 #include "pkgmgrinfo_debug.h"
34 #include "pkgmgr-info.h"
35
36 static void __free_update_info(gpointer data)
37 {
38         updateinfo_x *update_info = (updateinfo_x *)data;
39         if (update_info == NULL)
40                 return;
41
42         if (update_info->pkgid)
43                 free((void *)update_info->pkgid);
44         if (update_info->version)
45                 free((void *)update_info->version);
46         free((void *)update_info);
47
48 }
49
50 static int __convert_update_type(const char *type, pkgmgrinfo_updateinfo_update_type *convert_type)
51 {
52         if (strncasecmp(type, PMINFO_UPDATEINFO_TYPE_NONE,
53                         strlen(PMINFO_UPDATEINFO_TYPE_NONE)) == 0)
54                 *convert_type = PMINFO_UPDATEINFO_NONE;
55         else if (strncasecmp(type, PMINFO_UPDATEINFO_TYPE_FORCE,
56                         strlen(PMINFO_UPDATEINFO_TYPE_FORCE)) == 0)
57                 *convert_type = PMINFO_UPDATEINFO_FORCE;
58         else if (strncasecmp(type, PMINFO_UPDATEINFO_TYPE_OPTIONAL,
59                         strlen(PMINFO_UPDATEINFO_TYPE_OPTIONAL)) == 0)
60                 *convert_type = PMINFO_UPDATEINFO_OPTIONAL;
61         else
62                 return -1;
63         return 0;
64 }
65
66 API int pkgmgrinfo_updateinfo_create(
67                 pkgmgrinfo_updateinfo_h *updateinfo_handle)
68 {
69         updateinfo_x *update_info;
70
71         retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
72                         "Update handle output parameter is NULL\n");
73
74         update_info = (updateinfo_x *)calloc(
75                         1, sizeof(updateinfo_x));
76         if (update_info == NULL) {
77                 _LOGE("Out of memory");
78                 return PMINFO_R_ERROR;
79         }
80
81         *updateinfo_handle = update_info;
82
83         return PMINFO_R_OK;
84 }
85
86 API int pkgmgrinfo_updateinfo_destroy(
87                 pkgmgrinfo_updateinfo_h updateinfo_handle)
88 {
89         retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
90                         "Update info handle parameter is NULL\n");
91
92         __free_update_info(updateinfo_handle);
93         return PMINFO_R_OK;
94 }
95
96 API int pkgmgrinfo_updateinfo_set_pkgid(
97                 pkgmgrinfo_updateinfo_h updateinfo_handle, const char *pkgid)
98 {
99         updateinfo_x *updateinfo;
100
101         retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
102                         "Update info handle parameter is NULL\n");
103         retvm_if(pkgid == NULL, PMINFO_R_EINVAL,
104                                 "pkgid parameter is NULL\n");
105
106         updateinfo = (updateinfo_x *)updateinfo_handle;
107         if (updateinfo->pkgid)
108                 free(updateinfo->pkgid);
109
110         updateinfo->pkgid = strdup(pkgid);
111         if (updateinfo->pkgid == NULL) {
112                 _LOGE("Out of memory");
113                 return PMINFO_R_ERROR;
114         }
115
116         return PMINFO_R_OK;
117 }
118
119 API int pkgmgrinfo_updateinfo_set_version(
120                 pkgmgrinfo_updateinfo_h updateinfo_handle, const char *version)
121 {
122         updateinfo_x *updateinfo;
123
124         retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
125                         "Update info handle parameter is NULL\n");
126         retvm_if(version == NULL, PMINFO_R_EINVAL,
127                                 "pkgid parameter is NULL\n");
128
129         updateinfo = (updateinfo_x *)updateinfo_handle;
130         if (updateinfo->version)
131                 free(updateinfo->version);
132
133         updateinfo->version = strdup(version);
134         if (updateinfo->version == NULL) {
135                 _LOGE("Out of memory");
136                 return PMINFO_R_ERROR;
137         }
138
139         return PMINFO_R_OK;
140 }
141
142 API int pkgmgrinfo_updateinfo_set_type(
143                 pkgmgrinfo_updateinfo_h updateinfo_handle,
144                 pkgmgrinfo_updateinfo_update_type type)
145 {
146         updateinfo_x *updateinfo;
147
148         retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
149                         "Update info handle parameter is NULL\n");
150
151         updateinfo = (updateinfo_x *)updateinfo_handle;
152         updateinfo->type = type;
153         return PMINFO_R_OK;
154 }
155
156 API int pkgmgrinfo_updateinfo_get_pkgid(
157                 pkgmgrinfo_updateinfo_h updateinfo_handle, char **pkgid)
158 {
159         updateinfo_x *update_info;
160
161         retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
162                         "Update info node parameter is NULL\n");
163
164         update_info = (updateinfo_x *)updateinfo_handle;
165         if (update_info->pkgid == NULL)
166                 return PMINFO_R_ERROR;
167
168         *pkgid = update_info->pkgid;
169         return PMINFO_R_OK;
170 }
171
172 API int pkgmgrinfo_updateinfo_get_version(
173                 pkgmgrinfo_updateinfo_h updateinfo_handle, char **version)
174 {
175         updateinfo_x *update_info;
176
177         retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
178                         "Update info node parameter is NULL\n");
179
180         update_info = (updateinfo_x *)updateinfo_handle;
181         if (update_info->version == NULL)
182                 return PMINFO_R_ERROR;
183
184         *version = update_info->version;
185         return PMINFO_R_OK;
186 }
187
188 API int pkgmgrinfo_updateinfo_get_update_type(
189                 pkgmgrinfo_updateinfo_h updateinfo_handle,
190                 pkgmgrinfo_updateinfo_update_type *type)
191 {
192         updateinfo_x *update_info;
193
194         retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
195                         "Update info node parameter is NULL\n");
196
197         update_info = (updateinfo_x *)updateinfo_handle;
198         *type = update_info->type;
199
200         return PMINFO_R_OK;
201 }
202
203 static int _get_pkg_updateinfo_from_db(const char *pkgid,
204                 GSList **update_info_list, uid_t uid)
205 {
206         char *dbpath;
207         char *type;
208         char query[MAX_QUERY_LEN] = { '\0' };
209         int ret;
210         int idx;
211         sqlite3 *db;
212         sqlite3_stmt *stmt;
213         updateinfo_x *update_info = NULL;
214         pkgmgrinfo_updateinfo_update_type convert_type;
215
216         dbpath = getUserPkgParserDBPathUID(uid);
217         if (dbpath == NULL)
218                 return PMINFO_R_ERROR;
219
220         ret = __open_db(dbpath, &db, SQLITE_OPEN_READONLY);
221         if (ret != SQLITE_OK) {
222                 _LOGD("failed to open db: %d", ret);
223                 free(dbpath);
224                 return -1;
225         }
226
227         if (pkgid == NULL)
228                 sqlite3_snprintf(MAX_QUERY_LEN, query,
229                                                 "SELECT package, update_version, update_type " \
230                                                 "FROM package_update_info");
231         else
232                 sqlite3_snprintf(MAX_QUERY_LEN, query,
233                                                 "SELECT package, update_version, update_type " \
234                                                 "FROM package_update_info WHERE package=%Q",
235                                                 pkgid);
236
237         ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
238         if (ret != SQLITE_OK) {
239                 _LOGE("Don't execute query = %s error message = %s\n", query,
240                 sqlite3_errmsg(db));
241                 free(dbpath);
242                 return -1;
243         }
244
245         while (sqlite3_step(stmt) == SQLITE_ROW) {
246                 update_info = calloc(1, sizeof(updateinfo_x));
247                 if (update_info == NULL) {
248                         _LOGE("Out of memory");
249                         free(dbpath);
250                         sqlite3_finalize(stmt);
251                         sqlite3_close_v2(db);
252                         return -1;
253                 }
254                 idx = 0;
255                 _save_column_str(stmt, idx++, &update_info->pkgid);
256                 _save_column_str(stmt, idx++, &update_info->version);
257                 _save_column_str(stmt, idx, &type);
258                 ret = __convert_update_type(type, &convert_type);
259                 if (ret != 0) {
260                         __free_update_info(update_info);
261                         free(dbpath);
262                         sqlite3_finalize(stmt);
263                         sqlite3_close_v2(db);
264                         return -1;
265                 }
266                 update_info->type = convert_type;
267                 *update_info_list = g_slist_append(*update_info_list, update_info);
268         }
269
270         free(dbpath);
271         sqlite3_finalize(stmt);
272         sqlite3_close_v2(db);
273
274         return 0;
275 }
276
277 API int pkgmgrinfo_updateinfo_get_usr_updateinfo(const char *pkgid,
278                 pkgmgrinfo_updateinfo_h *update_handle, uid_t uid)
279 {
280         int ret;
281         pkgmgrinfo_pkginfo_h pkginfo = NULL;
282         bool is_global_pkg;
283         updateinfo_x *update_info;
284         GSList *info_list = NULL;
285
286         if (update_handle == NULL || pkgid == NULL)
287                 return PMINFO_R_EINVAL;
288
289         update_info = calloc(1, sizeof(updateinfo_x));
290         if (update_info == NULL) {
291                 _LOGE("Out of memory");
292                 return PMINFO_R_ERROR;
293         }
294
295         ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, uid, &pkginfo);
296         if (ret != PMINFO_R_OK) {
297                 free(update_info);
298                 return ret;
299         }
300         ret = pkgmgrinfo_pkginfo_is_global(pkginfo, &is_global_pkg);
301         if (ret != PMINFO_R_OK) {
302                 free(update_info);
303                 pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
304                 return ret;
305         }
306         pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
307
308         ret = _get_pkg_updateinfo_from_db(pkgid, &info_list,
309                         (is_global_pkg) ? GLOBAL_USER : uid);
310
311         if (ret != PMINFO_R_OK) {
312                 g_slist_free_full(info_list, __free_update_info);
313                 return PMINFO_R_ERROR;
314         }
315         *update_handle = (pkgmgrinfo_updateinfo_h)info_list->data;
316         g_slist_free(info_list);
317
318         return ret;
319 }
320
321 API int pkgmgrinfo_updateinfo_get_updateinfo(const char *pkgid,
322                 pkgmgrinfo_updateinfo_h *update_handle)
323 {
324         return pkgmgrinfo_updateinfo_get_usr_updateinfo(pkgid, update_handle, _getuid());
325 }
326
327 API int pkgmgrinfo_updateinfo_usr_foreach_updateinfo(uid_t uid,
328                 pkgmgrinfo_foreach_updateinfo_cb callback, void *user_data)
329 {
330         int ret;
331         GSList *info_list;
332         GSList *tmp_list;
333
334         if (callback == NULL)
335                 return PMINFO_R_EINVAL;
336
337         info_list = calloc(1, sizeof(updateinfo_x));
338         if (info_list == NULL) {
339                 _LOGE("Out of memory");
340                 return PMINFO_R_ERROR;
341         }
342
343         ret = _get_pkg_updateinfo_from_db(NULL, &info_list, uid);
344         if (ret != 0) {
345                 _LOGE("Failed to get pkg update info for user[%d]", (int)uid);
346                 pkgmgrinfo_updateinfo_destroy(info_list);
347                 return PMINFO_R_ERROR;
348         }
349
350         ret = _get_pkg_updateinfo_from_db(NULL, &info_list, GLOBAL_USER);
351         if (ret != 0) {
352                 _LOGE("Failed to get pkg update info for user[%d]",
353                                 (int)GLOBAL_USER);
354                 pkgmgrinfo_updateinfo_destroy(info_list);
355                 return PMINFO_R_ERROR;
356         }
357
358         for (tmp_list = info_list; tmp_list; tmp_list = g_slist_next(tmp_list)) {
359                 ret = callback((pkgmgrinfo_updateinfo_h)tmp_list->data, user_data);
360                 if (ret < 0)
361                         break;
362         }
363
364         g_slist_free_full(info_list, __free_update_info);
365         return PMINFO_R_OK;
366 }
367
368 API int pkgmgrinfo_updateinfo_foreach_updateinfo(
369                 pkgmgrinfo_foreach_updateinfo_cb callback, void *user_data)
370 {
371         return pkgmgrinfo_updateinfo_usr_foreach_updateinfo(_getuid(),
372                         callback, user_data);
373 }