[Genlist] Fix genlist selected issue
[framework/uifw/elementary.git] / src / bin / quicklaunch.c
1 #include <Elementary.h>
2 #ifdef HAVE_CONFIG_H
3 # include "elementary_config.h"
4 #endif
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <sys/un.h>
12 #ifdef HAVE_ENVIRON
13 # define _GNU_SOURCE 1
14 #endif
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <signal.h>
19 #include <sys/wait.h>
20
21 #ifdef HAVE_ENVIRON
22 extern char **environ;
23 #endif
24
25 static double restart_time = 0.0;
26
27 #define LENGTH_OF_SOCKADDR_UN(s) (strlen((s)->sun_path) + (size_t)(((struct sockaddr_un *)NULL)->sun_path))
28
29 static struct sigaction old_sigint;
30 static struct sigaction old_sigterm;
31 static struct sigaction old_sigquit;
32 static struct sigaction old_sigalrm;
33 static struct sigaction old_sigusr1;
34 static struct sigaction old_sigusr2;
35 static struct sigaction old_sighup;
36 static struct sigaction old_sigchld;
37 static struct sigaction old_sigsegv;
38 static struct sigaction old_sigill;
39 static struct sigaction old_sigfpe;
40 static struct sigaction old_sigbus;
41 static struct sigaction old_sigabrt;
42 static int _log_dom = -1;
43
44 #define CRITICAL(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)
45 #define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
46 #define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
47 #define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
48 #define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
49
50 static void
51 post_fork(void *data __UNUSED__)
52 {
53    sigaction(SIGINT, &old_sigint, NULL);
54    sigaction(SIGTERM, &old_sigterm, NULL);
55    sigaction(SIGQUIT, &old_sigquit, NULL);
56    sigaction(SIGALRM, &old_sigalrm, NULL);
57    sigaction(SIGUSR1, &old_sigusr1, NULL);
58    sigaction(SIGUSR2, &old_sigusr2, NULL);
59    sigaction(SIGHUP, &old_sighup, NULL);
60    sigaction(SIGCHLD, &old_sigchld, NULL);
61    sigaction(SIGSEGV, &old_sigsegv, NULL);
62    sigaction(SIGILL, &old_sigill, NULL);
63    sigaction(SIGFPE, &old_sigfpe, NULL);
64    sigaction(SIGBUS, &old_sigbus, NULL);
65    sigaction(SIGABRT, &old_sigabrt, NULL);
66    if ((_log_dom > -1) && (_log_dom != EINA_LOG_DOMAIN_GLOBAL))
67      {
68         eina_log_domain_unregister(_log_dom);
69         _log_dom = -1;
70      }
71 }
72
73 static void
74 child_handler(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
75 {
76    int status;
77    while (waitpid(-1, &status, WNOHANG) > 0);
78 }
79
80 static void
81 crash_handler(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
82 {
83    double t;
84
85    ERR("crash detected. restarting.");
86    t = ecore_time_get();
87    if ((t - restart_time) <= 2.0)
88      {
89         CRITICAL("crash too fast - less than 2 seconds. abort restart");
90         exit(-1);
91      }
92    ecore_app_restart();
93 }
94
95 static void
96 handle_run(int fd, unsigned long bytes)
97 {
98    unsigned char *buf = NULL;
99    int i;
100    char **argv = NULL;
101    char **envir = NULL;
102    char *cwd;
103    int argc, envnum;
104    unsigned long off;
105
106    buf = alloca(bytes);
107    if (read(fd, buf, bytes) != (int)bytes)
108      {
109         CRITICAL("cannot read %i bytes of args and environment data", (int)bytes);
110         close(fd);
111         return;
112      }
113    close(fd);
114    
115    argc = ((unsigned long *)(buf))[0];
116    envnum = ((unsigned long *)(buf))[1];
117
118    if (argc <= 0)
119      {
120         CRITICAL("no executable specified");
121         close(fd);
122         return;
123      }
124    
125    argv = alloca(argc * sizeof(char *));
126    if (envnum > 0) envir = alloca(envnum * sizeof(char *));
127    off = ((unsigned long *)(buf))[2 + argc + envnum] - sizeof(unsigned long);
128    cwd = (char *)(buf + off);
129
130    for (i = 0; i < argc; i++)
131      {
132         off = ((unsigned long *)(buf))[2 + i] - sizeof(unsigned long);
133         argv[i] = (char *)(buf + off);
134      }
135
136 #ifdef HAVE_ENVIRON
137    if (envir)
138      {
139 #ifdef HAVE_CLEARENV
140         clearenv();
141 #else
142         environ = NULL;
143 #endif
144         for (i = 0; i < envnum; i++)
145           {
146              off = ((unsigned long *)(buf))[2 + argc + i] - sizeof(unsigned long);
147              envir[i] = (char *)(buf + off);
148              putenv(envir[i]);
149           }
150      }
151 #endif
152    elm_quicklaunch_prepare(argc, argv);
153    elm_quicklaunch_fork(argc, argv, cwd, post_fork, NULL);
154    elm_quicklaunch_cleanup();
155 }
156
157 int
158 main(int argc, char **argv)
159 {
160    int sock, socket_unix_len;
161    struct stat st;
162    struct sockaddr_un socket_unix;
163    struct linger lin;
164    char buf[PATH_MAX];
165    struct sigaction action;
166    const char *disp;
167
168    if (!eina_init())
169      {
170         fprintf(stderr, "ERROR: failed to init eina.");
171         exit(-1);
172      }
173    _log_dom = eina_log_domain_register
174      ("elementary_quicklaunch", EINA_COLOR_CYAN);
175    if (_log_dom < 0)
176      {
177         EINA_LOG_ERR("could not register elementary_quicklaunch log domain.");
178         _log_dom = EINA_LOG_DOMAIN_GLOBAL;
179      }
180
181    if (!(disp = getenv("DISPLAY"))) disp = "unknown";
182    snprintf(buf, sizeof(buf), "/tmp/elm-ql-%i", getuid());
183    if (stat(buf, &st) < 0) mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);
184    snprintf(buf, sizeof(buf), "/tmp/elm-ql-%i/%s", getuid(), disp);
185    unlink(buf);
186    sock = socket(AF_UNIX, SOCK_STREAM, 0);
187    if (sock < 0)
188      {
189         CRITICAL("cannot create socket for socket for '%s': %s",
190                  buf, strerror(errno));
191         exit(-1);
192      }
193    if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0)
194      {
195         CRITICAL("cannot set close on exec socket for '%s' (fd=%d): %s",
196                  buf, sock, strerror(errno));
197         exit(-1);
198      }
199    lin.l_onoff = 1;
200    lin.l_linger = 0;
201    if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0)
202      {
203         CRITICAL("cannot set linger for socket for '%s' (fd=%d): %s",
204                  buf, sock, strerror(errno));
205         exit(-1);
206      }
207    socket_unix.sun_family = AF_UNIX;
208    strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
209    socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
210    if (bind(sock, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
211      {
212         CRITICAL("cannot bind socket for '%s' (fd=%d): %s",
213                  buf, sock, strerror(errno));
214         exit(-1);
215      }
216    if (listen(sock, 4096) < 0)
217      {
218         CRITICAL("listen(sock=%d, 4096): %s", sock, strerror(errno));
219         exit(-1);
220      }
221    elm_quicklaunch_mode_set(EINA_TRUE);
222    elm_quicklaunch_init(argc, argv);
223    restart_time = ecore_time_get();
224
225    memset(&action, 0, sizeof(struct sigaction));
226    action.sa_handler = SIG_DFL;
227    action.sa_sigaction = NULL;
228    action.sa_flags = SA_RESTART | SA_SIGINFO;
229    sigemptyset(&action.sa_mask);
230    sigaction(SIGINT, &action, &old_sigint);
231
232    action.sa_handler = SIG_DFL;
233    action.sa_sigaction = NULL;
234    action.sa_flags = SA_RESTART | SA_SIGINFO;
235    sigemptyset(&action.sa_mask);
236    sigaction(SIGTERM, &action, &old_sigterm);
237
238    action.sa_handler = SIG_DFL;
239    action.sa_sigaction = NULL;
240    action.sa_flags = SA_RESTART | SA_SIGINFO;
241    sigemptyset(&action.sa_mask);
242    sigaction(SIGQUIT, &action, &old_sigquit);
243
244    action.sa_handler = SIG_DFL;
245    action.sa_sigaction = NULL;
246    action.sa_flags = SA_RESTART | SA_SIGINFO;
247    sigemptyset(&action.sa_mask);
248    sigaction(SIGALRM, &action, &old_sigalrm);
249
250    action.sa_handler = SIG_DFL;
251    action.sa_sigaction = NULL;
252    action.sa_flags = SA_RESTART | SA_SIGINFO;
253    sigemptyset(&action.sa_mask);
254    sigaction(SIGUSR1, &action, &old_sigusr1);
255
256    action.sa_handler = SIG_DFL;
257    action.sa_sigaction = NULL;
258    action.sa_flags = SA_RESTART | SA_SIGINFO;
259    sigemptyset(&action.sa_mask);
260    sigaction(SIGUSR2, &action, &old_sigusr2);
261
262    action.sa_handler = SIG_DFL;
263    action.sa_sigaction = NULL;
264    action.sa_flags = SA_RESTART | SA_SIGINFO;
265    sigemptyset(&action.sa_mask);
266    sigaction(SIGHUP, &action, &old_sighup);
267
268    action.sa_handler = NULL;
269    action.sa_sigaction = child_handler;
270    action.sa_flags = SA_RESTART | SA_SIGINFO;
271    sigemptyset(&action.sa_mask);
272    sigaction(SIGCHLD, &action, &old_sigchld);
273
274    action.sa_handler = NULL;
275    action.sa_sigaction = crash_handler;
276    action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
277    sigemptyset(&action.sa_mask);
278    sigaction(SIGSEGV, &action, &old_sigsegv);
279
280    action.sa_handler = NULL;
281    action.sa_sigaction = crash_handler;
282    action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
283    sigemptyset(&action.sa_mask);
284    sigaction(SIGILL, &action, &old_sigill);
285
286    action.sa_handler = NULL;
287    action.sa_sigaction = crash_handler;
288    action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
289    sigemptyset(&action.sa_mask);
290    sigaction(SIGFPE, &action, &old_sigfpe);
291
292    action.sa_handler = NULL;
293    action.sa_sigaction = crash_handler;
294    action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
295    sigemptyset(&action.sa_mask);
296    sigaction(SIGBUS, &action, &old_sigbus);
297
298    action.sa_handler = NULL;
299    action.sa_sigaction = crash_handler;
300    action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
301    sigemptyset(&action.sa_mask);
302    sigaction(SIGABRT, &action, &old_sigabrt);
303
304    for (;;)
305      {
306         int fd;
307         struct sockaddr_un client;
308         socklen_t len;
309
310         len = sizeof(struct sockaddr_un);
311         fd = accept(sock, (struct sockaddr *)&client, &len);
312         elm_quicklaunch_sub_init(argc, argv);
313 // don't seed since we are doing this AFTER launch request        
314 //      elm_quicklaunch_seed();
315         if (fd >= 0)
316           {
317              unsigned long bytes;
318              int num;
319
320              num = read(fd, &bytes, sizeof(unsigned long));
321              if (num == sizeof(unsigned long))
322                handle_run(fd, bytes);
323           }
324         while (elm_quicklaunch_sub_shutdown() > 0);
325      }
326    elm_quicklaunch_shutdown();
327
328    if ((_log_dom > -1) && (_log_dom != EINA_LOG_DOMAIN_GLOBAL))
329      {
330         eina_log_domain_unregister(_log_dom);
331         _log_dom = -1;
332      }
333    eina_shutdown();
334
335    return 0;
336 }