1 diff -Naur php-src-vanilla/sapi/fpm/ac/fpm_build.m4 php-src/sapi/fpm/ac/fpm_build.m4
2 --- php-src-vanilla/sapi/fpm/ac/fpm_build.m4 1970-01-01 01:00:00.000000000 +0100
3 +++ php-src/sapi/fpm/ac/fpm_build.m4 2009-10-18 21:05:39.310440424 +0100
6 +AC_DEFUN([AC_FPM_BUILD_SAPI],
8 + PHP_ADD_MAKEFILE_FRAGMENT($abs_srcdir/sapi/fpm/ac/Makefile.frag,$abs_srcdir/sapi/fpm,sapi/fpm)
10 + SAPI_FPM_PATH=sapi/fpm/$php_fpm_bin
11 + PHP_SUBST(SAPI_FPM_PATH)
13 + mkdir -p sapi/fpm/cgi
14 + PHP_FPM_SAPI_FILES=`cd $abs_srcdir/sapi/fpm && find cgi/ \( -name *.c \) -exec printf "{} " \;`
15 + # PHP_FPM_SAPI_FILES="cgi/cgi_main.c cgi/fastcgi.c"
17 + mkdir -p sapi/fpm/fpm
18 + PHP_FPM_CORE_FILES=`cd $abs_srcdir/sapi/fpm && find fpm/ \( -name *.c -not -name fpm_trace*.c \) -exec printf "{} " \;`
19 + # PHP_FPM_CORE_FILES="fpm/fpm_process_ctl.c fpm/fpm_signals.c fpm/fpm_shm.c fpm/fpm.c fpm/fpm_worker_pool.c fpm/fpm_clock.c fpm/fpm_env.c fpm/fpm_shm_slots.c fpm/fpm_children.c fpm/fpm_events.c fpm/fpm_php.c fpm/fpm_unix.c fpm/fpm_request.c fpm/fpm_sockets.c fpm/fpm_php_trace.c fpm/zlog.c fpm/fpm_cleanup.c fpm/fpm_conf.c fpm/xml_config.c fpm/fpm_stdio.c"
21 + if test "$fpm_trace_type" ; then
22 + PHP_FPM_TRACE_FILES=`cd $abs_srcdir/sapi/fpm && find fpm/ \( -name fpm_trace.c -or -name fpm_trace_$fpm_trace_type.c \) -exec printf "{} " \;`
25 + PHP_FPM_CFLAGS="$LIBEVENT_CFLAGS -I$abs_srcdir/sapi/fpm"
27 + SAPI_EXTRA_LIBS="$LIBEVENT_LIBS"
28 + PHP_SUBST(SAPI_EXTRA_LIBS)
30 + dnl Set install target and select SAPI
33 + PHP_SELECT_SAPI(fpm, program, $PHP_FPM_SAPI_FILES $PHP_FPM_CORE_FILES $PHP_FPM_TRACE_FILES, $PHP_FPM_CFLAGS, '$(SAPI_FPM_PATH)')
37 + BUILD_FPM="echo '\#! .' > php.sym && echo >>php.sym && nm -BCpg \`echo \$(PHP_GLOBAL_OBJS) \$(PHP_SAPI_OBJS) | sed 's/\([A-Za-z0-9_]*\)\.lo/\1.o/g'\` | \$(AWK) '{ if (((\$\$2 == \"T\") || (\$\$2 == \"D\") || (\$\$2 == \"B\")) && (substr(\$\$3,1,1) != \".\")) { print \$\$3 } }' | sort -u >> php.sym && \$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) -Wl,-brtl -Wl,-bE:php.sym \$(PHP_RPATHS) \$(PHP_GLOBAL_OBJS) \$(PHP_SAPI_OBJS) \$(EXTRA_LIBS) \$(SAPI_EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_FPM_PATH)"
40 + BUILD_FPM="\$(CC) \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(NATIVE_RPATHS) \$(PHP_GLOBAL_OBJS:.lo=.o) \$(PHP_SAPI_OBJS:.lo=.o) \$(PHP_FRAMEWORKS) \$(EXTRA_LIBS) \$(SAPI_EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_FPM_PATH)"
43 + BUILD_FPM="\$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \$(PHP_GLOBAL_OBJS) \$(PHP_SAPI_OBJS) \$(EXTRA_LIBS) \$(SAPI_EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_FPM_PATH)"
49 + PHP_SUBST(BUILD_FPM)
52 diff -Naur php-src-vanilla/sapi/fpm/ac/fpm_checks.m4 php-src/sapi/fpm/ac/fpm_checks.m4
53 --- php-src-vanilla/sapi/fpm/ac/fpm_checks.m4 1970-01-01 01:00:00.000000000 +0100
54 +++ php-src/sapi/fpm/ac/fpm_checks.m4 2009-10-18 21:05:39.310440424 +0100
60 +AC_DEFUN([AC_FPM_CHECKS],
68 +AC_DEFUN([AC_FPM_STDLIBS],
70 + AC_CHECK_FUNCS(setenv clearenv)
72 + AC_SEARCH_LIBS(socket, socket)
73 + AC_SEARCH_LIBS(inet_addr, nsl)
75 + AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h sys/uio.h])
76 + AC_CHECK_HEADERS([sys/select.h sys/socket.h sys/time.h])
77 + AC_CHECK_HEADERS([arpa/inet.h netinet/in.h])
80 +AC_DEFUN([AC_FPM_PRCTL],
82 + AC_MSG_CHECKING([for prctl])
84 + AC_TRY_COMPILE([ #include <sys/prctl.h> ], [prctl(0, 0, 0, 0, 0);], [
85 + AC_DEFINE([HAVE_PRCTL], 1, [do we have prctl?])
86 + AC_MSG_RESULT([yes])
92 +AC_DEFUN([AC_FPM_CLOCK],
94 + have_clock_gettime=no
96 + AC_MSG_CHECKING([for clock_gettime])
98 + AC_TRY_LINK([ #include <time.h> ], [struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);], [
99 + have_clock_gettime=yes
100 + AC_MSG_RESULT([yes])
102 + AC_MSG_RESULT([no])
105 + if test "$have_clock_gettime" = "no"; then
106 + AC_MSG_CHECKING([for clock_gettime in -lrt])
111 + AC_TRY_LINK([ #include <time.h> ], [struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);], [
112 + have_clock_gettime=yes
113 + AC_MSG_RESULT([yes])
116 + AC_MSG_RESULT([no])
120 + if test "$have_clock_gettime" = "yes"; then
121 + AC_DEFINE([HAVE_CLOCK_GETTIME], 1, [do we have clock_gettime?])
124 + have_clock_get_time=no
126 + if test "$have_clock_gettime" = "no"; then
127 + AC_MSG_CHECKING([for clock_get_time])
129 + AC_TRY_RUN([ #include <mach/mach.h>
130 + #include <mach/clock.h>
131 + #include <mach/mach_error.h>
135 + kern_return_t ret; clock_serv_t aClock; mach_timespec_t aTime;
136 + ret = host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &aClock);
138 + if (ret != KERN_SUCCESS) {
142 + ret = clock_get_time(aClock, &aTime);
143 + if (ret != KERN_SUCCESS) {
150 + have_clock_get_time=yes
151 + AC_MSG_RESULT([yes])
153 + AC_MSG_RESULT([no])
157 + if test "$have_clock_get_time" = "yes"; then
158 + AC_DEFINE([HAVE_CLOCK_GET_TIME], 1, [do we have clock_get_time?])
162 +AC_DEFUN([AC_FPM_TRACE],
165 + have_broken_ptrace=no
167 + AC_MSG_CHECKING([for ptrace])
170 + #include <sys/types.h>
171 + #include <sys/ptrace.h> ], [ptrace(0, 0, (void *) 0, 0);], [
173 + AC_MSG_RESULT([yes])
175 + AC_MSG_RESULT([no])
178 + if test "$have_ptrace" = "yes"; then
179 + AC_MSG_CHECKING([whether ptrace works])
182 + #include <unistd.h>
183 + #include <signal.h>
184 + #include <sys/wait.h>
185 + #include <sys/types.h>
186 + #include <sys/ptrace.h>
189 + #if !defined(PTRACE_ATTACH) && defined(PT_ATTACH)
190 + #define PTRACE_ATTACH PT_ATTACH
193 + #if !defined(PTRACE_DETACH) && defined(PT_DETACH)
194 + #define PTRACE_DETACH PT_DETACH
197 + #if !defined(PTRACE_PEEKDATA) && defined(PT_READ_D)
198 + #define PTRACE_PEEKDATA PT_READ_D
203 + long v1 = (unsigned int) -1; /* copy will fail if sizeof(long) == 8 and we've got "int ptrace()" */
208 + if ( (child = fork()) ) { /* parent */
211 + if (0 > ptrace(PTRACE_ATTACH, child, 0, 0)) {
215 + waitpid(child, &status, 0);
218 + struct ptrace_io_desc ptio = {
219 + .piod_op = PIOD_READ_D,
222 + .piod_len = sizeof(v1)
225 + if (0 > ptrace(PT_IO, child, (void *) &ptio, 0)) {
231 + v2 = ptrace(PTRACE_PEEKDATA, child, (void *) &v1, 0);
237 + ptrace(PTRACE_DETACH, child, (void *) 1, 0);
239 + kill(child, SIGKILL);
241 + return ret ? ret : (v1 != v2);
249 + AC_MSG_RESULT([yes])
252 + have_broken_ptrace=yes
253 + AC_MSG_RESULT([no])
257 + if test "$have_ptrace" = "yes"; then
258 + AC_DEFINE([HAVE_PTRACE], 1, [do we have ptrace?])
261 + have_mach_vm_read=no
263 + if test "$have_broken_ptrace" = "yes"; then
264 + AC_MSG_CHECKING([for mach_vm_read])
266 + AC_TRY_COMPILE([ #include <mach/mach.h>
267 + #include <mach/mach_vm.h>
269 + mach_vm_read((vm_map_t)0, (mach_vm_address_t)0, (mach_vm_size_t)0, (vm_offset_t *)0, (mach_msg_type_number_t*)0);
271 + have_mach_vm_read=yes
272 + AC_MSG_RESULT([yes])
274 + AC_MSG_RESULT([no])
278 + if test "$have_mach_vm_read" = "yes"; then
279 + AC_DEFINE([HAVE_MACH_VM_READ], 1, [do we have mach_vm_read?])
284 + if test -r /proc/$$/mem ; then
285 + proc_mem_file="mem"
287 + if test -r /proc/$$/as ; then
292 + if test -n "$proc_mem_file" ; then
293 + AC_MSG_CHECKING([for proc mem file])
296 + #define _GNU_SOURCE
297 + #define _FILE_OFFSET_BITS 64
298 + #if HAVE_INTTYPES_H
299 + #include <inttypes.h>
301 + #include <stdint.h>
304 + #include <unistd.h>
305 + #include <sys/types.h>
306 + #include <sys/stat.h>
311 + long v1 = (unsigned int) -1, v2 = 0;
314 + sprintf(buf, "/proc/%d/$proc_mem_file", getpid());
315 + fd = open(buf, O_RDONLY);
319 + if (sizeof(long) != pread(fd, &v2, sizeof(long), (uintptr_t) &v1)) {
327 + AC_MSG_RESULT([$proc_mem_file])
330 + AC_MSG_RESULT([no])
334 + if test -n "$proc_mem_file"; then
335 + AC_DEFINE_UNQUOTED([PROC_MEM_FILE], "$proc_mem_file", [/proc/pid/mem interface])
340 + if test "$have_ptrace" = "yes"; then
341 + fpm_trace_type=ptrace
343 + elif test -n "$proc_mem_file"; then
344 + fpm_trace_type=pread
346 + elif test "$have_mach_vm_read" = "yes" ; then
347 + fpm_trace_type=mach
350 + AC_MSG_ERROR([FPM Trace - ptrace, pread, or mach: could not be found])
355 diff -Naur php-src-vanilla/sapi/fpm/ac/fpm_conf.m4 php-src/sapi/fpm/ac/fpm_conf.m4
356 --- php-src-vanilla/sapi/fpm/ac/fpm_conf.m4 1970-01-01 01:00:00.000000000 +0100
357 +++ php-src/sapi/fpm/ac/fpm_conf.m4 2009-10-18 21:05:39.310440424 +0100
360 +AC_DEFUN([AC_FPM_ARGS],
362 + PHP_ARG_WITH(fpm-bin,,
363 + [ --with-fpm-bin[=PATH] Set the path for the php-fpm binary [/usr/local/bin/php-fpm]], yes, no)
365 + PHP_ARG_WITH(fpm-port,,
366 + [ --with-fpm-port[=PORT] Set the tcp port number to listen for cgi requests [9000]], yes, no)
368 + PHP_ARG_WITH(fpm-conf,,
369 + [ --with-fpm-conf[=PATH] Set the path for php-fpm configuration file [/etc/php-fpm.conf]], yes, no)
371 + PHP_ARG_WITH(fpm-init,,
372 + [ --with-fpm-init[=PATH] Set the path for php-fpm init file [/etc/init.d/php-fpm]], yes, no)
374 + PHP_ARG_WITH(fpm-log,,
375 + [ --with-fpm-log[=PATH] Set the path for php-fpm log file [/var/log/php-fpm.log]], yes, no)
377 + PHP_ARG_WITH(fpm-pid,,
378 + [ --with-fpm-pid[=PATH] Set the path for php-fpm pid file [/var/run/php-fpm.pid]], yes, no)
380 + PHP_ARG_WITH(fpm-user,,
381 + [ --with-fpm-user[=USER] Set the user for php-fpm to run as [nobody]], yes, no)
383 + PHP_ARG_WITH(fpm-group,,
384 + [ --with-fpm-group[=GRP] Set the group for php-fpm to run as. For a system user,
385 + this should be set to match the fpm username [nobody]], yes, no)
388 +AC_DEFUN([AC_FPM_VARS],
390 + fpm_prefix=$ac_default_prefix
391 + if test $prefix != "NONE" -a $prefix != "" -a $prefix != "no" ; then
397 + if test $exec_prefix = "NONE" -o $exec_prefix = "" -o $exec_prefix = "no" ; then
398 + exec_prefix=$fpm_prefix
401 + if test `echo "$bindir" | grep "exec_prefix"` ; then
402 + bindir=$exec_prefix/bin
405 + fpm_bin_prefix=$fpm_prefix/bin
406 + if test $bindir != "NONE" -a $bindir != "" -a $bindir != "no" ; then
407 + fpm_bin_prefix=$bindir
410 + if test -z "$PHP_FPM_BIN" -o "$PHP_FPM_BIN" = "yes" -o "$PHP_FPM_BIN" = "no"; then
411 + php_fpm_bin_path="$fpm_bin_prefix/php-fpm"
413 + php_fpm_bin_path="$PHP_FPM_BIN"
415 + php_fpm_bin=`basename $php_fpm_bin_path`
416 + php_fpm_bin_dir=`dirname $php_fpm_bin_path`
418 + if test -z "$PHP_FPM_PORT" -o "$PHP_FPM_PORT" = "yes" -o "$PHP_FPM_PORT" = "no"; then
419 + php_fpm_port="9000"
421 + php_fpm_port="$PHP_FPM_PORT"
424 + if test -z "$PHP_FPM_CONF" -o "$PHP_FPM_CONF" = "yes"; then
426 + freebsd*|dragonfly*) php_fpm_conf_path="/usr/local/etc/php-fpm.conf" ;;
427 + *) php_fpm_conf_path="/etc/php-fpm.conf" ;;
429 + elif test "$PHP_FPM_CONF" = "no"; then
430 + php_fpm_conf_path=""
432 + php_fpm_conf_path="$PHP_FPM_CONF"
434 + if test -z "$php_fpm_conf_path"; then
436 + php_fpm_conf_dir=""
438 + php_fpm_conf=`basename $php_fpm_conf_path`
439 + php_fpm_conf_dir=`dirname $php_fpm_conf_path`
442 + if test -z "$PHP_FPM_INIT" -o "$PHP_FPM_INIT" = "yes"; then
444 + openbsd*) php_fpm_init_path="" ;;
445 + netbsd*) php_fpm_init_path="/etc/rc.d/php-fpm" ;;
446 + *bsd*|dragonfly*) php_fpm_init_path="/usr/local/etc/rc.d/php-fpm" ;;
447 + *) php_fpm_init_path="/etc/init.d/php-fpm" ;;
449 + test -f /etc/arch-release && php_fpm_init_path="/etc/rc.d/php-fpm" # arch linux
451 + elif test "$PHP_FPM_INIT" = "no"; then
452 + php_fpm_init_path=""
454 + php_fpm_init_path="$PHP_FPM_INIT"
456 + if test -z "$php_fpm_init_path"; then
458 + php_fpm_init_dir=""
460 + php_fpm_init=`basename $php_fpm_init_path`
461 + php_fpm_init_dir=`dirname $php_fpm_init_path`
464 + if test -z "$PHP_FPM_LOG" -o "$PHP_FPM_LOG" = "yes" -o "$PHP_FPM_LOG" = "no"; then
465 + php_fpm_log_path="/var/log/php-fpm.log"
467 + php_fpm_log_path="$PHP_FPM_LOG"
469 + php_fpm_log_dir=`dirname $php_fpm_log_path`
471 + if test -z "$PHP_FPM_PID" -o "$PHP_FPM_PID" = "yes" -o "$PHP_FPM_PID" = "no"; then
472 + php_fpm_pid_path="/var/run/php-fpm.pid"
474 + php_fpm_pid_path="$PHP_FPM_PID"
476 + php_fpm_pid_dir=`dirname $php_fpm_pid_path`
478 + if test -z "$PHP_FPM_USER" -o "$PHP_FPM_USER" = "yes" -o "$PHP_FPM_USER" = "no"; then
479 + php_fpm_user="nobody"
481 + php_fpm_user="$PHP_FPM_USER"
484 + if test -z "$PHP_FPM_GROUP" -o "$PHP_FPM_GROUP" = "yes" -o "$PHP_FPM_GROUP" = "no"; then
485 + php_fpm_group="nobody"
487 + php_fpm_group="$PHP_FPM_GROUP"
491 + PHP_SUBST_OLD(fpm_version)
492 + PHP_SUBST_OLD(php_fpm_bin)
493 + PHP_SUBST_OLD(php_fpm_bin_dir)
494 + PHP_SUBST_OLD(php_fpm_bin_path)
495 + PHP_SUBST_OLD(php_fpm_port)
496 + PHP_SUBST_OLD(php_fpm_conf)
497 + PHP_SUBST_OLD(php_fpm_conf_dir)
498 + PHP_SUBST_OLD(php_fpm_conf_path)
499 + PHP_SUBST_OLD(php_fpm_init)
500 + PHP_SUBST_OLD(php_fpm_init_dir)
501 + PHP_SUBST_OLD(php_fpm_init_path)
502 + PHP_SUBST_OLD(php_fpm_log_dir)
503 + PHP_SUBST_OLD(php_fpm_log_path)
504 + PHP_SUBST_OLD(php_fpm_pid_dir)
505 + PHP_SUBST_OLD(php_fpm_pid_path)
506 + PHP_SUBST_OLD(php_fpm_user)
507 + PHP_SUBST_OLD(php_fpm_group)
510 + AC_DEFINE_UNQUOTED(PHP_FPM_VERSION, "$fpm_version", [fpm version])
511 + AC_DEFINE_UNQUOTED(PHP_FPM_BIN, "$php_fpm_bin", [fpm binary executable])
512 + AC_DEFINE_UNQUOTED(PHP_FPM_BIN_DIR, "$php_fpm_bin_dir", [fpm binary dir])
513 + AC_DEFINE_UNQUOTED(PHP_FPM_BIN_PATH, "$php_fpm_bin_path", [fpm bin file path])
514 + AC_DEFINE_UNQUOTED(PHP_FPM_PORT, "$php_fpm_port", [tcp port])
515 + AC_DEFINE_UNQUOTED(PHP_FPM_CONF, "$php_fpm_conf", [fpm conf file])
516 + AC_DEFINE_UNQUOTED(PHP_FPM_CONF_DIR, "$php_fpm_conf_dir", [fpm conf dir])
517 + AC_DEFINE_UNQUOTED(PHP_FPM_CONF_PATH, "$php_fpm_conf_path", [fpm conf file path])
518 + AC_DEFINE_UNQUOTED(PHP_FPM_INIT, "$php_fpm_init", [fpm init file])
519 + AC_DEFINE_UNQUOTED(PHP_FPM_INIT_DIR, "$php_fpm_init_dir", [fpm init dir])
520 + AC_DEFINE_UNQUOTED(PHP_FPM_INIT_PATH, "$php_fpm_init_path", [fpm init file path])
521 + AC_DEFINE_UNQUOTED(PHP_FPM_LOG_DIR, "$php_fpm_log_dir", [fpm log dir])
522 + AC_DEFINE_UNQUOTED(PHP_FPM_LOG_PATH, "$php_fpm_log_path", [fpm log file path])
523 + AC_DEFINE_UNQUOTED(PHP_FPM_PID_DIR, "$php_fpm_pid_dir", [fpm pid dir])
524 + AC_DEFINE_UNQUOTED(PHP_FPM_PID_PATH, "$php_fpm_pid_path", [fpm pid file path])
525 + AC_DEFINE_UNQUOTED(PHP_FPM_USER, "$php_fpm_user", [fpm user name])
526 + AC_DEFINE_UNQUOTED(PHP_FPM_GROUP, "$php_fpm_group", [fpm group name])
531 +AC_DEFUN([AC_FPM_OUTPUT],
533 + PHP_OUTPUT(sapi/fpm/php_fpm.conf:sapi/fpm/conf/php-fpm.conf.in)
534 + PHP_OUTPUT(sapi/fpm/init.d.php_fpm:sapi/fpm/conf/init.d.php-fpm.in)
535 + PHP_OUTPUT(sapi/fpm/nginx-site-conf.sample:sapi/fpm/conf/nginx-site-conf.sample.in)
536 + PHP_OUTPUT(sapi/fpm/$php_fpm_bin.1:sapi/fpm/man/php-fpm.1.in)
540 +AC_DEFUN([AC_FPM_CONF],
547 diff -Naur php-src-vanilla/sapi/fpm/ac/fpm_libevent.m4 php-src/sapi/fpm/ac/fpm_libevent.m4
548 --- php-src-vanilla/sapi/fpm/ac/fpm_libevent.m4 1970-01-01 01:00:00.000000000 +0100
549 +++ php-src/sapi/fpm/ac/fpm_libevent.m4 2009-10-18 21:05:39.310440424 +0100
551 +dnl @synopsis AC_LIB_EVENT([MINIMUM-VERSION],[REQUIRED-VERSION])
553 +dnl Test for the libevent library of a particular version (or newer).
554 +dnl Source: http://svn.apache.org/repos/asf/incubator/thrift/trunk/aclocal/ax_lib_event.m4
555 +dnl Modified: This file was modified for autoconf-2.13 and the PHP_ARG_WITH macro.
557 +dnl If no path to the installed libevent is given, the macro will first try
558 +dnl using no -I or -L flags, then searches under /usr, /usr/local, /opt,
559 +dnl and /opt/libevent.
560 +dnl If these all fail, it will try the $LIBEVENT_ROOT environment variable.
562 +dnl This macro requires that #include <sys/types.h> works and defines u_char.
564 +dnl This macro calls:
565 +dnl AC_SUBST(LIBEVENT_CFLAGS)
566 +dnl AC_SUBST(LIBEVENT_LIBS)
568 +dnl And (if libevent is found):
569 +dnl AC_DEFINE(HAVE_LIBEVENT)
571 +dnl It also leaves the shell variables "success" and "ac_have_libevent"
572 +dnl set to "yes" or "no".
574 +dnl NOTE: This macro does not currently work for cross-compiling,
575 +dnl but it can be easily modified to allow it. (grep "cross").
577 +dnl @category InstalledPackages
579 +dnl @version 2007-09-12
580 +dnl @license AllPermissive
582 +dnl Copyright (C) 2009 David Reiss
583 +dnl Copying and distribution of this file, with or without modification,
584 +dnl are permitted in any medium without royalty provided the copyright
585 +dnl notice and this notice are preserved.
587 +AC_DEFUN([AC_LIB_EVENT_DO_CHECK],
590 +CPPFLAGS_SAVED="$CPPFLAGS"
591 +LDFLAGS_SAVED="$LDFLAGS"
593 +LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH"
595 +# Set our flags if we are checking a specific directory.
596 +if test -n "$ac_libevent_path" ; then
597 + LIBEVENT_CPPFLAGS="-I$ac_libevent_path/include"
598 + LIBEVENT_LDFLAGS="-L$ac_libevent_path/lib"
599 + LD_LIBRARY_PATH="$ac_libevent_path/lib:$LD_LIBRARY_PATH"
601 + LIBEVENT_CPPFLAGS=""
602 + LIBEVENT_LDFLAGS=""
605 +# Required flag for libevent.
606 +LIBEVENT_LIBS="-levent"
608 +# Prepare the environment for compilation.
609 +CPPFLAGS="$CPPFLAGS $LIBEVENT_CPPFLAGS"
610 +LDFLAGS="$LDFLAGS $LIBEVENT_LDFLAGS"
611 +LIBS="$LIBS $LIBEVENT_LIBS"
615 +export LD_LIBRARY_PATH
619 +# Compile, link, and run the program. This checks:
620 +# - event.h is available for including.
621 +# - event_get_version() is available for linking.
622 +# - The event version string is lexicographically greater
623 +# than the required version.
625 +#include <sys/types.h>
628 +int main(int argc, char *argv[])
630 + const char* lib_version = event_get_version();
631 + const char* wnt_version = "$WANT_LIBEVENT_VERSION";
633 + /* If we reached the end of the want version. We have it. */
634 + if (*wnt_version == '\0' || *wnt_version == '-') {
637 + /* If the want version continues but the lib version does not, */
638 + /* we are missing a letter. We don't have it. */
639 + if (*lib_version == '\0' || *lib_version == '-') {
643 + /* In the 1.4 version numbering style, if there are more digits */
644 + /* in one version than the other, that one is higher. */
646 + for (lib_digits = 0;
647 + lib_version[lib_digits] >= '0' &&
648 + lib_version[lib_digits] <= '9';
652 + for (wnt_digits = 0;
653 + wnt_version[wnt_digits] >= '0' &&
654 + wnt_version[wnt_digits] <= '9';
657 + if (lib_digits > wnt_digits) {
660 + if (lib_digits < wnt_digits) {
663 + /* If we have greater than what we want. We have it. */
664 + if (*lib_version > *wnt_version) {
667 + /* If we have less, we don't. */
668 + if (*lib_version < *wnt_version) {
682 +CPPFLAGS="$CPPFLAGS_SAVED"
683 +LDFLAGS="$LDFLAGS_SAVED"
685 +LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED"
688 +AC_DEFUN([AC_LIB_EVENT],
691 +PHP_ARG_WITH(libevent,,
692 +[ --with-libevent[=PATH] Path to the libevent, needed for fpm SAPI [/usr/local]], yes, yes)
694 +if test "$PHP_LIBEVENT" != "no"; then
695 + LIBEVENT_MIN_VERSION=ifelse([$1], ,1.4.3,$1)
696 + LIBEVENT_REQ_VERSION=ifelse([$2], ,1.4.11,$2)
698 + # Default library search paths ($sys_lib_search_path_spec)
699 + AC_LIBTOOL_SYS_DYNAMIC_LINKER
701 + libevent_prefix=$ac_default_prefix
702 + if test $prefix != "NONE" -a $prefix != "" -a $prefix != "no" ; then
703 + libevent_prefix=$prefix
706 + if test "$PHP_LIBEVENT" = "yes"; then
707 + PHP_LIBEVENT=$libevent_prefix
710 + AC_MSG_CHECKING(for libevent >= $LIBEVENT_REQ_VERSION)
711 + for ac_libevent_path in "" $PHP_LIBEVENT /usr /usr/local /opt /opt/local /opt/libevent ; do
712 + WANT_LIBEVENT_VERSION="$LIBEVENT_REQ_VERSION"
713 + AC_LIB_EVENT_DO_CHECK
714 + if test "$success" = "yes"; then
718 + if test "$success" = "no"; then
721 + AC_MSG_WARN([Could not find libevent $LIBEVENT_REQ_VERSION.])
722 + AC_MSG_WARN([The use of earlier versions of libevent is not recommended])
723 + AC_MSG_WARN([and can result in unspecified or unsupported behaviour.])
725 + AC_MSG_CHECKING(for minimum libevent version >= $LIBEVENT_MIN_VERSION)
726 + for ac_libevent_path in "" $PHP_LIBEVENT /usr /usr/local /opt /opt/local /opt/libevent ; do
727 + WANT_LIBEVENT_VERSION="$LIBEVENT_MIN_VERSION"
728 + AC_LIB_EVENT_DO_CHECK
729 + if test "$success" = "yes"; then
733 + if test "$success" = "no"; then
736 + ac_have_libevent=no
737 + AC_MSG_WARN([Syntax:])
738 + AC_MSG_WARN([--with-libevent=yes|[path] - link to libevent.a (static library)])
739 + AC_MSG_WARN([--with-libevent=shared[,path] - link to libevent.so (shared library)])
740 + AC_MSG_ERROR([Libevent minimum version >= $LIBEVENT_MIN_VERSION could not be found.])
744 + if test "$ext_shared" = "yes"; then
745 + if test -n "$ac_libevent_path"; then
746 + LIBEVENT_LIBS="-L$ac_libevent_path/lib -levent"
748 + LIBEVENT_LIBS="-levent"
751 + libevent_a="libevent.a"
752 + if test -n "$ac_libevent_path"; then
753 + if test -f "$ac_libevent_path/lib/$libevent_a" ; then
754 + LIBEVENT_LIBS="$ac_libevent_path/lib/$libevent_a"
756 + if test -z "$LIBEVENT_LIBS"; then
758 + AC_MSG_WARN([libevent.a could not be found. We looked in:])
759 + AC_MSG_WARN([\"$ac_libevent_path\"])
762 + for search_path in $sys_lib_search_path_spec ; do
763 + if test -f "$search_path$libevent_a" ; then
764 + LIBEVENT_LIBS="$search_path$libevent_a"
768 + if test -z "$LIBEVENT_LIBS"; then
770 + AC_MSG_WARN([libevent.a could not be found. We looked in:])
771 + AC_MSG_WARN([\"$sys_lib_search_path_spec\"])
774 + if test -z "$LIBEVENT_LIBS"; then
775 + AC_MSG_WARN([Install libevent system-wide (make install)])
776 + AC_MSG_WARN([Syntax:])
777 + AC_MSG_WARN([--with-libevent=yes|[path] - link to libevent.a (static library)])
778 + AC_MSG_WARN([--with-libevent=shared[,path] - link to libevent.so (shared library)])
779 + AC_MSG_ERROR([libevent.a could not be found. Stop.])
783 + if test "$success" = "yes" ; then
785 + ac_have_libevent=yes
786 + AC_DEFINE(HAVE_LIBEVENT, 1, [define if libevent is available])
789 + if test -n "$ac_libevent_path"; then
790 + LIBEVENT_CFLAGS="-I$ac_libevent_path/include"
793 + AC_SUBST(LIBEVENT_CFLAGS)
794 + AC_SUBST(LIBEVENT_LIBS)
797 + AC_MSG_ERROR([FPM Requires Libevent. You must build this target --with-libevent. Stop.])
801 diff -Naur php-src-vanilla/sapi/fpm/ac/Makefile.frag php-src/sapi/fpm/ac/Makefile.frag
802 --- php-src-vanilla/sapi/fpm/ac/Makefile.frag 1970-01-01 01:00:00.000000000 +0100
803 +++ php-src/sapi/fpm/ac/Makefile.frag 2009-10-18 21:05:39.310440424 +0100
805 +fpm: $(SAPI_FPM_PATH)
807 +$(SAPI_FPM_PATH): $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(SAPI_EXTRA_DEPS)
810 +install: install-fpm
813 + @echo "Installing PHP FPM binary: $(INSTALL_ROOT)$(php_fpm_bin_path)"
814 + @$(mkinstalldirs) $(INSTALL_ROOT)$(php_fpm_bin_dir)
815 + @$(mkinstalldirs) $(INSTALL_ROOT)$(php_fpm_pid_dir)
816 + @$(mkinstalldirs) $(INSTALL_ROOT)$(php_fpm_log_dir)
817 + @$(INSTALL) -m 0755 $(SAPI_FPM_PATH) $(INSTALL_ROOT)$(php_fpm_bin_path)$(program_suffix)$(EXEEXT)
819 + @test "$(php_fpm_conf)" && \
820 + echo "Installing PHP FPM config: $(INSTALL_ROOT)$(php_fpm_conf_path)" && \
821 + $(mkinstalldirs) $(INSTALL_ROOT)$(php_fpm_conf_dir) || :
823 + @test "$(php_fpm_conf)" && \
824 + test -f "$(INSTALL_ROOT)$(php_fpm_conf_path)" && \
825 + $(INSTALL_DATA) --backup=numbered $(INSTALL_ROOT)$(php_fpm_conf_path) $(INSTALL_ROOT)$(php_fpm_conf_path).old || :
827 + @test "$(php_fpm_conf)" && \
828 + $(INSTALL_DATA) sapi/fpm/php_fpm.conf $(INSTALL_ROOT)$(php_fpm_conf_path).default && \
829 + ln -sf $(INSTALL_ROOT)$(php_fpm_conf_path).default $(INSTALL_ROOT)$(php_fpm_conf_path) || :
831 + @echo "Installing PHP FPM man page: $(INSTALL_ROOT)$(mandir)/man1/$(php_fpm_bin)$(program_suffix).1"
832 + @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1
833 + @$(INSTALL_DATA) sapi/fpm/$(php_fpm_bin).1 $(INSTALL_ROOT)$(mandir)/man1/$(php_fpm_bin)$(program_suffix).1
835 + @test "$(php_fpm_init)" && \
836 + echo "Installing PHP FPM init script: $(INSTALL_ROOT)$(php_fpm_init_path)" && \
837 + $(mkinstalldirs) $(INSTALL_ROOT)$(php_fpm_init_dir) && \
838 + $(INSTALL) -m 0755 sapi/fpm/init.d.php_fpm $(INSTALL_ROOT)$(php_fpm_init_path) || :
840 + @test -d /etc/nginx/ && \
841 + echo "Installing NGINX sample config: /etc/nginx/nginx-site-conf.sample" && \
842 + $(mkinstalldirs) $(INSTALL_ROOT)/etc/nginx && \
843 + $(INSTALL_DATA) -b sapi/fpm/nginx-site-conf.sample $(INSTALL_ROOT)/etc/nginx/nginx-site-conf.sample || :
845 + @test -d /usr/local/etc/nginx/ && \
846 + echo "Installing NGINX sample config: /usr/local/etc/nginx/nginx-site-conf.sample" && \
847 + $(mkinstalldirs) $(INSTALL_ROOT)/usr/local/etc/nginx && \
848 + $(INSTALL_DATA) -b sapi/fpm/nginx-site-conf.sample $(INSTALL_ROOT)/usr/local/etc/nginx/nginx-site-conf.sample || :
850 + @test -d /usr/local/nginx/conf/ && \
851 + echo "Installing NGINX sample config: /usr/local/nginx/conf/nginx-site-conf.sample" && \
852 + $(mkinstalldirs) $(INSTALL_ROOT)/usr/local/nginx/conf && \
853 + $(INSTALL_DATA) -b sapi/fpm/nginx-site-conf.sample $(INSTALL_ROOT)/usr/local/nginx/conf/nginx-site-conf.sample || :
856 + @echo "*** FPM Installation complete. ***"
859 + @test "$(php_fpm_init)" && \
861 + echo "\`update-rc.d $(php_fpm_init) defaults; invoke-rc.d $(php_fpm_init) start\`" && \
863 + echo "or system equivalent to start the $(php_fpm_init) service." && \
866 diff -Naur php-src-vanilla/sapi/fpm/cgi/cgi_main.c php-src/sapi/fpm/cgi/cgi_main.c
867 --- php-src-vanilla/sapi/fpm/cgi/cgi_main.c 1970-01-01 01:00:00.000000000 +0100
868 +++ php-src/sapi/fpm/cgi/cgi_main.c 2009-10-18 21:05:39.302497288 +0100
871 + +----------------------------------------------------------------------+
873 + +----------------------------------------------------------------------+
874 + | Copyright (c) 1997-2008 The PHP Group |
875 + +----------------------------------------------------------------------+
876 + | This source file is subject to version 3.01 of the PHP license, |
877 + | that is bundled with this package in the file LICENSE, and is |
878 + | available through the world-wide-web at the following url: |
879 + | http://www.php.net/license/3_01.txt |
880 + | If you did not receive a copy of the PHP license and are unable to |
881 + | obtain it through the world-wide-web, please send a note to |
882 + | license@php.net so we can mail you a copy immediately. |
883 + +----------------------------------------------------------------------+
884 + | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
885 + | Stig Bakken <ssb@php.net> |
886 + | Zeev Suraski <zeev@zend.com> |
887 + | FastCGI: Ben Mansell <php@slimyhorror.com> |
888 + | Shane Caraveo <shane@caraveo.com> |
889 + | Dmitry Stogov <dmitry@zend.com> |
890 + +----------------------------------------------------------------------+
896 +#include <php_globals.h>
897 +#include <php_variables.h>
898 +#include <zend_modules.h>
905 +#include "win32/time.h"
906 +#include "win32/signal.h"
907 +#include <process.h>
910 +#include <sys/time.h>
921 +#if HAVE_SYS_TYPES_H
922 +#include <sys/types.h>
925 +#include <sys/wait.h>
931 +#include <zend_extensions.h>
932 +#include <php_ini.h>
933 +#include <php_main.h>
934 +#include <fopen_wrappers.h>
935 +#include <ext/standard/php_standard.h>
939 +#include "win32/php_registry.h"
943 +#include <unixlib/local.h>
944 +int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS;
947 +#include "zend_compile.h"
948 +#include "zend_execute.h"
949 +#include "zend_highlight.h"
950 +#include "zend_indent.h"
952 +#include "php_getopt.h"
954 +#include "fastcgi.h"
956 +#ifdef FPM_AUTOCONFIG_H
957 +#include <fpm_autoconfig.h>
959 +#include <php_config.h>
961 +#include <fpm/fpm.h>
962 +#include <fpm/fpm_request.h>
965 +static void (*php_php_import_environment_variables)(zval *array_ptr TSRMLS_DC);
967 +static int parent = 1;
969 +static int request_body_fd;
971 +static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC);
973 +static char *php_optarg = NULL;
974 +static int php_optind = 1;
975 +static zend_module_entry cgi_module_entry;
977 +static const opt_struct OPTIONS[] = {
978 + {'a', 0, "interactive"},
979 + {'b', 1, "bindpath"},
980 + {'C', 0, "no-chdir"},
981 + {'c', 1, "php-ini"},
982 + {'d', 1, "define"},
983 + {'e', 0, "profile-info"},
987 + {'l', 0, "syntax-check"},
988 + {'m', 0, "modules"},
989 + {'n', 0, "no-php-ini"},
990 + {'q', 0, "no-header"},
991 + {'s', 0, "syntax-highlight"},
992 + {'s', 0, "syntax-highlighting"},
994 + {'?', 0, "usage"},/* help alias (both '?' and 'usage') */
995 + {'v', 0, "version"},
997 + {'y', 1, "fpm-config"},
998 + {'z', 1, "zend-extension"},
999 + {'-', 0, NULL} /* end of args */
1002 +typedef struct _php_cgi_globals_struct {
1003 + zend_bool rfc2616_headers;
1005 + zend_bool check_shebang_line;
1006 +#if ENABLE_PATHINFO_CHECK
1007 + zend_bool fix_pathinfo;
1009 + zend_bool fcgi_logging;
1011 + zend_bool impersonate;
1013 + char *error_header;
1014 +} php_cgi_globals_struct;
1017 +static int php_cgi_globals_id;
1018 +#define CGIG(v) TSRMG(php_cgi_globals_id, php_cgi_globals_struct *, v)
1020 +static php_cgi_globals_struct php_cgi_globals;
1021 +#define CGIG(v) (php_cgi_globals.v)
1025 +#define TRANSLATE_SLASHES(path) \
1027 + char *tmp = path; \
1029 + if (*tmp == '\\') *tmp = '/'; \
1034 +#define TRANSLATE_SLASHES(path)
1037 +static int print_module_info(zend_module_entry *module, void *arg TSRMLS_DC)
1039 + php_printf("%s\n", module->name);
1043 +static int module_name_cmp(const void *a, const void *b TSRMLS_DC)
1045 + Bucket *f = *((Bucket **) a);
1046 + Bucket *s = *((Bucket **) b);
1048 + return strcasecmp(((zend_module_entry *)f->pData)->name,
1049 + ((zend_module_entry *)s->pData)->name);
1052 +static void print_modules(TSRMLS_D)
1054 + HashTable sorted_registry;
1055 + zend_module_entry tmp;
1057 + zend_hash_init(&sorted_registry, 50, NULL, NULL, 1);
1058 + zend_hash_copy(&sorted_registry, &module_registry, NULL, &tmp, sizeof(zend_module_entry));
1059 + zend_hash_sort(&sorted_registry, zend_qsort, module_name_cmp, 0 TSRMLS_CC);
1060 + zend_hash_apply_with_argument(&sorted_registry, (apply_func_arg_t) print_module_info, NULL TSRMLS_CC);
1061 + zend_hash_destroy(&sorted_registry);
1064 +static int print_extension_info(zend_extension *ext, void *arg TSRMLS_DC)
1066 + php_printf("%s\n", ext->name);
1070 +static int extension_name_cmp(const zend_llist_element **f,
1071 + const zend_llist_element **s TSRMLS_DC)
1073 + return strcmp(((zend_extension *)(*f)->data)->name,
1074 + ((zend_extension *)(*s)->data)->name);
1077 +static void print_extensions(TSRMLS_D)
1079 + zend_llist sorted_exts;
1081 + zend_llist_copy(&sorted_exts, &zend_extensions);
1082 + sorted_exts.dtor = NULL;
1083 + zend_llist_sort(&sorted_exts, extension_name_cmp TSRMLS_CC);
1084 + zend_llist_apply_with_argument(&sorted_exts, (llist_apply_with_arg_func_t) print_extension_info, NULL TSRMLS_CC);
1085 + zend_llist_destroy(&sorted_exts);
1088 +#ifndef STDOUT_FILENO
1089 +#define STDOUT_FILENO 1
1092 +static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC)
1096 + if (fcgi_is_fastcgi()) {
1097 + fcgi_request *request = (fcgi_request*) SG(server_context);
1098 + long ret = fcgi_write(request, FCGI_STDOUT, str, str_length);
1104 + ret = write(STDOUT_FILENO, str, str_length);
1105 + if (ret <= 0) return 0;
1109 +static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
1111 + const char *ptr = str;
1112 + uint remaining = str_length;
1115 + while (remaining > 0) {
1116 + ret = sapi_cgibin_single_write(ptr, remaining TSRMLS_CC);
1118 + php_handle_aborted_connection();
1119 + return str_length - remaining;
1125 + return str_length;
1129 +static void sapi_cgibin_flush(void *server_context)
1131 + if (fcgi_is_fastcgi()) {
1132 + fcgi_request *request = (fcgi_request*) server_context;
1137 + request && !fcgi_flush(request, 0)) {
1138 + php_handle_aborted_connection();
1142 + if (fflush(stdout) == EOF) {
1143 + php_handle_aborted_connection();
1147 +#define SAPI_CGI_MAX_HEADER_LENGTH 1024
1149 +typedef struct _http_error {
1154 +static const http_error http_error_codes[] = {
1155 + {100, "Continue"},
1156 + {101, "Switching Protocols"},
1159 + {202, "Accepted"},
1160 + {203, "Non-Authoritative Information"},
1161 + {204, "No Content"},
1162 + {205, "Reset Content"},
1163 + {206, "Partial Content"},
1164 + {300, "Multiple Choices"},
1165 + {301, "Moved Permanently"},
1166 + {302, "Moved Temporarily"},
1167 + {303, "See Other"},
1168 + {304, "Not Modified"},
1169 + {305, "Use Proxy"},
1170 + {400, "Bad Request"},
1171 + {401, "Unauthorized"},
1172 + {402, "Payment Required"},
1173 + {403, "Forbidden"},
1174 + {404, "Not Found"},
1175 + {405, "Method Not Allowed"},
1176 + {406, "Not Acceptable"},
1177 + {407, "Proxy Authentication Required"},
1178 + {408, "Request Time-out"},
1179 + {409, "Conflict"},
1181 + {411, "Length Required"},
1182 + {412, "Precondition Failed"},
1183 + {413, "Request Entity Too Large"},
1184 + {414, "Request-URI Too Large"},
1185 + {415, "Unsupported Media Type"},
1186 + {500, "Internal Server Error"},
1187 + {501, "Not Implemented"},
1188 + {502, "Bad Gateway"},
1189 + {503, "Service Unavailable"},
1190 + {504, "Gateway Time-out"},
1191 + {505, "HTTP Version not supported"},
1195 +static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
1197 + char buf[SAPI_CGI_MAX_HEADER_LENGTH];
1198 + sapi_header_struct *h;
1199 + zend_llist_position pos;
1200 + zend_bool ignore_status = 0;
1201 + int response_status = SG(sapi_headers).http_response_code;
1203 + if (SG(request_info).no_headers == 1) {
1204 + return SAPI_HEADER_SENT_SUCCESSFULLY;
1207 + if (CGIG(nph) || SG(sapi_headers).http_response_code != 200)
1210 + zend_bool has_status = 0;
1212 + if (CGIG(rfc2616_headers) && SG(sapi_headers).http_status_line) {
1214 + len = slprintf(buf, SAPI_CGI_MAX_HEADER_LENGTH, "%s\r\n", SG(sapi_headers).http_status_line);
1215 + if ((s = strchr(SG(sapi_headers).http_status_line, ' '))) {
1216 + response_status = atoi((s + 1));
1219 + if (len > SAPI_CGI_MAX_HEADER_LENGTH) {
1220 + len = SAPI_CGI_MAX_HEADER_LENGTH;
1226 + if (SG(sapi_headers).http_status_line &&
1227 + (s = strchr(SG(sapi_headers).http_status_line, ' ')) != 0 &&
1228 + (s - SG(sapi_headers).http_status_line) >= 5 &&
1229 + strncasecmp(SG(sapi_headers).http_status_line, "HTTP/", 5) == 0) {
1230 + len = slprintf(buf, sizeof(buf), "Status:%s\r\n", s);
1231 + response_status = atoi((s + 1));
1233 + h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
1235 + if (h->header_len > sizeof("Status:")-1 &&
1236 + strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0) {
1240 + h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
1242 + if (!has_status) {
1243 + http_error *err = (http_error*)http_error_codes;
1245 + while (err->code != 0) {
1246 + if (err->code == SG(sapi_headers).http_response_code) {
1252 + len = slprintf(buf, sizeof(buf), "Status: %d %s\r\n", SG(sapi_headers).http_response_code, err->msg);
1254 + len = slprintf(buf, sizeof(buf), "Status: %d\r\n", SG(sapi_headers).http_response_code);
1259 + if (!has_status) {
1260 + PHPWRITE_H(buf, len);
1261 + ignore_status = 1;
1265 + h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
1267 + /* prevent CRLFCRLF */
1268 + if (h->header_len) {
1269 + if (h->header_len > sizeof("Status:")-1 &&
1270 + strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0) {
1271 + if (!ignore_status) {
1272 + ignore_status = 1;
1273 + PHPWRITE_H(h->header, h->header_len);
1274 + PHPWRITE_H("\r\n", 2);
1276 + } else if (response_status == 304 && h->header_len > sizeof("Content-Type:")-1 &&
1277 + strncasecmp(h->header, "Content-Type:", sizeof("Content-Type:")-1) == 0) {
1278 + h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
1281 + PHPWRITE_H(h->header, h->header_len);
1282 + PHPWRITE_H("\r\n", 2);
1285 + h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
1287 + PHPWRITE_H("\r\n", 2);
1289 + return SAPI_HEADER_SENT_SUCCESSFULLY;
1293 +static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
1295 + int read_bytes=0, tmp_read_bytes;
1297 + count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
1298 + while (read_bytes < count_bytes) {
1299 + if (fcgi_is_fastcgi()) {
1300 + fcgi_request *request = (fcgi_request*) SG(server_context);
1302 + if (request_body_fd == -1) {
1303 + char *request_body_filename = sapi_cgibin_getenv((char *) "REQUEST_BODY_FILE",
1304 + sizeof("REQUEST_BODY_FILE")-1 TSRMLS_CC);
1306 + if (request_body_filename && *request_body_filename) {
1307 + request_body_fd = open(request_body_filename, O_RDONLY);
1309 + if (0 > request_body_fd) {
1310 + php_error(E_WARNING, "REQUEST_BODY_FILE: open('%s') failed: %s (%d)",
1311 + request_body_filename, strerror(errno), errno);
1317 + /* If REQUEST_BODY_FILE variable not available - read post body from fastcgi stream */
1318 + if (request_body_fd < 0) {
1319 + tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes);
1321 + tmp_read_bytes = read(request_body_fd, buffer + read_bytes, count_bytes - read_bytes);
1324 + tmp_read_bytes = read(0, buffer + read_bytes, count_bytes - read_bytes);
1327 + if (tmp_read_bytes <= 0) {
1330 + read_bytes += tmp_read_bytes;
1332 + return read_bytes;
1335 +static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
1337 + /* when php is started by mod_fastcgi, no regular environment
1338 + is provided to PHP. It is always sent to PHP at the start
1339 + of a request. So we have to do our own lookup to get env
1340 + vars. This could probably be faster somehow. */
1341 + if (fcgi_is_fastcgi()) {
1342 + fcgi_request *request = (fcgi_request*) SG(server_context);
1343 + return fcgi_getenv(request, name, name_len);
1345 + /* if cgi, or fastcgi and not found in fcgi env
1346 + check the regular environment */
1347 + return getenv(name);
1350 +static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC)
1353 +#if !HAVE_SETENV || !HAVE_UNSETENV
1361 + name_len = strlen(name);
1363 + /* when php is started by mod_fastcgi, no regular environment
1364 + is provided to PHP. It is always sent to PHP at the start
1365 + of a request. So we have to do our own lookup to get env
1366 + vars. This could probably be faster somehow. */
1367 + if (fcgi_is_fastcgi()) {
1368 + fcgi_request *request = (fcgi_request*) SG(server_context);
1369 + return fcgi_putenv(request, name, name_len, value);
1373 + setenv(name, value, 1);
1382 +#if !HAVE_SETENV || !HAVE_UNSETENV
1383 + /* if cgi, or fastcgi and not found in fcgi env
1384 + check the regular environment
1385 + this leaks, but it's only cgi anyway, we'll fix
1388 + len = name_len + (value ? strlen(value) : 0) + sizeof("=") + 2;
1389 + buf = (char *) malloc(len);
1390 + if (buf == NULL) {
1391 + return getenv(name);
1396 + len = slprintf(buf, len - 1, "%s=%s", name, value);
1402 + len = slprintf(buf, len - 1, "%s=", name);
1406 + return getenv(name);
1409 +static char *sapi_cgi_read_cookies(TSRMLS_D)
1411 + return sapi_cgibin_getenv((char *) "HTTP_COOKIE", sizeof("HTTP_COOKIE")-1 TSRMLS_CC);
1414 +void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
1416 + if (PG(http_globals)[TRACK_VARS_ENV] &&
1417 + array_ptr != PG(http_globals)[TRACK_VARS_ENV] &&
1418 + Z_TYPE_P(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY &&
1419 + zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV])) > 0) {
1420 + zval_dtor(array_ptr);
1421 + *array_ptr = *PG(http_globals)[TRACK_VARS_ENV];
1422 + INIT_PZVAL(array_ptr);
1423 + zval_copy_ctor(array_ptr);
1425 + } else if (PG(http_globals)[TRACK_VARS_SERVER] &&
1426 + array_ptr != PG(http_globals)[TRACK_VARS_SERVER] &&
1427 + Z_TYPE_P(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY &&
1428 + zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER])) > 0) {
1429 + zval_dtor(array_ptr);
1430 + *array_ptr = *PG(http_globals)[TRACK_VARS_SERVER];
1431 + INIT_PZVAL(array_ptr);
1432 + zval_copy_ctor(array_ptr);
1436 + /* call php's original import as a catch-all */
1437 + php_php_import_environment_variables(array_ptr TSRMLS_CC);
1439 + if (fcgi_is_fastcgi()) {
1440 + fcgi_request *request = (fcgi_request*) SG(server_context);
1442 + int magic_quotes_gpc = PG(magic_quotes_gpc);
1446 + int filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER;
1448 + /* turn off magic_quotes while importing environment variables */
1449 + PG(magic_quotes_gpc) = 0;
1450 + for (zend_hash_internal_pointer_reset_ex(&request->env, &pos);
1451 + zend_hash_get_current_key_ex(&request->env, &var, &var_len, &idx, 0, &pos) == HASH_KEY_IS_STRING &&
1452 + zend_hash_get_current_data_ex(&request->env, (void **) &val, &pos) == SUCCESS;
1453 + zend_hash_move_forward_ex(&request->env, &pos)) {
1454 + unsigned int new_val_len;
1455 + if (sapi_module.input_filter(filter_arg, var, val, strlen(*val), &new_val_len TSRMLS_CC)) {
1456 + php_register_variable_safe(var, *val, new_val_len, array_ptr TSRMLS_CC);
1459 + PG(magic_quotes_gpc) = magic_quotes_gpc;
1463 +static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
1465 + unsigned int php_self_len;
1468 + /* In CGI mode, we consider the environment to be a part of the server
1471 + php_import_environment_variables(track_vars_array TSRMLS_CC);
1473 +#if ENABLE_PATHINFO_CHECK
1474 + if (CGIG(fix_pathinfo)) {
1475 + char *script_name = SG(request_info).request_uri;
1476 + unsigned int script_name_len = script_name ? strlen(script_name) : 0;
1477 + char *path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
1478 + unsigned int path_info_len = path_info ? strlen(path_info) : 0;
1480 + php_self_len = script_name_len + path_info_len;
1481 + php_self = emalloc(php_self_len + 1);
1482 + if (script_name) {
1483 + memcpy(php_self, script_name, script_name_len + 1);
1486 + memcpy(php_self + script_name_len, path_info, path_info_len + 1);
1489 + /* Build the special-case PHP_SELF variable for the CGI version */
1490 + if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) {
1491 + php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC);
1498 + php_self = SG(request_info).request_uri ? SG(request_info).request_uri : "";
1499 + php_self_len = strlen(php_self);
1500 + if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) {
1501 + php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC);
1505 +static void sapi_cgi_log_message(char *message)
1509 + if (fcgi_is_fastcgi() && CGIG(fcgi_logging)) {
1510 + fcgi_request *request;
1512 + request = (fcgi_request*) SG(server_context);
1514 + int len = strlen(message);
1515 + char *buf = malloc(len+2);
1517 + memcpy(buf, message, len);
1518 + memcpy(buf + len, "\n", sizeof("\n"));
1519 + fcgi_write(request, FCGI_STDERR, buf, len+1);
1522 + fprintf(stderr, "%s\n", message);
1524 + /* ignore return code */
1526 + fprintf(stderr, "%s\n", message);
1529 +static int sapi_cgi_deactivate(TSRMLS_D)
1531 + /* flush only when SAPI was started. The reasons are:
1532 + 1. SAPI Deactivate is called from two places: module init and request shutdown
1533 + 2. When the first call occurs and the request is not set up, flush fails on
1536 + if (SG(sapi_started)) {
1537 + sapi_cgibin_flush(SG(server_context));
1542 +static int php_cgi_startup(sapi_module_struct *sapi_module)
1544 + if (php_module_startup(sapi_module, &cgi_module_entry, 1) == FAILURE) {
1551 +/* {{{ sapi_module_struct cgi_sapi_module
1553 +static sapi_module_struct cgi_sapi_module = {
1554 + "cgi-fcgi", /* name */
1555 + "CGI/FastCGI", /* pretty name */
1557 + php_cgi_startup, /* startup */
1558 + php_module_shutdown_wrapper, /* shutdown */
1560 + NULL, /* activate */
1561 + sapi_cgi_deactivate, /* deactivate */
1563 + sapi_cgibin_ub_write, /* unbuffered write */
1564 + sapi_cgibin_flush, /* flush */
1565 + NULL, /* get uid */
1566 + sapi_cgibin_getenv, /* getenv */
1568 + php_error, /* error handler */
1570 + NULL, /* header handler */
1571 + sapi_cgi_send_headers, /* send headers handler */
1572 + NULL, /* send header handler */
1574 + sapi_cgi_read_post, /* read POST data */
1575 + sapi_cgi_read_cookies, /* read Cookies */
1577 + sapi_cgi_register_variables, /* register server variables */
1578 + sapi_cgi_log_message, /* Log message */
1579 + NULL, /* Get request time */
1581 + STANDARD_SAPI_MODULE_PROPERTIES
1585 +/* {{{ php_cgi_usage
1587 +static void php_cgi_usage(char *argv0)
1591 + prog = strrchr(argv0, '/');
1598 + php_printf("Usage: %s [options]\n"
1600 + " -C Do not chdir to the script's directory\n"
1601 + " -c <path>|<file> Look for php.ini file in this directory\n"
1602 + " -n No php.ini file will be used\n"
1603 + " -d foo[=bar] Define INI entry foo with value 'bar'\n"
1604 + " -e Generate extended information for debugger/profiler\n"
1606 + " -i PHP information\n"
1607 + " -m Show compiled in modules\n"
1608 + " -v Version number\n"
1609 + " -y, --fpm-config <file>\n"
1610 + " Specify alternative path to FastCGI process manager config file.\n"
1611 + " -z <file> Load Zend extension <file>.\n"
1617 +/* {{{ is_valid_path
1619 + * some server configurations allow '..' to slip through in the
1620 + * translated path. We'll just refuse to handle such a path.
1622 +static int is_valid_path(const char *path)
1629 + p = strstr(path, "..");
1631 + if ((p == path || IS_SLASH(*(p-1))) &&
1632 + (*(p+2) == 0 || IS_SLASH(*(p+2)))) {
1636 + p = strstr(p+1, "..");
1640 + if (IS_SLASH(*(p-1)) &&
1641 + (*(p+2) == 0 || IS_SLASH(*(p+2)))) {
1650 +/* {{{ init_request_info
1652 + initializes request_info structure
1654 + specificly in this section we handle proper translations
1658 + derived from the portion of the URI path following
1659 + the script name but preceding any query data
1663 + derived by taking any path-info component of the
1664 + request URI and performing any virtual-to-physical
1665 + translation appropriate to map it onto the server's
1666 + document repository structure
1668 + empty if PATH_INFO is empty
1670 + The env var PATH_TRANSLATED **IS DIFFERENT** than the
1671 + request_info.path_translated variable, the latter should
1672 + match SCRIPT_FILENAME instead.
1675 + set to a URL path that could identify the CGI script
1676 + rather than the interpreter. PHP_SELF is set to this.
1679 + uri section following the domain:port part of a URI
1682 + The virtual-to-physical translation of SCRIPT_NAME (as per
1685 + These settings are documented at
1686 + http://cgi-spec.golux.com/
1689 + Based on the following URL request:
1691 + http://localhost/info.php/test?a=b
1693 + should produce, which btw is the same as if
1694 + we were running under mod_cgi on apache (ie. not
1695 + using ScriptAlias directives):
1698 + PATH_TRANSLATED=/docroot/test
1699 + SCRIPT_NAME=/info.php
1700 + REQUEST_URI=/info.php/test?a=b
1701 + SCRIPT_FILENAME=/docroot/info.php
1704 + but what we get is (cgi/mod_fastcgi under apache):
1706 + PATH_INFO=/info.php/test
1707 + PATH_TRANSLATED=/docroot/info.php/test
1708 + SCRIPT_NAME=/php/php-cgi (from the Action setting I suppose)
1709 + REQUEST_URI=/info.php/test?a=b
1710 + SCRIPT_FILENAME=/path/to/php/bin/php-cgi (Action setting translated)
1713 + Comments in the code below refer to using the above URL in a request
1716 +static void init_request_info(TSRMLS_D)
1718 + char *env_script_filename = sapi_cgibin_getenv("SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1 TSRMLS_CC);
1719 + char *env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED", sizeof("PATH_TRANSLATED")-1 TSRMLS_CC);
1720 + char *script_path_translated = env_script_filename;
1723 + /* some broken servers do not have script_filename or argv0
1724 + an example, IIS configured in some ways. then they do more
1725 + broken stuff and set path_translated to the cgi script location */
1726 + if (!script_path_translated && env_path_translated) {
1727 + script_path_translated = env_path_translated;
1731 + /* initialize the defaults */
1732 + SG(request_info).path_translated = NULL;
1733 + SG(request_info).request_method = NULL;
1734 + SG(request_info).proto_num = 1000;
1735 + SG(request_info).query_string = NULL;
1736 + SG(request_info).request_uri = NULL;
1737 + SG(request_info).content_type = NULL;
1738 + SG(request_info).content_length = 0;
1739 + SG(sapi_headers).http_response_code = 200;
1741 + /* script_path_translated being set is a good indication that
1742 + we are running in a cgi environment, since it is always
1743 + null otherwise. otherwise, the filename
1744 + of the script will be retreived later via argc/argv */
1745 + if (script_path_translated) {
1747 + char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1 TSRMLS_CC);
1748 + char *content_type = sapi_cgibin_getenv("CONTENT_TYPE", sizeof("CONTENT_TYPE")-1 TSRMLS_CC);
1749 + char *env_path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
1750 + char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
1751 +#if ENABLE_PATHINFO_CHECK
1753 + char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL", sizeof("REDIRECT_URL")-1 TSRMLS_CC);
1754 + char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")-1 TSRMLS_CC);
1755 + int script_path_translated_len;
1757 + /* Hack for buggy IIS that sets incorrect PATH_INFO */
1758 + char *env_server_software = sapi_cgibin_getenv("SERVER_SOFTWARE", sizeof("SERVER_SOFTWARE")-1 TSRMLS_CC);
1759 + if (env_server_software &&
1760 + env_script_name &&
1762 + strncmp(env_server_software, "Microsoft-IIS", sizeof("Microsoft-IIS")-1) == 0 &&
1763 + strncmp(env_path_info, env_script_name, strlen(env_script_name)) == 0) {
1764 + env_path_info = _sapi_cgibin_putenv("ORIG_PATH_INFO", env_path_info TSRMLS_CC);
1765 + env_path_info += strlen(env_script_name);
1766 + if (*env_path_info == 0) {
1767 + env_path_info = NULL;
1769 + env_path_info = _sapi_cgibin_putenv("PATH_INFO", env_path_info TSRMLS_CC);
1772 + if (CGIG(fix_pathinfo)) {
1773 + char *real_path = NULL;
1774 + char *orig_path_translated = env_path_translated;
1775 + char *orig_path_info = env_path_info;
1776 + char *orig_script_name = env_script_name;
1777 + char *orig_script_filename = env_script_filename;
1779 + if (!env_document_root && PG(doc_root)) {
1780 + env_document_root = _sapi_cgibin_putenv("DOCUMENT_ROOT", PG(doc_root) TSRMLS_CC);
1782 + TRANSLATE_SLASHES(env_document_root);
1785 + if (env_path_translated != NULL && env_redirect_url != NULL) {
1787 + pretty much apache specific. If we have a redirect_url
1788 + then our script_filename and script_name point to the
1791 + script_path_translated = env_path_translated;
1792 + /* we correct SCRIPT_NAME now in case we don't have PATH_INFO */
1793 + env_script_name = env_redirect_url;
1797 + /* Convert path to unix format*/
1798 + __riscosify_control |= __RISCOSIFY_DONT_CHECK_DIR;
1799 + script_path_translated = __unixify(script_path_translated, 0, NULL, 1, 0);
1803 + * if the file doesn't exist, try to extract PATH_INFO out
1804 + * of it by stat'ing back through the '/'
1805 + * this fixes url's like /info.php/test
1807 + if (script_path_translated &&
1808 + (script_path_translated_len = strlen(script_path_translated)) > 0 &&
1809 + (script_path_translated[script_path_translated_len-1] == '/' ||
1811 + script_path_translated[script_path_translated_len-1] == '\\' ||
1813 + (real_path = tsrm_realpath(script_path_translated, NULL TSRMLS_CC)) == NULL)) {
1814 + char *pt = estrndup(script_path_translated, script_path_translated_len);
1815 + int len = script_path_translated_len;
1818 + while ((ptr = strrchr(pt, '/')) || (ptr = strrchr(pt, '\\'))) {
1820 + if (stat(pt, &st) == 0 && S_ISREG(st.st_mode)) {
1822 + * okay, we found the base script!
1823 + * work out how many chars we had to strip off;
1824 + * then we can modify PATH_INFO
1827 + * we now have the makings of
1829 + * SCRIPT_FILENAME=/docroot/info.php
1831 + * we now need to figure out what docroot is.
1832 + * if DOCUMENT_ROOT is set, this is easy, otherwise,
1833 + * we have to play the game of hide and seek to figure
1834 + * out what SCRIPT_NAME should be
1836 + int slen = len - strlen(pt);
1837 + int pilen = env_path_info ? strlen(env_path_info) : 0;
1838 + char *path_info = env_path_info ? env_path_info + pilen - slen : NULL;
1840 + if (orig_path_info != path_info) {
1841 + if (orig_path_info) {
1844 + _sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
1845 + old = path_info[0];
1847 + if (!orig_script_name ||
1848 + strcmp(orig_script_name, env_path_info) != 0) {
1849 + if (orig_script_name) {
1850 + _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
1852 + SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_path_info TSRMLS_CC);
1854 + SG(request_info).request_uri = orig_script_name;
1856 + path_info[0] = old;
1858 + env_path_info = _sapi_cgibin_putenv("PATH_INFO", path_info TSRMLS_CC);
1860 + if (!orig_script_filename ||
1861 + strcmp(orig_script_filename, pt) != 0) {
1862 + if (orig_script_filename) {
1863 + _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
1865 + script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", pt TSRMLS_CC);
1867 + TRANSLATE_SLASHES(pt);
1869 + /* figure out docroot
1870 + SCRIPT_FILENAME minus SCRIPT_NAME
1873 + if (env_document_root) {
1874 + int l = strlen(env_document_root);
1875 + int path_translated_len = 0;
1876 + char *path_translated = NULL;
1878 + if (l && env_document_root[l - 1] == '/') {
1882 + /* we have docroot, so we should have:
1883 + * DOCUMENT_ROOT=/docroot
1884 + * SCRIPT_FILENAME=/docroot/info.php
1887 + /* PATH_TRANSLATED = DOCUMENT_ROOT + PATH_INFO */
1888 + path_translated_len = l + (env_path_info ? strlen(env_path_info) : 0);
1889 + path_translated = (char *) emalloc(path_translated_len + 1);
1890 + memcpy(path_translated, env_document_root, l);
1891 + if (env_path_info) {
1892 + memcpy(path_translated + l, env_path_info, (path_translated_len - l));
1894 + path_translated[path_translated_len] = '\0';
1895 + if (orig_path_translated) {
1896 + _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
1898 + env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
1899 + efree(path_translated);
1900 + } else if (env_script_name &&
1901 + strstr(pt, env_script_name)
1903 + /* PATH_TRANSLATED = PATH_TRANSLATED - SCRIPT_NAME + PATH_INFO */
1904 + int ptlen = strlen(pt) - strlen(env_script_name);
1905 + int path_translated_len = ptlen + (env_path_info ? strlen(env_path_info) : 0);
1906 + char *path_translated = NULL;
1908 + path_translated = (char *) emalloc(path_translated_len + 1);
1909 + memcpy(path_translated, pt, ptlen);
1910 + if (env_path_info) {
1911 + memcpy(path_translated + ptlen, env_path_info, path_translated_len - ptlen);
1913 + path_translated[path_translated_len] = '\0';
1914 + if (orig_path_translated) {
1915 + _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
1917 + env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
1918 + efree(path_translated);
1925 + * if we stripped out all the '/' and still didn't find
1926 + * a valid path... we will fail, badly. of course we would
1927 + * have failed anyway... we output 'no input file' now.
1929 + if (orig_script_filename) {
1930 + _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
1932 + script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", NULL TSRMLS_CC);
1933 + SG(sapi_headers).http_response_code = 404;
1935 + if (!SG(request_info).request_uri) {
1936 + if (!orig_script_name ||
1937 + strcmp(orig_script_name, env_script_name) != 0) {
1938 + if (orig_script_name) {
1939 + _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
1941 + SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
1943 + SG(request_info).request_uri = orig_script_name;
1949 + if (is_valid_path(script_path_translated)) {
1950 + SG(request_info).path_translated = estrdup(script_path_translated);
1953 + /* make sure path_info/translated are empty */
1954 + if (!orig_script_filename ||
1955 + (script_path_translated != orig_script_filename &&
1956 + strcmp(script_path_translated, orig_script_filename) != 0)) {
1957 + if (orig_script_filename) {
1958 + _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
1960 + script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", script_path_translated TSRMLS_CC);
1962 + if (env_redirect_url) {
1963 + if (orig_path_info) {
1964 + _sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
1965 + _sapi_cgibin_putenv("PATH_INFO", NULL TSRMLS_CC);
1967 + if (orig_path_translated) {
1968 + _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
1969 + _sapi_cgibin_putenv("PATH_TRANSLATED", NULL TSRMLS_CC);
1972 + if (env_script_name != orig_script_name) {
1973 + if (orig_script_name) {
1974 + _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
1976 + SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
1978 + SG(request_info).request_uri = env_script_name;
1980 + if (is_valid_path(script_path_translated)) {
1981 + SG(request_info).path_translated = estrdup(script_path_translated);
1987 + /* pre 4.3 behaviour, shouldn't be used but provides BC */
1988 + if (env_path_info) {
1989 + SG(request_info).request_uri = env_path_info;
1991 + SG(request_info).request_uri = env_script_name;
1994 + if (env_path_translated) {
1995 + script_path_translated = env_path_translated;
1998 + if (is_valid_path(script_path_translated)) {
1999 + SG(request_info).path_translated = estrdup(script_path_translated);
2001 +#if ENABLE_PATHINFO_CHECK
2004 + SG(request_info).request_method = sapi_cgibin_getenv("REQUEST_METHOD", sizeof("REQUEST_METHOD")-1 TSRMLS_CC);
2005 + /* FIXME - Work out proto_num here */
2006 + SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", sizeof("QUERY_STRING")-1 TSRMLS_CC);
2007 + SG(request_info).content_type = (content_type ? content_type : "" );
2008 + SG(request_info).content_length = (content_length ? atoi(content_length) : 0);
2010 + /* The CGI RFC allows servers to pass on unvalidated Authorization data */
2011 + auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION")-1 TSRMLS_CC);
2012 + php_handle_auth_data(auth TSRMLS_CC);
2019 + STD_PHP_INI_ENTRY("cgi.rfc2616_headers", "0", PHP_INI_ALL, OnUpdateBool, rfc2616_headers, php_cgi_globals_struct, php_cgi_globals)
2020 + STD_PHP_INI_ENTRY("cgi.nph", "0", PHP_INI_ALL, OnUpdateBool, nph, php_cgi_globals_struct, php_cgi_globals)
2021 + STD_PHP_INI_ENTRY("cgi.check_shebang_line", "1", PHP_INI_SYSTEM, OnUpdateBool, check_shebang_line, php_cgi_globals_struct, php_cgi_globals)
2022 +#if ENABLE_PATHINFO_CHECK
2023 + STD_PHP_INI_ENTRY("cgi.fix_pathinfo", "1", PHP_INI_SYSTEM, OnUpdateBool, fix_pathinfo, php_cgi_globals_struct, php_cgi_globals)
2025 + STD_PHP_INI_ENTRY("fastcgi.logging", "1", PHP_INI_SYSTEM, OnUpdateBool, fcgi_logging, php_cgi_globals_struct, php_cgi_globals)
2027 + STD_PHP_INI_ENTRY("fastcgi.impersonate", "0", PHP_INI_SYSTEM, OnUpdateBool, impersonate, php_cgi_globals_struct, php_cgi_globals)
2029 + STD_PHP_INI_ENTRY("fastcgi.error_header", NULL, PHP_INI_SYSTEM, OnUpdateString, error_header, php_cgi_globals_struct, php_cgi_globals)
2032 +/* {{{ php_cgi_globals_ctor
2034 +static void php_cgi_globals_ctor(php_cgi_globals_struct *php_cgi_globals TSRMLS_DC)
2036 + php_cgi_globals->rfc2616_headers = 0;
2037 + php_cgi_globals->nph = 0;
2038 + php_cgi_globals->check_shebang_line = 1;
2039 +#if ENABLE_PATHINFO_CHECK
2040 + php_cgi_globals->fix_pathinfo = 1;
2042 + php_cgi_globals->fcgi_logging = 1;
2044 + php_cgi_globals->impersonate = 0;
2046 + php_cgi_globals->error_header = NULL;
2050 +/* {{{ PHP_MINIT_FUNCTION
2052 +static PHP_MINIT_FUNCTION(cgi)
2055 + ts_allocate_id(&php_cgi_globals_id, sizeof(php_cgi_globals_struct), (ts_allocate_ctor) php_cgi_globals_ctor, NULL);
2057 + php_cgi_globals_ctor(&php_cgi_globals TSRMLS_CC);
2059 + REGISTER_INI_ENTRIES();
2064 +/* {{{ PHP_MSHUTDOWN_FUNCTION
2066 +static PHP_MSHUTDOWN_FUNCTION(cgi)
2068 + UNREGISTER_INI_ENTRIES();
2073 +/* {{{ PHP_MINFO_FUNCTION
2075 +static PHP_MINFO_FUNCTION(cgi)
2077 + DISPLAY_INI_ENTRIES();
2079 + php_info_print_table_start();
2080 + php_info_print_table_row(2, "php-fpm", "active");
2081 + php_info_print_table_row(2, "php-fpm version", PHP_FPM_VERSION);
2082 + php_info_print_table_end();
2087 +PHP_FUNCTION(fastcgi_finish_request)
2089 + fcgi_request *request = (fcgi_request*) SG(server_context);
2091 + if (fcgi_is_fastcgi() && request->fd >= 0) {
2093 + php_end_ob_buffers(1 TSRMLS_CC);
2094 + php_header(TSRMLS_C);
2096 + fcgi_flush(request, 1);
2097 + fcgi_close(request, 0, 0);
2105 +function_entry cgi_fcgi_sapi_functions[] = {
2106 + PHP_FE(fastcgi_finish_request, NULL)
2107 + {NULL, NULL, NULL}
2110 +static zend_module_entry cgi_module_entry = {
2111 + STANDARD_MODULE_HEADER,
2113 + cgi_fcgi_sapi_functions,
2115 + PHP_MSHUTDOWN(cgi),
2120 + STANDARD_MODULE_PROPERTIES
2125 +int main(int argc, char *argv[])
2127 + int free_query_string = 0;
2128 + int exit_status = SUCCESS;
2130 + zend_file_handle file_handle = {};
2132 +/* temporary locals */
2133 + int orig_optind = php_optind;
2134 + char *orig_optarg = php_optarg;
2135 + int ini_entries_len = 0;
2137 +/* end of temporary locals */
2142 + int max_requests = 500;
2145 + fcgi_request request;
2146 + char *fpm_config = NULL;
2148 +#ifdef HAVE_SIGNAL_H
2149 +#if defined(SIGPIPE) && defined(SIG_IGN)
2150 + signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so
2151 + that sockets created via fsockopen()
2152 + don't kill PHP if the remote site
2153 + closes it. in apache|apxs mode apache
2154 + does that for us! thies@thieso.net
2160 + tsrm_startup(1, 1, 0, NULL);
2161 + tsrm_ls = ts_resource(0);
2164 + sapi_startup(&cgi_sapi_module);
2165 + cgi_sapi_module.php_ini_path_override = NULL;
2168 + _fmode = _O_BINARY; /* sets default for file streams to binary */
2169 + setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
2170 + setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
2171 + setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
2174 + while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0)) != -1) {
2178 + if (cgi_sapi_module.php_ini_path_override) {
2179 + free(cgi_sapi_module.php_ini_path_override);
2181 + cgi_sapi_module.php_ini_path_override = strdup(php_optarg);
2185 + cgi_sapi_module.php_ini_ignore = 1;
2188 + case 'C': /* don't chdir to the script directory */
2189 + SG(options) |= SAPI_OPTION_NO_CHDIR;
2193 + /* define ini entries on command line */
2194 + int len = strlen(php_optarg);
2197 + if ((val = strchr(php_optarg, '='))) {
2199 + if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
2200 + cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
2201 + memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
2202 + ini_entries_len += (val - php_optarg);
2203 + memcpy(cgi_sapi_module.ini_entries + ini_entries_len, "\"", 1);
2204 + ini_entries_len++;
2205 + memcpy(cgi_sapi_module.ini_entries + ini_entries_len, val, len - (val - php_optarg));
2206 + ini_entries_len += len - (val - php_optarg);
2207 + memcpy(cgi_sapi_module.ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
2208 + ini_entries_len += sizeof("\n\0\"") - 2;
2210 + cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("\n\0"));
2211 + memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, len);
2212 + memcpy(cgi_sapi_module.ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
2213 + ini_entries_len += len + sizeof("\n\0") - 2;
2216 + cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
2217 + memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, len);
2218 + memcpy(cgi_sapi_module.ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
2219 + ini_entries_len += len + sizeof("=1\n\0") - 2;
2225 + fpm_config = php_optarg;
2228 + case 'e': /* enable extended info output */
2229 + /* CG(extended_info) = 1; */ /* 5_2 */
2230 + CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO; /* 5_3 */
2233 + case 'm': /* list compiled in modules */
2234 + cgi_sapi_module.startup(&cgi_sapi_module);
2235 + php_output_startup();
2236 + php_output_activate(TSRMLS_C);
2237 + SG(headers_sent) = 1;
2238 + php_printf("[PHP Modules]\n");
2239 + print_modules(TSRMLS_C);
2240 + php_printf("\n[Zend Modules]\n");
2241 + print_extensions(TSRMLS_C);
2243 + php_end_ob_buffers(1 TSRMLS_CC);
2247 + case 'i': /* php info & quit */
2248 + cgi_sapi_module.startup(&cgi_sapi_module);
2249 + if (php_request_startup(TSRMLS_C) == FAILURE) {
2250 + SG(server_context) = NULL;
2251 + php_module_shutdown(TSRMLS_C);
2254 + SG(headers_sent) = 1;
2255 + SG(request_info).no_headers = 1;
2256 + php_print_info(0xFFFFFFFF TSRMLS_CC);
2257 + php_request_shutdown((void *) 0);
2263 + cgi_sapi_module.startup(&cgi_sapi_module);
2264 + php_output_startup();
2265 + php_output_activate(TSRMLS_C);
2266 + SG(headers_sent) = 1;
2267 + php_cgi_usage(argv[0]);
2268 + php_end_ob_buffers(1 TSRMLS_CC);
2272 + case 'v': /* show php version & quit */
2273 + cgi_sapi_module.startup(&cgi_sapi_module);
2274 + if (php_request_startup(TSRMLS_C) == FAILURE) {
2275 + SG(server_context) = NULL;
2276 + php_module_shutdown(TSRMLS_C);
2279 + SG(headers_sent) = 1;
2280 + SG(request_info).no_headers = 1;
2284 + php_printf("PHP %s with Suhosin-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2009 The PHP Group\n%s", PHP_VERSION, SUHOSIN_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
2286 + php_printf("PHP %s with Suhosin-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2009 The PHP Group\n%s", PHP_VERSION, SUHOSIN_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
2290 + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2009 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
2292 + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2009 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
2295 + php_request_shutdown((void *) 0);
2302 + php_optind = orig_optind;
2303 + php_optarg = orig_optarg;
2306 + SG(request_info).path_translated = NULL;
2309 + cgi_sapi_module.executable_location = argv[0];
2311 + /* startup after we get the above ini override se we get things right */
2312 + if (cgi_sapi_module.startup(&cgi_sapi_module) == FAILURE) {
2319 + if (0 > fpm_init(argc, argv, fpm_config)) {
2323 + fcgi_fd = fpm_run(&max_requests);
2327 + fcgi_set_is_fastcgi(1);
2329 + /* make php call us to get _ENV vars */
2330 + php_php_import_environment_variables = php_import_environment_variables;
2331 + php_import_environment_variables = cgi_php_import_environment_variables;
2333 + /* library is already initialized, now init our request */
2334 + fcgi_init_request(&request, fcgi_fd);
2338 + /* start of FAST CGI loop */
2339 + /* Initialise FastCGI request structure */
2341 + /* attempt to set security impersonation for fastcgi
2342 + will only happen on NT based OS, others will ignore it. */
2343 + if (fastcgi && CGIG(impersonate)) {
2344 + fcgi_impersonate();
2347 + while (fcgi_accept_request(&request) >= 0) {
2349 + request_body_fd = -1;
2351 + SG(server_context) = (void *) &request;
2353 + init_request_info(TSRMLS_C);
2355 + CG(interactive) = 0;
2357 + fpm_request_info();
2360 + we never take stdin if we're (f)cgi, always
2361 + rely on the web server giving us the info
2362 + we need in the environment.
2364 + if (SG(request_info).path_translated) {
2365 + file_handle.type = ZEND_HANDLE_FILENAME;
2366 + file_handle.filename = SG(request_info).path_translated;
2367 + file_handle.handle.fp = NULL;
2369 + file_handle.opened_path = NULL;
2370 + file_handle.free_filename = 0;
2372 + /* request startup only after we've done all we can to
2373 + get path_translated */
2374 + if (php_request_startup(TSRMLS_C) == FAILURE) {
2375 + fcgi_finish_request(&request);
2376 + SG(server_context) = NULL;
2377 + php_module_shutdown(TSRMLS_C);
2382 + at this point path_translated will be set if:
2383 + 1. we are running from shell and got filename was there
2384 + 2. we are running as cgi or fastcgi
2387 + if (SG(request_info).path_translated) {
2388 + if (!php_check_open_basedir(SG(request_info).path_translated TSRMLS_CC)) {
2389 + retval = php_fopen_primary_script(&file_handle TSRMLS_CC);
2393 + if we are unable to open path_translated and we are not
2394 + running from shell (so fp == NULL), then fail.
2396 + if (retval == FAILURE && file_handle.handle.fp == NULL) {
2397 + if (errno == EACCES) {
2398 + SG(sapi_headers).http_response_code = 403;
2399 + PUTS("Access denied.\n");
2401 + SG(sapi_headers).http_response_code = 404;
2402 + PUTS("No input file specified.\n");
2404 + /* we want to serve more requests if this is fastcgi
2405 + so cleanup and continue, request shutdown is
2407 + goto fastcgi_request_done;
2409 + STR_FREE(SG(request_info).path_translated);
2411 + if (free_query_string && SG(request_info).query_string) {
2412 + free(SG(request_info).query_string);
2413 + SG(request_info).query_string = NULL;
2416 + php_request_shutdown((void *) 0);
2417 + SG(server_context) = NULL;
2418 + php_module_shutdown(TSRMLS_C);
2426 + fpm_request_executing();
2428 + php_execute_script(&file_handle TSRMLS_CC);
2430 +fastcgi_request_done:
2432 + if (request_body_fd != -1) close(request_body_fd);
2434 + request_body_fd = -2;
2437 + char *path_translated;
2439 + /* Go through this trouble so that the memory manager doesn't warn
2440 + * about SG(request_info).path_translated leaking
2442 + if (SG(request_info).path_translated) {
2443 + path_translated = strdup(SG(request_info).path_translated);
2444 + STR_FREE(SG(request_info).path_translated);
2445 + SG(request_info).path_translated = path_translated;
2448 + if (EG(exit_status) == 255) {
2449 + if (CGIG(error_header) && *CGIG(error_header)) {
2450 + sapi_header_line ctr = {0};
2452 + ctr.line = CGIG(error_header);
2453 + ctr.line_len = strlen(CGIG(error_header));
2454 + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
2458 + php_request_shutdown((void *) 0);
2459 + if (exit_status == 0) {
2460 + exit_status = EG(exit_status);
2463 + if (SG(request_info).path_translated) {
2464 + free(SG(request_info).path_translated);
2465 + SG(request_info).path_translated = NULL;
2467 + if (free_query_string && SG(request_info).query_string) {
2468 + free(SG(request_info).query_string);
2469 + SG(request_info).query_string = NULL;
2475 + if (max_requests && (requests == max_requests)) {
2476 + fcgi_finish_request(&request);
2480 + /* end of fastcgi loop */
2485 + if (fcgi_in_shutdown() || /* graceful shutdown by a signal */
2486 + (max_requests && (requests == max_requests)) /* we were told to process max_requests and we are done */
2491 + exit_status = 255;
2494 + if (cgi_sapi_module.php_ini_path_override) {
2495 + free(cgi_sapi_module.php_ini_path_override);
2497 + if (cgi_sapi_module.ini_entries) {
2498 + free(cgi_sapi_module.ini_entries);
2501 + exit_status = 255;
2506 + SG(server_context) = NULL;
2507 + php_module_shutdown(TSRMLS_C);
2511 + /*tsrm_shutdown();*/
2514 +#if defined(PHP_WIN32) && ZEND_DEBUG && 0
2515 + _CrtDumpMemoryLeaks();
2518 + return exit_status;
2523 + * Local variables:
2525 + * c-basic-offset: 4
2527 + * vim600: sw=4 ts=4 fdm=marker
2528 + * vim<600: sw=4 ts=4
2530 diff -Naur php-src-vanilla/sapi/fpm/cgi/CREDITS php-src/sapi/fpm/cgi/CREDITS
2531 --- php-src-vanilla/sapi/fpm/cgi/CREDITS 1970-01-01 01:00:00.000000000 +0100
2532 +++ php-src/sapi/fpm/cgi/CREDITS 2009-10-18 21:05:39.302497288 +0100
2535 +Rasmus Lerdorf, Stig Bakken, Shane Caraveo, Dmitry Stogov
2536 diff -Naur php-src-vanilla/sapi/fpm/cgi/fastcgi.c php-src/sapi/fpm/cgi/fastcgi.c
2537 --- php-src-vanilla/sapi/fpm/cgi/fastcgi.c 1970-01-01 01:00:00.000000000 +0100
2538 +++ php-src/sapi/fpm/cgi/fastcgi.c 2009-10-18 21:05:39.302497288 +0100
2541 + +----------------------------------------------------------------------+
2543 + +----------------------------------------------------------------------+
2544 + | Copyright (c) 1997-2008 The PHP Group |
2545 + +----------------------------------------------------------------------+
2546 + | This source file is subject to version 3.01 of the PHP license, |
2547 + | that is bundled with this package in the file LICENSE, and is |
2548 + | available through the world-wide-web at the following url: |
2549 + | http://www.php.net/license/3_01.txt |
2550 + | If you did not receive a copy of the PHP license and are unable to |
2551 + | obtain it through the world-wide-web, please send a note to |
2552 + | license@php.net so we can mail you a copy immediately. |
2553 + +----------------------------------------------------------------------+
2554 + | Authors: Dmitry Stogov <dmitry@zend.com> |
2555 + +----------------------------------------------------------------------+
2561 +#include "fastcgi.h"
2563 +#include <string.h>
2564 +#include <stdlib.h>
2566 +#include <stdarg.h>
2569 +#ifdef FPM_AUTOCONFIG_H
2570 +#include <fpm_autoconfig.h>
2572 +#include <php_config.h>
2574 +#include <fpm/fpm.h>
2575 +#include <fpm/fpm_request.h>
2579 +#include <windows.h>
2581 + typedef unsigned int in_addr_t;
2583 + struct sockaddr_un {
2585 + char sun_path[MAXPATHLEN];
2588 + static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
2589 + static int is_impersonate = 0;
2591 +#define FCGI_LOCK(fd) \
2592 + if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
2594 + while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
2595 + if (in_shutdown) return -1; \
2597 + if (ret == WAIT_FAILED) { \
2598 + fprintf(stderr, "WaitForSingleObject() failed\n"); \
2603 +#define FCGI_UNLOCK(fd) \
2604 + if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
2605 + ReleaseMutex(fcgi_accept_mutex); \
2610 +# include <sys/types.h>
2611 +# include <sys/stat.h>
2612 +# include <unistd.h>
2613 +# include <fcntl.h>
2614 +# include <sys/socket.h>
2615 +# include <sys/un.h>
2616 +# include <netinet/in.h>
2617 +# include <arpa/inet.h>
2618 +# include <netdb.h>
2619 +# include <signal.h>
2621 +# define closesocket(s) close(s)
2623 +# if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
2624 +# include <sys/poll.h>
2626 +# if defined(HAVE_SYS_SELECT_H)
2627 +# include <sys/select.h>
2630 +#ifndef INADDR_NONE
2631 +#define INADDR_NONE ((unsigned long) -1)
2634 +# ifndef HAVE_SOCKLEN_T
2635 + typedef unsigned int socklen_t;
2638 +# ifdef USE_LOCKING
2639 +# define FCGI_LOCK(fd) \
2641 + struct flock lock; \
2642 + lock.l_type = F_WRLCK; \
2643 + lock.l_start = 0; \
2644 + lock.l_whence = SEEK_SET; \
2646 + if (fcntl(fd, F_SETLKW, &lock) != -1) { \
2648 + } else if (errno != EINTR || in_shutdown) { \
2653 +# define FCGI_UNLOCK(fd) \
2655 + int orig_errno = errno; \
2657 + struct flock lock; \
2658 + lock.l_type = F_UNLCK; \
2659 + lock.l_start = 0; \
2660 + lock.l_whence = SEEK_SET; \
2662 + if (fcntl(fd, F_SETLK, &lock) != -1) { \
2664 + } else if (errno != EINTR) { \
2668 + errno = orig_errno; \
2671 +# define FCGI_LOCK(fd)
2672 +# define FCGI_UNLOCK(fd)
2677 +typedef union _sa_t {
2678 + struct sockaddr sa;
2679 + struct sockaddr_un sa_unix;
2680 + struct sockaddr_in sa_inet;
2683 +static HashTable *fcgi_mgmt_vars;
2685 +static int is_initialized = 0;
2686 +static int is_fastcgi = 0;
2687 +static int in_shutdown = 0;
2688 +static in_addr_t *allowed_clients = NULL;
2692 +static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
2694 + HANDLE shutdown_event = (HANDLE) arg;
2695 + WaitForSingleObject(shutdown_event, INFINITE);
2702 +static void fcgi_signal_handler(int signo)
2704 + if (signo == SIGUSR1 || signo == SIGTERM) {
2709 +static void fcgi_setup_signals(void)
2711 + struct sigaction new_sa, old_sa;
2713 + sigemptyset(&new_sa.sa_mask);
2714 + new_sa.sa_flags = 0;
2715 + new_sa.sa_handler = fcgi_signal_handler;
2716 + sigaction(SIGUSR1, &new_sa, NULL);
2717 + sigaction(SIGTERM, &new_sa, NULL);
2718 + sigaction(SIGPIPE, NULL, &old_sa);
2719 + if (old_sa.sa_handler == SIG_DFL) {
2720 + sigaction(SIGPIPE, &new_sa, NULL);
2725 +int fcgi_in_shutdown(void)
2727 + return in_shutdown;
2730 +int fcgi_init(void)
2732 + if (!is_initialized) {
2733 + fcgi_mgmt_vars = pemalloc(sizeof(HashTable), 1);
2734 + zend_hash_init(fcgi_mgmt_vars, 3, NULL, fcgi_free_mgmt_var_cb, 1);
2735 + fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, "1", sizeof("1")-1);
2736 + fcgi_set_mgmt_var("FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, "1", sizeof("1")-1);
2737 + fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS")-1, "0", sizeof("0")-1);
2740 + /* TODO: Support for TCP sockets */
2743 + if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
2744 + fprintf(stderr, "Error starting Windows Sockets. Error: %d", WSAGetLastError());
2748 + is_initialized = 1;
2750 + if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
2751 + (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) &&
2752 + (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)) {
2754 + DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
2755 + HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
2757 + SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
2759 + str = getenv("_FCGI_SHUTDOWN_EVENT_");
2760 + if (str != NULL) {
2761 + HANDLE shutdown_event = (HANDLE) atoi(str);
2762 + if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
2763 + shutdown_event, 0, NULL)) {
2767 + str = getenv("_FCGI_MUTEX_");
2768 + if (str != NULL) {
2769 + fcgi_accept_mutex = (HANDLE) atoi(str);
2771 + return is_fastcgi = 1;
2773 + return is_fastcgi = 0;
2777 + socklen_t len = sizeof(sa);
2779 + is_initialized = 1;
2781 + if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
2782 + fcgi_setup_signals();
2783 + return is_fastcgi = 1;
2785 + return is_fastcgi = 0;
2788 + fcgi_set_allowed_clients(getenv("FCGI_WEB_SERVER_ADDRS"));
2791 + return is_fastcgi;
2795 +int fcgi_is_fastcgi(void)
2797 + if (!is_initialized) {
2798 + return fcgi_init();
2800 + return is_fastcgi;
2804 +void fcgi_set_is_fastcgi(int new_value)
2806 + is_fastcgi = new_value;
2809 +void fcgi_set_in_shutdown(int new_value)
2811 + in_shutdown = new_value;
2814 +void fcgi_shutdown(void)
2816 + if (is_initialized) {
2817 + zend_hash_destroy(fcgi_mgmt_vars);
2818 + pefree(fcgi_mgmt_vars, 1);
2822 + if (allowed_clients) {
2823 + free(allowed_clients);
2824 + allowed_clients = 0;
2829 +/* Do some black magic with the NT security API.
2830 + * We prepare a DACL (Discretionary Access Control List) so that
2831 + * we, the creator, are allowed all access, while "Everyone Else"
2832 + * is only allowed to read and write to the pipe.
2833 + * This avoids security issues on shared hosts where a luser messes
2834 + * with the lower-level pipe settings and screws up the FastCGI service.
2836 +static PACL prepare_named_pipe_acl(PSECURITY_DESCRIPTOR sd, LPSECURITY_ATTRIBUTES sa)
2838 + DWORD req_acl_size;
2839 + char everyone_buf[32], owner_buf[32];
2840 + PSID sid_everyone, sid_owner;
2841 + SID_IDENTIFIER_AUTHORITY
2842 + siaWorld = SECURITY_WORLD_SID_AUTHORITY,
2843 + siaCreator = SECURITY_CREATOR_SID_AUTHORITY;
2846 + sid_everyone = (PSID)&everyone_buf;
2847 + sid_owner = (PSID)&owner_buf;
2849 + req_acl_size = sizeof(ACL) +
2850 + (2 * ((sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + GetSidLengthRequired(1)));
2852 + acl = malloc(req_acl_size);
2854 + if (acl == NULL) {
2858 + if (!InitializeSid(sid_everyone, &siaWorld, 1)) {
2861 + *GetSidSubAuthority(sid_everyone, 0) = SECURITY_WORLD_RID;
2863 + if (!InitializeSid(sid_owner, &siaCreator, 1)) {
2866 + *GetSidSubAuthority(sid_owner, 0) = SECURITY_CREATOR_OWNER_RID;
2868 + if (!InitializeAcl(acl, req_acl_size, ACL_REVISION)) {
2872 + if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_WRITE, sid_everyone)) {
2876 + if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, sid_owner)) {
2880 + if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
2884 + if (!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE)) {
2888 + sa->lpSecurityDescriptor = sd;
2898 +void fcgi_set_allowed_clients(char *ip)
2908 + if (*cur == ',') n++;
2911 + if (allowed_clients) free(allowed_clients);
2912 + allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
2916 + end = strchr(cur, ',');
2921 + allowed_clients[n] = inet_addr(cur);
2922 + if (allowed_clients[n] == INADDR_NONE) {
2923 + fprintf(stderr, "Wrong IP address '%s' in FCGI_WEB_SERVER_ADDRS\n", cur);
2928 + allowed_clients[n] = INADDR_NONE;
2933 +static int is_port_number(const char *bindpath)
2935 + while (*bindpath) {
2936 + if (*bindpath < '0' || *bindpath > '9') {
2944 +int fcgi_listen(const char *path, int backlog)
2948 + char host[MAXPATHLEN];
2950 + int listen_socket;
2952 + socklen_t sock_len;
2953 +#ifdef SO_REUSEADDR
2961 + if ((s = strchr(path, ':'))) {
2963 + if (port != 0 && (s-path) < MAXPATHLEN) {
2964 + strncpy(host, path, s-path);
2965 + host[s-path] = '\0';
2968 + } else if (is_port_number(path)) {
2969 + port = atoi(path);
2976 + /* Prepare socket address */
2978 + memset(&sa.sa_inet, 0, sizeof(sa.sa_inet));
2979 + sa.sa_inet.sin_family = AF_INET;
2980 + sa.sa_inet.sin_port = htons(port);
2981 + sock_len = sizeof(sa.sa_inet);
2983 + if (!*host || !strncmp(host, "*", sizeof("*")-1)) {
2984 + sa.sa_inet.sin_addr.s_addr = htonl(INADDR_ANY);
2986 + sa.sa_inet.sin_addr.s_addr = inet_addr(host);
2987 + if (sa.sa_inet.sin_addr.s_addr == INADDR_NONE) {
2988 + struct hostent *hep;
2990 + hep = gethostbyname(host);
2991 + if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) {
2992 + fprintf(stderr, "Cannot resolve host name '%s'!\n", host);
2994 + } else if (hep->h_addr_list[1]) {
2995 + fprintf(stderr, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host);
2998 + sa.sa_inet.sin_addr.s_addr = ((struct in_addr*)hep->h_addr_list[0])->s_addr;
3003 + SECURITY_DESCRIPTOR sd;
3004 + SECURITY_ATTRIBUTES sa;
3008 + memset(&sa, 0, sizeof(sa));
3009 + sa.nLength = sizeof(sa);
3010 + sa.bInheritHandle = FALSE;
3011 + acl = prepare_named_pipe_acl(&sd, &sa);
3013 + namedPipe = CreateNamedPipe(path,
3014 + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
3015 + PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
3016 + PIPE_UNLIMITED_INSTANCES,
3017 + 8192, 8192, 0, &sa);
3018 + if (namedPipe == INVALID_HANDLE_VALUE) {
3021 + listen_socket = _open_osfhandle((long)namedPipe, 0);
3022 + if (!is_initialized) {
3026 + return listen_socket;
3029 + int path_len = strlen(path);
3031 + if (path_len >= sizeof(sa.sa_unix.sun_path)) {
3032 + fprintf(stderr, "Listening socket's path name is too long.\n");
3036 + memset(&sa.sa_unix, 0, sizeof(sa.sa_unix));
3037 + sa.sa_unix.sun_family = AF_UNIX;
3038 + memcpy(sa.sa_unix.sun_path, path, path_len + 1);
3039 + sock_len = (size_t)(((struct sockaddr_un *)0)->sun_path) + path_len;
3040 +#ifdef HAVE_SOCKADDR_UN_SUN_LEN
3041 + sa.sa_unix.sun_len = sock_len;
3047 + /* Create, bind socket and start listen on it */
3048 + if ((listen_socket = socket(sa.sa.sa_family, SOCK_STREAM, 0)) < 0 ||
3049 +#ifdef SO_REUSEADDR
3050 + setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0 ||
3052 + bind(listen_socket, (struct sockaddr *) &sa, sock_len) < 0 ||
3053 + listen(listen_socket, backlog) < 0) {
3055 + fprintf(stderr, "Cannot bind/listen socket - [%d] %s.\n",errno, strerror(errno));
3060 + chmod(path, 0777);
3063 + if (!is_initialized) {
3070 + listen_socket = _open_osfhandle((long)listen_socket, 0);
3073 + fcgi_setup_signals();
3075 + return listen_socket;
3078 +void fcgi_init_request(fcgi_request *req, int listen_socket)
3080 + memset(req, 0, sizeof(fcgi_request));
3081 + req->listen_socket = listen_socket;
3088 + req->out_hdr = NULL;
3089 + req->out_pos = req->out_buf;
3092 + req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
3096 +static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
3105 + ret = write(req->fd, ((char*)buf)+n, count-n);
3107 + ret = send(req->fd, ((char*)buf)+n, count-n, 0);
3109 + errno = WSAGetLastError();
3113 + ret = write(req->fd, ((char*)buf)+n, count-n);
3117 + } else if (ret <= 0 && errno != 0 && errno != EINTR) {
3120 + } while (n != count);
3124 +static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
3133 + ret = read(req->fd, ((char*)buf)+n, count-n);
3135 + ret = recv(req->fd, ((char*)buf)+n, count-n, 0);
3137 + errno = WSAGetLastError();
3141 + ret = read(req->fd, ((char*)buf)+n, count-n);
3145 + } else if (ret == 0 && errno == 0) {
3147 + } else if (ret <= 0 && errno != 0 && errno != EINTR) {
3150 + } while (n != count);
3154 +static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
3156 + int pad = ((len + 7) & ~7) - len;
3158 + hdr->contentLengthB0 = (unsigned char)(len & 0xff);
3159 + hdr->contentLengthB1 = (unsigned char)((len >> 8) & 0xff);
3160 + hdr->paddingLength = (unsigned char)pad;
3161 + hdr->requestIdB0 = (unsigned char)(req_id & 0xff);
3162 + hdr->requestIdB1 = (unsigned char)((req_id >> 8) & 0xff);
3163 + hdr->reserved = 0;
3165 + hdr->version = FCGI_VERSION_1;
3167 + memset(((unsigned char*)hdr) + sizeof(fcgi_header) + len, 0, pad);
3172 +static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
3176 + int buf_size = sizeof(buf);
3177 + int name_len, val_len;
3183 + if (name_len >= 128) {
3184 + name_len = ((name_len & 0x7f) << 24);
3185 + name_len |= (*p++ << 16);
3186 + name_len |= (*p++ << 8);
3190 + if (val_len >= 128) {
3191 + val_len = ((val_len & 0x7f) << 24);
3192 + val_len |= (*p++ << 16);
3193 + val_len |= (*p++ << 8);
3196 + if (name_len + val_len < 0 ||
3197 + name_len + val_len > end - p) {
3198 + /* Malformated request */
3202 + if (name_len+1 >= buf_size) {
3203 + buf_size = name_len + 64;
3204 + tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
3206 + memcpy(tmp, p, name_len);
3207 + tmp[name_len] = 0;
3208 + s = zend_strndup((char*)p + name_len, val_len);
3209 + zend_hash_update(&req->env, tmp, name_len+1, &s, sizeof(char*), NULL);
3210 + p += name_len + val_len;
3212 + if (tmp != buf && tmp != NULL) {
3218 +static void fcgi_free_var(char **s)
3223 +static int fcgi_read_request(fcgi_request *req)
3227 + unsigned char buf[FCGI_MAX_LENGTH+8];
3231 + req->out_hdr = NULL;
3232 + req->out_pos = req->out_buf;
3233 + zend_hash_init(&req->env, 0, NULL, (void (*)(void *)) fcgi_free_var, 1);
3235 + if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
3236 + hdr.version < FCGI_VERSION_1) {
3240 + len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
3241 + padding = hdr.paddingLength;
3243 + while (hdr.type == FCGI_STDIN && len == 0) {
3244 + if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
3245 + hdr.version < FCGI_VERSION_1) {
3249 + len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
3250 + padding = hdr.paddingLength;
3253 + if (len + padding > FCGI_MAX_LENGTH) {
3257 + req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
3259 + if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
3262 + if (safe_read(req, buf, len+padding) != len+padding) {
3266 + req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
3267 + switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
3268 + case FCGI_RESPONDER:
3269 + val = strdup("RESPONDER");
3270 + zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
3272 + case FCGI_AUTHORIZER:
3273 + val = strdup("AUTHORIZER");
3274 + zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
3277 + val = strdup("FILTER");
3278 + zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
3284 + if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
3285 + hdr.version < FCGI_VERSION_1) {
3289 + len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
3290 + padding = hdr.paddingLength;
3292 + while (hdr.type == FCGI_PARAMS && len > 0) {
3293 + if (len + padding > FCGI_MAX_LENGTH) {
3297 + if (safe_read(req, buf, len+padding) != len+padding) {
3302 + if (!fcgi_get_params(req, buf, buf+len)) {
3307 + if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
3308 + hdr.version < FCGI_VERSION_1) {
3312 + len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
3313 + padding = hdr.paddingLength;
3315 + } else if (hdr.type == FCGI_GET_VALUES) {
3316 + unsigned char *p = buf + sizeof(fcgi_header);
3324 + if (safe_read(req, buf, len+padding) != len+padding) {
3329 + if (!fcgi_get_params(req, buf, buf+len)) {
3334 + zend_hash_internal_pointer_reset_ex(&req->env, &pos);
3335 + while ((key_type = zend_hash_get_current_key_ex(&req->env, &str_index, &str_length, &num_index, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
3337 + zend_hash_move_forward_ex(&req->env, &pos);
3338 + if (key_type != HASH_KEY_IS_STRING) {
3341 + if (zend_hash_find(fcgi_mgmt_vars, str_index, str_length, (void**) &value) != SUCCESS) {
3345 + zlen = Z_STRLEN_PP(value);
3346 + if ((p + 4 + 4 + str_length + zlen) >= (buf + sizeof(buf))) {
3349 + if (str_length < 0x80) {
3350 + *p++ = str_length;
3352 + *p++ = ((str_length >> 24) & 0xff) | 0x80;
3353 + *p++ = (str_length >> 16) & 0xff;
3354 + *p++ = (str_length >> 8) & 0xff;
3355 + *p++ = str_length & 0xff;
3357 + if (zlen < 0x80) {
3360 + *p++ = ((zlen >> 24) & 0xff) | 0x80;
3361 + *p++ = (zlen >> 16) & 0xff;
3362 + *p++ = (zlen >> 8) & 0xff;
3363 + *p++ = zlen & 0xff;
3365 + memcpy(p, str_index, str_length);
3367 + memcpy(p, Z_STRVAL_PP(value), zlen);
3370 + len = p - buf - sizeof(fcgi_header);
3371 + len += fcgi_make_header((fcgi_header*)buf, FCGI_GET_VALUES_RESULT, 0, len);
3372 + if (safe_write(req, buf, sizeof(fcgi_header)+len) != (int)sizeof(fcgi_header)+len) {
3384 +int fcgi_read(fcgi_request *req, char *str, int len)
3388 + unsigned char buf[255];
3392 + while (rest > 0) {
3393 + if (req->in_len == 0) {
3394 + if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
3395 + hdr.version < FCGI_VERSION_1 ||
3396 + hdr.type != FCGI_STDIN) {
3400 + req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
3401 + req->in_pad = hdr.paddingLength;
3402 + if (req->in_len == 0) {
3407 + if (req->in_len >= rest) {
3408 + ret = safe_read(req, str, rest);
3410 + ret = safe_read(req, str, req->in_len);
3415 + } else if (ret > 0) {
3416 + req->in_len -= ret;
3420 + if (req->in_len == 0) {
3421 + if (req->in_pad) {
3422 + if (safe_read(req, buf, req->in_pad) != req->in_pad) {
3437 +void fcgi_close(fcgi_request *req, int force, int destroy)
3440 + zend_hash_destroy(&req->env);
3444 + if (is_impersonate && !req->tcp) {
3449 + if ((force || !req->keep) && req->fd >= 0) {
3452 + HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
3455 + FlushFileBuffers(pipe);
3457 + DisconnectNamedPipe(pipe);
3462 + shutdown(req->fd, 1);
3463 + while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
3465 + closesocket(req->fd);
3471 + shutdown(req->fd, 1);
3472 + while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
3478 + fpm_request_finished();
3482 +int fcgi_accept_request(fcgi_request *req)
3488 + fcgi_finish_request(req);
3491 + if (req->fd < 0) {
3493 + if (in_shutdown) {
3498 + pipe = (HANDLE)_get_osfhandle(req->listen_socket);
3499 + FCGI_LOCK(req->listen_socket);
3500 + ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3501 + if (!ConnectNamedPipe(pipe, &ov)) {
3502 + errno = GetLastError();
3503 + if (errno == ERROR_IO_PENDING) {
3504 + while (WaitForSingleObject(ov.hEvent, 1000) == WAIT_TIMEOUT) {
3505 + if (in_shutdown) {
3506 + CloseHandle(ov.hEvent);
3507 + FCGI_UNLOCK(req->listen_socket);
3511 + } else if (errno != ERROR_PIPE_CONNECTED) {
3514 + CloseHandle(ov.hEvent);
3515 + req->fd = req->listen_socket;
3516 + FCGI_UNLOCK(req->listen_socket);
3518 + SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
3521 + int listen_socket = req->listen_socket;
3524 + socklen_t len = sizeof(sa);
3526 + fpm_request_accepting();
3528 + FCGI_LOCK(req->listen_socket);
3529 + req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len);
3530 + FCGI_UNLOCK(req->listen_socket);
3531 + if (req->fd >= 0 && allowed_clients) {
3535 + while (allowed_clients[n] != INADDR_NONE) {
3536 + if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
3543 + fprintf(stderr, "Connection from disallowed IP address '%s' is dropped.\n", inet_ntoa(sa.sa_inet.sin_addr));
3544 + closesocket(req->fd);
3552 + if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
3554 + if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
3562 + if (req->fd >= 0) {
3564 + fpm_request_reading_headers();
3566 +#if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
3567 + struct pollfd fds;
3571 + fds.events = POLLIN;
3575 + ret = poll(&fds, 1, 5000);
3576 + } while (ret < 0 && errno == EINTR);
3577 + if (ret > 0 && (fds.revents & POLLIN)) {
3580 + fcgi_close(req, 1, 0);
3582 + if (req->fd < FD_SETSIZE) {
3583 + struct timeval tv = {5,0};
3588 + FD_SET(req->fd, &set);
3591 + ret = select(req->fd + 1, &set, NULL, NULL, &tv) >= 0;
3592 + } while (ret < 0 && errno == EINTR);
3593 + if (ret > 0 && FD_ISSET(req->fd, &set)) {
3596 + fcgi_close(req, 1, 0);
3598 + fprintf(stderr, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
3599 + fcgi_close(req, 1, 0);
3605 + } else if (in_shutdown) {
3608 + if (fcgi_read_request(req)) {
3610 + if (is_impersonate && !req->tcp) {
3611 + pipe = (HANDLE)_get_osfhandle(req->fd);
3612 + if (!ImpersonateNamedPipeClient(pipe)) {
3613 + fcgi_close(req, 1, 1);
3620 + fcgi_close(req, 1, 1);
3625 +static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
3627 + req->out_hdr = (fcgi_header*) req->out_pos;
3628 + req->out_hdr->type = type;
3629 + req->out_pos += sizeof(fcgi_header);
3630 + return req->out_hdr;
3633 +static inline void close_packet(fcgi_request *req)
3635 + if (req->out_hdr) {
3636 + int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
3638 + req->out_pos += fcgi_make_header(req->out_hdr, (fcgi_request_type)req->out_hdr->type, req->id, len);
3639 + req->out_hdr = NULL;
3643 +int fcgi_flush(fcgi_request *req, int close)
3647 + close_packet(req);
3649 + len = req->out_pos - req->out_buf;
3652 + fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
3654 + fcgi_make_header(&rec->hdr, FCGI_END_REQUEST, req->id, sizeof(fcgi_end_request));
3655 + rec->body.appStatusB3 = 0;
3656 + rec->body.appStatusB2 = 0;
3657 + rec->body.appStatusB1 = 0;
3658 + rec->body.appStatusB0 = 0;
3659 + rec->body.protocolStatus = FCGI_REQUEST_COMPLETE;
3660 + len += sizeof(fcgi_end_request_rec);
3663 + if (safe_write(req, req->out_buf, len) != len) {
3668 + req->out_pos = req->out_buf;
3672 +int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
3680 + if (req->out_hdr && req->out_hdr->type != type) {
3681 + close_packet(req);
3684 + /* Unoptimized, but clear version */
3686 + while (rest > 0) {
3687 + limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
3689 + if (!req->out_hdr) {
3690 + if (limit < sizeof(fcgi_header)) {
3691 + if (!fcgi_flush(req, 0)) {
3695 + open_packet(req, type);
3697 + limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
3698 + if (rest < limit) {
3699 + memcpy(req->out_pos, str, rest);
3700 + req->out_pos += rest;
3703 + memcpy(req->out_pos, str, limit);
3704 + req->out_pos += limit;
3707 + if (!fcgi_flush(req, 0)) {
3713 + /* Optimized version */
3714 + limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
3715 + if (!req->out_hdr) {
3716 + limit -= sizeof(fcgi_header);
3717 + if (limit < 0) limit = 0;
3720 + if (len < limit) {
3721 + if (!req->out_hdr) {
3722 + open_packet(req, type);
3724 + memcpy(req->out_pos, str, len);
3725 + req->out_pos += len;
3726 + } else if (len - limit < sizeof(req->out_buf) - sizeof(fcgi_header)) {
3727 + if (!req->out_hdr) {
3728 + open_packet(req, type);
3731 + memcpy(req->out_pos, str, limit);
3732 + req->out_pos += limit;
3734 + if (!fcgi_flush(req, 0)) {
3737 + if (len > limit) {
3738 + open_packet(req, type);
3739 + memcpy(req->out_pos, str + limit, len - limit);
3740 + req->out_pos += len - limit;
3746 + close_packet(req);
3747 + while ((len - pos) > 0xffff) {
3748 + open_packet(req, type);
3749 + fcgi_make_header(req->out_hdr, type, req->id, 0xfff8);
3750 + req->out_hdr = NULL;
3751 + if (!fcgi_flush(req, 0)) {
3754 + if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
3761 + pad = (((len - pos) + 7) & ~7) - (len - pos);
3762 + rest = pad ? 8 - pad : 0;
3764 + open_packet(req, type);
3765 + fcgi_make_header(req->out_hdr, type, req->id, (len - pos) - rest);
3766 + req->out_hdr = NULL;
3767 + if (!fcgi_flush(req, 0)) {
3770 + if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
3775 + open_packet(req, type);
3776 + memcpy(req->out_pos, str + len - rest, rest);
3777 + req->out_pos += rest;
3784 +int fcgi_finish_request(fcgi_request *req)
3786 + if (req->fd >= 0) {
3787 + fcgi_flush(req, 1);
3788 + fcgi_close(req, 0, 1);
3793 +char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
3797 + if (!req) return NULL;
3799 + if (zend_hash_find(&req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
3805 +char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
3808 + if (val == NULL) {
3809 + zend_hash_del(&req->env, var, var_len+1);
3813 + val = strdup(val);
3814 + if (zend_hash_update(&req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
3823 +void fcgi_impersonate(void)
3827 + os_name = getenv("OS");
3828 + if (os_name && stricmp(os_name, "Windows_NT") == 0) {
3829 + is_impersonate = 1;
3834 +void fcgi_set_mgmt_var(char * name, size_t name_len, const char * value, size_t value_len)
3837 + zvalue = pemalloc(sizeof(*zvalue), 1);
3838 + Z_TYPE_P(zvalue) = IS_STRING;
3839 + Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
3840 + Z_STRLEN_P(zvalue) = value_len;
3841 + zend_hash_update(fcgi_mgmt_vars, name, name_len + 1, &zvalue, sizeof(zvalue), NULL);
3844 +void fcgi_free_mgmt_var_cb(void * ptr)
3846 + zval ** var = (zval **)ptr;
3847 + pefree(Z_STRVAL_PP(var), 1);
3852 + * Local variables:
3854 + * c-basic-offset: 4
3856 + * vim600: sw=4 ts=4 fdm=marker
3857 + * vim<600: sw=4 ts=4
3859 diff -Naur php-src-vanilla/sapi/fpm/cgi/fastcgi.h php-src/sapi/fpm/cgi/fastcgi.h
3860 --- php-src-vanilla/sapi/fpm/cgi/fastcgi.h 1970-01-01 01:00:00.000000000 +0100
3861 +++ php-src/sapi/fpm/cgi/fastcgi.h 2009-10-18 21:05:39.302497288 +0100
3864 + +----------------------------------------------------------------------+
3866 + +----------------------------------------------------------------------+
3867 + | Copyright (c) 1997-2008 The PHP Group |
3868 + +----------------------------------------------------------------------+
3869 + | This source file is subject to version 3.01 of the PHP license, |
3870 + | that is bundled with this package in the file LICENSE, and is |
3871 + | available through the world-wide-web at the following url: |
3872 + | http://www.php.net/license/3_01.txt |
3873 + | If you did not receive a copy of the PHP license and are unable to |
3874 + | obtain it through the world-wide-web, please send a note to |
3875 + | license@php.net so we can mail you a copy immediately. |
3876 + +----------------------------------------------------------------------+
3877 + | Authors: Dmitry Stogov <dmitry@zend.com> |
3878 + +----------------------------------------------------------------------+
3883 +/* FastCGI protocol */
3885 +#define FCGI_VERSION_1 1
3887 +#define FCGI_MAX_LENGTH 0xffff
3889 +#define FCGI_KEEP_CONN 1
3891 +typedef enum _fcgi_role {
3892 + FCGI_RESPONDER = 1,
3893 + FCGI_AUTHORIZER = 2,
3897 +typedef enum _fcgi_request_type {
3898 + FCGI_BEGIN_REQUEST = 1, /* [in] */
3899 + FCGI_ABORT_REQUEST = 2, /* [in] (not supported) */
3900 + FCGI_END_REQUEST = 3, /* [out] */
3901 + FCGI_PARAMS = 4, /* [in] environment variables */
3902 + FCGI_STDIN = 5, /* [in] post data */
3903 + FCGI_STDOUT = 6, /* [out] response */
3904 + FCGI_STDERR = 7, /* [out] errors */
3905 + FCGI_DATA = 8, /* [in] filter data (not supported) */
3906 + FCGI_GET_VALUES = 9, /* [in] */
3907 + FCGI_GET_VALUES_RESULT = 10 /* [out] */
3908 +} fcgi_request_type;
3910 +typedef enum _fcgi_protocol_status {
3911 + FCGI_REQUEST_COMPLETE = 0,
3912 + FCGI_CANT_MPX_CONN = 1,
3913 + FCGI_OVERLOADED = 2,
3914 + FCGI_UNKNOWN_ROLE = 3
3915 +} dcgi_protocol_status;
3917 +typedef struct _fcgi_header {
3918 + unsigned char version;
3919 + unsigned char type;
3920 + unsigned char requestIdB1;
3921 + unsigned char requestIdB0;
3922 + unsigned char contentLengthB1;
3923 + unsigned char contentLengthB0;
3924 + unsigned char paddingLength;
3925 + unsigned char reserved;
3928 +typedef struct _fcgi_begin_request {
3929 + unsigned char roleB1;
3930 + unsigned char roleB0;
3931 + unsigned char flags;
3932 + unsigned char reserved[5];
3933 +} fcgi_begin_request;
3935 +typedef struct _fcgi_begin_request_rec {
3937 + fcgi_begin_request body;
3938 +} fcgi_begin_request_rec;
3940 +typedef struct _fcgi_end_request {
3941 + unsigned char appStatusB3;
3942 + unsigned char appStatusB2;
3943 + unsigned char appStatusB1;
3944 + unsigned char appStatusB0;
3945 + unsigned char protocolStatus;
3946 + unsigned char reserved[3];
3947 +} fcgi_end_request;
3949 +typedef struct _fcgi_end_request_rec {
3951 + fcgi_end_request body;
3952 +} fcgi_end_request_rec;
3954 +/* FastCGI client API */
3956 +typedef struct _fcgi_request {
3957 + int listen_socket;
3968 + fcgi_header *out_hdr;
3969 + unsigned char *out_pos;
3970 + unsigned char out_buf[1024*8];
3971 + unsigned char reserved[sizeof(fcgi_end_request_rec)];
3976 +int fcgi_init(void);
3977 +void fcgi_shutdown(void);
3978 +int fcgi_is_fastcgi(void);
3979 +void fcgi_set_is_fastcgi(int);
3980 +void fcgi_set_in_shutdown(int);
3981 +void fcgi_set_allowed_clients(char *);
3982 +int fcgi_in_shutdown(void);
3983 +int fcgi_listen(const char *path, int backlog);
3984 +void fcgi_init_request(fcgi_request *req, int listen_socket);
3985 +int fcgi_accept_request(fcgi_request *req);
3986 +int fcgi_finish_request(fcgi_request *req);
3988 +char* fcgi_getenv(fcgi_request *req, const char* var, int var_len);
3989 +char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val);
3991 +int fcgi_read(fcgi_request *req, char *str, int len);
3993 +int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len);
3994 +int fcgi_flush(fcgi_request *req, int close);
3996 +void fcgi_close(fcgi_request *req, int force, int destroy);
3999 +void fcgi_impersonate(void);
4002 +void fcgi_set_mgmt_var(char * name, size_t name_len, const char * value, size_t value_len);
4003 +void fcgi_free_mgmt_var_cb(void * ptr);
4006 + * Local variables:
4008 + * c-basic-offset: 4
4010 + * vim600: sw=4 ts=4 fdm=marker
4011 + * vim<600: sw=4 ts=4
4013 diff -Naur php-src-vanilla/sapi/fpm/cgi/php_getopt.h php-src/sapi/fpm/cgi/php_getopt.h
4014 --- php-src-vanilla/sapi/fpm/cgi/php_getopt.h 1970-01-01 01:00:00.000000000 +0100
4015 +++ php-src/sapi/fpm/cgi/php_getopt.h 2009-10-18 21:05:39.302497288 +0100
4018 + +----------------------------------------------------------------------+
4020 + +----------------------------------------------------------------------+
4021 + | Copyright (c) 1997-2008 The PHP Group |
4022 + +----------------------------------------------------------------------+
4023 + | This source file is subject to version 3.01 of the PHP license, |
4024 + | that is bundled with this package in the file LICENSE, and is |
4025 + | available through the world-wide-web at the following url: |
4026 + | http://www.php.net/license/3_01.txt |
4027 + | If you did not receive a copy of the PHP license and are unable to |
4028 + | obtain it through the world-wide-web, please send a note to |
4029 + | license@php.net so we can mail you a copy immediately. |
4030 + +----------------------------------------------------------------------+
4031 + | Author: Marcus Boerger <helly@php.net> |
4032 + +----------------------------------------------------------------------+
4041 +As NetWare LibC has optind and optarg macros defined in unistd.h our local variables were getting mistakenly preprocessed so undeffing optind and optarg
4046 +/* Define structure for one recognized option (both single char and long name).
4047 + * If short_open is '-' this is the last option.
4049 +typedef struct _opt_struct {
4050 + const char opt_char;
4051 + const int need_param;
4052 + const char * opt_name;
4055 +int php_getopt(int argc, char* const *argv, const opt_struct opts[], char **optarg, int *optind, int show_err);
4056 diff -Naur php-src-vanilla/sapi/fpm/conf/init.d.php-fpm.in php-src/sapi/fpm/conf/init.d.php-fpm.in
4057 --- php-src-vanilla/sapi/fpm/conf/init.d.php-fpm.in 1970-01-01 01:00:00.000000000 +0100
4058 +++ php-src/sapi/fpm/conf/init.d.php-fpm.in 2009-10-18 21:05:39.298456068 +0100
4062 +### BEGIN INIT INFO
4063 +# Provides: @php_fpm_bin@
4064 +# Required-Start: $all
4065 +# Required-Stop: $all
4066 +# Default-Start: 2 3 4 5
4067 +# Default-Stop: 0 1 6
4068 +# Short-Description: starts @php_fpm_bin@
4069 +# Description: starts the PHP FastCGI Process Manager daemon
4072 +php_fpm_BIN=@php_fpm_bin_path@
4073 +php_fpm_CONF=@php_fpm_conf_path@
4074 +php_fpm_PID=@php_fpm_pid_path@
4077 +php_opts="--fpm-config $php_fpm_CONF"
4083 + while test $try -lt 35 ; do
4087 + if [ -f "$2" ] ; then
4094 + if [ ! -f "$2" ] ; then
4102 + try=`expr $try + 1`
4111 + echo -n "Starting @php_fpm_bin@ "
4113 + $php_fpm_BIN $php_opts
4115 + if [ "$?" != 0 ] ; then
4120 + wait_for_pid created $php_fpm_PID
4122 + if [ -n "$try" ] ; then
4131 + echo -n "Gracefully shutting down @php_fpm_bin@ "
4133 + if [ ! -r $php_fpm_PID ] ; then
4134 + echo "warning, no pid file found - php-fpm is not running ?"
4138 + kill -QUIT `cat $php_fpm_PID`
4140 + wait_for_pid removed $php_fpm_PID
4142 + if [ -n "$try" ] ; then
4143 + echo " failed. Use force-exit"
4151 + echo -n "Terminating @php_fpm_bin@ "
4153 + if [ ! -r $php_fpm_PID ] ; then
4154 + echo "warning, no pid file found - php-fpm is not running ?"
4158 + kill -TERM `cat $php_fpm_PID`
4160 + wait_for_pid removed $php_fpm_PID
4162 + if [ -n "$try" ] ; then
4177 + echo -n "Reload service @php_fpm_bin@ "
4179 + if [ ! -r $php_fpm_PID ] ; then
4180 + echo "warning, no pid file found - @php_fpm_bin@ is not running ?"
4184 + kill -USR2 `cat $php_fpm_PID`
4190 + echo "Usage: $0 {start|stop|force-quit|restart|reload}"
4195 diff -Naur php-src-vanilla/sapi/fpm/conf/nginx-site-conf.sample.in php-src/sapi/fpm/conf/nginx-site-conf.sample.in
4196 --- php-src-vanilla/sapi/fpm/conf/nginx-site-conf.sample.in 1970-01-01 01:00:00.000000000 +0100
4197 +++ php-src/sapi/fpm/conf/nginx-site-conf.sample.in 2009-10-18 21:05:39.298456068 +0100
4199 +# @php_fpm_bin@ - PHP FastCGI Process Manager 'PHP-FPM'
4201 +# nginx-site-conf.sample:
4202 +# Php Site configuration for nginx webserver
4204 +# 1. set server root /path/to/your/website;
4205 +# 2. Rename this file. Copy it to /etc/nginx/sites-available, /etc/nginx/sites-enabled
4206 +# or otherwise ensure that this file is included by the nginx.conf
4207 +# 3. Restart nginx webserver, and @php_fpm_bin@ service.
4212 + root /var/www/nginx-site;
4214 + server_name localhost;
4217 + access_log /var/log/nginx/localhost.access.log;
4220 + index index.html index.htm;
4223 + #error_page 404 /404.html;
4225 + # redirect server error pages to the static page /50x.html
4227 + error_page 500 502 503 504 /50x.html;
4228 + location = /50x.html {
4229 + root /var/www/nginx-default;
4232 + # pass the *.php scripts to @php_fpm_bin@ listening on tcp port @php_fpm_port@
4234 + location ~ \.php$ {
4236 + fastcgi_pass 127.0.0.1:@php_fpm_port@;
4237 + fastcgi_index index.php;
4239 + include fastcgi_params;
4240 + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
4241 + fastcgi_param SERVER_NAME $http_host;
4242 + fastcgi_ignore_client_abort on;
4245 diff -Naur php-src-vanilla/sapi/fpm/conf/php-fpm.conf.in php-src/sapi/fpm/conf/php-fpm.conf.in
4246 --- php-src-vanilla/sapi/fpm/conf/php-fpm.conf.in 1970-01-01 01:00:00.000000000 +0100
4247 +++ php-src/sapi/fpm/conf/php-fpm.conf.in 2009-10-18 21:05:39.298456068 +0100
4249 +<?xml version="1.0" ?>
4252 + All relative paths in this config are relative to php's install prefix
4254 + <section name="global_options">
4257 + <value name="pid_file">@php_fpm_pid_path@</value>
4260 + <value name="error_log">@php_fpm_log_path@</value>
4263 + <value name="log_level">notice</value>
4265 + When this amount of php processes exited with SIGSEGV or SIGBUS ...
4266 + <value name="emergency_restart_threshold">10</value>
4268 + ... in a less than this interval of time, a graceful restart will be initiated.
4269 + Useful to work around accidental curruptions in accelerator's shared memory.
4270 + <value name="emergency_restart_interval">1m</value>
4272 + Time limit on waiting child's reaction on signals from master
4273 + <value name="process_control_timeout">5s</value>
4275 + Set to 'no' to debug fpm
4276 + <value name="daemonize">yes</value>
4282 + <section name="pool">
4284 + Name of pool. Used in logs and stats.
4285 + <value name="name">default</value>
4287 + Address to accept fastcgi requests on.
4288 + Valid syntax is 'ip.ad.re.ss:port' or just 'port' or '/path/to/unix/socket'
4289 + <value name="listen_address">127.0.0.1:@php_fpm_port@</value>
4291 + <value name="listen_options">
4293 + Set listen(2) backlog
4294 + <value name="backlog">-1</value>
4296 + Set permissions for unix socket, if one used.
4297 + In Linux read/write permissions must be set in order to allow connections from web server.
4298 + Many BSD-derrived systems allow connections regardless of permissions.
4299 + <value name="owner">@php_fpm_user@</value>
4300 + <value name="group">@php_fpm_group@</value>
4301 + <value name="mode">0666</value>
4304 + Additional php.ini defines, specific to this pool of workers.
4305 + These settings overwrite the values previously defined in the php.ini.
4306 + <value name="php_defines">
4307 + <!-- <value name="sendmail_path">/usr/sbin/sendmail -t -i</value> -->
4308 + <!-- <value name="display_errors">0</value> -->
4309 + <!-- <value name="error_log">/var/log/php-error.log</value> -->
4310 + <!-- <value name="log_errors">true</value> -->
4313 + Unix user of processes
4314 + <value name="user">@php_fpm_user@</value>
4316 + Unix group of processes
4317 + <value name="group">@php_fpm_group@</value>
4319 + Process manager settings
4322 + Sets style of controling worker process count.
4323 + Valid values are 'static' and 'apache-like'
4324 + <value name="style">static</value>
4326 + Sets the limit on the number of simultaneous requests that will be served.
4327 + Equivalent to Apache MaxClients directive.
4328 + Equivalent to PHP_FCGI_CHILDREN environment in original php.fcgi
4329 + Used with any pm_style.
4330 + <value name="max_children">5</value>
4332 + Settings group for 'apache-like' pm style
4333 + <value name="apache_like">
4335 + Sets the number of server processes created on startup.
4336 + Used only when 'apache-like' pm_style is selected
4337 + <value name="StartServers">20</value>
4339 + Sets the desired minimum number of idle server processes.
4340 + Used only when 'apache-like' pm_style is selected
4341 + <value name="MinSpareServers">5</value>
4343 + Sets the desired maximum number of idle server processes.
4344 + Used only when 'apache-like' pm_style is selected
4345 + <value name="MaxSpareServers">35</value>
4351 + The timeout (in seconds) for serving a single request after which the worker process will be terminated
4352 + Should be used when 'max_execution_time' ini option does not stop script execution for some reason
4354 + <value name="request_terminate_timeout">0s</value>
4356 + The timeout (in seconds) for serving of single request after which a php backtrace will be dumped to slow.log file
4358 + <value name="request_slowlog_timeout">0s</value>
4360 + The log file for slow requests
4361 + <value name="slowlog">@php_fpm_log_path@.slow</value>
4363 + Set open file desc rlimit
4364 + <value name="rlimit_files">1024</value>
4366 + Set max core size rlimit
4367 + <value name="rlimit_core">0</value>
4369 + Chroot to this directory at the start, absolute path
4370 + <value name="chroot"></value>
4372 + Chdir to this directory at the start, absolute path
4373 + <value name="chdir"></value>
4375 + Redirect workers' stdout and stderr into main error log.
4376 + If not set, they will be redirected to /dev/null, according to FastCGI specs
4377 + <value name="catch_workers_output">yes</value>
4379 + How much requests each process should execute before respawn.
4380 + Useful to work around memory leaks in 3rd party libraries.
4381 + For endless request processing please specify 0
4382 + Equivalent to PHP_FCGI_MAX_REQUESTS
4383 + <value name="max_requests">500</value>
4385 + Comma separated list of ipv4 addresses of FastCGI clients that allowed to connect.
4386 + Equivalent to FCGI_WEB_SERVER_ADDRS environment in original php.fcgi (5.2.2+)
4387 + Makes sense only with AF_INET listening socket.
4388 + <value name="allowed_clients">127.0.0.1</value>
4390 + Pass environment variables like LD_LIBRARY_PATH
4391 + All $VARIABLEs are taken from current environment
4392 + <value name="environment">
4393 + <value name="HOSTNAME">$HOSTNAME</value>
4394 + <value name="PATH">/usr/local/bin:/usr/bin:/bin</value>
4395 + <value name="TMP">/tmp</value>
4396 + <value name="TMPDIR">/tmp</value>
4397 + <value name="TEMP">/tmp</value>
4398 + <value name="OSTYPE">$OSTYPE</value>
4399 + <value name="MACHTYPE">$MACHTYPE</value>
4400 + <value name="MALLOC_CHECK_">2</value>
4408 diff -Naur php-src-vanilla/sapi/fpm/config.m4 php-src/sapi/fpm/config.m4
4409 --- php-src-vanilla/sapi/fpm/config.m4 1970-01-01 01:00:00.000000000 +0100
4410 +++ php-src/sapi/fpm/config.m4 2009-10-18 21:05:39.302497288 +0100
4417 +[ --with-fpm Build PHP FastCGI - FPM executable], no)
4419 +if test "$PHP_FPM" != "no"; then
4421 + PHP_CONFIGURE_PART(Configuring fpm)
4423 + sinclude(sapi/fpm/ac/fpm_libevent.m4)
4424 + AC_LIB_EVENT([1.4.3],[1.4.11])
4426 + sinclude(sapi/fpm/ac/fpm_checks.m4)
4429 + sinclude(sapi/fpm/ac/fpm_conf.m4)
4433 + sinclude(sapi/fpm/ac/fpm_build.m4)
4438 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_arrays.h php-src/sapi/fpm/fpm/fpm_arrays.h
4439 --- php-src-vanilla/sapi/fpm/fpm/fpm_arrays.h 1970-01-01 01:00:00.000000000 +0100
4440 +++ php-src/sapi/fpm/fpm/fpm_arrays.h 2009-10-18 21:05:39.308376784 +0100
4444 + /* (c) 2007,2008 Andrei Nigmatulin */
4446 +#ifndef FPM_ARRAYS_H
4447 +#define FPM_ARRAYS_H 1
4449 +#include <stdlib.h>
4450 +#include <string.h>
4452 +struct fpm_array_s {
4459 +static inline struct fpm_array_s *fpm_array_init(struct fpm_array_s *a, unsigned int sz, unsigned int initial_num)
4461 + void *allocated = 0;
4464 + a = malloc(sizeof(struct fpm_array_s));
4475 + a->data = calloc(sz, initial_num);
4482 + a->allocated = initial_num;
4488 +static inline void *fpm_array_item(struct fpm_array_s *a, unsigned int n)
4492 + ret = (char *) a->data + a->sz * n;
4497 +static inline void *fpm_array_item_last(struct fpm_array_s *a)
4499 + return fpm_array_item(a, a->used - 1);
4502 +static inline int fpm_array_item_remove(struct fpm_array_s *a, unsigned int n)
4506 + if (n < a->used - 1) {
4507 + void *last = fpm_array_item(a, a->used - 1);
4508 + void *to_remove = fpm_array_item(a, n);
4510 + memcpy(to_remove, last, a->sz);
4520 +static inline void *fpm_array_push(struct fpm_array_s *a)
4524 + if (a->used == a->allocated) {
4525 + size_t new_allocated = a->allocated ? a->allocated * 2 : 20;
4526 + void *new_ptr = realloc(a->data, a->sz * new_allocated);
4532 + a->data = new_ptr;
4533 + a->allocated = new_allocated;
4536 + ret = fpm_array_item(a, a->used);
4543 +static inline void fpm_array_free(struct fpm_array_s *a)
4548 + a->used = a->allocated = 0;
4552 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_atomic.h php-src/sapi/fpm/fpm/fpm_atomic.h
4553 --- php-src-vanilla/sapi/fpm/fpm/fpm_atomic.h 1970-01-01 01:00:00.000000000 +0100
4554 +++ php-src/sapi/fpm/fpm/fpm_atomic.h 2009-10-18 21:05:39.308376784 +0100
4558 + /* (c) 2007,2008 Andrei Nigmatulin */
4560 +#ifndef FPM_ATOMIC_H
4561 +#define FPM_ATOMIC_H 1
4563 +#if HAVE_INTTYPES_H
4564 +#include <inttypes.h>
4566 +#include <stdint.h>
4570 +#if ( __i386__ || __i386 )
4572 +typedef int32_t atomic_int_t;
4573 +typedef uint32_t atomic_uint_t;
4574 +typedef volatile atomic_uint_t atomic_t;
4577 +static inline atomic_int_t atomic_fetch_add(atomic_t *value, atomic_int_t add)
4579 + __asm__ volatile ( "lock;" "xaddl %0, %1;" :
4580 + "+r" (add) : "m" (*value) : "memory");
4585 +static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set)
4587 + unsigned char res;
4589 + __asm__ volatile ( "lock;" "cmpxchgl %3, %1;" "sete %0;" :
4590 + "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory");
4595 +#elif ( __amd64__ || __amd64 )
4597 +typedef int64_t atomic_int_t;
4598 +typedef uint64_t atomic_uint_t;
4599 +typedef volatile atomic_uint_t atomic_t;
4601 +static inline atomic_int_t atomic_fetch_add(atomic_t *value, atomic_int_t add)
4603 + __asm__ volatile ( "lock;" "xaddq %0, %1;" :
4604 + "+r" (add) : "m" (*value) : "memory");
4609 +static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set)
4611 + unsigned char res;
4613 + __asm__ volatile ( "lock;" "cmpxchgq %3, %1;" "sete %0;" :
4614 + "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory");
4619 +#if (__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
4621 +#elif ( __arm__ || __arm ) /* W-Mark Kubacki */
4623 +#if (__arch64__ || __arch64)
4624 +typedef int64_t atomic_int_t;
4625 +typedef uint64_t atomic_uint_t;
4627 +typedef int32_t atomic_int_t;
4628 +typedef uint32_t atomic_uint_t;
4631 +#define atomic_cmp_set(a,b,c) __sync_bool_compare_and_swap(a,b,c)
4633 +#endif /* defined (__GNUC__) &&... */
4635 +#elif ( __sparc__ || __sparc ) /* Marcin Ochab */
4637 +#if (__arch64__ || __arch64)
4638 +typedef uint64_t atomic_uint_t;
4639 +typedef volatile atomic_uint_t atomic_t;
4641 +static inline int atomic_cas_64(atomic_t *lock, atomic_uint_t old, atomic_uint_t new)
4643 + __asm__ __volatile__("casx [%2], %3, %0 " : "=&r"(new) : "0"(new), "r"(lock), "r"(old): "memory");
4648 +static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set)
4650 + return (atomic_cas_64(lock, old, set)==old);
4653 +typedef uint32_t atomic_uint_t;
4654 +typedef volatile atomic_uint_t atomic_t;
4656 +static inline int atomic_cas_32(atomic_t *lock, atomic_uint_t old, atomic_uint_t new)
4658 + __asm__ __volatile__("cas [%2], %3, %0 " : "=&r"(new) : "0"(new), "r"(lock), "r"(old): "memory");
4663 +static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set)
4665 + return (atomic_cas_32(lock, old, set)==old);
4671 +#error unsupported architecture. please write a patch and send it in
4675 +static inline int fpm_spinlock(atomic_t *lock, int try_once)
4678 + return atomic_cmp_set(lock, 0, 1) ? 0 : -1;
4683 + if (atomic_cmp_set(lock, 0, 1)) {
4695 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm.c php-src/sapi/fpm/fpm/fpm.c
4696 --- php-src-vanilla/sapi/fpm/fpm/fpm.c 1970-01-01 01:00:00.000000000 +0100
4697 +++ php-src/sapi/fpm/fpm/fpm.c 2009-10-18 21:05:39.308376784 +0100
4701 + /* (c) 2007,2008 Andrei Nigmatulin */
4703 +#include "fpm_config.h"
4705 +#include <stdlib.h> /* for exit */
4708 +#include "fpm_children.h"
4709 +#include "fpm_signals.h"
4710 +#include "fpm_env.h"
4711 +#include "fpm_events.h"
4712 +#include "fpm_cleanup.h"
4713 +#include "fpm_php.h"
4714 +#include "fpm_sockets.h"
4715 +#include "fpm_unix.h"
4716 +#include "fpm_process_ctl.h"
4717 +#include "fpm_conf.h"
4718 +#include "fpm_worker_pool.h"
4719 +#include "fpm_stdio.h"
4722 +struct fpm_globals_s fpm_globals;
4724 +int fpm_init(int argc, char **argv, char *config)
4726 + fpm_globals.argc = argc;
4727 + fpm_globals.argv = argv;
4728 + fpm_globals.config = config;
4730 + if (0 > fpm_php_init_main() ||
4731 + 0 > fpm_stdio_init_main() ||
4732 + 0 > fpm_conf_init_main() ||
4733 + 0 > fpm_unix_init_main() ||
4734 + 0 > fpm_env_init_main() ||
4735 + 0 > fpm_signals_init_main() ||
4736 + 0 > fpm_pctl_init_main() ||
4737 + 0 > fpm_children_init_main() ||
4738 + 0 > fpm_sockets_init_main() ||
4739 + 0 > fpm_worker_pool_init_main() ||
4740 + 0 > fpm_event_init_main()) {
4744 + if (0 > fpm_conf_write_pid()) {
4748 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "fpm is running, pid %d", (int) fpm_globals.parent_pid);
4753 +/* children: return listening socket
4754 + parent: never return */
4755 +int fpm_run(int *max_requests)
4757 + struct fpm_worker_pool_s *wp;
4759 + /* create initial children in all pools */
4760 + for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
4763 + is_parent = fpm_children_create_initial(wp);
4770 + /* run event loop forever */
4773 +run_child: /* only workers reach this point */
4775 + fpm_cleanups_run(FPM_CLEANUP_CHILD);
4777 + *max_requests = fpm_globals.max_requests;
4778 + return fpm_globals.listening_socket;
4781 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_children.c php-src/sapi/fpm/fpm/fpm_children.c
4782 --- php-src-vanilla/sapi/fpm/fpm/fpm_children.c 1970-01-01 01:00:00.000000000 +0100
4783 +++ php-src/sapi/fpm/fpm/fpm_children.c 2009-10-18 21:05:39.308376784 +0100
4787 + /* (c) 2007,2008 Andrei Nigmatulin */
4789 +#include "fpm_config.h"
4791 +#include <sys/types.h>
4792 +#include <sys/wait.h>
4794 +#include <unistd.h>
4795 +#include <string.h>
4799 +#include "fpm_children.h"
4800 +#include "fpm_signals.h"
4801 +#include "fpm_worker_pool.h"
4802 +#include "fpm_sockets.h"
4803 +#include "fpm_process_ctl.h"
4804 +#include "fpm_php.h"
4805 +#include "fpm_conf.h"
4806 +#include "fpm_cleanup.h"
4807 +#include "fpm_events.h"
4808 +#include "fpm_clock.h"
4809 +#include "fpm_stdio.h"
4810 +#include "fpm_unix.h"
4811 +#include "fpm_env.h"
4812 +#include "fpm_shm_slots.h"
4816 +static time_t *last_faults;
4819 +static int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop);
4821 +static void fpm_children_cleanup(int which, void *arg)
4823 + free(last_faults);
4826 +static struct fpm_child_s *fpm_child_alloc()
4828 + struct fpm_child_s *ret;
4830 + ret = malloc(sizeof(struct fpm_child_s));
4832 + if (!ret) { return 0; }
4834 + memset(ret, 0, sizeof(*ret));
4839 +static void fpm_child_free(struct fpm_child_s *child)
4844 +static void fpm_child_close(struct fpm_child_s *child, int in_event_loop)
4846 + if (child->fd_stdout != -1) {
4847 + if (in_event_loop) {
4848 + fpm_event_fire(&child->ev_stdout);
4850 + if (child->fd_stdout != -1) {
4851 + close(child->fd_stdout);
4855 + if (child->fd_stderr != -1) {
4856 + if (in_event_loop) {
4857 + fpm_event_fire(&child->ev_stderr);
4859 + if (child->fd_stderr != -1) {
4860 + close(child->fd_stderr);
4864 + fpm_child_free(child);
4867 +static void fpm_child_link(struct fpm_child_s *child)
4869 + struct fpm_worker_pool_s *wp = child->wp;
4871 + ++wp->running_children;
4872 + ++fpm_globals.running_children;
4874 + child->next = wp->children;
4875 + if (child->next) { child->next->prev = child; }
4877 + wp->children = child;
4880 +static void fpm_child_unlink(struct fpm_child_s *child)
4882 + --child->wp->running_children;
4883 + --fpm_globals.running_children;
4885 + if (child->prev) { child->prev->next = child->next; }
4886 + else { child->wp->children = child->next; }
4887 + if (child->next) { child->next->prev = child->prev; }
4891 +static struct fpm_child_s *fpm_child_find(pid_t pid)
4893 + struct fpm_worker_pool_s *wp;
4894 + struct fpm_child_s *child = 0;
4896 + for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
4898 + for (child = wp->children; child; child = child->next) {
4899 + if (child->pid == pid) {
4916 +static void fpm_child_init(struct fpm_worker_pool_s *wp)
4918 + fpm_globals.max_requests = wp->config->max_requests;
4920 + if (0 > fpm_stdio_init_child(wp) ||
4921 + 0 > fpm_unix_init_child(wp) ||
4922 + 0 > fpm_signals_init_child() ||
4923 + 0 > fpm_env_init_child(wp) ||
4924 + 0 > fpm_php_init_child(wp)) {
4926 + zlog(ZLOG_STUFF, ZLOG_ERROR, "child failed to initialize (pool %s)", wp->config->name);
4931 +int fpm_children_free(struct fpm_child_s *child)
4933 + struct fpm_child_s *next;
4935 + for (; child; child = next) {
4936 + next = child->next;
4937 + fpm_child_close(child, 0 /* in_event_loop */);
4943 +void fpm_children_bury()
4947 + struct fpm_child_s *child;
4949 + while ( (pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
4951 + int severity = ZLOG_NOTICE;
4953 + child = fpm_child_find(pid);
4955 + if (WIFEXITED(status)) {
4957 + snprintf(buf, sizeof(buf), "with code %d", WEXITSTATUS(status));
4959 + if (WEXITSTATUS(status) != 0) {
4960 + severity = ZLOG_WARNING;
4964 + else if (WIFSIGNALED(status)) {
4965 + const char *signame = fpm_signal_names[WTERMSIG(status)];
4966 + const char *have_core = WCOREDUMP(status) ? " (core dumped)" : "";
4968 + if (signame == NULL) {
4972 + snprintf(buf, sizeof(buf), "on signal %d %s%s", WTERMSIG(status), signame, have_core);
4974 + if (WTERMSIG(status) != SIGQUIT) { /* possible request loss */
4975 + severity = ZLOG_WARNING;
4978 + else if (WIFSTOPPED(status)) {
4980 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "child %d stopped for tracing", (int) pid);
4982 + if (child && child->tracer) {
4983 + child->tracer(child);
4990 + struct fpm_worker_pool_s *wp = child->wp;
4991 + struct timeval tv1, tv2;
4993 + fpm_child_unlink(child);
4995 + fpm_shm_slots_discard_slot(child);
4997 + fpm_clock_get(&tv1);
4999 + timersub(&tv1, &child->started, &tv2);
5001 + zlog(ZLOG_STUFF, severity, "child %d (pool %s) exited %s after %ld.%06d seconds from start", (int) pid,
5002 + child->wp->config->name, buf, tv2.tv_sec, (int) tv2.tv_usec);
5004 + fpm_child_close(child, 1 /* in event_loop */);
5006 + fpm_pctl_child_exited();
5008 + if (last_faults && (WTERMSIG(status) == SIGSEGV || WTERMSIG(status) == SIGBUS)) {
5009 + time_t now = tv1.tv_sec;
5010 + int restart_condition = 1;
5013 + last_faults[fault++] = now;
5015 + if (fault == fpm_global_config.emergency_restart_threshold) {
5019 + for (i = 0; i < fpm_global_config.emergency_restart_threshold; i++) {
5020 + if (now - last_faults[i] > fpm_global_config.emergency_restart_interval) {
5021 + restart_condition = 0;
5026 + if (restart_condition) {
5028 + zlog(ZLOG_STUFF, ZLOG_WARNING, "failed processes threshold (%d in %d sec) is reached, initiating reload",
5029 + fpm_global_config.emergency_restart_threshold, fpm_global_config.emergency_restart_interval);
5031 + fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET);
5035 + fpm_children_make(wp, 1 /* in event loop */);
5037 + if (fpm_globals.is_child) {
5042 + zlog(ZLOG_STUFF, ZLOG_ALERT, "oops, unknown child exited %s", buf);
5048 +static struct fpm_child_s *fpm_resources_prepare(struct fpm_worker_pool_s *wp)
5050 + struct fpm_child_s *c;
5052 + c = fpm_child_alloc();
5055 + zlog(ZLOG_STUFF, ZLOG_ERROR, "malloc failed (pool %s)", wp->config->name);
5060 + c->fd_stdout = -1; c->fd_stderr = -1;
5062 + if (0 > fpm_stdio_prepare_pipes(c)) {
5063 + fpm_child_free(c);
5067 + if (0 > fpm_shm_slots_prepare_slot(c)) {
5068 + fpm_stdio_discard_pipes(c);
5069 + fpm_child_free(c);
5076 +static void fpm_resources_discard(struct fpm_child_s *child)
5078 + fpm_shm_slots_discard_slot(child);
5079 + fpm_stdio_discard_pipes(child);
5080 + fpm_child_free(child);
5083 +static void fpm_child_resources_use(struct fpm_child_s *child)
5085 + fpm_shm_slots_child_use_slot(child);
5086 + fpm_stdio_child_use_pipes(child);
5087 + fpm_child_free(child);
5090 +static void fpm_parent_resources_use(struct fpm_child_s *child)
5092 + fpm_shm_slots_parent_use_slot(child);
5093 + fpm_stdio_parent_use_pipes(child);
5094 + fpm_child_link(child);
5097 +static int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop)
5101 + struct fpm_child_s *child;
5103 + while (!enough && fpm_pctl_can_spawn_children() && wp->running_children < wp->config->pm->max_children) {
5105 + child = fpm_resources_prepare(wp);
5117 + fpm_child_resources_use(child);
5118 + fpm_globals.is_child = 1;
5119 + if (in_event_loop) {
5120 + fpm_event_exit_loop();
5122 + fpm_child_init(wp);
5126 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fork() failed");
5129 + fpm_resources_discard(child);
5131 + break; /* dont try any more on error */
5135 + fpm_clock_get(&child->started);
5136 + fpm_parent_resources_use(child);
5138 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "child %d (pool %s) started", (int) pid, wp->config->name);
5143 + return 1; /* we are done */
5146 +int fpm_children_create_initial(struct fpm_worker_pool_s *wp)
5148 + return fpm_children_make(wp, 0 /* not in event loop yet */);
5151 +int fpm_children_init_main()
5153 + if (fpm_global_config.emergency_restart_threshold &&
5154 + fpm_global_config.emergency_restart_interval) {
5156 + last_faults = malloc(sizeof(time_t) * fpm_global_config.emergency_restart_threshold);
5158 + if (!last_faults) {
5162 + memset(last_faults, 0, sizeof(time_t) * fpm_global_config.emergency_restart_threshold);
5165 + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_children_cleanup, 0)) {
5172 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_children.h php-src/sapi/fpm/fpm/fpm_children.h
5173 --- php-src-vanilla/sapi/fpm/fpm/fpm_children.h 1970-01-01 01:00:00.000000000 +0100
5174 +++ php-src/sapi/fpm/fpm/fpm_children.h 2009-10-18 21:05:39.308376784 +0100
5178 + /* (c) 2007,2008 Andrei Nigmatulin */
5180 +#ifndef FPM_CHILDREN_H
5181 +#define FPM_CHILDREN_H 1
5183 +#include <sys/time.h>
5184 +#include <sys/types.h>
5187 +#include "fpm_worker_pool.h"
5189 +int fpm_children_create_initial(struct fpm_worker_pool_s *wp);
5190 +int fpm_children_free(struct fpm_child_s *child);
5191 +void fpm_children_bury();
5192 +int fpm_children_init_main();
5194 +struct fpm_child_s;
5196 +struct fpm_child_s {
5197 + struct fpm_child_s *prev, *next;
5198 + struct timeval started;
5199 + struct fpm_worker_pool_s *wp;
5200 + struct event ev_stdout, ev_stderr;
5202 + int fd_stdout, fd_stderr;
5203 + void (*tracer)(struct fpm_child_s *);
5204 + struct timeval slow_logged;
5209 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_cleanup.c php-src/sapi/fpm/fpm/fpm_cleanup.c
5210 --- php-src-vanilla/sapi/fpm/fpm/fpm_cleanup.c 1970-01-01 01:00:00.000000000 +0100
5211 +++ php-src/sapi/fpm/fpm/fpm_cleanup.c 2009-10-18 21:05:39.310440424 +0100
5215 + /* (c) 2007,2008 Andrei Nigmatulin */
5217 +#include "fpm_config.h"
5219 +#include <stdlib.h>
5221 +#include "fpm_arrays.h"
5222 +#include "fpm_cleanup.h"
5227 + void (*cleanup)(int, void *);
5231 +static struct fpm_array_s cleanups = { .sz = sizeof(struct cleanup_s) };
5233 +int fpm_cleanup_add(int type, void (*cleanup)(int, void *), void *arg)
5235 + struct cleanup_s *c;
5237 + c = fpm_array_push(&cleanups);
5244 + c->cleanup = cleanup;
5250 +void fpm_cleanups_run(int type)
5252 + struct cleanup_s *c = fpm_array_item_last(&cleanups);
5253 + int cl = cleanups.used;
5255 + for ( ; cl--; c--) {
5256 + if (c->type & type) {
5257 + c->cleanup(type, c->arg);
5261 + fpm_array_free(&cleanups);
5264 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_cleanup.h php-src/sapi/fpm/fpm/fpm_cleanup.h
5265 --- php-src-vanilla/sapi/fpm/fpm/fpm_cleanup.h 1970-01-01 01:00:00.000000000 +0100
5266 +++ php-src/sapi/fpm/fpm/fpm_cleanup.h 2009-10-18 21:05:39.308376784 +0100
5270 + /* (c) 2007,2008 Andrei Nigmatulin */
5272 +#ifndef FPM_CLEANUP_H
5273 +#define FPM_CLEANUP_H 1
5275 +int fpm_cleanup_add(int type, void (*cleanup)(int, void *), void *);
5276 +void fpm_cleanups_run(int type);
5279 + FPM_CLEANUP_CHILD = (1 << 0),
5280 + FPM_CLEANUP_PARENT_EXIT = (1 << 1),
5281 + FPM_CLEANUP_PARENT_EXIT_MAIN = (1 << 2),
5282 + FPM_CLEANUP_PARENT_EXEC = (1 << 3),
5283 + FPM_CLEANUP_PARENT = (1 << 1) | (1 << 2) | (1 << 3),
5284 + FPM_CLEANUP_ALL = ~0,
5289 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_clock.c php-src/sapi/fpm/fpm/fpm_clock.c
5290 --- php-src-vanilla/sapi/fpm/fpm/fpm_clock.c 1970-01-01 01:00:00.000000000 +0100
5291 +++ php-src/sapi/fpm/fpm/fpm_clock.c 2009-10-18 21:05:39.308376784 +0100
5295 + /* (c) 2007,2008 Andrei Nigmatulin */
5297 +#include "fpm_config.h"
5299 +#if defined(HAVE_CLOCK_GETTIME)
5300 +#include <time.h> /* for CLOCK_MONOTONIC */
5303 +#include "fpm_clock.h"
5307 +/* posix monotonic clock - preferred source of time */
5308 +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
5310 +static int monotonic_works;
5312 +int fpm_clock_init()
5314 + struct timespec ts;
5316 + monotonic_works = 0;
5318 + if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) {
5319 + monotonic_works = 1;
5325 +int fpm_clock_get(struct timeval *tv)
5327 + if (monotonic_works) {
5328 + struct timespec ts;
5330 + if (0 > clock_gettime(CLOCK_MONOTONIC, &ts)) {
5331 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "clock_gettime() failed");
5335 + tv->tv_sec = ts.tv_sec;
5336 + tv->tv_usec = ts.tv_nsec / 1000;
5340 + return gettimeofday(tv, 0);
5344 +#elif defined(HAVE_CLOCK_GET_TIME)
5346 +#include <mach/mach.h>
5347 +#include <mach/clock.h>
5348 +#include <mach/mach_error.h>
5350 +static clock_serv_t mach_clock;
5352 +/* this code borrowed from here: http://lists.apple.com/archives/Darwin-development/2002/Mar/msg00746.html */
5353 +/* mach_clock also should be re-initialized in child process after fork */
5354 +int fpm_clock_init()
5356 + kern_return_t ret;
5357 + mach_timespec_t aTime;
5359 + ret = host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &mach_clock);
5361 + if (ret != KERN_SUCCESS) {
5362 + zlog(ZLOG_STUFF, ZLOG_ERROR, "host_get_clock_service() failed: %s", mach_error_string(ret));
5366 + /* test if it works */
5367 + ret = clock_get_time(mach_clock, &aTime);
5369 + if (ret != KERN_SUCCESS) {
5370 + zlog(ZLOG_STUFF, ZLOG_ERROR, "clock_get_time() failed: %s", mach_error_string(ret));
5377 +int fpm_clock_get(struct timeval *tv)
5379 + kern_return_t ret;
5380 + mach_timespec_t aTime;
5382 + ret = clock_get_time(mach_clock, &aTime);
5384 + if (ret != KERN_SUCCESS) {
5385 + zlog(ZLOG_STUFF, ZLOG_ERROR, "clock_get_time() failed: %s", mach_error_string(ret));
5389 + tv->tv_sec = aTime.tv_sec;
5390 + tv->tv_usec = aTime.tv_nsec / 1000;
5395 +#else /* no clock */
5397 +int fpm_clock_init()
5402 +int fpm_clock_get(struct timeval *tv)
5404 + return gettimeofday(tv, 0);
5408 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_clock.h php-src/sapi/fpm/fpm/fpm_clock.h
5409 --- php-src-vanilla/sapi/fpm/fpm/fpm_clock.h 1970-01-01 01:00:00.000000000 +0100
5410 +++ php-src/sapi/fpm/fpm/fpm_clock.h 2009-10-18 21:05:39.310440424 +0100
5414 + /* (c) 2007,2008 Andrei Nigmatulin */
5416 +#ifndef FPM_CLOCK_H
5417 +#define FPM_CLOCK_H 1
5419 +#include <sys/time.h>
5421 +int fpm_clock_init();
5422 +int fpm_clock_get(struct timeval *tv);
5425 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_conf.c php-src/sapi/fpm/fpm/fpm_conf.c
5426 --- php-src-vanilla/sapi/fpm/fpm/fpm_conf.c 1970-01-01 01:00:00.000000000 +0100
5427 +++ php-src/sapi/fpm/fpm/fpm_conf.c 2009-10-18 21:05:39.310440424 +0100
5431 + /* (c) 2007,2008 Andrei Nigmatulin */
5433 +#include "fpm_config.h"
5435 +#include <sys/types.h>
5436 +#include <sys/stat.h>
5438 +#include <string.h>
5439 +#include <stdlib.h>
5440 +#include <stddef.h>
5441 +#if HAVE_INTTYPES_H
5442 +#include <inttypes.h>
5444 +#include <stdint.h>
5448 +#include <unistd.h>
5451 +#include "fpm_conf.h"
5452 +#include "fpm_stdio.h"
5453 +#include "fpm_worker_pool.h"
5454 +#include "fpm_cleanup.h"
5455 +#include "fpm_php.h"
5456 +#include "fpm_sockets.h"
5457 +#include "xml_config.h"
5461 +struct fpm_global_config_s fpm_global_config;
5463 +static void *fpm_global_config_ptr()
5465 + return &fpm_global_config;
5468 +static char *fpm_conf_set_log_level(void **conf, char *name, void *vv, intptr_t offset)
5472 + if (!strcmp(value, "debug")) {
5473 + fpm_globals.log_level = ZLOG_DEBUG;
5475 + else if (!strcmp(value, "notice")) {
5476 + fpm_globals.log_level = ZLOG_NOTICE;
5478 + else if (!strcmp(value, "warn")) {
5479 + fpm_globals.log_level = ZLOG_WARNING;
5481 + else if (!strcmp(value, "error")) {
5482 + fpm_globals.log_level = ZLOG_ERROR;
5484 + else if (!strcmp(value, "alert")) {
5485 + fpm_globals.log_level = ZLOG_ALERT;
5488 + return "invalid value for 'log_level'";
5494 +static struct xml_conf_section xml_section_fpm_global_options = {
5495 + .conf = &fpm_global_config_ptr,
5496 + .path = "/configuration/global_options",
5497 + .parsers = (struct xml_value_parser []) {
5498 + { XML_CONF_SCALAR, "emergency_restart_threshold", &xml_conf_set_slot_integer, offsetof(struct fpm_global_config_s, emergency_restart_threshold) },
5499 + { XML_CONF_SCALAR, "emergency_restart_interval", &xml_conf_set_slot_time, offsetof(struct fpm_global_config_s, emergency_restart_interval) },
5500 + { XML_CONF_SCALAR, "process_control_timeout", &xml_conf_set_slot_time, offsetof(struct fpm_global_config_s, process_control_timeout) },
5501 + { XML_CONF_SCALAR, "daemonize", &xml_conf_set_slot_boolean, offsetof(struct fpm_global_config_s, daemonize) },
5502 + { XML_CONF_SCALAR, "pid_file", &xml_conf_set_slot_string, offsetof(struct fpm_global_config_s, pid_file) },
5503 + { XML_CONF_SCALAR, "error_log", &xml_conf_set_slot_string, offsetof(struct fpm_global_config_s, error_log) },
5504 + { XML_CONF_SCALAR, "log_level", &fpm_conf_set_log_level, 0 },
5509 +static char *fpm_conf_set_pm_style(void **conf, char *name, void *vv, intptr_t offset)
5512 + struct fpm_pm_s *c = *conf;
5514 + if (!strcmp(value, "static")) {
5515 + c->style = PM_STYLE_STATIC;
5517 + else if (!strcmp(value, "apache-like")) {
5518 + c->style = PM_STYLE_APACHE_LIKE;
5521 + return "invalid value for 'style'";
5527 +static char *fpm_conf_set_rlimit_core(void **conf, char *name, void *vv, intptr_t offset)
5530 + struct fpm_worker_pool_config_s *c = *conf;
5532 + if (!strcmp(value, "unlimited")) {
5533 + c->rlimit_core = -1;
5537 + void *subconf = &int_value;
5540 + error = xml_conf_set_slot_integer(&subconf, name, vv, 0);
5542 + if (error) { return error; }
5544 + if (int_value < 0) { return "invalid value for 'rlimit_core'"; }
5546 + c->rlimit_core = int_value;
5552 +static char *fpm_conf_set_catch_workers_output(void **conf, char *name, void *vv, intptr_t offset)
5554 + struct fpm_worker_pool_config_s *c = *conf;
5556 + void *subconf = &int_value;
5559 + error = xml_conf_set_slot_boolean(&subconf, name, vv, 0);
5561 + if (error) { return error; }
5563 + c->catch_workers_output = int_value;
5568 +static struct xml_conf_section fpm_conf_set_apache_like_subsection_conf = {
5569 + .path = "apache_like somewhere", /* fixme */
5570 + .parsers = (struct xml_value_parser []) {
5571 + { XML_CONF_SCALAR, "StartServers", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, options_apache_like.StartServers) },
5572 + { XML_CONF_SCALAR, "MinSpareServers", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, options_apache_like.MinSpareServers) },
5573 + { XML_CONF_SCALAR, "MaxSpareServers", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, options_apache_like.MaxSpareServers) },
5578 +static char *fpm_conf_set_apache_like_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
5580 + return xml_conf_parse_section(conf, &fpm_conf_set_apache_like_subsection_conf, xml_node);
5583 +static struct xml_conf_section fpm_conf_set_listen_options_subsection_conf = {
5584 + .path = "listen options somewhere", /* fixme */
5585 + .parsers = (struct xml_value_parser []) {
5586 + { XML_CONF_SCALAR, "backlog", &xml_conf_set_slot_integer, offsetof(struct fpm_listen_options_s, backlog) },
5587 + { XML_CONF_SCALAR, "owner", &xml_conf_set_slot_string, offsetof(struct fpm_listen_options_s, owner) },
5588 + { XML_CONF_SCALAR, "group", &xml_conf_set_slot_string, offsetof(struct fpm_listen_options_s, group) },
5589 + { XML_CONF_SCALAR, "mode", &xml_conf_set_slot_string, offsetof(struct fpm_listen_options_s, mode) },
5594 +static char *fpm_conf_set_listen_options_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
5596 + void *subconf = (char *) *conf + offset;
5597 + struct fpm_listen_options_s *lo;
5599 + lo = malloc(sizeof(*lo));
5602 + return "malloc() failed";
5605 + memset(lo, 0, sizeof(*lo));
5609 + * (struct fpm_listen_options_s **) subconf = lo;
5613 + return xml_conf_parse_section(&subconf, &fpm_conf_set_listen_options_subsection_conf, xml_node);
5616 +static struct xml_conf_section fpm_conf_set_pm_subsection_conf = {
5617 + .path = "pm settings somewhere", /* fixme */
5618 + .parsers = (struct xml_value_parser []) {
5619 + { XML_CONF_SCALAR, "style", &fpm_conf_set_pm_style, 0 },
5620 + { XML_CONF_SCALAR, "max_children", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, max_children) },
5621 + { XML_CONF_SUBSECTION, "apache_like", &fpm_conf_set_apache_like_subsection, offsetof(struct fpm_pm_s, options_apache_like) },
5626 +static char *fpm_conf_set_pm_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
5628 + void *subconf = (char *) *conf + offset;
5629 + struct fpm_pm_s *pm;
5631 + pm = malloc(sizeof(*pm));
5634 + return "fpm_conf_set_pm_subsection(): malloc failed";
5637 + memset(pm, 0, sizeof(*pm));
5639 + * (struct fpm_pm_s **) subconf = pm;
5643 + return xml_conf_parse_section(&subconf, &fpm_conf_set_pm_subsection_conf, xml_node);
5646 +static char *xml_conf_set_slot_key_value_pair(void **conf, char *name, void *vv, intptr_t offset)
5649 + struct key_value_s *kv;
5650 + struct key_value_s ***parent = (struct key_value_s ***) conf;
5652 + kv = malloc(sizeof(*kv));
5655 + return "malloc() failed";
5658 + memset(kv, 0, sizeof(*kv));
5660 + kv->key = strdup(name);
5661 + kv->value = strdup(value);
5663 + if (!kv->key || !kv->value) {
5664 + return "xml_conf_set_slot_key_value_pair(): strdup() failed";
5669 + *parent = &kv->next;
5674 +static struct xml_conf_section fpm_conf_set_key_value_pairs_subsection_conf = {
5675 + .path = "key_value_pairs somewhere", /* fixme */
5676 + .parsers = (struct xml_value_parser []) {
5677 + { XML_CONF_SCALAR, 0, &xml_conf_set_slot_key_value_pair, 0 },
5682 +static char *fpm_conf_set_key_value_pairs_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
5684 + void *next_kv = (char *) *conf + offset;
5686 + return xml_conf_parse_section(&next_kv, &fpm_conf_set_key_value_pairs_subsection_conf, xml_node);
5689 +static void *fpm_worker_pool_config_alloc()
5691 + static struct fpm_worker_pool_s *current_wp = 0;
5692 + struct fpm_worker_pool_s *wp;
5694 + wp = fpm_worker_pool_alloc();
5696 + if (!wp) { return 0; }
5698 + wp->config = malloc(sizeof(struct fpm_worker_pool_config_s));
5700 + if (!wp->config) { return 0; }
5702 + memset(wp->config, 0, sizeof(struct fpm_worker_pool_config_s));
5704 + if (current_wp) { current_wp->next = wp; }
5708 + return wp->config;
5711 +int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc)
5713 + struct key_value_s *kv, *kv_next;
5716 + free(wpc->listen_address);
5717 + if (wpc->listen_options) {
5718 + free(wpc->listen_options->owner);
5719 + free(wpc->listen_options->group);
5720 + free(wpc->listen_options->mode);
5721 + free(wpc->listen_options);
5723 + for (kv = wpc->php_defines; kv; kv = kv_next) {
5724 + kv_next = kv->next;
5729 + for (kv = wpc->environment; kv; kv = kv_next) {
5730 + kv_next = kv->next;
5738 + free(wpc->chroot);
5740 + free(wpc->allowed_clients);
5741 + free(wpc->slowlog);
5746 +static struct xml_conf_section xml_section_fpm_worker_pool_config = {
5747 + .conf = &fpm_worker_pool_config_alloc,
5748 + .path = "/configuration/workers/pool",
5749 + .parsers = (struct xml_value_parser []) {
5750 + { XML_CONF_SCALAR, "name", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, name) },
5751 + { XML_CONF_SCALAR, "listen_address", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, listen_address) },
5752 + { XML_CONF_SUBSECTION, "listen_options", &fpm_conf_set_listen_options_subsection, offsetof(struct fpm_worker_pool_config_s, listen_options) },
5753 + { XML_CONF_SUBSECTION, "php_defines", &fpm_conf_set_key_value_pairs_subsection, offsetof(struct fpm_worker_pool_config_s, php_defines) },
5754 + { XML_CONF_SCALAR, "user", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, user) },
5755 + { XML_CONF_SCALAR, "group", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, group) },
5756 + { XML_CONF_SCALAR, "chroot", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, chroot) },
5757 + { XML_CONF_SCALAR, "chdir", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, chdir) },
5758 + { XML_CONF_SCALAR, "allowed_clients", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, allowed_clients) },
5759 + { XML_CONF_SUBSECTION, "environment", &fpm_conf_set_key_value_pairs_subsection, offsetof(struct fpm_worker_pool_config_s, environment) },
5760 + { XML_CONF_SCALAR, "request_terminate_timeout", &xml_conf_set_slot_time, offsetof(struct fpm_worker_pool_config_s, request_terminate_timeout) },
5761 + { XML_CONF_SCALAR, "request_slowlog_timeout", &xml_conf_set_slot_time, offsetof(struct fpm_worker_pool_config_s, request_slowlog_timeout) },
5762 + { XML_CONF_SCALAR, "slowlog", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, slowlog) },
5763 + { XML_CONF_SCALAR, "rlimit_files", &xml_conf_set_slot_integer, offsetof(struct fpm_worker_pool_config_s, rlimit_files) },
5764 + { XML_CONF_SCALAR, "rlimit_core", &fpm_conf_set_rlimit_core, 0 },
5765 + { XML_CONF_SCALAR, "max_requests", &xml_conf_set_slot_integer, offsetof(struct fpm_worker_pool_config_s, max_requests) },
5766 + { XML_CONF_SCALAR, "catch_workers_output", &fpm_conf_set_catch_workers_output, 0 },
5767 + { XML_CONF_SUBSECTION, "pm", &fpm_conf_set_pm_subsection, offsetof(struct fpm_worker_pool_config_s, pm) },
5772 +static struct xml_conf_section *fpm_conf_all_sections[] = {
5773 + &xml_section_fpm_global_options,
5774 + &xml_section_fpm_worker_pool_config,
5778 +static int fpm_evaluate_full_path(char **path)
5780 + if (**path != '/') {
5783 + full_path = malloc(sizeof(PHP_PREFIX) + strlen(*path) + 1);
5785 + if (!full_path) { return -1; }
5787 + sprintf(full_path, "%s/%s", PHP_PREFIX, *path);
5791 + *path = full_path;
5797 +static int fpm_conf_process_all_pools()
5799 + struct fpm_worker_pool_s *wp;
5801 + if (!fpm_worker_all_pools) {
5802 + zlog(ZLOG_STUFF, ZLOG_ERROR, "at least one pool section must be specified in config file");
5806 + for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
5808 + if (wp->config->listen_address && *wp->config->listen_address) {
5810 + wp->listen_address_domain = fpm_sockets_domain_from_address(wp->config->listen_address);
5812 + if (wp->listen_address_domain == FPM_AF_UNIX && *wp->config->listen_address != '/') {
5813 + fpm_evaluate_full_path(&wp->config->listen_address);
5819 + wp->is_template = 1;
5823 + if (wp->config->request_slowlog_timeout) {
5825 + if (! (wp->config->slowlog && *wp->config->slowlog)) {
5826 + zlog(ZLOG_STUFF, ZLOG_ERROR, "pool %s: 'slowlog' must be specified for use with 'request_slowlog_timeout'",
5827 + wp->config->name);
5831 + static int warned = 0;
5834 + zlog(ZLOG_STUFF, ZLOG_WARNING, "pool %s: 'request_slowlog_timeout' is not supported on your system",
5835 + wp->config->name);
5839 + wp->config->request_slowlog_timeout = 0;
5843 + if (wp->config->request_slowlog_timeout && wp->config->slowlog && *wp->config->slowlog) {
5846 + fpm_evaluate_full_path(&wp->config->slowlog);
5848 + if (wp->config->request_slowlog_timeout) {
5849 + fd = open(wp->config->slowlog, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
5852 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(%s) failed", wp->config->slowlog);
5863 +int fpm_conf_unlink_pid()
5865 + if (fpm_global_config.pid_file) {
5867 + if (0 > unlink(fpm_global_config.pid_file)) {
5868 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "unlink(\"%s\") failed", fpm_global_config.pid_file);
5877 +int fpm_conf_write_pid()
5881 + if (fpm_global_config.pid_file) {
5885 + unlink(fpm_global_config.pid_file);
5887 + fd = creat(fpm_global_config.pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
5890 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "creat(\"%s\") failed", fpm_global_config.pid_file);
5894 + len = sprintf(buf, "%d", (int) fpm_globals.parent_pid);
5896 + if (len != write(fd, buf, len)) {
5897 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "write() failed");
5907 +static int fpm_conf_post_process()
5909 + if (fpm_global_config.pid_file) {
5910 + fpm_evaluate_full_path(&fpm_global_config.pid_file);
5913 + if (!fpm_global_config.error_log) {
5914 + fpm_global_config.error_log = strdup(PHP_FPM_LOG_PATH);
5917 + fpm_evaluate_full_path(&fpm_global_config.error_log);
5919 + if (0 > fpm_stdio_open_error_log(0)) {
5923 + return fpm_conf_process_all_pools();
5926 +static void fpm_conf_cleanup(int which, void *arg)
5928 + free(fpm_global_config.pid_file);
5929 + free(fpm_global_config.error_log);
5930 + fpm_global_config.pid_file = 0;
5931 + fpm_global_config.error_log = 0;
5934 +int fpm_conf_init_main()
5936 + char *filename = fpm_globals.config;
5939 + if (0 > xml_conf_sections_register(fpm_conf_all_sections)) {
5943 + if (filename == NULL) {
5944 + filename = PHP_FPM_CONF_PATH;
5947 + err = xml_conf_load_file(filename);
5950 + zlog(ZLOG_STUFF, ZLOG_ERROR, "failed to load configuration file: %s", err);
5954 + if (0 > fpm_conf_post_process()) {
5960 + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_conf_cleanup, 0)) {
5966 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_conf.h php-src/sapi/fpm/fpm/fpm_conf.h
5967 --- php-src-vanilla/sapi/fpm/fpm/fpm_conf.h 1970-01-01 01:00:00.000000000 +0100
5968 +++ php-src/sapi/fpm/fpm/fpm_conf.h 2009-10-18 21:05:39.308376784 +0100
5972 + /* (c) 2007,2008 Andrei Nigmatulin */
5975 +#define FPM_CONF_H 1
5977 +struct key_value_s;
5979 +struct key_value_s {
5980 + struct key_value_s *next;
5985 +struct fpm_global_config_s {
5986 + int emergency_restart_threshold;
5987 + int emergency_restart_interval;
5988 + int process_control_timeout;
5994 +extern struct fpm_global_config_s fpm_global_config;
6001 + int MinSpareServers;
6002 + int MaxSpareServers;
6003 + } options_apache_like;
6006 +struct fpm_listen_options_s {
6013 +struct fpm_worker_pool_config_s {
6015 + char *listen_address;
6016 + struct fpm_listen_options_s *listen_options;
6017 + struct key_value_s *php_defines;
6022 + char *allowed_clients;
6023 + struct key_value_s *environment;
6024 + struct fpm_pm_s *pm;
6025 + int request_terminate_timeout;
6026 + int request_slowlog_timeout;
6031 + unsigned catch_workers_output:1;
6034 +enum { PM_STYLE_STATIC = 1, PM_STYLE_APACHE_LIKE = 2 };
6036 +int fpm_conf_init_main();
6037 +int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc);
6038 +int fpm_conf_write_pid();
6039 +int fpm_conf_unlink_pid();
6043 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_config.h php-src/sapi/fpm/fpm/fpm_config.h
6044 --- php-src-vanilla/sapi/fpm/fpm/fpm_config.h 1970-01-01 01:00:00.000000000 +0100
6045 +++ php-src/sapi/fpm/fpm/fpm_config.h 2009-10-18 21:05:39.310440424 +0100
6049 + /* (c) 2007,2008 Andrei Nigmatulin */
6051 +#include <php_config.h>
6052 +#ifdef FPM_AUTOCONFIG_H
6053 +#include <fpm_autoconfig.h>
6056 +/* Solaris does not have it */
6057 +#ifndef INADDR_NONE
6058 +#define INADDR_NONE (-1)
6062 +/* If we're not using GNU C, elide __attribute__ */
6064 +# define __attribute__(x) /*NOTHING*/
6068 +/* Solaris does not have it */
6070 +#define timersub(tvp, uvp, vvp) \
6072 + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
6073 + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
6074 + if ((vvp)->tv_usec < 0) { \
6075 + (vvp)->tv_sec--; \
6076 + (vvp)->tv_usec += 1000000; \
6081 +#if defined(HAVE_PTRACE) || defined(PROC_MEM_FILE) || defined(HAVE_MACH_VM_READ)
6082 +#define HAVE_FPM_TRACE 1
6084 +#define HAVE_FPM_TRACE 0
6087 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_env.c php-src/sapi/fpm/fpm/fpm_env.c
6088 --- php-src-vanilla/sapi/fpm/fpm/fpm_env.c 1970-01-01 01:00:00.000000000 +0100
6089 +++ php-src/sapi/fpm/fpm/fpm_env.c 2009-10-18 21:05:39.308376784 +0100
6093 + /* (c) 2007,2008 Andrei Nigmatulin */
6095 +#include "fpm_config.h"
6097 +#ifdef HAVE_ALLOCA_H
6098 +#include <alloca.h>
6101 +#include <stdlib.h>
6102 +#include <string.h>
6104 +#include "fpm_env.h"
6107 +#ifndef HAVE_SETENV
6108 +#ifdef (__sparc__ || __sparc)
6109 +int setenv(name, value, clobber)
6118 + if (clobber == 0 && getenv(name) != 0)
6120 + if ((cp = malloc(strlen(name) + strlen(value) + 2)) == 0)
6122 + sprintf(cp, "%s=%s", name, value);
6123 + return (putenv(cp));
6126 +int setenv(char *name, char *value, int overwrite)
6128 + int name_len = strlen(name);
6129 + int value_len = strlen(value);
6130 + char *var = alloca(name_len + 1 + value_len + 1);
6132 + memcpy(var, name, name_len);
6134 + var[name_len] = '=';
6136 + memcpy(var + name_len + 1, value, value_len);
6138 + var[name_len + 1 + value_len] = '\0';
6140 + return putenv(var);
6145 +#ifndef HAVE_CLEARENV
6151 + /* this algo is the only one known to me
6152 + that works well on all systems */
6153 + while (*(envp = environ)) {
6154 + char *eq = strchr(*envp, '=');
6156 + s = strdup(*envp);
6158 + if (eq) { s[eq - *envp] = '\0'; }
6167 +#ifndef HAVE_UNSETENV
6168 +void unsetenv(const char *name)
6170 + if(getenv(name)!=NULL)
6175 + while(environ[ct] != NULL)
6177 + if (nvmatch(name, environ[ct]) != 0) del=ct;
6180 + /* isn't needed free here?? */
6181 + environ[del]=environ[ct-1];
6182 + environ[ct-1]=NULL;
6185 +static char * nvmatch(s1, s2)
6186 +register char *s1, *s2;
6188 + while(*s1 == *s2++)
6193 + if(*s1 == '\0' && *(s2-1) == '=')
6199 +int fpm_env_init_child(struct fpm_worker_pool_s *wp)
6201 + struct key_value_s *kv;
6205 + for (kv = wp->config->environment; kv; kv = kv->next) {
6206 + setenv(kv->key, kv->value, 1);
6210 + setenv("USER", wp->user, 1);
6214 + setenv("HOME", wp->home, 1);
6220 +static int fpm_env_conf_wp(struct fpm_worker_pool_s *wp)
6222 + struct key_value_s *kv;
6224 + kv = wp->config->environment;
6226 + for (kv = wp->config->environment; kv; kv = kv->next) {
6227 + if (*kv->value == '$') {
6228 + char *value = getenv(kv->value + 1);
6230 + if (!value) { value = ""; }
6233 + kv->value = strdup(value);
6236 + /* autodetected values should be removed
6237 + if these vars specified in config */
6238 + if (!strcmp(kv->key, "USER")) {
6243 + if (!strcmp(kv->key, "HOME")) {
6252 +int fpm_env_init_main()
6254 + struct fpm_worker_pool_s *wp;
6256 + for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
6258 + if (0 > fpm_env_conf_wp(wp)) {
6266 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_env.h php-src/sapi/fpm/fpm/fpm_env.h
6267 --- php-src-vanilla/sapi/fpm/fpm/fpm_env.h 1970-01-01 01:00:00.000000000 +0100
6268 +++ php-src/sapi/fpm/fpm/fpm_env.h 2009-10-18 21:05:39.308376784 +0100
6272 + /* (c) 2007,2008 Andrei Nigmatulin */
6275 +#define FPM_ENV_H 1
6277 +#include "fpm_worker_pool.h"
6279 +int fpm_env_init_child(struct fpm_worker_pool_s *wp);
6280 +int fpm_env_init_main();
6282 +extern char **environ;
6284 +#ifndef HAVE_SETENV
6285 +int setenv(char *name, char *value, int overwrite);
6288 +#ifndef HAVE_CLEARENV
6294 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_events.c php-src/sapi/fpm/fpm/fpm_events.c
6295 --- php-src-vanilla/sapi/fpm/fpm/fpm_events.c 1970-01-01 01:00:00.000000000 +0100
6296 +++ php-src/sapi/fpm/fpm/fpm_events.c 2009-10-18 21:05:39.310440424 +0100
6300 + /* (c) 2007,2008 Andrei Nigmatulin */
6302 +#include "fpm_config.h"
6304 +#include <unistd.h>
6306 +#include <stdlib.h> /* for putenv */
6307 +#include <string.h>
6308 +#include <sys/types.h> /* for event.h below */
6312 +#include "fpm_process_ctl.h"
6313 +#include "fpm_events.h"
6314 +#include "fpm_cleanup.h"
6315 +#include "fpm_stdio.h"
6316 +#include "fpm_signals.h"
6317 +#include "fpm_children.h"
6320 +static void fpm_event_cleanup(int which, void *arg)
6322 + event_base_free(0);
6325 +static void fpm_got_signal(int fd, short ev, void *arg)
6333 + res = read(fd, &c, 1);
6334 + } while (res == -1 && errno == EINTR);
6337 + if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
6338 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "read() failed");
6344 + case 'C' : /* SIGCHLD */
6345 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGCHLD");
6346 + fpm_children_bury();
6348 + case 'I' : /* SIGINT */
6349 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGINT");
6350 + fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
6352 + case 'T' : /* SIGTERM */
6353 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGTERM");
6354 + fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
6356 + case 'Q' : /* SIGQUIT */
6357 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGQUIT");
6358 + fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET);
6360 + case '1' : /* SIGUSR1 */
6361 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGUSR1");
6362 + if (0 == fpm_stdio_open_error_log(1)) {
6363 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "log file re-opened");
6366 + case '2' : /* SIGUSR2 */
6367 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGUSR2");
6368 + fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET);
6372 + if (fpm_globals.is_child) {
6381 +int fpm_event_init_main()
6385 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "libevent: using %s", event_get_method());
6387 + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, 0)) {
6394 +int fpm_event_loop()
6396 + static struct event signal_fd_event;
6398 + event_set(&signal_fd_event, fpm_signals_get_fd(), EV_PERSIST | EV_READ, &fpm_got_signal, 0);
6400 + event_add(&signal_fd_event, 0);
6402 + fpm_pctl_heartbeat(-1, 0, 0);
6404 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "libevent: entering main loop");
6411 +int fpm_event_add(int fd, struct event *ev, void (*callback)(int, short, void *), void *arg)
6413 + event_set(ev, fd, EV_PERSIST | EV_READ, callback, arg);
6415 + return event_add(ev, 0);
6418 +int fpm_event_del(struct event *ev)
6420 + return event_del(ev);
6423 +void fpm_event_exit_loop()
6425 + event_loopbreak();
6428 +void fpm_event_fire(struct event *ev)
6430 + (*ev->ev_callback)( (int) ev->ev_fd, (short) ev->ev_res, ev->ev_arg);
6433 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_events.h php-src/sapi/fpm/fpm/fpm_events.h
6434 --- php-src-vanilla/sapi/fpm/fpm/fpm_events.h 1970-01-01 01:00:00.000000000 +0100
6435 +++ php-src/sapi/fpm/fpm/fpm_events.h 2009-10-18 21:05:39.310440424 +0100
6439 + /* (c) 2007,2008 Andrei Nigmatulin */
6441 +#ifndef FPM_EVENTS_H
6442 +#define FPM_EVENTS_H 1
6444 +void fpm_event_exit_loop();
6445 +int fpm_event_loop();
6446 +int fpm_event_add(int fd, struct event *ev, void (*callback)(int, short, void *), void *arg);
6447 +int fpm_event_del(struct event *ev);
6448 +void fpm_event_fire(struct event *ev);
6449 +int fpm_event_init_main();
6453 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm.h php-src/sapi/fpm/fpm/fpm.h
6454 --- php-src-vanilla/sapi/fpm/fpm/fpm.h 1970-01-01 01:00:00.000000000 +0100
6455 +++ php-src/sapi/fpm/fpm/fpm.h 2009-10-18 21:05:39.308376784 +0100
6459 + /* (c) 2007,2008 Andrei Nigmatulin */
6464 +#include <unistd.h>
6466 +int fpm_run(int *max_requests);
6467 +int fpm_init(int argc, char **argv, char *config);
6469 +struct fpm_globals_s {
6474 + int running_children;
6477 + int listening_socket; /* for this child */
6478 + int max_requests; /* for this child */
6482 +extern struct fpm_globals_s fpm_globals;
6485 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_php.c php-src/sapi/fpm/fpm/fpm_php.c
6486 --- php-src-vanilla/sapi/fpm/fpm/fpm_php.c 1970-01-01 01:00:00.000000000 +0100
6487 +++ php-src/sapi/fpm/fpm/fpm_php.c 2009-10-18 21:05:39.310440424 +0100
6491 + /* (c) 2007,2008 Andrei Nigmatulin */
6493 +#include "fpm_config.h"
6495 +#include <stdlib.h>
6496 +#include <string.h>
6500 +#include "php_main.h"
6501 +#include "php_ini.h"
6502 +#include "ext/standard/dl.h"
6504 +#include "cgi/fastcgi.h"
6507 +#include "fpm_php.h"
6508 +#include "fpm_cleanup.h"
6509 +#include "fpm_worker_pool.h"
6511 +static int zend_ini_alter_master(char *name, int name_length, char *new_value, int new_value_length, int stage TSRMLS_DC)
6513 + zend_ini_entry *ini_entry;
6516 + if (zend_hash_find(EG(ini_directives), name, name_length, (void **) &ini_entry) == FAILURE) {
6520 + duplicate = strdup(new_value);
6522 + if (!ini_entry->on_modify
6523 + || ini_entry->on_modify(ini_entry, duplicate, new_value_length,
6524 + ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage TSRMLS_CC) == SUCCESS) {
6525 + ini_entry->value = duplicate;
6526 + ini_entry->value_length = new_value_length;
6534 +static void fpm_php_disable(char *value, int (*zend_disable)(char *, uint TSRMLS_DC) TSRMLS_DC)
6536 + char *s = 0, *e = value;
6544 + zend_disable(s, e - s TSRMLS_CC);
6558 + zend_disable(s, e - s TSRMLS_CC);
6562 +static int fpm_php_apply_defines(struct fpm_worker_pool_s *wp)
6565 + struct key_value_s *kv;
6567 + for (kv = wp->config->php_defines; kv; kv = kv->next) {
6568 + char *name = kv->key;
6569 + char *value = kv->value;
6570 + int name_len = strlen(name);
6571 + int value_len = strlen(value);
6573 + if (!strcmp(name, "extension") && *value) {
6576 +#if defined(PHP_VERSION_ID) && (PHP_VERSION_ID >= 50300)
6577 + php_dl(value, MODULE_PERSISTENT, &zv, 1 TSRMLS_CC);
6580 + ZVAL_STRINGL(&filename, value, value_len, 0);
6581 +#if (PHP_MAJOR_VERSION >= 5)
6582 + php_dl(&filename, MODULE_PERSISTENT, &zv, 1 TSRMLS_CC);
6584 + php_dl(&filename, MODULE_PERSISTENT, &zv TSRMLS_CC);
6590 + zend_ini_alter_master(name, name_len + 1, value, value_len, PHP_INI_STAGE_ACTIVATE TSRMLS_CC);
6592 + if (!strcmp(name, "disable_functions") && *value) {
6593 + char *v = strdup(value);
6594 +#if (PHP_MAJOR_VERSION >= 5)
6595 + PG(disable_functions) = v;
6597 + fpm_php_disable(v, zend_disable_function TSRMLS_CC);
6599 + else if (!strcmp(name, "disable_classes") && *value) {
6600 + char *v = strdup(value);
6601 +#if (PHP_MAJOR_VERSION >= 5)
6602 + PG(disable_classes) = v;
6604 + fpm_php_disable(v, zend_disable_class TSRMLS_CC);
6611 +static int fpm_php_set_allowed_clients(struct fpm_worker_pool_s *wp)
6613 + if (wp->listen_address_domain == FPM_AF_INET) {
6614 + fcgi_set_allowed_clients(wp->config->allowed_clients);
6620 +static int fpm_php_set_fcgi_mgmt_vars(struct fpm_worker_pool_s *wp)
6622 + char max_workers[10 + 1]; /* 4294967295 */
6625 + len = sprintf(max_workers, "%u", (unsigned int) wp->config->pm->max_children);
6627 + fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, max_workers, len);
6628 + fcgi_set_mgmt_var("FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, max_workers, len);
6633 +char *fpm_php_script_filename(TSRMLS_D)
6635 + return SG(request_info).path_translated;
6638 +char *fpm_php_request_method(TSRMLS_D)
6640 + return (char *) SG(request_info).request_method;
6643 +size_t fpm_php_content_length(TSRMLS_D)
6645 + return SG(request_info).content_length;
6648 +static void fpm_php_cleanup(int which, void *arg)
6651 + php_module_shutdown(TSRMLS_C);
6655 +void fpm_php_soft_quit()
6657 + fcgi_set_in_shutdown(1);
6660 +int fpm_php_init_main()
6662 + if (0 > fpm_cleanup_add(FPM_CLEANUP_PARENT, fpm_php_cleanup, 0)) {
6669 +int fpm_php_init_child(struct fpm_worker_pool_s *wp)
6671 + if (0 > fpm_php_apply_defines(wp) ||
6672 + 0 > fpm_php_set_allowed_clients(wp)) {
6678 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_php.h php-src/sapi/fpm/fpm/fpm_php.h
6679 --- php-src-vanilla/sapi/fpm/fpm/fpm_php.h 1970-01-01 01:00:00.000000000 +0100
6680 +++ php-src/sapi/fpm/fpm/fpm_php.h 2009-10-18 21:05:39.302497288 +0100
6684 + /* (c) 2007,2008 Andrei Nigmatulin */
6687 +#define FPM_PHP_H 1
6691 +#include "build-defs.h" /* for PHP_ defines */
6693 +struct fpm_worker_pool_s;
6695 +int fpm_php_init_child(struct fpm_worker_pool_s *wp);
6696 +char *fpm_php_script_filename(TSRMLS_D);
6697 +char *fpm_php_request_method(TSRMLS_D);
6698 +size_t fpm_php_content_length(TSRMLS_D);
6699 +void fpm_php_soft_quit();
6700 +int fpm_php_init_main();
6704 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_php_trace.c php-src/sapi/fpm/fpm/fpm_php_trace.c
6705 --- php-src-vanilla/sapi/fpm/fpm/fpm_php_trace.c 1970-01-01 01:00:00.000000000 +0100
6706 +++ php-src/sapi/fpm/fpm/fpm_php_trace.c 2009-10-18 21:05:39.310440424 +0100
6710 + /* (c) 2007,2008 Andrei Nigmatulin */
6712 +#include "fpm_config.h"
6717 +#include "php_main.h"
6720 +#include <stddef.h>
6721 +#if HAVE_INTTYPES_H
6722 +#include <inttypes.h>
6724 +#include <stdint.h>
6727 +#include <unistd.h>
6728 +#include <sys/time.h>
6729 +#include <sys/types.h>
6732 +#include "fpm_trace.h"
6733 +#include "fpm_php_trace.h"
6734 +#include "fpm_children.h"
6735 +#include "fpm_worker_pool.h"
6736 +#include "fpm_process_ctl.h"
6741 +#define valid_ptr(p) ((p) && 0 == ((p) & (sizeof(long) - 1)))
6743 +#if SIZEOF_LONG == 4
6744 +#define PTR_FMT "08"
6745 +#elif SIZEOF_LONG == 8
6746 +#define PTR_FMT "016"
6750 +static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC)
6752 + int callers_limit = 20;
6753 + pid_t pid = child->pid;
6754 + struct timeval tv;
6755 + static const int buf_size = 1024;
6756 + char buf[buf_size];
6757 + long execute_data;
6760 + gettimeofday(&tv, 0);
6762 + zlog_print_time(&tv, buf, buf_size);
6764 + fprintf(slowlog, "\n%s pid %d (pool %s)\n", buf, (int) pid, child->wp->config->name);
6766 + if (0 > fpm_trace_get_strz(buf, buf_size, (long) &SG(request_info).path_translated)) {
6770 + fprintf(slowlog, "script_filename = %s\n", buf);
6772 + if (0 > fpm_trace_get_long((long) &EG(current_execute_data), &l)) {
6778 + while (execute_data) {
6782 + fprintf(slowlog, "[0x%" PTR_FMT "lx] ", execute_data);
6784 + if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, function_state.function), &l)) {
6790 + if (valid_ptr(function)) {
6791 + if (0 > fpm_trace_get_strz(buf, buf_size, function + offsetof(zend_function, common.function_name))) {
6795 + fprintf(slowlog, "%s()", buf);
6798 + fprintf(slowlog, "???");
6801 + if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, op_array), &l)) {
6807 + if (valid_ptr(l)) {
6808 + long op_array = l;
6810 + if (0 > fpm_trace_get_strz(buf, buf_size, op_array + offsetof(zend_op_array, filename))) {
6815 + if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, opline), &l)) {
6819 + if (valid_ptr(l)) {
6821 + uint *lu = (uint *) &l;
6823 + if (0 > fpm_trace_get_long(opline + offsetof(struct _zend_op, lineno), &l)) {
6830 + fprintf(slowlog, " %s:%u\n", *buf ? buf : "unknown", lineno);
6832 + if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, prev_execute_data), &l)) {
6838 + if (0 == --callers_limit) {
6846 +void fpm_php_trace(struct fpm_child_s *child)
6851 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "about to trace %d", (int) child->pid);
6853 + slowlog = fopen(child->wp->config->slowlog, "a+");
6856 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fopen(%s) failed", child->wp->config->slowlog);
6860 + if (0 > fpm_trace_ready(child->pid)) {
6864 + if (0 > fpm_php_trace_dump(child, slowlog TSRMLS_CC)) {
6865 + fprintf(slowlog, "+++ dump failed\n");
6868 + if (0 > fpm_trace_close(child->pid)) {
6876 + fpm_pctl_kill(child->pid, FPM_PCTL_CONT);
6877 + child->tracer = 0;
6879 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "finished trace of %d", (int) child->pid);
6884 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_php_trace.h php-src/sapi/fpm/fpm/fpm_php_trace.h
6885 --- php-src-vanilla/sapi/fpm/fpm/fpm_php_trace.h 1970-01-01 01:00:00.000000000 +0100
6886 +++ php-src/sapi/fpm/fpm/fpm_php_trace.h 2009-10-18 21:05:39.310440424 +0100
6890 + /* (c) 2007,2008 Andrei Nigmatulin */
6892 +#ifndef FPM_PHP_TRACE_H
6893 +#define FPM_PHP_TRACE_H 1
6895 +struct fpm_child_s;
6897 +void fpm_php_trace(struct fpm_child_s *);
6901 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_process_ctl.c php-src/sapi/fpm/fpm/fpm_process_ctl.c
6902 --- php-src-vanilla/sapi/fpm/fpm/fpm_process_ctl.c 1970-01-01 01:00:00.000000000 +0100
6903 +++ php-src/sapi/fpm/fpm/fpm_process_ctl.c 2009-10-18 21:05:39.308376784 +0100
6907 + /* (c) 2007,2008 Andrei Nigmatulin */
6909 +#include "fpm_config.h"
6911 +#include <sys/types.h>
6912 +#include <signal.h>
6913 +#include <unistd.h>
6914 +#include <stdlib.h>
6917 +#include "fpm_clock.h"
6918 +#include "fpm_children.h"
6919 +#include "fpm_signals.h"
6920 +#include "fpm_events.h"
6921 +#include "fpm_process_ctl.h"
6922 +#include "fpm_cleanup.h"
6923 +#include "fpm_request.h"
6924 +#include "fpm_worker_pool.h"
6928 +static int fpm_state = FPM_PCTL_STATE_NORMAL;
6929 +static int fpm_signal_sent = 0;
6932 +static const char *fpm_state_names[] = {
6933 + [FPM_PCTL_STATE_NORMAL] = "normal",
6934 + [FPM_PCTL_STATE_RELOADING] = "reloading",
6935 + [FPM_PCTL_STATE_TERMINATING] = "terminating",
6936 + [FPM_PCTL_STATE_FINISHING] = "finishing"
6939 +static int saved_argc;
6940 +static char **saved_argv;
6942 +static void fpm_pctl_cleanup(int which, void *arg)
6946 + if (which != FPM_CLEANUP_PARENT_EXEC) {
6948 + for (i = 0; i < saved_argc; i++) {
6949 + free(saved_argv[i]);
6957 +static struct event pctl_event;
6959 +static void fpm_pctl_action(int fd, short which, void *arg)
6961 + evtimer_del(&pctl_event);
6963 + memset(&pctl_event, 0, sizeof(pctl_event));
6965 + fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_TIMEOUT);
6968 +static int fpm_pctl_timeout_set(int sec)
6970 + struct timeval tv = { .tv_sec = sec, .tv_usec = 0 };
6972 + if (evtimer_initialized(&pctl_event)) {
6973 + evtimer_del(&pctl_event);
6976 + evtimer_set(&pctl_event, &fpm_pctl_action, 0);
6978 + evtimer_add(&pctl_event, &tv);
6983 +static void fpm_pctl_exit()
6985 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "exiting, bye-bye!");
6987 + fpm_conf_unlink_pid();
6989 + fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT_MAIN);
6994 +#define optional_arg(c) (saved_argc > c ? ", \"" : ""), (saved_argc > c ? saved_argv[c] : ""), (saved_argc > c ? "\"" : "")
6996 +static void fpm_pctl_exec()
6999 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "reloading: execvp(\"%s\", {\"%s\""
7000 + "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s"
7001 + "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s"
7003 + saved_argv[0], saved_argv[0],
7016 + fpm_cleanups_run(FPM_CLEANUP_PARENT_EXEC);
7018 + execvp(saved_argv[0], saved_argv);
7020 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "execvp() failed");
7025 +static void fpm_pctl_action_last()
7027 + switch (fpm_state) {
7029 + case FPM_PCTL_STATE_RELOADING :
7034 + case FPM_PCTL_STATE_FINISHING :
7036 + case FPM_PCTL_STATE_TERMINATING :
7043 +int fpm_pctl_kill(pid_t pid, int how)
7048 + case FPM_PCTL_TERM :
7051 + case FPM_PCTL_STOP :
7054 + case FPM_PCTL_CONT :
7061 + return kill(pid, s);
7064 +static void fpm_pctl_kill_all(int signo)
7066 + struct fpm_worker_pool_s *wp;
7067 + int alive_children = 0;
7069 + for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
7070 + struct fpm_child_s *child;
7072 + for (child = wp->children; child; child = child->next) {
7074 + int res = kill(child->pid, signo);
7076 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "sending signal %d %s to child %d (pool %s)", signo,
7077 + fpm_signal_names[signo] ? fpm_signal_names[signo] : "",
7078 + (int) child->pid, child->wp->config->name);
7080 + if (res == 0) { ++alive_children; }
7084 + if (alive_children) {
7085 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "%d %s still alive", alive_children, alive_children == 1 ? "child is" : "children are");
7089 +static void fpm_pctl_action_next()
7093 + if (!fpm_globals.running_children) { fpm_pctl_action_last(); }
7095 + if (fpm_signal_sent == 0) {
7096 + if (fpm_state == FPM_PCTL_STATE_TERMINATING) {
7102 + timeout = fpm_global_config.process_control_timeout;
7105 + if (fpm_signal_sent == SIGQUIT) {
7114 + fpm_pctl_kill_all(sig);
7116 + fpm_signal_sent = sig;
7118 + fpm_pctl_timeout_set(timeout);
7121 +void fpm_pctl(int new_state, int action)
7125 + case FPM_PCTL_ACTION_SET :
7127 + if (fpm_state == new_state) { /* already in progress - just ignore duplicate signal */
7131 + switch (fpm_state) { /* check which states can be overridden */
7133 + case FPM_PCTL_STATE_NORMAL :
7135 + /* 'normal' can be overridden by any other state */
7138 + case FPM_PCTL_STATE_RELOADING :
7140 + /* 'reloading' can be overridden by 'finishing' */
7141 + if (new_state == FPM_PCTL_STATE_FINISHING) { break; }
7143 + case FPM_PCTL_STATE_FINISHING :
7145 + /* 'reloading' and 'finishing' can be overridden by 'terminating' */
7146 + if (new_state == FPM_PCTL_STATE_TERMINATING) { break; }
7148 + case FPM_PCTL_STATE_TERMINATING :
7150 + /* nothing can override 'terminating' state */
7151 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "not switching to '%s' state, because already in '%s' state",
7152 + fpm_state_names[new_state], fpm_state_names[fpm_state]);
7157 + fpm_signal_sent = 0;
7158 + fpm_state = new_state;
7160 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "switching to '%s' state", fpm_state_names[fpm_state]);
7164 + case FPM_PCTL_ACTION_TIMEOUT :
7166 + fpm_pctl_action_next();
7170 + case FPM_PCTL_ACTION_LAST_CHILD_EXITED :
7172 + fpm_pctl_action_last();
7179 +int fpm_pctl_can_spawn_children()
7181 + return fpm_state == FPM_PCTL_STATE_NORMAL;
7184 +int fpm_pctl_child_exited()
7186 + if (fpm_state == FPM_PCTL_STATE_NORMAL) { return 0; }
7188 + if (!fpm_globals.running_children) {
7189 + fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_LAST_CHILD_EXITED);
7195 +int fpm_pctl_init_main()
7199 + saved_argc = fpm_globals.argc;
7201 + saved_argv = malloc(sizeof(char *) * (saved_argc + 1));
7203 + if (!saved_argv) {
7207 + for (i = 0; i < saved_argc; i++) {
7208 + saved_argv[i] = strdup(fpm_globals.argv[i]);
7210 + if (!saved_argv[i]) {
7215 + saved_argv[i] = 0;
7217 + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_pctl_cleanup, 0)) {
7224 +static void fpm_pctl_check_request_timeout(struct timeval *now)
7226 + struct fpm_worker_pool_s *wp;
7228 + for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
7229 + int terminate_timeout = wp->config->request_terminate_timeout;
7230 + int slowlog_timeout = wp->config->request_slowlog_timeout;
7231 + struct fpm_child_s *child;
7233 + if (terminate_timeout || slowlog_timeout) {
7234 + for (child = wp->children; child; child = child->next) {
7235 + fpm_request_check_timed_out(child, now, terminate_timeout, slowlog_timeout);
7242 +void fpm_pctl_heartbeat(int fd, short which, void *arg)
7244 + static struct event heartbeat;
7245 + struct timeval tv = { .tv_sec = 0, .tv_usec = 130000 };
7246 + struct timeval now;
7248 + if (which == EV_TIMEOUT) {
7249 + evtimer_del(&heartbeat);
7250 + fpm_clock_get(&now);
7251 + fpm_pctl_check_request_timeout(&now);
7254 + evtimer_set(&heartbeat, &fpm_pctl_heartbeat, 0);
7256 + evtimer_add(&heartbeat, &tv);
7259 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_process_ctl.h php-src/sapi/fpm/fpm/fpm_process_ctl.h
7260 --- php-src-vanilla/sapi/fpm/fpm/fpm_process_ctl.h 1970-01-01 01:00:00.000000000 +0100
7261 +++ php-src/sapi/fpm/fpm/fpm_process_ctl.h 2009-10-18 21:05:39.310440424 +0100
7265 + /* (c) 2007,2008 Andrei Nigmatulin */
7267 +#ifndef FPM_PROCESS_CTL_H
7268 +#define FPM_PROCESS_CTL_H 1
7270 +struct fpm_child_s;
7272 +void fpm_pctl(int new_state, int action);
7273 +int fpm_pctl_can_spawn_children();
7274 +int fpm_pctl_kill(pid_t pid, int how);
7275 +void fpm_pctl_heartbeat(int fd, short which, void *arg);
7276 +int fpm_pctl_child_exited();
7277 +int fpm_pctl_init_main();
7281 + FPM_PCTL_STATE_UNSPECIFIED,
7282 + FPM_PCTL_STATE_NORMAL,
7283 + FPM_PCTL_STATE_RELOADING,
7284 + FPM_PCTL_STATE_TERMINATING,
7285 + FPM_PCTL_STATE_FINISHING
7289 + FPM_PCTL_ACTION_SET,
7290 + FPM_PCTL_ACTION_TIMEOUT,
7291 + FPM_PCTL_ACTION_LAST_CHILD_EXITED
7302 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_request.c php-src/sapi/fpm/fpm/fpm_request.c
7303 --- php-src-vanilla/sapi/fpm/fpm/fpm_request.c 1970-01-01 01:00:00.000000000 +0100
7304 +++ php-src/sapi/fpm/fpm/fpm_request.c 2009-10-18 21:05:39.310440424 +0100
7308 + /* (c) 2007,2008 Andrei Nigmatulin */
7310 +#include "fpm_config.h"
7312 +#include "fpm_php.h"
7313 +#include "fpm_str.h"
7314 +#include "fpm_clock.h"
7315 +#include "fpm_conf.h"
7316 +#include "fpm_trace.h"
7317 +#include "fpm_php_trace.h"
7318 +#include "fpm_process_ctl.h"
7319 +#include "fpm_children.h"
7320 +#include "fpm_shm_slots.h"
7321 +#include "fpm_request.h"
7325 +void fpm_request_accepting()
7327 + struct fpm_shm_slot_s *slot;
7329 + slot = fpm_shm_slots_acquire(0, 0);
7331 + slot->request_stage = FPM_REQUEST_ACCEPTING;
7333 + fpm_clock_get(&slot->tv);
7334 + memset(slot->request_method, 0, sizeof(slot->request_method));
7335 + slot->content_length = 0;
7336 + memset(slot->script_filename, 0, sizeof(slot->script_filename));
7338 + fpm_shm_slots_release(slot);
7341 +void fpm_request_reading_headers()
7343 + struct fpm_shm_slot_s *slot;
7345 + slot = fpm_shm_slots_acquire(0, 0);
7347 + slot->request_stage = FPM_REQUEST_READING_HEADERS;
7349 + fpm_clock_get(&slot->tv);
7350 + slot->accepted = slot->tv;
7352 + fpm_shm_slots_release(slot);
7355 +void fpm_request_info()
7358 + struct fpm_shm_slot_s *slot;
7359 + char *request_method = fpm_php_request_method(TSRMLS_C);
7360 + char *script_filename = fpm_php_script_filename(TSRMLS_C);
7362 + slot = fpm_shm_slots_acquire(0, 0);
7364 + slot->request_stage = FPM_REQUEST_INFO;
7366 + fpm_clock_get(&slot->tv);
7368 + if (request_method) {
7369 + cpystrn(slot->request_method, request_method, sizeof(slot->request_method));
7372 + slot->content_length = fpm_php_content_length(TSRMLS_C);
7374 + /* if cgi.fix_pathinfo is set to "1" and script cannot be found (404)
7375 + the sapi_globals.request_info.path_translated is set to NULL */
7376 + if (script_filename) {
7377 + cpystrn(slot->script_filename, script_filename, sizeof(slot->script_filename));
7380 + fpm_shm_slots_release(slot);
7383 +void fpm_request_executing()
7385 + struct fpm_shm_slot_s *slot;
7387 + slot = fpm_shm_slots_acquire(0, 0);
7389 + slot->request_stage = FPM_REQUEST_EXECUTING;
7391 + fpm_clock_get(&slot->tv);
7393 + fpm_shm_slots_release(slot);
7396 +void fpm_request_finished()
7398 + struct fpm_shm_slot_s *slot;
7400 + slot = fpm_shm_slots_acquire(0, 0);
7402 + slot->request_stage = FPM_REQUEST_FINISHED;
7404 + fpm_clock_get(&slot->tv);
7405 + memset(&slot->accepted, 0, sizeof(slot->accepted));
7407 + fpm_shm_slots_release(slot);
7410 +void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *now, int terminate_timeout, int slowlog_timeout)
7412 + struct fpm_shm_slot_s *slot;
7413 + struct fpm_shm_slot_s slot_c;
7415 + slot = fpm_shm_slot(child);
7417 + if (!fpm_shm_slots_acquire(slot, 1)) {
7423 + fpm_shm_slots_release(slot);
7426 + if (child->slow_logged.tv_sec) {
7427 + if (child->slow_logged.tv_sec != slot_c.accepted.tv_sec || child->slow_logged.tv_usec != slot_c.accepted.tv_usec) {
7428 + child->slow_logged.tv_sec = 0;
7429 + child->slow_logged.tv_usec = 0;
7434 + if (slot_c.request_stage > FPM_REQUEST_ACCEPTING && slot_c.request_stage < FPM_REQUEST_FINISHED) {
7435 + char purified_script_filename[sizeof(slot_c.script_filename)];
7436 + struct timeval tv;
7438 + timersub(now, &slot_c.accepted, &tv);
7441 + if (child->slow_logged.tv_sec == 0 && slowlog_timeout &&
7442 + slot_c.request_stage == FPM_REQUEST_EXECUTING && tv.tv_sec >= slowlog_timeout) {
7444 + str_purify_filename(purified_script_filename, slot_c.script_filename, sizeof(slot_c.script_filename));
7446 + child->slow_logged = slot_c.accepted;
7447 + child->tracer = fpm_php_trace;
7449 + fpm_trace_signal(child->pid);
7451 + zlog(ZLOG_STUFF, ZLOG_WARNING, "child %d, script '%s' (pool %s) executing too slow (%d.%06d sec), logging",
7452 + (int) child->pid, purified_script_filename, child->wp->config->name, (int) tv.tv_sec, (int) tv.tv_usec);
7457 + if (terminate_timeout && tv.tv_sec >= terminate_timeout) {
7459 + str_purify_filename(purified_script_filename, slot_c.script_filename, sizeof(slot_c.script_filename));
7461 + fpm_pctl_kill(child->pid, FPM_PCTL_TERM);
7463 + zlog(ZLOG_STUFF, ZLOG_WARNING, "child %d, script '%s' (pool %s) execution timed out (%d.%06d sec), terminating",
7464 + (int) child->pid, purified_script_filename, child->wp->config->name, (int) tv.tv_sec, (int) tv.tv_usec);
7470 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_request.h php-src/sapi/fpm/fpm/fpm_request.h
7471 --- php-src-vanilla/sapi/fpm/fpm/fpm_request.h 1970-01-01 01:00:00.000000000 +0100
7472 +++ php-src/sapi/fpm/fpm/fpm_request.h 2009-10-18 21:05:39.308376784 +0100
7476 + /* (c) 2007,2008 Andrei Nigmatulin */
7478 +#ifndef FPM_REQUEST_H
7479 +#define FPM_REQUEST_H 1
7481 +void fpm_request_accepting(); /* hanging in accept() */
7482 +void fpm_request_reading_headers(); /* start reading fastcgi request from very first byte */
7483 +void fpm_request_info(); /* not a stage really but a point in the php code, where all request params have become known to sapi */
7484 +void fpm_request_executing(); /* the script is executing */
7485 +void fpm_request_finished(); /* request processed: script response have been sent to web server */
7487 +struct fpm_child_s;
7490 +void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *tv, int terminate_timeout, int slowlog_timeout);
7492 +enum fpm_request_stage_e {
7493 + FPM_REQUEST_ACCEPTING = 1,
7494 + FPM_REQUEST_READING_HEADERS,
7496 + FPM_REQUEST_EXECUTING,
7497 + FPM_REQUEST_FINISHED
7501 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_shm.c php-src/sapi/fpm/fpm/fpm_shm.c
7502 --- php-src-vanilla/sapi/fpm/fpm/fpm_shm.c 1970-01-01 01:00:00.000000000 +0100
7503 +++ php-src/sapi/fpm/fpm/fpm_shm.c 2009-10-18 21:05:39.308376784 +0100
7507 + /* (c) 2007,2008 Andrei Nigmatulin */
7509 +#include "fpm_config.h"
7511 +#include <unistd.h>
7512 +#include <sys/mman.h>
7513 +#include <stdlib.h>
7515 +#include "fpm_shm.h"
7519 +/* MAP_ANON is depricated, but not in macosx */
7520 +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
7521 +#define MAP_ANONYMOUS MAP_ANON
7525 +struct fpm_shm_s *fpm_shm_alloc(size_t sz)
7527 + struct fpm_shm_s *shm;
7529 + shm = malloc(sizeof(*shm));
7535 + shm->mem = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
7538 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "mmap(MAP_ANONYMOUS | MAP_SHARED) failed");
7549 +static void fpm_shm_free(struct fpm_shm_s *shm, int do_unmap)
7552 + munmap(shm->mem, shm->sz);
7558 +void fpm_shm_free_list(struct fpm_shm_s *shm, void *mem)
7560 + struct fpm_shm_s *next;
7562 + for (; shm; shm = next) {
7565 + fpm_shm_free(shm, mem != shm->mem);
7569 +void *fpm_shm_alloc_chunk(struct fpm_shm_s **head, size_t sz, void **mem)
7571 + size_t pagesize = getpagesize();
7572 + static const size_t cache_line_size = 16;
7573 + size_t aligned_sz;
7574 + struct fpm_shm_s *shm;
7577 + sz = (sz + cache_line_size - 1) & -cache_line_size;
7581 + if (0 == shm || shm->sz - shm->used < sz) {
7582 + /* allocate one more shm segment */
7584 + aligned_sz = (sz + pagesize - 1) & -pagesize;
7586 + shm = fpm_shm_alloc(aligned_sz);
7592 + shm->next = *head;
7593 + if (shm->next) { shm->next->prev = shm; }
7599 + ret = (char *) shm->mem + shm->used;
7605 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_shm.h php-src/sapi/fpm/fpm/fpm_shm.h
7606 --- php-src-vanilla/sapi/fpm/fpm/fpm_shm.h 1970-01-01 01:00:00.000000000 +0100
7607 +++ php-src/sapi/fpm/fpm/fpm_shm.h 2009-10-18 21:05:39.308376784 +0100
7611 + /* (c) 2007,2008 Andrei Nigmatulin */
7614 +#define FPM_SHM_H 1
7619 + struct fpm_shm_s *prev, *next;
7625 +struct fpm_shm_s *fpm_shm_alloc(size_t sz);
7626 +void fpm_shm_free_list(struct fpm_shm_s *, void *);
7627 +void *fpm_shm_alloc_chunk(struct fpm_shm_s **head, size_t sz, void **mem);
7631 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_shm_slots.c php-src/sapi/fpm/fpm/fpm_shm_slots.c
7632 --- php-src-vanilla/sapi/fpm/fpm/fpm_shm_slots.c 1970-01-01 01:00:00.000000000 +0100
7633 +++ php-src/sapi/fpm/fpm/fpm_shm_slots.c 2009-10-18 21:05:39.308376784 +0100
7637 + /* (c) 2007,2008 Andrei Nigmatulin */
7639 +#include "fpm_config.h"
7641 +#include "fpm_atomic.h"
7642 +#include "fpm_worker_pool.h"
7643 +#include "fpm_children.h"
7644 +#include "fpm_shm.h"
7645 +#include "fpm_shm_slots.h"
7648 +static void *shm_mem;
7649 +static struct fpm_shm_slot_s *shm_slot;
7651 +int fpm_shm_slots_prepare_slot(struct fpm_child_s *child)
7653 + struct fpm_worker_pool_s *wp = child->wp;
7654 + struct fpm_shm_slot_ptr_s *shm_slot_ptr;
7656 + child->shm_slot_i = wp->slots_used.used;
7658 + shm_slot_ptr = fpm_array_push(&wp->slots_used);
7660 + if (0 == shm_slot_ptr) {
7664 + if (0 == wp->slots_free.used) {
7665 + shm_slot_ptr->shm_slot = fpm_shm_alloc_chunk(&wp->shm_list, sizeof(struct fpm_shm_slot_s), &shm_slot_ptr->mem);
7667 + if (!shm_slot_ptr->shm_slot) {
7672 + *shm_slot_ptr = *(struct fpm_shm_slot_ptr_s *) fpm_array_item_last(&wp->slots_free);
7674 + --wp->slots_free.used;
7677 + memset(shm_slot_ptr->shm_slot, 0, sizeof(struct fpm_shm_slot_s));
7679 + shm_slot_ptr->child = child;
7684 +void fpm_shm_slots_discard_slot(struct fpm_child_s *child)
7686 + struct fpm_shm_slot_ptr_s *shm_slot_ptr;
7687 + struct fpm_worker_pool_s *wp = child->wp;
7690 + shm_slot_ptr = fpm_array_push(&wp->slots_free);
7692 + if (shm_slot_ptr) {
7694 + struct fpm_shm_slot_ptr_s *shm_slot_ptr_used;
7696 + shm_slot_ptr_used = fpm_array_item(&wp->slots_used, child->shm_slot_i);
7698 + *shm_slot_ptr = *shm_slot_ptr_used;
7700 + shm_slot_ptr->child = 0;
7704 + n = fpm_array_item_remove(&wp->slots_used, child->shm_slot_i);
7707 + shm_slot_ptr = fpm_array_item(&wp->slots_used, n);
7709 + shm_slot_ptr->child->shm_slot_i = n;
7713 +void fpm_shm_slots_child_use_slot(struct fpm_child_s *child)
7715 + struct fpm_shm_slot_ptr_s *shm_slot_ptr;
7716 + struct fpm_worker_pool_s *wp = child->wp;
7718 + shm_slot_ptr = fpm_array_item(&wp->slots_used, child->shm_slot_i);
7720 + shm_slot = shm_slot_ptr->shm_slot;
7721 + shm_mem = shm_slot_ptr->mem;
7724 +void fpm_shm_slots_parent_use_slot(struct fpm_child_s *child)
7726 + /* nothing to do */
7729 +void *fpm_shm_slots_mem()
7734 +struct fpm_shm_slot_s *fpm_shm_slot(struct fpm_child_s *child)
7736 + struct fpm_shm_slot_ptr_s *shm_slot_ptr;
7737 + struct fpm_worker_pool_s *wp = child->wp;
7739 + shm_slot_ptr = fpm_array_item(&wp->slots_used, child->shm_slot_i);
7741 + return shm_slot_ptr->shm_slot;
7744 +struct fpm_shm_slot_s *fpm_shm_slots_acquire(struct fpm_shm_slot_s *s, int nohang)
7750 + if (0 > fpm_spinlock(&s->lock, nohang)) {
7757 +void fpm_shm_slots_release(struct fpm_shm_slot_s *s)
7762 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_shm_slots.h php-src/sapi/fpm/fpm/fpm_shm_slots.h
7763 --- php-src-vanilla/sapi/fpm/fpm/fpm_shm_slots.h 1970-01-01 01:00:00.000000000 +0100
7764 +++ php-src/sapi/fpm/fpm/fpm_shm_slots.h 2009-10-18 21:05:39.308376784 +0100
7768 + /* (c) 2007,2008 Andrei Nigmatulin */
7770 +#ifndef FPM_SHM_SLOTS_H
7771 +#define FPM_SHM_SLOTS_H 1
7773 +#include "fpm_atomic.h"
7774 +#include "fpm_worker_pool.h"
7775 +#include "fpm_request.h"
7777 +struct fpm_child_s;
7779 +struct fpm_shm_slot_s {
7784 + enum fpm_request_stage_e request_stage;
7785 + struct timeval accepted;
7786 + struct timeval tv;
7787 + char request_method[16];
7788 + size_t content_length; /* used with POST only */
7789 + char script_filename[256];
7792 +struct fpm_shm_slot_ptr_s {
7794 + struct fpm_shm_slot_s *shm_slot;
7795 + struct fpm_child_s *child;
7798 +int fpm_shm_slots_prepare_slot(struct fpm_child_s *child);
7799 +void fpm_shm_slots_discard_slot(struct fpm_child_s *child);
7800 +void fpm_shm_slots_child_use_slot(struct fpm_child_s *child);
7801 +void fpm_shm_slots_parent_use_slot(struct fpm_child_s *child);
7802 +void *fpm_shm_slots_mem();
7803 +struct fpm_shm_slot_s *fpm_shm_slot(struct fpm_child_s *child);
7804 +struct fpm_shm_slot_s *fpm_shm_slots_acquire(struct fpm_shm_slot_s *, int nohang);
7805 +void fpm_shm_slots_release(struct fpm_shm_slot_s *);
7809 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_signals.c php-src/sapi/fpm/fpm/fpm_signals.c
7810 --- php-src-vanilla/sapi/fpm/fpm/fpm_signals.c 1970-01-01 01:00:00.000000000 +0100
7811 +++ php-src/sapi/fpm/fpm/fpm_signals.c 2009-10-18 21:05:39.308376784 +0100
7815 + /* (c) 2007,2008 Andrei Nigmatulin */
7817 +#include "fpm_config.h"
7819 +#include <signal.h>
7821 +#include <sys/types.h>
7822 +#include <sys/socket.h>
7823 +#include <stdlib.h>
7824 +#include <string.h>
7826 +#include <unistd.h>
7830 +#include "fpm_signals.h"
7831 +#include "fpm_sockets.h"
7832 +#include "fpm_php.h"
7837 +const char *fpm_signal_names[NSIG + 1] = {
7839 + [SIGHUP] = "SIGHUP",
7842 + [SIGINT] = "SIGINT",
7845 + [SIGQUIT] = "SIGQUIT",
7848 + [SIGILL] = "SIGILL",
7851 + [SIGTRAP] = "SIGTRAP",
7854 + [SIGABRT] = "SIGABRT",
7857 + [SIGEMT] = "SIGEMT",
7860 + [SIGBUS] = "SIGBUS",
7863 + [SIGFPE] = "SIGFPE",
7866 + [SIGKILL] = "SIGKILL",
7869 + [SIGUSR1] = "SIGUSR1",
7872 + [SIGSEGV] = "SIGSEGV",
7875 + [SIGUSR2] = "SIGUSR2",
7878 + [SIGPIPE] = "SIGPIPE",
7881 + [SIGALRM] = "SIGALRM",
7884 + [SIGTERM] = "SIGTERM",
7887 + [SIGCHLD] = "SIGCHLD",
7890 + [SIGCONT] = "SIGCONT",
7893 + [SIGSTOP] = "SIGSTOP",
7896 + [SIGTSTP] = "SIGTSTP",
7899 + [SIGTTIN] = "SIGTTIN",
7902 + [SIGTTOU] = "SIGTTOU",
7905 + [SIGURG] = "SIGURG",
7908 + [SIGXCPU] = "SIGXCPU",
7911 + [SIGXFSZ] = "SIGXFSZ",
7914 + [SIGVTALRM] = "SIGVTALRM",
7917 + [SIGPROF] = "SIGPROF",
7920 + [SIGWINCH] = "SIGWINCH",
7923 + [SIGINFO] = "SIGINFO",
7926 + [SIGIO] = "SIGIO",
7929 + [SIGPWR] = "SIGPWR",
7932 + [SIGSYS] = "SIGSYS",
7935 + [SIGWAITING] = "SIGWAITING",
7938 + [SIGLWP] = "SIGLWP",
7941 + [SIGFREEZE] = "SIGFREEZE",
7944 + [SIGTHAW] = "SIGTHAW",
7947 + [SIGCANCEL] = "SIGCANCEL",
7950 + [SIGLOST] = "SIGLOST",
7954 +static void sig_soft_quit(int signo)
7956 + int saved_errno = errno;
7958 + /* closing fastcgi listening socket will force fcgi_accept() exit immediately */
7960 + socket(AF_UNIX, SOCK_STREAM, 0);
7962 + fpm_php_soft_quit();
7964 + errno = saved_errno;
7967 +static void sig_handler(int signo)
7969 + static const char sig_chars[NSIG + 1] = {
7980 + if (fpm_globals.parent_pid != getpid()) {
7981 + /* prevent a signal race condition when child process
7982 + have not set up it's own signal handler yet */
7986 + saved_errno = errno;
7988 + s = sig_chars[signo];
7990 + write(sp[1], &s, sizeof(s));
7992 + errno = saved_errno;
7995 +int fpm_signals_init_main()
7997 + struct sigaction act;
7999 + if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) {
8000 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "socketpair() failed");
8004 + if (0 > fd_set_blocked(sp[0], 0) || 0 > fd_set_blocked(sp[1], 0)) {
8005 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fd_set_blocked() failed");
8009 + if (0 > fcntl(sp[0], F_SETFD, FD_CLOEXEC) || 0 > fcntl(sp[1], F_SETFD, FD_CLOEXEC)) {
8010 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fcntl(F_SETFD, FD_CLOEXEC) failed");
8014 + memset(&act, 0, sizeof(act));
8015 + act.sa_handler = sig_handler;
8016 + sigfillset(&act.sa_mask);
8018 + if (0 > sigaction(SIGTERM, &act, 0) ||
8019 + 0 > sigaction(SIGINT, &act, 0) ||
8020 + 0 > sigaction(SIGUSR1, &act, 0) ||
8021 + 0 > sigaction(SIGUSR2, &act, 0) ||
8022 + 0 > sigaction(SIGCHLD, &act, 0) ||
8023 + 0 > sigaction(SIGQUIT, &act, 0)) {
8025 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "sigaction() failed");
8032 +int fpm_signals_init_child()
8034 + struct sigaction act, act_dfl;
8036 + memset(&act, 0, sizeof(act));
8037 + memset(&act_dfl, 0, sizeof(act_dfl));
8039 + act.sa_handler = &sig_soft_quit;
8040 + act.sa_flags |= SA_RESTART;
8042 + act_dfl.sa_handler = SIG_DFL;
8047 + if (0 > sigaction(SIGTERM, &act_dfl, 0) ||
8048 + 0 > sigaction(SIGINT, &act_dfl, 0) ||
8049 + 0 > sigaction(SIGUSR1, &act_dfl, 0) ||
8050 + 0 > sigaction(SIGUSR2, &act_dfl, 0) ||
8051 + 0 > sigaction(SIGCHLD, &act_dfl, 0) ||
8052 + 0 > sigaction(SIGQUIT, &act, 0)) {
8054 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "sigaction() failed");
8061 +int fpm_signals_get_fd()
8065 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_signals.h php-src/sapi/fpm/fpm/fpm_signals.h
8066 --- php-src-vanilla/sapi/fpm/fpm/fpm_signals.h 1970-01-01 01:00:00.000000000 +0100
8067 +++ php-src/sapi/fpm/fpm/fpm_signals.h 2009-10-18 21:05:39.308376784 +0100
8071 + /* (c) 2007,2008 Andrei Nigmatulin */
8073 +#ifndef FPM_SIGNALS_H
8074 +#define FPM_SIGNALS_H 1
8076 +#include <signal.h>
8078 +int fpm_signals_init_main();
8079 +int fpm_signals_init_child();
8080 +int fpm_signals_get_fd();
8082 +extern const char *fpm_signal_names[NSIG + 1];
8085 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_sockets.c php-src/sapi/fpm/fpm/fpm_sockets.c
8086 --- php-src-vanilla/sapi/fpm/fpm/fpm_sockets.c 1970-01-01 01:00:00.000000000 +0100
8087 +++ php-src/sapi/fpm/fpm/fpm_sockets.c 2009-10-18 21:05:39.310440424 +0100
8091 + /* (c) 2007,2008 Andrei Nigmatulin */
8093 +#include "fpm_config.h"
8095 +#ifdef HAVE_ALLOCA_H
8096 +#include <alloca.h>
8098 +#include <sys/types.h>
8099 +#include <sys/stat.h> /* for chmod(2) */
8100 +#include <sys/socket.h>
8101 +#include <netinet/in.h>
8102 +#include <arpa/inet.h>
8103 +#include <sys/un.h>
8106 +#include <stdlib.h>
8107 +#include <string.h>
8109 +#include <unistd.h>
8112 +#include "fpm_arrays.h"
8113 +#include "fpm_sockets.h"
8114 +#include "fpm_worker_pool.h"
8115 +#include "fpm_unix.h"
8116 +#include "fpm_str.h"
8117 +#include "fpm_env.h"
8118 +#include "fpm_cleanup.h"
8120 +struct listening_socket_s {
8127 +static struct fpm_array_s sockets_list;
8129 +static int fpm_sockets_resolve_af_inet(char *node, char *service, struct sockaddr_in *addr)
8131 + struct addrinfo *res;
8132 + struct addrinfo hints;
8135 + memset(&hints, 0, sizeof(hints));
8137 + hints.ai_family = AF_INET;
8139 + ret = getaddrinfo(node, service, &hints, &res);
8142 + zlog(ZLOG_STUFF, ZLOG_ERROR, "can't resolve hostname '%s%s%s': getaddrinfo said: %s%s%s\n",
8143 + node, service ? ":" : "", service ? service : "",
8144 + gai_strerror(ret), ret == EAI_SYSTEM ? ", system error: " : "", ret == EAI_SYSTEM ? strerror(errno) : "");
8148 + *addr = *(struct sockaddr_in *) res->ai_addr;
8150 + freeaddrinfo(res);
8155 +enum { FPM_GET_USE_SOCKET = 1, FPM_STORE_SOCKET = 2, FPM_STORE_USE_SOCKET = 3 };
8157 +static void fpm_sockets_cleanup(int which, void *arg)
8160 + char *env_value = 0;
8162 + struct listening_socket_s *ls = sockets_list.data;
8164 + for (i = 0; i < sockets_list.used; i++, ls++) {
8166 + if (which != FPM_CLEANUP_PARENT_EXEC) {
8171 + else { /* on PARENT EXEC we want socket fds to be inherited through environment variable */
8173 + sprintf(fd, "%d", ls->sock);
8174 + env_value = realloc(env_value, p + (p ? 1 : 0) + strlen(ls->key) + 1 + strlen(fd) + 1);
8175 + p += sprintf(env_value + p, "%s%s=%s", p ? "," : "", ls->key, fd);
8178 + if (which == FPM_CLEANUP_PARENT_EXIT_MAIN) {
8180 + if (ls->type == FPM_AF_UNIX) {
8190 + setenv("FPM_SOCKETS", env_value, 1);
8194 + fpm_array_free(&sockets_list);
8197 +static int fpm_sockets_hash_op(int sock, struct sockaddr *sa, char *key, int type, int op)
8200 + if (key == NULL) {
8204 + case FPM_AF_INET : {
8205 + struct sockaddr_in *sa_in = (struct sockaddr_in *) sa;
8207 + key = alloca(sizeof("xxx.xxx.xxx.xxx:ppppp"));
8209 + sprintf(key, "%u.%u.%u.%u:%u", IPQUAD(&sa_in->sin_addr), (unsigned int) ntohs(sa_in->sin_port));
8214 + case FPM_AF_UNIX : {
8215 + struct sockaddr_un *sa_un = (struct sockaddr_un *) sa;
8217 + key = alloca(strlen(sa_un->sun_path) + 1);
8219 + strcpy(key, sa_un->sun_path);
8233 + case FPM_GET_USE_SOCKET :
8237 + struct listening_socket_s *ls = sockets_list.data;
8239 + for (i = 0; i < sockets_list.used; i++, ls++) {
8241 + if (!strcmp(ls->key, key)) {
8250 + case FPM_STORE_SOCKET : /* inherited socket */
8251 + case FPM_STORE_USE_SOCKET : /* just created */
8254 + struct listening_socket_s *ls;
8256 + ls = fpm_array_push(&sockets_list);
8262 + if (op == FPM_STORE_SOCKET) {
8270 + ls->key = strdup(key);
8281 +static int fpm_sockets_new_listening_socket(struct fpm_worker_pool_s *wp, struct sockaddr *sa, int socklen)
8286 + mode_t saved_umask;
8288 + /* we have custom backlog value */
8289 + if (wp->config->listen_options) {
8290 + backlog = wp->config->listen_options->backlog;
8293 + sock = socket(sa->sa_family, SOCK_STREAM, 0);
8296 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "socket() failed");
8300 + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
8302 + if (wp->listen_address_domain == FPM_AF_UNIX) {
8303 + unlink( ((struct sockaddr_un *) sa)->sun_path);
8306 + saved_umask = umask(0777 ^ wp->socket_mode);
8308 + if (0 > bind(sock, sa, socklen)) {
8309 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "bind() for address '%s' failed", wp->config->listen_address);
8313 + if (wp->listen_address_domain == FPM_AF_UNIX) {
8315 + char *path = ((struct sockaddr_un *) sa)->sun_path;
8317 + if (wp->socket_uid != -1 || wp->socket_gid != -1) {
8319 + if (0 > chown(path, wp->socket_uid, wp->socket_gid)) {
8320 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "chown() for address '%s' failed", wp->config->listen_address);
8328 + umask(saved_umask);
8330 + if (0 > listen(sock, backlog)) {
8331 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "listen() for address '%s' failed", wp->config->listen_address);
8338 +static int fpm_sockets_get_listening_socket(struct fpm_worker_pool_s *wp, struct sockaddr *sa, int socklen)
8342 + sock = fpm_sockets_hash_op(0, sa, 0, wp->listen_address_domain, FPM_GET_USE_SOCKET);
8344 + if (sock >= 0) { return sock; }
8346 + sock = fpm_sockets_new_listening_socket(wp, sa, socklen);
8348 + fpm_sockets_hash_op(sock, sa, 0, wp->listen_address_domain, FPM_STORE_USE_SOCKET);
8353 +enum fpm_address_domain fpm_sockets_domain_from_address(char *address)
8355 + if (strchr(address, ':')) { return FPM_AF_INET; }
8357 + if (strlen(address) == strspn(address, "0123456789")) { return FPM_AF_INET; }
8359 + return FPM_AF_UNIX;
8362 +static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp)
8364 + struct sockaddr_in sa_in;
8365 + char *dup_address = strdup(wp->config->listen_address);
8366 + char *port_str = strchr(dup_address, ':');
8367 + char *addr = NULL;
8370 + if (port_str) { /* this is host:port pair */
8371 + *port_str++ = '\0';
8372 + port = atoi(port_str);
8373 + addr = dup_address;
8375 + else if (strlen(dup_address) == strspn(dup_address, "0123456789")) { /* this is port */
8376 + port = atoi(dup_address);
8377 + port_str = dup_address;
8381 + zlog(ZLOG_STUFF, ZLOG_ERROR, "invalid port value '%s'", port_str);
8385 + memset(&sa_in, 0, sizeof(sa_in));
8389 + sa_in.sin_addr.s_addr = inet_addr(addr);
8391 + if (sa_in.sin_addr.s_addr == INADDR_NONE) { /* do resolve */
8392 + if (0 > fpm_sockets_resolve_af_inet(addr, NULL, &sa_in)) {
8395 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "address '%s' resolved as %u.%u.%u.%u", addr, IPQUAD(&sa_in.sin_addr));
8400 + sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
8404 + sa_in.sin_family = AF_INET;
8405 + sa_in.sin_port = htons(port);
8407 + free(dup_address);
8409 + return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_in, sizeof(struct sockaddr_in));
8412 +static int fpm_socket_af_unix_listening_socket(struct fpm_worker_pool_s *wp)
8414 + struct sockaddr_un sa_un;
8416 + memset(&sa_un, 0, sizeof(sa_un));
8418 + cpystrn(sa_un.sun_path, wp->config->listen_address, sizeof(sa_un.sun_path));
8419 + sa_un.sun_family = AF_UNIX;
8421 + return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_un, sizeof(struct sockaddr_un));
8424 +int fpm_sockets_init_main()
8427 + struct fpm_worker_pool_s *wp;
8428 + char *inherited = getenv("FPM_SOCKETS");
8429 + struct listening_socket_s *ls;
8431 + if (0 == fpm_array_init(&sockets_list, sizeof(struct listening_socket_s), 10)) {
8435 + /* import inherited sockets */
8436 + while (inherited && *inherited) {
8437 + char *comma = strchr(inherited, ',');
8441 + if (comma) { *comma = '\0'; }
8443 + eq = strchr(inherited, '=');
8448 + fd_no = atoi(eq + 1);
8450 + type = fpm_sockets_domain_from_address(inherited);
8452 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "using inherited socket fd=%d, \"%s\"", fd_no, inherited);
8454 + fpm_sockets_hash_op(fd_no, 0, inherited, type, FPM_STORE_SOCKET);
8457 + if (comma) { inherited = comma + 1; }
8458 + else { inherited = 0; }
8461 + /* create all required sockets */
8462 + for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
8464 + if (!wp->is_template) {
8466 + switch (wp->listen_address_domain) {
8468 + case FPM_AF_INET :
8470 + wp->listening_socket = fpm_socket_af_inet_listening_socket(wp);
8473 + case FPM_AF_UNIX :
8475 + if (0 > fpm_unix_resolve_socket_premissions(wp)) {
8479 + wp->listening_socket = fpm_socket_af_unix_listening_socket(wp);
8484 + if (wp->listening_socket == -1) {
8491 + /* close unused sockets that was inherited */
8492 + ls = sockets_list.data;
8494 + for (i = 0; i < sockets_list.used; ) {
8496 + if (ls->refcount == 0) {
8498 + if (ls->type == FPM_AF_UNIX) {
8502 + fpm_array_item_remove(&sockets_list, i);
8510 + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_sockets_cleanup, 0)) {
8516 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_sockets.h php-src/sapi/fpm/fpm/fpm_sockets.h
8517 --- php-src-vanilla/sapi/fpm/fpm/fpm_sockets.h 1970-01-01 01:00:00.000000000 +0100
8518 +++ php-src/sapi/fpm/fpm/fpm_sockets.h 2009-10-18 21:05:39.310440424 +0100
8522 + /* (c) 2007,2008 Andrei Nigmatulin */
8525 +#define FPM_MISC_H 1
8527 +#include <unistd.h>
8530 +#include "fpm_worker_pool.h"
8532 +enum fpm_address_domain fpm_sockets_domain_from_address(char *addr);
8533 +int fpm_sockets_init_main();
8536 +static inline int fd_set_blocked(int fd, int blocked)
8538 + int flags = fcntl(fd, F_GETFL);
8540 + if (flags < 0) { return -1; }
8543 + { flags &= ~O_NONBLOCK; }
8545 + { flags |= O_NONBLOCK; }
8547 + return fcntl(fd, F_SETFL, flags);
8550 +#define IPQUAD(sin_addr) \
8551 + (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[0], \
8552 + (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[1], \
8553 + (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[2], \
8554 + (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[3]
8557 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_stdio.c php-src/sapi/fpm/fpm/fpm_stdio.c
8558 --- php-src-vanilla/sapi/fpm/fpm/fpm_stdio.c 1970-01-01 01:00:00.000000000 +0100
8559 +++ php-src/sapi/fpm/fpm/fpm_stdio.c 2009-10-18 21:05:39.310440424 +0100
8563 + /* (c) 2007,2008 Andrei Nigmatulin */
8565 +#include "fpm_config.h"
8567 +#include <sys/types.h>
8568 +#include <sys/stat.h>
8569 +#include <string.h>
8571 +#include <unistd.h>
8575 +#include "fpm_children.h"
8576 +#include "fpm_events.h"
8577 +#include "fpm_sockets.h"
8578 +#include "fpm_stdio.h"
8581 +static int fd_stdout[2];
8582 +static int fd_stderr[2];
8584 +int fpm_stdio_init_main()
8586 + int fd = open("/dev/null", O_RDWR);
8589 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(\"/dev/null\") failed");
8593 + if (0 > dup2(fd, STDIN_FILENO) || 0 > dup2(fd, STDOUT_FILENO)) {
8594 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed");
8603 +int fpm_stdio_init_final()
8605 + if (fpm_global_config.daemonize) {
8607 + if (fpm_globals.error_log_fd != STDERR_FILENO) {
8608 + /* there might be messages to stderr from libevent, we need to log them all */
8609 + if (0 > dup2(fpm_globals.error_log_fd, STDERR_FILENO)) {
8610 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed");
8615 + zlog_set_level(fpm_globals.log_level);
8617 + zlog_set_fd(fpm_globals.error_log_fd);
8623 +int fpm_stdio_init_child(struct fpm_worker_pool_s *wp)
8625 + close(fpm_globals.error_log_fd);
8626 + fpm_globals.error_log_fd = -1;
8629 + if (wp->listening_socket != STDIN_FILENO) {
8630 + if (0 > dup2(wp->listening_socket, STDIN_FILENO)) {
8631 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed");
8639 +static void fpm_stdio_child_said(int fd, short which, void *arg)
8641 + static const int max_buf_size = 1024;
8642 + char buf[max_buf_size];
8643 + struct fpm_child_s *child = arg;
8644 + int is_stdout = fd == child->fd_stdout;
8645 + struct event *ev = is_stdout ? &child->ev_stdout : &child->ev_stderr;
8646 + int fifo_in = 1, fifo_out = 1;
8647 + int is_last_message = 0;
8652 + zlog(ZLOG_STUFF, ZLOG_DEBUG, "child %d said %s", (int) child->pid, is_stdout ? "stdout" : "stderr");
8655 + while (fifo_in || fifo_out) {
8659 + res = read(fd, buf + in_buf, max_buf_size - 1 - in_buf);
8661 + if (res <= 0) { /* no data */
8664 + if (res < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
8665 + /* just no more data ready */
8667 + else { /* error or pipe is closed */
8669 + if (res < 0) { /* error */
8670 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "read() failed");
8673 + fpm_event_del(ev);
8674 + is_last_message = 1;
8677 + close(child->fd_stdout);
8678 + child->fd_stdout = -1;
8681 + close(child->fd_stderr);
8682 + child->fd_stderr = -1;
8686 + if (in_buf == 0 && !fpm_globals.is_child) {
8687 + zlog(ZLOG_STUFF, ZLOG_DEBUG, "child %d (pool %s) %s pipe is closed", (int) child->pid,
8688 + child->wp->config->name, is_stdout ? "stdout" : "stderr");
8699 + if (in_buf == 0) {
8704 + int should_print = 0;
8705 + buf[in_buf] = '\0';
8707 + /* FIXME: there might be binary data */
8709 + /* we should print if no more space in the buffer */
8710 + if (in_buf == max_buf_size - 1) {
8714 + /* we should print if no more data to come */
8719 + nl = strchr(buf, '\n');
8721 + if (nl || should_print) {
8727 + zlog(ZLOG_STUFF, ZLOG_WARNING, "child %d (pool %s) said into %s: \"%s\"%s", (int) child->pid,
8728 + child->wp->config->name, is_stdout ? "stdout" : "stderr", buf, is_last_message ? ", pipe is closed" : "");
8731 + int out_buf = 1 + nl - buf;
8732 + memmove(buf, buf + out_buf, in_buf - out_buf);
8733 + in_buf -= out_buf;
8745 +int fpm_stdio_prepare_pipes(struct fpm_child_s *child)
8747 + if (0 == child->wp->config->catch_workers_output) { /* not required */
8751 + if (0 > pipe(fd_stdout)) {
8752 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pipe() failed");
8756 + if (0 > pipe(fd_stderr)) {
8757 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pipe() failed");
8758 + close(fd_stdout[0]); close(fd_stdout[1]);
8762 + if (0 > fd_set_blocked(fd_stdout[0], 0) || 0 > fd_set_blocked(fd_stderr[0], 0)) {
8763 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fd_set_blocked() failed");
8764 + close(fd_stdout[0]); close(fd_stdout[1]);
8765 + close(fd_stderr[0]); close(fd_stderr[1]);
8772 +int fpm_stdio_parent_use_pipes(struct fpm_child_s *child)
8774 + if (0 == child->wp->config->catch_workers_output) { /* not required */
8778 + close(fd_stdout[1]);
8779 + close(fd_stderr[1]);
8781 + child->fd_stdout = fd_stdout[0];
8782 + child->fd_stderr = fd_stderr[0];
8784 + fpm_event_add(child->fd_stdout, &child->ev_stdout, fpm_stdio_child_said, child);
8785 + fpm_event_add(child->fd_stderr, &child->ev_stderr, fpm_stdio_child_said, child);
8790 +int fpm_stdio_discard_pipes(struct fpm_child_s *child)
8792 + if (0 == child->wp->config->catch_workers_output) { /* not required */
8796 + close(fd_stdout[1]);
8797 + close(fd_stderr[1]);
8799 + close(fd_stdout[0]);
8800 + close(fd_stderr[0]);
8805 +void fpm_stdio_child_use_pipes(struct fpm_child_s *child)
8807 + if (child->wp->config->catch_workers_output) {
8808 + dup2(fd_stdout[1], STDOUT_FILENO);
8809 + dup2(fd_stderr[1], STDERR_FILENO);
8810 + close(fd_stdout[0]); close(fd_stdout[1]);
8811 + close(fd_stderr[0]); close(fd_stderr[1]);
8814 + /* stdout of parent is always /dev/null */
8815 + dup2(STDOUT_FILENO, STDERR_FILENO);
8819 +int fpm_stdio_open_error_log(int reopen)
8823 + fd = open(fpm_global_config.error_log, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
8826 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(\"%s\") failed", fpm_global_config.error_log);
8831 + if (fpm_global_config.daemonize) {
8832 + dup2(fd, STDERR_FILENO);
8835 + dup2(fd, fpm_globals.error_log_fd);
8837 + fd = fpm_globals.error_log_fd; /* for FD_CLOSEXEC to work */
8840 + fpm_globals.error_log_fd = fd;
8843 + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
8847 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_stdio.h php-src/sapi/fpm/fpm/fpm_stdio.h
8848 --- php-src-vanilla/sapi/fpm/fpm/fpm_stdio.h 1970-01-01 01:00:00.000000000 +0100
8849 +++ php-src/sapi/fpm/fpm/fpm_stdio.h 2009-10-18 21:05:39.310440424 +0100
8853 + /* (c) 2007,2008 Andrei Nigmatulin */
8855 +#ifndef FPM_STDIO_H
8856 +#define FPM_STDIO_H 1
8858 +#include "fpm_worker_pool.h"
8860 +int fpm_stdio_init_main();
8861 +int fpm_stdio_init_final();
8862 +int fpm_stdio_init_child(struct fpm_worker_pool_s *wp);
8863 +int fpm_stdio_prepare_pipes(struct fpm_child_s *child);
8864 +void fpm_stdio_child_use_pipes(struct fpm_child_s *child);
8865 +int fpm_stdio_parent_use_pipes(struct fpm_child_s *child);
8866 +int fpm_stdio_discard_pipes(struct fpm_child_s *child);
8867 +int fpm_stdio_open_error_log(int reopen);
8871 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_str.h php-src/sapi/fpm/fpm/fpm_str.h
8872 --- php-src-vanilla/sapi/fpm/fpm/fpm_str.h 1970-01-01 01:00:00.000000000 +0100
8873 +++ php-src/sapi/fpm/fpm/fpm_str.h 2009-10-18 21:05:39.308376784 +0100
8877 + /* (c) 2007,2008 Andrei Nigmatulin */
8880 +#define FPM_STR_H 1
8882 +static inline char *cpystrn(char *dst, const char *src, size_t dst_size)
8886 + if (!dst_size) { return dst; }
8889 + end = dst + dst_size - 1;
8891 + for (; d < end; ++d, ++src) {
8892 + if (!(*d = *src)) {
8902 +static inline char *str_purify_filename(char *dst, char *src, size_t size)
8907 + end = dst + size - 1;
8909 + for (; d < end && *src; ++d, ++src) {
8910 + if (* (unsigned char *) src < ' ' || * (unsigned char *) src > '\x7f') {
8924 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_trace.c php-src/sapi/fpm/fpm/fpm_trace.c
8925 --- php-src-vanilla/sapi/fpm/fpm/fpm_trace.c 1970-01-01 01:00:00.000000000 +0100
8926 +++ php-src/sapi/fpm/fpm/fpm_trace.c 2009-10-18 21:05:39.310440424 +0100
8930 + /* (c) 2007,2008 Andrei Nigmatulin */
8932 +#include "fpm_config.h"
8934 +#include <sys/types.h>
8936 +#include "fpm_trace.h"
8938 +int fpm_trace_get_strz(char *buf, size_t sz, long addr)
8942 + char *lc = (char *) &l;
8944 + if (0 > fpm_trace_get_long(addr, &l)) {
8948 + i = l % SIZEOF_LONG;
8952 + for (addr = l; ; addr += SIZEOF_LONG) {
8954 + if (0 > fpm_trace_get_long(addr, &l)) {
8958 + for ( ; i < SIZEOF_LONG; i++) {
8961 + if (sz && lc[i]) {
8974 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_trace.h php-src/sapi/fpm/fpm/fpm_trace.h
8975 --- php-src-vanilla/sapi/fpm/fpm/fpm_trace.h 1970-01-01 01:00:00.000000000 +0100
8976 +++ php-src/sapi/fpm/fpm/fpm_trace.h 2009-10-18 21:05:39.302497288 +0100
8980 + /* (c) 2007,2008 Andrei Nigmatulin */
8982 +#ifndef FPM_TRACE_H
8983 +#define FPM_TRACE_H 1
8985 +#include <unistd.h>
8987 +int fpm_trace_signal(pid_t pid);
8988 +int fpm_trace_ready(pid_t pid);
8989 +int fpm_trace_close(pid_t pid);
8990 +int fpm_trace_get_long(long addr, long *data);
8991 +int fpm_trace_get_strz(char *buf, size_t sz, long addr);
8995 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_trace_mach.c php-src/sapi/fpm/fpm/fpm_trace_mach.c
8996 --- php-src-vanilla/sapi/fpm/fpm/fpm_trace_mach.c 1970-01-01 01:00:00.000000000 +0100
8997 +++ php-src/sapi/fpm/fpm/fpm_trace_mach.c 2009-10-18 21:05:39.308376784 +0100
9001 + /* (c) 2007,2008 Andrei Nigmatulin */
9003 +#include "fpm_config.h"
9005 +#include <mach/mach.h>
9006 +#include <mach/mach_vm.h>
9008 +#include <unistd.h>
9010 +#include "fpm_trace.h"
9011 +#include "fpm_process_ctl.h"
9012 +#include "fpm_unix.h"
9016 +static mach_port_name_t target;
9017 +static vm_offset_t target_page_base;
9018 +static vm_offset_t local_page;
9019 +static mach_msg_type_number_t local_size;
9021 +static void fpm_mach_vm_deallocate()
9024 + mach_vm_deallocate(mach_task_self(), local_page, local_size);
9025 + target_page_base = 0;
9031 +static int fpm_mach_vm_read_page(vm_offset_t page)
9035 + kr = mach_vm_read(target, page, fpm_pagesize, &local_page, &local_size);
9037 + if (kr != KERN_SUCCESS) {
9038 + zlog(ZLOG_STUFF, ZLOG_ERROR, "mach_vm_read() failed: %s (%d)", mach_error_string(kr), kr);
9045 +int fpm_trace_signal(pid_t pid)
9047 + if (0 > fpm_pctl_kill(pid, FPM_PCTL_STOP)) {
9048 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "kill(SIGSTOP) failed");
9055 +int fpm_trace_ready(pid_t pid)
9059 + kr = task_for_pid(mach_task_self(), pid, &target);
9061 + if (kr != KERN_SUCCESS) {
9064 + if (kr == KERN_FAILURE) {
9065 + msg = " It seems that master process does not have enough privileges to trace processes.";
9068 + zlog(ZLOG_STUFF, ZLOG_ERROR, "task_for_pid() failed: %s (%d)%s", mach_error_string(kr), kr, msg);
9075 +int fpm_trace_close(pid_t pid)
9077 + fpm_mach_vm_deallocate();
9084 +int fpm_trace_get_long(long addr, long *data)
9086 + size_t offset = ((uintptr_t) (addr) % fpm_pagesize);
9087 + vm_offset_t base = (uintptr_t) (addr) - offset;
9089 + if (base != target_page_base) {
9090 + fpm_mach_vm_deallocate();
9091 + if (0 > fpm_mach_vm_read_page(base)) {
9096 + *data = * (long *) (local_page + offset);
9101 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_trace_pread.c php-src/sapi/fpm/fpm/fpm_trace_pread.c
9102 --- php-src-vanilla/sapi/fpm/fpm/fpm_trace_pread.c 1970-01-01 01:00:00.000000000 +0100
9103 +++ php-src/sapi/fpm/fpm/fpm_trace_pread.c 2009-10-18 21:05:39.310440424 +0100
9107 + /* (c) 2007,2008 Andrei Nigmatulin */
9109 +#define _GNU_SOURCE
9110 +#define _FILE_OFFSET_BITS 64
9112 +#include "fpm_config.h"
9114 +#include <unistd.h>
9118 +#if HAVE_INTTYPES_H
9119 +#include <inttypes.h>
9121 +#include <stdint.h>
9125 +#include "fpm_trace.h"
9126 +#include "fpm_process_ctl.h"
9130 +static int mem_file = -1;
9132 +int fpm_trace_signal(pid_t pid)
9134 + if (0 > fpm_pctl_kill(pid, FPM_PCTL_STOP)) {
9135 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "kill(SIGSTOP) failed");
9142 +int fpm_trace_ready(pid_t pid)
9146 + sprintf(buf, "/proc/%d/" PROC_MEM_FILE, (int) pid);
9148 + mem_file = open(buf, O_RDONLY);
9150 + if (0 > mem_file) {
9151 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(%s) failed", buf);
9158 +int fpm_trace_close(pid_t pid)
9167 +int fpm_trace_get_long(long addr, long *data)
9169 + if (sizeof(*data) != pread(mem_file, (void *) data, sizeof(*data), (uintptr_t) addr)) {
9170 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pread() failed");
9177 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_trace_ptrace.c php-src/sapi/fpm/fpm/fpm_trace_ptrace.c
9178 --- php-src-vanilla/sapi/fpm/fpm/fpm_trace_ptrace.c 1970-01-01 01:00:00.000000000 +0100
9179 +++ php-src/sapi/fpm/fpm/fpm_trace_ptrace.c 2009-10-18 21:05:39.302497288 +0100
9183 + /* (c) 2007,2008 Andrei Nigmatulin */
9185 +#include "fpm_config.h"
9187 +#include <sys/wait.h>
9188 +#include <sys/ptrace.h>
9189 +#include <unistd.h>
9192 +#if defined(PT_ATTACH) && !defined(PTRACE_ATTACH)
9193 +#define PTRACE_ATTACH PT_ATTACH
9196 +#if defined(PT_DETACH) && !defined(PTRACE_DETACH)
9197 +#define PTRACE_DETACH PT_DETACH
9200 +#if defined(PT_READ_D) && !defined(PTRACE_PEEKDATA)
9201 +#define PTRACE_PEEKDATA PT_READ_D
9204 +#include "fpm_trace.h"
9207 +static pid_t traced_pid;
9209 +int fpm_trace_signal(pid_t pid)
9211 + if (0 > ptrace(PTRACE_ATTACH, pid, 0, 0)) {
9212 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(ATTACH) failed");
9219 +int fpm_trace_ready(pid_t pid)
9226 +int fpm_trace_close(pid_t pid)
9228 + if (0 > ptrace(PTRACE_DETACH, pid, (void *) 1, 0)) {
9229 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(DETACH) failed");
9238 +int fpm_trace_get_long(long addr, long *data)
9241 + struct ptrace_io_desc ptio = {
9242 + .piod_op = PIOD_READ_D,
9243 + .piod_offs = (void *) addr,
9244 + .piod_addr = (void *) data,
9245 + .piod_len = sizeof(long)
9248 + if (0 > ptrace(PT_IO, traced_pid, (void *) &ptio, 0)) {
9249 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(PT_IO) failed");
9255 + *data = ptrace(PTRACE_PEEKDATA, traced_pid, (void *) addr, 0);
9258 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(PEEKDATA) failed");
9266 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_unix.c php-src/sapi/fpm/fpm/fpm_unix.c
9267 --- php-src-vanilla/sapi/fpm/fpm/fpm_unix.c 1970-01-01 01:00:00.000000000 +0100
9268 +++ php-src/sapi/fpm/fpm/fpm_unix.c 2009-10-18 21:05:39.310440424 +0100
9272 + /* (c) 2007,2008 Andrei Nigmatulin */
9274 +#include "fpm_config.h"
9276 +#include <string.h>
9277 +#include <sys/time.h>
9278 +#include <sys/resource.h>
9279 +#include <stdlib.h>
9280 +#include <unistd.h>
9281 +#include <sys/types.h>
9286 +#include <sys/prctl.h>
9290 +#include "fpm_conf.h"
9291 +#include "fpm_cleanup.h"
9292 +#include "fpm_clock.h"
9293 +#include "fpm_stdio.h"
9294 +#include "fpm_unix.h"
9297 +size_t fpm_pagesize;
9299 +int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp)
9301 + struct fpm_listen_options_s *lo = wp->config->listen_options;
9303 + /* uninitialized */
9304 + wp->socket_uid = -1;
9305 + wp->socket_gid = -1;
9306 + wp->socket_mode = 0666;
9308 + if (!lo) { return 0; }
9310 + if (lo->owner && *lo->owner) {
9311 + struct passwd *pwd;
9313 + pwd = getpwnam(lo->owner);
9316 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "cannot get uid for user '%s', pool '%s'", lo->owner, wp->config->name);
9320 + wp->socket_uid = pwd->pw_uid;
9321 + wp->socket_gid = pwd->pw_gid;
9324 + if (lo->group && *lo->group) {
9325 + struct group *grp;
9327 + grp = getgrnam(lo->group);
9330 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "cannot get gid for group '%s', pool '%s'", lo->group, wp->config->name);
9334 + wp->socket_gid = grp->gr_gid;
9337 + if (lo->mode && *lo->mode) {
9338 + wp->socket_mode = strtoul(lo->mode, 0, 8);
9344 +static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp)
9346 + int is_root = !geteuid();
9349 + if (wp->config->user && *wp->config->user) {
9351 + if (strlen(wp->config->user) == strspn(wp->config->user, "0123456789")) {
9352 + wp->set_uid = strtoul(wp->config->user, 0, 10);
9355 + struct passwd *pwd;
9357 + pwd = getpwnam(wp->config->user);
9360 + zlog(ZLOG_STUFF, ZLOG_ERROR, "cannot get uid for user '%s', pool '%s'", wp->config->user, wp->config->name);
9364 + wp->set_uid = pwd->pw_uid;
9365 + wp->set_gid = pwd->pw_gid;
9367 + wp->user = strdup(pwd->pw_name);
9368 + wp->home = strdup(pwd->pw_dir);
9372 + if (wp->config->group && *wp->config->group) {
9374 + if (strlen(wp->config->group) == strspn(wp->config->group, "0123456789")) {
9375 + wp->set_gid = strtoul(wp->config->group, 0, 10);
9378 + struct group *grp;
9380 + grp = getgrnam(wp->config->group);
9383 + zlog(ZLOG_STUFF, ZLOG_ERROR, "cannot get gid for group '%s', pool '%s'", wp->config->group, wp->config->name);
9387 + wp->set_gid = grp->gr_gid;
9391 +#ifndef I_REALLY_WANT_ROOT_PHP
9392 + if (wp->set_uid == 0 || wp->set_gid == 0) {
9393 + zlog(ZLOG_STUFF, ZLOG_ERROR, "please specify user and group other than root, pool '%s'", wp->config->name);
9398 + else { /* not root */
9399 + if (wp->config->user && *wp->config->user) {
9400 + zlog(ZLOG_STUFF, ZLOG_WARNING, "'user' directive is ignored, pool '%s'", wp->config->name);
9402 + if (wp->config->group && *wp->config->group) {
9403 + zlog(ZLOG_STUFF, ZLOG_WARNING, "'group' directive is ignored, pool '%s'", wp->config->name);
9405 + if (wp->config->chroot && *wp->config->chroot) {
9406 + zlog(ZLOG_STUFF, ZLOG_WARNING, "'chroot' directive is ignored, pool '%s'", wp->config->name);
9409 + { /* set up HOME and USER anyway */
9410 + struct passwd *pwd;
9412 + pwd = getpwuid(getuid());
9415 + wp->user = strdup(pwd->pw_name);
9416 + wp->home = strdup(pwd->pw_dir);
9424 +int fpm_unix_init_child(struct fpm_worker_pool_s *wp)
9426 + int is_root = !geteuid();
9427 + int made_chroot = 0;
9429 + if (wp->config->rlimit_files) {
9432 + getrlimit(RLIMIT_NOFILE, &r);
9434 + r.rlim_cur = (rlim_t) wp->config->rlimit_files;
9436 + if (0 > setrlimit(RLIMIT_NOFILE, &r)) {
9437 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setrlimit(RLIMIT_NOFILE) failed");
9441 + if (wp->config->rlimit_core) {
9444 + getrlimit(RLIMIT_CORE, &r);
9446 + r.rlim_cur = wp->config->rlimit_core == -1 ? (rlim_t) RLIM_INFINITY : (rlim_t) wp->config->rlimit_core;
9448 + if (0 > setrlimit(RLIMIT_CORE, &r)) {
9449 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setrlimit(RLIMIT_CORE) failed");
9453 + if (is_root && wp->config->chroot && *wp->config->chroot) {
9454 + if (0 > chroot(wp->config->chroot)) {
9455 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "chroot(%s) failed", wp->config->chroot);
9461 + if (wp->config->chdir && *wp->config->chdir) {
9462 + if (0 > chdir(wp->config->chdir)) {
9463 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "chdir(%s) failed", wp->config->chdir);
9467 + else if (made_chroot) {
9472 + if (wp->set_gid) {
9473 + if (0 > setgid(wp->set_gid)) {
9474 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setgid(%d) failed", wp->set_gid);
9478 + if (wp->set_uid) {
9479 + if (0 > initgroups(wp->config->user, wp->set_gid)) {
9480 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "initgroups(%s, %d) failed", wp->config->user, wp->set_gid);
9483 + if (0 > setuid(wp->set_uid)) {
9484 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setuid(%d) failed", wp->set_uid);
9491 + if (0 > prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) {
9492 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "prctl(PR_SET_DUMPABLE) failed");
9496 + if (0 > fpm_clock_init()) {
9503 +int fpm_unix_init_main()
9505 + struct fpm_worker_pool_s *wp;
9507 + fpm_pagesize = getpagesize();
9509 + if (fpm_global_config.daemonize) {
9515 + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fork() failed");
9524 + fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT);
9533 + if (0 > fpm_clock_init()) {
9537 + fpm_globals.parent_pid = getpid();
9539 + for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
9541 + if (0 > fpm_unix_conf_wp(wp)) {
9547 + fpm_stdio_init_final();
9551 + getrlimit(RLIMIT_NOFILE, &r);
9553 + zlog(ZLOG_STUFF, ZLOG_NOTICE, "getrlimit(nofile): max:%lld, cur:%lld",
9554 + (long long) r.rlim_max, (long long) r.rlim_cur);
9559 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_unix.h php-src/sapi/fpm/fpm/fpm_unix.h
9560 --- php-src-vanilla/sapi/fpm/fpm/fpm_unix.h 1970-01-01 01:00:00.000000000 +0100
9561 +++ php-src/sapi/fpm/fpm/fpm_unix.h 2009-10-18 21:05:39.308376784 +0100
9565 + /* (c) 2007,2008 Andrei Nigmatulin */
9568 +#define FPM_UNIX_H 1
9570 +#include "fpm_worker_pool.h"
9572 +int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp);
9573 +int fpm_unix_init_child(struct fpm_worker_pool_s *wp);
9574 +int fpm_unix_init_main();
9576 +extern size_t fpm_pagesize;
9580 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_worker_pool.c php-src/sapi/fpm/fpm/fpm_worker_pool.c
9581 --- php-src-vanilla/sapi/fpm/fpm/fpm_worker_pool.c 1970-01-01 01:00:00.000000000 +0100
9582 +++ php-src/sapi/fpm/fpm/fpm_worker_pool.c 2009-10-18 21:05:39.308376784 +0100
9586 + /* (c) 2007,2008 Andrei Nigmatulin */
9588 +#include "fpm_config.h"
9590 +#include <string.h>
9591 +#include <stdlib.h>
9592 +#include <unistd.h>
9594 +#include "fpm_worker_pool.h"
9595 +#include "fpm_cleanup.h"
9596 +#include "fpm_children.h"
9597 +#include "fpm_shm.h"
9598 +#include "fpm_shm_slots.h"
9599 +#include "fpm_conf.h"
9601 +struct fpm_worker_pool_s *fpm_worker_all_pools;
9603 +static void fpm_worker_pool_cleanup(int which, void *arg)
9605 + struct fpm_worker_pool_s *wp, *wp_next;
9607 + for (wp = fpm_worker_all_pools; wp; wp = wp_next) {
9608 + wp_next = wp->next;
9609 + fpm_worker_pool_config_free(wp->config);
9610 + fpm_children_free(wp->children);
9611 + fpm_array_free(&wp->slots_used);
9612 + fpm_array_free(&wp->slots_free);
9613 + fpm_shm_free_list(wp->shm_list, which == FPM_CLEANUP_CHILD ? fpm_shm_slots_mem() : 0);
9620 + fpm_worker_all_pools = 0;
9623 +struct fpm_worker_pool_s *fpm_worker_pool_alloc()
9625 + struct fpm_worker_pool_s *ret;
9627 + ret = malloc(sizeof(struct fpm_worker_pool_s));
9633 + memset(ret, 0, sizeof(struct fpm_worker_pool_s));
9635 + if (!fpm_worker_all_pools) {
9636 + fpm_worker_all_pools = ret;
9639 + fpm_array_init(&ret->slots_used, sizeof(struct fpm_shm_slot_ptr_s), 50);
9640 + fpm_array_init(&ret->slots_free, sizeof(struct fpm_shm_slot_ptr_s), 50);
9645 +int fpm_worker_pool_init_main()
9647 + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_worker_pool_cleanup, 0)) {
9653 diff -Naur php-src-vanilla/sapi/fpm/fpm/fpm_worker_pool.h php-src/sapi/fpm/fpm/fpm_worker_pool.h
9654 --- php-src-vanilla/sapi/fpm/fpm/fpm_worker_pool.h 1970-01-01 01:00:00.000000000 +0100
9655 +++ php-src/sapi/fpm/fpm/fpm_worker_pool.h 2009-10-18 21:05:39.310440424 +0100
9659 + /* (c) 2007,2008 Andrei Nigmatulin */
9661 +#ifndef FPM_WORKER_POOL_H
9662 +#define FPM_WORKER_POOL_H 1
9664 +#include "fpm_conf.h"
9665 +#include "fpm_arrays.h"
9667 +struct fpm_worker_pool_s;
9668 +struct fpm_child_s;
9669 +struct fpm_child_stat_s;
9672 +enum fpm_address_domain {
9677 +struct fpm_worker_pool_s {
9678 + struct fpm_worker_pool_s *next;
9679 + struct fpm_worker_pool_config_s *config;
9680 + char *user, *home; /* for setting env USER and HOME */
9681 + enum fpm_address_domain listen_address_domain;
9682 + int listening_socket;
9683 + int set_uid, set_gid; /* config uid and gid */
9684 + unsigned is_template:1; /* just config template, no processes will be created */
9685 + int socket_uid, socket_gid, socket_mode;
9687 + struct fpm_shm_s *shm_list;
9688 + struct fpm_array_s slots_used;
9689 + struct fpm_array_s slots_free;
9692 + struct fpm_child_s *children;
9693 + int running_children;
9696 +struct fpm_worker_pool_s *fpm_worker_pool_alloc();
9697 +int fpm_worker_pool_init_main();
9699 +extern struct fpm_worker_pool_s *fpm_worker_all_pools;
9703 diff -Naur php-src-vanilla/sapi/fpm/fpm/xml_config.c php-src/sapi/fpm/fpm/xml_config.c
9704 --- php-src-vanilla/sapi/fpm/fpm/xml_config.c 1970-01-01 01:00:00.000000000 +0100
9705 +++ php-src/sapi/fpm/fpm/xml_config.c 2009-10-18 21:05:39.310440424 +0100
9709 + /* (c) 2004-2007 Andrei Nigmatulin */
9711 +#include "fpm_config.h"
9713 +#ifdef HAVE_ALLOCA_H
9714 +#include <alloca.h>
9716 +#include <string.h>
9718 +#include <stddef.h>
9719 +#include <stdlib.h>
9721 +#include <libxml/parser.h>
9722 +#include <libxml/tree.h>
9724 +#include "xml_config.h"
9726 +static struct xml_conf_section **xml_conf_sections = 0;
9727 +static int xml_conf_sections_allocated = 0;
9728 +static int xml_conf_sections_used = 0;
9730 +char *xml_conf_set_slot_boolean(void **conf, char *name, void *vv, intptr_t offset)
9733 + long value_y = !strcasecmp(value, "yes") || !strcmp(value, "1") || !strcasecmp(value, "on");
9734 + long value_n = !strcasecmp(value, "no") || !strcmp(value, "0") || !strcasecmp(value, "off");
9736 + if (!value_y && !value_n) {
9737 + return "xml_conf_set_slot(): invalid boolean value";
9740 +#ifdef XML_CONF_DEBUG
9741 + fprintf(stderr, "setting boolean '%s' => %s\n", name, value_y ? "TRUE" : "FALSE");
9744 + * (int *) ((char *) *conf + offset) = value_y ? 1 : 0;
9749 +char *xml_conf_set_slot_string(void **conf, char *name, void *vv, intptr_t offset)
9752 + char *v = strdup(value);
9754 + if (!v) { return "xml_conf_set_slot_string(): strdup() failed"; }
9756 +#ifdef XML_CONF_DEBUG
9757 + fprintf(stderr, "setting string '%s' => '%s'\n", name, v);
9760 + * (char **) ((char *) *conf + offset) = v;
9765 +char *xml_conf_set_slot_integer(void **conf, char *name, void *vv, intptr_t offset)
9768 + int v = atoi(value);
9770 + * (int *) ((char *) *conf + offset) = v;
9772 +#ifdef XML_CONF_DEBUG
9773 + fprintf(stderr, "setting integer '%s' => %d\n", name, v);
9779 +char *xml_conf_set_slot_time(void **conf, char *name, void *vv, intptr_t offset)
9782 + int len = strlen(value);
9786 + if (!len) { return "xml_conf_set_slot_timeval(): invalid timeval value"; }
9788 + suffix = value[len-1];
9790 + value[len-1] = '\0';
9794 + seconds = atoi(value);
9797 + seconds = 60 * atoi(value);
9800 + seconds = 60 * 60 * atoi(value);
9803 + seconds = 24 * 60 * 60 * atoi(value);
9806 + return "xml_conf_set_slot_timeval(): unknown suffix used in timeval value";
9809 + * (int *) ((char *) *conf + offset) = seconds;
9811 +#ifdef XML_CONF_DEBUG
9812 + fprintf(stderr, "setting time '%s' => %d:%02d:%02d:%02d\n", name, expand_dhms(seconds));
9818 +char *xml_conf_parse_section(void **conf, struct xml_conf_section *section, void *xml_node)
9820 + xmlNode *element = xml_node;
9823 +#ifdef XML_CONF_DEBUG
9824 + fprintf(stderr, "processing a section %s\n", section->path);
9827 + for ( ; element; element = element->next) {
9828 + if (element->type == XML_ELEMENT_NODE && !strcmp((const char *) element->name, "value") && element->children) {
9829 + xmlChar *name = xmlGetProp(element, (unsigned char *) "name");
9834 +#ifdef XML_CONF_DEBUG
9835 + fprintf(stderr, "found a value: %s\n", name);
9837 + for (i = 0; section->parsers[i].parser; i++) {
9838 + if (!section->parsers[i].name || !strcmp(section->parsers[i].name, (char *) name)) {
9843 + if (section->parsers[i].parser) {
9844 + if (section->parsers[i].type == XML_CONF_SCALAR) {
9845 + if (element->children->type == XML_TEXT_NODE) {
9846 + ret = section->parsers[i].parser(conf, (char *) name, element->children->content, section->parsers[i].offset);
9849 + ret = "XML_TEXT_NODE is expected, something different is given";
9853 + ret = section->parsers[i].parser(conf, (char *) name, element->children, section->parsers[i].offset);
9857 + if (ret) { return ret; }
9858 + else { continue; }
9861 + fprintf(stderr, "Warning, unknown setting '%s' in section '%s'\n", (char *) name, section->path);
9871 +static char *xml_conf_parse_file(xmlNode *element)
9875 + for ( ; element; element = element->next) {
9877 + if (element->parent && element->type == XML_ELEMENT_NODE && !strcmp((const char *) element->name, "section")) {
9878 + xmlChar *name = xmlGetProp(element, (unsigned char *) "name");
9881 + char *parent_name = (char *) xmlGetNodePath(element->parent);
9884 + struct xml_conf_section *section = NULL;
9886 +#ifdef XML_CONF_DEBUG
9887 + fprintf(stderr, "got a section: %s/%s\n", parent_name, name);
9889 + full_name = alloca(strlen(parent_name) + strlen((char *) name) + 1 + 1);
9891 + sprintf(full_name, "%s/%s", parent_name, (char *) name);
9893 + xmlFree(parent_name);
9896 + for (i = 0; i < xml_conf_sections_used; i++) {
9897 + if (!strcmp(xml_conf_sections[i]->path, full_name)) {
9898 + section = xml_conf_sections[i];
9902 + if (section) { /* found a registered section */
9903 + void *conf = section->conf();
9904 + ret = xml_conf_parse_section(&conf, section, element->children);
9905 + if (ret) { break; }
9911 + if (element->children) {
9912 + ret = xml_conf_parse_file(element->children);
9913 + if (ret) { break; }
9920 +char *xml_conf_load_file(char *file)
9925 + LIBXML_TEST_VERSION
9927 + doc = xmlParseFile(file);
9930 + ret = xml_conf_parse_file(doc->children);
9934 + ret = "failed to parse conf file";
9937 + xmlCleanupParser();
9941 +int xml_conf_init()
9946 +void xml_conf_clean()
9948 + if (xml_conf_sections) {
9949 + free(xml_conf_sections);
9953 +int xml_conf_section_register(struct xml_conf_section *section)
9955 + if (xml_conf_sections_allocated == xml_conf_sections_used) {
9956 + int new_size = xml_conf_sections_used + 10;
9957 + void *new_ptr = realloc(xml_conf_sections, sizeof(struct xml_conf_section *) * new_size);
9960 + xml_conf_sections = new_ptr;
9961 + xml_conf_sections_allocated = new_size;
9964 + fprintf(stderr, "xml_conf_section_register(): out of memory\n");
9969 + xml_conf_sections[xml_conf_sections_used++] = section;
9974 +int xml_conf_sections_register(struct xml_conf_section *sections[])
9976 + for ( ; sections && *sections; sections++) {
9977 + if (0 > xml_conf_section_register(*sections)) {
9985 diff -Naur php-src-vanilla/sapi/fpm/fpm/xml_config.h php-src/sapi/fpm/fpm/xml_config.h
9986 --- php-src-vanilla/sapi/fpm/fpm/xml_config.h 1970-01-01 01:00:00.000000000 +0100
9987 +++ php-src/sapi/fpm/fpm/xml_config.h 2009-10-18 21:05:39.310440424 +0100
9991 + /* (c) 2004-2007 Andrei Nigmatulin */
9993 +#ifndef XML_CONFIG_H
9994 +#define XML_CONFIG_H 1
9996 +#if HAVE_INTTYPES_H
9997 +#include <inttypes.h>
9999 +#include <stdint.h>
10003 +struct xml_value_parser;
10005 +struct xml_value_parser {
10008 + char *(*parser)(void **, char *, void *, intptr_t offset);
10012 +struct xml_conf_section {
10015 + struct xml_value_parser *parsers;
10018 +char *xml_conf_set_slot_boolean(void **conf, char *name, void *value, intptr_t offset);
10019 +char *xml_conf_set_slot_string(void **conf, char *name, void *value, intptr_t offset);
10020 +char *xml_conf_set_slot_integer(void **conf, char *name, void *value, intptr_t offset);
10021 +char *xml_conf_set_slot_time(void **conf, char *name, void *value, intptr_t offset);
10023 +int xml_conf_init();
10024 +void xml_conf_clean();
10025 +char *xml_conf_load_file(char *file);
10026 +char *xml_conf_parse_section(void **conf, struct xml_conf_section *section, void *ve);
10027 +int xml_conf_section_register(struct xml_conf_section *section);
10028 +int xml_conf_sections_register(struct xml_conf_section *sections[]);
10030 +#define expand_hms(value) (value) / 3600, ((value) % 3600) / 60, (value) % 60
10032 +#define expand_dhms(value) (value) / 86400, ((value) % 86400) / 3600, ((value) % 3600) / 60, (value) % 60
10034 +enum { XML_CONF_SCALAR = 1, XML_CONF_SUBSECTION = 2 };
10037 diff -Naur php-src-vanilla/sapi/fpm/fpm/zlog.c php-src/sapi/fpm/fpm/zlog.c
10038 --- php-src-vanilla/sapi/fpm/fpm/zlog.c 1970-01-01 01:00:00.000000000 +0100
10039 +++ php-src/sapi/fpm/fpm/zlog.c 2009-10-18 21:05:39.310440424 +0100
10043 + /* (c) 2004-2007 Andrei Nigmatulin */
10045 +#include "fpm_config.h"
10047 +#include <stdio.h>
10048 +#include <unistd.h>
10050 +#include <string.h>
10051 +#include <stdarg.h>
10052 +#include <sys/time.h>
10053 +#include <errno.h>
10057 +#define MAX_LINE_LENGTH 1024
10059 +static int zlog_fd = -1;
10060 +static int zlog_level = ZLOG_NOTICE;
10062 +static const char *level_names[] = {
10063 + [ZLOG_DEBUG] = "DEBUG",
10064 + [ZLOG_NOTICE] = "NOTICE",
10065 + [ZLOG_WARNING] = "WARNING",
10066 + [ZLOG_ERROR] = "ERROR",
10067 + [ZLOG_ALERT] = "ALERT",
10070 +size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len)
10075 + len = strftime(timebuf, timebuf_len, "%b %d %H:%M:%S", localtime_r((const time_t *) &tv->tv_sec, &t));
10076 + len += snprintf(timebuf + len, timebuf_len - len, ".%06d", (int) tv->tv_usec);
10081 +int zlog_set_fd(int new_fd)
10083 + int old_fd = zlog_fd;
10084 + zlog_fd = new_fd;
10089 +int zlog_set_level(int new_value)
10091 + int old_value = zlog_level;
10093 + zlog_level = new_value;
10095 + return old_value;
10098 +void zlog(const char *function, int line, int flags, const char *fmt, ...)
10100 + struct timeval tv;
10101 + char buf[MAX_LINE_LENGTH];
10102 + const size_t buf_size = MAX_LINE_LENGTH;
10105 + int truncated = 0;
10108 + if ((flags & ZLOG_LEVEL_MASK) < zlog_level) {
10112 + saved_errno = errno;
10114 + gettimeofday(&tv, 0);
10116 + len = zlog_print_time(&tv, buf, buf_size);
10118 + len += snprintf(buf + len, buf_size - len, " [%s] %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line);
10120 + if (len > buf_size - 1) {
10124 + if (!truncated) {
10125 + va_start(args, fmt);
10127 + len += vsnprintf(buf + len, buf_size - len, fmt, args);
10131 + if (len >= buf_size) {
10136 + if (!truncated) {
10137 + if (flags & ZLOG_HAVE_ERRNO) {
10138 + len += snprintf(buf + len, buf_size - len, ": %s (%d)", strerror(saved_errno), saved_errno);
10139 + if (len >= buf_size) {
10146 + memcpy(buf + buf_size - sizeof("..."), "...", sizeof("...") - 1);
10147 + len = buf_size - 1;
10150 + buf[len++] = '\n';
10152 + write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len);
10154 diff -Naur php-src-vanilla/sapi/fpm/fpm/zlog.h php-src/sapi/fpm/fpm/zlog.h
10155 --- php-src-vanilla/sapi/fpm/fpm/zlog.h 1970-01-01 01:00:00.000000000 +0100
10156 +++ php-src/sapi/fpm/fpm/zlog.h 2009-10-18 21:05:39.308376784 +0100
10160 + /* (c) 2004-2007 Andrei Nigmatulin */
10165 +#define ZLOG_STUFF __func__, __LINE__
10169 +int zlog_set_fd(int new_fd);
10170 +int zlog_set_level(int new_value);
10172 +size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len);
10174 +void zlog(const char *function, int line, int flags, const char *fmt, ...)
10175 + __attribute__ ((format(printf,4,5)));
10180 + ZLOG_WARNING = 3,
10185 +#define ZLOG_LEVEL_MASK 7
10187 +#define ZLOG_HAVE_ERRNO 0x100
10189 +#define ZLOG_SYSERROR (ZLOG_ERROR | ZLOG_HAVE_ERRNO)
10192 diff -Naur php-src-vanilla/sapi/fpm/LICENSE php-src/sapi/fpm/LICENSE
10193 --- php-src-vanilla/sapi/fpm/LICENSE 1970-01-01 01:00:00.000000000 +0100
10194 +++ php-src/sapi/fpm/LICENSE 2009-10-18 21:05:39.302497288 +0100
10196 +Copyright (c) 2007-2009, Andrei Nigmatulin
10197 +All rights reserved.
10199 +Redistribution and use in source and binary forms, with or without
10200 +modification, are permitted provided that the following conditions
10202 +1. Redistributions of source code must retain the above copyright
10203 + notice, this list of conditions and the following disclaimer.
10204 +2. Redistributions in binary form must reproduce the above copyright
10205 + notice, this list of conditions and the following disclaimer in the
10206 + documentation and/or other materials provided with the distribution.
10208 +THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
10209 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10210 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10211 +ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
10212 +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10213 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10214 +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10215 +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10216 +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10217 +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10219 diff -Naur php-src-vanilla/sapi/fpm/man/php-fpm.1.in php-src/sapi/fpm/man/php-fpm.1.in
10220 --- php-src-vanilla/sapi/fpm/man/php-fpm.1.in 1970-01-01 01:00:00.000000000 +0100
10221 +++ php-src/sapi/fpm/man/php-fpm.1.in 2009-10-18 21:05:39.310440424 +0100
10223 +.TH PHP-FPM 1 "2009" "The PHP Group" "Scripting Language"
10226 +@php_fpm_bin@ \- PHP FastCGI Process Manager 'PHP-FPM'
10232 +\fBPHP\fP is a widely\-used general\-purpose scripting language that is especially suited for
10233 +Web development and can be embedded into HTML. This is a variant of PHP that will run in the background as a daemon, listening for CGI requests. Output is logged to @php_fpm_log_path@.
10235 +Most options are set in the xml configuration file @php_fpm_conf_path@. Unless configured otherwise, @php_fpm_bin@ will respond to CGI requests listening on http localhost port 9000 by default. Therefore @php_fpm_bin@ expects your webserver to forward all requests for '.php' files to port 9000 and you should edit your webserver configuration file appropriately.
10239 +Do not chdir to the script's directory
10242 +.B \-\-php\-ini \fIpath\fP|\fIfile\fP
10245 +.B \-c \fIpath\fP|\fIfile\fP
10248 +file in the directory
10250 +or use the specified
10254 +.B \-\-no\-php\-ini
10263 +.B \-\-define \fIfoo\fP[=\fIbar\fP]
10266 +.B \-d \fIfoo\fP[=\fIbar\fP]
10273 +Generate extended information for debugger/profiler
10287 +PHP information and configuration
10294 +Show compiled in modules
10304 +.B \-\-fpm\-config \fIfile\fP
10308 +Specify alternative path to FastCGI process manager configuration file (the default is @php_fpm_conf_path@)
10311 +.B \-\-zend\-extension \fIfile\fP
10315 +Load Zend extension
10319 +.B @php_fpm_bin@.conf
10320 +The configuration file for the @php_fpm_bin@ daemon.
10323 +The standard php configuration file.
10325 +You should use the init script provided to start and stop the @php_fpm_bin@ daemon. This situation applies for any unix systems which use init.d for their main process manager.
10329 +sudo /etc/init.d/@php_fpm_bin@ start
10332 +If your installation has no appropriate init script, launch @php_fpm_bin_path@ with no arguments. It will launch as a daemon (background process) by default. The file @php_fpm_pid_path@ determines whether @php_fpm_bin@ is already up and running. Once started, @php_fpm_bin@ then responds to several POSIX signals:
10336 +.B SIGINT,SIGTERM \fPimmediate termination
10338 +.B SIGQUIT \fPgraceful stop
10340 +.B SIGUSR1 \fPre-open log file
10342 +.B SIGUSR2 \fPgraceful reload of all workers + reload of fpm conf/binary
10347 +The PHP-FPM CGI daemon will work well with most popular webservers, including Apache2 and light-httpd. For best efficiency and performance improvements its also worthwhile to consider the engine-x webserver ('nginx'), and php opcode-cacher ('php5-xcache').
10351 +The PHP-FPM website:
10354 +.B http://php-fpm.org
10357 +For a more or less complete description of PHP look here:
10360 +.B http://www.php.net/manual/
10363 +A nice introduction to PHP by Stig Bakken can be found here:
10366 +.B http://www.zend.com/zend/art/intro.php
10369 +You can view the list of known bugs or report any new bug you
10373 +.B http://bugs.php.net
10376 +PHP-FPM Sapi was written by Andrei Nigmatulin. The mailing-lists are highload-php-en (English) and highload-php-ru (Russion).
10378 +The PHP Group: Thies C. Arntzen, Stig Bakken, Andi Gutmans, Rasmus Lerdorf, Sam Ruby, Sascha Schumann, Zeev Suraski, Jim Winstead, Andrei Zmievski.
10380 +A List of active developers can be found here:
10383 +.B http://www.php.net/credits.php
10386 +And last but not least PHP was developed with the help of a huge amount of
10387 +contributors all around the world.
10388 +.SH VERSION INFORMATION
10389 +This manpage describes \fBphp\fP, version @PHP_VERSION@, \fBfpm\fP, version @fpm_version@.
10391 +Copyright \(co 1997\-2009 The PHP Group
10394 +Copyright (c) 2007-2009, Andrei Nigmatulin
10397 +This source file is subject to version 3.01 of the PHP license,
10398 +that is bundled with this package in the file LICENSE, and is
10399 +available through the world-wide-web at the following url:
10402 +.B http://www.php.net/license/3_01.txt
10405 +If you did not receive a copy of the PHP license and are unable to
10406 +obtain it through the world-wide-web, please send a note to
10407 +.B license@php.net
10408 +so we can mail you a copy immediately.
10409 diff -Naur php-src-vanilla/sapi/fpm/readme-ru.markdown php-src/sapi/fpm/readme-ru.markdown
10410 --- php-src-vanilla/sapi/fpm/readme-ru.markdown 1970-01-01 01:00:00.000000000 +0100
10411 +++ php-src/sapi/fpm/readme-ru.markdown 2009-10-18 21:05:39.310440424 +0100
10413 +# PHP FastCGI Менеджер процессов (PHP-FPM)
10415 +PHP-FPM это Fast-CGI фронтэнд для php и расширение php-cgi. Проект находится на [Launchpad](https://launchpad.net/php-fpm)
10419 +Выберите один из 2 путей сборки fpm: Или `встроенный`, или `отдельный`. Если вы не разработчик или не системный администратор, то мы рекомендуем `встроенный` вариант компиляции. Для дополнительной информации смотрите файл `readme.markdown`.
10422 +Если вы до этого не устанавливали php, то вам придётся установить пакет `libxml2-dev`. FPM также необходим `libevent-dev`. Debian / ubuntu:
10424 + sudo aptitude install -y libxml2-dev libevent-dev
10426 +Рекомендуется использовать libevent 1.4.12-stable или позднее, но необходим, как минимум, libevent 1.4.3-stable. Если нет подходящей версии, скайте и скомпилируйте с [сайта Libevent](http://www.monkey.org/~provos/libevent/).
10428 + export LE_VER=1.4.12-stable
10429 + wget "http://www.monkey.org/~provos/libevent-$LE_VER.tar.gz"
10430 + tar -zxvf "libevent-$LE_VER.tar.gz"
10431 + cd "libevent-$LE_VER"
10432 + ./configure && make
10433 + DESTDIR=$PWD make install
10434 + export LIBEVENT_SEARCH_PATH="$PWD/usr/local"
10436 +## Встроенная сборка
10438 +Скачайте fpm и сгенерируйте патч
10440 + export PHP_VER=5.3.0
10441 + wget "http://launchpad.net/php-fpm/master/0.6/+download/php-fpm-0.6-$PHP_VER.tar.gz"
10442 + tar -zxvf "php-fpm-0.6-$PHP_VER.tar.gz"
10443 + "php-fpm-0.6-$PHP_VER/generate-fpm-patch"
10445 +Скачайте и распакуйте исходный код PHP
10447 + wget "http://ru2.php.net/get/php-$PHP_VER.tar.gz/from/ru2.php.net/mirror"
10448 + tar xvfz "php-$PHP_VER.tar.gz"
10449 + cd "php-$PHP_VER"
10451 +Примените патч и компилируйте
10453 + patch -p1 < ../fpm.patch
10454 + ./buildconf --force
10455 + mkdir fpm-build && cd fpm-build
10456 + ../configure --with-fpm \
10457 + --with-libevent="$LIBEVENT_SEARCH_PATH" && make
10459 +## Отдельная сборка
10461 +Скачайте и распакуйте исходный код PHP
10463 + export PHP_VER=5.3.0
10464 + wget "http://ru2.php.net/get/php-$PHP_VER.tar.gz/from/ru2.php.net/mirror"
10465 + tar xvfz "php-$PHP_VER.tar.gz"
10466 + cd "php-$PHP_VER"
10467 + mkdir php-build && cd php-build
10468 + ../configure && make
10470 +Теперь можете скачать, конфигурировать и компилировать FPM фронтэнд
10472 + wget "http://launchpad.net/php-fpm/master/0.6/+download/php-fpm-0.6-$PHP_VER.tar.gz"
10473 + tar -zxvf "php-fpm-0.6-$PHP_VER.tar.gz"
10474 + cd "php-fpm-0.6-$PHP_VER"
10475 + mkdir fpm-build && cd fpm-build
10476 + ../configure --srcdir=../ \
10477 + --with-php-src="../../php-$PHP_VER" \
10478 + --with-php-build="../../php-$PHP_VER/php-build" \
10479 + --with-libevent="$LIBEVENT_SEARCH_PATH" && make
10481 +## Флаги конфигурирования
10483 + --with-libevent[=PATH] Путь до libevent, для fpm SAPI [/usr/local]
10484 + --with-fpm-bin[=PATH] Путь для откомпилированного php-fpm [/usr/local/bin/php-fpm]
10485 + --with-fpm-port[=PORT] TCP порт для cgi запросов [9000]
10486 + --with[out]-fpm-conf[=PATH] Путь до файла конфигурации php-fpm [/etc/php-fpm.conf]
10487 + --with[out]-fpm-init[=PATH] Путь до init-файла php-fpm [/etc/init.d/php-fpm]
10488 + --with-fpm-log[=PATH] Путь до лог-файла php-fpm [/var/log/php-fpm.log]
10489 + --with-fpm-pid[=PATH] Путь до pid-файла php-fpm [/var/run/php-fpm.pid]
10490 + --with-fpm-user[=USER] Пользователь, под которым запускать php-fpm [nobody]
10491 + --with-fpm-group[=GRP] Группа, под которой запускать php-fpm. Для системных
10492 + пользователей задайте имя пользователя [nobody]
10496 +Если вы делали `встроенную` сборку, то вы получите полный php, включая исполнитель коммандной строки `php-cli` и библиотеку PEAR. `Отдельная` или `независимая` сборка установит только демон `php-fpm` и минимум файлов, необходимых для его запуска.
10498 + # Посмотреть, какие файлы будут установлены
10499 + make install --dry-run
10501 + # Установить в '/'
10502 + sudo make install
10504 + # Установить в '/opt'
10505 + sudo INSTALL_ROOT=/opt make install
10509 +* (Upgrade) When overwriting existing FPM installation files: A previous configuration file `php-fpm.conf` will be moved to `php-fpm.conf.old`. Then a newer (default) configuration file will be installed in it's place. If you have any custom XML settings which you wish to keep, its recommended to copy these back over manually.
10511 +* (BSD) the default init.d path is `/usr/local/etc/rc.d/php-fpm` or disable: `--without-fpm-init`
10513 +* (Nginx) An example nginx configuration file is generated. The file `nginx-site-conf.sample` may be installed into your nginx configuration directory, if exists: `/etc/nginx/`, `/usr/local/etc/nginx/`, or `/usr/local/nginx/conf`
10515 +## Больше о процессе сборки PHP-FPM
10517 +Процесс сборки можно описать так:
10519 + 1) Компилируются исходники php в объектные файлы
10520 + 2) Компилируются исходники fpm в объектные файлы
10521 + 3) Линковка php и fpm объектных файлов
10522 + 4) Результат: исполняемый php5, в основе которого php и fast-CGI от fpm как фронтэнд
10524 +Fpm подмешивается в php при линковке (link-level). Андрей разделил исходный код fpm, сделав SAPI чем-то менее чуствительным к изменениям в остальном коде php. Код cgi-main.c из PHP-FPM - конктроллер запросов - вырезан из оригинального fcgi-sapi. Мы отправляем билд 0.6 в PHP Group. Мы будем отслеживать развитие PHP и периодически синхронизировать изменения с проектами встроенной / отдельной сборки.
10528 +Для сборки fpm отдельно, конфигурирование (`./configure`) требует некоторой версии набора инструментов autoconf. Buildconf запустит `./generate-autotools` и попробует установить эти инструменты самостоятельно. Если `./buildconf` не работает, смотрите лог ошибок.
10533 +Есть 2 группы для обсуждения php-fpm,
10535 +- [highload-php-ru](http://groups.google.com/group/highload-php-en) (english)
10537 +- [highload-php-ru](http://groups.google.com/group/highload-php-ru) (русская)
10539 +Translated by Anatoly Pashin