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