e862671ddf827f311d40e0cd09e1a73a0efae9b3
[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()
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 int _pm_queue_push(pm_dbus_msg *item)
261 {
262         pm_queue_data *data = NULL;
263         pm_queue_data *cur = NULL;
264         pm_queue_data *tmp = NULL;
265         int ret = 0;
266         ret = __is_pkg_supported(item->pkg_type);
267         if (ret == 0)
268                 return -1;
269
270         cur = __get_head_from_pkgtype(item);
271         tmp = cur;
272
273         data = _add_node();
274         if (!data) { /* fail to allocate mem */
275                 ERR("Fail to allocate memory\n");
276                 return -1;
277         }
278
279         strncpy(data->msg->req_id, item->req_id, strlen(item->req_id));
280         data->msg->req_type = item->req_type;
281         data->msg->uid = item->uid;
282         strncpy(data->msg->pkg_type, item->pkg_type, strlen(item->pkg_type));
283         strncpy(data->msg->pkgid, item->pkgid, strlen(item->pkgid));
284         strncpy(data->msg->args, item->args, strlen(item->args));
285
286         data->next = NULL;
287
288         if (cur == NULL) {
289                 /* first push */
290                 cur = data;
291                 __update_head_from_pkgtype(data);
292         }
293         else {
294                 while (tmp->next)
295                         tmp = tmp->next;
296
297                 tmp->next = data;
298         }
299         return 0;
300 }
301
302 /*pop request from queue slot "position" */
303 pm_dbus_msg *_pm_queue_pop(int position)
304 {
305         pm_dbus_msg *ret;
306         pm_queue_data *cur = NULL;
307         pm_queue_data *saveptr = NULL;
308         queue_info_map *ptr = NULL;
309         int i = 0;
310
311         ret = (pm_dbus_msg *) malloc(sizeof(pm_dbus_msg));
312         if (!ret) {
313                 ERR("Mem alloc error");
314                 return NULL;
315         }
316         memset(ret, 0x00, sizeof(pm_dbus_msg));
317         ptr = start;
318         for(i = 0; i < entries; i++)
319         {
320                 if (ptr->queue_slot == position) {
321                                 cur = ptr->head;
322                                 break;
323                 }
324                 ptr++;
325         }
326
327         if (!cur) {             /* queue is empty */
328                 ret->req_type = -1;
329                 return ret;
330         }
331
332         strncpy(ret->req_id, cur->msg->req_id, strlen(cur->msg->req_id));
333         ret->req_type = cur->msg->req_type;
334         ret->uid = cur->msg->uid;
335         strncpy(ret->pkg_type, cur->msg->pkg_type, strlen(cur->msg->pkg_type));
336         strncpy(ret->pkgid, cur->msg->pkgid, strlen(cur->msg->pkgid));
337         strncpy(ret->args, cur->msg->args, strlen(cur->msg->args));
338
339         ptr->head = cur->next;
340         saveptr = ptr->head;
341         cur->next = NULL;
342         free(cur->msg);
343         free(cur);
344         /*update head for each duplicate queue entry*/
345         ptr = start;
346         for(i = 0; i < entries; i++)
347         {
348                 if(ptr->queue_slot == position) {
349                         ptr->head = saveptr;
350                 }
351                 ptr++;
352         }
353         return ret;
354 }
355
356 /*populate an array of all queue heads and delete them one by one*/
357 void _pm_queue_final()
358 {
359         int c = 0;
360         int i = 0;
361         int slot = -1;
362         pm_queue_data *cur = NULL;
363         pm_queue_data *tail = NULL;
364         pm_queue_data *prev = NULL;
365         pm_queue_data *head[MAX_QUEUE_NUM] = {NULL,};
366         queue_info_map *ptr = NULL;
367         ptr = start;
368
369         for(i = 0; i < num_of_backends; i++)
370         {
371                 head[i] = NULL;
372         }
373
374         for(i = 0; i < entries; i++)
375         {
376                 if (ptr->queue_slot <= slot) {
377                         ptr++;
378                         continue;
379                 }
380                 else {
381                         head[c] = ptr->head;
382                         slot = ptr->queue_slot;
383                         c++;
384                         ptr++;
385                 }
386         }
387
388         c = 0;
389         while(c < num_of_backends) {
390                 if (!head[c]) { /* in case of head is NULL */
391                         ERR("queue is NULL");
392                         c = c + 1;
393                         continue;
394                 }
395
396                 while (head[c]->next) {
397                         cur = head[c]->next;
398
399                         while (cur->next) {
400                                 prev = cur;
401                                 cur = cur->next;
402                         }
403
404                         tail = cur;
405
406                         free(tail->msg);
407                         free(tail);
408                         prev->next = NULL;
409                 }
410
411                 free(head[c]->msg);
412                 free(head[c]);
413
414                 head[c] = NULL;
415                 c = c + 1;
416         }
417         /*Free the info map*/
418         if (start) {
419                 free(start);
420                 start = NULL;
421         }
422 }
423
424 pm_queue_data *_add_node()
425 {
426         pm_queue_data *newnode = NULL;
427
428         newnode = (pm_queue_data *) malloc(sizeof(pm_queue_data));
429         if (!newnode) { /* if NULL */
430                 ERR("Mem alloc error");
431                 return NULL;
432         }
433         memset(newnode, 0x00, sizeof(pm_queue_data));
434
435         newnode->msg = (pm_dbus_msg *) malloc(sizeof(pm_dbus_msg));
436         if (!newnode->msg) {
437                 ERR("Mem alloc error");
438                 free(newnode);
439                 return NULL;
440         }
441         memset(newnode->msg, 0x00, sizeof(pm_dbus_msg));
442
443         return newnode;
444 }
445
446 void _pm_queue_delete(pm_dbus_msg *item)
447 {
448         /* Assume that pacakge name is unique */
449         pm_queue_data *cur = NULL;
450         pm_queue_data *prev = NULL;
451         cur = __get_head_from_pkgtype(item);
452         prev = cur;
453         if (cur) {
454                 while (cur->next) {
455                         if (!strcmp(item->pkgid, cur->msg->pkgid)) {
456                                 prev->next = cur->next;
457                                 free(cur->msg);
458                                 free(cur);
459                                 break;
460                         }
461                         prev = cur;
462                         cur = cur->next;
463                 }
464         }
465 }
466
467 void _save_queue_status(pm_dbus_msg *item, char *status)
468 {
469         FILE *fp_status = NULL;
470
471         fp_status = fopen(STATUS_FILE, "w");    /* overwrite always */
472         if (!fp_status) {
473                 ERR("Can't open status file:%s", STATUS_FILE);
474                 return;
475         }
476
477         fprintf(fp_status, "%s\n", status);
478         fprintf(fp_status, "%s\n", item->pkg_type);
479
480         fsync(fileno(fp_status));
481
482         fclose(fp_status);
483 }
484
485 void _print_queue(int position)
486 {
487         pm_queue_data *cur = NULL;
488         queue_info_map *ptr = start;
489         int i = 0;
490         for(i =0; i < entries; i++)
491         {
492                 if (ptr->queue_slot == position) {
493                                 cur = ptr->head;
494                                 break;
495                 }
496                 ptr++;
497         }
498         int index = 1;
499         if (!cur) {
500                 return;
501         }
502
503         while (cur) {
504                 index++;
505                 cur = cur->next;
506         }
507 }