Skip to content

Commit 01cc975

Browse files
committed
Refactor accel_finish_startup
1 parent a289bb3 commit 01cc975

File tree

1 file changed

+183
-165
lines changed

1 file changed

+183
-165
lines changed

ext/opcache/ZendAccelerator.c

+183-165
Original file line numberDiff line numberDiff line change
@@ -4565,206 +4565,224 @@ static void preload_send_header(sapi_header_struct *sapi_header, void *server_co
45654565
{
45664566
}
45674567

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

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

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

4602-
/* exclusive lock */
4603-
zend_shared_alloc_lock();
4634+
orig_report_memleaks = PG(report_memleaks);
4635+
PG(report_memleaks) = false;
4636+
#ifdef ZEND_SIGNALS
4637+
/* We may not have registered signal handlers due to SIGG(reset)=0, so
4638+
* also disable the check that they are registered. */
4639+
SIGG(check) = false;
4640+
#endif
4641+
php_request_shutdown(NULL); /* calls zend_shared_alloc_unlock(); */
4642+
PG(report_memleaks) = orig_report_memleaks;
4643+
} else {
4644+
zend_shared_alloc_unlock();
4645+
ret = FAILURE;
4646+
}
4647+
#ifdef ZEND_SIGNALS
4648+
SIGG(reset) = old_reset_signals;
4649+
#endif
46044650

4605-
if (ZCSG(preload_script)) {
4606-
/* Preloading was done in another process */
4607-
preload_load();
4608-
zend_shared_alloc_unlock();
4609-
return SUCCESS;
4651+
sapi_module.activate = orig_activate;
4652+
sapi_module.deactivate = orig_deactivate;
4653+
sapi_module.register_server_variables = orig_register_server_variables;
4654+
sapi_module.header_handler = orig_header_handler;
4655+
sapi_module.send_headers = orig_send_headers;
4656+
sapi_module.send_header = orig_send_header;
4657+
sapi_module.getenv = orig_getenv;
4658+
sapi_module.ub_write = orig_ub_write;
4659+
sapi_module.flush = orig_flush;
4660+
4661+
sapi_activate();
4662+
4663+
return ret;
4664+
}
4665+
4666+
static int accel_finish_startup_preload_subprocess(pid_t *pid)
4667+
{
4668+
uid_t euid = geteuid();
4669+
if (euid != 0) {
4670+
if (ZCG(accel_directives).preload_user
4671+
&& *ZCG(accel_directives).preload_user) {
4672+
zend_accel_error(ACCEL_LOG_WARNING, "\"opcache.preload_user\" is ignored");
46104673
}
46114674

4612-
uid_t euid = geteuid();
4613-
if (euid == 0) {
4614-
pid_t pid;
4615-
struct passwd *pw;
4675+
*pid = -1;
4676+
return SUCCESS;
4677+
}
46164678

4617-
if (!ZCG(accel_directives).preload_user
4618-
|| !*ZCG(accel_directives).preload_user) {
4619-
zend_shared_alloc_unlock();
4620-
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "\"opcache.preload\" requires \"opcache.preload_user\" when running under uid 0");
4621-
return FAILURE;
4622-
}
4679+
if (!ZCG(accel_directives).preload_user
4680+
|| !*ZCG(accel_directives).preload_user) {
46234681

4624-
pw = getpwnam(ZCG(accel_directives).preload_user);
4625-
if (pw == NULL) {
4626-
zend_shared_alloc_unlock();
4627-
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
4628-
return FAILURE;
4629-
}
46304682

4631-
if (pw->pw_uid != euid) {
4632-
pid = fork();
4633-
if (pid == -1) {
4634-
zend_shared_alloc_unlock();
4635-
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to fork()");
4636-
return FAILURE;
4637-
} else if (pid == 0) { /* children */
4638-
if (setgid(pw->pw_gid) < 0) {
4639-
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setgid(%d)", pw->pw_gid);
4640-
exit(1);
4641-
}
4642-
if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
4643-
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to initgroups(\"%s\", %d)", pw->pw_name, pw->pw_uid);
4644-
exit(1);
4645-
}
4646-
if (setuid(pw->pw_uid) < 0) {
4647-
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid);
4648-
exit(1);
4649-
}
4650-
in_child = true;
4651-
} else { /* parent */
4652-
int status;
4683+
zend_shared_alloc_unlock();
4684+
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "\"opcache.preload\" requires \"opcache.preload_user\" when running under uid 0");
4685+
return FAILURE;
4686+
}
46534687

