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