xref: /PHP-8.0/sapi/fpm/fpm/fpm_conf.c (revision 1c5844aa)
1 	/* (c) 2007,2008 Andrei Nigmatulin */
2 
3 #include "fpm_config.h"
4 
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stddef.h>
11 #include <string.h>
12 #include <inttypes.h>
13 #ifdef HAVE_GLOB
14 # include <glob.h>
15 #endif
16 
17 #include <stdio.h>
18 #include <unistd.h>
19 
20 #include "php.h"
21 #include "zend_ini_scanner.h"
22 #include "zend_globals.h"
23 #include "zend_stream.h"
24 #include "php_syslog.h"
25 
26 #include "fpm.h"
27 #include "fpm_conf.h"
28 #include "fpm_stdio.h"
29 #include "fpm_worker_pool.h"
30 #include "fpm_cleanup.h"
31 #include "fpm_php.h"
32 #include "fpm_sockets.h"
33 #include "fpm_shm.h"
34 #include "fpm_status.h"
35 #include "fpm_log.h"
36 #include "fpm_events.h"
37 #include "zlog.h"
38 #ifdef HAVE_SYSTEMD
39 #include "fpm_systemd.h"
40 #endif
41 
42 
43 #define STR2STR(a) (a ? a : "undefined")
44 #define BOOL2STR(a) (a ? "yes" : "no")
45 #define GO(field) offsetof(struct fpm_global_config_s, field)
46 #define WPO(field) offsetof(struct fpm_worker_pool_config_s, field)
47 
48 static int fpm_conf_load_ini_file(char *filename);
49 static char *fpm_conf_set_integer(zval *value, void **config, intptr_t offset);
50 #if 0 /* not used for now */
51 static char *fpm_conf_set_long(zval *value, void **config, intptr_t offset);
52 #endif
53 static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset);
54 static char *fpm_conf_set_boolean(zval *value, void **config, intptr_t offset);
55 static char *fpm_conf_set_string(zval *value, void **config, intptr_t offset);
56 static char *fpm_conf_set_log_level(zval *value, void **config, intptr_t offset);
57 static char *fpm_conf_set_rlimit_core(zval *value, void **config, intptr_t offset);
58 static char *fpm_conf_set_pm(zval *value, void **config, intptr_t offset);
59 #ifdef HAVE_SYSLOG_H
60 static char *fpm_conf_set_syslog_facility(zval *value, void **config, intptr_t offset);
61 #endif
62 
63 struct fpm_global_config_s fpm_global_config = {
64 	.daemonize = 1,
65 #ifdef HAVE_SYSLOG_H
66 	.syslog_facility = -1,
67 #endif
68 	.process_max = 0,
69 	.process_priority = 64, /* 64 means unset */
70 #ifdef HAVE_SYSTEMD
71 	.systemd_watchdog = 0,
72 	.systemd_interval = -1, /* -1 means not set */
73 #endif
74 	.log_buffering = ZLOG_DEFAULT_BUFFERING,
75 	.log_limit = ZLOG_DEFAULT_LIMIT
76 };
77 static struct fpm_worker_pool_s *current_wp = NULL;
78 static int ini_recursion = 0;
79 static char *ini_filename = NULL;
80 static int ini_lineno = 0;
81 static char *ini_include = NULL;
82 
83 /*
84  * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in
85  */
86 static struct ini_value_parser_s ini_fpm_global_options[] = {
87 	{ "pid",                         &fpm_conf_set_string,          GO(pid_file) },
88 	{ "error_log",                   &fpm_conf_set_string,          GO(error_log) },
89 #ifdef HAVE_SYSLOG_H
90 	{ "syslog.ident",                &fpm_conf_set_string,          GO(syslog_ident) },
91 	{ "syslog.facility",             &fpm_conf_set_syslog_facility, GO(syslog_facility) },
92 #endif
93 	{ "log_buffering",               &fpm_conf_set_boolean,         GO(log_buffering) },
94 	{ "log_level",                   &fpm_conf_set_log_level,       GO(log_level) },
95 	{ "log_limit",                   &fpm_conf_set_integer,         GO(log_limit) },
96 	{ "emergency_restart_threshold", &fpm_conf_set_integer,         GO(emergency_restart_threshold) },
97 	{ "emergency_restart_interval",  &fpm_conf_set_time,            GO(emergency_restart_interval) },
98 	{ "process_control_timeout",     &fpm_conf_set_time,            GO(process_control_timeout) },
99 	{ "process.max",                 &fpm_conf_set_integer,         GO(process_max) },
100 	{ "process.priority",            &fpm_conf_set_integer,         GO(process_priority) },
101 	{ "daemonize",                   &fpm_conf_set_boolean,         GO(daemonize) },
102 	{ "rlimit_files",                &fpm_conf_set_integer,         GO(rlimit_files) },
103 	{ "rlimit_core",                 &fpm_conf_set_rlimit_core,     GO(rlimit_core) },
104 	{ "events.mechanism",            &fpm_conf_set_string,          GO(events_mechanism) },
105 #ifdef HAVE_SYSTEMD
106 	{ "systemd_interval",            &fpm_conf_set_time,            GO(systemd_interval) },
107 #endif
108 	{ 0, 0, 0 }
109 };
110 
111 /*
112  * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in
113  */
114 static struct ini_value_parser_s ini_fpm_pool_options[] = {
115 	{ "prefix",                    &fpm_conf_set_string,      WPO(prefix) },
116 	{ "user",                      &fpm_conf_set_string,      WPO(user) },
117 	{ "group",                     &fpm_conf_set_string,      WPO(group) },
118 	{ "listen",                    &fpm_conf_set_string,      WPO(listen_address) },
119 	{ "listen.backlog",            &fpm_conf_set_integer,     WPO(listen_backlog) },
120 #ifdef HAVE_FPM_ACL
121 	{ "listen.acl_users",          &fpm_conf_set_string,      WPO(listen_acl_users) },
122 	{ "listen.acl_groups",         &fpm_conf_set_string,      WPO(listen_acl_groups) },
123 #endif
124 	{ "listen.owner",              &fpm_conf_set_string,      WPO(listen_owner) },
125 	{ "listen.group",              &fpm_conf_set_string,      WPO(listen_group) },
126 	{ "listen.mode",               &fpm_conf_set_string,      WPO(listen_mode) },
127 	{ "listen.allowed_clients",    &fpm_conf_set_string,      WPO(listen_allowed_clients) },
128 	{ "process.priority",          &fpm_conf_set_integer,     WPO(process_priority) },
129 	{ "process.dumpable",          &fpm_conf_set_boolean,     WPO(process_dumpable) },
130 	{ "pm",                        &fpm_conf_set_pm,          WPO(pm) },
131 	{ "pm.max_children",           &fpm_conf_set_integer,     WPO(pm_max_children) },
132 	{ "pm.start_servers",          &fpm_conf_set_integer,     WPO(pm_start_servers) },
133 	{ "pm.min_spare_servers",      &fpm_conf_set_integer,     WPO(pm_min_spare_servers) },
134 	{ "pm.max_spare_servers",      &fpm_conf_set_integer,     WPO(pm_max_spare_servers) },
135 	{ "pm.process_idle_timeout",   &fpm_conf_set_time,        WPO(pm_process_idle_timeout) },
136 	{ "pm.max_requests",           &fpm_conf_set_integer,     WPO(pm_max_requests) },
137 	{ "pm.status_path",            &fpm_conf_set_string,      WPO(pm_status_path) },
138 	{ "pm.status_listen",          &fpm_conf_set_string,      WPO(pm_status_listen) },
139 	{ "ping.path",                 &fpm_conf_set_string,      WPO(ping_path) },
140 	{ "ping.response",             &fpm_conf_set_string,      WPO(ping_response) },
141 	{ "access.log",                &fpm_conf_set_string,      WPO(access_log) },
142 	{ "access.format",             &fpm_conf_set_string,      WPO(access_format) },
143 	{ "slowlog",                   &fpm_conf_set_string,      WPO(slowlog) },
144 	{ "request_slowlog_timeout",   &fpm_conf_set_time,        WPO(request_slowlog_timeout) },
145 	{ "request_slowlog_trace_depth", &fpm_conf_set_integer,     WPO(request_slowlog_trace_depth) },
146 	{ "request_terminate_timeout", &fpm_conf_set_time,        WPO(request_terminate_timeout) },
147 	{ "request_terminate_timeout_track_finished", &fpm_conf_set_boolean, WPO(request_terminate_timeout_track_finished) },
148 	{ "rlimit_files",              &fpm_conf_set_integer,     WPO(rlimit_files) },
149 	{ "rlimit_core",               &fpm_conf_set_rlimit_core, WPO(rlimit_core) },
150 	{ "chroot",                    &fpm_conf_set_string,      WPO(chroot) },
151 	{ "chdir",                     &fpm_conf_set_string,      WPO(chdir) },
152 	{ "catch_workers_output",      &fpm_conf_set_boolean,     WPO(catch_workers_output) },
153 	{ "decorate_workers_output",   &fpm_conf_set_boolean,     WPO(decorate_workers_output) },
154 	{ "clear_env",                 &fpm_conf_set_boolean,     WPO(clear_env) },
155 	{ "security.limit_extensions", &fpm_conf_set_string,      WPO(security_limit_extensions) },
156 #ifdef HAVE_APPARMOR
157 	{ "apparmor_hat",              &fpm_conf_set_string,      WPO(apparmor_hat) },
158 #endif
159 	{ 0, 0, 0 }
160 };
161 
fpm_conf_is_dir(char * path)162 static int fpm_conf_is_dir(char *path) /* {{{ */
163 {
164 	struct stat sb;
165 
166 	if (stat(path, &sb) != 0) {
167 		return 0;
168 	}
169 
170 	return (sb.st_mode & S_IFMT) == S_IFDIR;
171 }
172 /* }}} */
173 
174 /*
175  * Expands the '$pool' token in a dynamically allocated string
176  */
fpm_conf_expand_pool_name(char ** value)177 static int fpm_conf_expand_pool_name(char **value) {
178 	char *token;
179 
180 	if (!value || !*value) {
181 		return 0;
182 	}
183 
184 	while (*value && (token = strstr(*value, "$pool"))) {
185 		char *buf;
186 		char *p2 = token + strlen("$pool");
187 
188 		/* If we are not in a pool, we cannot expand this name now */
189 		if (!current_wp || !current_wp->config  || !current_wp->config->name) {
190 			return -1;
191 		}
192 
193 		/* "aaa$poolbbb" becomes "aaa\0oolbbb" */
194 		token[0] = '\0';
195 
196 		/* Build a brand new string with the expanded token */
197 		spprintf(&buf, 0, "%s%s%s", *value, current_wp->config->name, p2);
198 
199 		/* Free the previous value and save the new one */
200 		free(*value);
201 		*value = strdup(buf);
202 		efree(buf);
203 	}
204 
205 	return 0;
206 }
207 
fpm_conf_set_boolean(zval * value,void ** config,intptr_t offset)208 static char *fpm_conf_set_boolean(zval *value, void **config, intptr_t offset) /* {{{ */
209 {
210 	char *val = Z_STRVAL_P(value);
211 	long value_y = !strcasecmp(val, "1");
212 	long value_n = !strcasecmp(val, "");
213 
214 	if (!value_y && !value_n) {
215 		return "invalid boolean value";
216 	}
217 
218 	* (int *) ((char *) *config + offset) = value_y ? 1 : 0;
219 	return NULL;
220 }
221 /* }}} */
222 
fpm_conf_set_string(zval * value,void ** config,intptr_t offset)223 static char *fpm_conf_set_string(zval *value, void **config, intptr_t offset) /* {{{ */
224 {
225 	char **config_val = (char **) ((char *) *config + offset);
226 
227 	if (!config_val) {
228 		return "internal error: NULL value";
229 	}
230 
231 	/* Check if there is a previous value to deallocate */
232 	if (*config_val) {
233 		free(*config_val);
234 	}
235 
236 	*config_val = strdup(Z_STRVAL_P(value));
237 	if (!*config_val) {
238 		return "fpm_conf_set_string(): strdup() failed";
239 	}
240 	if (fpm_conf_expand_pool_name(config_val) == -1) {
241 		return "Can't use '$pool' when the pool is not defined";
242 	}
243 
244 	return NULL;
245 }
246 /* }}} */
247 
fpm_conf_set_integer(zval * value,void ** config,intptr_t offset)248 static char *fpm_conf_set_integer(zval *value, void **config, intptr_t offset) /* {{{ */
249 {
250 	char *val = Z_STRVAL_P(value);
251 	char *p;
252 
253 	/* we don't use strtol because we don't want to allow negative values */
254 	for (p = val; *p; p++) {
255 		if (p == val && *p == '-') continue;
256 		if (*p < '0' || *p > '9') {
257 			return "is not a valid number (greater or equal than zero)";
258 		}
259 	}
260 	* (int *) ((char *) *config + offset) = atoi(val);
261 	return NULL;
262 }
263 /* }}} */
264 
265 #if 0 /* not used for now */
266 static char *fpm_conf_set_long(zval *value, void **config, intptr_t offset) /* {{{ */
267 {
268 	char *val = Z_STRVAL_P(value);
269 	char *p;
270 
271 	for (p = val; *p; p++) {
272 		if ( p == val && *p == '-' ) continue;
273 		if (*p < '0' || *p > '9') {
274 			return "is not a valid number (greater or equal than zero)";
275 		}
276 	}
277 	* (long int *) ((char *) *config + offset) = atol(val);
278 	return NULL;
279 }
280 /* }}} */
281 #endif
282 
fpm_conf_set_time(zval * value,void ** config,intptr_t offset)283 static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset) /* {{{ */
284 {
285 	char *val = Z_STRVAL_P(value);
286 	int len = strlen(val);
287 	char suffix;
288 	int seconds;
289 	if (!len) {
290 		return "invalid time value";
291 	}
292 
293 	suffix = val[len-1];
294 	switch (suffix) {
295 		case 'm' :
296 			val[len-1] = '\0';
297 			seconds = 60 * atoi(val);
298 			break;
299 		case 'h' :
300 			val[len-1] = '\0';
301 			seconds = 60 * 60 * atoi(val);
302 			break;
303 		case 'd' :
304 			val[len-1] = '\0';
305 			seconds = 24 * 60 * 60 * atoi(val);
306 			break;
307 		case 's' : /* s is the default suffix */
308 			val[len-1] = '\0';
309 			suffix = '0';
310 		default :
311 			if (suffix < '0' || suffix > '9') {
312 				return "unknown suffix used in time value";
313 			}
314 			seconds = atoi(val);
315 			break;
316 	}
317 
318 	* (int *) ((char *) *config + offset) = seconds;
319 	return NULL;
320 }
321 /* }}} */
322 
fpm_conf_set_log_level(zval * value,void ** config,intptr_t offset)323 static char *fpm_conf_set_log_level(zval *value, void **config, intptr_t offset) /* {{{ */
324 {
325 	char *val = Z_STRVAL_P(value);
326 	int log_level;
327 
328 	if (!strcasecmp(val, "debug")) {
329 		log_level = ZLOG_DEBUG;
330 	} else if (!strcasecmp(val, "notice")) {
331 		log_level = ZLOG_NOTICE;
332 	} else if (!strcasecmp(val, "warning") || !strcasecmp(val, "warn")) {
333 		log_level = ZLOG_WARNING;
334 	} else if (!strcasecmp(val, "error")) {
335 		log_level = ZLOG_ERROR;
336 	} else if (!strcasecmp(val, "alert")) {
337 		log_level = ZLOG_ALERT;
338 	} else {
339 		return "invalid value for 'log_level'";
340 	}
341 
342 	* (int *) ((char *) *config + offset) = log_level;
343 	return NULL;
344 }
345 /* }}} */
346 
347 #ifdef HAVE_SYSLOG_H
fpm_conf_set_syslog_facility(zval * value,void ** config,intptr_t offset)348 static char *fpm_conf_set_syslog_facility(zval *value, void **config, intptr_t offset) /* {{{ */
349 {
350 	char *val = Z_STRVAL_P(value);
351 	int *conf = (int *) ((char *) *config + offset);
352 
353 #ifdef LOG_AUTH
354 	if (!strcasecmp(val, "AUTH")) {
355 		*conf = LOG_AUTH;
356 		return NULL;
357 	}
358 #endif
359 
360 #ifdef LOG_AUTHPRIV
361 	if (!strcasecmp(val, "AUTHPRIV")) {
362 		*conf = LOG_AUTHPRIV;
363 		return NULL;
364 	}
365 #endif
366 
367 #ifdef LOG_CRON
368 	if (!strcasecmp(val, "CRON")) {
369 		*conf = LOG_CRON;
370 		return NULL;
371 	}
372 #endif
373 
374 #ifdef LOG_DAEMON
375 	if (!strcasecmp(val, "DAEMON")) {
376 		*conf = LOG_DAEMON;
377 		return NULL;
378 	}
379 #endif
380 
381 #ifdef LOG_FTP
382 	if (!strcasecmp(val, "FTP")) {
383 		*conf = LOG_FTP;
384 		return NULL;
385 	}
386 #endif
387 
388 #ifdef LOG_KERN
389 	if (!strcasecmp(val, "KERN")) {
390 		*conf = LOG_KERN;
391 		return NULL;
392 	}
393 #endif
394 
395 #ifdef LOG_LPR
396 	if (!strcasecmp(val, "LPR")) {
397 		*conf = LOG_LPR;
398 		return NULL;
399 	}
400 #endif
401 
402 #ifdef LOG_MAIL
403 	if (!strcasecmp(val, "MAIL")) {
404 		*conf = LOG_MAIL;
405 		return NULL;
406 	}
407 #endif
408 
409 #ifdef LOG_NEWS
410 	if (!strcasecmp(val, "NEWS")) {
411 		*conf = LOG_NEWS;
412 		return NULL;
413 	}
414 #endif
415 
416 #ifdef LOG_SYSLOG
417 	if (!strcasecmp(val, "SYSLOG")) {
418 		*conf = LOG_SYSLOG;
419 		return NULL;
420 	}
421 #endif
422 
423 #ifdef LOG_USER
424 	if (!strcasecmp(val, "USER")) {
425 		*conf = LOG_USER;
426 		return NULL;
427 	}
428 #endif
429 
430 #ifdef LOG_UUCP
431 	if (!strcasecmp(val, "UUCP")) {
432 		*conf = LOG_UUCP;
433 		return NULL;
434 	}
435 #endif
436 
437 #ifdef LOG_LOCAL0
438 	if (!strcasecmp(val, "LOCAL0")) {
439 		*conf = LOG_LOCAL0;
440 		return NULL;
441 	}
442 #endif
443 
444 #ifdef LOG_LOCAL1
445 	if (!strcasecmp(val, "LOCAL1")) {
446 		*conf = LOG_LOCAL1;
447 		return NULL;
448 	}
449 #endif
450 
451 #ifdef LOG_LOCAL2
452 	if (!strcasecmp(val, "LOCAL2")) {
453 		*conf = LOG_LOCAL2;
454 		return NULL;
455 	}
456 #endif
457 
458 #ifdef LOG_LOCAL3
459 	if (!strcasecmp(val, "LOCAL3")) {
460 		*conf = LOG_LOCAL3;
461 		return NULL;
462 	}
463 #endif
464 
465 #ifdef LOG_LOCAL4
466 	if (!strcasecmp(val, "LOCAL4")) {
467 		*conf = LOG_LOCAL4;
468 		return NULL;
469 	}
470 #endif
471 
472 #ifdef LOG_LOCAL5
473 	if (!strcasecmp(val, "LOCAL5")) {
474 		*conf = LOG_LOCAL5;
475 		return NULL;
476 	}
477 #endif
478 
479 #ifdef LOG_LOCAL6
480 	if (!strcasecmp(val, "LOCAL6")) {
481 		*conf = LOG_LOCAL6;
482 		return NULL;
483 	}
484 #endif
485 
486 #ifdef LOG_LOCAL7
487 	if (!strcasecmp(val, "LOCAL7")) {
488 		*conf = LOG_LOCAL7;
489 		return NULL;
490 	}
491 #endif
492 
493 	return "invalid value";
494 }
495 /* }}} */
496 #endif
497 
fpm_conf_set_rlimit_core(zval * value,void ** config,intptr_t offset)498 static char *fpm_conf_set_rlimit_core(zval *value, void **config, intptr_t offset) /* {{{ */
499 {
500 	char *val = Z_STRVAL_P(value);
501 	int *ptr = (int *) ((char *) *config + offset);
502 
503 	if (!strcasecmp(val, "unlimited")) {
504 		*ptr = -1;
505 	} else {
506 		int int_value;
507 		void *subconf = &int_value;
508 		char *error;
509 
510 		error = fpm_conf_set_integer(value, &subconf, 0);
511 
512 		if (error) {
513 			return error;
514 		}
515 
516 		if (int_value < 0) {
517 			return "must be greater than zero or 'unlimited'";
518 		}
519 
520 		*ptr = int_value;
521 	}
522 
523 	return NULL;
524 }
525 /* }}} */
526 
fpm_conf_set_pm(zval * value,void ** config,intptr_t offset)527 static char *fpm_conf_set_pm(zval *value, void **config, intptr_t offset) /* {{{ */
528 {
529 	char *val = Z_STRVAL_P(value);
530 	struct fpm_worker_pool_config_s  *c = *config;
531 	if (!strcasecmp(val, "static")) {
532 		c->pm = PM_STYLE_STATIC;
533 	} else if (!strcasecmp(val, "dynamic")) {
534 		c->pm = PM_STYLE_DYNAMIC;
535 	} else if (!strcasecmp(val, "ondemand")) {
536 		c->pm = PM_STYLE_ONDEMAND;
537 	} else {
538 		return "invalid process manager (static, dynamic or ondemand)";
539 	}
540 	return NULL;
541 }
542 /* }}} */
543 
fpm_conf_set_array(zval * key,zval * value,void ** config,int convert_to_bool)544 static char *fpm_conf_set_array(zval *key, zval *value, void **config, int convert_to_bool) /* {{{ */
545 {
546 	struct key_value_s *kv;
547 	struct key_value_s ***parent = (struct key_value_s ***) config;
548 	int b;
549 	void *subconf = &b;
550 
551 	kv = malloc(sizeof(*kv));
552 
553 	if (!kv) {
554 		return "malloc() failed";
555 	}
556 
557 	memset(kv, 0, sizeof(*kv));
558 	kv->key = strdup(Z_STRVAL_P(key));
559 
560 	if (!kv->key) {
561 		free(kv);
562 		return "fpm_conf_set_array: strdup(key) failed";
563 	}
564 
565 	if (convert_to_bool) {
566 		char *err = fpm_conf_set_boolean(value, &subconf, 0);
567 		if (err) {
568 			free(kv->key);
569 			free(kv);
570 			return err;
571 		}
572 		kv->value = strdup(b ? "1" : "0");
573 	} else {
574 		kv->value = strdup(Z_STRVAL_P(value));
575 		if (fpm_conf_expand_pool_name(&kv->value) == -1) {
576 			free(kv->key);
577 			free(kv);
578 			return "Can't use '$pool' when the pool is not defined";
579 		}
580 	}
581 
582 	if (!kv->value) {
583 		free(kv->key);
584 		free(kv);
585 		return "fpm_conf_set_array: strdup(value) failed";
586 	}
587 
588 	kv->next = **parent;
589 	**parent = kv;
590 	return NULL;
591 }
592 /* }}} */
593 
fpm_worker_pool_config_alloc(void)594 static void *fpm_worker_pool_config_alloc(void)
595 {
596 	struct fpm_worker_pool_s *wp;
597 
598 	wp = fpm_worker_pool_alloc();
599 
600 	if (!wp) {
601 		return 0;
602 	}
603 
604 	wp->config = malloc(sizeof(struct fpm_worker_pool_config_s));
605 
606 	if (!wp->config) {
607 		fpm_worker_pool_free(wp);
608 		return 0;
609 	}
610 
611 	memset(wp->config, 0, sizeof(struct fpm_worker_pool_config_s));
612 	wp->config->listen_backlog = FPM_BACKLOG_DEFAULT;
613 	wp->config->pm_process_idle_timeout = 10; /* 10s by default */
614 	wp->config->process_priority = 64; /* 64 means unset */
615 	wp->config->process_dumpable = 0;
616 	wp->config->clear_env = 1;
617 	wp->config->decorate_workers_output = 1;
618 
619 	if (!fpm_worker_all_pools) {
620 		fpm_worker_all_pools = wp;
621 	} else {
622 		struct fpm_worker_pool_s *tmp = fpm_worker_all_pools;
623 		while (tmp) {
624 			if (!tmp->next) {
625 				tmp->next = wp;
626 				break;
627 			}
628 			tmp = tmp->next;
629 		}
630 	}
631 
632 	current_wp = wp;
633 	return wp->config;
634 }
635 
fpm_worker_pool_config_free(struct fpm_worker_pool_config_s * wpc)636 int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc) /* {{{ */
637 {
638 	struct key_value_s *kv, *kv_next;
639 
640 	free(wpc->name);
641 	free(wpc->prefix);
642 	free(wpc->user);
643 	free(wpc->group);
644 	free(wpc->listen_address);
645 	free(wpc->listen_owner);
646 	free(wpc->listen_group);
647 	free(wpc->listen_mode);
648 	free(wpc->listen_allowed_clients);
649 	free(wpc->pm_status_path);
650 	free(wpc->ping_path);
651 	free(wpc->ping_response);
652 	free(wpc->access_log);
653 	free(wpc->access_format);
654 	free(wpc->slowlog);
655 	free(wpc->chroot);
656 	free(wpc->chdir);
657 	free(wpc->security_limit_extensions);
658 #ifdef HAVE_APPARMOR
659 	free(wpc->apparmor_hat);
660 #endif
661 
662 	for (kv = wpc->php_values; kv; kv = kv_next) {
663 		kv_next = kv->next;
664 		free(kv->key);
665 		free(kv->value);
666 		free(kv);
667 	}
668 	for (kv = wpc->php_admin_values; kv; kv = kv_next) {
669 		kv_next = kv->next;
670 		free(kv->key);
671 		free(kv->value);
672 		free(kv);
673 	}
674 	for (kv = wpc->env; kv; kv = kv_next) {
675 		kv_next = kv->next;
676 		free(kv->key);
677 		free(kv->value);
678 		free(kv);
679 	}
680 
681 	return 0;
682 }
683 /* }}} */
684 
685 #define FPM_WPC_STR_CP_EX(_cfg, _scfg, _sf, _df) \
686 	do { \
687 		if (_scfg->_df && !(_cfg->_sf = strdup(_scfg->_df))) { \
688 			return -1; \
689 		} \
690 	} while (0)
691 #define FPM_WPC_STR_CP(_cfg, _scfg, _field) FPM_WPC_STR_CP_EX(_cfg, _scfg, _field, _field)
692 
fpm_worker_pool_shared_status_alloc(struct fpm_worker_pool_s * shared_wp)693 static int fpm_worker_pool_shared_status_alloc(struct fpm_worker_pool_s *shared_wp) { /* {{{ */
694 	struct fpm_worker_pool_config_s *config, *shared_config;
695 	config = fpm_worker_pool_config_alloc();
696 	if (!config) {
697 		return -1;
698 	}
699 	shared_config = shared_wp->config;
700 
701 	config->name = malloc(strlen(shared_config->name) + sizeof("_status"));
702 	if (!config->name) {
703 		return -1;
704 	}
705 	strcpy(config->name, shared_config->name);
706 	strcpy(config->name + strlen(shared_config->name), "_status");
707 
708 	if (!shared_config->pm_status_path) {
709 		shared_config->pm_status_path = strdup("/");
710 	}
711 
712 	FPM_WPC_STR_CP_EX(config, shared_config, listen_address, pm_status_listen);
713 #ifdef HAVE_FPM_ACL
714 	FPM_WPC_STR_CP(config, shared_config, listen_acl_groups);
715 	FPM_WPC_STR_CP(config, shared_config, listen_acl_users);
716 #endif
717 	FPM_WPC_STR_CP(config, shared_config, listen_allowed_clients);
718 	FPM_WPC_STR_CP(config, shared_config, listen_group);
719 	FPM_WPC_STR_CP(config, shared_config, listen_owner);
720 	FPM_WPC_STR_CP(config, shared_config, listen_mode);
721 	FPM_WPC_STR_CP(config, shared_config, user);
722 	FPM_WPC_STR_CP(config, shared_config, group);
723 	FPM_WPC_STR_CP(config, shared_config, pm_status_path);
724 
725 	config->pm = PM_STYLE_ONDEMAND;
726 	config->pm_max_children = 2;
727 
728 	current_wp->shared = shared_wp;
729 
730 	return 0;
731 }
732 /* }}} */
733 
fpm_evaluate_full_path(char ** path,struct fpm_worker_pool_s * wp,char * default_prefix,int expand)734 static int fpm_evaluate_full_path(char **path, struct fpm_worker_pool_s *wp, char *default_prefix, int expand) /* {{{ */
735 {
736 	char *prefix = NULL;
737 	char *full_path;
738 
739 	if (!path || !*path || **path == '/') {
740 		return 0;
741 	}
742 
743 	if (wp && wp->config) {
744 		prefix = wp->config->prefix;
745 	}
746 
747 	/* if the wp prefix is not set */
748 	if (prefix == NULL) {
749 		prefix = fpm_globals.prefix;
750 	}
751 
752 	/* if the global prefix is not set */
753 	if (prefix == NULL) {
754 		prefix = default_prefix ? default_prefix : PHP_PREFIX;
755 	}
756 
757 	if (expand) {
758 		char *tmp;
759 		tmp = strstr(*path, "$prefix");
760 		if (tmp != NULL) {
761 
762 			if (tmp != *path) {
763 				zlog(ZLOG_ERROR, "'$prefix' must be use at the beginning of the value");
764 				return -1;
765 			}
766 
767 			if (strlen(*path) > strlen("$prefix")) {
768 				tmp = strdup((*path) + strlen("$prefix"));
769 				free(*path);
770 				*path = tmp;
771 			} else {
772 				free(*path);
773 				*path = NULL;
774 			}
775 		}
776 	}
777 
778 	if (*path) {
779 		spprintf(&full_path, 0, "%s/%s", prefix, *path);
780 		free(*path);
781 		*path = strdup(full_path);
782 		efree(full_path);
783 	} else {
784 		*path = strdup(prefix);
785 	}
786 
787 	if (**path != '/' && wp != NULL && wp->config) {
788 		return fpm_evaluate_full_path(path, NULL, default_prefix, expand);
789 	}
790 	return 0;
791 }
792 /* }}} */
793 
fpm_conf_process_all_pools(void)794 static int fpm_conf_process_all_pools(void)
795 {
796 	struct fpm_worker_pool_s *wp, *wp2;
797 
798 	if (!fpm_worker_all_pools) {
799 		zlog(ZLOG_ERROR, "No pool defined. at least one pool section must be specified in config file");
800 		return -1;
801 	}
802 
803 	for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
804 
805 		/* prefix */
806 		if (wp->config->prefix && *wp->config->prefix) {
807 			fpm_evaluate_full_path(&wp->config->prefix, NULL, NULL, 0);
808 
809 			if (!fpm_conf_is_dir(wp->config->prefix)) {
810 				zlog(ZLOG_ERROR, "[pool %s] the prefix '%s' does not exist or is not a directory", wp->config->name, wp->config->prefix);
811 				return -1;
812 			}
813 		}
814 
815 		/* alert if user is not set; only if we are root and fpm is not running with --allow-to-run-as-root */
816 		if (!wp->config->user && !geteuid() && !fpm_globals.run_as_root) {
817 			zlog(ZLOG_ALERT, "[pool %s] user has not been defined", wp->config->name);
818 			return -1;
819 		}
820 
821 		/* listen */
822 		if (wp->config->listen_address && *wp->config->listen_address) {
823 			wp->listen_address_domain = fpm_sockets_domain_from_address(wp->config->listen_address);
824 
825 			if (wp->listen_address_domain == FPM_AF_UNIX && *wp->config->listen_address != '/') {
826 				fpm_evaluate_full_path(&wp->config->listen_address, wp, NULL, 0);
827 			}
828 		} else {
829 			zlog(ZLOG_ALERT, "[pool %s] no listen address have been defined!", wp->config->name);
830 			return -1;
831 		}
832 
833 		if (wp->config->process_priority != 64 && (wp->config->process_priority < -19 || wp->config->process_priority > 20)) {
834 			zlog(ZLOG_ERROR, "[pool %s] process.priority must be included into [-19,20]", wp->config->name);
835 			return -1;
836 		}
837 
838 		/* pm */
839 		if (wp->config->pm != PM_STYLE_STATIC && wp->config->pm != PM_STYLE_DYNAMIC && wp->config->pm != PM_STYLE_ONDEMAND) {
840 			zlog(ZLOG_ALERT, "[pool %s] the process manager is missing (static, dynamic or ondemand)", wp->config->name);
841 			return -1;
842 		}
843 
844 		/* pm.max_children */
845 		if (wp->config->pm_max_children < 1) {
846 			zlog(ZLOG_ALERT, "[pool %s] pm.max_children must be a positive value", wp->config->name);
847 			return -1;
848 		}
849 
850 		/* pm.start_servers, pm.min_spare_servers, pm.max_spare_servers */
851 		if (wp->config->pm == PM_STYLE_DYNAMIC) {
852 			struct fpm_worker_pool_config_s *config = wp->config;
853 
854 			if (config->pm_min_spare_servers <= 0) {
855 				zlog(ZLOG_ALERT, "[pool %s] pm.min_spare_servers(%d) must be a positive value", wp->config->name, config->pm_min_spare_servers);
856 				return -1;
857 			}
858 
859 			if (config->pm_max_spare_servers <= 0) {
860 				zlog(ZLOG_ALERT, "[pool %s] pm.max_spare_servers(%d) must be a positive value", wp->config->name, config->pm_max_spare_servers);
861 				return -1;
862 			}
863 
864 			if (config->pm_min_spare_servers > config->pm_max_children ||
865 					config->pm_max_spare_servers > config->pm_max_children) {
866 				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);
867 				return -1;
868 			}
869 
870 			if (config->pm_max_spare_servers < config->pm_min_spare_servers) {
871 				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);
872 				return -1;
873 			}
874 
875 			if (config->pm_start_servers <= 0) {
876 				config->pm_start_servers = config->pm_min_spare_servers + ((config->pm_max_spare_servers - config->pm_min_spare_servers) / 2);
877 				zlog(ZLOG_NOTICE, "[pool %s] pm.start_servers is not set. It's been set to %d.", wp->config->name, config->pm_start_servers);
878 
879 			} else if (config->pm_start_servers < config->pm_min_spare_servers || config->pm_start_servers > config->pm_max_spare_servers) {
880 				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);
881 				return -1;
882 			}
883 		} else if (wp->config->pm == PM_STYLE_ONDEMAND) {
884 			struct fpm_worker_pool_config_s *config = wp->config;
885 
886 			if (!fpm_event_support_edge_trigger()) {
887 				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);
888 				return -1;
889 			}
890 
891 			if (config->pm_process_idle_timeout < 1) {
892 				zlog(ZLOG_ALERT, "[pool %s] pm.process_idle_timeout(%ds) must be greater than 0s", wp->config->name, config->pm_process_idle_timeout);
893 				return -1;
894 			}
895 
896 			if (config->listen_backlog < FPM_BACKLOG_DEFAULT) {
897 				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);
898 				config->listen_backlog = FPM_BACKLOG_DEFAULT;
899 			}
900 
901 			/* certainely useless but proper */
902 			config->pm_start_servers = 0;
903 			config->pm_min_spare_servers = 0;
904 			config->pm_max_spare_servers = 0;
905 		}
906 
907 		/* status */
908 		if (wp->config->pm_status_listen && fpm_worker_pool_shared_status_alloc(wp)) {
909 			zlog(ZLOG_ERROR, "[pool %s] failed to initialize a status listener pool", wp->config->name);
910 		}
911 
912 		if (wp->config->pm_status_path && *wp->config->pm_status_path) {
913 			size_t i;
914 			char *status = wp->config->pm_status_path;
915 
916 			if (*status != '/') {
917 				zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must start with a '/'", wp->config->name, status);
918 				return -1;
919 			}
920 
921 			if (!wp->config->pm_status_listen && !wp->shared && strlen(status) < 2) {
922 				zlog(ZLOG_ERROR, "[pool %s] the status path '%s' is not long enough", wp->config->name, status);
923 				return -1;
924 			}
925 
926 			for (i = 0; i < strlen(status); i++) {
927 				if (!isalnum(status[i]) && status[i] != '/' && status[i] != '-' && status[i] != '_' && status[i] != '.' && status[i] != '~') {
928 					zlog(ZLOG_ERROR, "[pool %s] the status path '%s' must contain only the following characters '[alphanum]/_-.~'", wp->config->name, status);
929 					return -1;
930 				}
931 			}
932 		}
933 
934 		/* ping */
935 		if (wp->config->ping_path && *wp->config->ping_path) {
936 			char *ping = wp->config->ping_path;
937 			size_t i;
938 
939 			if (*ping != '/') {
940 				zlog(ZLOG_ERROR, "[pool %s] the ping path '%s' must start with a '/'", wp->config->name, ping);
941 				return -1;
942 			}
943 
944 			if (strlen(ping) < 2) {
945 				zlog(ZLOG_ERROR, "[pool %s] the ping path '%s' is not long enough", wp->config->name, ping);
946 				return -1;
947 			}
948 
949 			for (i = 0; i < strlen(ping); i++) {
950 				if (!isalnum(ping[i]) && ping[i] != '/' && ping[i] != '-' && ping[i] != '_' && ping[i] != '.' && ping[i] != '~') {
951 					zlog(ZLOG_ERROR, "[pool %s] the ping path '%s' must contain only the following characters '[alphanum]/_-.~'", wp->config->name, ping);
952 					return -1;
953 				}
954 			}
955 
956 			if (!wp->config->ping_response) {
957 				wp->config->ping_response = strdup("pong");
958 			} else {
959 				if (strlen(wp->config->ping_response) < 1) {
960 					zlog(ZLOG_ERROR, "[pool %s] the ping response page '%s' is not long enough", wp->config->name, wp->config->ping_response);
961 					return -1;
962 				}
963 			}
964 		} else {
965 			if (wp->config->ping_response) {
966 				free(wp->config->ping_response);
967 				wp->config->ping_response = NULL;
968 			}
969 		}
970 
971 		/* access.log, access.format */
972 		if (wp->config->access_log && *wp->config->access_log) {
973 			fpm_evaluate_full_path(&wp->config->access_log, wp, NULL, 0);
974 			if (!wp->config->access_format) {
975 				wp->config->access_format = strdup("%R - %u %t \"%m %r\" %s");
976 			}
977 		}
978 
979 		if (wp->config->request_terminate_timeout) {
980 			fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_terminate_timeout * 1000) / 3) : (wp->config->request_terminate_timeout * 1000) / 3;
981 		}
982 
983 		/* slowlog */
984 		if (wp->config->slowlog && *wp->config->slowlog) {
985 			fpm_evaluate_full_path(&wp->config->slowlog, wp, NULL, 0);
986 		}
987 
988 		/* request_slowlog_timeout */
989 		if (wp->config->request_slowlog_timeout) {
990 #if HAVE_FPM_TRACE
991 			if (! (wp->config->slowlog && *wp->config->slowlog)) {
992 				zlog(ZLOG_ERROR, "[pool %s] 'slowlog' must be specified for use with 'request_slowlog_timeout'", wp->config->name);
993 				return -1;
994 			}
995 #else
996 			static int warned = 0;
997 
998 			if (!warned) {
999 				zlog(ZLOG_WARNING, "[pool %s] 'request_slowlog_timeout' is not supported on your system",	wp->config->name);
1000 				warned = 1;
1001 			}
1002 
1003 			wp->config->request_slowlog_timeout = 0;
1004 #endif
1005 
1006 			if (wp->config->slowlog && *wp->config->slowlog) {
1007 				int fd;
1008 
1009 				fd = open(wp->config->slowlog, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
1010 
1011 				if (0 > fd) {
1012 					zlog(ZLOG_SYSERROR, "Unable to create or open slowlog(%s)", wp->config->slowlog);
1013 					return -1;
1014 				}
1015 				close(fd);
1016 			}
1017 
1018 			fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_slowlog_timeout * 1000) / 3) : (wp->config->request_slowlog_timeout * 1000) / 3;
1019 
1020 			if (wp->config->request_terminate_timeout && wp->config->request_slowlog_timeout > wp->config->request_terminate_timeout) {
1021 				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);
1022 				return -1;
1023 			}
1024 		}
1025 
1026 		/* request_slowlog_trace_depth */
1027 		if (wp->config->request_slowlog_trace_depth) {
1028 #if HAVE_FPM_TRACE
1029 			if (! (wp->config->slowlog && *wp->config->slowlog)) {
1030 				zlog(ZLOG_ERROR, "[pool %s] 'slowlog' must be specified for use with 'request_slowlog_trace_depth'", wp->config->name);
1031 				return -1;
1032 			}
1033 #else
1034 			static int warned = 0;
1035 
1036 			if (!warned) {
1037 				zlog(ZLOG_WARNING, "[pool %s] 'request_slowlog_trace_depth' is not supported on your system", wp->config->name);
1038 				warned = 1;
1039 			}
1040 #endif
1041 
1042 			if (wp->config->request_slowlog_trace_depth <= 0) {
1043 				zlog(ZLOG_ERROR, "[pool %s] 'request_slowlog_trace_depth' (%d) must be a positive value", wp->config->name, wp->config->request_slowlog_trace_depth);
1044 				return -1;
1045 			}
1046 		} else {
1047 			wp->config->request_slowlog_trace_depth = 20;
1048 		}
1049 
1050 		/* chroot */
1051 		if (wp->config->chroot && *wp->config->chroot) {
1052 
1053 			fpm_evaluate_full_path(&wp->config->chroot, wp, NULL, 1);
1054 
1055 			if (*wp->config->chroot != '/') {
1056 				zlog(ZLOG_ERROR, "[pool %s] the chroot path '%s' must start with a '/'", wp->config->name, wp->config->chroot);
1057 				return -1;
1058 			}
1059 
1060 			if (!fpm_conf_is_dir(wp->config->chroot)) {
1061 				zlog(ZLOG_ERROR, "[pool %s] the chroot path '%s' does not exist or is not a directory", wp->config->name, wp->config->chroot);
1062 				return -1;
1063 			}
1064 		}
1065 
1066 		/* chdir */
1067 		if (wp->config->chdir && *wp->config->chdir) {
1068 
1069 			fpm_evaluate_full_path(&wp->config->chdir, wp, NULL, 0);
1070 
1071 			if (*wp->config->chdir != '/') {
1072 				zlog(ZLOG_ERROR, "[pool %s] the chdir path '%s' must start with a '/'", wp->config->name, wp->config->chdir);
1073 				return -1;
1074 			}
1075 
1076 			if (wp->config->chroot) {
1077 				char *buf;
1078 
1079 				spprintf(&buf, 0, "%s/%s", wp->config->chroot, wp->config->chdir);
1080 
1081 				if (!fpm_conf_is_dir(buf)) {
1082 					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);
1083 					efree(buf);
1084 					return -1;
1085 				}
1086 
1087 				efree(buf);
1088 			} else {
1089 				if (!fpm_conf_is_dir(wp->config->chdir)) {
1090 					zlog(ZLOG_ERROR, "[pool %s] the chdir path '%s' does not exist or is not a directory", wp->config->name, wp->config->chdir);
1091 					return -1;
1092 				}
1093 			}
1094 		}
1095 
1096 		/* security.limit_extensions */
1097 		if (!wp->config->security_limit_extensions) {
1098 			wp->config->security_limit_extensions = strdup(".php .phar");
1099 		}
1100 
1101 		if (*wp->config->security_limit_extensions) {
1102 			int nb_ext;
1103 			char *ext;
1104 			char *security_limit_extensions;
1105 			char *limit_extensions;
1106 
1107 
1108 			/* strdup because strtok(3) alters the string it parses */
1109 			security_limit_extensions = strdup(wp->config->security_limit_extensions);
1110 			limit_extensions = security_limit_extensions;
1111 			nb_ext = 0;
1112 
1113 			/* find the number of extensions */
1114 			while (strtok(limit_extensions, " \t")) {
1115 				limit_extensions = NULL;
1116 				nb_ext++;
1117 			}
1118 			free(security_limit_extensions);
1119 
1120 			/* if something found */
1121 			if (nb_ext > 0) {
1122 
1123 				/* malloc the extension array */
1124 				wp->limit_extensions = malloc(sizeof(char *) * (nb_ext + 1));
1125 				if (!wp->limit_extensions) {
1126 					zlog(ZLOG_ERROR, "[pool %s] unable to malloc extensions array", wp->config->name);
1127 					return -1;
1128 				}
1129 
1130 				/* strdup because strtok(3) alters the string it parses */
1131 				security_limit_extensions = strdup(wp->config->security_limit_extensions);
1132 				limit_extensions = security_limit_extensions;
1133 				nb_ext = 0;
1134 
1135 				/* parse the string and save the extension in the array */
1136 				while ((ext = strtok(limit_extensions, " \t"))) {
1137 					limit_extensions = NULL;
1138 					wp->limit_extensions[nb_ext++] = strdup(ext);
1139 				}
1140 
1141 				/* end the array with NULL in order to parse it */
1142 				wp->limit_extensions[nb_ext] = NULL;
1143 				free(security_limit_extensions);
1144 			}
1145 		}
1146 
1147 		/* env[], php_value[], php_admin_values[] */
1148 		if (!wp->config->chroot) {
1149 			struct key_value_s *kv;
1150 			char *options[] = FPM_PHP_INI_TO_EXPAND;
1151 			char **p;
1152 
1153 			for (kv = wp->config->php_values; kv; kv = kv->next) {
1154 				for (p = options; *p; p++) {
1155 					if (!strcasecmp(kv->key, *p)) {
1156 						fpm_evaluate_full_path(&kv->value, wp, NULL, 0);
1157 					}
1158 				}
1159 			}
1160 			for (kv = wp->config->php_admin_values; kv; kv = kv->next) {
1161 				if (!strcasecmp(kv->key, "error_log") && !strcasecmp(kv->value, "syslog")) {
1162 					continue;
1163 				}
1164 				for (p = options; *p; p++) {
1165 					if (!strcasecmp(kv->key, *p)) {
1166 						fpm_evaluate_full_path(&kv->value, wp, NULL, 0);
1167 					}
1168 				}
1169 			}
1170 		}
1171 	}
1172 
1173 	/* ensure 2 pools do not use the same listening address */
1174 	for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
1175 		for (wp2 = fpm_worker_all_pools; wp2; wp2 = wp2->next) {
1176 			if (wp == wp2) {
1177 				continue;
1178 			}
1179 
1180 			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)) {
1181 				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);
1182 				return -1;
1183 			}
1184 		}
1185 	}
1186 	return 0;
1187 }
1188 
fpm_conf_unlink_pid(void)1189 int fpm_conf_unlink_pid(void)
1190 {
1191 	if (fpm_global_config.pid_file) {
1192 		if (0 > unlink(fpm_global_config.pid_file)) {
1193 			zlog(ZLOG_SYSERROR, "Unable to remove the PID file (%s).", fpm_global_config.pid_file);
1194 			return -1;
1195 		}
1196 	}
1197 	return 0;
1198 }
1199 
fpm_conf_write_pid(void)1200 int fpm_conf_write_pid(void)
1201 {
1202 	int fd;
1203 
1204 	if (fpm_global_config.pid_file) {
1205 		char buf[64];
1206 		int len;
1207 
1208 		unlink(fpm_global_config.pid_file);
1209 		fd = creat(fpm_global_config.pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1210 
1211 		if (fd < 0) {
1212 			zlog(ZLOG_SYSERROR, "Unable to create the PID file (%s).", fpm_global_config.pid_file);
1213 			return -1;
1214 		}
1215 
1216 		len = sprintf(buf, "%d", (int) fpm_globals.parent_pid);
1217 
1218 		if (len != write(fd, buf, len)) {
1219 			zlog(ZLOG_SYSERROR, "Unable to write to the PID file.");
1220 			close(fd);
1221 			return -1;
1222 		}
1223 		close(fd);
1224 	}
1225 	return 0;
1226 }
1227 
fpm_conf_post_process(int force_daemon)1228 static int fpm_conf_post_process(int force_daemon) /* {{{ */
1229 {
1230 	struct fpm_worker_pool_s *wp;
1231 
1232 	if (fpm_global_config.pid_file) {
1233 		fpm_evaluate_full_path(&fpm_global_config.pid_file, NULL, PHP_LOCALSTATEDIR, 0);
1234 	}
1235 
1236 	if (force_daemon >= 0) {
1237 		/* forced from command line options */
1238 		fpm_global_config.daemonize = force_daemon;
1239 	}
1240 
1241 	fpm_globals.log_level = fpm_global_config.log_level;
1242 	zlog_set_level(fpm_globals.log_level);
1243 	if (fpm_global_config.log_limit < ZLOG_MIN_LIMIT) {
1244 		zlog(ZLOG_ERROR, "log_limit must be greater than %d", ZLOG_MIN_LIMIT);
1245 		return -1;
1246 	}
1247 	zlog_set_limit(fpm_global_config.log_limit);
1248 	zlog_set_buffering(fpm_global_config.log_buffering);
1249 
1250 	if (fpm_global_config.process_max < 0) {
1251 		zlog(ZLOG_ERROR, "process_max can't be negative");
1252 		return -1;
1253 	}
1254 
1255 	if (fpm_global_config.process_priority != 64 && (fpm_global_config.process_priority < -19 || fpm_global_config.process_priority > 20)) {
1256 		zlog(ZLOG_ERROR, "process.priority must be included into [-19,20]");
1257 		return -1;
1258 	}
1259 
1260 	if (!fpm_global_config.error_log) {
1261 		fpm_global_config.error_log = strdup("log/php-fpm.log");
1262 	}
1263 
1264 #ifdef HAVE_SYSTEMD
1265 	if (0 > fpm_systemd_conf()) {
1266 		return -1;
1267 	}
1268 #endif
1269 
1270 #ifdef HAVE_SYSLOG_H
1271 	if (!fpm_global_config.syslog_ident) {
1272 		fpm_global_config.syslog_ident = strdup("php-fpm");
1273 	}
1274 
1275 	if (fpm_global_config.syslog_facility < 0) {
1276 		fpm_global_config.syslog_facility = LOG_DAEMON;
1277 	}
1278 
1279 	if (strcasecmp(fpm_global_config.error_log, "syslog") != 0)
1280 #endif
1281 	{
1282 		fpm_evaluate_full_path(&fpm_global_config.error_log, NULL, PHP_LOCALSTATEDIR, 0);
1283 	}
1284 
1285 	if (!fpm_global_config.daemonize && 0 > fpm_stdio_save_original_stderr()) {
1286 		return -1;
1287 	}
1288 
1289 	if (0 > fpm_stdio_open_error_log(0)) {
1290 		return -1;
1291 	}
1292 
1293 	if (0 > fpm_event_pre_init(fpm_global_config.events_mechanism)) {
1294 		return -1;
1295 	}
1296 
1297 	if (0 > fpm_conf_process_all_pools()) {
1298 		return -1;
1299 	}
1300 
1301 	if (0 > fpm_log_open(0)) {
1302 		return -1;
1303 	}
1304 
1305 	for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
1306 		if (!wp->config->access_log || !*wp->config->access_log) {
1307 			continue;
1308 		}
1309 		if (0 > fpm_log_write(wp->config->access_format)) {
1310 			zlog(ZLOG_ERROR, "[pool %s] wrong format for access.format '%s'", wp->config->name, wp->config->access_format);
1311 			return -1;
1312 		}
1313 	}
1314 
1315 	return 0;
1316 }
1317 /* }}} */
1318 
fpm_conf_cleanup(int which,void * arg)1319 static void fpm_conf_cleanup(int which, void *arg) /* {{{ */
1320 {
1321 	free(fpm_global_config.pid_file);
1322 	free(fpm_global_config.error_log);
1323 	free(fpm_global_config.events_mechanism);
1324 	fpm_global_config.pid_file = 0;
1325 	fpm_global_config.error_log = 0;
1326 	fpm_global_config.log_limit = ZLOG_DEFAULT_LIMIT;
1327 #ifdef HAVE_SYSLOG_H
1328 	free(fpm_global_config.syslog_ident);
1329 	fpm_global_config.syslog_ident = 0;
1330 #endif
1331 	free(fpm_globals.config);
1332 }
1333 /* }}} */
1334 
fpm_conf_ini_parser_include(char * inc,void * arg)1335 static void fpm_conf_ini_parser_include(char *inc, void *arg) /* {{{ */
1336 {
1337 	char *filename;
1338 	int *error = (int *)arg;
1339 #ifdef HAVE_GLOB
1340 	glob_t g;
1341 #endif
1342 	size_t i;
1343 
1344 	if (!inc || !arg) return;
1345 	if (*error) return; /* We got already an error. Switch to the end. */
1346 	spprintf(&filename, 0, "%s", ini_filename);
1347 
1348 #ifdef HAVE_GLOB
1349 	{
1350 		g.gl_offs = 0;
1351 		if ((i = glob(inc, GLOB_ERR | GLOB_MARK, NULL, &g)) != 0) {
1352 #ifdef GLOB_NOMATCH
1353 			if (i == GLOB_NOMATCH) {
1354 				zlog(ZLOG_WARNING, "Nothing matches the include pattern '%s' from %s at line %d.", inc, filename, ini_lineno);
1355 				efree(filename);
1356 				return;
1357 			}
1358 #endif /* GLOB_NOMATCH */
1359 			zlog(ZLOG_ERROR, "Unable to globalize '%s' (ret=%zd) from %s at line %d.", inc, i, filename, ini_lineno);
1360 			*error = 1;
1361 			efree(filename);
1362 			return;
1363 		}
1364 
1365 		for (i = 0; i < g.gl_pathc; i++) {
1366 			int len = strlen(g.gl_pathv[i]);
1367 			if (len < 1) continue;
1368 			if (g.gl_pathv[i][len - 1] == '/') continue; /* don't parse directories */
1369 			if (0 > fpm_conf_load_ini_file(g.gl_pathv[i])) {
1370 				zlog(ZLOG_ERROR, "Unable to include %s from %s at line %d", g.gl_pathv[i], filename, ini_lineno);
1371 				*error = 1;
1372 				efree(filename);
1373 				return;
1374 			}
1375 		}
1376 		globfree(&g);
1377 	}
1378 #else /* HAVE_GLOB */
1379 	if (0 > fpm_conf_load_ini_file(inc)) {
1380 		zlog(ZLOG_ERROR, "Unable to include %s from %s at line %d", inc, filename, ini_lineno);
1381 		*error = 1;
1382 		efree(filename);
1383 		return;
1384 	}
1385 #endif /* HAVE_GLOB */
1386 
1387 	efree(filename);
1388 }
1389 /* }}} */
1390 
fpm_conf_ini_parser_section(zval * section,void * arg)1391 static void fpm_conf_ini_parser_section(zval *section, void *arg) /* {{{ */
1392 {
1393 	struct fpm_worker_pool_s *wp;
1394 	struct fpm_worker_pool_config_s *config;
1395 	int *error = (int *)arg;
1396 
1397 	/* switch to global conf */
1398 	if (!strcasecmp(Z_STRVAL_P(section), "global")) {
1399 		current_wp = NULL;
1400 		return;
1401 	}
1402 
1403 	for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
1404 		if (!wp->config) continue;
1405 		if (!wp->config->name) continue;
1406 		if (!strcasecmp(wp->config->name, Z_STRVAL_P(section))) {
1407 			/* Found a wp with the same name. Bring it back */
1408 			current_wp = wp;
1409 			return;
1410 		}
1411 	}
1412 
1413 	/* it's a new pool */
1414 	config = (struct fpm_worker_pool_config_s *)fpm_worker_pool_config_alloc();
1415 	if (!current_wp || !config) {
1416 		zlog(ZLOG_ERROR, "[%s:%d] Unable to alloc a new WorkerPool for worker '%s'", ini_filename, ini_lineno, Z_STRVAL_P(section));
1417 		*error = 1;
1418 		return;
1419 	}
1420 	config->name = strdup(Z_STRVAL_P(section));
1421 	if (!config->name) {
1422 		zlog(ZLOG_ERROR, "[%s:%d] Unable to alloc memory for configuration name for worker '%s'", ini_filename, ini_lineno, Z_STRVAL_P(section));
1423 		*error = 1;
1424 		return;
1425 	}
1426 }
1427 /* }}} */
1428 
fpm_conf_ini_parser_entry(zval * name,zval * value,void * arg)1429 static void fpm_conf_ini_parser_entry(zval *name, zval *value, void *arg) /* {{{ */
1430 {
1431 	struct ini_value_parser_s *parser;
1432 	void *config = NULL;
1433 
1434 	int *error = (int *)arg;
1435 	if (!value) {
1436 		zlog(ZLOG_ERROR, "[%s:%d] value is NULL for a ZEND_INI_PARSER_ENTRY", ini_filename, ini_lineno);
1437 		*error = 1;
1438 		return;
1439 	}
1440 
1441 	if (!strcmp(Z_STRVAL_P(name), "include")) {
1442 		if (ini_include) {
1443 			zlog(ZLOG_ERROR, "[%s:%d] two includes at the same time !", ini_filename, ini_lineno);
1444 			*error = 1;
1445 			return;
1446 		}
1447 		ini_include = strdup(Z_STRVAL_P(value));
1448 		return;
1449 	}
1450 
1451 	if (!current_wp) { /* we are in the global section */
1452 		parser = ini_fpm_global_options;
1453 		config = &fpm_global_config;
1454 	} else {
1455 		parser = ini_fpm_pool_options;
1456 		config = current_wp->config;
1457 	}
1458 
1459 	for (; parser->name; parser++) {
1460 		if (!strcasecmp(parser->name, Z_STRVAL_P(name))) {
1461 			char *ret;
1462 			if (!parser->parser) {
1463 				zlog(ZLOG_ERROR, "[%s:%d] the parser for entry '%s' is not defined", ini_filename, ini_lineno, parser->name);
1464 				*error = 1;
1465 				return;
1466 			}
1467 
1468 			ret = parser->parser(value, &config, parser->offset);
1469 			if (ret) {
1470 				zlog(ZLOG_ERROR, "[%s:%d] unable to parse value for entry '%s': %s", ini_filename, ini_lineno, parser->name, ret);
1471 				*error = 1;
1472 				return;
1473 			}
1474 
1475 			/* all is good ! */
1476 			return;
1477 		}
1478 	}
1479 
1480 	/* nothing has been found if we got here */
1481 	zlog(ZLOG_ERROR, "[%s:%d] unknown entry '%s'", ini_filename, ini_lineno, Z_STRVAL_P(name));
1482 	*error = 1;
1483 }
1484 /* }}} */
1485 
fpm_conf_ini_parser_array(zval * name,zval * key,zval * value,void * arg)1486 static void fpm_conf_ini_parser_array(zval *name, zval *key, zval *value, void *arg) /* {{{ */
1487 {
1488 	int *error = (int *)arg;
1489 	char *err = NULL;
1490 	void *config;
1491 
1492 	if (!Z_STRVAL_P(key) || !Z_STRVAL_P(value) || !*Z_STRVAL_P(key)) {
1493 		zlog(ZLOG_ERROR, "[%s:%d] Misspelled  array ?", ini_filename, ini_lineno);
1494 		*error = 1;
1495 		return;
1496 	}
1497 	if (!current_wp || !current_wp->config) {
1498 		zlog(ZLOG_ERROR, "[%s:%d] Array are not allowed in the global section", ini_filename, ini_lineno);
1499 		*error = 1;
1500 		return;
1501 	}
1502 
1503 	if (!strcmp("env", Z_STRVAL_P(name))) {
1504 		if (!*Z_STRVAL_P(value)) {
1505 			zlog(ZLOG_ERROR, "[%s:%d] empty value", ini_filename, ini_lineno);
1506 			*error = 1;
1507 			return;
1508 		}
1509 		config = (char *)current_wp->config + WPO(env);
1510 		err = fpm_conf_set_array(key, value, &config, 0);
1511 
1512 	} else if (!strcmp("php_value", Z_STRVAL_P(name))) {
1513 		config = (char *)current_wp->config + WPO(php_values);
1514 		err = fpm_conf_set_array(key, value, &config, 0);
1515 
1516 	} else if (!strcmp("php_admin_value", Z_STRVAL_P(name))) {
1517 		config = (char *)current_wp->config + WPO(php_admin_values);
1518 		err = fpm_conf_set_array(key, value, &config, 0);
1519 
1520 	} else if (!strcmp("php_flag", Z_STRVAL_P(name))) {
1521 		config = (char *)current_wp->config + WPO(php_values);
1522 		err = fpm_conf_set_array(key, value, &config, 1);
1523 
1524 	} else if (!strcmp("php_admin_flag", Z_STRVAL_P(name))) {
1525 		config = (char *)current_wp->config + WPO(php_admin_values);
1526 		err = fpm_conf_set_array(key, value, &config, 1);
1527 
1528 	} else {
1529 		zlog(ZLOG_ERROR, "[%s:%d] unknown directive '%s'", ini_filename, ini_lineno, Z_STRVAL_P(name));
1530 		*error = 1;
1531 		return;
1532 	}
1533 
1534 	if (err) {
1535 		zlog(ZLOG_ERROR, "[%s:%d] error while parsing '%s[%s]' : %s", ini_filename, ini_lineno, Z_STRVAL_P(name), Z_STRVAL_P(key), err);
1536 		*error = 1;
1537 		return;
1538 	}
1539 }
1540 /* }}} */
1541 
fpm_conf_ini_parser(zval * arg1,zval * arg2,zval * arg3,int callback_type,void * arg)1542 static void fpm_conf_ini_parser(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg) /* {{{ */
1543 {
1544 	int *error;
1545 
1546 	if (!arg1 || !arg) return;
1547 	error = (int *)arg;
1548 	if (*error) return; /* We got already an error. Switch to the end. */
1549 
1550 	switch(callback_type) {
1551 		case ZEND_INI_PARSER_ENTRY:
1552 			fpm_conf_ini_parser_entry(arg1, arg2, error);
1553 			break;
1554 		case ZEND_INI_PARSER_SECTION:
1555 			fpm_conf_ini_parser_section(arg1, error);
1556 			break;
1557 		case ZEND_INI_PARSER_POP_ENTRY:
1558 			fpm_conf_ini_parser_array(arg1, arg3, arg2, error);
1559 			break;
1560 		default:
1561 			zlog(ZLOG_ERROR, "[%s:%d] Unknown INI syntax", ini_filename, ini_lineno);
1562 			*error = 1;
1563 			break;
1564 	}
1565 }
1566 /* }}} */
1567 
fpm_conf_load_ini_file(char * filename)1568 int fpm_conf_load_ini_file(char *filename) /* {{{ */
1569 {
1570 	int error = 0;
1571 	char *buf = NULL, *newbuf = NULL;
1572 	int bufsize = 0;
1573 	int fd, n;
1574 	int nb_read = 1;
1575 	char c = '*';
1576 
1577 	int ret = 1;
1578 
1579 	if (!filename || !filename[0]) {
1580 		zlog(ZLOG_ERROR, "configuration filename is empty");
1581 		return -1;
1582 	}
1583 
1584 	fd = open(filename, O_RDONLY, 0);
1585 	if (fd < 0) {
1586 		zlog(ZLOG_SYSERROR, "failed to open configuration file '%s'", filename);
1587 		return -1;
1588 	}
1589 
1590 	if (ini_recursion++ > 4) {
1591 		zlog(ZLOG_ERROR, "failed to include more than 5 files recursively");
1592 		close(fd);
1593 		return -1;
1594 	}
1595 
1596 	ini_lineno = 0;
1597 	while (nb_read > 0) {
1598 		int tmp;
1599 		ini_lineno++;
1600 		ini_filename = filename;
1601 		for (n = 0; (nb_read = read(fd, &c, sizeof(char))) == sizeof(char) && c != '\n'; n++) {
1602 			if (n == bufsize) {
1603 				bufsize += 1024;
1604 				newbuf = (char*) realloc(buf, sizeof(char) * (bufsize + 2));
1605 				if (newbuf == NULL) {
1606 					ini_recursion--;
1607 					close(fd);
1608 					free(buf);
1609 					return -1;
1610 				}
1611 				buf = newbuf;
1612 			}
1613 
1614 			buf[n] = c;
1615 		}
1616 		if (n == 0) {
1617 			continue;
1618 		}
1619 		/* always append newline and null terminate */
1620 		buf[n++] = '\n';
1621 		buf[n] = '\0';
1622 		tmp = zend_parse_ini_string(buf, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t)fpm_conf_ini_parser, &error);
1623 		ini_filename = filename;
1624 		if (error || tmp == FAILURE) {
1625 			if (ini_include) {
1626 				free(ini_include);
1627 				ini_include = NULL;
1628 			}
1629 			ini_recursion--;
1630 			close(fd);
1631 			free(buf);
1632 			return -1;
1633 		}
1634 		if (ini_include) {
1635 			char *tmp = ini_include;
1636 			ini_include = NULL;
1637 			fpm_evaluate_full_path(&tmp, NULL, NULL, 0);
1638 			fpm_conf_ini_parser_include(tmp, &error);
1639 			if (error) {
1640 				free(tmp);
1641 				ini_recursion--;
1642 				close(fd);
1643 				free(buf);
1644 				return -1;
1645 			}
1646 			free(tmp);
1647 		}
1648 	}
1649 	free(buf);
1650 
1651 	ini_recursion--;
1652 	close(fd);
1653 	return ret;
1654 }
1655 /* }}} */
1656 
fpm_conf_dump(void)1657 static void fpm_conf_dump(void)
1658 {
1659 	struct fpm_worker_pool_s *wp;
1660 
1661 	/*
1662 	 * Please keep the same order as in fpm_conf.h and in php-fpm.conf.in
1663 	 */
1664 	zlog(ZLOG_NOTICE, "[global]");
1665 	zlog(ZLOG_NOTICE, "\tpid = %s",                         STR2STR(fpm_global_config.pid_file));
1666 	zlog(ZLOG_NOTICE, "\terror_log = %s",                   STR2STR(fpm_global_config.error_log));
1667 #ifdef HAVE_SYSLOG_H
1668 	zlog(ZLOG_NOTICE, "\tsyslog.ident = %s",                STR2STR(fpm_global_config.syslog_ident));
1669 	zlog(ZLOG_NOTICE, "\tsyslog.facility = %d",             fpm_global_config.syslog_facility); /* FIXME: convert to string */
1670 #endif
1671 	zlog(ZLOG_NOTICE, "\tlog_buffering = %s",               BOOL2STR(fpm_global_config.log_buffering));
1672 	zlog(ZLOG_NOTICE, "\tlog_level = %s",                   zlog_get_level_name(fpm_globals.log_level));
1673 	zlog(ZLOG_NOTICE, "\tlog_limit = %d",                   fpm_global_config.log_limit);
1674 	zlog(ZLOG_NOTICE, "\temergency_restart_interval = %ds", fpm_global_config.emergency_restart_interval);
1675 	zlog(ZLOG_NOTICE, "\temergency_restart_threshold = %d", fpm_global_config.emergency_restart_threshold);
1676 	zlog(ZLOG_NOTICE, "\tprocess_control_timeout = %ds",    fpm_global_config.process_control_timeout);
1677 	zlog(ZLOG_NOTICE, "\tprocess.max = %d",                 fpm_global_config.process_max);
1678 	if (fpm_global_config.process_priority == 64) {
1679 		zlog(ZLOG_NOTICE, "\tprocess.priority = undefined");
1680 	} else {
1681 		zlog(ZLOG_NOTICE, "\tprocess.priority = %d", fpm_global_config.process_priority);
1682 	}
1683 	zlog(ZLOG_NOTICE, "\tdaemonize = %s",                   BOOL2STR(fpm_global_config.daemonize));
1684 	zlog(ZLOG_NOTICE, "\trlimit_files = %d",                fpm_global_config.rlimit_files);
1685 	zlog(ZLOG_NOTICE, "\trlimit_core = %d",                 fpm_global_config.rlimit_core);
1686 	zlog(ZLOG_NOTICE, "\tevents.mechanism = %s",            fpm_event_machanism_name());
1687 #ifdef HAVE_SYSTEMD
1688 	zlog(ZLOG_NOTICE, "\tsystemd_interval = %ds",           fpm_global_config.systemd_interval/1000);
1689 #endif
1690 	zlog(ZLOG_NOTICE, " ");
1691 
1692 	for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
1693 		struct key_value_s *kv;
1694 
1695 		if (!wp->config || wp->shared) {
1696 			continue;
1697 		}
1698 
1699 		zlog(ZLOG_NOTICE, "[%s]",                              STR2STR(wp->config->name));
1700 		zlog(ZLOG_NOTICE, "\tprefix = %s",                     STR2STR(wp->config->prefix));
1701 		zlog(ZLOG_NOTICE, "\tuser = %s",                       STR2STR(wp->config->user));
1702 		zlog(ZLOG_NOTICE, "\tgroup = %s",                      STR2STR(wp->config->group));
1703 		zlog(ZLOG_NOTICE, "\tlisten = %s",                     STR2STR(wp->config->listen_address));
1704 		zlog(ZLOG_NOTICE, "\tlisten.backlog = %d",             wp->config->listen_backlog);
1705 #ifdef HAVE_FPM_ACL
1706 		zlog(ZLOG_NOTICE, "\tlisten.acl_users = %s",           STR2STR(wp->config->listen_acl_users));
1707 		zlog(ZLOG_NOTICE, "\tlisten.acl_groups = %s",          STR2STR(wp->config->listen_acl_groups));
1708 #endif
1709 		zlog(ZLOG_NOTICE, "\tlisten.owner = %s",               STR2STR(wp->config->listen_owner));
1710 		zlog(ZLOG_NOTICE, "\tlisten.group = %s",               STR2STR(wp->config->listen_group));
1711 		zlog(ZLOG_NOTICE, "\tlisten.mode = %s",                STR2STR(wp->config->listen_mode));
1712 		zlog(ZLOG_NOTICE, "\tlisten.allowed_clients = %s",     STR2STR(wp->config->listen_allowed_clients));
1713 		if (wp->config->process_priority == 64) {
1714 			zlog(ZLOG_NOTICE, "\tprocess.priority = undefined");
1715 		} else {
1716 			zlog(ZLOG_NOTICE, "\tprocess.priority = %d", wp->config->process_priority);
1717 		}
1718 		zlog(ZLOG_NOTICE, "\tprocess.dumpable = %s",           BOOL2STR(wp->config->process_dumpable));
1719 		zlog(ZLOG_NOTICE, "\tpm = %s",                         PM2STR(wp->config->pm));
1720 		zlog(ZLOG_NOTICE, "\tpm.max_children = %d",            wp->config->pm_max_children);
1721 		zlog(ZLOG_NOTICE, "\tpm.start_servers = %d",           wp->config->pm_start_servers);
1722 		zlog(ZLOG_NOTICE, "\tpm.min_spare_servers = %d",       wp->config->pm_min_spare_servers);
1723 		zlog(ZLOG_NOTICE, "\tpm.max_spare_servers = %d",       wp->config->pm_max_spare_servers);
1724 		zlog(ZLOG_NOTICE, "\tpm.process_idle_timeout = %d",    wp->config->pm_process_idle_timeout);
1725 		zlog(ZLOG_NOTICE, "\tpm.max_requests = %d",            wp->config->pm_max_requests);
1726 		zlog(ZLOG_NOTICE, "\tpm.status_path = %s",             STR2STR(wp->config->pm_status_path));
1727 		zlog(ZLOG_NOTICE, "\tpm.status_listen = %s",           STR2STR(wp->config->pm_status_listen));
1728 		zlog(ZLOG_NOTICE, "\tping.path = %s",                  STR2STR(wp->config->ping_path));
1729 		zlog(ZLOG_NOTICE, "\tping.response = %s",              STR2STR(wp->config->ping_response));
1730 		zlog(ZLOG_NOTICE, "\taccess.log = %s",                 STR2STR(wp->config->access_log));
1731 		zlog(ZLOG_NOTICE, "\taccess.format = %s",              STR2STR(wp->config->access_format));
1732 		zlog(ZLOG_NOTICE, "\tslowlog = %s",                    STR2STR(wp->config->slowlog));
1733 		zlog(ZLOG_NOTICE, "\trequest_slowlog_timeout = %ds",   wp->config->request_slowlog_timeout);
1734 		zlog(ZLOG_NOTICE, "\trequest_slowlog_trace_depth = %d", wp->config->request_slowlog_trace_depth);
1735 		zlog(ZLOG_NOTICE, "\trequest_terminate_timeout = %ds", wp->config->request_terminate_timeout);
1736 		zlog(ZLOG_NOTICE, "\trequest_terminate_timeout_track_finished = %s", BOOL2STR(wp->config->request_terminate_timeout_track_finished));
1737 		zlog(ZLOG_NOTICE, "\trlimit_files = %d",               wp->config->rlimit_files);
1738 		zlog(ZLOG_NOTICE, "\trlimit_core = %d",                wp->config->rlimit_core);
1739 		zlog(ZLOG_NOTICE, "\tchroot = %s",                     STR2STR(wp->config->chroot));
1740 		zlog(ZLOG_NOTICE, "\tchdir = %s",                      STR2STR(wp->config->chdir));
1741 		zlog(ZLOG_NOTICE, "\tcatch_workers_output = %s",       BOOL2STR(wp->config->catch_workers_output));
1742 		zlog(ZLOG_NOTICE, "\tdecorate_workers_output = %s",    BOOL2STR(wp->config->decorate_workers_output));
1743 		zlog(ZLOG_NOTICE, "\tclear_env = %s",                  BOOL2STR(wp->config->clear_env));
1744 		zlog(ZLOG_NOTICE, "\tsecurity.limit_extensions = %s",  wp->config->security_limit_extensions);
1745 
1746 		for (kv = wp->config->env; kv; kv = kv->next) {
1747 			zlog(ZLOG_NOTICE, "\tenv[%s] = %s", kv->key, kv->value);
1748 		}
1749 
1750 		for (kv = wp->config->php_values; kv; kv = kv->next) {
1751 			zlog(ZLOG_NOTICE, "\tphp_value[%s] = %s", kv->key, kv->value);
1752 		}
1753 
1754 		for (kv = wp->config->php_admin_values; kv; kv = kv->next) {
1755 			zlog(ZLOG_NOTICE, "\tphp_admin_value[%s] = %s", kv->key, kv->value);
1756 		}
1757 		zlog(ZLOG_NOTICE, " ");
1758 	}
1759 }
1760 
fpm_conf_init_main(int test_conf,int force_daemon)1761 int fpm_conf_init_main(int test_conf, int force_daemon) /* {{{ */
1762 {
1763 	int ret;
1764 
1765 	if (fpm_globals.prefix && *fpm_globals.prefix) {
1766 		if (!fpm_conf_is_dir(fpm_globals.prefix)) {
1767 			zlog(ZLOG_ERROR, "the global prefix '%s' does not exist or is not a directory", fpm_globals.prefix);
1768 			return -1;
1769 		}
1770 	}
1771 
1772 	if (fpm_globals.pid && *fpm_globals.pid) {
1773 		fpm_global_config.pid_file = strdup(fpm_globals.pid);
1774 	}
1775 
1776 	if (fpm_globals.config == NULL) {
1777 		char *tmp;
1778 
1779 		if (fpm_globals.prefix == NULL) {
1780 			spprintf(&tmp, 0, "%s/php-fpm.conf", PHP_SYSCONFDIR);
1781 		} else {
1782 			spprintf(&tmp, 0, "%s/etc/php-fpm.conf", fpm_globals.prefix);
1783 		}
1784 
1785 		if (!tmp) {
1786 			zlog(ZLOG_SYSERROR, "spprintf() failed (tmp for fpm_globals.config)");
1787 			return -1;
1788 		}
1789 
1790 		fpm_globals.config = strdup(tmp);
1791 		efree(tmp);
1792 
1793 		if (!fpm_globals.config) {
1794 			zlog(ZLOG_SYSERROR, "spprintf() failed (fpm_globals.config)");
1795 			return -1;
1796 		}
1797 	}
1798 
1799 	ret = fpm_conf_load_ini_file(fpm_globals.config);
1800 
1801 	if (0 > ret) {
1802 		zlog(ZLOG_ERROR, "failed to load configuration file '%s'", fpm_globals.config);
1803 		return -1;
1804 	}
1805 
1806 	if (0 > fpm_conf_post_process(force_daemon)) {
1807 		zlog(ZLOG_ERROR, "failed to post process the configuration");
1808 		return -1;
1809 	}
1810 
1811 	if (test_conf) {
1812 		if (test_conf > 1) {
1813 			fpm_conf_dump();
1814 		}
1815 		zlog(ZLOG_NOTICE, "configuration file %s test is successful\n", fpm_globals.config);
1816 		fpm_globals.test_successful = 1;
1817 		return -1;
1818 	}
1819 
1820 	if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_conf_cleanup, 0)) {
1821 		return -1;
1822 	}
1823 
1824 	return 0;
1825 }
1826 /* }}} */
1827