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