Пример #1
0
static int fpm_conf_post_process(TSRMLS_D) /* {{{ */
{
	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);
	}

	fpm_globals.log_level = fpm_global_config.log_level;

	if (fpm_global_config.process_max < 0) {
		zlog(ZLOG_ERROR, "process_max can't be negative");
		return -1;
	}

	if (!fpm_global_config.error_log) {
		fpm_global_config.error_log = strdup("log/php-fpm.log");
	}

#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_log_open(0)) {
		return -1;
	}

	if (0 > fpm_conf_process_all_pools()) {
		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;
}
Пример #2
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;
}
Пример #3
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) {
			size_t 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;
			size_t 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;
}
Пример #4
0
int fpm_conf_load_ini_file(char *filename) /* {{{ */
{
	int error = 0;
	char *buf = NULL, *newbuf = NULL;
	int bufsize = 0;
	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;
		ini_lineno++;
		ini_filename = filename;
		for (n = 0; (nb_read = read(fd, &c, sizeof(char))) == sizeof(char) && c != '\n'; n++) {
			if (n == bufsize) {
				bufsize += 1024;
				newbuf = (char*) realloc(buf, sizeof(char) * (bufsize + 2));
				if (newbuf == NULL) {
					ini_recursion--;
					close(fd);
					free(buf);
					return -1;
				}
				buf = newbuf;
			}

			buf[n] = c;
		}
		if (n == 0) {
			continue;
		}
		/* always append newline and null terminate */
		buf[n++] = '\n';
		buf[n] = '\0';
		tmp = zend_parse_ini_string(buf, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t)fpm_conf_ini_parser, &error);
		ini_filename = filename;
		if (error || tmp == FAILURE) {
			if (ini_include) free(ini_include);
			ini_recursion--;
			close(fd);
			free(buf);
			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);
			if (error) {
				free(tmp);
				ini_recursion--;
				close(fd);
				free(buf);
				return -1;
			}
			free(tmp);
		}
	}
	free(buf);

	ini_recursion--;
	close(fd);
	return ret;
}
Пример #5
0
static int fpm_conf_post_process(int force_daemon) /* {{{ */
{
	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)) {
			zlog(ZLOG_ERROR, "[pool %s] wrong format for access.format '%s'", wp->config->name, wp->config->access_format);
			return -1;
		}
	}

	return 0;
}
Пример #6
0
static int fpm_conf_process_all_pools() /* {{{ */
{
	struct fpm_worker_pool_s *wp;

	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;
			}
		}

		/* user */
		if (!wp->config->user) {
			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;
		}

		/* pm */
		if (wp->config->pm != PM_STYLE_STATIC && wp->config->pm != PM_STYLE_DYNAMIC) {
			zlog(ZLOG_ALERT, "[pool %s] the process manager is missing (static or dynamic)", 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_WARNING, "[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;
			}

		}

		/* 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");
			}
		}

		/* 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);
			}
		}

		/* 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");
		}

		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 ((ext = 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(security_limit_extensions, " \t"))) {
					security_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) {
				for (p = options; *p; p++) {
					if (!strcasecmp(kv->key, *p)) {
						fpm_evaluate_full_path(&kv->value, wp, NULL, 0);
					}
				}
			}
		}
	}
	return 0;
}