1
0
mirror of https://github.com/php/php-src.git synced 2026-04-11 10:03:18 +02:00

Refactor accel_finish_startup

This commit is contained in:
Arnaud Le Blanc
2022-09-09 15:04:09 +02:00
parent 519c21f87a
commit 73dabdfebe

View File

@@ -4572,206 +4572,227 @@ static void preload_send_header(sapi_header_struct *sapi_header, void *server_co
{
}
#ifndef ZEND_WIN32
static int accel_finish_startup_preload(bool in_child)
{
int ret = SUCCESS;
int rc;
int orig_error_reporting;
int (*orig_activate)(void) = sapi_module.activate;
int (*orig_deactivate)(void) = sapi_module.deactivate;
void (*orig_register_server_variables)(zval *track_vars_array) = sapi_module.register_server_variables;
int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers) = sapi_module.header_handler;
int (*orig_send_headers)(sapi_headers_struct *sapi_headers) = sapi_module.send_headers;
void (*orig_send_header)(sapi_header_struct *sapi_header, void *server_context)= sapi_module.send_header;
char *(*orig_getenv)(const char *name, size_t name_len) = sapi_module.getenv;
size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
void (*orig_flush)(void *server_context) = sapi_module.flush;
#ifdef ZEND_SIGNALS
bool old_reset_signals = SIGG(reset);
#endif
sapi_module.activate = NULL;
sapi_module.deactivate = NULL;
sapi_module.register_server_variables = NULL;
sapi_module.header_handler = preload_header_handler;
sapi_module.send_headers = preload_send_headers;
sapi_module.send_header = preload_send_header;
sapi_module.getenv = NULL;
sapi_module.ub_write = preload_ub_write;
sapi_module.flush = preload_flush;
zend_interned_strings_switch_storage(1);
#ifdef ZEND_SIGNALS
SIGG(reset) = false;
#endif
orig_error_reporting = EG(error_reporting);
EG(error_reporting) = 0;
rc = php_request_startup();
EG(error_reporting) = orig_error_reporting;
if (rc == SUCCESS) {
bool orig_report_memleaks;
/* don't send headers */
SG(headers_sent) = true;
SG(request_info).no_headers = true;
php_output_set_status(0);
ZCG(auto_globals_mask) = 0;
ZCG(request_time) = (time_t)sapi_get_request_time();
ZCG(cache_opline) = NULL;
ZCG(cache_persistent_script) = NULL;
ZCG(include_path_key_len) = 0;
ZCG(include_path_check) = true;
ZCG(cwd) = NULL;
ZCG(cwd_key_len) = 0;
ZCG(cwd_check) = true;
if (accel_preload(ZCG(accel_directives).preload, in_child) != SUCCESS) {
ret = FAILURE;
}
preload_flush(NULL);
orig_report_memleaks = PG(report_memleaks);
PG(report_memleaks) = false;
#ifdef ZEND_SIGNALS
/* We may not have registered signal handlers due to SIGG(reset)=0, so
* also disable the check that they are registered. */
SIGG(check) = false;
#endif
php_request_shutdown(NULL); /* calls zend_shared_alloc_unlock(); */
PG(report_memleaks) = orig_report_memleaks;
} else {
zend_shared_alloc_unlock();
ret = FAILURE;
}
#ifdef ZEND_SIGNALS
SIGG(reset) = old_reset_signals;
#endif
sapi_module.activate = orig_activate;
sapi_module.deactivate = orig_deactivate;
sapi_module.register_server_variables = orig_register_server_variables;
sapi_module.header_handler = orig_header_handler;
sapi_module.send_headers = orig_send_headers;
sapi_module.send_header = orig_send_header;
sapi_module.getenv = orig_getenv;
sapi_module.ub_write = orig_ub_write;
sapi_module.flush = orig_flush;
sapi_activate();
return ret;
}
static int accel_finish_startup_preload_subprocess(pid_t *pid)
{
uid_t euid = geteuid();
if (euid != 0) {
if (ZCG(accel_directives).preload_user
&& *ZCG(accel_directives).preload_user) {
zend_accel_error(ACCEL_LOG_WARNING, "\"opcache.preload_user\" is ignored");
}
*pid = -1;
return SUCCESS;
}
if (!ZCG(accel_directives).preload_user
|| !*ZCG(accel_directives).preload_user) {
zend_shared_alloc_unlock();
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "\"opcache.preload\" requires \"opcache.preload_user\" when running under uid 0");
return FAILURE;
}
struct passwd *pw = getpwnam(ZCG(accel_directives).preload_user);
if (pw == NULL) {
zend_shared_alloc_unlock();
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
return FAILURE;
}
if (pw->pw_uid == euid) {
*pid = -1;
return SUCCESS;
}
*pid = fork();
if (*pid == -1) {
zend_shared_alloc_unlock();
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to fork()");
return FAILURE;
}
if (*pid == 0) { /* children */
if (setgid(pw->pw_gid) < 0) {
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setgid(%d)", pw->pw_gid);
exit(1);
}
if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to initgroups(\"%s\", %d)", pw->pw_name, pw->pw_uid);
exit(1);
}
if (setuid(pw->pw_uid) < 0) {
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid);
exit(1);
}
}
return SUCCESS;
}
#endif /* ZEND_WIN32 */
static int accel_finish_startup(void)
{
if (!ZCG(enabled) || !accel_startup_ok) {
return SUCCESS;
}
if (ZCG(accel_directives).preload && *ZCG(accel_directives).preload) {
#ifdef ZEND_WIN32
zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
return FAILURE;
#else
bool in_child = false;
int ret = SUCCESS;
int rc;
int orig_error_reporting;
int (*orig_activate)(void) = sapi_module.activate;
int (*orig_deactivate)(void) = sapi_module.deactivate;
void (*orig_register_server_variables)(zval *track_vars_array) = sapi_module.register_server_variables;
int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers) = sapi_module.header_handler;
int (*orig_send_headers)(sapi_headers_struct *sapi_headers) = sapi_module.send_headers;
void (*orig_send_header)(sapi_header_struct *sapi_header, void *server_context)= sapi_module.send_header;
char *(*orig_getenv)(const char *name, size_t name_len) = sapi_module.getenv;
size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
void (*orig_flush)(void *server_context) = sapi_module.flush;
#ifdef ZEND_SIGNALS
bool old_reset_signals = SIGG(reset);
#endif
if (UNEXPECTED(file_cache_only)) {
zend_accel_error(ACCEL_LOG_WARNING, "Preloading doesn't work in \"file_cache_only\" mode");
return SUCCESS;
}
/* exclusive lock */
zend_shared_alloc_lock();
if (ZCSG(preload_script)) {
/* Preloading was done in another process */
preload_load();
zend_shared_alloc_unlock();
return SUCCESS;
}
uid_t euid = geteuid();
if (euid == 0) {
pid_t pid;
struct passwd *pw;
if (!ZCG(accel_directives).preload_user
|| !*ZCG(accel_directives).preload_user) {
zend_shared_alloc_unlock();
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "\"opcache.preload\" requires \"opcache.preload_user\" when running under uid 0");
return FAILURE;
}
pw = getpwnam(ZCG(accel_directives).preload_user);
if (pw == NULL) {
zend_shared_alloc_unlock();
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
return FAILURE;
}
if (pw->pw_uid != euid) {
pid = fork();
if (pid == -1) {
zend_shared_alloc_unlock();
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to fork()");
return FAILURE;
} else if (pid == 0) { /* children */
if (setgid(pw->pw_gid) < 0) {
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setgid(%d)", pw->pw_gid);
exit(1);
}
if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to initgroups(\"%s\", %d)", pw->pw_name, pw->pw_uid);
exit(1);
}
if (setuid(pw->pw_uid) < 0) {
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid);
exit(1);
}
in_child = true;
} else { /* parent */
int status;
if (waitpid(pid, &status, 0) < 0) {
zend_shared_alloc_unlock();
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
return FAILURE;
}
if (ZCSG(preload_script)) {
preload_load();
}
zend_shared_alloc_unlock();
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
return SUCCESS;
} else {
return FAILURE;
}
}
}
} else {
if (ZCG(accel_directives).preload_user
&& *ZCG(accel_directives).preload_user) {
zend_accel_error(ACCEL_LOG_WARNING, "\"opcache.preload_user\" is ignored");
}
}
sapi_module.activate = NULL;
sapi_module.deactivate = NULL;
sapi_module.register_server_variables = NULL;
sapi_module.header_handler = preload_header_handler;
sapi_module.send_headers = preload_send_headers;
sapi_module.send_header = preload_send_header;
sapi_module.getenv = NULL;
sapi_module.ub_write = preload_ub_write;
sapi_module.flush = preload_flush;
zend_interned_strings_switch_storage(1);
#ifdef ZEND_SIGNALS
SIGG(reset) = false;
#endif
orig_error_reporting = EG(error_reporting);
EG(error_reporting) = 0;
rc = php_request_startup();
EG(error_reporting) = orig_error_reporting;
if (rc == SUCCESS) {
bool orig_report_memleaks;
/* don't send headers */
SG(headers_sent) = true;
SG(request_info).no_headers = true;
php_output_set_status(0);
ZCG(auto_globals_mask) = 0;
ZCG(request_time) = (time_t)sapi_get_request_time();
ZCG(cache_opline) = NULL;
ZCG(cache_persistent_script) = NULL;
ZCG(include_path_key_len) = 0;
ZCG(include_path_check) = true;
ZCG(cwd) = NULL;
ZCG(cwd_key_len) = 0;
ZCG(cwd_check) = true;
if (accel_preload(ZCG(accel_directives).preload, in_child) != SUCCESS) {
ret = FAILURE;
}
preload_flush(NULL);
orig_report_memleaks = PG(report_memleaks);
PG(report_memleaks) = false;
#ifdef ZEND_SIGNALS
/* We may not have registered signal handlers due to SIGG(reset)=0, so
* also disable the check that they are registered. */
SIGG(check) = false;
#endif
php_request_shutdown(NULL); /* calls zend_shared_alloc_unlock(); */
PG(report_memleaks) = orig_report_memleaks;
} else {
zend_shared_alloc_unlock();
ret = FAILURE;
}
#ifdef ZEND_SIGNALS
SIGG(reset) = old_reset_signals;
#endif
sapi_module.activate = orig_activate;
sapi_module.deactivate = orig_deactivate;
sapi_module.register_server_variables = orig_register_server_variables;
sapi_module.header_handler = orig_header_handler;
sapi_module.send_headers = orig_send_headers;
sapi_module.send_header = orig_send_header;
sapi_module.getenv = orig_getenv;
sapi_module.ub_write = orig_ub_write;
sapi_module.flush = orig_flush;
sapi_activate();
if (in_child) {
if (ret == SUCCESS) {
exit(0);
} else {
exit(2);
}
}
return ret;
#endif
if (!(ZCG(accel_directives).preload && *ZCG(accel_directives).preload)) {
return SUCCESS;
}
return SUCCESS;
#ifdef ZEND_WIN32
zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
return FAILURE;
#else /* ZEND_WIN32 */
if (UNEXPECTED(file_cache_only)) {
zend_accel_error(ACCEL_LOG_WARNING, "Preloading doesn't work in \"file_cache_only\" mode");
return SUCCESS;
}
/* exclusive lock */
zend_shared_alloc_lock();
if (ZCSG(preload_script)) {
/* Preloading was done in another process */
preload_load();
zend_shared_alloc_unlock();
return SUCCESS;
}
pid_t pid;
if (accel_finish_startup_preload_subprocess(&pid) == FAILURE) {
zend_shared_alloc_unlock();
return FAILURE;
}
if (pid == -1) { /* no subprocess was needed */
return accel_finish_startup_preload(false);
} else if (pid == 0) { /* subprocess */
int ret = accel_finish_startup_preload(true);
exit(ret == SUCCESS ? 0 : 1);
} else { /* parent */
int status;
if (waitpid(pid, &status, 0) < 0) {
zend_shared_alloc_unlock();
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
}
if (ZCSG(preload_script)) {
preload_load();
}
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
return SUCCESS;
} else {
return FAILURE;
}
}
#endif /* ZEND_WIN32 */
}
ZEND_EXT_API zend_extension zend_extension_entry = {