Skip to content

Commit 73dabdf

Browse files
committed
Refactor accel_finish_startup
1 parent 519c21f commit 73dabdf

File tree

1 file changed

+186
-165
lines changed

1 file changed

+186
-165
lines changed

ext/opcache/ZendAccelerator.c

Lines changed: 186 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -4572,206 +4572,227 @@ static void preload_send_header(sapi_header_struct *sapi_header, void *server_co
45724572
{
45734573
}
45744574

4575-
static int accel_finish_startup(void)
4575+
#ifndef ZEND_WIN32
4576+
static int accel_finish_startup_preload(bool in_child)
45764577
{
4577-
if (!ZCG(enabled) || !accel_startup_ok) {
4578-
return SUCCESS;
4579-
}
4578+
int ret = SUCCESS;
4579+
int rc;
4580+
int orig_error_reporting;
4581+
4582+
int (*orig_activate)(void) = sapi_module.activate;
4583+
int (*orig_deactivate)(void) = sapi_module.deactivate;
4584+
void (*orig_register_server_variables)(zval *track_vars_array) = sapi_module.register_server_variables;
4585+
int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers) = sapi_module.header_handler;
4586+
int (*orig_send_headers)(sapi_headers_struct *sapi_headers) = sapi_module.send_headers;
4587+
void (*orig_send_header)(sapi_header_struct *sapi_header, void *server_context)= sapi_module.send_header;
4588+
char *(*orig_getenv)(const char *name, size_t name_len) = sapi_module.getenv;
4589+
size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
4590+
void (*orig_flush)(void *server_context) = sapi_module.flush;
4591+
#ifdef ZEND_SIGNALS
4592+
bool old_reset_signals = SIGG(reset);
4593+
#endif
4594+
4595+
sapi_module.activate = NULL;
4596+
sapi_module.deactivate = NULL;
4597+
sapi_module.register_server_variables = NULL;
4598+
sapi_module.header_handler = preload_header_handler;
4599+
sapi_module.send_headers = preload_send_headers;
4600+
sapi_module.send_header = preload_send_header;
4601+
sapi_module.getenv = NULL;
4602+
sapi_module.ub_write = preload_ub_write;
4603+
sapi_module.flush = preload_flush;
4604+
4605+
zend_interned_strings_switch_storage(1);
45804606

4581-
if (ZCG(accel_directives).preload && *ZCG(accel_directives).preload) {
4582-
#ifdef ZEND_WIN32
4583-
zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
4584-
return FAILURE;
4585-
#else
4586-
bool in_child = false;
4587-
int ret = SUCCESS;
4588-
int rc;
4589-
int orig_error_reporting;
4590-
4591-
int (*orig_activate)(void) = sapi_module.activate;
4592-
int (*orig_deactivate)(void) = sapi_module.deactivate;
4593-
void (*orig_register_server_variables)(zval *track_vars_array) = sapi_module.register_server_variables;
4594-
int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers) = sapi_module.header_handler;
4595-
int (*orig_send_headers)(sapi_headers_struct *sapi_headers) = sapi_module.send_headers;
4596-
void (*orig_send_header)(sapi_header_struct *sapi_header, void *server_context)= sapi_module.send_header;
4597-
char *(*orig_getenv)(const char *name, size_t name_len) = sapi_module.getenv;
4598-
size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
4599-
void (*orig_flush)(void *server_context) = sapi_module.flush;
46004607
#ifdef ZEND_SIGNALS
4601-
bool old_reset_signals = SIGG(reset);
4608+
SIGG(reset) = false;
46024609
#endif
46034610

4604-
if (UNEXPECTED(file_cache_only)) {
4605-
zend_accel_error(ACCEL_LOG_WARNING, "Preloading doesn't work in \"file_cache_only\" mode");
4606-
return SUCCESS;
4611+
orig_error_reporting = EG(error_reporting);
4612+
EG(error_reporting) = 0;
4613+
4614+
rc = php_request_startup();
4615+
4616+
EG(error_reporting) = orig_error_reporting;
4617+
4618+
if (rc == SUCCESS) {
4619+
bool orig_report_memleaks;
4620+
4621+
/* don't send headers */
4622+
SG(headers_sent) = true;
4623+
SG(request_info).no_headers = true;
4624+
php_output_set_status(0);
4625+
4626+
ZCG(auto_globals_mask) = 0;
4627+
ZCG(request_time) = (time_t)sapi_get_request_time();
4628+
ZCG(cache_opline) = NULL;
4629+
ZCG(cache_persistent_script) = NULL;
4630+
ZCG(include_path_key_len) = 0;
4631+
ZCG(include_path_check) = true;
4632+
4633+
ZCG(cwd) = NULL;
4634+
ZCG(cwd_key_len) = 0;
4635+
ZCG(cwd_check) = true;
4636+
4637+
if (accel_preload(ZCG(accel_directives).preload, in_child) != SUCCESS) {
4638+
ret = FAILURE;
46074639
}
4640+
preload_flush(NULL);
46084641

4609-
/* exclusive lock */
4610-
zend_shared_alloc_lock();
4642+
orig_report_memleaks = PG(report_memleaks);
4643+
PG(report_memleaks) = false;
4644+
#ifdef ZEND_SIGNALS
4645+
/* We may not have registered signal handlers due to SIGG(reset)=0, so
4646+
* also disable the check that they are registered. */
4647+
SIGG(check) = false;
4648+
#endif
4649+
php_request_shutdown(NULL); /* calls zend_shared_alloc_unlock(); */
4650+
PG(report_memleaks) = orig_report_memleaks;
4651+
} else {
4652+
zend_shared_alloc_unlock();
4653+
ret = FAILURE;
4654+
}
4655+
#ifdef ZEND_SIGNALS
4656+
SIGG(reset) = old_reset_signals;
4657+
#endif
46114658

4612-
if (ZCSG(preload_script)) {
4613-
/* Preloading was done in another process */
4614-
preload_load();
4615-
zend_shared_alloc_unlock();
4616-
return SUCCESS;
4659+
sapi_module.activate = orig_activate;
4660+
sapi_module.deactivate = orig_deactivate;
4661+
sapi_module.register_server_variables = orig_register_server_variables;
4662+
sapi_module.header_handler = orig_header_handler;
4663+
sapi_module.send_headers = orig_send_headers;
4664+
sapi_module.send_header = orig_send_header;
4665+
sapi_module.getenv = orig_getenv;
4666+
sapi_module.ub_write = orig_ub_write;
4667+
sapi_module.flush = orig_flush;
4668+
4669+
sapi_activate();
4670+
4671+
return ret;
4672+
}
4673+
4674+
static int accel_finish_startup_preload_subprocess(pid_t *pid)
4675+
{
4676+
uid_t euid = geteuid();
4677+
if (euid != 0) {
4678+
if (ZCG(accel_directives).preload_user
4679+
&& *ZCG(accel_directives).preload_user) {
4680+
zend_accel_error(ACCEL_LOG_WARNING, "\"opcache.preload_user\" is ignored");
46174681
}
46184682

4619-
uid_t euid = geteuid();
4620-
if (euid == 0) {
4621-
pid_t pid;
4622-
struct passwd *pw;
4683+
*pid = -1;
4684+
return SUCCESS;
4685+
}
46234686

4624-
if (!ZCG(accel_directives).preload_user
4625-
|| !*ZCG(accel_directives).preload_user) {
4626-
zend_shared_alloc_unlock();
4627-
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "\"opcache.preload\" requires \"opcache.preload_user\" when running under uid 0");
4628-
return FAILURE;
4629-
}
4687+
if (!ZCG(accel_directives).preload_user
4688+
|| !*ZCG(accel_directives).preload_user) {
46304689

4631-
pw = getpwnam(ZCG(accel_directives).preload_user);
4632-
if (pw == NULL) {
4633-
zend_shared_alloc_unlock();
4634-
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
4635-
return FAILURE;
4636-
}
46374690

4638-
if (pw->pw_uid != euid) {
4639-
pid = fork();
4640-
if (pid == -1) {
4641-
zend_shared_alloc_unlock();
4642-
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to fork()");
4643-
return FAILURE;
4644-
} else if (pid == 0) { /* children */
4645-
if (setgid(pw->pw_gid) < 0) {
4646-
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setgid(%d)", pw->pw_gid);
4647-
exit(1);
4648-
}
4649-
if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
4650-
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to initgroups(\"%s\", %d)", pw->pw_name, pw->pw_uid);
4651-
exit(1);
4652-
}
4653-
if (setuid(pw->pw_uid) < 0) {
4654-
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid);
4655-
exit(1);
4656-
}
4657-
in_child = true;
4658-
} else { /* parent */
4659-
int status;
4691+
zend_shared_alloc_unlock();
4692+
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "\"opcache.preload\" requires \"opcache.preload_user\" when running under uid 0");
4693+
return FAILURE;
4694+
}
46604695

4661-
if (waitpid(pid, &status, 0) < 0) {
4662-
zend_shared_alloc_unlock();
4663-
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
4664-
return FAILURE;
4665-
}
4696+
struct passwd *pw = getpwnam(ZCG(accel_directives).preload_user);
4697+
if (pw == NULL) {
4698+
zend_shared_alloc_unlock();
4699+
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
4700+
return FAILURE;
4701+
}
46664702

4667-
if (ZCSG(preload_script)) {
4668-
preload_load();
4669-
}
4703+
if (pw->pw_uid == euid) {
4704+
*pid = -1;
4705+
return SUCCESS;
4706+
}
46704707

4671-
zend_shared_alloc_unlock();
4672-
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
4673-
return SUCCESS;
4674-
} else {
4675-
return FAILURE;
4676-
}
4677-
}
4678-
}
4679-
} else {
4680-
if (ZCG(accel_directives).preload_user
4681-
&& *ZCG(accel_directives).preload_user) {
4682-
zend_accel_error(ACCEL_LOG_WARNING, "\"opcache.preload_user\" is ignored");
4683-
}
4708+
*pid = fork();
4709+
if (*pid == -1) {
4710+
zend_shared_alloc_unlock();
4711+
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to fork()");
4712+
return FAILURE;
4713+
}
4714+
4715+
if (*pid == 0) { /* children */
4716+
if (setgid(pw->pw_gid) < 0) {
4717+
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setgid(%d)", pw->pw_gid);
4718+
exit(1);
4719+
}
4720+
if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
4721+
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to initgroups(\"%s\", %d)", pw->pw_name, pw->pw_uid);
4722+
exit(1);
4723+
}
4724+
if (setuid(pw->pw_uid) < 0) {
4725+
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid);
4726+
exit(1);
46844727
}
4728+
}
46854729

