Release version 1.6.27
[platform/core/appfw/data-provider-master.git] / src / pkgmgr.c
1 /*
2  * Copyright 2016  Samsung Electronics Co., Ltd
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 <stdio.h>
18 #include <errno.h>
19 #include <stdlib.h>
20
21 #include <dlog.h>
22 #include <package-manager.h>
23
24 #include "service_common.h"
25 #include "debug.h"
26 #include "pkgmgr.h"
27 #include "conf.h"
28
29 #define PKGMGR_EVENT_MIN PKGMGR_EVENT_DOWNLOAD
30 #define PKGMGR_EVENT_MAX PKGMGR_EVENT_APP_DISABLE
31
32 struct item {
33         uid_t uid;
34         char *pkgname;
35         char *icon;
36
37         enum pkgmgr_event_type type;
38         enum pkgmgr_status status;
39 };
40
41 struct event_item {
42         int (*cb)(uid_t uid, const char *pkgname, enum pkgmgr_status status, double value, void *data);
43         void *data;
44 };
45
46 static struct {
47         pkgmgr_client *listen_pc;
48         GList *item_list;
49
50 } s_info = {
51         .listen_pc = NULL,
52         .item_list = NULL,
53 };
54
55 static GList *event_list[PKGMGR_EVENT_MAX + 1];
56
57 static inline void invoke_callback(uid_t uid, const char *pkgname, struct item *item, double value)
58 {
59         GList *l;
60         struct event_item *e_item;
61
62         for (l = event_list[item->type]; l != NULL; l = g_list_next(l)) {
63                 e_item = (struct event_item *)g_list_nth_data(l, 0);
64                 if (e_item->cb)
65                         e_item->cb(uid, pkgname, item->status, value, e_item->data);
66         }
67 }
68
69 static inline int is_valid_status(struct item *item, const char *status)
70 {
71         const char *expected_status;
72
73         switch (item->type) {
74         case PKGMGR_EVENT_DOWNLOAD:
75                 expected_status = "download";
76                 break;
77         case PKGMGR_EVENT_UNINSTALL:
78                 expected_status = "uninstall";
79                 break;
80         case PKGMGR_EVENT_INSTALL:
81                 expected_status = "install";
82                 break;
83         case PKGMGR_EVENT_UPDATE:
84                 expected_status = "update";
85                 break;
86         case PKGMGR_EVENT_RECOVER:
87                 expected_status = "recover";
88                 break;
89         case PKGMGR_EVENT_APP_ENABLE:
90                 expected_status = "app_enable_app";
91                 break;
92         case PKGMGR_EVENT_APP_DISABLE:
93                 expected_status = "app_disable_app";
94                 break;
95         default:
96                 return 0;
97         }
98
99         return !strcasecmp(status, expected_status);
100 }
101
102 static struct item *find_item(const char *pkgname, uid_t uid)
103 {
104         GList *l;
105         struct item *item;
106
107         if (!pkgname) {
108                 ERR("Invalid pkgname");
109                 return NULL;
110         }
111
112         for (l = s_info.item_list; l != NULL; l = g_list_next(l)) {
113                 item = g_list_nth_data(l, 0);
114                 if (uid != item->uid || strcmp(item->pkgname, pkgname))
115                         continue;
116
117                 return item;
118         }
119
120         DBG("Package [%s] is not found", pkgname);
121         return NULL;
122 }
123
124 static int start_cb(uid_t uid, const char *pkgname, const char *val, void *data)
125 {
126         struct item *item;
127
128         INFO("pkgname[%s] val[%s]", pkgname, val);
129
130         item = calloc(1, sizeof(*item));
131         if (!item) {
132                 ERR("calloc [%d]", errno);
133                 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
134         }
135
136         item->pkgname = strdup(pkgname);
137         if (!item->pkgname) {
138                 ERR("strdup [%d]", errno);
139                 free(item);
140                 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
141         }
142
143         item->uid = uid;
144         item->status = PKGMGR_STATUS_START;
145
146         if (!strcasecmp(val, "download")) {
147                 item->type = PKGMGR_EVENT_DOWNLOAD;
148         } else if (!strcasecmp(val, "uninstall")) {
149                 item->type = PKGMGR_EVENT_UNINSTALL;
150         } else if (!strcasecmp(val, "install")) {
151                 item->type = PKGMGR_EVENT_INSTALL;
152         } else if (!strcasecmp(val, "update")) {
153                 item->type = PKGMGR_EVENT_UPDATE;
154         } else if (!strcasecmp(val, "recover")) {
155                 item->type = PKGMGR_EVENT_RECOVER;
156         } else if (!strcasecmp(val, "enable_app")) {
157                 item->type = PKGMGR_EVENT_APP_ENABLE;
158         } else if (!strcasecmp(val, "disable_app")) {
159                 item->type = PKGMGR_EVENT_APP_DISABLE;
160         } else {
161                 free(item->pkgname);
162                 free(item);
163                 ERR("Invalid val [%s]", val);
164                 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
165         }
166         s_info.item_list = g_list_append(s_info.item_list, item);
167
168         invoke_callback(uid, pkgname, item, 0.0f);
169         return SERVICE_COMMON_ERROR_NONE;
170 }
171
172 static int icon_path_cb(uid_t uid, const char *pkgname, const char *val, void *data)
173 {
174         struct item *item;
175
176         DBG("pkgname[%s] val[%s]", pkgname, val);
177
178         item = find_item(pkgname, uid);
179         if (!item)
180                 return SERVICE_COMMON_ERROR_NOT_EXIST;
181
182         if (item->icon)
183                 free(item->icon);
184
185         item->icon = strdup(val);
186         if (!item->icon) {
187                 ERR("strdup [%d]", errno);
188                 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
189         }
190
191         return SERVICE_COMMON_ERROR_NONE;
192 }
193
194 static int command_cb(uid_t uid, const char *pkgname, const char *val, void *data)
195 {
196         struct item *item;
197
198         DBG("pkgname[%s] val[%s]", pkgname, val);
199
200         item = find_item(pkgname, uid);
201         if (!item)
202                 return SERVICE_COMMON_ERROR_NOT_EXIST;
203
204         if (!is_valid_status(item, val)) {
205                 DBG("Invalid status[%d] val[%s]", item->type, val);
206                 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
207         }
208
209         item->status = PKGMGR_STATUS_COMMAND;
210         invoke_callback(uid, pkgname, item, 0.0f);
211         return SERVICE_COMMON_ERROR_NONE;
212 }
213
214 static int error_cb(uid_t uid, const char *pkgname, const char *val, void *data)
215 {
216         /* val = error */
217         struct item *item;
218
219         INFO("pkgname[%s] val[%s]", pkgname, val);
220
221         item = find_item(pkgname, uid);
222         if (!item)
223                 return SERVICE_COMMON_ERROR_NOT_EXIST;
224
225         item->status = PKGMGR_STATUS_ERROR;
226         invoke_callback(uid, pkgname, item, 0.0f);
227         return SERVICE_COMMON_ERROR_NONE;
228 }
229
230 static int change_pkgname_cb(uid_t uid, const char *pkgname, const char *val, void *data)
231 {
232         struct item *item;
233         char *new_pkgname;
234
235         INFO("pkgname[%s] val[%s]", pkgname, val);
236
237         item = find_item(pkgname, uid);
238         if (!item)
239                 return SERVICE_COMMON_ERROR_NOT_EXIST;
240
241         new_pkgname = strdup(val);
242         if (!new_pkgname) {
243                 ERR("strdup: %d", errno);
244                 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
245         }
246
247         free(item->pkgname);
248         item->pkgname = new_pkgname;
249         return SERVICE_COMMON_ERROR_NONE;
250 }
251
252 static int download_cb(uid_t uid, const char *pkgname, const char *val, void *data)
253 {
254         /* val = integer */
255         struct item *item;
256         double value;
257
258         INFO("pkgname[%s] val[%s]", pkgname, val);
259
260         item = find_item(pkgname, uid);
261         if (!item) {
262                 DBG("ITEM is not started from the start_cb");
263                 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
264         }
265
266         if (item->type != PKGMGR_EVENT_DOWNLOAD) {
267                 DBG("TYPE is not \"download\" [%d]", item->type);
268                 item->type = PKGMGR_EVENT_DOWNLOAD;
269         }
270
271         switch (item->status) {
272         case PKGMGR_STATUS_START:
273         case PKGMGR_STATUS_COMMAND:
274                 item->status = PKGMGR_STATUS_PROCESSING;
275         case PKGMGR_STATUS_PROCESSING:
276                 break;
277         default:
278                 ERR("Invalid status, pkgname[%s] val[%s]", pkgname, val);
279                 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
280         }
281
282         if (val) {
283                 if (sscanf(val, "%lf", &value) != 1)
284                         value = (double)SERVICE_COMMON_ERROR_INVALID_PARAMETER;
285         } else {
286                 value = (double)SERVICE_COMMON_ERROR_INVALID_PARAMETER;
287         }
288
289         invoke_callback(uid, pkgname, item, value);
290         return SERVICE_COMMON_ERROR_NONE;
291 }
292
293 static int progress_cb(uid_t uid, const char *pkgname, const char *val, void *data)
294 {
295         /* val = integer */
296         struct item *item;
297         double value;
298
299         item = find_item(pkgname, uid);
300         if (!item) {
301                 ERR("ITEM is not started from the start_cb");
302                 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
303         }
304
305         switch (item->status) {
306         case PKGMGR_STATUS_START:
307         case PKGMGR_STATUS_COMMAND:
308                 item->status = PKGMGR_STATUS_PROCESSING;
309         case PKGMGR_STATUS_PROCESSING:
310                 break;
311         default:
312                 ERR("Invalid status, pkgname[%s] val[%s]", pkgname, val);
313                 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
314         }
315
316         if (val) {
317                 if (sscanf(val, "%lf", &value) != 1)
318                         value = (double)SERVICE_COMMON_ERROR_INVALID_PARAMETER;
319         } else {
320                 value = (double)SERVICE_COMMON_ERROR_INVALID_PARAMETER;
321         }
322
323         invoke_callback(uid, pkgname, item, value);
324         return SERVICE_COMMON_ERROR_NONE;
325 }
326
327 static int end_cb(uid_t uid, const char *pkgname, const char *val, void *data)
328 {
329         struct item *item;
330
331         DBG("[%s] %s", pkgname, val);
332
333         item = find_item(pkgname, uid);
334         if (!item)
335                 return SERVICE_COMMON_ERROR_NOT_EXIST;
336
337         item->status = !strcasecmp(val, "ok") ? PKGMGR_STATUS_END : PKGMGR_STATUS_ERROR;
338
339         invoke_callback(uid, pkgname, item, 0.0f);
340
341         s_info.item_list = g_list_remove(s_info.item_list, item);
342         free(item->icon);
343         free(item->pkgname);
344         free(item);
345         return SERVICE_COMMON_ERROR_NONE;
346 }
347
348 static struct pkgmgr_handler {
349         const char *key;
350         int (*func)(uid_t uid, const char *package, const char *val, void *data);
351 } handler[] = {
352         { "install_percent", progress_cb },
353         { "download_percent", download_cb },
354         { "start", start_cb },
355         { "end", end_cb },
356         { "change_pkg_name", change_pkgname_cb },
357         { "icon_path", icon_path_cb },
358         { "command", command_cb },
359         { "error", error_cb },
360         { NULL, NULL },
361 };
362
363 static int status_cb(uid_t target_uid, int req_id, const char *type,
364                 const char *pkgname, const char *key, const char *val,
365                 const void *pmsg, void *data)
366 {
367         register int i;
368         int ret;
369
370         for (i = 0; handler[i].key; i++) {
371                 if (strcasecmp(key, handler[i].key))
372                         continue;
373
374                 ret = handler[i].func(target_uid, pkgname, val, data);
375                 if (ret < 0) {
376                         DBG("REQ[%d] UID[%d] pkgname[%s] type[%s] key[%s] val[%s] ret[%d]",
377                                         req_id, target_uid, pkgname, type, key, val, ret);
378                 }
379         }
380
381         return SERVICE_COMMON_ERROR_NONE;
382 }
383
384 static int app_status_cb(uid_t target_uid, int req_id, const char *pkg_type,
385                 const char *pkgid, const char *appid, const char *key, const char *val,
386                 const void *pmsg, void *data)
387 {
388         register int i;
389         int ret;
390
391         for (i = 0; handler[i].key; i++) {
392                 if (strcasecmp(key, handler[i].key))
393                         continue;
394
395                 ret = handler[i].func(target_uid, appid, val, data);
396                 if (ret < 0) {
397                         DBG("REQ[%d] UID[%d] appid[%s] type[%s] key[%s] val[%s] ret[%d]",
398                                         req_id, target_uid, appid, pkg_type, key, val, ret);
399                 }
400         }
401
402         return SERVICE_COMMON_ERROR_NONE;
403 }
404
405 static void __free_event_data(gpointer data)
406 {
407         struct event_item *item = (struct event_item *)data;
408
409         if (item)
410                 free(item);
411 }
412
413 static void __free_item_data(gpointer data)
414 {
415         struct item *ctx = (struct item *)data;
416
417         if (ctx) {
418                 if (ctx->pkgname)
419                         free(ctx->pkgname);
420                 if (ctx->icon)
421                         free(ctx->icon);
422                 free(ctx);
423         }
424 }
425
426 HAPI int pkgmgr_init(void)
427 {
428         if (s_info.listen_pc)
429                 return SERVICE_COMMON_ERROR_ALREADY_EXIST;
430
431         s_info.listen_pc = pkgmgr_client_new(PC_LISTENING);
432         if (!s_info.listen_pc)
433                 return SERVICE_COMMON_ERROR_FAULT;
434
435         /* the pkgmgr api returns an id greater than 1 */
436         if (pkgmgr_client_listen_status(s_info.listen_pc, status_cb, NULL) <= 0)
437                 return SERVICE_COMMON_ERROR_FAULT;
438
439         if (pkgmgr_client_listen_app_status(s_info.listen_pc, app_status_cb, NULL) <= 0)
440                 return SERVICE_COMMON_ERROR_FAULT;
441
442         return SERVICE_COMMON_ERROR_NONE;
443 }
444
445 HAPI int pkgmgr_fini(void)
446 {
447         int i;
448
449         if (!s_info.listen_pc)
450                 return SERVICE_COMMON_ERROR_INVALID_PARAMETER;
451
452         if (pkgmgr_client_free(s_info.listen_pc) != PKGMGR_R_OK)
453                 return SERVICE_COMMON_ERROR_FAULT;
454
455         s_info.listen_pc = NULL;
456
457         for (i = PKGMGR_EVENT_MIN; i <= PKGMGR_EVENT_MAX; i++)
458                 g_list_free_full(event_list[i], __free_event_data);
459
460         g_list_free_full(s_info.item_list, __free_item_data);
461
462         return SERVICE_COMMON_ERROR_NONE;
463 }
464
465 HAPI int pkgmgr_add_event_callback(enum pkgmgr_event_type type, int (*cb)(uid_t uid, const char *pkgname, enum pkgmgr_status status, double value, void *data), void *data)
466 {
467         struct event_item *item;
468
469         item = calloc(1, sizeof(*item));
470         if (!item) {
471                 ERR("calloc [%d]", errno);
472                 return SERVICE_COMMON_ERROR_OUT_OF_MEMORY;
473         }
474
475         item->cb = cb;
476         item->data = data;
477
478         event_list[type] = g_list_prepend(event_list[type], item);
479
480         return SERVICE_COMMON_ERROR_NONE;
481 }
482
483 HAPI void *pkgmgr_del_event_callback(enum pkgmgr_event_type type, int (*cb)(uid_t uid, const char *pkgname, enum pkgmgr_status status, double value, void *data), void *data)
484 {
485         struct event_item *item;
486         GList *l;
487         void *cbdata = NULL;
488
489         for (l = event_list[type]; l != NULL; l = g_list_next(l)) {
490                 item = g_list_nth_data(l, 0);
491                 if (item->cb == cb && item->data == data) {
492                         event_list[type] = g_list_remove(event_list[type], item);
493                         cbdata = item->data;
494                         free(item);
495                         break;
496                 }
497         }
498
499         return cbdata;
500 }
501
502 /* End of a file */