change permission and smack of massif output log file
[framework/appfw/debug-launchpad.git] / src / sigchild.h
1 /*
2  *  debug-launchpad
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jungmin Cho <chivalry.cho@samsung.com>, Gwangho Hwang <gwang.hwang@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22
23 #include <pthread.h>
24 #include "app_signal.h"
25
26 static struct sigaction old_sigchild;
27 static DBusConnection *bus = NULL;
28 sigset_t oldmask;
29 static int gdbserver_pid;
30 static int gdbserver_app_pid;
31
32 static inline void __socket_garbage_collector()
33 {
34         DIR *dp;
35         struct dirent *dentry;
36         char tmp[MAX_LOCAL_BUFSZ];
37
38         dp = opendir(AUL_SOCK_PREFIX);
39         if (dp == NULL)
40                 return;
41
42         while ((dentry = readdir(dp)) != NULL) {
43                 if (!isdigit(dentry->d_name[0]))
44                         continue;
45
46                 snprintf(tmp, MAX_LOCAL_BUFSZ, "/proc/%s", dentry->d_name);
47                 if (access(tmp, F_OK) < 0) {    /* Flawfinder: ignore */
48                         snprintf(tmp, MAX_LOCAL_BUFSZ, "%s/%s", AUL_SOCK_PREFIX,
49                                  dentry->d_name);
50                         unlink(tmp);
51                         continue;
52                 }
53         }
54         closedir(dp);
55 }
56
57 static inline int __send_app_dead_signal(int dead_pid)
58 {
59         DBusMessage *message;
60
61         if (bus == NULL)
62                 return -1;
63
64         message = dbus_message_new_signal(AUL_DBUS_PATH,
65                                           AUL_DBUS_SIGNAL_INTERFACE,
66                                           AUL_DBUS_APPDEAD_SIGNAL);
67
68         if (dbus_message_append_args(message,
69                                      DBUS_TYPE_UINT32, &dead_pid,
70                                      DBUS_TYPE_INVALID) == FALSE) {
71                 _E("Failed to load data error");
72                 return -1;
73         }
74
75         if (dbus_connection_send(bus, message, NULL) == FALSE) {
76                 _E("dbus send error");
77                 return -1;
78         }
79
80         dbus_connection_flush(bus);
81         dbus_message_unref(message);
82
83         _D("send dead signal done\n");
84
85         return 0;
86 }
87
88 static inline int __send_app_launch_signal(int launch_pid)
89 {
90         DBusMessage *message;
91
92         if (bus == NULL)
93                 return -1;
94
95         message = dbus_message_new_signal(AUL_DBUS_PATH,
96                                           AUL_DBUS_SIGNAL_INTERFACE,
97                                           AUL_DBUS_APPLAUNCH_SIGNAL);
98
99         if (dbus_message_append_args(message,
100                                      DBUS_TYPE_UINT32, &launch_pid,
101                                      DBUS_TYPE_INVALID) == FALSE) {
102                 _E("Failed to load data error");
103                 return -1;
104         }
105
106         if (dbus_connection_send(bus, message, NULL) == FALSE) {
107                 _E("dbus send error");
108                 return -1;
109         }
110
111         dbus_connection_flush(bus);
112         dbus_message_unref(message);
113
114         _D("send launch signal done\n");
115
116         return 0;
117 }
118
119 /* chmod and chsmack to read file without root privilege */
120 static void __chmod_chsmack_toread(const char * path)
121 {
122         /* chmod */
123         if(dlp_chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, 0))
124         {
125                 _E("unable to set 644 to %s", path);
126         }else{
127                 _D("set 644 to %s", path);
128         }
129
130         /* chsmack */
131         if(smack_setlabel(path, "*", SMACK_LABEL_ACCESS))
132         {
133                 _E("failed chsmack -a \"*\" %s", path);
134         }else{
135                 _D("chsmack -a \"*\" %s", path);
136         }
137
138         return;
139 }
140
141 static int __sigchild_action(void *data)
142 {
143         pid_t dead_pid;
144         char buf[MAX_LOCAL_BUFSZ];
145
146         dead_pid = (pid_t) data;
147         if (dead_pid <= 0)
148                 goto end;
149
150         /* send app pid instead of gdbserver pid */
151         if(dead_pid == gdbserver_pid)
152                 dead_pid = gdbserver_app_pid;
153
154         /* valgrind xml file */
155         if(access(PATH_VALGRIND_XMLFILE,F_OK)==0)
156         {
157                 __chmod_chsmack_toread(PATH_VALGRIND_XMLFILE);
158         }
159
160         __send_app_dead_signal(dead_pid);
161
162         snprintf(buf, MAX_LOCAL_BUFSZ, "%s/%d", AUL_SOCK_PREFIX, dead_pid);
163         unlink(buf);
164
165         __socket_garbage_collector();
166  end:
167         return 0;
168 }
169
170 static void __launchpad_sig_child(int signo, siginfo_t *info, void *data)
171 {
172         int status;
173         pid_t child_pid;
174         pid_t child_pgid;
175
176         child_pgid = getpgid(info->si_pid);
177         _D("dead_pid = %d pgid = %d", info->si_pid, child_pgid);
178
179         while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
180                 if (child_pid == child_pgid)
181                         killpg(child_pgid, SIGKILL);
182                 __sigchild_action((void *)child_pid);
183         }
184
185         return;
186 }
187
188 static inline int __signal_init(void)
189 {
190         int i;
191         for (i = 0; i < _NSIG; i++) {
192                 switch (i) {
193                         /* controlled by sys-assert package*/
194                 case SIGQUIT:
195                 case SIGILL:
196                 case SIGABRT:
197                 case SIGBUS:
198                 case SIGFPE:
199                 case SIGSEGV:
200                 case SIGPIPE:
201                         break;
202                 default:
203                         signal(i, SIG_DFL);
204                         break;
205                 }
206         }
207
208         return 0;
209 }
210
211 static inline int __signal_set_sigchld(void)
212 {
213         struct sigaction act;
214         DBusError error;
215
216         dbus_error_init(&error);
217         dbus_threads_init_default();
218         bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
219         if (!bus) {
220                 _E("Failed to connect to the D-BUS daemon: %s", error.message);
221                 dbus_error_free(&error);
222                 return -1;
223         }
224         /* TODO: if process stop mechanism is included, 
225         should be modified (SA_NOCLDSTOP)*/
226         act.sa_handler = NULL;
227         act.sa_sigaction = __launchpad_sig_child;
228         sigemptyset(&act.sa_mask);
229         act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
230
231         if (sigaction(SIGCHLD, &act, &old_sigchild) < 0)
232                 return -1;
233
234         return 0;
235 }
236
237 static inline int __signal_unset_sigchld(void)
238 {
239         struct sigaction dummy;
240
241         if (bus == NULL)
242                 return 0;
243
244         dbus_connection_close(bus);
245         if (sigaction(SIGCHLD, &old_sigchild, &dummy) < 0)
246                 return -1;
247
248         return 0;
249 }
250
251 static inline int __signal_block_sigchld(void)
252 {
253         sigset_t newmask;
254
255         sigemptyset(&newmask);
256         sigaddset(&newmask, SIGCHLD);
257
258         if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
259                 _E("SIG_BLOCK error");
260                 return -1;
261         }
262
263         _D("SIGCHLD blocked");
264
265         return 0;
266 }
267
268 static inline int __signal_unblock_sigchld(void)
269 {
270         if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
271                 _E("SIG_SETMASK error");
272                 return -1;
273         }
274
275         _D("SIGCHLD unblocked");
276         return 0;
277 }
278
279 static inline int __signal_fini(void)
280 {
281 #ifndef PRELOAD_ACTIVATE
282         int i;
283         for (i = 0; i < _NSIG; i++)
284                 signal(i, SIG_DFL);
285 #endif
286         return 0;
287 }
288