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