44#define STR2STR(a) (a ? a : "undefined")
45#define BOOL2STR(a) (a ? "yes" : "no")
46#define GO(field) offsetof(struct fpm_global_config_s, field)
47#define WPO(field) offsetof(struct fpm_worker_pool_config_s, field)
49static int fpm_conf_load_ini_file(
char *filename);
50static char *fpm_conf_set_integer(
zval *
value,
void **config, intptr_t
offset);
52static char *fpm_conf_set_long(
zval *
value,
void **config, intptr_t
offset);
54static char *fpm_conf_set_time(
zval *
value,
void **config, intptr_t
offset);
55static char *fpm_conf_set_boolean(
zval *
value,
void **config, intptr_t
offset);
56static char *fpm_conf_set_string(
zval *
value,
void **config, intptr_t
offset);
57static char *fpm_conf_set_log_level(
zval *
value,
void **config, intptr_t
offset);
58static char *fpm_conf_set_rlimit_core(
zval *
value,
void **config, intptr_t
offset);
59static char *fpm_conf_set_pm(
zval *
value,
void **config, intptr_t
offset);
61static char *fpm_conf_set_syslog_facility(
zval *
value,
void **config, intptr_t
offset);
67 .syslog_facility = -1,
70 .process_priority = 64,
72 .systemd_watchdog = 0,
73 .systemd_interval = -1,
79static int ini_recursion = 0;
80static char *ini_filename =
NULL;
81static int ini_lineno = 0;
82static char *ini_include =
NULL;
88 {
"pid", &fpm_conf_set_string,
GO(pid_file) },
89 {
"error_log", &fpm_conf_set_string,
GO(
error_log) },
91 {
"syslog.ident", &fpm_conf_set_string,
GO(syslog_ident) },
92 {
"syslog.facility", &fpm_conf_set_syslog_facility,
GO(syslog_facility) },
94 {
"log_buffering", &fpm_conf_set_boolean,
GO(log_buffering) },
95 {
"log_level", &fpm_conf_set_log_level,
GO(log_level) },
96 {
"log_limit", &fpm_conf_set_integer,
GO(log_limit) },
97 {
"emergency_restart_threshold", &fpm_conf_set_integer,
GO(emergency_restart_threshold) },
98 {
"emergency_restart_interval", &fpm_conf_set_time,
GO(emergency_restart_interval) },
99 {
"process_control_timeout", &fpm_conf_set_time,
GO(process_control_timeout) },
100 {
"process.max", &fpm_conf_set_integer,
GO(process_max) },
101 {
"process.priority", &fpm_conf_set_integer,
GO(process_priority) },
102 {
"daemonize", &fpm_conf_set_boolean,
GO(daemonize) },
103 {
"rlimit_files", &fpm_conf_set_integer,
GO(rlimit_files) },
104 {
"rlimit_core", &fpm_conf_set_rlimit_core,
GO(rlimit_core) },
105 {
"events.mechanism", &fpm_conf_set_string,
GO(events_mechanism) },
107 {
"systemd_interval", &fpm_conf_set_time,
GO(systemd_interval) },
116 {
"prefix", &fpm_conf_set_string,
WPO(
prefix) },
117 {
"user", &fpm_conf_set_string,
WPO(user) },
118 {
"group", &fpm_conf_set_string,
WPO(group) },
119 {
"listen", &fpm_conf_set_string,
WPO(listen_address) },
120 {
"listen.backlog", &fpm_conf_set_integer,
WPO(listen_backlog) },
122 {
"listen.acl_users", &fpm_conf_set_string,
WPO(listen_acl_users) },
123 {
"listen.acl_groups", &fpm_conf_set_string,
WPO(listen_acl_groups) },
125 {
"listen.owner", &fpm_conf_set_string,
WPO(listen_owner) },
126 {
"listen.group", &fpm_conf_set_string,
WPO(listen_group) },
127 {
"listen.mode", &fpm_conf_set_string,
WPO(listen_mode) },
128 {
"listen.allowed_clients", &fpm_conf_set_string,
WPO(listen_allowed_clients) },
130 {
"listen.setfib", &fpm_conf_set_integer,
WPO(listen_setfib) },
132 {
"process.priority", &fpm_conf_set_integer,
WPO(process_priority) },
133 {
"process.dumpable", &fpm_conf_set_boolean,
WPO(process_dumpable) },
134 {
"pm", &fpm_conf_set_pm,
WPO(pm) },
135 {
"pm.max_children", &fpm_conf_set_integer,
WPO(pm_max_children) },
136 {
"pm.start_servers", &fpm_conf_set_integer,
WPO(pm_start_servers) },
137 {
"pm.min_spare_servers", &fpm_conf_set_integer,
WPO(pm_min_spare_servers) },
138 {
"pm.max_spare_servers", &fpm_conf_set_integer,
WPO(pm_max_spare_servers) },
139 {
"pm.max_spawn_rate", &fpm_conf_set_integer,
WPO(pm_max_spawn_rate) },
140 {
"pm.process_idle_timeout", &fpm_conf_set_time,
WPO(pm_process_idle_timeout) },
141 {
"pm.max_requests", &fpm_conf_set_integer,
WPO(pm_max_requests) },
142 {
"pm.status_path", &fpm_conf_set_string,
WPO(pm_status_path) },
143 {
"pm.status_listen", &fpm_conf_set_string,
WPO(pm_status_listen) },
144 {
"ping.path", &fpm_conf_set_string,
WPO(ping_path) },
145 {
"ping.response", &fpm_conf_set_string,
WPO(ping_response) },
146 {
"access.log", &fpm_conf_set_string,
WPO(access_log) },
147 {
"access.format", &fpm_conf_set_string,
WPO(access_format) },
148 {
"slowlog", &fpm_conf_set_string,
WPO(slowlog) },
149 {
"request_slowlog_timeout", &fpm_conf_set_time,
WPO(request_slowlog_timeout) },
150 {
"request_slowlog_trace_depth", &fpm_conf_set_integer,
WPO(request_slowlog_trace_depth) },
151 {
"request_terminate_timeout", &fpm_conf_set_time,
WPO(request_terminate_timeout) },
152 {
"request_terminate_timeout_track_finished", &fpm_conf_set_boolean,
WPO(request_terminate_timeout_track_finished) },
153 {
"rlimit_files", &fpm_conf_set_integer,
WPO(rlimit_files) },
154 {
"rlimit_core", &fpm_conf_set_rlimit_core,
WPO(rlimit_core) },
155 {
"chroot", &fpm_conf_set_string,
WPO(
chroot) },
156 {
"chdir", &fpm_conf_set_string,
WPO(
chdir) },
157 {
"catch_workers_output", &fpm_conf_set_boolean,
WPO(catch_workers_output) },
158 {
"decorate_workers_output", &fpm_conf_set_boolean,
WPO(decorate_workers_output) },
159 {
"clear_env", &fpm_conf_set_boolean,
WPO(clear_env) },
160 {
"security.limit_extensions", &fpm_conf_set_string,
WPO(security_limit_extensions) },
162 {
"apparmor_hat", &fpm_conf_set_string,
WPO(apparmor_hat) },
167static int fpm_conf_is_dir(
char *path)
171 if (
stat(path, &sb) != 0) {
175 return (sb.st_mode & S_IFMT) == S_IFDIR;
182static int fpm_conf_expand_pool_name(
char **
value) {
191 char *p2 = token +
strlen(
"$pool");
194 if (!current_wp || !current_wp->config || !current_wp->config->name) {
213static char *fpm_conf_set_boolean(
zval *
value,
void **config, intptr_t
offset)
233 if (!value_y && !value_n) {
234 return "invalid boolean value";
237 * (
int *) ((
char *) *config +
offset) = value_y ? 1 : 0;
242static char *fpm_conf_set_string(
zval *
value,
void **config, intptr_t
offset)
244 char **config_val = (
char **) ((
char *) *config +
offset);
247 return "internal error: NULL value";
257 return "fpm_conf_set_string(): strdup() failed";
259 if (fpm_conf_expand_pool_name(config_val) == -1) {
260 return "Can't use '$pool' when the pool is not defined";
267static char *fpm_conf_set_integer(
zval *
value,
void **config, intptr_t
offset)
274 if (
p ==
val && *
p ==
'-')
continue;
275 if (*
p <
'0' || *
p >
'9') {
276 return "is not a valid number (greater or equal than zero)";
279 * (
int *) ((
char *) *config +
offset) = atoi(
val);
285static char *fpm_conf_set_long(
zval *
value,
void **config, intptr_t
offset)
291 if (
p ==
val && *
p ==
'-' )
continue;
292 if (*
p <
'0' || *
p >
'9') {
293 return "is not a valid number (greater or equal than zero)";
296 * (
long int *) ((
char *) *config +
offset) = atol(
val);
302static char *fpm_conf_set_time(
zval *
value,
void **config, intptr_t
offset)
309 return "invalid time value";
316 seconds = 60 * atoi(
val);
320 seconds = 60 * 60 * atoi(
val);
324 seconds = 24 * 60 * 60 * atoi(
val);
331 if (suffix <
'0' || suffix >
'9') {
332 return "unknown suffix used in time value";
338 * (
int *) ((
char *) *config +
offset) = seconds;
343static char *fpm_conf_set_log_level(
zval *
value,
void **config, intptr_t
offset)
359 return "invalid value for 'log_level'";
362 * (
int *) ((
char *) *config +
offset) = log_level;
368static char *fpm_conf_set_syslog_facility(
zval *
value,
void **config, intptr_t
offset)
371 int *conf = (
int *) ((
char *) *config +
offset);
513 return "invalid value";
518static char *fpm_conf_set_rlimit_core(
zval *
value,
void **config, intptr_t
offset)
521 int *
ptr = (
int *) ((
char *) *config +
offset);
527 void *subconf = &int_value;
530 error = fpm_conf_set_integer(
value, &subconf, 0);
537 return "must be greater than zero or 'unlimited'";
547static char *fpm_conf_set_pm(
zval *
value,
void **config, intptr_t
offset)
558 return "invalid process manager (static, dynamic or ondemand)";
564static char *fpm_conf_set_array(
zval *
key,
zval *
value,
void **config,
int convert_to_bool)
571 kv = malloc(
sizeof(*kv));
574 return "malloc() failed";
577 memset(kv, 0,
sizeof(*kv));
583 return "fpm_conf_set_array: strdup(key) failed";
587 if (convert_to_bool) {
588 char *
err = fpm_conf_set_boolean(
value, &subconf, 0);
594 kv->
value = strdup(b ?
"1" :
"0");
597 if (fpm_conf_expand_pool_name(&kv->
value) == -1) {
600 return "Can't use '$pool' when the pool is not defined";
607 return "fpm_conf_set_array: strdup(value) failed";
616static void *fpm_worker_pool_config_alloc(
void)
642 wp->
config->listen_setfib = -1;
685 free(wpc->apparmor_hat);
693 for (kv = wpc->
php_values; kv; kv = kv_next) {
705 for (kv = wpc->
env; kv; kv = kv_next) {
716#define FPM_WPC_STR_CP_EX(_cfg, _scfg, _sf, _df) \
718 if (_scfg->_df && !(_cfg->_sf = strdup(_scfg->_df))) { \
722#define FPM_WPC_STR_CP(_cfg, _scfg, _field) FPM_WPC_STR_CP_EX(_cfg, _scfg, _field, _field)
724static void fpm_conf_apply_kv_array_to_kv_array(
struct key_value_s *src,
void *dest) {
727 for (kv = src; kv; kv = kv->
next) {
731 fpm_conf_set_array(&k, &
v, &dest, 0);
735static int fpm_worker_pool_shared_status_alloc(
struct fpm_worker_pool_s *shared_wp) {
737 config = fpm_worker_pool_config_alloc();
741 shared_config = shared_wp->
config;
743 config->
name = malloc(
strlen(shared_config->
name) +
sizeof(
"_status"));
747 strcpy(config->
name, shared_config->
name);
775 current_wp->shared = shared_wp;
781static int fpm_evaluate_full_path(
char **path,
struct fpm_worker_pool_s *wp,
char *default_prefix,
int expand)
786 if (!path || !*path || **path ==
'/') {
806 tmp =
strstr(*path,
"$prefix");
810 zlog(
ZLOG_ERROR,
"'$prefix' must be use at the beginning of the value");
815 tmp = strdup((*path) +
strlen(
"$prefix"));
828 *path = strdup(full_path);
834 if (**path !=
'/' && wp !=
NULL && wp->
config) {
835 return fpm_evaluate_full_path(path,
NULL, default_prefix, expand);
841static int fpm_conf_process_all_pools(
void)
846 zlog(
ZLOG_ERROR,
"No pool defined. at least one pool section must be specified in config file");
939 zlog(
ZLOG_ALERT,
"[pool %s] ondemand process manager can ONLY be used when events.mechanism is either epoll (Linux) or kqueue (*BSD).", wp->
config->
name);
1001 for (i = 0; i <
strlen(ping); i++) {
1002 if (!isalnum(ping[i]) && ping[i] !=
'/' && ping[i] !=
'-' && ping[i] !=
'_' && ping[i] !=
'.' && ping[i] !=
'~') {
1003 zlog(
ZLOG_ERROR,
"[pool %s] the ping path '%s' must contain only the following characters '[alphanum]/_-.~'", wp->
config->
name, ping);
1044 zlog(
ZLOG_ERROR,
"[pool %s] 'slowlog' must be specified for use with 'request_slowlog_timeout'", wp->
config->
name);
1048 static int warned = 0;
1061 fd = open(wp->
config->
slowlog, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
1073 zlog(ZLOG_ERROR,
"[pool %s] 'request_slowlog_timeout' (%d) can't be greater than 'request_terminate_timeout' (%d)", wp->config->name, wp->config->request_slowlog_timeout, wp->config->request_terminate_timeout);
1082 zlog(
ZLOG_ERROR,
"[pool %s] 'slowlog' must be specified for use with 'request_slowlog_trace_depth'", wp->
config->
name);
1086 static int warned = 0;
1133 if (!fpm_conf_is_dir(
buf)) {
1157 char *limit_extensions;
1166 while (
strtok(limit_extensions,
" \t")) {
1167 limit_extensions =
NULL;
1188 while ((
ext =
strtok(limit_extensions,
" \t"))) {
1189 limit_extensions =
NULL;
1205 for (
const char *
const*
p =
options; *
p;
p++) {
1207 fpm_evaluate_full_path(&kv->
value, wp,
NULL, 0);
1215 for (
const char *
const*
p =
options; *
p;
p++) {
1217 fpm_evaluate_full_path(&kv->
value, wp,
NULL, 0);
1279static int fpm_conf_post_process(
int force_daemon)
1287 if (force_daemon >= 0) {
1307 zlog(
ZLOG_ERROR,
"process.priority must be included into [-19,20]");
1348 if (0 > fpm_conf_process_all_pools()) {
1370static void fpm_conf_cleanup(
int which,
void *
arg)
1386static void fpm_conf_ini_parser_include(
char *inc,
void *
arg)
1395 if (!inc || !
arg)
return;
1397 spprintf(&filename, 0,
"%s", ini_filename);
1405 zlog(
ZLOG_WARNING,
"Nothing matches the include pattern '%s' from %s at line %d.", inc, filename, ini_lineno);
1410 zlog(
ZLOG_ERROR,
"Unable to globalize '%s' (ret=%zd) from %s at line %d.", inc, i, filename, ini_lineno);
1418 if (
len < 1)
continue;
1420 if (0 > fpm_conf_load_ini_file(g.
gl_pathv[i])) {
1430 if (0 > fpm_conf_load_ini_file(inc)) {
1431 zlog(
ZLOG_ERROR,
"Unable to include %s from %s at line %d", inc, filename, ini_lineno);
1442static void fpm_conf_ini_parser_section(
zval *section,
void *
arg)
1455 if (!wp->
config)
continue;
1466 if (!current_wp || !config) {
1467 zlog(
ZLOG_ERROR,
"[%s:%d] Unable to alloc a new WorkerPool for worker '%s'", ini_filename, ini_lineno,
Z_STRVAL_P(section));
1472 if (!config->
name) {
1473 zlog(
ZLOG_ERROR,
"[%s:%d] Unable to alloc memory for configuration name for worker '%s'", ini_filename, ini_lineno,
Z_STRVAL_P(section));
1483 void *config =
NULL;
1487 zlog(
ZLOG_ERROR,
"[%s:%d] value is NULL for a ZEND_INI_PARSER_ENTRY", ini_filename, ini_lineno);
1494 zlog(
ZLOG_ERROR,
"[%s:%d] two includes at the same time !", ini_filename, ini_lineno);
1503 parser = ini_fpm_global_options;
1506 parser = ini_fpm_pool_options;
1507 config = current_wp->config;
1514 zlog(
ZLOG_ERROR,
"[%s:%d] the parser for entry '%s' is not defined", ini_filename, ini_lineno,
parser->name);
1521 zlog(
ZLOG_ERROR,
"[%s:%d] unable to parse value for entry '%s': %s", ini_filename, ini_lineno,
parser->name,
ret);
1545 zlog(
ZLOG_ERROR,
"[%s:%d] Keys provided to field 'access.suppress_path' are ignored", ini_filename, ini_lineno);
1549 zlog(
ZLOG_ERROR,
"[%s:%d] Values provided to field 'access.suppress_path' must begin with '/'", ini_filename, ini_lineno);
1561 if (!current_wp || !current_wp->config) {
1562 zlog(
ZLOG_ERROR,
"[%s:%d] Array are not allowed in the global section", ini_filename, ini_lineno);
1569 zlog(
ZLOG_ERROR,
"[%s:%d] empty value", ini_filename, ini_lineno);
1573 config = (
char *)current_wp->config +
WPO(env);
1577 config = (
char *)current_wp->config +
WPO(php_values);
1581 config = (
char *)current_wp->config +
WPO(php_admin_values);
1585 config = (
char *)current_wp->config +
WPO(php_values);
1589 config = (
char *)current_wp->config +
WPO(php_admin_values);
1593 config = (
char *)current_wp->config +
WPO(access_suppress_paths);
1618 switch(callback_type) {
1623 fpm_conf_ini_parser_section(
arg1,
error);
1629 zlog(
ZLOG_ERROR,
"[%s:%d] Unknown INI syntax", ini_filename, ini_lineno);
1636int fpm_conf_load_ini_file(
char *filename)
1647 if (!filename || !filename[0]) {
1652 fd = open(filename, O_RDONLY, 0);
1658 if (ini_recursion++ > 4) {
1659 zlog(
ZLOG_ERROR,
"failed to include more than 5 files recursively");
1665 while (nb_read > 0) {
1668 ini_filename = filename;
1669 for (
n = 0; (nb_read = read(
fd, &c,
sizeof(
char))) ==
sizeof(char) && c !=
'\n';
n++) {
1672 newbuf = (
char*) realloc(
buf,
sizeof(
char) * (bufsize + 2));
1673 if (newbuf ==
NULL) {
1691 ini_filename = filename;
1703 char *tmp = ini_include;
1705 fpm_evaluate_full_path(&tmp,
NULL,
NULL, 0);
1706 fpm_conf_ini_parser_include(tmp, &
error);
1725static void fpm_conf_dump(
void)
1881 if (0 > fpm_conf_post_process(force_daemon)) {
1893 if (test_conf > 1) {
file_private const char ext[]
chroot(string $directory)
unlink(string $filename, $context=null)
strtok(string $string, ?string $token=null)
error_log(string $message, int $message_type=0, ?string $destination=null, ?string $additional_headers=null)
glob(string $pattern, int $flags=0)
strstr(string $haystack, string $needle, bool $before_needle=false)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
struct fpm_globals_s fpm_globals
int fpm_cleanup_add(int type, void(*cleanup)(int, void *), void *arg)
#define FPM_WPC_STR_CP(_cfg, _scfg, _field)
#define FPM_WPC_STR_CP_EX(_cfg, _scfg, _sf, _df)
int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc)
int fpm_conf_unlink_pid(void)
int fpm_conf_init_main(int test_conf, int force_daemon)
struct fpm_global_config_s fpm_global_config
int fpm_conf_write_pid(void)
int fpm_event_pre_init(char *mechanism)
int fpm_event_support_edge_trigger(void)
const char * fpm_event_mechanism_name(void)
int fpm_log_open(int reopen)
int fpm_log_write(char *log_format)
#define FPM_PHP_INI_TO_EXPAND
enum fpm_address_domain fpm_sockets_domain_from_address(char *address)
#define FPM_BACKLOG_DEFAULT
int fpm_stdio_open_error_log(int reopen)
int fpm_stdio_save_original_stderr(void)
int fpm_systemd_conf(void)
bool fpm_unix_test_config(struct fpm_worker_pool_s *wp)
struct fpm_worker_pool_s * fpm_worker_pool_alloc(void)
void fpm_worker_pool_free(struct fpm_worker_pool_s *wp)
struct fpm_worker_pool_s * fpm_worker_all_pools
PHPAPI void globfree(glob_t *pglob)
PHP_JSON_API size_t int options
unsigned char key[REFLECTION_KEY_LEN]
char * security_limit_extensions
int request_terminate_timeout_track_finished
int request_slowlog_timeout
struct key_value_s * php_admin_values
struct key_value_s * php_values
char * listen_allowed_clients
int request_slowlog_trace_depth
struct key_value_s * access_suppress_paths
int pm_process_idle_timeout
int decorate_workers_output
int request_terminate_timeout
struct fpm_worker_pool_config_s * config
enum fpm_address_domain listen_address_domain
struct fpm_worker_pool_s * shared
struct fpm_worker_pool_s * next
char *(* parser)(zval *, void **, intptr_t)
struct key_value_s * next
#define ZVAL_STRING(z, s)
strcmp(string $string1, string $string2)
#define strcasecmp(s1, s2)
#define ZEND_INI_PARSER_ENTRY
void(* zend_ini_parser_cb_t)(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg)
#define ZEND_INI_PARSER_POP_ENTRY
ZEND_API zend_result zend_parse_ini_string(const char *str, bool unbuffered_errors, int scanner_mode, zend_ini_parser_cb_t ini_parser_cb, void *arg)
#define ZEND_INI_PARSER_SECTION
#define ZEND_INI_SCANNER_NORMAL
struct _zend_string zend_string
#define zend_string_equals_literal(str, literal)
#define zend_string_equals_ci(s1, s2)
#define zend_string_equals_literal_ci(str, c)
#define Z_STRVAL_P(zval_p)
int zlog_set_limit(int new_value)
int zlog_set_level(int new_value)
const char * zlog_get_level_name(int log_level)
int zlog_set_buffering(zlog_bool buffering)
#define ZLOG_DEFAULT_LIMIT
#define ZLOG_DEFAULT_BUFFERING