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