Add new implementation for pkg update info
[platform/core/appfw/pkgmgr-server.git] / src / queue.c
1 /*
2  * Copyright (c) 2016 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
18 #define _XOPEN_SOURCE 500
19 #include <ftw.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <strings.h>
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27
28 #include <glib.h>
29
30 #include "pkgmgr-server.h"
31 #include "queue.h"
32
33 #define BACKEND_DIR "/etc/package-manager/backend"
34 #define NOPENFD 20
35
36 struct backend_queue {
37         char *path;
38         char *type;
39         int slot;
40         GList *job_list;
41 };
42
43 static GHashTable *queue_type_table;
44 static GHashTable *queue_slot_table;
45
46 int num_of_backends;
47
48 int _is_queue_empty(int pos)
49 {
50         struct backend_queue *queue;
51
52         queue = (struct backend_queue *)g_hash_table_lookup(queue_slot_table,
53                         (gconstpointer)pos);
54         if (queue == NULL) {
55                 ERR("cannot find queue of slot %d", pos);
56                 return -1;
57         }
58
59         if (queue->job_list == NULL)
60                 return 1;
61
62         return 0;
63 }
64
65 struct backend_job *_pop_queue(int pos)
66 {
67         struct backend_queue *queue;
68         struct backend_job *job;
69         GList *tmp;
70
71         queue = (struct backend_queue *)g_hash_table_lookup(queue_slot_table,
72                         (gconstpointer)pos);
73         if (queue == NULL) {
74                 ERR("cannot find queue of slot %d", pos);
75                 return NULL;
76         }
77
78         tmp = g_list_first(queue->job_list);
79         if (tmp == NULL)
80                 return NULL;
81         job = (struct backend_job *)tmp->data;
82         queue->job_list = g_list_delete_link(queue->job_list, tmp);
83
84         return job;
85 }
86
87 int _push_queue(uid_t target_uid, uid_t caller_uid, const char *req_id,
88                 int req_type, const char *queue_type, const char *pkgid,
89                 const char *args, void *extra_data)
90 {
91         struct backend_queue *queue;
92         struct backend_job *job;
93
94         queue = (struct backend_queue *)g_hash_table_lookup(queue_type_table,
95                         (gconstpointer)queue_type);
96         if (queue == NULL) {
97                 ERR("no such queue: %s", queue_type);
98                 return -1;
99         }
100
101         job = calloc(1, sizeof(struct backend_job));
102         job->target_uid = target_uid;
103         job->caller_uid = caller_uid;
104         if (req_id)
105                 job->req_id = strdup(req_id);
106         job->req_type = req_type;
107         if (pkgid)
108                 job->pkgid = strdup(pkgid);
109         if (args)
110                 job->args = strdup(args);
111         /* just assign pointer value */
112         job->backend_slot = queue->slot;
113         job->backend_type = queue->type;
114         job->backend_path = queue->path;
115         if (extra_data)
116                 job->extra_data = extra_data;
117
118         queue->job_list = g_list_append(queue->job_list, (gpointer)job);
119
120         return 0;
121 }
122
123 static int __init_backends(const char *fpath, const struct stat *sb,
124                 int typeflag, struct FTW *ftwbuf)
125 {
126         int r;
127         struct backend_queue *queue;
128
129         if (typeflag != FTW_F && typeflag != FTW_SL)
130                 return 0;
131
132         queue = calloc(1, sizeof(struct backend_queue));
133         if (typeflag == FTW_F) {
134                 queue->path = strdup(fpath);
135         } else if (typeflag == FTW_SL) {
136                 queue->path = malloc(sb->st_size + 1);
137                 r = readlink(fpath, queue->path, sb->st_size + 1);
138                 if (r < 0 || r > sb->st_size) {
139                         ERR("failed to readlink for %s", fpath);
140                         free(queue->path);
141                         free(queue);
142                         return -1;
143                 }
144                 queue->path[r] = '\0';
145         }
146         queue->type = strdup(fpath + ftwbuf->base);
147         queue->slot = num_of_backends++;
148         g_hash_table_insert(queue_type_table, (gpointer)queue->type,
149                         (gpointer)queue);
150         g_hash_table_insert(queue_slot_table, (gpointer)queue->slot,
151                         (gpointer)queue);
152
153         DBG("backend detected: %s(%s)", queue->type, queue->path);
154
155         return 0;
156 }
157
158 static gboolean __str_equal(gconstpointer v1, gconstpointer v2)
159 {
160         const char *str1 = (const char *)v1;
161         const char *str2 = (const char *)v2;
162
163         /* ignore case */
164         return strcasecmp(str1, str2) == 0;
165 }
166
167 void __free_extra_info(struct backend_job *job)
168 {
169         if (job->extra) {
170                 if (job->extra->getsize_io)
171                         g_io_channel_unref(job->extra->getsize_io);
172                 if (job->extra->getsize_fd)
173                         close(job->extra->getsize_fd);
174                 if (job->extra->getsize_fifo) {
175                         unlink(job->extra->getsize_fifo);
176                         free(job->extra->getsize_fifo);
177                 }
178                 free(job->extra);
179                 job->extra = NULL;
180         }
181 }
182
183 void _free_backend_job(struct backend_job *job)
184 {
185         __free_extra_info(job);
186         free(job->req_id);
187         free(job->pkgid);
188         free(job->appid);
189         free(job->args);
190         if (job->extra_data)
191                 free(job->extra_data);
192         free(job);
193 }
194
195 static void __free_backend_queue(gpointer data)
196 {
197         struct backend_queue *queue = (struct backend_queue *)data;
198
199         g_list_free_full(queue->job_list, (GDestroyNotify)_free_backend_job);
200         free(queue->path);
201         free(queue->type);
202         free(queue);
203 }
204
205 void _fini_backend_queue(void)
206 {
207         g_hash_table_destroy(queue_slot_table);
208         g_hash_table_destroy(queue_type_table);
209 }
210
211 int _init_backend_queue(void)
212 {
213         queue_type_table = g_hash_table_new_full(g_str_hash, __str_equal,
214                         NULL, __free_backend_queue);
215         queue_slot_table = g_hash_table_new(g_direct_hash, g_direct_equal);
216
217         if (nftw(BACKEND_DIR, __init_backends, NOPENFD, FTW_PHYS))
218                 return -1;
219
220         DBG("number of backends: %d", num_of_backends);
221
222         return 0;
223 }