8b1d62f349c26f0c393fb78f417b5d7610f210ca
[platform/core/appfw/debug-launchpad.git] / src / signal_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 <signal.h>
19 #include <sys/smack.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 #include <sys/signalfd.h>
23 #include <dirent.h>
24 #include <glib.h>
25 #include <gio/gio.h>
26
27 #include "defs.h"
28 #include "common.h"
29 #include "file_util.h"
30 #include "debug_util.h"
31 #include "signal_util.h"
32
33 #define AUL_DBUS_PATH "/aul/dbus_handler"
34 #define AUL_DBUS_SIGNAL_INTERFACE "org.tizen.aul.signal"
35 #define AUL_DBUS_APPDEAD_SIGNAL "app_dead"
36 #define AUL_DBUS_APPLAUNCH_SIGNAL "app_launch"
37
38 static GDBusConnection *bus;
39 static sigset_t oldmask;
40
41 static void __socket_garbage_collector(void)
42 {
43         DIR *dp;
44         struct dirent *dentry;
45         char path[PATH_MAX];
46
47         snprintf(path, sizeof(path), "%s/apps/%d", SOCKET_PATH, getuid());
48         dp = opendir(path);
49         if (dp == NULL)
50                 return;
51
52         while ((dentry = readdir(dp)) != NULL) {
53                 if (!isdigit(dentry->d_name[0]))
54                         continue;
55
56                 snprintf(path, sizeof(path), "/proc/%s", dentry->d_name);
57                 if (access(path, F_OK) != 0) { /* Flawfinder: ignore */
58                         snprintf(path, sizeof(path), "%s/apps/%d/%s",
59                                         SOCKET_PATH, getuid(), dentry->d_name);
60                         unlink(path);
61                         continue;
62                 }
63         }
64
65         closedir(dp);
66 }
67
68 int _send_app_dead_signal(int dead_pid)
69 {
70         GError *err = NULL;
71
72         if (bus == NULL)
73                 return -1;
74
75         if (g_dbus_connection_emit_signal(bus,
76                                 NULL,
77                                 AUL_DBUS_PATH,
78                                 AUL_DBUS_SIGNAL_INTERFACE,
79                                 AUL_DBUS_APPDEAD_SIGNAL,
80                                 g_variant_new("(u)", dead_pid),
81                                 &err) == FALSE) {
82                 _E("g_dbus_connection_emit_signal() is failed: %s",
83                                         err->message);
84                 g_error_free(err);
85                 return -1;
86         }
87
88         if (g_dbus_connection_flush_sync(bus, NULL, &err) == FALSE) {
89                 _E("g_dbus_connection_flush_sync() is failed: %s",
90                                         err->message);
91                 g_error_free(err);
92                 return -1;
93         }
94
95         _D("send dead signal done (pid: %d)", dead_pid);
96
97         return 0;
98 }
99
100 int _send_app_launch_signal(int launch_pid, const char *app_id)
101 {
102         GError *err = NULL;
103
104         if (bus == NULL)
105                 return -1;
106
107         if (g_dbus_connection_emit_signal(bus,
108                                 NULL,
109                                 AUL_DBUS_PATH,
110                                 AUL_DBUS_SIGNAL_INTERFACE,
111                                 AUL_DBUS_APPLAUNCH_SIGNAL,
112                                 g_variant_new("(us)", launch_pid, app_id),
113                                 &err) == FALSE) {
114                 _E("g_dbus_connection_emit_signal() is failed: %s",
115                                 err->message);
116                 g_error_free(err);
117                 return -1;
118         }
119
120         if (g_dbus_connection_flush_sync(bus, NULL, &err) == FALSE) {
121                 _E("g_dbus_connection_flush_sync() is failed: %s",
122                                         err->message);
123                 g_error_free(err);
124                 return -1;
125         }
126
127         _D("send launch signal done (pid: %d, app_id: %s)", launch_pid, app_id);
128
129         return 0;
130 }
131
132 static int __sigchild_action(pid_t dead_pid)
133 {
134         char buf[MAX_LOCAL_BUFSZ];
135
136         if (dead_pid <= 0)
137                 return -1;
138
139         /* send app pid instead of gdbserver pid */
140         if (dead_pid == _get_gdbserver_pid())
141                 dead_pid = _get_gdbserver_app_pid();
142
143         /* valgrind xml file */
144         if (access(PATH_VALGRIND_XMLFILE, F_OK) == 0)
145                 _change_file(PATH_VALGRIND_XMLFILE);
146
147         _send_app_dead_signal(dead_pid);
148
149         snprintf(buf, MAX_LOCAL_BUFSZ, "%s/apps/%d/%d",
150                                 SOCKET_PATH, getuid(), dead_pid);
151         unlink(buf);
152
153         __socket_garbage_collector();
154
155         return 0;
156 }
157
158 void _debug_launchpad_sigchld(struct signalfd_siginfo *info)
159 {
160         int status;
161         pid_t child_pid;
162         pid_t child_pgid;
163
164         child_pgid = getpgid(info->ssi_pid);
165         _D("dead pid = %d pgid = %d", info->ssi_pid, child_pgid);
166
167         while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
168                 if (child_pid == child_pgid)
169                         killpg(child_pgid, SIGKILL);
170                 __sigchild_action(child_pid);
171         }
172 }
173
174 int _signal_init(void)
175 {
176         int i;
177         GError *error = NULL;
178
179         bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
180         if (!bus) {
181                 _E("Failed to connect to the D-BUS daemon: %s", error->message);
182                 g_error_free(error);
183                 return -1;
184         }
185
186         for (i = 0; i < _NSIG; i++) {
187                 switch (i) {
188                 /* controlled by sys-assert package*/
189                 case SIGQUIT:
190                 case SIGILL:
191                 case SIGABRT:
192                 case SIGBUS:
193                 case SIGFPE:
194                 case SIGSEGV:
195                 case SIGPIPE:
196                         break;
197                 default:
198                         signal(i, SIG_DFL);
199                         break;
200                 }
201         }
202
203         return 0;
204 }
205
206 int _signal_get_sigchld_fd(void)
207 {
208         sigset_t mask;
209         int sfd;
210
211         sigemptyset(&mask);
212         sigaddset(&mask, SIGCHLD);
213
214         if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1)
215                 _E("sigprocmask() is failed.");
216
217         sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
218         if (sfd == -1) {
219                 _E("Failed to create signal fd");
220                 return -1;
221         }
222
223         return sfd;
224 }
225
226 int _signal_unblock_sigchld(void)
227 {
228         if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
229                 _E("SIG_SETMASK error");
230                 return -1;
231         }
232
233         _D("SIGCHLD unblocked");
234
235         return 0;
236 }
237
238 int _signal_fini(void)
239 {
240         int i;
241
242         if (bus)
243                 g_object_unref(bus);
244
245 #ifndef PRELOAD_ACTIVATE
246         for (i = 0; i < _NSIG; i++)
247                 signal(i, SIG_DFL);
248 #endif
249         return 0;
250 }
251