4654-
if (waitpid(pid, &status, 0) < 0) {
4655-
zend_shared_alloc_unlock();
4656-
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
4657-
return FAILURE;
4658-
}
4688+
struct passwd *pw = getpwnam(ZCG(accel_directives).preload_user);
4689+
if (pw == NULL) {
4690+
zend_shared_alloc_unlock();
4691+
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
4692+
return FAILURE;
4693+
}
46594694

4660-
if (ZCSG(preload_script)) {
4661-
preload_load();
4662-
}
4695+
if (pw->pw_uid == euid) {
4696+
*pid = -1;
4697+
return SUCCESS;
4698+
}
46634699

4664-
zend_shared_alloc_unlock();
4665-
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
4666-
return SUCCESS;
4667-
} else {
4668-
return FAILURE;
4669-
}
4670-
}
4671-
}
4672-
} else {
4673-
if (ZCG(accel_directives).preload_user
4674-
&& *ZCG(accel_directives).preload_user) {
4675-
zend_accel_error(ACCEL_LOG_WARNING, "\"opcache.preload_user\" is ignored");
4676-
}
4700+
*pid = fork();
4701+
if (*pid == -1) {
4702+
zend_shared_alloc_unlock();
4703+
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to fork()");
4704+
return FAILURE;
4705+
}
4706+
4707+
if (*pid == 0) { /* children */
4708+
if (setgid(pw->pw_gid) < 0) {
4709+
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setgid(%d)", pw->pw_gid);
4710+
exit(1);
4711+
}
4712+
if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
4713+
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to initgroups(\"%s\", %d)", pw->pw_name, pw->pw_uid);
4714+
exit(1);
46774715
}
4716+
if (setuid(pw->pw_uid) < 0) {
4717+
zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid);
4718+
exit(1);
4719+
}
4720+
}
46784721

4679-
sapi_module.activate = NULL;
4680-
sapi_module.deactivate = NULL;
4681-
sapi_module.register_server_variables = NULL;
4682-
sapi_module.header_handler = preload_header_handler;
4683-
sapi_module.send_headers = preload_send_headers;
4684-
sapi_module.send_header = preload_send_header;
4685-
sapi_module.getenv = NULL;
4686-
sapi_module.ub_write = preload_ub_write;
4687-
sapi_module.flush = preload_flush;
4722+
return SUCCESS;
4723+
}
46884724

