Release version 0.15.20
[platform/core/appfw/launchpad.git] / src / launchpad / src / launchpad_debug.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 #define _GNU_SOURCE
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <linux/limits.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <bundle_internal.h>
26
27 #include "debugger_info.h"
28 #include "key.h"
29 #include "launchpad_common.h"
30 #include "launchpad_debug.h"
31 #include "launchpad_types.h"
32
33 #define DEBUGGER_INFO_PATH "/usr/share/aul"
34
35 static int debug_initialized;
36 static GList *debugger_info_list;
37 static debugger_info_h debugger_info;
38 static GList *debug_argv_list;
39 static GList *extra_argv_list;
40
41 int _debug_create_extra_argv(int *argc, char ***argv)
42 {
43         int new_argc;
44         char **new_argv;
45         const char *extra_argv;
46         GList *iter;
47         int i;
48
49         if (argc == NULL || argv == NULL) {
50                 _E("[DEBUG] Invalid parameter");
51                 return -1;
52         }
53
54         if (debugger_info == NULL)
55                 return 0;
56
57         new_argc = g_list_length(extra_argv_list);
58         if (new_argc == 0)
59                 return 0;
60
61         new_argv = (char **)calloc(new_argc, sizeof(char *));
62         if (new_argv == NULL) {
63                 _E("out of memory");
64                 return -1;
65         }
66
67         i = LOADER_ARG_PATH;
68         iter = g_list_first(extra_argv_list);
69         while (iter) {
70                 extra_argv = (const char *)iter->data;
71                 if (extra_argv)
72                         new_argv[i++] = strdup(extra_argv);
73
74                 iter = g_list_next(iter);
75         }
76
77         *argc = new_argc;
78         *argv = new_argv;
79         _D("[DEBUG] argc: %d, i: %d", *argc, i);
80
81         return 0;
82 }
83
84 int _debug_create_argv(int *argc, char ***argv, bool *attach)
85 {
86         int new_argc = 0;
87         char **new_argv;
88         const char *exe;
89         const char *debug_argv;
90         const char *attach_str;
91         GList *iter;
92         GList *list;
93         int i;
94
95         if (argc == NULL || argv == NULL || attach == NULL) {
96                 _E("[DEBUG] Invalid parameter");
97                 return -1;
98         }
99
100         if (debugger_info == NULL)
101                 return 0;
102
103         exe = _debugger_info_get_exe(debugger_info);
104         if (exe == NULL)
105                 return 0;
106
107         attach_str = _debugger_info_get_attach(debugger_info);
108         if (attach_str && strcasecmp(attach_str, "true") == 0) {
109                 *attach = true;
110                 new_argc++;
111         }
112
113         list = _debugger_info_get_default_opt_list(debugger_info);
114         new_argc += g_list_length(debug_argv_list) + g_list_length(list) + 1;
115         new_argv = (char **)calloc(new_argc, sizeof(char *));
116         if (new_argv == NULL) {
117                 _E("out of memory");
118                 return -1;
119         }
120
121         i = LOADER_ARG_PATH;
122         new_argv[i++] = strdup(exe);
123
124         iter = g_list_first(list);
125         while (iter) {
126                 debug_argv = (const char *)iter->data;
127                 if (debug_argv)
128                         new_argv[i++] = strdup(debug_argv);
129
130                 iter = g_list_next(iter);
131         }
132
133         iter = g_list_first(debug_argv_list);
134         while (iter) {
135                 debug_argv = (const char *)iter->data;
136                 if (debug_argv)
137                         new_argv[i++] = strdup(debug_argv);
138
139                 iter = g_list_next(iter);
140         }
141
142         *argc = new_argc;
143         *argv = new_argv;
144         _D("[DEBUG] argc: %d, argv[0]: %s",
145                         new_argc, new_argv[LOADER_ARG_PATH]);
146
147         return 0;
148 }
149
150 void _debug_destroy_argv(int argc, char **argv)
151 {
152         int i;
153
154         if (argv == NULL)
155                 return;
156
157         for (i = 0; i < argc; i++)
158                 free(argv[i]);
159         free(argv);
160 }
161
162 int _debug_get_caller_pid(bundle *kb)
163 {
164         const char *pid_str;
165         int pid;
166
167         pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
168         if (pid_str == NULL)
169                 pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
170
171         if (pid_str == NULL)
172                 return -1;
173
174         pid = atoi(pid_str);
175         if (pid <= 1)
176                 return -1;
177
178         return pid;
179 }
180
181 static int __redirect_std_fds(bundle *kb)
182 {
183         char path[PATH_MAX];
184         char err_buf[1024];
185         int fd;
186         int caller_pid;
187
188         if (kb == NULL) {
189                 _E("[DEBUG] Invalid parameter");
190                 return -1;
191         }
192
193         caller_pid = _debug_get_caller_pid(kb);
194         if (caller_pid < 0) {
195                 _E("[DEBUG] Failed to get caller pid");
196                 return -1;
197         }
198
199         /* stdin */
200         snprintf(path, sizeof(path), "/proc/%d/fd/0", caller_pid);
201         fd = open(path, O_RDONLY);
202         if (fd < 0) {
203                 _E("[DEBUG] Failed to open %s [%s]", path,
204                                 strerror_r(errno, err_buf, sizeof(err_buf)));
205                 return -1;
206         }
207         dup2(fd, 0);
208         close(fd);
209
210         /* stdout */
211         snprintf(path, sizeof(path), "/proc/%d/fd/1", caller_pid);
212         fd = open(path, O_WRONLY);
213         if (fd < 0) {
214                 _E("[DEBUG] Failed to open %s [%s]", path,
215                                 strerror_r(errno, err_buf, sizeof(err_buf)));
216                 return -1;
217         }
218         dup2(fd, 1);
219         close(fd);
220
221         /* stderr */
222         snprintf(path, sizeof(path), "/proc/%d/fd/2", caller_pid);
223         fd = open(path, O_WRONLY);
224         if (fd < 0) {
225                 _E("[DEBUG] Failed to open %s [%s]", path,
226                                 strerror_r(errno, err_buf, sizeof(err_buf)));
227                 return -1;
228         }
229         dup2(fd, 2);
230         close(fd);
231
232         return 0;
233 }
234
235 static void __add_extra_argv(gpointer data, gpointer user_data)
236 {
237         const char *key = (const char *)data;
238         bundle *kb = (bundle *)user_data;
239         const char *str;
240         const char **str_arr = NULL;
241         int len = 0;
242         int i;
243
244         if (key == NULL || kb == NULL)
245                 return;
246
247         _D("[DEBUG] key: %s", key);
248         if (bundle_get_type(kb, key) & BUNDLE_TYPE_ARRAY) {
249                 str_arr = bundle_get_str_array(kb, key, &len);
250         } else {
251                 str = bundle_get_val(kb, key);
252                 if (str) {
253                         str_arr = &str;
254                         len = 1;
255                 }
256         }
257
258         for (i = 0; i < len; i++) {
259                 if (str_arr[i] == NULL)
260                         break;
261
262                 extra_argv_list = g_list_append(extra_argv_list,
263                                 strdup(str_arr[i]));
264         }
265
266         if (str_arr)
267                 bundle_del(kb, key);
268 }
269
270 static void __add_debug_argv(gpointer data, gpointer user_data)
271 {
272         const char *key = (const char *)data;
273         bundle *kb = (bundle *)user_data;
274         const char *str;
275         const char **str_arr = NULL;
276         int len = 0;
277         int i;
278
279         if (key == NULL || kb == NULL)
280                 return;
281
282         _D("[DEBUG] key: %s", key);
283         if (bundle_get_type(kb, key) & BUNDLE_TYPE_ARRAY) {
284                 str_arr = bundle_get_str_array(kb, key, &len);
285         } else {
286                 str = bundle_get_val(kb, key);
287                 if (str) {
288                         str_arr = &str;
289                         len = 1;
290                 }
291         }
292
293         for (i = 0; i < len; i++) {
294                 if (str_arr[i] == NULL)
295                         break;
296
297                 debug_argv_list = g_list_append(debug_argv_list,
298                                 strdup(str_arr[i]));
299         }
300
301         if (str_arr)
302                 bundle_del(kb, key);
303 }
304
305 static void __set_debug_env(gpointer data, gpointer user_data)
306 {
307         const char *key = (const char *)data;
308         bundle *kb = (bundle *)user_data;
309         const char *str;
310         const char **str_arr = NULL;
311         int len = 0;
312         int i;
313         char buf[LINE_MAX] = {0,};
314
315         if (key == NULL || kb == NULL)
316                 return;
317
318         _D("[DEBUG] key: %s", key);
319         if (bundle_get_type(kb, key) & BUNDLE_TYPE_ARRAY) {
320                 str_arr = bundle_get_str_array(kb, key, &len);
321         } else {
322                 str = bundle_get_val(kb, key);
323                 if (str) {
324                         str_arr = &str;
325                         len = 1;
326                 }
327         }
328
329         if (str_arr == NULL)
330                 return;
331
332         strncat(buf, str_arr[0], sizeof(buf) - strlen(buf) - 1);
333         for (i = 1; i < len; i++) {
334                 if (str_arr[i] == NULL)
335                         break;
336
337                 strncat(buf, ",", sizeof(buf) - strlen(buf) - 1);
338                 strncat(buf, str_arr[i], sizeof(buf) - strlen(buf) - 1);
339         }
340
341         bundle_del(kb, key);
342         _D("[DEBUG] name: %s, value: %s", key, buf);
343         setenv(key, buf, 1);
344 }
345
346 static void __remove_file(gpointer data, gpointer user_data)
347 {
348         const char *file = (const char *)data;
349
350         if (file == NULL)
351                 return;
352
353         _D("[DEBUG] file: %s", file);
354         if (access(file, F_OK) == 0) {
355                 if (remove(file) != 0)
356                         _W("[DEBUG] Failed to remove %s", file);
357         }
358 }
359
360 void _debug_prepare_debugger(bundle *kb)
361 {
362         const char *debugger;
363         GList *list;
364         int ret;
365
366         if (kb == NULL)
367                 return;
368
369         debugger = bundle_get_val(kb, AUL_K_SDK);
370         if (debugger == NULL)
371                 return;
372
373         ret = __redirect_std_fds(kb);
374         if (ret < 0)
375                 _E("[DEBUG] Failed to redirect standard fds");
376
377         _D("[DEBUG] debugger: %s", debugger);
378         debugger_info = _debugger_info_find(debugger_info_list, debugger);
379         if (debugger_info == NULL)
380                 return;
381
382         list = _debugger_info_get_unlink_list(debugger_info);
383         g_list_foreach(list, __remove_file, NULL);
384
385         list = _debugger_info_get_extra_env_list(debugger_info);
386         g_list_foreach(list, __set_debug_env, kb);
387
388         list = _debugger_info_get_extra_key_list(debugger_info);
389         g_list_foreach(list, __add_debug_argv, kb);
390
391         list = _debugger_info_get_last_extra_key_list(debugger_info);
392         g_list_foreach(list, __add_extra_argv, kb);
393 }
394
395 int _debug_init(void)
396 {
397         if (debug_initialized)
398                 return 0;
399
400         debugger_info_list = _debugger_info_load(DEBUGGER_INFO_PATH);
401         if (debugger_info_list == NULL)
402                 return -1;
403
404         debug_initialized = 1;
405
406         return 0;
407 }
408
409 void _debug_fini(void)
410 {
411         if (!debug_initialized)
412                 return;
413
414         _debugger_info_unload(debugger_info_list);
415 }