Bump up efl module version.
[platform/core/appfw/launchpad.git] / src / launchpad_signal.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 #define _GNU_SOURCE
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <dirent.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <gio/gio.h>
24 #include <glib.h>
25
26 #include "launchpad_common.h"
27 #include "launchpad_signal.h"
28
29 #define AUL_DBUS_PATH                   "/aul/dbus_handler"
30 #define AUL_DBUS_SIGNAL_INTERFACE       "org.tizen.aul.signal"
31 #define AUL_DBUS_APPDEAD_SIGNAL         "app_dead"
32 #define AUL_DBUS_APPLAUNCH_SIGNAL       "app_launch"
33 #define PENDING_SIGNAL_INTERVAL         1000
34
35 enum signal_e {
36         APP_DEAD,
37         APP_LAUNCH,
38 };
39
40 struct pending_signal {
41         char *appid;
42         int pid;
43         int signal;
44 };
45
46 static GDBusConnection *bus;
47 static sigset_t oldmask;
48 static GList *pending_signal_list;
49 static guint timeout_handle;
50
51 static int __send_app_dead_signal(int dead_pid);
52 static int __send_app_launch_signal(int launch_pid, const char *app_id);
53
54 static struct pending_signal *__create_pending_signal(const char *appid,
55                 const int pid, const int signal)
56 {
57         struct pending_signal *handle;
58
59         handle = (struct pending_signal *)calloc(1,
60                         sizeof(struct pending_signal));
61         if (handle == NULL) {
62                 _E("out of memory");
63                 return NULL;
64         }
65
66         if (appid) {
67                 handle->appid = strdup(appid);
68                 if (handle->appid == NULL) {
69                         _E("out of memory");
70                         free(handle);
71                         return NULL;
72                 }
73         }
74
75         handle->pid = pid;
76         handle->signal = signal;
77
78         return handle;
79 }
80
81 static void __destroy_pending_signal(struct pending_signal *handle)
82 {
83         if (handle == NULL)
84                 return;
85
86         if (handle->appid)
87                 free(handle->appid);
88         free(handle);
89 }
90
91 static gboolean __flush_pending_signal(gpointer data)
92 {
93         struct pending_signal *handle;
94         GList *iter;
95         int ret;
96
97         if (pending_signal_list == NULL) {
98                 timeout_handle = 0;
99                 return FALSE;
100         }
101
102         iter = g_list_first(pending_signal_list);
103         while (iter) {
104                 handle = (struct pending_signal *)iter->data;
105                 iter = g_list_next(iter);
106                 if (handle) {
107                         if (handle->signal == APP_DEAD) {
108                                 ret = __send_app_dead_signal(handle->pid);
109                         } else {
110                                 ret = __send_app_launch_signal(handle->pid,
111                                                 handle->appid);
112                         }
113                         if (ret < 0)
114                                 return TRUE;
115
116                         pending_signal_list = g_list_remove(pending_signal_list,
117                                         handle);
118                         __destroy_pending_signal(handle);
119                 }
120         }
121
122         timeout_handle = 0;
123
124         return FALSE;
125 }
126
127 static void __socket_garbage_collector(void)
128 {
129         DIR *dp;
130         struct dirent *dentry = NULL;
131         char tmp[MAX_LOCAL_BUFSZ];
132
133         snprintf(tmp, sizeof(tmp), "/run/aul/apps/%d", getuid());
134         dp = opendir(tmp);
135         if (dp == NULL)
136                 return;
137
138         while ((dentry = readdir(dp)) != NULL) {
139                 if (!isdigit(dentry->d_name[0]))
140                         continue;
141
142                 snprintf(tmp, MAX_LOCAL_BUFSZ, "/proc/%s", dentry->d_name);
143                 if (access(tmp, F_OK) < 0) {    /* Flawfinder: ignore */
144                         _delete_sock_path(atoi(dentry->d_name), getuid());
145                         continue;
146                 }
147         }
148         closedir(dp);
149 }
150
151 static int __send_app_dead_signal(int dead_pid)
152 {
153         GError *err = NULL;
154
155         /* send over session dbus for other applications */
156         if (bus == NULL) {
157                 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
158                 if (bus == NULL) {
159                         _E("Failed to connect to the D-BUS daemon: %s",
160                                         err->message);
161                         g_error_free(err);
162                         return -1;
163                 }
164         }
165
166         if (g_dbus_connection_emit_signal(bus,
167                                         NULL,
168                                         AUL_DBUS_PATH,
169                                         AUL_DBUS_SIGNAL_INTERFACE,
170                                         AUL_DBUS_APPDEAD_SIGNAL,
171                                         g_variant_new("(u)", dead_pid),
172                                         &err) == FALSE) {
173                 _E("g_dbus_connection_emit_signal() is failed: %s",
174                                         err->message);
175                 g_error_free(err);
176                 return -1;
177         }
178
179         if (g_dbus_connection_flush_sync(bus, NULL, &err) == FALSE) {
180                 _E("g_dbus_connection_flush_sync() is failed: %s",
181                                         err->message);
182                 g_error_free(err);
183                 return -1;
184         }
185
186         _D("send_app_dead_signal_dbus done (pid=%d)", dead_pid);
187
188         return 0;
189 }
190
191 static int __send_app_launch_signal(int launch_pid, const char *app_id)
192 {
193         GError *err = NULL;
194         GVariant *param;
195
196         if (bus == NULL) {
197                 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
198                 if (bus == NULL) {
199                         _E("Failed to connect to the D-BUS daemon: %s",
200                                         err->message);
201                         g_error_free(err);
202                         return -1;
203                 }
204         }
205
206         param = g_variant_new("(us)", launch_pid, app_id);
207         if (g_dbus_connection_emit_signal(bus,
208                                         NULL,
209                                         AUL_DBUS_PATH,
210                                         AUL_DBUS_SIGNAL_INTERFACE,
211                                         AUL_DBUS_APPLAUNCH_SIGNAL,
212                                         param,
213                                         &err) == FALSE) {
214                 _E("g_dbus_connection_emit_signal() is failed: %s",
215                                         err->message);
216                 g_error_free(err);
217                 return -1;
218         }
219
220         if (g_dbus_connection_flush_sync(bus, NULL, &err) == FALSE) {
221                 _E("g_dbus_connection_flush_sync() is failed: %s",
222                                         err->message);
223                 g_error_free(err);
224                 return -1;
225         }
226
227         _D("send_app_launch_signal_dbus done (pid=%d)", launch_pid);
228
229         return 0;
230 }
231
232 int _signal_send_app_launch_signal(int launch_pid, const char *app_id)
233 {
234         int ret;
235         struct pending_signal *handle;
236
237         ret = __send_app_launch_signal(launch_pid, app_id);
238         if (ret < 0) {
239                 handle = __create_pending_signal(app_id, launch_pid,
240                                 APP_LAUNCH);
241                 pending_signal_list = g_list_append(pending_signal_list,
242                                 handle);
243                 if (timeout_handle == 0) {
244                         timeout_handle = g_timeout_add(PENDING_SIGNAL_INTERVAL,
245                                         __flush_pending_signal, NULL);
246                 }
247                 return -1;
248         }
249
250         return 0;
251 }
252
253 static int __sigchild_action(pid_t dead_pid)
254 {
255         int ret;
256         struct pending_signal *handle;
257
258         if (dead_pid <= 0)
259                 return 0;
260
261         ret = __send_app_dead_signal(dead_pid);
262         if (ret < 0) {
263                 handle = __create_pending_signal(NULL, dead_pid, APP_DEAD);
264                 pending_signal_list = g_list_append(pending_signal_list,
265                                 handle);
266                 if (timeout_handle == 0) {
267                         timeout_handle = g_timeout_add(PENDING_SIGNAL_INTERVAL,
268                                         __flush_pending_signal, NULL);
269                 }
270         }
271
272         _delete_sock_path(dead_pid, getuid());
273         __socket_garbage_collector();
274
275         return 0;
276 }
277
278 void _signal_process_sigchld(struct signalfd_siginfo *info)
279 {
280         int status;
281         pid_t child_pid;
282         pid_t child_pgid;
283
284         child_pgid = getpgid(info->ssi_pid);
285         _D("dead_pid = %d pgid = %d signo = %d status = %d", info->ssi_pid,
286                 child_pgid, info->ssi_signo, info->ssi_status);
287
288         while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
289                 if (child_pid == child_pgid)
290                         killpg(child_pgid, SIGKILL);
291                 __sigchild_action(child_pid);
292         }
293 }
294
295 int _signal_init(void)
296 {
297         int i;
298         GError *error = NULL;
299
300         bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
301         if (!bus) {
302                 _E("Failed to connect to the D-BUS daemon: %s", error->message);
303                 g_error_free(error);
304         }
305
306         for (i = 0; i < _NSIG; i++) {
307                 switch (i) {
308                         /* controlled by sys-assert package*/
309                 case SIGQUIT:
310                 case SIGILL:
311                 case SIGABRT:
312                 case SIGBUS:
313                 case SIGFPE:
314                 case SIGSEGV:
315                 case SIGPIPE:
316                         break;
317                 default:
318                         signal(i, SIG_DFL);
319                         break;
320                 }
321         }
322
323         return 0;
324 }
325
326 int _signal_get_sigchld_fd(void)
327 {
328         sigset_t mask;
329         int sfd;
330
331         sigemptyset(&mask);
332         sigaddset(&mask, SIGCHLD);
333
334         if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1)
335                 _E("failed to sigprocmask");
336
337         sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
338         if (sfd == -1) {
339                 _E("failed to create signal for SIGCHLD");
340                 return -1;
341         }
342
343         return sfd;
344 }
345
346 int _signal_unblock_sigchld(void)
347 {
348         if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
349                 _E("SIG_SETMASK error");
350                 return -1;
351         }
352
353         _D("SIGCHLD unblocked");
354         return 0;
355 }
356
357 void _signal_fini(void)
358 {
359 #ifndef PRELOAD_ACTIVATE
360         int i;
361
362         for (i = 0; i < _NSIG; i++)
363                 signal(i, SIG_DFL);
364 #endif
365         if (bus) {
366                 g_object_unref(bus);
367                 bus = NULL;
368         }
369 }