4689-
zend_interned_strings_switch_storage(1);
4725+
static int accel_finish_startup(void)
4726+
{
4727+
if (!ZCG(enabled) || !accel_startup_ok) {
4728+
return SUCCESS;
4729+
}
46904730

4691-
#ifdef ZEND_SIGNALS
4692-
SIGG(reset) = false;
4693-
#endif
4731+
if (!(ZCG(accel_directives).preload && *ZCG(accel_directives).preload)) {
4732+
return SUCCESS;
4733+
}
46944734

4695-
orig_error_reporting = EG(error_reporting);
4696-
EG(error_reporting) = 0;
4735+
#ifdef ZEND_WIN32
4736+
zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
4737+
return FAILURE;
4738+
#endif
46974739

4698-
rc = php_request_startup();
4740+
if (UNEXPECTED(file_cache_only)) {
4741+
zend_accel_error(ACCEL_LOG_WARNING, "Preloading doesn't work in \"file_cache_only\" mode");
4742+
return SUCCESS;
4743+
}
46994744

4700-
EG(error_reporting) = orig_error_reporting;
4745+
/* exclusive lock */
4746+
zend_shared_alloc_lock();
47014747

4702-
if (rc == SUCCESS) {
4703-
bool orig_report_memleaks;
4748+
if (ZCSG(preload_script)) {
4749+
/* Preloading was done in another process */
4750+
preload_load();
4751+
zend_shared_alloc_unlock();
4752+
return SUCCESS;
4753+
}
47044754

4705-
/* don't send headers */
4706-
SG(headers_sent) = true;
4707-
SG(request_info).no_headers = true;
4708-
php_output_set_status(0);
47094755

4710-
ZCG(auto_globals_mask) = 0;
4711-
ZCG(request_time) = (time_t)sapi_get_request_time();
4712-
ZCG(cache_opline) = NULL;
4713-
ZCG(cache_persistent_script) = NULL;
4714-
ZCG(include_path_key_len) = 0;
4715-
ZCG(include_path_check) = true;
4756+
pid_t pid;
4757+
if (accel_finish_startup_preload_subprocess(&pid) == FAILURE) {
4758+
zend_shared_alloc_unlock();
4759+
return FAILURE;
4760+
}
47164761

4717-
ZCG(cwd) = NULL;
4718-
ZCG(cwd_key_len) = 0;
4719-
ZCG(cwd_check) = true;
4762+
if (pid == -1) { /* no subprocess was needed */
4763+
return accel_finish_startup_preload(false);
4764+
} else if (pid == 0) { /* subprocess */
4765+
int ret = accel_finish_startup_preload(true);
47204766

4721-
if (accel_preload(ZCG(accel_directives).preload, in_child) != SUCCESS) {
4722-
ret = FAILURE;
4723-
}
4724-
preload_flush(NULL);
4767+
exit(ret == SUCCESS ? 0 : 1);
4768+
} else { /* parent */
4769+
int status;
47254770

4726-
orig_report_memleaks = PG(report_memleaks);
4727-
PG(report_memleaks) = false;
4728-
#ifdef ZEND_SIGNALS
4729-
/* We may not have registered signal handlers due to SIGG(reset)=0, so
4730-
* also disable the check that they are registered. */
4731-
SIGG(check) = false;
4732-
#endif
4733-
php_request_shutdown(NULL); /* calls zend_shared_alloc_unlock(); */
4734-
PG(report_memleaks) = orig_report_memleaks;
4735-
} else {
4771+
if (waitpid(pid, &status, 0) < 0) {
47364772
zend_shared_alloc_unlock();
4737-
ret = FAILURE;
4773+
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
47384774
}
4739-
#ifdef ZEND_SIGNALS
4740-
SIGG(reset) = old_reset_signals;
4741-
#endif
47424775

4743-
sapi_module.activate = orig_activate;
4744-
sapi_module.deactivate = orig_deactivate;
4745-
sapi_module.register_server_variables = orig_register_server_variables;
4746-
sapi_module.header_handler = orig_header_handler;
4747-
sapi_module.send_headers = orig_send_headers;
4748-
sapi_module.send_header = orig_send_header;
4749-
sapi_module.getenv = orig_getenv;
4750-
sapi_module.ub_write = orig_ub_write;
4751-
sapi_module.flush = orig_flush;
4752-
4753-
sapi_activate();
4754-
4755-
if (in_child) {
4756-
if (ret == SUCCESS) {
4757-
exit(0);
4758-
} else {
4759-
exit(2);
4760-
}
4776+
if (ZCSG(preload_script)) {
4777+
preload_load();
47614778
}
47624779

4763-
return ret;
4764-
#endif
4780+
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
4781+
return SUCCESS;
4782+
} else {
4783+
return FAILURE;
4784+
}
47654785
}
4766-
4767-
return SUCCESS;
47684786
}
47694787

47704788
ZEND_EXT_API zend_extension zend_extension_entry = {

0 commit comments

Comments
 (0)