4686-
sapi_module.activate = NULL;
4687-
sapi_module.deactivate = NULL;
4688-
sapi_module.register_server_variables = NULL;
4689-
sapi_module.header_handler = preload_header_handler;
4690-
sapi_module.send_headers = preload_send_headers;
4691-
sapi_module.send_header = preload_send_header;
4692-
sapi_module.getenv = NULL;
4693-
sapi_module.ub_write = preload_ub_write;
4694-
sapi_module.flush = preload_flush;
4730+
return SUCCESS;
4731+
}
4732+
#endif /* ZEND_WIN32 */
46954733

4696-
zend_interned_strings_switch_storage(1);
4734+
static int accel_finish_startup(void)
4735+
{
4736+
if (!ZCG(enabled) || !accel_startup_ok) {
4737+
return SUCCESS;
4738+
}
46974739

4698-
#ifdef ZEND_SIGNALS
4699-
SIGG(reset) = false;
4700-
#endif
4740+
if (!(ZCG(accel_directives).preload && *ZCG(accel_directives).preload)) {
4741+
return SUCCESS;
4742+
}
47014743

4702-
orig_error_reporting = EG(error_reporting);
4703-
EG(error_reporting) = 0;
4744+
#ifdef ZEND_WIN32
4745+
zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
4746+
return FAILURE;
4747+
#else /* ZEND_WIN32 */
47044748

4705-
rc = php_request_startup();
4749+
if (UNEXPECTED(file_cache_only)) {
4750+
zend_accel_error(ACCEL_LOG_WARNING, "Preloading doesn't work in \"file_cache_only\" mode");
4751+
return SUCCESS;
4752+
}
47064753

4707-
EG(error_reporting) = orig_error_reporting;
4754+
/* exclusive lock */
4755+
zend_shared_alloc_lock();
47084756

4709-
if (rc == SUCCESS) {
4710-
bool orig_report_memleaks;
4757+
if (ZCSG(preload_script)) {
4758+
/* Preloading was done in another process */
4759+
preload_load();
4760+
zend_shared_alloc_unlock();
4761+
return SUCCESS;
4762+
}
47114763

4712-
/* don't send headers */
4713-
SG(headers_sent) = true;
4714-
SG(request_info).no_headers = true;
4715-
php_output_set_status(0);
47164764

4717-
ZCG(auto_globals_mask) = 0;
4718-
ZCG(request_time) = (time_t)sapi_get_request_time();
4719-
ZCG(cache_opline) = NULL;
4720-
ZCG(cache_persistent_script) = NULL;
4721-
ZCG(include_path_key_len) = 0;
4722-
ZCG(include_path_check) = true;
4765+
pid_t pid;
4766+
if (accel_finish_startup_preload_subprocess(&pid) == FAILURE) {
4767+
zend_shared_alloc_unlock();
4768+
return FAILURE;
4769+
}
47234770

4724-
ZCG(cwd) = NULL;
4725-
ZCG(cwd_key_len) = 0;
4726-
ZCG(cwd_check) = true;
4771+
if (pid == -1) { /* no subprocess was needed */
4772+
return accel_finish_startup_preload(false);
4773+
} else if (pid == 0) { /* subprocess */
4774+
int ret = accel_finish_startup_preload(true);
47274775

4728-
if (accel_preload(ZCG(accel_directives).preload, in_child) != SUCCESS) {
4729-
ret = FAILURE;
4730-
}
4731-
preload_flush(NULL);
4776+
exit(ret == SUCCESS ? 0 : 1);
4777+
} else { /* parent */
4778+
int status;
47324779

4733-
orig_report_memleaks = PG(report_memleaks);
4734-
PG(report_memleaks) = false;
4735-
#ifdef ZEND_SIGNALS
4736-
/* We may not have registered signal handlers due to SIGG(reset)=0, so
4737-
* also disable the check that they are registered. */
4738-
SIGG(check) = false;
4739-
#endif
4740-
php_request_shutdown(NULL); /* calls zend_shared_alloc_unlock(); */
4741-
PG(report_memleaks) = orig_report_memleaks;
4742-
} else {
4780+
if (waitpid(pid, &status, 0) < 0) {
47434781
zend_shared_alloc_unlock();
4744-
ret = FAILURE;
4782+
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
47454783
}
4746-
#ifdef ZEND_SIGNALS
4747-
SIGG(reset) = old_reset_signals;
4748-
#endif
47494784

4750-
sapi_module.activate = orig_activate;
4751-
sapi_module.deactivate = orig_deactivate;
4752-
sapi_module.register_server_variables = orig_register_server_variables;
4753-
sapi_module.header_handler = orig_header_handler;
4754-
sapi_module.send_headers = orig_send_headers;
4755-
sapi_module.send_header = orig_send_header;
4756-
sapi_module.getenv = orig_getenv;
4757-
sapi_module.ub_write = orig_ub_write;
4758-
sapi_module.flush = orig_flush;
4759-
4760-
sapi_activate();
4761-
4762-
if (in_child) {
4763-
if (ret == SUCCESS) {
4764-
exit(0);
4765-
} else {
4766-
exit(2);
4767-
}
4785+
if (ZCSG(preload_script)) {
4786+
preload_load();
47684787
}
47694788

4770-
return ret;
4771-
#endif
4789+
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
4790+
return SUCCESS;
4791+
} else {
4792+
return FAILURE;
4793+
}
47724794
}
4773-
4774-
return SUCCESS;
4795+
#endif /* ZEND_WIN32 */
47754796
}
47764797

47774798
ZEND_EXT_API zend_extension zend_extension_entry = {

0 commit comments

Comments
 (0)