summaryrefslogtreecommitdiff
path: root/sapi
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2012-07-23 10:51:19 +0200
committerOndřej Surý <ondrej@sury.org>2012-07-23 10:51:19 +0200
commit3365f28adf90110ca7475df889720fc244820f4b (patch)
tree5415edde3e396a93f05f887d9f07071871467bdf /sapi
parentf0f8d7084aec4be5c07f02f2e29c2820f85c8315 (diff)
downloadphp-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.phpt4
-rw-r--r--sapi/cli/php_cli.c3
-rw-r--r--sapi/cli/php_cli_server.c3
-rw-r--r--sapi/cli/tests/bug61546.phpt11
-rw-r--r--sapi/fpm/config.m45
-rw-r--r--sapi/fpm/fpm/fastcgi.c14
-rw-r--r--sapi/fpm/fpm/fpm.c9
-rw-r--r--sapi/fpm/fpm/fpm.h33
-rw-r--r--sapi/fpm/fpm/fpm_children.c4
-rw-r--r--sapi/fpm/fpm/fpm_conf.c48
-rw-r--r--sapi/fpm/fpm/fpm_conf.h2
-rw-r--r--sapi/fpm/fpm/fpm_main.c90
-rw-r--r--sapi/fpm/fpm/fpm_php.c38
-rw-r--r--sapi/fpm/fpm/fpm_php.h1
-rw-r--r--sapi/fpm/fpm/fpm_process_ctl.c4
-rw-r--r--sapi/fpm/fpm/fpm_signals.c12
-rw-r--r--sapi/fpm/fpm/fpm_signals.h3
-rw-r--r--sapi/fpm/fpm/fpm_sockets.c25
-rw-r--r--sapi/fpm/fpm/fpm_sockets.h4
-rw-r--r--sapi/fpm/fpm/fpm_status.c9
-rw-r--r--sapi/fpm/fpm/fpm_unix.c102
-rw-r--r--sapi/fpm/fpm/zlog.c20
-rw-r--r--sapi/fpm/fpm/zlog.h1
-rw-r--r--sapi/fpm/php-fpm.conf.in16
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;