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