Check privilege via dbus-daemon
[platform/core/appfw/slp-pkgmgr.git] / server / src / pm-queue.c
1 /*
2  * slp-pkgmgr
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>,
7  * Jaeho Lee <jaeho81.lee@samsung.com>, Shobhit Srivastava <shobhit.s@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 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <dirent.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30
31 #include "pkgmgr-server.h"
32 #include "pm-queue.h"
33
34 #define BACKEND_INFO_DIR        "/etc/package-manager/backend"
35
36 static pm_queue_data *__get_head_from_pkgtype(pm_dbus_msg *item);
37 static void __update_head_from_pkgtype(pm_queue_data *data);
38 static int __entry_exist(char *backend);
39 static int __is_pkg_supported(char *pkgtype);
40
41 queue_info_map *start = NULL;
42 int entries = 0;
43 int slot = 0;
44 int num_of_backends = 0;
45
46 /*Function to check whether a particular package type
47 is supported or not. It parses the queue info map
48 to get the information.
49 It will prevent the accidental hanging of server.
50 Returns 1 if found.*/
51 static int __is_pkg_supported(char *pkgtype)
52 {
53         queue_info_map *ptr = NULL;
54         ptr = start;
55         int i = 0;
56         for(i = 0; i < entries; i++)
57         {
58                 if (!strncmp(ptr->pkgtype, pkgtype, MAX_PKG_TYPE_LEN))
59                         return 1;
60                 else {
61                         ptr++;
62                         continue;
63                 }
64         }
65         return 0;
66 }
67
68 /*tells whether a particular backend exists in the
69 * info map or not.
70 * on Success it return the queue slot of the already present entry
71 * on Failure -1 is returned*/
72 static int __entry_exist(char *backend)
73 {
74         queue_info_map *ptr = NULL;
75         ptr = start;
76         int i = 0;
77         for(i = 0; i < entries; i++)
78         {
79                 if (!strncmp(ptr->backend, backend, MAX_PKG_NAME_LEN))
80                         return ptr->queue_slot;
81                 else {
82                         ptr++;
83                         continue;
84                 }
85         }
86         return -1;
87 }
88
89 /*In case of first push, it updates the queue head
90 and copies it to all duplicate entries in queue info map*/
91 static void __update_head_from_pkgtype(pm_queue_data *data)
92 {
93         queue_info_map *ptr = NULL;
94         ptr = start;
95         int slot = -1;
96         int i = 0;
97         for(i = 0; i < entries; i++)
98         {
99                 if (!strncmp(ptr->pkgtype, data->msg->pkg_type, MAX_PKG_TYPE_LEN)) {
100                         ptr->head = data;
101                         slot = ptr->queue_slot;
102                 }
103                 else {
104                         ptr++;
105                         continue;
106                 }
107         }
108         /*update head for each duplicate entry*/
109         ptr = start;
110         for(i = 0; i < entries; i++)
111         {
112                 if(ptr->queue_slot == slot && !ptr->head) {
113                         ptr->head = data;
114                 }
115                 ptr++;
116         }
117         return;
118 }
119
120 /*Gets the queue head based on pkg type*/
121 static pm_queue_data *__get_head_from_pkgtype(pm_dbus_msg *item)
122 {
123         queue_info_map *ptr = NULL;
124         ptr = start;
125         int i = 0;
126         for(i = 0; i < entries; i++)
127         {
128                 if (!strncmp(ptr->pkgtype, item->pkg_type, MAX_PKG_TYPE_LEN))
129                         return ptr->head;
130                 else {
131                         ptr++;
132                         continue;
133                 }
134         }
135         return NULL;
136
137 }
138
139 int _pm_queue_init(void)
140 {
141         /*Find the num of backends currently supported and initialize
142         that many queues. It is dynamically determined.*/
143         struct dirent **namelist;
144         struct stat fileinfo;
145         queue_info_map *ptr = NULL;
146         int n = 0;
147         int c = 0;
148         int i = 0;
149         int ret = 0;
150         char abs_filename[MAX_PKG_NAME_LEN] = {'\0'};
151         char buf[MAX_PKG_NAME_LEN] = {'\0'};
152         n = scandir(BACKEND_INFO_DIR, &namelist, NULL, alphasort);
153         if (n < 0) {
154                 perror("scandir");
155                 return -1;
156         }
157         i = n;
158         /*Find number of backends (symlinks + executables)
159         The /usr/etc/package-manager/backend dir should not conatin
160         any other file except the backends.*/
161         while(n--)
162         {
163                 if(!strcmp(namelist[n]->d_name, ".") ||
164                         !strcmp(namelist[n]->d_name, ".."))
165                                 continue;
166                 snprintf(abs_filename, MAX_PKG_NAME_LEN, "%s/%s",
167                         BACKEND_INFO_DIR, namelist[n]->d_name);
168                 if (lstat(abs_filename, &fileinfo)) {
169                         perror("lstat");
170                         continue;
171                 }
172                 if (S_ISDIR(fileinfo.st_mode))
173                         continue;
174                 c++;
175                 memset(abs_filename, 0x00, MAX_PKG_NAME_LEN);
176         }
177         /*Add entries to info map.*/
178         ptr = (queue_info_map*)calloc(c , sizeof(queue_info_map));
179         memset(ptr, '\0', c * sizeof(queue_info_map));
180         start = ptr;
181         for(n = 0; n < c ; n++)
182         {
183                 ptr->backend[0] = '\0';
184                 ptr->head = NULL;
185                 ptr->queue_slot = -2;/*-1 can be error return*/
186                 ptr->pkgtype[0] = '\0';
187                 ptr++;
188         }
189         n = i;
190         ptr = start;
191         while(n--)
192         {
193                 if(!strcmp(namelist[n]->d_name, ".") ||
194                         !strcmp(namelist[n]->d_name, ".."))
195                                 continue;
196                 snprintf(abs_filename, MAX_PKG_NAME_LEN, "%s/%s",
197                         BACKEND_INFO_DIR, namelist[n]->d_name);
198                 if (lstat(abs_filename, &fileinfo) < 0) {
199                         perror(abs_filename);
200                         return -1;
201                 }
202                 if (S_ISDIR(fileinfo.st_mode))
203                         continue;
204                 /*Found backend*/
205                 if (S_ISLNK(fileinfo.st_mode)) {
206                         /*found a symlink*/
207                         ret = readlink(abs_filename, buf, MAX_PKG_NAME_LEN - 1);
208                         if (ret == -1) {
209                                 perror("readlink");
210                                 return -1;
211                         }
212                         buf[ret] = '\0';
213                 }
214                 /*executable*/
215                 else {
216                         strncpy(buf, abs_filename, MAX_PKG_NAME_LEN - 1);
217                 }
218                 ret = __entry_exist(buf);
219                 if (ret == -1) {
220                         strncpy(ptr->backend, buf, MAX_PKG_NAME_LEN - 1);
221                         strncpy(ptr->pkgtype, namelist[n]->d_name, MAX_PKG_TYPE_LEN - 1);
222                         ptr->queue_slot = slot;
223                         ptr->head = NULL;
224                         entries++;
225                         slot++;
226                         ptr++;
227                 }
228                 else {
229                         strncpy(ptr->backend, buf, MAX_PKG_NAME_LEN - 1);
230                         strncpy(ptr->pkgtype, namelist[n]->d_name, MAX_PKG_TYPE_LEN - 1);
231                         ptr->queue_slot = ret;
232                         ptr->head = NULL;
233                         entries++;
234                         ptr++;
235                 }
236                 free(namelist[n]);
237                 memset(buf, 0x00, MAX_PKG_NAME_LEN);
238                 continue;
239         }
240         free(namelist);
241         num_of_backends = slot;
242
243 #ifdef DEBUG_INFO
244         /*Debug info*/
245         DBG("Queue Info Map");
246         DBG("Number of Backends is %d", num_of_backends);
247         DBG("Number of Entries is %d", entries);
248         DBG("Backend\tType\tSlot\tHead");
249         ptr = start;
250         for(n = 0; n < entries; n++)
251         {
252                 DBG("%s\t%s\t%d\t%p", ptr->backend, ptr->pkgtype, ptr->queue_slot, ptr->head);
253                 ptr++;
254         }
255 #endif
256
257         return 0;
258 }
259
260 pm_dbus_msg *_pm_queue_create_item(uid_t uid, const char *req_id,
261                 int req_type, const char *pkg_type, const char *pkgid,
262                 const char *args)
263 {
264         pm_dbus_msg *item;
265
266         item = calloc(1, sizeof(pm_dbus_msg));
267         if (item == NULL) {
268                 ERR("Fail to allocate memory");
269                 return NULL;
270         }
271
272         item->uid = uid;
273         snprintf(item->req_id, sizeof(item->req_id), "%s", req_id);
274         item->req_type = req_type;
275         snprintf(item->pkg_type, sizeof(item->pkg_type), "%s", pkg_type);
276         snprintf(item->pkgid, sizeof(item->pkgid), "%s", pkgid);
277         snprintf(item->args, sizeof(item->args), "%s", args);
278
279         return item;
280 }
281
282 int _pm_queue_push(pm_dbus_msg *item)
283 {
284         pm_queue_data *data = NULL;
285         pm_queue_data *cur = NULL;
286         pm_queue_data *tmp = NULL;
287         int ret = 0;
288         ret = __is_pkg_supported(item->pkg_type);
289         if (ret == 0)
290                 return -1;
291
292         cur = __get_head_from_pkgtype(item);
293         tmp = cur;
294
295         data = _add_node();
296         if (!data) { /* fail to allocate mem */
297                 ERR("Fail to allocate memory\n");
298                 return -1;
299         }
300
301         strncpy(data->msg->req_id, item->req_id, strlen(item->req_id));
302         data->msg->req_type = item->req_type;
303         data->msg->uid = item->uid;
304         strncpy(data->msg->pkg_type, item->pkg_type, strlen(item->pkg_type));
305         strncpy(data->msg->pkgid, item->pkgid, strlen(item->pkgid));
306         strncpy(data->msg->args, item->args, strlen(item->args));
307
308         data->next = NULL;
309
310         if (cur == NULL) {
311                 /* first push */
312                 cur = data;
313                 __update_head_from_pkgtype(data);
314         }
315         else {
316                 while (tmp->next)
317                         tmp = tmp->next;
318
319                 tmp->next = data;
320         }
321         return 0;
322 }
323
324 /*pop request from queue slot "position" */
325 pm_dbus_msg *_pm_queue_pop(int position)
326 {
327         pm_dbus_msg *ret;
328         pm_queue_data *cur = NULL;
329         pm_queue_data *saveptr = NULL;
330         queue_info_map *ptr = NULL;
331         int i = 0;
332
333         ret = (pm_dbus_msg *) malloc(sizeof(pm_dbus_msg));
334         if (!ret) {
335                 ERR("Mem alloc error");
336                 return NULL;
337         }
338         memset(ret, 0x00, sizeof(pm_dbus_msg));
339         ptr = start;
340         for(i = 0; i < entries; i++)
341         {
342                 if (ptr->queue_slot == position) {
343                                 cur = ptr->head;
344                                 break;
345                 }
346                 ptr++;
347         }
348
349         if (!cur) {             /* queue is empty */
350                 ret->req_type = -1;
351                 return ret;
352         }
353
354         strncpy(ret->req_id, cur->msg->req_id, strlen(cur->msg->req_id));
355         ret->req_type = cur->msg->req_type;
356         ret->uid = cur->msg->uid;
357         strncpy(ret->pkg_type, cur->msg->pkg_type, strlen(cur->msg->pkg_type));
358         strncpy(ret->pkgid, cur->msg->pkgid, strlen(cur->msg->pkgid));
359         strncpy(ret->args, cur->msg->args, strlen(cur->msg->args));
360
361         ptr->head = cur->next;
362         saveptr = ptr->head;
363         cur->next = NULL;
364         free(cur->msg);
365         free(cur);
366         /*update head for each duplicate queue entry*/
367         ptr = start;
368         for(i = 0; i < entries; i++)
369         {
370                 if(ptr->queue_slot == position) {
371                         ptr->head = saveptr;
372                 }
373                 ptr++;
374         }
375         return ret;
376 }
377
378 /*populate an array of all queue heads and delete them one by one*/
379 void _pm_queue_final()
380 {
381         int c = 0;
382         int i = 0;
383         int slot = -1;
384         pm_queue_data *cur = NULL;
385         pm_queue_data *tail = NULL;
386         pm_queue_data *prev = NULL;
387         pm_queue_data *head[MAX_QUEUE_NUM] = {NULL,};
388         queue_info_map *ptr = NULL;
389         ptr = start;
390
391         for(i = 0; i < num_of_backends; i++)
392         {
393                 head[i] = NULL;
394         }
395
396         for(i = 0; i < entries; i++)
397         {
398                 if (ptr->queue_slot <= slot) {
399                         ptr++;
400                         continue;
401                 }
402                 else {
403                         head[c] = ptr->head;
404                         slot = ptr->queue_slot;
405                         c++;
406                         ptr++;
407                 }
408         }
409
410         c = 0;
411         while(c < num_of_backends) {
412                 if (!head[c]) { /* in case of head is NULL */
413                         ERR("queue is NULL");
414                         c = c + 1;
415                         continue;
416                 }
417
418                 while (head[c]->next) {
419                         cur = head[c]->next;
420
421                         while (cur->next) {
422                                 prev = cur;
423                                 cur = cur->next;
424                         }
425
426                         tail = cur;
427
428                         free(tail->msg);
429                         free(tail);
430                         prev->next = NULL;
431                 }
432
433                 free(head[c]->msg);
434                 free(head[c]);
435
436                 head[c] = NULL;
437                 c = c + 1;
438         }
439         /*Free the info map*/
440         if (start) {
441                 free(start);
442                 start = NULL;
443         }
444 }
445
446 pm_queue_data *_add_node()
447 {
448         pm_queue_data *newnode = NULL;
449
450         newnode = (pm_queue_data *) malloc(sizeof(pm_queue_data));
451         if (!newnode) { /* if NULL */
452                 ERR("Mem alloc error");
453                 return NULL;
454         }
455         memset(newnode, 0x00, sizeof(pm_queue_data));
456
457         newnode->msg = (pm_dbus_msg *) malloc(sizeof(pm_dbus_msg));
458         if (!newnode->msg) {
459                 ERR("Mem alloc error");
460                 free(newnode);
461                 return NULL;
462         }
463         memset(newnode->msg, 0x00, sizeof(pm_dbus_msg));
464
465         return newnode;
466 }
467
468 void _pm_queue_delete(pm_dbus_msg *item)
469 {
470         /* Assume that pacakge name is unique */
471         pm_queue_data *cur = NULL;
472         pm_queue_data *prev = NULL;
473         cur = __get_head_from_pkgtype(item);
474         prev = cur;
475         if (cur) {
476                 while (cur->next) {
477                         if (!strcmp(item->pkgid, cur->msg->pkgid)) {
478                                 prev->next = cur->next;
479                                 free(cur->msg);
480                                 free(cur);
481                                 break;
482                         }
483                         prev = cur;
484                         cur = cur->next;
485                 }
486         }
487 }
488
489 void _save_queue_status(pm_dbus_msg *item, char *status)
490 {
491         FILE *fp_status = NULL;
492
493         fp_status = fopen(STATUS_FILE, "w");    /* overwrite always */
494         if (!fp_status) {
495                 ERR("Can't open status file:%s", STATUS_FILE);
496                 return;
497         }
498
499         fprintf(fp_status, "%s\n", status);
500         fprintf(fp_status, "%s\n", item->pkg_type);
501
502         fsync(fileno(fp_status));
503
504         fclose(fp_status);
505 }
506
507 void _print_queue(int position)
508 {
509         pm_queue_data *cur = NULL;
510         queue_info_map *ptr = start;
511         int i = 0;
512         for(i =0; i < entries; i++)
513         {
514                 if (ptr->queue_slot == position) {
515                                 cur = ptr->head;
516                                 break;
517                 }
518                 ptr++;
519         }
520         int index = 1;
521         if (!cur) {
522                 return;
523         }
524
525         while (cur) {
526                 index++;
527                 cur = cur->next;
528         }
529 }