/* $Id: fpm_conf.c,v 1.33.2.3 2008/12/13 03:50:29 anight Exp $ */ /* (c) 2007,2008 Andrei Nigmatulin */ #include "fpm_config.h" #include #include #include #include #include #include #include #if HAVE_INTTYPES_H # include #else # include #endif #ifdef HAVE_GLOB # ifndef PHP_WIN32 # include # else # include "win32/glob.h" # endif #endif #include #include #include "php.h" #include "zend_ini_scanner.h" #include "zend_globals.h" #include "zend_stream.h" #include "php_syslog.h" #include "fpm.h" #include "fpm_conf.h" #include "fpm_stdio.h" #include "fpm_worker_pool.h" #include "fpm_cleanup.h" #include "fpm_php.h" #include "fpm_sockets.h" #include "fpm_shm.h" #include "fpm_status.h" #include "fpm_log.h" #include "fpm_events.h" #include "zlog.h" #ifdef HAVE_SYSTEMD #include "fpm_systemd.h" #endif #define STR2STR(a) (a ? a : "undefined") #define BOOL2STR(a) (a ? "yes" : "no") #define GO(field) offsetof(struct fpm_global_config_s, field) #define WPO(field) offsetof(struct fpm_worker_pool_config_s, field) 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); static char *fpm_conf_set_log_level(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_rlimit_core(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_pm(zval *value, void **config, intptr_t offset); #ifdef HAVE_SYSLOG_H static char *fpm_conf_set_syslog_facility(zval *value, void **config, intptr_t offset); #endif struct fpm_global_config_s fpm_global_config = { .daemonize = 1, #ifdef HAVE_SYSLOG_H .syslog_facility = -1, #endif .process_max = 0, .process_priority = 64, /* 64 means unset */ #ifdef HAVE_SYSTEMD .systemd_watchdog = 0, .systemd_interval = -1, /* -1 means not set */ #endif }; static struct fpm_worker_pool_s *current_wp = NULL; static int ini_recursion = 0; static char *ini_filename = NULL; static int ini_lineno = 0; static char *ini_include = NULL; /* * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in */ static struct ini_value_parser_s ini_fpm_global_options[] = { { "pid", &fpm_conf_set_string, GO(pid_file) }, { "error_log", &fpm_conf_set_string, GO(error_log) }, #ifdef HAVE_SYSLOG_H { "syslog.ident", &fpm_conf_set_string, GO(syslog_ident) }, { "syslog.facility", &fpm_conf_set_syslog_facility, GO(syslog_facility) }, #endif { "log_level", &fpm_conf_set_log_level, GO(log_level) }, { "emergency_restart_threshold", &fpm_conf_set_integer, GO(emergency_restart_threshold) }, { "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) }, { "events.mechanism", &fpm_conf_set_string, GO(events_mechanism) }, #ifdef HAVE_SYSTEMD { "systemd_interval", &fpm_conf_set_time, GO(systemd_interval) }, #endif { 0, 0, 0 } }; /* * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in */ static struct ini_value_parser_s ini_fpm_pool_options[] = { { "prefix", &fpm_conf_set_string, WPO(prefix) }, { "user", &fpm_conf_set_string, WPO(user) }, { "group", &fpm_conf_set_string, WPO(group) }, { "listen", &fpm_conf_set_string, WPO(listen_address) }, { "listen.backlog", &fpm_conf_set_integer, WPO(listen_backlog) }, { "listen.owner", &fpm_conf_set_string, WPO(listen_owner) }, { "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) }, { "pm.min_spare_servers", &fpm_conf_set_integer, WPO(pm_min_spare_servers) }, { "pm.max_spare_servers", &fpm_conf_set_integer, WPO(pm_max_spare_servers) }, { "pm.process_idle_timeout", &fpm_conf_set_time, WPO(pm_process_idle_timeout) }, { "pm.max_requests", &fpm_conf_set_integer, WPO(pm_max_requests) }, { "pm.status_path", &fpm_conf_set_string, WPO(pm_status_path) }, { "ping.path", &fpm_conf_set_string, WPO(ping_path) }, { "ping.response", &fpm_conf_set_string, WPO(ping_response) }, { "access.log", &fpm_conf_set_string, WPO(access_log) }, { "access.format", &fpm_conf_set_string, WPO(access_format) }, { "slowlog", &fpm_conf_set_string, WPO(slowlog) }, { "request_slowlog_timeout", &fpm_conf_set_time, WPO(request_slowlog_timeout) }, { "request_terminate_timeout", &fpm_conf_set_time, WPO(request_terminate_timeout) }, { "rlimit_files", &fpm_conf_set_integer, WPO(rlimit_files) }, { "rlimit_core", &fpm_conf_set_rlimit_core, WPO(rlimit_core) }, { "chroot", &fpm_conf_set_string, WPO(chroot) }, { "chdir", &fpm_conf_set_string, WPO(chdir) }, { "catch_workers_output", &fpm_conf_set_boolean, WPO(catch_workers_output) }, { "clear_env", &fpm_conf_set_boolean, WPO(clear_env) }, { "security.limit_extensions", &fpm_conf_set_string, WPO(security_limit_extensions) }, { 0, 0, 0 } }; static int fpm_conf_is_dir(char *path) /* {{{ */ { struct stat sb; if (stat(path, &sb) != 0) { return 0; } return (sb.st_mode & S_IFMT) == S_IFDIR; } /* }}} */ /* * Expands the '$pool' token in a dynamically allocated string */ static int fpm_conf_expand_pool_name(char **value) { char *token; if (!value || !*value) { return 0; } while (*value && (token = strstr(*value, "$pool"))) { char *buf; char *p2 = token + strlen("$pool"); /* If we are not in a pool, we cannot expand this name now */ if (!current_wp || !current_wp->config || !current_wp->config->name) { return -1; } /* "aaa$poolbbb" becomes "aaa\0oolbbb" */ token[0] = '\0'; /* Build a brand new string with the expanded token */ spprintf(&buf, 0, "%s%s%s", *value, current_wp->config->name, p2); /* Free the previous value and save the new one */ free(*value); *value = strdup(buf); efree(buf); } return 0; } static char *fpm_conf_set_boolean(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); long value_y = !strcasecmp(val, "1"); long value_n = !strcasecmp(val, ""); if (!value_y && !value_n) { return "invalid boolean value"; } * (int *) ((char *) *config + offset) = value_y ? 1 : 0; return NULL; } /* }}} */ static char *fpm_conf_set_string(zval *value, void **config, intptr_t offset) /* {{{ */ { char **config_val = (char **) ((char *) *config + offset); if (!config_val) { return "internal error: NULL value"; } /* Check if there is a previous value to deallocate */ if (*config_val) { free(*config_val); } *config_val = strdup(Z_STRVAL_P(value)); if (!*config_val) { return "fpm_conf_set_string(): strdup() failed"; } if (fpm_conf_expand_pool_name(config_val) == -1) { return "Can't use '$pool' when the pool is not defined"; } return NULL; } /* }}} */ static char *fpm_conf_set_integer(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); char *p; /* we don't use strtol because we don't want to allow negative values */ for (p = val; *p; p++) { if (p == val && *p == '-') continue; if (*p < '0' || *p > '9') { return "is not a valid number (greater or equal than zero)"; } } * (int *) ((char *) *config + offset) = atoi(val); return NULL; } /* }}} */ #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); char *p; for (p = val; *p; p++) { if ( p == val && *p == '-' ) continue; if (*p < '0' || *p > '9') { return "is not a valid number (greater or equal than zero)"; } } * (long int *) ((char *) *config + offset) = atol(val); return NULL; } /* }}} */ #endif static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); int len = strlen(val); char suffix; int seconds; if (!len) { return "invalid time value"; } suffix = val[len-1]; switch (suffix) { case 'm' : val[len-1] = '\0'; seconds = 60 * atoi(val); break; case 'h' : val[len-1] = '\0'; seconds = 60 * 60 * atoi(val); break; case 'd' : val[len-1] = '\0'; seconds = 24 * 60 * 60 * atoi(val); break; case 's' : /* s is the default suffix */ val[len-1] = '\0'; suffix = '0'; default : if (suffix < '0' || suffix > '9') { return "unknown suffix used in time value"; } seconds = atoi(val); break; } * (int *) ((char *) *config + offset) = seconds; return NULL; } /* }}} */ static char *fpm_conf_set_log_level(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); int log_level; if (!strcasecmp(val, "debug")) { log_level = ZLOG_DEBUG; } else if (!strcasecmp(val, "notice")) { log_level = ZLOG_NOTICE; } else if (!strcasecmp(val, "warning") || !strcasecmp(val, "warn")) { log_level = ZLOG_WARNING; } else if (!strcasecmp(val, "error")) { log_level = ZLOG_ERROR; } else if (!strcasecmp(val, "alert")) { log_level = ZLOG_ALERT; } else { return "invalid value for 'log_level'"; } * (int *) ((char *) *config + offset) = log_level; return NULL; } /* }}} */ #ifdef HAVE_SYSLOG_H static char *fpm_conf_set_syslog_facility(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); int *conf = (int *) ((char *) *config + offset); #ifdef LOG_AUTH if (!strcasecmp(val, "AUTH")) { *conf = LOG_AUTH; return NULL; } #endif #ifdef LOG_AUTHPRIV if (!strcasecmp(val, "AUTHPRIV")) { *conf = LOG_AUTHPRIV; return NULL; } #endif #ifdef LOG_CRON if (!strcasecmp(val, "CRON")) { *conf = LOG_CRON; return NULL; } #endif #ifdef LOG_DAEMON if (!strcasecmp(val, "DAEMON")) { *conf = LOG_DAEMON; return NULL; } #endif #ifdef LOG_FTP if (!strcasecmp(val, "FTP")) { *conf = LOG_FTP; return NULL; } #endif #ifdef LOG_KERN if (!strcasecmp(val, "KERN")) { *conf = LOG_KERN; return NULL; } #endif #ifdef LOG_LPR if (!strcasecmp(val, "LPR")) { *conf = LOG_LPR; return NULL; } #endif #ifdef LOG_MAIL if (!strcasecmp(val, "MAIL")) { *conf = LOG_MAIL; return NULL; } #endif #ifdef LOG_NEWS if (!strcasecmp(val, "NEWS")) { *conf = LOG_NEWS; return NULL; } #endif #ifdef LOG_SYSLOG if (!strcasecmp(val, "SYSLOG")) { *conf = LOG_SYSLOG; return NULL; } #endif #ifdef LOG_USER if (!strcasecmp(val, "USER")) { *conf = LOG_USER; return NULL; } #endif #ifdef LOG_UUCP if (!strcasecmp(val, "UUCP")) { *conf = LOG_UUCP; return NULL; } #endif #ifdef LOG_LOCAL0 if (!strcasecmp(val, "LOCAL0")) { *conf = LOG_LOCAL0; return NULL; } #endif #ifdef LOG_LOCAL1 if (!strcasecmp(val, "LOCAL1")) { *conf = LOG_LOCAL1; return NULL; } #endif #ifdef LOG_LOCAL2 if (!strcasecmp(val, "LOCAL2")) { *conf = LOG_LOCAL2; return NULL; } #endif #ifdef LOG_LOCAL3 if (!strcasecmp(val, "LOCAL3")) { *conf = LOG_LOCAL3; return NULL; } #endif #ifdef LOG_LOCAL4 if (!strcasecmp(val, "LOCAL4")) { *conf = LOG_LOCAL4; return NULL; } #endif #ifdef LOG_LOCAL5 if (!strcasecmp(val, "LOCAL5")) { *conf = LOG_LOCAL5; return NULL; } #endif #ifdef LOG_LOCAL6 if (!strcasecmp(val, "LOCAL6")) { *conf = LOG_LOCAL6; return NULL; } #endif #ifdef LOG_LOCAL7 if (!strcasecmp(val, "LOCAL7")) { *conf = LOG_LOCAL7; return NULL; } #endif return "invalid value"; } /* }}} */ #endif static char *fpm_conf_set_rlimit_core(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); int *ptr = (int *) ((char *) *config + offset); if (!strcasecmp(val, "unlimited")) { *ptr = -1; } else { int int_value; void *subconf = &int_value; char *error; error = fpm_conf_set_integer(value, &subconf, 0); if (error) { return error; } if (int_value < 0) { return "must be greater than zero or 'unlimited'"; } *ptr = int_value; } return NULL; } /* }}} */ static char *fpm_conf_set_pm(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); struct fpm_worker_pool_config_s *c = *config; if (!strcasecmp(val, "static")) { c->pm = PM_STYLE_STATIC; } else if (!strcasecmp(val, "dynamic")) { c->pm = PM_STYLE_DYNAMIC; } else if (!strcasecmp(val, "ondemand")) { c->pm = PM_STYLE_ONDEMAND; } else { return "invalid process manager (static, dynamic or ondemand)"; } return NULL; } /* }}} */ static char *fpm_conf_set_array(zval *key, zval *value, void **config, int convert_to_bool) /* {{{ */ { struct key_value_s *kv; struct key_value_s ***parent = (struct key_value_s ***) config; int b; void *subconf = &b; kv = malloc(sizeof(*kv)); if (!kv) { return "malloc() failed"; } memset(kv, 0, sizeof(*kv)); kv->key = strdup(Z_STRVAL_P(key)); if (!kv->key) { free(kv); return "fpm_conf_set_array: strdup(key) failed"; } if (convert_to_bool) { char *err = fpm_conf_set_boolean(value, &subconf, 0); if (err) { free(kv->key); free(kv); return err; } kv->value = strdup(b ? "1" : "0"); } else { kv->value = strdup(Z_STRVAL_P(value)); if (fpm_conf_expand_pool_name(&kv->value) == -1) { return "Can't use '$pool' when the pool is not defined"; } } if (!kv->value) { free(kv->key); free(kv); return "fpm_conf_set_array: strdup(value) failed"; } kv->next = **parent; **parent = kv; return NULL; } /* }}} */ static void *fpm_worker_pool_config_alloc() /* {{{ */ { struct fpm_worker_pool_s *wp; wp = fpm_worker_pool_alloc(); if (!wp) { return 0; } wp->config = malloc(sizeof(struct fpm_worker_pool_config_s)); if (!wp->config) { fpm_worker_pool_free(wp); return 0; } 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 */ wp->config->clear_env = 1; if (!fpm_worker_all_pools) { fpm_worker_all_pools = wp; } else { struct fpm_worker_pool_s *tmp = fpm_worker_all_pools; while (tmp) { if (!tmp->next) { tmp->next = wp; break; } tmp = tmp->next; } } current_wp = wp; return wp->config; } /* }}} */ int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc) /* {{{ */ { struct key_value_s *kv, *kv_next; free(wpc->name); free(wpc->prefix); free(wpc->user); free(wpc->group); free(wpc->listen_address); free(wpc->listen_owner); free(wpc->listen_group); free(wpc->listen_mode); free(wpc->listen_allowed_clients); free(wpc->pm_status_path); free(wpc->ping_path); free(wpc->ping_response); free(wpc->access_log); free(wpc->access_format); free(wpc->slowlog); free(wpc->chroot); free(wpc->chdir); free(wpc->security_limit_extensions); for (kv = wpc->php_values; kv; kv = kv_next) { kv_next = kv->next; free(kv->key); free(kv->value); free(kv); } for (kv = wpc->php_admin_values; kv; kv = kv_next) { kv_next = kv->next; free(kv->key); free(kv->value); free(kv); } for (kv = wpc->env; kv; kv = kv_next) { kv_next = kv->next; free(kv->key); free(kv->value); free(kv); } return 0; } /* }}} */ static int fpm_evaluate_full_path(char **path, struct fpm_worker_pool_s *wp, char *default_prefix, int expand) /* {{{ */ { char *prefix = NULL; char *full_path; if (!path || !*path || **path == '/') { return 0; } if (wp && wp->config) { prefix = wp->config->prefix; } /* if the wp prefix is not set */ if (prefix == NULL) { prefix = fpm_globals.prefix; } /* if the global prefix is not set */ if (prefix == NULL) { prefix = default_prefix ? default_prefix : PHP_PREFIX; } if (expand) { char *tmp; tmp = strstr(*path, "$prefix"); if (tmp != NULL) { if (tmp != *path) { zlog(ZLOG_ERROR, "'$prefix' must be use at the beginning of the value"); return -1; } if (strlen(*path) > strlen("$prefix")) { free(*path); tmp = strdup((*path) + strlen("$prefix")); *path = tmp; } else { free(*path); *path = NULL; } } } if (*path) { spprintf(&full_path, 0, "%s/%s", prefix, *path); free(*path); *path = strdup(full_path); efree(full_path); } else { *path = strdup(prefix); } if (**path != '/' && wp != NULL && wp->config) { return fpm_evaluate_full_path(path, NULL, default_prefix, expand); } return 0; } /* }}} */ static int fpm_conf_process_all_pools() /* {{{ */ { 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"); return -1; } for (wp = fpm_worker_all_pools; wp; wp = wp->next) { /* prefix */ if (wp->config->prefix && *wp->config->prefix) { fpm_evaluate_full_path(&wp->config->prefix, NULL, NULL, 0); if (!fpm_conf_is_dir(wp->config->prefix)) { zlog(ZLOG_ERROR, "[pool %s] the prefix '%s' does not exist or is not a directory", wp->config->name, wp->config->prefix); return -1; } } /* 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; } /* listen */ if (wp->config->listen_address && *wp->config->listen_address) { wp->listen_address_domain = fpm_sockets_domain_from_address(wp->config->listen_address); if (wp->listen_address_domain == FPM_AF_UNIX && *wp->config->listen_address != '/') { fpm_evaluate_full_path(&wp->config->listen_address, wp, NULL, 0); } } else { zlog(ZLOG_ALERT, "[pool %s] no listen address have been defined!", wp->config->name); 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); return -1; } /* pm.max_children */ if (wp->config->pm_max_children < 1) { zlog(ZLOG_ALERT, "[pool %s] pm.max_children must be a positive value", wp->config->name); return -1; } /* pm.start_servers, pm.min_spare_servers, pm.max_spare_servers */ if (wp->config->pm == PM_STYLE_DYNAMIC) { struct fpm_worker_pool_config_s *config = wp->config; if (config->pm_min_spare_servers <= 0) { zlog(ZLOG_ALERT, "[pool %s] pm.min_spare_servers(%d) must be a positive value", wp->config->name, config->pm_min_spare_servers); return -1; } if (config->pm_max_spare_servers <= 0) { zlog(ZLOG_ALERT, "[pool %s] pm.max_spare_servers(%d) must be a positive value", wp->config->name, config->pm_max_spare_servers); return -1; } if (config->pm_min_spare_servers > config->pm_max_children || config->pm_max_spare_servers > config->pm_max_children) { zlog(ZLOG_ALERT, "[pool %s] pm.min_spare_servers(%d) and pm.max_spare_servers(%d) cannot be greater than pm.max_children(%d)", wp->config->name, config->pm_min_spare_servers, config->pm_max_spare_servers, config->pm_max_children); return -1; } if (config->pm_max_spare_servers < config->pm_min_spare_servers) { zlog(ZLOG_ALERT, "[pool %s] pm.max_spare_servers(%d) must not be less than pm.min_spare_servers(%d)", wp->config->name, config->pm_max_spare_servers, config->pm_min_spare_servers); return -1; } if (config->pm_start_servers <= 0) { config->pm_start_servers = config->pm_min_spare_servers + ((config->pm_max_spare_servers - config->pm_min_spare_servers) / 2); zlog(ZLOG_NOTICE, "[pool %s] pm.start_servers is not set. It's been set to %d.", wp->config->name, config->pm_start_servers); } else if (config->pm_start_servers < config->pm_min_spare_servers || config->pm_start_servers > config->pm_max_spare_servers) { zlog(ZLOG_ALERT, "[pool %s] pm.start_servers(%d) must not be less than pm.min_spare_servers(%d) and not greater than pm.max_spare_servers(%d)", wp->config->name, config->pm_start_servers, config->pm_min_spare_servers, config->pm_max_spare_servers); return -1; } } else if (wp->config->pm == PM_STYLE_ONDEMAND) { struct fpm_worker_pool_config_s *config = wp->config; if (!fpm_event_support_edge_trigger()) { zlog(ZLOG_ALERT, "[pool %s] ondemand process manager can ONLY be used when events.mechanisme is either epoll (Linux) or kqueue (*BSD).", wp->config->name); return -1; } if (config->pm_process_idle_timeout < 1) { zlog(ZLOG_ALERT, "[pool %s] pm.process_idle_timeout(%ds) must be greater than 0s", wp->config->name, config->pm_process_idle_timeout); return -1; } if (config->listen_backlog < FPM_BACKLOG_DEFAULT) { zlog(ZLOG_WARNING, "[pool %s] listen.backlog(%d) was too low for the ondemand process manager. I updated it for you to %d.", wp->config->name, config->listen_backlog, FPM_BACKLOG_DEFAULT); config->listen_backlog = FPM_BACKLOG_DEFAULT; } /* certainely useless but proper */ config->pm_start_servers = 0; config->pm_min_spare_servers = 0; config->pm_max_spare_servers = 0; } /* status */ if (wp->config->pm_status_path && *wp->config->pm_status_path) { int i; char *status = wp->config->pm_status_path; if (*status != '/') { zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must start with a '/'", wp->config->name, status); return -1; } if (strlen(status) < 2) { zlog(ZLOG_ERROR, "[pool %s] the status path '%s' is not long enough", wp->config->name, status); return -1; } for (i = 0; i < strlen(status); i++) { if (!isalnum(status[i]) && status[i] != '/' && status[i] != '-' && status[i] != '_' && status[i] != '.') { zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must contain only the following characters '[alphanum]/_-.'", wp->config->name, status); return -1; } } } /* ping */ if (wp->config->ping_path && *wp->config->ping_path) { char *ping = wp->config->ping_path; int i; if (*ping != '/') { zlog(ZLOG_ERROR, "[pool %s] the ping path '%s' must start with a '/'", wp->config->name, ping); return -1; } if (strlen(ping) < 2) { zlog(ZLOG_ERROR, "[pool %s] the ping path '%s' is not long enough", wp->config->name, ping); return -1; } for (i = 0; i < strlen(ping); i++) { if (!isalnum(ping[i]) && ping[i] != '/' && ping[i] != '-' && ping[i] != '_' && ping[i] != '.') { zlog(ZLOG_ERROR, "[pool %s] the ping path '%s' must containt only the following characters '[alphanum]/_-.'", wp->config->name, ping); return -1; } } if (!wp->config->ping_response) { wp->config->ping_response = strdup("pong"); } else { if (strlen(wp->config->ping_response) < 1) { zlog(ZLOG_ERROR, "[pool %s] the ping response page '%s' is not long enough", wp->config->name, wp->config->ping_response); return -1; } } } else { if (wp->config->ping_response) { free(wp->config->ping_response); wp->config->ping_response = NULL; } } /* access.log, access.format */ if (wp->config->access_log && *wp->config->access_log) { fpm_evaluate_full_path(&wp->config->access_log, wp, NULL, 0); if (!wp->config->access_format) { wp->config->access_format = strdup("%R - %u %t \"%m %r\" %s"); } } if (wp->config->request_terminate_timeout) { fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_terminate_timeout * 1000) / 3) : (wp->config->request_terminate_timeout * 1000) / 3; } /* slowlog */ if (wp->config->slowlog && *wp->config->slowlog) { fpm_evaluate_full_path(&wp->config->slowlog, wp, NULL, 0); } /* request_slowlog_timeout */ if (wp->config->request_slowlog_timeout) { #if HAVE_FPM_TRACE if (! (wp->config->slowlog && *wp->config->slowlog)) { zlog(ZLOG_ERROR, "[pool %s] 'slowlog' must be specified for use with 'request_slowlog_timeout'", wp->config->name); return -1; } #else static int warned = 0; if (!warned) { zlog(ZLOG_WARNING, "[pool %s] 'request_slowlog_timeout' is not supported on your system", wp->config->name); warned = 1; } wp->config->request_slowlog_timeout = 0; #endif if (wp->config->slowlog && *wp->config->slowlog) { int fd; fd = open(wp->config->slowlog, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); if (0 > fd) { zlog(ZLOG_SYSERROR, "Unable to create or open slowlog(%s)", wp->config->slowlog); return -1; } close(fd); } fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_slowlog_timeout * 1000) / 3) : (wp->config->request_slowlog_timeout * 1000) / 3; if (wp->config->request_terminate_timeout && wp->config->request_slowlog_timeout > wp->config->request_terminate_timeout) { 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); return -1; } } /* chroot */ if (wp->config->chroot && *wp->config->chroot) { fpm_evaluate_full_path(&wp->config->chroot, wp, NULL, 1); if (*wp->config->chroot != '/') { zlog(ZLOG_ERROR, "[pool %s] the chroot path '%s' must start with a '/'", wp->config->name, wp->config->chroot); return -1; } if (!fpm_conf_is_dir(wp->config->chroot)) { zlog(ZLOG_ERROR, "[pool %s] the chroot path '%s' does not exist or is not a directory", wp->config->name, wp->config->chroot); return -1; } } /* chdir */ if (wp->config->chdir && *wp->config->chdir) { fpm_evaluate_full_path(&wp->config->chdir, wp, NULL, 0); if (*wp->config->chdir != '/') { zlog(ZLOG_ERROR, "[pool %s] the chdir path '%s' must start with a '/'", wp->config->name, wp->config->chdir); return -1; } if (wp->config->chroot) { char *buf; spprintf(&buf, 0, "%s/%s", wp->config->chroot, wp->config->chdir); if (!fpm_conf_is_dir(buf)) { zlog(ZLOG_ERROR, "[pool %s] the chdir path '%s' within the chroot path '%s' ('%s') does not exist or is not a directory", wp->config->name, wp->config->chdir, wp->config->chroot, buf); efree(buf); return -1; } efree(buf); } else { if (!fpm_conf_is_dir(wp->config->chdir)) { zlog(ZLOG_ERROR, "[pool %s] the chdir path '%s' does not exist or is not a directory", wp->config->name, wp->config->chdir); return -1; } } } /* security.limit_extensions */ if (!wp->config->security_limit_extensions) { wp->config->security_limit_extensions = strdup(".php .phar"); } if (*wp->config->security_limit_extensions) { int nb_ext; char *ext; char *security_limit_extensions; char *limit_extensions; /* strdup because strtok(3) alters the string it parses */ security_limit_extensions = strdup(wp->config->security_limit_extensions); limit_extensions = security_limit_extensions; nb_ext = 0; /* find the number of extensions */ while (strtok(limit_extensions, " \t")) { limit_extensions = NULL; nb_ext++; } free(security_limit_extensions); /* if something found */ if (nb_ext > 0) { /* malloc the extension array */ wp->limit_extensions = malloc(sizeof(char *) * (nb_ext + 1)); if (!wp->limit_extensions) { zlog(ZLOG_ERROR, "[pool %s] unable to malloc extensions array", wp->config->name); return -1; } /* strdup because strtok(3) alters the string it parses */ security_limit_extensions = strdup(wp->config->security_limit_extensions); limit_extensions = security_limit_extensions; nb_ext = 0; /* parse the string and save the extension in the array */ while ((ext = strtok(limit_extensions, " \t"))) { limit_extensions = NULL; wp->limit_extensions[nb_ext++] = strdup(ext); } /* end the array with NULL in order to parse it */ wp->limit_extensions[nb_ext] = NULL; free(security_limit_extensions); } } /* env[], php_value[], php_admin_values[] */ if (!wp->config->chroot) { struct key_value_s *kv; char *options[] = FPM_PHP_INI_TO_EXPAND; char **p; for (kv = wp->config->php_values; kv; kv = kv->next) { for (p = options; *p; p++) { if (!strcasecmp(kv->key, *p)) { fpm_evaluate_full_path(&kv->value, wp, NULL, 0); } } } for (kv = wp->config->php_admin_values; kv; kv = kv->next) { if (!strcasecmp(kv->key, "error_log") && !strcasecmp(kv->value, "syslog")) { continue; } for (p = options; *p; p++) { if (!strcasecmp(kv->key, *p)) { fpm_evaluate_full_path(&kv->value, wp, NULL, 0); } } } } } /* 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; } /* }}} */ int fpm_conf_unlink_pid() /* {{{ */ { if (fpm_global_config.pid_file) { if (0 > unlink(fpm_global_config.pid_file)) { zlog(ZLOG_SYSERROR, "Unable to remove the PID file (%s).", fpm_global_config.pid_file); return -1; } } return 0; } /* }}} */ int fpm_conf_write_pid() /* {{{ */ { int fd; if (fpm_global_config.pid_file) { char buf[64]; int len; unlink(fpm_global_config.pid_file); fd = creat(fpm_global_config.pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { zlog(ZLOG_SYSERROR, "Unable to create the PID file (%s).", fpm_global_config.pid_file); return -1; } len = sprintf(buf, "%d", (int) fpm_globals.parent_pid); if (len != write(fd, buf, len)) { zlog(ZLOG_SYSERROR, "Unable to write to the PID file."); close(fd); return -1; } close(fd); } return 0; } /* }}} */ static int fpm_conf_post_process(int force_daemon TSRMLS_DC) /* {{{ */ { struct fpm_worker_pool_s *wp; if (fpm_global_config.pid_file) { fpm_evaluate_full_path(&fpm_global_config.pid_file, NULL, PHP_LOCALSTATEDIR, 0); } if (force_daemon >= 0) { /* forced from command line options */ fpm_global_config.daemonize = force_daemon; } fpm_globals.log_level = fpm_global_config.log_level; zlog_set_level(fpm_globals.log_level); if (fpm_global_config.process_max < 0) { zlog(ZLOG_ERROR, "process_max can't be negative"); 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"); } #ifdef HAVE_SYSTEMD if (0 > fpm_systemd_conf()) { return -1; } #endif #ifdef HAVE_SYSLOG_H if (!fpm_global_config.syslog_ident) { fpm_global_config.syslog_ident = strdup("php-fpm"); } if (fpm_global_config.syslog_facility < 0) { fpm_global_config.syslog_facility = LOG_DAEMON; } if (strcasecmp(fpm_global_config.error_log, "syslog") != 0) #endif { fpm_evaluate_full_path(&fpm_global_config.error_log, NULL, PHP_LOCALSTATEDIR, 0); } if (0 > fpm_stdio_open_error_log(0)) { return -1; } if (0 > fpm_event_pre_init(fpm_global_config.events_mechanism)) { return -1; } if (0 > fpm_conf_process_all_pools()) { return -1; } if (0 > fpm_log_open(0)) { return -1; } for (wp = fpm_worker_all_pools; wp; wp = wp->next) { if (!wp->config->access_log || !*wp->config->access_log) { continue; } if (0 > fpm_log_write(wp->config->access_format TSRMLS_CC)) { zlog(ZLOG_ERROR, "[pool %s] wrong format for access.format '%s'", wp->config->name, wp->config->access_format); return -1; } } return 0; } /* }}} */ static void fpm_conf_cleanup(int which, void *arg) /* {{{ */ { free(fpm_global_config.pid_file); free(fpm_global_config.error_log); free(fpm_global_config.events_mechanism); fpm_global_config.pid_file = 0; fpm_global_config.error_log = 0; #ifdef HAVE_SYSLOG_H free(fpm_global_config.syslog_ident); fpm_global_config.syslog_ident = 0; #endif free(fpm_globals.config); } /* }}} */ static void fpm_conf_ini_parser_include(char *inc, void *arg TSRMLS_DC) /* {{{ */ { char *filename; int *error = (int *)arg;; #ifdef HAVE_GLOB glob_t g; #endif int i; if (!inc || !arg) return; if (*error) return; /* We got already an error. Switch to the end. */ spprintf(&filename, 0, "%s", ini_filename); #ifdef HAVE_GLOB { g.gl_offs = 0; if ((i = glob(inc, GLOB_ERR | GLOB_MARK, NULL, &g)) != 0) { #ifdef GLOB_NOMATCH if (i == GLOB_NOMATCH) { zlog(ZLOG_WARNING, "Nothing matches the include pattern '%s' from %s at line %d.", inc, filename, ini_lineno); efree(filename); return; } #endif /* GLOB_NOMATCH */ zlog(ZLOG_ERROR, "Unable to globalize '%s' (ret=%d) from %s at line %d.", inc, i, filename, ini_lineno); *error = 1; efree(filename); return; } for (i = 0; i < g.gl_pathc; i++) { int len = strlen(g.gl_pathv[i]); if (len < 1) continue; if (g.gl_pathv[i][len - 1] == '/') continue; /* don't parse directories */ if (0 > fpm_conf_load_ini_file(g.gl_pathv[i] TSRMLS_CC)) { zlog(ZLOG_ERROR, "Unable to include %s from %s at line %d", g.gl_pathv[i], filename, ini_lineno); *error = 1; efree(filename); return; } } globfree(&g); } #else /* HAVE_GLOB */ if (0 > fpm_conf_load_ini_file(inc TSRMLS_CC)) { zlog(ZLOG_ERROR, "Unable to include %s from %s at line %d", inc, filename, ini_lineno); *error = 1; efree(filename); return; } #endif /* HAVE_GLOB */ efree(filename); } /* }}} */ static void fpm_conf_ini_parser_section(zval *section, void *arg TSRMLS_DC) /* {{{ */ { struct fpm_worker_pool_s *wp; struct fpm_worker_pool_config_s *config; int *error = (int *)arg; /* switch to global conf */ if (!strcasecmp(Z_STRVAL_P(section), "global")) { current_wp = NULL; return; } for (wp = fpm_worker_all_pools; wp; wp = wp->next) { if (!wp->config) continue; if (!wp->config->name) continue; if (!strcasecmp(wp->config->name, Z_STRVAL_P(section))) { /* Found a wp with the same name. Bring it back */ current_wp = wp; return; } } /* it's a new pool */ config = (struct fpm_worker_pool_config_s *)fpm_worker_pool_config_alloc(); if (!current_wp || !config) { zlog(ZLOG_ERROR, "[%s:%d] Unable to alloc a new WorkerPool for worker '%s'", ini_filename, ini_lineno, Z_STRVAL_P(section)); *error = 1; return; } config->name = strdup(Z_STRVAL_P(section)); if (!config->name) { zlog(ZLOG_ERROR, "[%s:%d] Unable to alloc memory for configuration name for worker '%s'", ini_filename, ini_lineno, Z_STRVAL_P(section)); *error = 1; return; } } /* }}} */ static void fpm_conf_ini_parser_entry(zval *name, zval *value, void *arg TSRMLS_DC) /* {{{ */ { struct ini_value_parser_s *parser; void *config = NULL; int *error = (int *)arg; if (!value) { zlog(ZLOG_ERROR, "[%s:%d] value is NULL for a ZEND_INI_PARSER_ENTRY", ini_filename, ini_lineno); *error = 1; return; } if (!strcmp(Z_STRVAL_P(name), "include")) { if (ini_include) { zlog(ZLOG_ERROR, "[%s:%d] two includes at the same time !", ini_filename, ini_lineno); *error = 1; return; } ini_include = strdup(Z_STRVAL_P(value)); return; } if (!current_wp) { /* we are in the global section */ parser = ini_fpm_global_options; config = &fpm_global_config; } else { parser = ini_fpm_pool_options; config = current_wp->config; } for (; parser->name; parser++) { if (!strcasecmp(parser->name, Z_STRVAL_P(name))) { char *ret; if (!parser->parser) { zlog(ZLOG_ERROR, "[%s:%d] the parser for entry '%s' is not defined", ini_filename, ini_lineno, parser->name); *error = 1; return; } ret = parser->parser(value, &config, parser->offset); if (ret) { zlog(ZLOG_ERROR, "[%s:%d] unable to parse value for entry '%s': %s", ini_filename, ini_lineno, parser->name, ret); *error = 1; return; } /* all is good ! */ return; } } /* nothing has been found if we got here */ zlog(ZLOG_ERROR, "[%s:%d] unknown entry '%s'", ini_filename, ini_lineno, Z_STRVAL_P(name)); *error = 1; } /* }}} */ static void fpm_conf_ini_parser_array(zval *name, zval *key, zval *value, void *arg TSRMLS_DC) /* {{{ */ { int *error = (int *)arg; char *err = NULL; void *config; if (!Z_STRVAL_P(key) || !Z_STRVAL_P(value) || !*Z_STRVAL_P(key)) { zlog(ZLOG_ERROR, "[%s:%d] Misspelled array ?", ini_filename, ini_lineno); *error = 1; return; } if (!current_wp || !current_wp->config) { zlog(ZLOG_ERROR, "[%s:%d] Array are not allowed in the global section", ini_filename, ini_lineno); *error = 1; return; } if (!strcmp("env", Z_STRVAL_P(name))) { if (!*Z_STRVAL_P(value)) { zlog(ZLOG_ERROR, "[%s:%d] empty value", ini_filename, ini_lineno); *error = 1; return; } config = (char *)current_wp->config + WPO(env); err = fpm_conf_set_array(key, value, &config, 0); } else if (!strcmp("php_value", Z_STRVAL_P(name))) { config = (char *)current_wp->config + WPO(php_values); err = fpm_conf_set_array(key, value, &config, 0); } else if (!strcmp("php_admin_value", Z_STRVAL_P(name))) { config = (char *)current_wp->config + WPO(php_admin_values); err = fpm_conf_set_array(key, value, &config, 0); } else if (!strcmp("php_flag", Z_STRVAL_P(name))) { config = (char *)current_wp->config + WPO(php_values); err = fpm_conf_set_array(key, value, &config, 1); } else if (!strcmp("php_admin_flag", Z_STRVAL_P(name))) { config = (char *)current_wp->config + WPO(php_admin_values); err = fpm_conf_set_array(key, value, &config, 1); } else { zlog(ZLOG_ERROR, "[%s:%d] unknown directive '%s'", ini_filename, ini_lineno, Z_STRVAL_P(name)); *error = 1; return; } if (err) { zlog(ZLOG_ERROR, "[%s:%d] error while parsing '%s[%s]' : %s", ini_filename, ini_lineno, Z_STRVAL_P(name), Z_STRVAL_P(key), err); *error = 1; return; } } /* }}} */ static void fpm_conf_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg TSRMLS_DC) /* {{{ */ { int *error; if (!arg1 || !arg) return; error = (int *)arg; if (*error) return; /* We got already an error. Switch to the end. */ switch(callback_type) { case ZEND_INI_PARSER_ENTRY: fpm_conf_ini_parser_entry(arg1, arg2, error TSRMLS_CC); break;; case ZEND_INI_PARSER_SECTION: fpm_conf_ini_parser_section(arg1, error TSRMLS_CC); break;; case ZEND_INI_PARSER_POP_ENTRY: fpm_conf_ini_parser_array(arg1, arg3, arg2, error TSRMLS_CC); break;; default: zlog(ZLOG_ERROR, "[%s:%d] Unknown INI syntax", ini_filename, ini_lineno); *error = 1; break;; } } /* }}} */ int fpm_conf_load_ini_file(char *filename TSRMLS_DC) /* {{{ */ { int error = 0; char buf[1024+1]; int fd, n; int nb_read = 1; char c = '*'; int ret = 1; if (!filename || !filename[0]) { zlog(ZLOG_ERROR, "configuration filename is empty"); return -1; } fd = open(filename, O_RDONLY, 0); if (fd < 0) { zlog(ZLOG_SYSERROR, "failed to open configuration file '%s'", filename); return -1; } if (ini_recursion++ > 4) { zlog(ZLOG_ERROR, "failed to include more than 5 files recusively"); close(fd); return -1; } ini_lineno = 0; while (nb_read > 0) { int tmp; memset(buf, 0, sizeof(char) * (1024 + 1)); for (n = 0; n < 1024 && (nb_read = read(fd, &c, sizeof(char))) == sizeof(char) && c != '\n'; n++) { buf[n] = c; } buf[n++] = '\n'; ini_lineno++; ini_filename = filename; tmp = zend_parse_ini_string(buf, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t)fpm_conf_ini_parser, &error TSRMLS_CC); ini_filename = filename; if (error || tmp == FAILURE) { if (ini_include) free(ini_include); ini_recursion--; close(fd); return -1; } if (ini_include) { char *tmp = ini_include; ini_include = NULL; fpm_evaluate_full_path(&tmp, NULL, NULL, 0); fpm_conf_ini_parser_include(tmp, &error TSRMLS_CC); if (error) { free(tmp); ini_recursion--; close(fd); return -1; } free(tmp); } } ini_recursion--; close(fd); return ret; } /* }}} */ static void fpm_conf_dump() /* {{{ */ { struct fpm_worker_pool_s *wp; /* * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in */ zlog(ZLOG_NOTICE, "[General]"); zlog(ZLOG_NOTICE, "\tpid = %s", STR2STR(fpm_global_config.pid_file)); zlog(ZLOG_NOTICE, "\terror_log = %s", STR2STR(fpm_global_config.error_log)); #ifdef HAVE_SYSLOG_H zlog(ZLOG_NOTICE, "\tsyslog.ident = %s", STR2STR(fpm_global_config.syslog_ident)); zlog(ZLOG_NOTICE, "\tsyslog.facility = %d", fpm_global_config.syslog_facility); /* FIXME: convert to string */ #endif zlog(ZLOG_NOTICE, "\tlog_level = %s", zlog_get_level_name(fpm_globals.log_level)); zlog(ZLOG_NOTICE, "\temergency_restart_interval = %ds", fpm_global_config.emergency_restart_interval); 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); zlog(ZLOG_NOTICE, "\tevents.mechanism = %s", fpm_event_machanism_name()); #ifdef HAVE_SYSTEMD zlog(ZLOG_NOTICE, "\tsystemd_interval = %ds", fpm_global_config.systemd_interval/1000); #endif zlog(ZLOG_NOTICE, " "); for (wp = fpm_worker_all_pools; wp; wp = wp->next) { struct key_value_s *kv; if (!wp->config) continue; zlog(ZLOG_NOTICE, "[%s]", STR2STR(wp->config->name)); zlog(ZLOG_NOTICE, "\tprefix = %s", STR2STR(wp->config->prefix)); zlog(ZLOG_NOTICE, "\tuser = %s", STR2STR(wp->config->user)); zlog(ZLOG_NOTICE, "\tgroup = %s", STR2STR(wp->config->group)); zlog(ZLOG_NOTICE, "\tlisten = %s", STR2STR(wp->config->listen_address)); zlog(ZLOG_NOTICE, "\tlisten.backlog = %d", wp->config->listen_backlog); zlog(ZLOG_NOTICE, "\tlisten.owner = %s", STR2STR(wp->config->listen_owner)); 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); zlog(ZLOG_NOTICE, "\tpm.min_spare_servers = %d", wp->config->pm_min_spare_servers); zlog(ZLOG_NOTICE, "\tpm.max_spare_servers = %d", wp->config->pm_max_spare_servers); zlog(ZLOG_NOTICE, "\tpm.process_idle_timeout = %d", wp->config->pm_process_idle_timeout); zlog(ZLOG_NOTICE, "\tpm.max_requests = %d", wp->config->pm_max_requests); zlog(ZLOG_NOTICE, "\tpm.status_path = %s", STR2STR(wp->config->pm_status_path)); zlog(ZLOG_NOTICE, "\tping.path = %s", STR2STR(wp->config->ping_path)); zlog(ZLOG_NOTICE, "\tping.response = %s", STR2STR(wp->config->ping_response)); zlog(ZLOG_NOTICE, "\taccess.log = %s", STR2STR(wp->config->access_log)); zlog(ZLOG_NOTICE, "\taccess.format = %s", STR2STR(wp->config->access_format)); zlog(ZLOG_NOTICE, "\tslowlog = %s", STR2STR(wp->config->slowlog)); zlog(ZLOG_NOTICE, "\trequest_slowlog_timeout = %ds", wp->config->request_slowlog_timeout); zlog(ZLOG_NOTICE, "\trequest_terminate_timeout = %ds", wp->config->request_terminate_timeout); zlog(ZLOG_NOTICE, "\trlimit_files = %d", wp->config->rlimit_files); zlog(ZLOG_NOTICE, "\trlimit_core = %d", wp->config->rlimit_core); zlog(ZLOG_NOTICE, "\tchroot = %s", STR2STR(wp->config->chroot)); zlog(ZLOG_NOTICE, "\tchdir = %s", STR2STR(wp->config->chdir)); zlog(ZLOG_NOTICE, "\tcatch_workers_output = %s", BOOL2STR(wp->config->catch_workers_output)); zlog(ZLOG_NOTICE, "\tclear_env = %s", BOOL2STR(wp->config->clear_env)); zlog(ZLOG_NOTICE, "\tsecurity.limit_extensions = %s", wp->config->security_limit_extensions); for (kv = wp->config->env; kv; kv = kv->next) { zlog(ZLOG_NOTICE, "\tenv[%s] = %s", kv->key, kv->value); } for (kv = wp->config->php_values; kv; kv = kv->next) { zlog(ZLOG_NOTICE, "\tphp_value[%s] = %s", kv->key, kv->value); } for (kv = wp->config->php_admin_values; kv; kv = kv->next) { zlog(ZLOG_NOTICE, "\tphp_admin_value[%s] = %s", kv->key, kv->value); } zlog(ZLOG_NOTICE, " "); } } /* }}} */ int fpm_conf_init_main(int test_conf, int force_daemon) /* {{{ */ { int ret; TSRMLS_FETCH(); if (fpm_globals.prefix && *fpm_globals.prefix) { if (!fpm_conf_is_dir(fpm_globals.prefix)) { zlog(ZLOG_ERROR, "the global prefix '%s' does not exist or is not a directory", fpm_globals.prefix); return -1; } } if (fpm_globals.pid && *fpm_globals.pid) { fpm_global_config.pid_file = strdup(fpm_globals.pid); } if (fpm_globals.config == NULL) { char *tmp; if (fpm_globals.prefix == NULL) { spprintf(&tmp, 0, "%s/php-fpm.conf", PHP_SYSCONFDIR); } else { spprintf(&tmp, 0, "%s/etc/php-fpm.conf", fpm_globals.prefix); } if (!tmp) { zlog(ZLOG_SYSERROR, "spprintf() failed (tmp for fpm_globals.config)"); return -1; } fpm_globals.config = strdup(tmp); efree(tmp); if (!fpm_globals.config) { zlog(ZLOG_SYSERROR, "spprintf() failed (fpm_globals.config)"); return -1; } } ret = fpm_conf_load_ini_file(fpm_globals.config TSRMLS_CC); if (0 > ret) { zlog(ZLOG_ERROR, "failed to load configuration file '%s'", fpm_globals.config); return -1; } if (0 > fpm_conf_post_process(force_daemon TSRMLS_CC)) { zlog(ZLOG_ERROR, "failed to post process the configuration"); return -1; } if (test_conf) { if (test_conf > 1) { fpm_conf_dump(); } zlog(ZLOG_NOTICE, "configuration file %s test is successful\n", fpm_globals.config); fpm_globals.test_successful = 1; return -1; } if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_conf_cleanup, 0)) { return -1; } return 0; } /* }}} */