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