diff options
author | Ondřej Surý <ondrej@sury.org> | 2012-07-23 10:51:19 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2012-07-23 10:51:19 +0200 |
commit | 3365f28adf90110ca7475df889720fc244820f4b (patch) | |
tree | 5415edde3e396a93f05f887d9f07071871467bdf /sapi | |
parent | f0f8d7084aec4be5c07f02f2e29c2820f85c8315 (diff) | |
download | php-3365f28adf90110ca7475df889720fc244820f4b.tar.gz |
Imported Upstream version 5.4.5upstream/5.4.5
Diffstat (limited to 'sapi')
-rw-r--r-- | sapi/cgi/tests/apache_request_headers.phpt | 4 | ||||
-rw-r--r-- | sapi/cli/php_cli.c | 3 | ||||
-rw-r--r-- | sapi/cli/php_cli_server.c | 3 | ||||
-rw-r--r-- | sapi/cli/tests/bug61546.phpt | 11 | ||||
-rw-r--r-- | sapi/fpm/config.m4 | 5 | ||||
-rw-r--r-- | sapi/fpm/fpm/fastcgi.c | 14 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm.c | 9 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm.h | 33 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_children.c | 4 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_conf.c | 48 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_conf.h | 2 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_main.c | 90 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_php.c | 38 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_php.h | 1 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_process_ctl.c | 4 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_signals.c | 12 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_signals.h | 3 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_sockets.c | 25 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_sockets.h | 4 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_status.c | 9 | ||||
-rw-r--r-- | sapi/fpm/fpm/fpm_unix.c | 102 | ||||
-rw-r--r-- | sapi/fpm/fpm/zlog.c | 20 | ||||
-rw-r--r-- | sapi/fpm/fpm/zlog.h | 1 | ||||
-rw-r--r-- | sapi/fpm/php-fpm.conf.in | 16 |
24 files changed, 403 insertions, 58 deletions
diff --git a/sapi/cgi/tests/apache_request_headers.phpt b/sapi/cgi/tests/apache_request_headers.phpt index 2c82d57b2..3dc3580c2 100644 --- a/sapi/cgi/tests/apache_request_headers.phpt +++ b/sapi/cgi/tests/apache_request_headers.phpt @@ -1,5 +1,7 @@ --TEST-- apache_request_headers() stack overflow. +--INI-- +default_charset="UTF-8" --SKIPIF-- <?php include "skipif.inc"; @@ -29,7 +31,7 @@ echo "Done\n"; ?> --EXPECTF-- X-Powered-By: PHP/%s -Content-type: text/html +Content-type: text/html; charset=UTF-8 Array ( diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c index 205b9db3f..2cdd1aac6 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -1173,6 +1173,9 @@ out: if (request_started) { php_request_shutdown((void *) 0); } + if (translated_path) { + free(translated_path); + } return exit_status; err: sapi_deactivate(TSRMLS_C); diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 87ab7b48f..876c57a34 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -1826,6 +1826,9 @@ static int php_cli_server_send_error_page(php_cli_server *server, php_cli_server return SUCCESS; fail: + if (errstr) { + pefree(errstr, 1); + } efree(escaped_request_uri); return FAILURE; } /* }}} */ diff --git a/sapi/cli/tests/bug61546.phpt b/sapi/cli/tests/bug61546.phpt index 2cd690f65..071edb722 100644 --- a/sapi/cli/tests/bug61546.phpt +++ b/sapi/cli/tests/bug61546.phpt @@ -2,13 +2,22 @@ Bug #61546 (functions related to current script failed when chdir() in cli sapi) --FILE-- <?php +// reference doc for getmyinode() on php.net states that it returns an integer or FALSE on error +// on Windows, getmyinode() returns 0 which normally casts to FALSE +// however, the implementation of getmyinode() (in pageinfo.c) returns an explicit FALSE in the +// event that the internal page_inode structure is less than 0, otherwise it returns the long value +// of page_inode. therefore, an explicit 0 should be a passing value for this test. +// +// the ext/standard/tests/file/statpage.phpt test also tests getmyinode() returns an integer and will +// pass even if that integer is 0. on Windows, the getmyinode() call in statpage.phpt returns 0 and +// passes on Windows. $php = getenv("TEST_PHP_EXECUTABLE"); $test_code = <<<PHP <?php chdir('..'); var_dump(get_current_user() != ""); chdir('..'); -var_dump(getmyinode() != false); +var_dump(getmyinode() !== false); var_dump(getlastmod() != false); PHP; diff --git a/sapi/fpm/config.m4 b/sapi/fpm/config.m4 index 89628100b..ad46717ac 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], @@ -192,6 +193,8 @@ AC_DEFUN([AC_FPM_TRACE], have_ptrace=no have_broken_ptrace=yes AC_MSG_RESULT([no]) + ], [ + AC_MSG_RESULT([skipped (cross compiling)]) ]) fi @@ -264,6 +267,8 @@ AC_DEFUN([AC_FPM_TRACE], ], [ proc_mem_file="" AC_MSG_RESULT([no]) + ], [ + AC_MSG_RESULT([skipped (cross compiling)]) ]) fi diff --git a/sapi/fpm/fpm/fastcgi.c b/sapi/fpm/fpm/fastcgi.c index 212b6ff1d..e2e208aa7 100644 --- a/sapi/fpm/fpm/fastcgi.c +++ b/sapi/fpm/fpm/fastcgi.c @@ -399,7 +399,7 @@ static inline int fcgi_param_get_eff_len( unsigned char *p, unsigned char *end, { int ret = 1; int zero_found = 0; - *eff_len = 0; + *eff_len = 0; for (; p != end; ++p) { if (*p == '\0') { zero_found = 1; @@ -427,7 +427,7 @@ static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *e char *tmp = buf; size_t buf_size = sizeof(buf); int name_len, val_len; - uint eff_name_len, eff_val_len; + uint eff_name_len; char *s; int ret = 1; size_t bytes_consumed; @@ -453,8 +453,12 @@ static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *e ret = 0; break; } - if (!fcgi_param_get_eff_len(p, p+name_len, &eff_name_len) || - !fcgi_param_get_eff_len(p+name_len, p+name_len+val_len, &eff_val_len)) { + + /* + * get the effective length of the name in case it's not a valid string + * don't do this on the value because it can be binary data + */ + if (!fcgi_param_get_eff_len(p, p+name_len, &eff_name_len)){ /* Malicious request */ ret = 0; break; @@ -473,7 +477,7 @@ static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *e } memcpy(tmp, p, eff_name_len); tmp[eff_name_len] = 0; - s = estrndup((char*)p + name_len, eff_val_len); + s = estrndup((char*)p + name_len, val_len); if (s == NULL) { ret = 0; break; diff --git a/sapi/fpm/fpm/fpm.c b/sapi/fpm/fpm/fpm.c index 96aabbfc4..dab415d12 100644 --- a/sapi/fpm/fpm/fpm.c +++ b/sapi/fpm/fpm/fpm.c @@ -37,10 +37,12 @@ struct fpm_globals_s fpm_globals = { .max_requests = 0, .is_child = 0, .test_successful = 0, - .heartbeat = 0 + .heartbeat = 0, + .run_as_root = 0, + .send_config_signal = 0, }; -int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf) /* {{{ */ +int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root) /* {{{ */ { fpm_globals.argc = argc; fpm_globals.argv = argv; @@ -49,6 +51,7 @@ int fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int t } fpm_globals.prefix = prefix; fpm_globals.pid = pid; + fpm_globals.run_as_root = run_as_root; if (0 > fpm_php_init_main() || 0 > fpm_stdio_init_main() || @@ -64,7 +67,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 bfeac4d67..7a2903d07 100644 --- a/sapi/fpm/fpm/fpm.h +++ b/sapi/fpm/fpm/fpm.h @@ -7,8 +7,37 @@ #include <unistd.h> +#ifdef HAVE_SYSEXITS_H +#include <sysexits.h> +#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 fpm_init(int argc, char **argv, char *config, char *prefix, char *pid, int test_conf, int run_as_root); struct fpm_globals_s { pid_t parent_pid; @@ -25,6 +54,8 @@ struct fpm_globals_s { int is_child; int test_successful; int heartbeat; + int run_as_root; + int send_config_signal; }; extern struct fpm_globals_s fpm_globals; diff --git a/sapi/fpm/fpm/fpm_children.c b/sapi/fpm/fpm/fpm_children.c index 35058b0ea..84a947433 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_conf.c b/sapi/fpm/fpm/fpm_conf.c index 304076d35..dfe6792c0 100644 --- a/sapi/fpm/fpm/fpm_conf.c +++ b/sapi/fpm/fpm/fpm_conf.c @@ -53,7 +53,9 @@ static int fpm_conf_load_ini_file(char *filename TSRMLS_DC); static char *fpm_conf_set_integer(zval *value, void **config, intptr_t offset); +#if 0 /* not used for now */ static char *fpm_conf_set_long(zval *value, void **config, intptr_t offset); +#endif static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_boolean(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_string(zval *value, void **config, intptr_t offset); @@ -70,6 +72,7 @@ struct fpm_global_config_s fpm_global_config = { .syslog_facility = -1, #endif .process_max = 0, + .process_priority = 64, /* 64 means unset */ }; static struct fpm_worker_pool_s *current_wp = NULL; static int ini_recursion = 0; @@ -92,6 +95,7 @@ static struct ini_value_parser_s ini_fpm_global_options[] = { { "emergency_restart_interval", &fpm_conf_set_time, GO(emergency_restart_interval) }, { "process_control_timeout", &fpm_conf_set_time, GO(process_control_timeout) }, { "process.max", &fpm_conf_set_integer, GO(process_max) }, + { "process.priority", &fpm_conf_set_integer, GO(process_priority) }, { "daemonize", &fpm_conf_set_boolean, GO(daemonize) }, { "rlimit_files", &fpm_conf_set_integer, GO(rlimit_files) }, { "rlimit_core", &fpm_conf_set_rlimit_core, GO(rlimit_core) }, @@ -112,6 +116,7 @@ static struct ini_value_parser_s ini_fpm_pool_options[] = { { "listen.group", &fpm_conf_set_string, WPO(listen_group) }, { "listen.mode", &fpm_conf_set_string, WPO(listen_mode) }, { "listen.allowed_clients", &fpm_conf_set_string, WPO(listen_allowed_clients) }, + { "process.priority", &fpm_conf_set_integer, WPO(process_priority) }, { "pm", &fpm_conf_set_pm, WPO(pm) }, { "pm.max_children", &fpm_conf_set_integer, WPO(pm_max_children) }, { "pm.start_servers", &fpm_conf_set_integer, WPO(pm_start_servers) }, @@ -239,6 +244,7 @@ static char *fpm_conf_set_integer(zval *value, void **config, intptr_t offset) / } /* }}} */ +#if 0 /* not used for now */ static char *fpm_conf_set_long(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); @@ -254,6 +260,7 @@ static char *fpm_conf_set_long(zval *value, void **config, intptr_t offset) /* { return NULL; } /* }}} */ +#endif static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset) /* {{{ */ { @@ -577,6 +584,7 @@ static void *fpm_worker_pool_config_alloc() /* {{{ */ memset(wp->config, 0, sizeof(struct fpm_worker_pool_config_s)); wp->config->listen_backlog = FPM_BACKLOG_DEFAULT; wp->config->pm_process_idle_timeout = 10; /* 10s by default */ + wp->config->process_priority = 64; /* 64 means unset */ if (!fpm_worker_all_pools) { fpm_worker_all_pools = wp; @@ -704,7 +712,7 @@ static int fpm_evaluate_full_path(char **path, struct fpm_worker_pool_s *wp, cha static int fpm_conf_process_all_pools() /* {{{ */ { - struct fpm_worker_pool_s *wp; + struct fpm_worker_pool_s *wp, *wp2; if (!fpm_worker_all_pools) { zlog(ZLOG_ERROR, "No pool defined. at least one pool section must be specified in config file"); @@ -723,8 +731,8 @@ static int fpm_conf_process_all_pools() /* {{{ */ } } - /* user */ - if (!wp->config->user) { + /* alert if user is not set only if we are not root*/ + if (!wp->config->user && !geteuid()) { zlog(ZLOG_ALERT, "[pool %s] user has not been defined", wp->config->name); return -1; } @@ -741,6 +749,11 @@ static int fpm_conf_process_all_pools() /* {{{ */ return -1; } + if (wp->config->process_priority != 64 && (wp->config->process_priority < -19 || wp->config->process_priority > 20)) { + zlog(ZLOG_ERROR, "[pool %s] process.priority must be included into [-19,20]", wp->config->name); + return -1; + } + /* pm */ if (wp->config->pm != PM_STYLE_STATIC && wp->config->pm != PM_STYLE_DYNAMIC && wp->config->pm != PM_STYLE_ONDEMAND) { zlog(ZLOG_ALERT, "[pool %s] the process manager is missing (static, dynamic or ondemand)", wp->config->name); @@ -1044,6 +1057,20 @@ static int fpm_conf_process_all_pools() /* {{{ */ } } } + + /* ensure 2 pools do not use the same listening address */ + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { + for (wp2 = fpm_worker_all_pools; wp2; wp2 = wp2->next) { + if (wp == wp2) { + continue; + } + + if (wp->config->listen_address && *wp->config->listen_address && wp2->config->listen_address && *wp2->config->listen_address && !strcmp(wp->config->listen_address, wp2->config->listen_address)) { + zlog(ZLOG_ERROR, "[pool %s] unable to set listen address as it's already used in another pool '%s'", wp2->config->name, wp->config->name); + return -1; + } + } + } return 0; } /* }}} */ @@ -1103,6 +1130,11 @@ static int fpm_conf_post_process(TSRMLS_D) /* {{{ */ return -1; } + if (fpm_global_config.process_priority != 64 && (fpm_global_config.process_priority < -19 || fpm_global_config.process_priority > 20)) { + zlog(ZLOG_ERROR, "process.priority must be included into [-19,20]"); + return -1; + } + if (!fpm_global_config.error_log) { fpm_global_config.error_log = strdup("log/php-fpm.log"); } @@ -1485,6 +1517,11 @@ static void fpm_conf_dump() /* {{{ */ zlog(ZLOG_NOTICE, "\temergency_restart_threshold = %d", fpm_global_config.emergency_restart_threshold); zlog(ZLOG_NOTICE, "\tprocess_control_timeout = %ds", fpm_global_config.process_control_timeout); zlog(ZLOG_NOTICE, "\tprocess.max = %d", fpm_global_config.process_max); + if (fpm_global_config.process_priority == 64) { + zlog(ZLOG_NOTICE, "\tprocess.priority = undefined"); + } else { + zlog(ZLOG_NOTICE, "\tprocess.priority = %d", fpm_global_config.process_priority); + } zlog(ZLOG_NOTICE, "\tdaemonize = %s", BOOL2STR(fpm_global_config.daemonize)); zlog(ZLOG_NOTICE, "\trlimit_files = %d", fpm_global_config.rlimit_files); zlog(ZLOG_NOTICE, "\trlimit_core = %d", fpm_global_config.rlimit_core); @@ -1504,6 +1541,11 @@ static void fpm_conf_dump() /* {{{ */ zlog(ZLOG_NOTICE, "\tlisten.group = %s", STR2STR(wp->config->listen_group)); zlog(ZLOG_NOTICE, "\tlisten.mode = %s", STR2STR(wp->config->listen_mode)); zlog(ZLOG_NOTICE, "\tlisten.allowed_clients = %s", STR2STR(wp->config->listen_allowed_clients)); + if (wp->config->process_priority == 64) { + zlog(ZLOG_NOTICE, "\tprocess.priority = undefined"); + } else { + zlog(ZLOG_NOTICE, "\tprocess.priority = %d", wp->config->process_priority); + } zlog(ZLOG_NOTICE, "\tpm = %s", PM2STR(wp->config->pm)); zlog(ZLOG_NOTICE, "\tpm.max_children = %d", wp->config->pm_max_children); zlog(ZLOG_NOTICE, "\tpm.start_servers = %d", wp->config->pm_start_servers); diff --git a/sapi/fpm/fpm/fpm_conf.h b/sapi/fpm/fpm/fpm_conf.h index 9fbd5064c..f780f0389 100644 --- a/sapi/fpm/fpm/fpm_conf.h +++ b/sapi/fpm/fpm/fpm_conf.h @@ -35,6 +35,7 @@ struct fpm_global_config_s { int emergency_restart_interval; int process_control_timeout; int process_max; + int process_priority; int daemonize; int rlimit_files; int rlimit_core; @@ -57,6 +58,7 @@ struct fpm_worker_pool_config_s { char *listen_group; char *listen_mode; char *listen_allowed_clients; + int process_priority; int pm; int pm_max_children; int pm_start_servers; diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index 14dccbd14..83b461b79 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -154,6 +154,7 @@ static const opt_struct OPTIONS[] = { {'t', 0, "test"}, {'p', 1, "prefix"}, {'g', 1, "pid"}, + {'R', 0, "allow-to-run-as-root"}, {'-', 0, NULL} /* end of args */ }; @@ -646,12 +647,38 @@ static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC) } } -static void sapi_cgi_log_message(char *message TSRMLS_DC) +/* {{{ sapi_cgi_log_fastcgi + * + * Ignore level, we want to send all messages through fastcgi + */ +void sapi_cgi_log_fastcgi(int level, char *message, size_t len) { - if (CGIG(fcgi_logging)) { - zlog(ZLOG_NOTICE, "PHP message: %s", message); + TSRMLS_FETCH(); + + fcgi_request *request = (fcgi_request*) SG(server_context); + + /* ensure we want: + * - to log (fastcgi.logging in php.ini) + * - we are currently dealing with a request + * - the message is not empty + */ + if (CGIG(fcgi_logging) && request && message && len > 0) { + char *buf = malloc(len + 2); + memcpy(buf, message, len); + memcpy(buf + len, "\n", sizeof("\n")); + fcgi_write(request, FCGI_STDERR, buf, len+1); + free(buf); } } +/* }}} */ + +/* {{{ sapi_cgi_log_message + */ +static void sapi_cgi_log_message(char *message) +{ + zlog(ZLOG_NOTICE, "PHP message: %s", message); +} +/* }}} */ /* {{{ php_cgi_ini_activate_user_config */ @@ -900,7 +927,9 @@ static void php_cgi_usage(char *argv0) " Specify the PID file location.\n" " -y, --fpm-config <file>\n" " Specify alternative path to FastCGI process manager config file.\n" - " -t, --test Test FPM configuration and exit\n", + " -t, --test Test FPM configuration and exit\n" + " -R, --allow-to-run-as-root\n" + " Allow pool to run as root (disabled by default)\n", prog, PHP_PREFIX); } /* }}} */ @@ -1499,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; @@ -1522,6 +1551,7 @@ int main(int argc, char *argv[]) char *fpm_pid = NULL; int test_conf = 0; int php_information = 0; + int php_allow_to_run_as_root = 0; #ifdef HAVE_SIGNAL_H #if defined(SIGPIPE) && defined(SIG_IGN) @@ -1629,13 +1659,17 @@ 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 */ php_information = 1; break; + case 'R': /* allow to run as root */ + php_allow_to_run_as_root = 1; + break; + default: case 'h': case '?': @@ -1646,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 */ @@ -1654,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; @@ -1666,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; } } @@ -1677,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; } @@ -1697,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; } @@ -1716,7 +1750,7 @@ int main(int argc, char *argv[]) #ifdef ZTS tsrm_shutdown(); #endif - return FAILURE; + return FPM_EXIT_SOFTWARE; } if (use_extended_info) { @@ -1759,19 +1793,31 @@ 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)) { - return FAILURE; + 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)) { + + if (fpm_globals.send_config_signal) { + zlog(ZLOG_DEBUG, "Sending SIGUSR2 (error) to parent %d", getppid()); + kill(getppid(), SIGUSR2); + } + return FPM_EXIT_CONFIG; } + if (fpm_globals.send_config_signal) { + zlog(ZLOG_DEBUG, "Sending SIGUSR1 (OK) to parent %d", getppid()); + kill(getppid(), SIGUSR1); + } fpm_is_running = 1; fcgi_fd = fpm_run(&max_requests); parent = 0; + /* onced forked tell zlog to also send messages through sapi_cgi_log_fastcgi() */ + zlog_set_external_logger(sapi_cgi_log_fastcgi); + /* make php call us to get _ENV vars */ php_php_import_environment_variables = php_import_environment_variables; php_import_environment_variables = cgi_php_import_environment_variables; @@ -1795,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. @@ -1883,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 */ @@ -1907,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_php.c b/sapi/fpm/fpm/fpm_php.c index 840eec73e..cd4d3aef3 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -257,3 +257,41 @@ int fpm_php_limit_extensions(char *path) /* {{{ */ return 1; /* extension not found: not allowed */ } /* }}} */ + +char* fpm_php_get_string_from_table(char *table, char *key TSRMLS_DC) /* {{{ */ +{ + zval **data, **tmp; + char *string_key; + uint string_len; + ulong num_key; + if (!table || !key) { + return NULL; + } + + /* inspired from ext/standard/info.c */ + + zend_is_auto_global(table, strlen(table) TSRMLS_CC); + + /* find the table and ensure it's an array */ + if (zend_hash_find(&EG(symbol_table), table, strlen(table) + 1, (void **) &data) == SUCCESS && Z_TYPE_PP(data) == IS_ARRAY) { + + /* reset the internal pointer */ + zend_hash_internal_pointer_reset(Z_ARRVAL_PP(data)); + + /* parse the array to look for our key */ + while (zend_hash_get_current_data(Z_ARRVAL_PP(data), (void **) &tmp) == SUCCESS) { + /* ensure the key is a string */ + if (zend_hash_get_current_key_ex(Z_ARRVAL_PP(data), &string_key, &string_len, &num_key, 0, NULL) == HASH_KEY_IS_STRING) { + /* compare to our key */ + if (!strncmp(string_key, key, string_len)) { + return Z_STRVAL_PP(tmp); + } + } + zend_hash_move_forward(Z_ARRVAL_PP(data)); + } + } + + return NULL; +} +/* }}} */ + diff --git a/sapi/fpm/fpm/fpm_php.h b/sapi/fpm/fpm/fpm_php.h index a2c7ed318..d6054737d 100644 --- a/sapi/fpm/fpm/fpm_php.h +++ b/sapi/fpm/fpm/fpm_php.h @@ -44,6 +44,7 @@ void fpm_php_soft_quit(); int fpm_php_init_main(); int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode); int fpm_php_limit_extensions(char *path); +char* fpm_php_get_string_from_table(char *table, char *key TSRMLS_DC); #endif diff --git a/sapi/fpm/fpm/fpm_process_ctl.c b/sapi/fpm/fpm/fpm_process_ctl.c index e698eb0ca..7840d17f8 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 8993a860a..656269f1a 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 eb80faecf..13484cbac 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_sockets.c b/sapi/fpm/fpm/fpm_sockets.c index cb4897e9b..d24dcccc9 100644 --- a/sapi/fpm/fpm/fpm_sockets.c +++ b/sapi/fpm/fpm/fpm_sockets.c @@ -179,6 +179,10 @@ static int fpm_sockets_new_listening_socket(struct fpm_worker_pool_s *wp, struct setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)); if (wp->listen_address_domain == FPM_AF_UNIX) { + if (fpm_socket_unix_test_connect((struct sockaddr_un *)sa, socklen) == 0) { + zlog(ZLOG_ERROR, "An another FPM instance seems to already listen on %s", ((struct sockaddr_un *) sa)->sun_path); + return -1; + } unlink( ((struct sockaddr_un *) sa)->sun_path); saved_umask = umask(0777 ^ wp->socket_mode); } @@ -450,3 +454,24 @@ int fpm_socket_get_listening_queue(int sock, unsigned *cur_lq, unsigned *max_lq) } #endif + +int fpm_socket_unix_test_connect(struct sockaddr_un *sun, size_t socklen) /* {{{ */ +{ + int fd; + + if (!sun || sun->sun_family != AF_UNIX) { + return -1; + } + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + return -1; + } + + if (connect(fd, (struct sockaddr *)sun, socklen) == -1) { + return -1; + } + + close(fd); + return 0; +} +/* }}} */ diff --git a/sapi/fpm/fpm/fpm_sockets.h b/sapi/fpm/fpm/fpm_sockets.h index 447fbff4b..499ba6baf 100644 --- a/sapi/fpm/fpm/fpm_sockets.h +++ b/sapi/fpm/fpm/fpm_sockets.h @@ -5,6 +5,9 @@ #ifndef FPM_MISC_H #define FPM_MISC_H 1 +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> #include <unistd.h> #include <fcntl.h> @@ -22,6 +25,7 @@ enum fpm_address_domain fpm_sockets_domain_from_address(char *addr); int fpm_sockets_init_main(); int fpm_socket_get_listening_queue(int sock, unsigned *cur_lq, unsigned *max_lq); +int fpm_socket_unix_test_connect(struct sockaddr_un *sun, size_t socklen); static inline int fd_set_blocked(int fd, int blocked) /* {{{ */ diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c index 83de76d5a..5f2c852c7 100644 --- a/sapi/fpm/fpm/fpm_status.c +++ b/sapi/fpm/fpm/fpm_status.c @@ -14,6 +14,7 @@ #include "zlog.h" #include "fpm_atomic.h" #include "fpm_conf.h" +#include "fpm_php.h" #include <ext/standard/html.h> static char *fpm_status_uri = NULL; @@ -125,13 +126,13 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ } /* full status ? */ - full = SG(request_info).request_uri && strstr(SG(request_info).query_string, "full"); + full = (fpm_php_get_string_from_table("_GET", "full" TSRMLS_CC) != NULL); short_syntax = short_post = NULL; full_separator = full_pre = full_syntax = full_post = NULL; encode = 0; /* HTML */ - if (SG(request_info).query_string && strstr(SG(request_info).query_string, "html")) { + if (fpm_php_get_string_from_table("_GET", "html" TSRMLS_CC)) { sapi_add_header_ex(ZEND_STRL("Content-Type: text/html"), 1, 1 TSRMLS_CC); time_format = "%d/%b/%Y:%H:%M:%S %z"; encode = 1; @@ -205,7 +206,7 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ } /* XML */ - } else if (SG(request_info).request_uri && strstr(SG(request_info).query_string, "xml")) { + } else if (fpm_php_get_string_from_table("_GET", "xml" TSRMLS_CC)) { sapi_add_header_ex(ZEND_STRL("Content-Type: text/xml"), 1, 1 TSRMLS_CC); time_format = "%s"; encode = 1; @@ -256,7 +257,7 @@ int fpm_status_handle_request(TSRMLS_D) /* {{{ */ } /* JSON */ - } else if (SG(request_info).request_uri && strstr(SG(request_info).query_string, "json")) { + } else if (fpm_php_get_string_from_table("_GET", "json" TSRMLS_CC)) { sapi_add_header_ex(ZEND_STRL("Content-Type: application/json"), 1, 1 TSRMLS_CC); time_format = "%s"; diff --git a/sapi/fpm/fpm/fpm_unix.c b/sapi/fpm/fpm/fpm_unix.c index 17d0b8125..5c5e37c3a 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; @@ -112,12 +113,12 @@ static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ } } -#ifndef I_REALLY_WANT_ROOT_PHP - if (wp->set_uid == 0 || wp->set_gid == 0) { - zlog(ZLOG_ERROR, "[pool %s] please specify user and group other than root", wp->config->name); - return -1; + if (!fpm_globals.run_as_root) { + if (wp->set_uid == 0 || wp->set_gid == 0) { + zlog(ZLOG_ERROR, "[pool %s] please specify user and group other than root", wp->config->name); + return -1; + } } -#endif } else { /* not root */ if (wp->config->user && *wp->config->user) { zlog(ZLOG_WARNING, "[pool %s] 'user' directive is ignored when FPM is not running as root", wp->config->name); @@ -128,6 +129,9 @@ static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */ if (wp->config->chroot && *wp->config->chroot) { zlog(ZLOG_WARNING, "[pool %s] 'chroot' directive is ignored when FPM is not running as root", wp->config->name); } + if (wp->config->process_priority != 64) { + zlog(ZLOG_WARNING, "[pool %s] 'process.priority' directive is ignored when FPM is not running as root", wp->config->name); + } /* set up HOME and USER anyway */ pwd = getpwuid(getuid()); @@ -183,6 +187,14 @@ int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ } if (is_root) { + + if (wp->config->process_priority != 64) { + if (setpriority(PRIO_PROCESS, 0, wp->config->process_priority) < 0) { + zlog(ZLOG_SYSERROR, "[pool %s] Unable to set priority for this new process", wp->config->name); + return -1; + } + } + if (wp->set_gid) { if (0 > setgid(wp->set_gid)) { zlog(ZLOG_SYSERROR, "[pool %s] failed to setgid(%d)", wp->config->name, wp->set_gid); @@ -217,6 +229,7 @@ int fpm_unix_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ int fpm_unix_init_main() /* {{{ */ { struct fpm_worker_pool_s *wp; + int is_root = !geteuid(); if (fpm_global_config.rlimit_files) { struct rlimit r; @@ -242,23 +255,92 @@ 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); + fpm_globals.send_config_signal = 1; 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; } + if (fpm_global_config.process_priority != 64) { + if (is_root) { + if (setpriority(PRIO_PROCESS, 0, fpm_global_config.process_priority) < 0) { + zlog(ZLOG_SYSERROR, "Unable to set priority for the master process"); + return -1; + } + } else { + zlog(ZLOG_WARNING, "'process.priority' directive is ignored when FPM is not running as root"); + } + } + fpm_globals.parent_pid = getpid(); for (wp = fpm_worker_all_pools; wp; wp = wp->next) { if (0 > fpm_unix_conf_wp(wp)) { diff --git a/sapi/fpm/fpm/zlog.c b/sapi/fpm/fpm/zlog.c index b127ec16f..80db9d837 100644 --- a/sapi/fpm/fpm/zlog.c +++ b/sapi/fpm/fpm/zlog.c @@ -22,6 +22,7 @@ static int zlog_fd = -1; static int zlog_level = ZLOG_NOTICE; static int launched = 0; +static void (*external_logger)(int, char *, size_t) = NULL; static const char *level_names[] = { [ZLOG_DEBUG] = "DEBUG", @@ -41,6 +42,12 @@ const int syslog_priorities[] = { }; #endif +void zlog_set_external_logger(void (*logger)(int, char *, size_t)) /* {{{ */ +{ + external_logger = logger; +} +/* }}} */ + const char *zlog_get_level_name(int log_level) /* {{{ */ { if (log_level < 0) { @@ -101,6 +108,19 @@ void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /* int truncated = 0; int saved_errno; + if (external_logger) { + va_start(args, fmt); + len = vsnprintf(buf, buf_size, fmt, args); + va_end(args); + if (len >= buf_size) { + memcpy(buf + buf_size - sizeof("..."), "...", sizeof("...") - 1); + len = buf_size - 1; + } + external_logger(flags & ZLOG_LEVEL_MASK, buf, len); + len = 0; + memset(buf, '\0', buf_size); + } + if ((flags & ZLOG_LEVEL_MASK) < zlog_level) { return; } diff --git a/sapi/fpm/fpm/zlog.h b/sapi/fpm/fpm/zlog.h index e6a5c019a..1945922da 100644 --- a/sapi/fpm/fpm/zlog.h +++ b/sapi/fpm/fpm/zlog.h @@ -9,6 +9,7 @@ struct timeval; +void zlog_set_external_logger(void (*logger)(int, char *, size_t)); int zlog_set_fd(int new_fd); int zlog_set_level(int new_value); const char *zlog_get_level_name(int log_level); diff --git a/sapi/fpm/php-fpm.conf.in b/sapi/fpm/php-fpm.conf.in index 2dad9d7f5..a63dec709 100644 --- a/sapi/fpm/php-fpm.conf.in +++ b/sapi/fpm/php-fpm.conf.in @@ -76,6 +76,14 @@ ; Default Value: 0 ; process.max = 128 +; Specify the nice(2) priority to apply to the master process (only if set) +; The value can vary from -19 (highest priority) to 20 (lower priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool process will inherit the master process priority +; unless it specified otherwise +; Default Value: no set +; process.priority = -19 + ; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. ; Default Value: yes ;daemonize = yes @@ -163,6 +171,14 @@ listen = 127.0.0.1:9000 ; Default Value: any ;listen.allowed_clients = 127.0.0.1 +; Specify the nice(2) priority to apply to the pool processes (only if set) +; The value can vary from -19 (highest priority) to 20 (lower priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool processes will inherit the master process priority +; unless it specified otherwise +; Default Value: no set +; priority = -19 + ; Choose how the process manager will control the number of child processes. ; Possible Values: ; static - a fixed number (pm.max_children) of child processes; |