Adjust coding rules
[platform/core/appfw/debug-launchpad.git] / src / debug_util.c
1 /*
2  * Copyright (c) 2015 - 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 #include <stdio.h>
18 #include <string.h>
19 #include <stdbool.h>
20 #include <pkgmgr-info.h>
21 #include <bundle.h>
22 #include <bundle_internal.h>
23
24 #include "defs.h"
25 #include "common.h"
26 #include "file_util.h"
27 #include "security_util.h"
28 #include "debug_util.h"
29
30 #define LABEL_SDBD "sdbd"
31 #define LABEL_NETWORK "system::debugging_network"
32
33 #define POLL_VALGRIND_LOGFILE 0x00000001
34 #define POLL_VALGRIND_XMLFILE 0x00000002
35 #define POLL_VALGRIND_MASSIFFILE 0x00000004
36
37 static int gdbserver_pid = -1;
38 static int gdbserver_app_pid = -1;
39 static bool gdbserver;
40 static int valgrind_option;
41
42 bool _gdbserver_is_running(void)
43 {
44         return gdbserver;
45 }
46
47 int _get_gdbserver_pid(void)
48 {
49         return gdbserver_pid;
50 }
51
52 int _get_gdbserver_app_pid(void)
53 {
54         return gdbserver_app_pid;
55 }
56
57 int _get_valgrind_option(void)
58 {
59         return valgrind_option;
60 }
61
62 static int __check_pkginfo(const char *appid)
63 {
64         int r;
65         bool preload = false;
66         char *storeclientid = NULL;
67         pkgmgrinfo_pkginfo_h handle;
68
69         r = pkgmgrinfo_pkginfo_get_usr_pkginfo(appid, getuid(), &handle);
70         if (r != PMINFO_R_OK) {
71                 _E("Failed to get pkginfo: %s", appid);
72                 return -1;
73         }
74
75         r = pkgmgrinfo_pkginfo_is_preload(handle, &preload);
76         if (r != PMINFO_R_OK) {
77                 _E("Faield to check preload: %s", appid);
78                 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
79                 return -1;
80         }
81
82         r = pkgmgrinfo_pkginfo_get_storeclientid(handle, &storeclientid);
83         if (r != PMINFO_R_OK) {
84                 _E("Failed to get store client id: %s", appid);
85                 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
86                 return -1;
87         }
88
89         if (preload == true || (storeclientid && storeclientid[0] != '\0')) {
90                 _E("Debugging is not allowed");
91                 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
92                 return -1;
93         }
94
95         r = pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
96         if (r != PMINFO_R_OK) {
97                 _E("Failed to destroy pkginfo: %s", appid);
98                 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
99         }
100
101         return 0;
102 }
103
104 static int __prepare_gdbserver(bundle *kb, const char *appid)
105 {
106         int r;
107         const char *path;
108
109         r = __check_pkginfo(appid);
110         if (r < 0)
111                 return -1;
112
113         path = bundle_get_val(kb, DLP_K_GDBSERVER_PATH);
114         if (path == NULL)
115                 return -1;
116
117         r = dlp_chmod(path, S_IRUSR | S_IWUSR
118                         | S_IXUSR | S_IRGRP | S_IXGRP
119                         | S_IROTH | S_IXOTH, 1);
120         if (r != 0)
121                 _W("Failed to set 755: %s", path);
122
123         gdbserver = true;
124
125         return 0;
126 }
127
128 static int __prepare_valgrind(bundle *kb)
129 {
130         const char *str;
131         const char **str_arr = NULL;
132         int len = 0;
133         int i;
134
135         if (bundle_get_type(kb, DLP_K_VALGRIND_ARG) & BUNDLE_TYPE_ARRAY) {
136                 str_arr = bundle_get_str_array(kb, DLP_K_VALGRIND_ARG, &len);
137                 if (str_arr == NULL)
138                         return -1;
139         } else {
140                 str = bundle_get_val(kb, DLP_K_VALGRIND_ARG);
141                 if (str) {
142                         str_arr = &str;
143                         len = 1;
144                 }
145         }
146
147         for (i = 0; i < len; i++) {
148                 if (str_arr[i] == NULL)
149                         break;
150
151                 if (strncmp(str_arr[i], OPT_VALGRIND_LOGFILE_FIXED,
152                                 strlen(OPT_VALGRIND_LOGFILE_FIXED)) == 0) {
153                         valgrind_option |= POLL_VALGRIND_LOGFILE;
154                         if (access(PATH_VALGRIND_LOGFILE, F_OK) == 0) {
155                                 if (remove(PATH_VALGRIND_LOGFILE) != 0)
156                                         _W("Failed to remove %s",
157                                                 PATH_VALGRIND_LOGFILE);
158                         }
159                 } else if (strncmp(str_arr[i], OPT_VALGRIND_XMLFILE_FIXED,
160                                 strlen(OPT_VALGRIND_XMLFILE_FIXED)) == 0) {
161                         valgrind_option |= POLL_VALGRIND_XMLFILE;
162                         if (access(PATH_VALGRIND_XMLFILE, F_OK) == 0) {
163                                 if (remove(PATH_VALGRIND_XMLFILE) != 0)
164                                         _W("Failed to remove %s",
165                                                 PATH_VALGRIND_XMLFILE);
166                         }
167                 } else if (strncmp(str_arr[i], OPT_VALGRIND_MASSIFFILE_FIXED,
168                                 strlen(OPT_VALGRIND_MASSIFFILE_FIXED)) == 0) {
169                         valgrind_option |= POLL_VALGRIND_MASSIFFILE;
170                         if (access(PATH_VALGRIND_MASSIFFILE, F_OK) == 0) {
171                                 if (remove(PATH_VALGRIND_MASSIFFILE) != 0)
172                                         _W("Failed to remove %s",
173                                                 PATH_VALGRIND_MASSIFFILE);
174                         }
175                 }
176         }
177
178         return 0;
179 }
180
181 int _prepare_debug_tool(bundle *kb, const char *appid,
182                 const char **str_arr, int len)
183 {
184         int i;
185
186         if (appid == NULL || str_arr == NULL)
187                 return -1;
188
189         gdbserver = false;
190         gdbserver_pid = -1;
191         gdbserver_app_pid = -1;
192         valgrind_option = 0;
193
194         for (i = 0; i < len; i++) {
195                 if (str_arr[i] == NULL)
196                         break;
197
198                 if (strncmp(str_arr[i], SDK_DEBUG, strlen(SDK_DEBUG)) == 0 ||
199                                 strncmp(str_arr[i], SDK_ATTACH,
200                                         strlen(SDK_ATTACH)) == 0) {
201                         if (__prepare_gdbserver(kb, appid) < 0)
202                                 return -1;
203                 } else if (strncmp(str_arr[i], SDK_VALGRIND,
204                                         strlen(SDK_VALGRIND)) == 0) {
205                         __prepare_valgrind(kb);
206                 }
207         }
208
209         return 0;
210 }
211
212 /* chmod and chsmack to read file without root privilege */
213 void _change_file(const char *path)
214 {
215         int r;
216
217         r = dlp_chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0);
218         if (r)
219                 _E("Failed to set 644: %s", path);
220
221         r = _set_smack_access_label(path, "*");
222         if (r)
223                 _E("Failed to set smack label %s *", path);
224 }
225
226 void _wait_for_valgrind_output(void)
227 {
228         int wait_count = 1;
229
230         do {
231                 if (valgrind_option & POLL_VALGRIND_LOGFILE) {
232                         if (access(PATH_VALGRIND_LOGFILE, F_OK) == 0) {
233                                 _change_file(PATH_VALGRIND_LOGFILE);
234                                 valgrind_option &= ~POLL_VALGRIND_LOGFILE;
235                         }
236                 }
237
238                 if (valgrind_option & POLL_VALGRIND_XMLFILE) {
239                         if (access(PATH_VALGRIND_XMLFILE, F_OK) == 0) {
240                                 _change_file(PATH_VALGRIND_XMLFILE);
241                                 valgrind_option &= ~POLL_VALGRIND_XMLFILE;
242                         }
243                 }
244
245                 if (valgrind_option & POLL_VALGRIND_MASSIFFILE) {
246                         if (access(PATH_VALGRIND_MASSIFFILE, F_OK) == 0) {
247                                 _change_file(PATH_VALGRIND_MASSIFFILE);
248                                 valgrind_option &= ~POLL_VALGRIND_MASSIFFILE;
249                         }
250                 }
251
252                 usleep(50 * 1000); /* 50ms */
253                 wait_count++;
254         } while (valgrind_option && wait_count <= 10);
255
256         if (valgrind_option)
257                 _E("Failed to wait for valgrind output file");
258 }