[Release] wrt_0.8.166 for tizen_2.1 branch
[platform/framework/web/wrt.git] / src / wrt-launchpad-daemon / launchpad_src / launchpad.c
1 /*
2  * Copyright (c) 2011 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 /*
18  * simple AUL daemon - launchpad
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <dlfcn.h>
24 #include <X11/Xlib.h>
25 #include <sys/types.h>
26 #include <signal.h>
27 #include <dirent.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <sys/wait.h>
31 #include <poll.h>
32 #include <sys/prctl.h>
33 #include <sys/time.h>
34 #include <sys/resource.h>
35 #include <malloc.h>
36
37 #include "app_sock.h"
38 #include <aul.h>
39
40 #include "config.h"
41
42 #include "menu_db_util.h"
43 #include "simple_util.h"
44 #include "access_control.h"
45 #include "preload.h"
46 #include "preexec.h"
47 #include "perf.h"
48 #include "sigchild.h"
49 #include "aul_util.h"
50
51 #include "util_x.h"
52
53 #include "gl.h"
54
55 #include <app-checker.h>
56 #include <sqlite3.h>
57
58 #include "process_pool.h"
59 #include "launchpad_util.h"
60
61 #define _static_ static inline
62 #define SQLITE_FLUSH_MAX    (1048576)       /* (1024*1024) */
63 #define AUL_POLL_CNT        15
64 #define AUL_PR_NAME         16
65 #define PKG_ID_LENGTH       11
66
67 #define EXEC_DUMMY_EXPIRED 5
68 #define DIFF(a,b) (((a)>(b))?(a)-(b):(b)-(a))
69 #define WRT_CLIENT_PATH "/usr/bin/wrt-client"
70 #define LOWEST_PRIO 20
71 #define DUMMY_NONE 0
72
73 static char *launchpad_cmdline;
74 static int initialized = 0;
75 static int dummy_process_pid    = DUMMY_NONE;
76 static int dummy_process_fd     = -1;
77 static int last_dummy_exec_time = 0;
78 static int process_pool_disable = 0;
79
80 _static_ int __prepare_exec(const char *pkg_name,
81                             const char *app_path, app_info_from_db * menu_info,
82                             bundle * kb);
83 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb);
84 _static_ char **__create_argc_argv(bundle * kb, int *margc);
85 _static_ int __normal_fork_exec(int argc, char **argv);
86 _static_ void __real_launch(const char *app_path, bundle * kb);
87 _static_ int __dummy_launch(int dummy_client_fd, app_pkt_t* pkt);
88 _static_ int __child_raise_win_by_x(int pid, void *priv);
89 _static_ int __raise_win_by_x(int pid);
90 _static_ int __send_to_sigkill(int pid);
91 _static_ int __term_app(int pid);
92 _static_ int __resume_app(int pid);
93 _static_ void __real_send(int clifd, int ret);
94 _static_ void __send_result_to_caller(int clifd, int ret);
95 _static_ void __launchpad_exec_dummy(int main_fd, int pool_fd, int client_fd);
96 _static_ void __launchpad_main_loop(int main_fd, int pool_fd);
97 _static_ int __launchpad_pre_init(int argc, char **argv);
98 _static_ int __launchpad_post_init();
99
100 extern ail_error_e ail_db_close(void);
101
102 _static_ int __prepare_exec(const char *pkg_name,
103                             const char *app_path, app_info_from_db * menu_info,
104                             bundle * kb)
105 {
106     char *file_name;
107     char process_name[AUL_PR_NAME];
108
109     /* Set new session ID & new process group ID*/
110     /* In linux, child can set new session ID without check permission */
111     /* TODO : should be add to check permission in the kernel*/
112     setsid();
113
114     __preexec_run(menu_info->pkg_type, pkg_name, app_path);
115
116     /* SET OOM*/
117     __set_oom();
118
119     /* SET PRIVILEGES*/
120     char pkg_id[PKG_ID_LENGTH];
121     memset(pkg_id, '\0', PKG_ID_LENGTH);
122     snprintf(pkg_id, PKG_ID_LENGTH, "%s", pkg_name);
123
124     if (__set_access(pkg_id, menu_info->pkg_type, app_path) < 0) {
125         _D("fail to set privileges - check your package's credential\n");
126         return -1;
127     }
128
129     /* SET DUMPABLE - for coredump*/
130     prctl(PR_SET_DUMPABLE, 1);
131
132     /* SET PROCESS NAME*/
133     if (app_path == NULL) {
134         _D("app_path should not be NULL - check menu db");
135         return -1;
136     }
137     file_name = strrchr(app_path, '/') + 1;
138     if (file_name == NULL) {
139         _D("can't locate file name to execute");
140         return -1;
141     }
142     memset(process_name, '\0', AUL_PR_NAME);
143     snprintf(process_name, AUL_PR_NAME, "%s", file_name);
144     prctl(PR_SET_NAME, process_name);
145
146     /* SET ENVIROMENT*/
147     __set_env(menu_info, kb);
148
149     return 0;
150 }
151
152 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb)
153 {
154     int datalen;
155     int ret;
156     bundle_raw *kb_data;
157
158     bundle_encode(kb, &kb_data, &datalen);
159     if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0) {
160         _E("error request fake launch - error code = %d", ret);
161     }
162     free(kb_data);
163     return ret;
164 }
165
166 _static_ int __normal_fork_exec(int argc, char **argv)
167 {
168     _D("start real fork and exec\n");
169
170     // warning: unused parameter
171     (void)argc;
172
173     if (execv(argv[0], argv) < 0) {     /* Flawfinder: ignore */
174         if (errno == EACCES) {
175             _E("such a file is no executable - %s", argv[0]);
176         } else {
177             _E("unknown executable error - %s", argv[0]);
178         }
179         return -1;
180     }
181     /* never reach*/
182     return 0;
183 }
184
185 _static_ void __real_launch(const char *app_path, bundle * kb)
186 {
187     int app_argc;
188     char **app_argv;
189     int i;
190
191     app_argv = __create_argc_argv(kb, &app_argc);
192
193 #ifndef NATIVE_LAUNCHPAD
194     if (__change_cmdline((char *)app_path) < 0) {
195         _E("change cmdline fail");
196         return;
197     }
198
199     app_argv[0] = g_argv[0];
200 #else
201     app_argv[0] = strdup(app_path);
202 #endif
203
204     for (i = 0; i < app_argc; i++) {
205         _D("input argument %d : %s##", i, app_argv[i]);
206     }
207
208     PERF("setup argument done");
209     _E("lock up test log(no error) : setup argument done");
210
211     /* Temporary log: launch time checking */
212     LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
213
214     __preload_exec(app_argc, app_argv);
215
216     __normal_fork_exec(app_argc, app_argv);
217 }
218
219 _static_ int __dummy_launch(int dummy_client_fd, app_pkt_t* pkt)
220 {
221     return __send_pkt_raw_data(dummy_client_fd, pkt);
222 }
223
224 _static_ int __child_raise_win_by_x(int pid, void *priv)
225 {
226     // warning: unused parameter
227     priv = priv;
228
229     return x_util_raise_win(pid);
230 }
231
232 _static_ int __raise_win_by_x(int pid)
233 {
234     int pgid;
235     if (x_util_raise_win(pid) == 0) {
236         return 0;
237     }
238
239     /* support app launched by shell script*/
240     pgid = getpgid(pid);
241     _D("X raise failed. try to find first child & raise it - c:%d p:%d\n",
242        pgid, pid);
243
244     if (pgid <= 1) {
245         return -1;
246     }
247     if (__proc_iter_pgid(pgid, __child_raise_win_by_x, NULL) < 0) {
248         return -1;
249     }
250
251     return 0;
252 }
253
254 _static_ int __send_to_sigkill(int pid)
255 {
256     int pgid;
257
258     pgid = getpgid(pid);
259     if (pgid <= 1) {
260         return -1;
261     }
262
263     if (killpg(pgid, SIGKILL) < 0) {
264         return -1;
265     }
266
267     return 0;
268 }
269
270 _static_ int __term_app(int pid)
271 {
272     int dummy;
273     if (__app_send_raw
274             (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0)
275     {
276         _D("terminate packet send error - use SIGKILL");
277         if (__send_to_sigkill(pid) < 0) {
278             _E("fail to killing - %d\n", pid);
279             return -1;
280         }
281     }
282     _D("term done\n");
283     return 0;
284 }
285
286 _static_ int __resume_app(int pid)
287 {
288     int dummy;
289     int ret;
290     if ((ret =
291              __app_send_raw(pid, APP_RESUME_BY_PID, (unsigned char *)&dummy,
292                             sizeof(int))) < 0)
293     {
294         if (ret == -EAGAIN) {
295             _E("resume packet timeout error");
296         } else {
297             _D("resume packet send error - use raise win");
298             if (__raise_win_by_x(pid) < 0) {
299                 _E("raise failed - %d resume fail\n", pid);
300                 _E("we will term the app - %d\n", pid);
301                 __send_to_sigkill(pid);
302                 ret = -1;
303             } else {
304                 ret = 0;
305             }
306         }
307     }
308     _D("resume done\n");
309     return ret;
310 }
311
312 static int __get_caller_pid(bundle *kb)
313 {
314     const char *pid_str;
315     int pid;
316
317     pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
318     if (pid_str) {
319         goto end;
320     }
321
322     pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
323     if (pid_str == NULL) {
324         return -1;
325     }
326
327 end:
328     pid = atoi(pid_str);
329     if (pid <= 1) {
330         return -1;
331     }
332
333     return pid;
334 }
335
336 _static_ int __foward_cmd(int cmd, bundle *kb, int cr_pid)
337 {
338     int pid;
339     char tmp_pid[MAX_PID_STR_BUFSZ];
340     int datalen;
341     bundle_raw *kb_data;
342     int res;
343
344     if ((pid = __get_caller_pid(kb)) < 0) {
345         return AUL_R_ERROR;
346     }
347
348     snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", cr_pid);
349
350     bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
351
352     bundle_encode(kb, &kb_data, &datalen);
353     if ((res = __app_send_raw(pid, cmd, kb_data, datalen)) < 0) {
354         res = AUL_R_ERROR;
355     }
356
357     free(kb_data);
358
359     return res;
360 }
361
362 _static_ void __real_send(int clifd, int ret)
363 {
364     if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
365         if (errno == EPIPE) {
366             _E("send failed due to EPIPE.\n");
367         }
368         _E("send fail to client");
369     }
370
371     close(clifd);
372 }
373
374 _static_ void __send_result_to_caller(int clifd, int ret)
375 {
376     char *cmdline;
377     int wait_count;
378     int cmdline_changed = 0;
379     int cmdline_exist = 0;
380
381     if (clifd == -1) {
382         return;
383     }
384
385     if (ret <= 1) {
386         __real_send(clifd, ret);
387         return;
388     }
389     /* check normally was launched?*/
390     wait_count = 1;
391     do {
392         cmdline = __proc_get_cmdline_bypid(ret);
393         if (cmdline == NULL) {
394             _E("error founded when being launched with %d", ret);
395         } else if (strcmp(cmdline, launchpad_cmdline)) {
396             free(cmdline);
397             cmdline_changed = 1;
398             break;
399         } else {
400             cmdline_exist = 1;
401             free(cmdline);
402         }
403
404         _D("-- now wait to change cmdline --");
405         struct timespec duration = { 0, 50 * 1000 * 1000 };
406         nanosleep(&duration, NULL);     /* 50ms sleep*/
407         wait_count++;
408     } while (wait_count <= 20);         /* max 50*20ms will be sleep*/
409
410     if ((!cmdline_exist) && (!cmdline_changed)) {
411         __real_send(clifd, -1);         /* abnormally launched*/
412         return;
413     }
414
415     if (!cmdline_changed) {
416         _E("process launched, but cmdline not changed");
417     }
418
419     __real_send(clifd, ret);
420     return;
421 }
422
423 _static_ void __launchpad_exec_dummy(int main_fd, int pool_fd, int client_fd)
424 {
425     int pid;
426
427     last_dummy_exec_time = time(NULL);
428
429     pid = fork();
430
431     if (pid == 0) // child
432     {
433         setpriority(PRIO_PROCESS, 0, LOWEST_PRIO);
434         _D("Launch dummy process...");
435
436         //temp - this requires some optimization.
437         sleep(1);
438         _D("sleeping 1sec...");
439
440         /* Set new session ID & new process group ID*/
441         /* In linux, child can set new session ID without check permission */
442         /* TODO : should be add to check permission in the kernel*/
443         setsid();
444
445         /* SET OOM*/
446         __set_oom();
447
448
449         if (main_fd != -1)
450         {
451             close(main_fd);
452         }
453
454         if (pool_fd != -1)
455         {
456             close(pool_fd);
457         }
458
459         if (client_fd != -1)
460         {
461             close(client_fd);
462         }
463
464         __signal_unset_sigchld();
465         __signal_fini();
466
467         /* SET DUMPABLE - for coredump*/
468         prctl(PR_SET_DUMPABLE, 1);
469
470         {
471             void *handle = NULL;
472             int (*dl_main) (int, char **);
473
474             handle = dlopen(WRT_CLIENT_PATH, RTLD_NOW | RTLD_GLOBAL);
475
476             if (handle == NULL)
477             {
478                 _E("dlopen failed.");
479                 exit(-1);
480             }
481
482             dl_main = dlsym(handle, "main");
483
484             sprintf(g_argv[1], "%s", "-d");
485
486             if (dl_main != NULL)
487             {
488                 dl_main(g_argc, g_argv);
489             }
490             else
491             {
492                 _E("dlsym not founded. bad preloaded app - check fpie pie");
493             }
494
495             exit(0);
496         }
497     }
498 }
499
500 _static_ void __launchpad_main_loop(int main_fd, int pool_fd)
501 {
502     bundle *kb = NULL;
503     app_pkt_t *pkt = NULL;
504     app_info_from_db *menu_info = NULL;
505
506     const char *pkg_name = NULL;
507     const char *app_path = NULL;
508     int pid = -1;
509     int clifd = -1;
510     struct ucred cr;
511     int is_real_launch = 0;
512
513     char sock_path[UNIX_PATH_MAX] = { 0, };
514
515     pkt = __app_recv_raw(main_fd, &clifd, &cr);
516     if (!pkt) {
517         _D("packet is NULL");
518         goto end;
519     }
520
521     kb = bundle_decode(pkt->data, pkt->len);
522     if (!kb) {
523         _D("bundle decode error");
524         goto end;
525     }
526
527     INIT_PERF(kb);
528     PERF("packet processing start");
529
530     pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME);
531     _D("pkg name : %s\n", pkg_name);
532
533     menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb);
534     if (menu_info == NULL) {
535         _D("such pkg no found");
536         goto end;
537     }
538
539     app_path = _get_app_path(menu_info);
540     if (app_path == NULL) {
541         _E("app_path is NULL");
542         goto end;
543     }
544     if (app_path[0] != '/') {
545         _D("app_path is not absolute path");
546         goto end;
547     }
548
549     __modify_bundle(kb, cr.pid, menu_info, pkt->cmd);
550     pkg_name = _get_pkgname(menu_info);
551
552     PERF("get package information & modify bundle done");
553
554     if (dummy_process_pid != DUMMY_NONE)
555     {
556         snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, dummy_process_pid);
557         unlink(sock_path);
558
559         __dummy_launch(dummy_process_fd, pkt);
560
561         pid = dummy_process_pid;
562         is_real_launch = 1;
563         close(dummy_process_fd);
564
565         dummy_process_pid = DUMMY_NONE;
566         dummy_process_fd  = -1;
567
568         /* Temporary log: launch time checking */
569         LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
570
571         __launchpad_exec_dummy(main_fd, pool_fd, clifd);
572
573         _D("==> dummy launch pid : %d %s\n", pid, app_path);
574     }
575     else
576     {
577         pid = fork();
578
579         if (pid == 0)
580         {
581             PERF("fork done");
582             _E("lock up test log(no error) : fork done");
583
584             close(clifd);
585             close(main_fd);
586             __signal_unset_sigchld();
587             __signal_fini();
588
589             snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, getpid());
590             unlink(sock_path);
591
592             PERF("prepare exec - first done");
593             _E("lock up test log(no error) : prepare exec - first done");
594
595             if (__prepare_exec(pkg_name, app_path,
596                                menu_info, kb) < 0)
597             {
598                 _E("preparing work fail to launch - "
599                    "can not launch %s\n", pkg_name);
600                 exit(-1);
601             }
602
603             PERF("prepare exec - second done");
604             _E("lock up test log(no error) : prepare exec - second done");
605
606             __real_launch(app_path, kb);
607
608             exit(-1);
609         }
610         _D("==> real launch pid : %d %s\n", pid, app_path);
611         is_real_launch = 1;
612     }
613
614 end:
615     __send_result_to_caller(clifd, pid);
616
617     if (pid > 0) {
618         if (is_real_launch) {
619             /*TODO: retry*/
620             __signal_block_sigchld();
621             __send_app_launch_signal(pid);
622             __signal_unblock_sigchld();
623         }
624     }
625
626     if (menu_info != NULL) {
627         _free_app_info_from_db(menu_info);
628     }
629
630     if (kb != NULL) {
631         bundle_free(kb);
632     }
633     if (pkt != NULL) {
634         free(pkt);
635     }
636
637     /* Active Flusing for Daemon */
638     if (initialized > AUL_POLL_CNT) {
639         sqlite3_release_memory(SQLITE_FLUSH_MAX);
640         malloc_trim(0);
641         initialized = 1;
642     }
643 }
644
645 _static_ int __launchpad_pre_init(int argc, char **argv)
646 {
647     int fd;
648
649     /* signal init*/
650     __signal_init();
651
652     /* get my(launchpad) command line*/
653     launchpad_cmdline = __proc_get_cmdline_bypid(getpid());
654     if (launchpad_cmdline == NULL) {
655         _E("launchpad cmdline fail to get");
656         return -1;
657     }
658     _D("launchpad cmdline = %s", launchpad_cmdline);
659
660     /* create launchpad sock        */
661     fd = __create_server_sock(WRT_LAUNCHPAD_PID);
662     if (fd < 0) {
663         _E("server sock error");
664         return -1;
665     }
666
667     __preload_init(argc, argv);
668
669     __preload_init_for_wrt();
670
671     __preexec_init(argc, argv);
672
673     return fd;
674 }
675
676 _static_ int __launchpad_post_init()
677 {
678     /* Setting this as a global variable to keep track
679      * of launchpad poll cnt */
680     /* static int initialized = 0;*/
681
682     if (initialized) {
683         initialized++;
684         return 0;
685     }
686
687     if (__signal_set_sigchld() < 0) {
688         return -1;
689     }
690
691     initialized++;
692
693     return 0;
694 }
695
696 int main(int argc, char **argv)
697 {
698     enum {
699         LAUNCH_PAD = 0,
700         POOL_SERVER,
701         DUMMY_PROCESS,
702         POLLFD_MAX
703     };
704
705     int main_fd = -1, pool_fd = -1;
706     struct pollfd pfds[POLLFD_MAX];
707
708     memset(pfds, 0x00, sizeof(pfds));
709
710     // process pool feature disable
711     if (getenv("WRT_PROCESS_POOL_DISABLE"))
712     {
713         process_pool_disable = 1;
714     }
715
716     /* init without concerning X & EFL*/
717     main_fd = __launchpad_pre_init(argc, argv);
718
719     if (main_fd < 0)
720     {
721         _E("launchpad pre init failed");
722         goto exit_main;
723     }
724
725     pfds[LAUNCH_PAD].fd      = main_fd;
726     pfds[LAUNCH_PAD].events  = POLLIN;
727     pfds[LAUNCH_PAD].revents = 0;
728
729     pool_fd = __create_process_pool_server();
730
731     if (pool_fd == -1)
732     {
733         _E("Error creationg pool server!");
734         goto exit_main;
735     }
736
737     pfds[POOL_SERVER].fd      = pool_fd;
738     pfds[POOL_SERVER].events  = POLLIN;
739     pfds[POOL_SERVER].revents = 0;
740
741     while (1)
742     {
743         if (dummy_process_pid == DUMMY_NONE)
744         {
745             pfds[DUMMY_PROCESS].fd      = -1;
746             pfds[DUMMY_PROCESS].events  = 0;
747             pfds[DUMMY_PROCESS].revents = 0;
748
749             if ( !process_pool_disable &&
750                  DIFF(last_dummy_exec_time, time(NULL)) > EXEC_DUMMY_EXPIRED)
751             {
752                 __launchpad_exec_dummy(main_fd, pool_fd, -1);
753             }
754         }
755
756         if (poll(pfds, POLLFD_MAX, -1) < 0)
757         {
758             continue;
759         }
760
761         _D("pfds[LAUNCH_PAD].revents    : 0x%x", pfds[LAUNCH_PAD].revents) ;
762         _D("pfds[POOL_SERVER].revents   : 0x%x", pfds[POOL_SERVER].revents) ;
763         _D("pfds[DUMMY_PROCESS].revents : 0x%x", pfds[DUMMY_PROCESS].revents) ;
764
765         /* init with concerning X & EFL (because of booting
766         * sequence problem)*/
767         if (__launchpad_post_init() < 0)
768         {
769             _E("launcpad post init failed");
770             goto exit_main;
771         }
772
773         if ((pfds[LAUNCH_PAD].revents & POLLIN) != 0)
774         {
775             _D("pfds[LAUNCH_PAD].revents & POLLIN");
776             __launchpad_main_loop(pfds[LAUNCH_PAD].fd, pfds[POOL_SERVER].fd);
777         }
778
779         if ((pfds[POOL_SERVER].revents & POLLIN) != 0)
780         {
781             int server_fd, client_fd, client_pid;
782
783             server_fd = pfds[POOL_SERVER].fd;
784
785             _D("pfds[POOL_SERVER].revents & POLLIN");
786
787             if (dummy_process_pid == DUMMY_NONE)
788             {
789                 __accept_dummy_process(server_fd, &client_fd, &client_pid);
790
791                 dummy_process_pid = client_pid;
792                 dummy_process_fd  = client_fd;
793
794                 pfds[DUMMY_PROCESS].fd     = dummy_process_fd;
795                 pfds[DUMMY_PROCESS].events = POLLIN|POLLHUP;
796                 pfds[DUMMY_PROCESS].revents = 0;
797
798                 _D("Dummy process was connected! (pid:%d)", dummy_process_pid);
799             }
800             else
801             {
802                 __refuse_dummy_process(server_fd);
803
804                 _E("Refused dummy process connection!");
805             }
806         }
807
808         if ((pfds[DUMMY_PROCESS].revents & (POLLHUP|POLLNVAL)) != 0)
809         {
810             _D("pfds[DUMMY_PROCESS].revents & (POLLHUP|POLLNVAL) (pid:%d)", dummy_process_pid);
811             close(pfds[DUMMY_PROCESS].fd);
812
813             dummy_process_pid = DUMMY_NONE;
814             dummy_process_fd = -1;
815
816             pfds[DUMMY_PROCESS].fd      = -1;
817             pfds[DUMMY_PROCESS].events  = 0;
818             pfds[DUMMY_PROCESS].revents = 0;
819         }
820     }
821
822     return 0;
823
824     exit_main:
825     if (main_fd != -1)
826     {
827         close(main_fd);
828     }
829
830     if (pool_fd != -1)
831     {
832         close(pool_fd);
833     }
834
835     return -1;
836 }
837