Move function definition to aul header
[platform/core/appfw/aul-1.git] / src / aul_debug_info.c
1 /*
2  * Copyright (c) 2018 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 _GNU_SOURCE
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <dirent.h>
24 #include <unistd.h>
25 #include <glib.h>
26 #include <bundle_internal.h>
27
28 #include "aul.h"
29 #include "aul_api.h"
30 #include "aul_util.h"
31 #include "aul_debug_info.h"
32
33 #define PATH_AUL                "/usr/share/aul"
34 #define TAG_DEBUGGER            "[DEBUGGER]"
35 #define TAG_NAME                "NAME"
36 #define TAG_EXTRA_KEY           "EXTRA_KEY"
37 #define TAG_EXTRA_ENV           "EXTRA_ENV"
38 #define TAG_UNLINK              "UNLINK"
39 #define TAG_ATTACH              "ATTACH"
40 #define TAG_LAST_EXTRA_KEY      "LAST_EXTRA_KEY"
41 #define TAG_DEFAULT_OPT         "DEFAULT_OPT"
42
43 #define FREE_AND_NULL(x) do {   \
44         if (x) {                \
45                 free(x);        \
46                 x = NULL;       \
47         }                       \
48 } while (0)
49
50 struct debugger_info_s {
51         char *name;
52         char *attach;
53         GList *extra_key_list;
54         GList *extra_env_list;
55         GList *unlink_list;
56         GList *last_extra_key_list;
57         GList *default_opt_list;
58 };
59
60 struct debug_info_s {
61         bool initialized;
62         GList *debugger_list;
63 };
64
65 struct cb_data_s {
66         bundle *src;
67         bundle *dst;
68 };
69
70 static struct debug_info_s __info;
71
72 static struct debugger_info_s *__create_debugger_info(void)
73 {
74         struct debugger_info_s *info;
75
76         info = calloc(1, sizeof(struct debugger_info_s));
77         if (info == NULL) {
78                 _E("out of memory");
79                 return NULL;
80         }
81
82         return info;
83 }
84
85 static void __destroy_debugger_info(gpointer data)
86 {
87         struct debugger_info_s *info = (struct debugger_info_s *)data;
88
89         if (info == NULL)
90                 return;
91
92         if (info->default_opt_list)
93                 g_list_free_full(info->default_opt_list, free);
94         if (info->last_extra_key_list)
95                 g_list_free_full(info->last_extra_key_list, free);
96         if (info->attach)
97                 free(info->attach);
98         if (info->unlink_list)
99                 g_list_free_full(info->unlink_list, free);
100         if (info->extra_env_list)
101                 g_list_free_full(info->extra_env_list, free);
102         if (info->extra_key_list)
103                 g_list_free_full(info->extra_key_list, free);
104         if (info->name)
105                 free(info->name);
106         free(info);
107 }
108
109 static struct debugger_info_s *__find_debugger_info(const char *name)
110 {
111         struct debugger_info_s *debugger;
112         GList *iter;
113
114         iter = __info.debugger_list;
115         while (iter) {
116                 debugger = (struct debugger_info_s *)iter->data;
117                 if (debugger && debugger->name &&
118                                 !strcmp(debugger->name, name))
119                         return debugger;
120
121                 iter = g_list_next(iter);
122         }
123
124         return NULL;
125 }
126
127 static GList *__parse_file(GList *list, const char *path)
128 {
129         FILE *fp;
130         char buf[LINE_MAX];
131         char *tok1 = NULL;
132         char *tok2 = NULL;
133         struct debugger_info_s *info = NULL;
134
135         fp = fopen(path, "rt");
136         if (fp == NULL)
137                 return list;
138
139         while (fgets(buf, sizeof(buf), fp) != NULL) {
140                 FREE_AND_NULL(tok1);
141                 FREE_AND_NULL(tok2);
142                 sscanf(buf, "%ms %ms", &tok1, &tok2);
143                 if (tok1 && strcasecmp(TAG_DEBUGGER, tok1) == 0) {
144                         if (info) {
145                                 _D("name: %s", info->name);
146                                 list = g_list_append(list, info);
147                         }
148
149                         info = __create_debugger_info();
150                         if (info == NULL)
151                                 break;
152
153                         continue;
154                 }
155
156                 if (!tok1 || !tok2)
157                         continue;
158                 if (tok1[0] == '\0' || tok2[0] == '\0' || tok1[0] == '#')
159                         continue;
160                 if (info == NULL)
161                         continue;
162
163                 if (strcasecmp(TAG_NAME, tok1) == 0) {
164                         info->name = strdup(tok2);
165                         if (info->name == NULL) {
166                                 _E("out of memory");
167                                 __destroy_debugger_info(info);
168                                 info = NULL;
169                                 break;
170                         }
171                 } else if (strcasecmp(TAG_EXTRA_KEY, tok1) == 0) {
172                         info->extra_key_list = g_list_append(
173                                         info->extra_key_list, strdup(tok2));
174                 } else if (strcasecmp(TAG_EXTRA_ENV, tok1) == 0) {
175                         info->extra_env_list = g_list_append(
176                                         info->extra_env_list, strdup(tok2));
177                 } else if (strcasecmp(TAG_UNLINK, tok1) == 0) {
178                         info->unlink_list = g_list_append(info->unlink_list,
179                                         strdup(tok2));
180                 } else if (strcasecmp(TAG_ATTACH, tok1) == 0) {
181                         info->attach = strdup(tok2);
182                         if (info->attach == NULL) {
183                                 _E("attach is NULL");
184                                 __destroy_debugger_info(info);
185                                 info = NULL;
186                                 break;
187                         }
188                 } else if (strcasecmp(TAG_LAST_EXTRA_KEY, tok1) == 0) {
189                         info->last_extra_key_list = g_list_append(
190                                         info->last_extra_key_list,
191                                         strdup(tok2));
192                 } else if (strcasecmp(TAG_DEFAULT_OPT, tok1) == 0) {
193                         info->default_opt_list = g_list_append(
194                                         info->default_opt_list,
195                                         strdup(tok2));
196                 }
197         }
198         fclose(fp);
199
200         if (info) {
201                 _D("name: %s", info->name);
202                 list = g_list_append(list, info);
203         }
204
205         if (tok1)
206                 free(tok1);
207         if (tok2)
208                 free(tok2);
209
210         return list;
211 }
212
213 static int __load_debugger_info(const char *path)
214 {
215         DIR *dp;
216         struct dirent *dentry = NULL;
217         char buf[PATH_MAX];
218         char *ext;
219
220         if (path == NULL)
221                 return -1;
222
223         dp = opendir(path);
224         if (dp == NULL)
225                 return -1;
226
227         while ((dentry = readdir(dp)) != NULL) {
228                 if (dentry->d_name[0] == '.')
229                         continue;
230
231                 ext = strrchr(dentry->d_name, '.');
232                 if (ext && strcmp(ext, ".debugger") == 0) {
233                         snprintf(buf, sizeof(buf), "%s/%s",
234                                         path, dentry->d_name);
235                         __info.debugger_list = __parse_file(
236                                         __info.debugger_list, buf);
237                 }
238         }
239         closedir(dp);
240
241         return 0;
242 }
243
244 static void __unload_debugger_info(void)
245 {
246         if (__info.debugger_list == NULL)
247                 return;
248
249         g_list_free_full(__info.debugger_list, __destroy_debugger_info);
250         __info.debugger_list = NULL;
251 }
252
253 API int aul_debug_info_init(void)
254 {
255         int r;
256
257         if (__info.initialized)
258                 return AUL_R_OK;
259
260         r = __load_debugger_info(PATH_AUL);
261         if (r != 0) {
262                 _E("Failed to loader debugger information");
263                 return AUL_R_ERROR;
264         }
265
266         __info.initialized = true;
267         return AUL_R_OK;
268 }
269
270 API int aul_debug_info_fini(void)
271 {
272         if (!__info.initialized)
273                 return AUL_R_OK;
274
275         __unload_debugger_info();
276
277         __info.initialized = false;
278         return AUL_R_OK;
279 }
280
281 static void __copy_data(bundle *src, bundle *dst, const char *key)
282 {
283         const char **str_arr;
284         char *str = NULL;
285         int len = 0;
286
287         if (bundle_get_type(src, key) == BUNDLE_TYPE_STR_ARRAY) {
288                 str_arr = bundle_get_str_array(src, key, &len);
289                 if (str_arr) {
290                         bundle_del(dst, key);
291                         bundle_add_str_array(dst, key, str_arr, len);
292                 }
293         } else {
294                 bundle_get_str(src, key, &str);
295                 if (str) {
296                         bundle_del(dst, key);
297                         bundle_add_str(dst, key, str);
298                 }
299         }
300 }
301
302 static void __foreach_cb(gpointer data, gpointer user_data)
303 {
304         struct cb_data_s *cb_data = (struct cb_data_s *)user_data;
305         const char *key = (const char *)data;
306
307         if (!key || !cb_data) {
308                 _E("Critical error!");
309                 return;
310         }
311
312         __copy_data(cb_data->src, cb_data->dst, key);
313         _D("[__DEBUG_INFO__] key(%s)", key);
314 }
315
316 static void __set_debug_info(struct debugger_info_s *debugger,
317                 bundle *src, bundle *dst)
318 {
319         const char *val;
320         struct cb_data_s cb_data = {
321                 .src = src,
322                 .dst = dst
323         };
324
325         __copy_data(src, dst, AUL_K_SDK);
326         if (debugger->extra_key_list)
327                 g_list_foreach(debugger->extra_key_list, __foreach_cb, &cb_data);
328         if (debugger->extra_env_list)
329                 g_list_foreach(debugger->extra_env_list, __foreach_cb, &cb_data);
330         if (debugger->unlink_list)
331                 g_list_foreach(debugger->unlink_list, __foreach_cb, &cb_data);
332         if (debugger->last_extra_key_list)
333                 g_list_foreach(debugger->last_extra_key_list, __foreach_cb, &cb_data);
334         if (debugger->default_opt_list)
335                 g_list_foreach(debugger->default_opt_list, __foreach_cb, &cb_data);
336
337         val = bundle_get_val(src, AUL_K_ORG_CALLER_PID);
338         if (!val)
339                 val = bundle_get_val(src, AUL_K_CALLER_PID);
340
341         if (val) {
342                 bundle_del(dst, AUL_K_ORG_CALLER_PID);
343                 bundle_add(dst, AUL_K_ORG_CALLER_PID, val);
344         }
345
346         _D("[__DEBUG_INFO__] Debugger(%s)", debugger->name);
347 }
348
349 API int aul_debug_info_set(bundle *src, bundle *dst)
350 {
351         const char *name;
352         struct debugger_info_s *debugger;
353
354         if (!src || !dst) {
355                 _E("Invalid parameter");
356                 return AUL_R_EINVAL;
357         }
358
359         if (!__info.initialized) {
360                 _E("Debug info is not initilaized");
361                 return AUL_R_ERROR;
362         }
363
364         name = bundle_get_val(src, AUL_K_SDK);
365         if (!name) {
366                 _E("Invalid parameter");
367                 return AUL_R_EINVAL;
368         }
369
370         debugger = __find_debugger_info(name);
371         if (!debugger) {
372                 _E("Failed to find debugger(%s)", name);
373                 return AUL_R_EINVAL;
374         }
375
376         __set_debug_info(debugger, src, dst);
377
378         return AUL_R_OK;
379 }