diff --git a/sapi/fpm/config.m4 b/sapi/fpm/config.m4 index 6c860c9a221..ad46717acdb 100644 --- a/sapi/fpm/config.m4 +++ b/sapi/fpm/config.m4 @@ -16,6 +16,7 @@ AC_DEFUN([AC_FPM_STDLIBS], AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h sys/uio.h]) AC_CHECK_HEADERS([sys/select.h sys/socket.h sys/time.h]) AC_CHECK_HEADERS([arpa/inet.h netinet/in.h]) + AC_CHECK_HEADERS([sysexits.h]) ]) AC_DEFUN([AC_FPM_PRCTL], diff --git a/sapi/fpm/fpm/fpm.c b/sapi/fpm/fpm/fpm.c index 909902b71c5..176dbaf32ec 100644 --- a/sapi/fpm/fpm/fpm.c +++ b/sapi/fpm/fpm/fpm.c @@ -66,7 +66,7 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int t 0 > fpm_event_init_main()) { if (fpm_globals.test_successful) { - exit(0); + exit(FPM_EXIT_OK); } else { zlog(ZLOG_ERROR, "FPM initialization failed"); return -1; diff --git a/sapi/fpm/fpm/fpm.h b/sapi/fpm/fpm/fpm.h index 2a69cb229f9..b0bed0a0741 100644 --- a/sapi/fpm/fpm/fpm.h +++ b/sapi/fpm/fpm/fpm.h @@ -7,6 +7,35 @@ #include +#ifdef HAVE_SYSEXITS_H +#include +#endif + +#ifdef EX_OK +#define FPM_EXIT_OK EX_OK +#else +#define FPM_EXIT_OK 0 +#endif + +#ifdef EX_USAGE +#define FPM_EXIT_USAGE EX_USAGE +#else +#define FPM_EXIT_USAGE 64 +#endif + +#ifdef EX_SOFTWARE +#define FPM_EXIT_SOFTWARE EX_SOFTWARE +#else +#define FPM_EXIT_SOFTWARE 70 +#endif + +#ifdef EX_CONFIG +#define FPM_EXIT_CONFIG EX_CONFIG +#else +#define FPM_EXIT_CONFIG 78 +#endif + + int fpm_run(int *max_requests); int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root); diff --git a/sapi/fpm/fpm/fpm_children.c b/sapi/fpm/fpm/fpm_children.c index 35058b0ea10..84a94743322 100644 --- a/sapi/fpm/fpm/fpm_children.c +++ b/sapi/fpm/fpm/fpm_children.c @@ -156,7 +156,7 @@ static void fpm_child_init(struct fpm_worker_pool_s *wp) /* {{{ */ 0 > fpm_php_init_child(wp)) { zlog(ZLOG_ERROR, "[pool %s] child failed to initialize", wp->config->name); - exit(255); + exit(FPM_EXIT_SOFTWARE); } } /* }}} */ @@ -198,7 +198,7 @@ void fpm_children_bury() /* {{{ */ restart_child = 0; } - if (WEXITSTATUS(status) != 0) { + if (WEXITSTATUS(status) != FPM_EXIT_OK) { severity = ZLOG_WARNING; } diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index 130673f331b..c3fd2bca74c 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -1528,7 +1528,7 @@ static zend_module_entry cgi_module_entry = { */ int main(int argc, char *argv[]) { - int exit_status = SUCCESS; + int exit_status = FPM_EXIT_OK; int cgi = 0, c, use_extended_info = 0; zend_file_handle file_handle; @@ -1659,7 +1659,7 @@ int main(int argc, char *argv[]) php_output_end_all(TSRMLS_C); php_output_deactivate(TSRMLS_C); fcgi_shutdown(); - exit_status = 0; + exit_status = FPM_EXIT_OK; goto out; case 'i': /* php info & quit */ @@ -1680,7 +1680,7 @@ int main(int argc, char *argv[]) php_output_end_all(TSRMLS_C); php_output_deactivate(TSRMLS_C); fcgi_shutdown(); - exit_status = 0; + exit_status = (c == 'h') ? FPM_EXIT_OK : FPM_EXIT_USAGE; goto out; case 'v': /* show php version & quit */ @@ -1688,7 +1688,7 @@ int main(int argc, char *argv[]) if (php_request_startup(TSRMLS_C) == FAILURE) { SG(server_context) = NULL; php_module_shutdown(TSRMLS_C); - return FAILURE; + return FPM_EXIT_SOFTWARE; } SG(headers_sent) = 1; SG(request_info).no_headers = 1; @@ -1700,7 +1700,7 @@ int main(int argc, char *argv[]) #endif php_request_shutdown((void *) 0); fcgi_shutdown(); - exit_status = 0; + exit_status = FPM_EXIT_OK; goto out; } } @@ -1711,14 +1711,14 @@ int main(int argc, char *argv[]) if (php_request_startup(TSRMLS_C) == FAILURE) { SG(server_context) = NULL; php_module_shutdown(TSRMLS_C); - return FAILURE; + return FPM_EXIT_SOFTWARE; } SG(headers_sent) = 1; SG(request_info).no_headers = 1; php_print_info(0xFFFFFFFF TSRMLS_CC); php_request_shutdown((void *) 0); fcgi_shutdown(); - exit_status = 0; + exit_status = FPM_EXIT_OK; goto out; } @@ -1731,7 +1731,7 @@ int main(int argc, char *argv[]) php_output_end_all(TSRMLS_C); php_output_deactivate(TSRMLS_C); fcgi_shutdown(); - exit_status = 0; + exit_status = FPM_EXIT_USAGE; goto out; } @@ -1750,7 +1750,7 @@ int main(int argc, char *argv[]) #ifdef ZTS tsrm_shutdown(); #endif - return FAILURE; + return FPM_EXIT_SOFTWARE; } if (use_extended_info) { @@ -1793,14 +1793,23 @@ consult the installation file that came with this distribution, or visit \n\ */ tsrm_shutdown(); #endif - return FAILURE; + return FPM_EXIT_SOFTWARE; } } if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root)) { - return FAILURE; + + if (fpm_global_config.daemonize) { + zlog(ZLOG_DEBUG, "Sending SIGUSR2 (error) to parent %d", getppid()); + kill(getppid(), SIGUSR2); + } + return FPM_EXIT_CONFIG; } + if (fpm_global_config.daemonize) { + zlog(ZLOG_DEBUG, "Sending SIGUSR1 (OK) to parent %d", getppid()); + kill(getppid(), SIGUSR1); + } fpm_is_running = 1; fcgi_fd = fpm_run(&max_requests); @@ -1832,7 +1841,7 @@ consult the installation file that came with this distribution, or visit \n\ fcgi_finish_request(&request, 1); SG(server_context) = NULL; php_module_shutdown(TSRMLS_C); - return FAILURE; + return FPM_EXIT_SOFTWARE; } /* check if request_method has been sent. @@ -1920,17 +1929,9 @@ fastcgi_request_done: php_request_shutdown((void *) 0); - if (exit_status == 0) { - exit_status = EG(exit_status); - } - requests++; if (max_requests && (requests == max_requests)) { fcgi_finish_request(&request, 1); - if (max_requests != 1) { - /* no need to return exit_status of the last request */ - exit_status = 0; - } break; } /* end of fastcgi loop */ @@ -1944,7 +1945,7 @@ fastcgi_request_done: free(cgi_sapi_module.ini_entries); } } zend_catch { - exit_status = 255; + exit_status = FPM_EXIT_SOFTWARE; } zend_end_try(); out: diff --git a/sapi/fpm/fpm/fpm_process_ctl.c b/sapi/fpm/fpm/fpm_process_ctl.c index e698eb0ca2a..7840d17f8b9 100644 --- a/sapi/fpm/fpm/fpm_process_ctl.c +++ b/sapi/fpm/fpm/fpm_process_ctl.c @@ -71,7 +71,7 @@ static void fpm_pctl_exit() /* {{{ */ fpm_conf_unlink_pid(); fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT_MAIN); - exit(0); + exit(FPM_EXIT_OK); } /* }}} */ @@ -100,7 +100,7 @@ static void fpm_pctl_exec() /* {{{ */ fpm_cleanups_run(FPM_CLEANUP_PARENT_EXEC); execvp(saved_argv[0], saved_argv); zlog(ZLOG_SYSERROR, "failed to reload: execvp() failed"); - exit(1); + exit(FPM_EXIT_SOFTWARE); } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_signals.c b/sapi/fpm/fpm/fpm_signals.c index 8993a860ae8..656269f1a36 100644 --- a/sapi/fpm/fpm/fpm_signals.c +++ b/sapi/fpm/fpm/fpm_signals.c @@ -249,3 +249,15 @@ int fpm_signals_get_fd() /* {{{ */ } /* }}} */ +void fpm_signals_sighandler_exit_ok(pid_t pid) /* {{{ */ +{ + exit(FPM_EXIT_OK); +} +/* }}} */ + +void fpm_signals_sighandler_exit_config(pid_t pid) /* {{{ */ +{ + exit(FPM_EXIT_CONFIG); +} +/* }}} */ + diff --git a/sapi/fpm/fpm/fpm_signals.h b/sapi/fpm/fpm/fpm_signals.h index eb80faecfdb..13484cbac28 100644 --- a/sapi/fpm/fpm/fpm_signals.h +++ b/sapi/fpm/fpm/fpm_signals.h @@ -11,6 +11,9 @@ int fpm_signals_init_main(); int fpm_signals_init_child(); int fpm_signals_get_fd(); +void fpm_signals_sighandler_exit_ok(pid_t pid); +void fpm_signals_sighandler_exit_config(pid_t pid); + extern const char *fpm_signal_names[NSIG + 1]; #endif diff --git a/sapi/fpm/fpm/fpm_unix.c b/sapi/fpm/fpm/fpm_unix.c index fb61d63416d..1ab81896054 100644 --- a/sapi/fpm/fpm/fpm_unix.c +++ b/sapi/fpm/fpm/fpm_unix.c @@ -23,6 +23,7 @@ #include "fpm_clock.h" #include "fpm_stdio.h" #include "fpm_unix.h" +#include "fpm_signals.h" #include "zlog.h" size_t fpm_pagesize; @@ -242,18 +243,75 @@ int fpm_unix_init_main() /* {{{ */ fpm_pagesize = getpagesize(); if (fpm_global_config.daemonize) { - switch (fork()) { - case -1 : + /* + * If daemonize, the calling process will die soon + * and the master process continues to initialize itself. + * + * The parent process has then to wait for the master + * process to initialize to return a consistent exit + * value. For this pupose, the master process will + * send USR1 if everything went well and USR2 + * otherwise. + */ + + struct sigaction act; + struct sigaction oldact_usr1; + struct sigaction oldact_usr2; + struct timeval tv; + + /* + * set sigaction for USR1 before fork + * save old sigaction to restore it after + * fork in the child process (the master process) + */ + memset(&act, 0, sizeof(act)); + memset(&act, 0, sizeof(oldact_usr1)); + act.sa_handler = fpm_signals_sighandler_exit_ok; + sigfillset(&act.sa_mask); + sigaction(SIGUSR1, &act, &oldact_usr1); + + /* + * set sigaction for USR2 before fork + * save old sigaction to restore it after + * fork in the child process (the master process) + */ + memset(&act, 0, sizeof(act)); + memset(&act, 0, sizeof(oldact_usr2)); + act.sa_handler = fpm_signals_sighandler_exit_config; + sigfillset(&act.sa_mask); + sigaction(SIGUSR2, &act, &oldact_usr2); + + /* then fork */ + pid_t pid = fork(); + switch (pid) { + + case -1 : /* error */ zlog(ZLOG_SYSERROR, "failed to daemonize"); return -1; - case 0 : + + case 0 : /* children */ + /* restore USR1 and USR2 sigaction */ + sigaction(SIGUSR1, &oldact_usr1, NULL); + sigaction(SIGUSR2, &oldact_usr2, NULL); break; - default : + + default : /* parent */ fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT); - exit(0); + + /* + * wait for 10s before exiting with error + * the child is supposed to send USR1 or USR2 to tell the parent + * how it goes for it + */ + tv.tv_sec = 10; + tv.tv_usec = 0; + zlog(ZLOG_DEBUG, "The calling process is waiting for the master process to ping"); + select(0, NULL, NULL, NULL, &tv); + exit(FPM_EXIT_SOFTWARE); } } + /* continue as a child */ setsid(); if (0 > fpm_clock_init()) { return -1;