]> git.pld-linux.org Git - packages/php.git/blame - php-fpm.patch
rel 3
[packages/php.git] / php-fpm.patch
CommitLineData
08e9ce79
ER
1diff -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
4@@ -0,0 +1,47 @@
5+
6+AC_DEFUN([AC_FPM_BUILD_SAPI],
7+[
8+ PHP_ADD_MAKEFILE_FRAGMENT($abs_srcdir/sapi/fpm/ac/Makefile.frag,$abs_srcdir/sapi/fpm,sapi/fpm)
9+
10+ SAPI_FPM_PATH=sapi/fpm/$php_fpm_bin
11+ PHP_SUBST(SAPI_FPM_PATH)
12+
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"
16+
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"
20+
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 "{} " \;`
23+ fi
24+
25+ PHP_FPM_CFLAGS="$LIBEVENT_CFLAGS -I$abs_srcdir/sapi/fpm"
26+
27+ SAPI_EXTRA_LIBS="$LIBEVENT_LIBS"
28+ PHP_SUBST(SAPI_EXTRA_LIBS)
29+
30+ dnl Set install target and select SAPI
31+ INSTALL_IT=":"
32+
33+ PHP_SELECT_SAPI(fpm, program, $PHP_FPM_SAPI_FILES $PHP_FPM_CORE_FILES $PHP_FPM_TRACE_FILES, $PHP_FPM_CFLAGS, '$(SAPI_FPM_PATH)')
34+
35+ case $host_alias in
36+ *aix*)
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)"
38+ ;;
39+ *darwin*)
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)"
41+ ;;
42+ *)
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)"
44+ ;;
45+ esac
46+
47+ ENDIF=endif
48+ PHP_SUBST(ENDIF)
49+ PHP_SUBST(BUILD_FPM)
50+
51+])
52diff -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
55@@ -0,0 +1,299 @@
56+dnl
57+dnl $Id$
58+dnl
59+
60+AC_DEFUN([AC_FPM_CHECKS],
61+[
62+ AC_FPM_STDLIBS
63+ AC_FPM_PRCTL
64+ AC_FPM_CLOCK
65+ AC_FPM_TRACE
66+])
67+
68+AC_DEFUN([AC_FPM_STDLIBS],
69+[
70+ AC_CHECK_FUNCS(setenv clearenv)
71+
72+ AC_SEARCH_LIBS(socket, socket)
73+ AC_SEARCH_LIBS(inet_addr, nsl)
74+
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])
78+])
79+
80+AC_DEFUN([AC_FPM_PRCTL],
81+[
82+ AC_MSG_CHECKING([for prctl])
83+
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])
87+ ], [
88+ AC_MSG_RESULT([no])
89+ ])
90+])
91+
92+AC_DEFUN([AC_FPM_CLOCK],
93+[
94+ have_clock_gettime=no
95+
96+ AC_MSG_CHECKING([for clock_gettime])
97+
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])
101+ ], [
102+ AC_MSG_RESULT([no])
103+ ])
104+
105+ if test "$have_clock_gettime" = "no"; then
106+ AC_MSG_CHECKING([for clock_gettime in -lrt])
107+
108+ SAVED_LIBS="$LIBS"
109+ LIBS="$LIBS -lrt"
110+
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])
114+ ], [
115+ LIBS="$SAVED_LIBS"
116+ AC_MSG_RESULT([no])
117+ ])
118+ fi
119+
120+ if test "$have_clock_gettime" = "yes"; then
121+ AC_DEFINE([HAVE_CLOCK_GETTIME], 1, [do we have clock_gettime?])
122+ fi
123+
124+ have_clock_get_time=no
125+
126+ if test "$have_clock_gettime" = "no"; then
127+ AC_MSG_CHECKING([for clock_get_time])
128+
129+ AC_TRY_RUN([ #include <mach/mach.h>
130+ #include <mach/clock.h>
131+ #include <mach/mach_error.h>
132+
133+ int main()
134+ {
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);
137+
138+ if (ret != KERN_SUCCESS) {
139+ return 1;
140+ }
141+
142+ ret = clock_get_time(aClock, &aTime);
143+ if (ret != KERN_SUCCESS) {
144+ return 2;
145+ }
146+
147+ return 0;
148+ }
149+ ], [
150+ have_clock_get_time=yes
151+ AC_MSG_RESULT([yes])
152+ ], [
153+ AC_MSG_RESULT([no])
154+ ])
155+ fi
156+
157+ if test "$have_clock_get_time" = "yes"; then
158+ AC_DEFINE([HAVE_CLOCK_GET_TIME], 1, [do we have clock_get_time?])
159+ fi
160+])
161+
162+AC_DEFUN([AC_FPM_TRACE],
163+[
164+ have_ptrace=no
165+ have_broken_ptrace=no
166+
167+ AC_MSG_CHECKING([for ptrace])
168+
169+ AC_TRY_COMPILE([
170+ #include <sys/types.h>
171+ #include <sys/ptrace.h> ], [ptrace(0, 0, (void *) 0, 0);], [
172+ have_ptrace=yes
173+ AC_MSG_RESULT([yes])
174+ ], [
175+ AC_MSG_RESULT([no])
176+ ])
177+
178+ if test "$have_ptrace" = "yes"; then
179+ AC_MSG_CHECKING([whether ptrace works])
180+
181+ AC_TRY_RUN([
182+ #include <unistd.h>
183+ #include <signal.h>
184+ #include <sys/wait.h>
185+ #include <sys/types.h>
186+ #include <sys/ptrace.h>
187+ #include <errno.h>
188+
189+ #if !defined(PTRACE_ATTACH) && defined(PT_ATTACH)
190+ #define PTRACE_ATTACH PT_ATTACH
191+ #endif
192+
193+ #if !defined(PTRACE_DETACH) && defined(PT_DETACH)
194+ #define PTRACE_DETACH PT_DETACH
195+ #endif
196+
197+ #if !defined(PTRACE_PEEKDATA) && defined(PT_READ_D)
198+ #define PTRACE_PEEKDATA PT_READ_D
199+ #endif
200+
201+ int main()
202+ {
203+ long v1 = (unsigned int) -1; /* copy will fail if sizeof(long) == 8 and we've got "int ptrace()" */
204+ long v2;
205+ pid_t child;
206+ int status;
207+
208+ if ( (child = fork()) ) { /* parent */
209+ int ret = 0;
210+
211+ if (0 > ptrace(PTRACE_ATTACH, child, 0, 0)) {
212+ return 1;
213+ }
214+
215+ waitpid(child, &status, 0);
216+
217+ #ifdef PT_IO
218+ struct ptrace_io_desc ptio = {
219+ .piod_op = PIOD_READ_D,
220+ .piod_offs = &v1,
221+ .piod_addr = &v2,
222+ .piod_len = sizeof(v1)
223+ };
224+
225+ if (0 > ptrace(PT_IO, child, (void *) &ptio, 0)) {
226+ ret = 1;
227+ }
228+ #else
229+ errno = 0;
230+
231+ v2 = ptrace(PTRACE_PEEKDATA, child, (void *) &v1, 0);
232+
233+ if (errno) {
234+ ret = 1;
235+ }
236+ #endif
237+ ptrace(PTRACE_DETACH, child, (void *) 1, 0);
238+
239+ kill(child, SIGKILL);
240+
241+ return ret ? ret : (v1 != v2);
242+ }
243+ else { /* child */
244+ sleep(10);
245+ return 0;
246+ }
247+ }
248+ ], [
249+ AC_MSG_RESULT([yes])
250+ ], [
251+ have_ptrace=no
252+ have_broken_ptrace=yes
253+ AC_MSG_RESULT([no])
254+ ])
255+ fi
256+
257+ if test "$have_ptrace" = "yes"; then
258+ AC_DEFINE([HAVE_PTRACE], 1, [do we have ptrace?])
259+ fi
260+
261+ have_mach_vm_read=no
262+
263+ if test "$have_broken_ptrace" = "yes"; then
264+ AC_MSG_CHECKING([for mach_vm_read])
265+
266+ AC_TRY_COMPILE([ #include <mach/mach.h>
267+ #include <mach/mach_vm.h>
268+ ], [
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);
270+ ], [
271+ have_mach_vm_read=yes
272+ AC_MSG_RESULT([yes])
273+ ], [
274+ AC_MSG_RESULT([no])
275+ ])
276+ fi
277+
278+ if test "$have_mach_vm_read" = "yes"; then
279+ AC_DEFINE([HAVE_MACH_VM_READ], 1, [do we have mach_vm_read?])
280+ fi
281+
282+ proc_mem_file=""
283+
284+ if test -r /proc/$$/mem ; then
285+ proc_mem_file="mem"
286+ else
287+ if test -r /proc/$$/as ; then
288+ proc_mem_file="as"
289+ fi
290+ fi
291+
292+ if test -n "$proc_mem_file" ; then
293+ AC_MSG_CHECKING([for proc mem file])
294+
295+ AC_TRY_RUN([
296+ #define _GNU_SOURCE
297+ #define _FILE_OFFSET_BITS 64
298+ #if HAVE_INTTYPES_H
299+ #include <inttypes.h>
300+ #else
301+ #include <stdint.h>
302+ #endif
303+
304+ #include <unistd.h>
305+ #include <sys/types.h>
306+ #include <sys/stat.h>
307+ #include <fcntl.h>
308+ #include <stdio.h>
309+ int main()
310+ {
311+ long v1 = (unsigned int) -1, v2 = 0;
312+ char buf[128];
313+ int fd;
314+ sprintf(buf, "/proc/%d/$proc_mem_file", getpid());
315+ fd = open(buf, O_RDONLY);
316+ if (0 > fd) {
317+ return 1;
318+ }
319+ if (sizeof(long) != pread(fd, &v2, sizeof(long), (uintptr_t) &v1)) {
320+ close(fd);
321+ return 1;
322+ }
323+ close(fd);
324+ return v1 != v2;
325+ }
326+ ], [
327+ AC_MSG_RESULT([$proc_mem_file])
328+ ], [
329+ proc_mem_file=""
330+ AC_MSG_RESULT([no])
331+ ])
332+ fi
333+
334+ if test -n "$proc_mem_file"; then
335+ AC_DEFINE_UNQUOTED([PROC_MEM_FILE], "$proc_mem_file", [/proc/pid/mem interface])
336+ fi
337+
338+ fpm_trace_type=""
339+
340+ if test "$have_ptrace" = "yes"; then
341+ fpm_trace_type=ptrace
342+
343+ elif test -n "$proc_mem_file"; then
344+ fpm_trace_type=pread
345+
346+ elif test "$have_mach_vm_read" = "yes" ; then
347+ fpm_trace_type=mach
348+
349+ else
350+ AC_MSG_ERROR([FPM Trace - ptrace, pread, or mach: could not be found])
351+ fi
352+
353+])
354+
355diff -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
358@@ -0,0 +1,188 @@
359+
360+AC_DEFUN([AC_FPM_ARGS],
361+[
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)
364+
365+ PHP_ARG_WITH(fpm-port,,
366+ [ --with-fpm-port[=PORT] Set the tcp port number to listen for cgi requests [9000]], yes, no)
367+
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)
370+
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)
373+
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)
376+
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)
379+
380+ PHP_ARG_WITH(fpm-user,,
381+ [ --with-fpm-user[=USER] Set the user for php-fpm to run as [nobody]], yes, no)
382+
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)
386+])
387+
388+AC_DEFUN([AC_FPM_VARS],
389+[
390+ fpm_prefix=$ac_default_prefix
391+ if test $prefix != "NONE" -a $prefix != "" -a $prefix != "no" ; then
392+ fpm_prefix=$prefix
393+ else
394+ prefix=$fpm_prefix
395+ fi
396+
397+ if test $exec_prefix = "NONE" -o $exec_prefix = "" -o $exec_prefix = "no" ; then
398+ exec_prefix=$fpm_prefix
399+ fi
400+
401+ if test `echo "$bindir" | grep "exec_prefix"` ; then
402+ bindir=$exec_prefix/bin
403+ fi
404+
405+ fpm_bin_prefix=$fpm_prefix/bin
406+ if test $bindir != "NONE" -a $bindir != "" -a $bindir != "no" ; then
407+ fpm_bin_prefix=$bindir
408+ fi
409+
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"
412+ else
413+ php_fpm_bin_path="$PHP_FPM_BIN"
414+ fi
415+ php_fpm_bin=`basename $php_fpm_bin_path`
416+ php_fpm_bin_dir=`dirname $php_fpm_bin_path`
417+
418+ if test -z "$PHP_FPM_PORT" -o "$PHP_FPM_PORT" = "yes" -o "$PHP_FPM_PORT" = "no"; then
419+ php_fpm_port="9000"
420+ else
421+ php_fpm_port="$PHP_FPM_PORT"
422+ fi
423+
424+ if test -z "$PHP_FPM_CONF" -o "$PHP_FPM_CONF" = "yes"; then
425+ case $host_os in
426+ freebsd*|dragonfly*) php_fpm_conf_path="/usr/local/etc/php-fpm.conf" ;;
427+ *) php_fpm_conf_path="/etc/php-fpm.conf" ;;
428+ esac
429+ elif test "$PHP_FPM_CONF" = "no"; then
430+ php_fpm_conf_path=""
431+ else
432+ php_fpm_conf_path="$PHP_FPM_CONF"
433+ fi
434+ if test -z "$php_fpm_conf_path"; then
435+ php_fpm_conf=""
436+ php_fpm_conf_dir=""
437+ else
438+ php_fpm_conf=`basename $php_fpm_conf_path`
439+ php_fpm_conf_dir=`dirname $php_fpm_conf_path`
440+ fi
441+
442+ if test -z "$PHP_FPM_INIT" -o "$PHP_FPM_INIT" = "yes"; then
443+ case $host_os in
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" ;;
448+ esac
449+ test -f /etc/arch-release && php_fpm_init_path="/etc/rc.d/php-fpm" # arch linux
450+
451+ elif test "$PHP_FPM_INIT" = "no"; then
452+ php_fpm_init_path=""
453+ else
454+ php_fpm_init_path="$PHP_FPM_INIT"
455+ fi
456+ if test -z "$php_fpm_init_path"; then
457+ php_fpm_init=""
458+ php_fpm_init_dir=""
459+ else
460+ php_fpm_init=`basename $php_fpm_init_path`
461+ php_fpm_init_dir=`dirname $php_fpm_init_path`
462+ fi
463+
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"
466+ else
467+ php_fpm_log_path="$PHP_FPM_LOG"
468+ fi
469+ php_fpm_log_dir=`dirname $php_fpm_log_path`
470+
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"
473+ else
474+ php_fpm_pid_path="$PHP_FPM_PID"
475+ fi
476+ php_fpm_pid_dir=`dirname $php_fpm_pid_path`
477+
478+ if test -z "$PHP_FPM_USER" -o "$PHP_FPM_USER" = "yes" -o "$PHP_FPM_USER" = "no"; then
479+ php_fpm_user="nobody"
480+ else
481+ php_fpm_user="$PHP_FPM_USER"
482+ fi
483+
484+ if test -z "$PHP_FPM_GROUP" -o "$PHP_FPM_GROUP" = "yes" -o "$PHP_FPM_GROUP" = "no"; then
485+ php_fpm_group="nobody"
486+ else
487+ php_fpm_group="$PHP_FPM_GROUP"
488+ fi
489+
490+
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)
508+
509+
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])
527+
528+])
529+
530+
531+AC_DEFUN([AC_FPM_OUTPUT],
532+[
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)
537+])
538+
539+
540+AC_DEFUN([AC_FPM_CONF],
541+[
542+ AC_FPM_ARGS
543+ AC_FPM_VARS
544+ AC_FPM_OUTPUT
545+])
546+
547diff -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
550@@ -0,0 +1,250 @@
551+dnl @synopsis AC_LIB_EVENT([MINIMUM-VERSION],[REQUIRED-VERSION])
552+dnl
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.
556+dnl
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.
561+dnl
562+dnl This macro requires that #include <sys/types.h> works and defines u_char.
563+dnl
564+dnl This macro calls:
565+dnl AC_SUBST(LIBEVENT_CFLAGS)
566+dnl AC_SUBST(LIBEVENT_LIBS)
567+dnl
568+dnl And (if libevent is found):
569+dnl AC_DEFINE(HAVE_LIBEVENT)
570+dnl
571+dnl It also leaves the shell variables "success" and "ac_have_libevent"
572+dnl set to "yes" or "no".
573+dnl
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").
576+dnl
577+dnl @category InstalledPackages
578+dnl @category C
579+dnl @version 2007-09-12
580+dnl @license AllPermissive
581+dnl
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.
586+
587+AC_DEFUN([AC_LIB_EVENT_DO_CHECK],
588+[
589+# Save our flags.
590+CPPFLAGS_SAVED="$CPPFLAGS"
591+LDFLAGS_SAVED="$LDFLAGS"
592+LIBS_SAVED="$LIBS"
593+LD_LIBRARY_PATH_SAVED="$LD_LIBRARY_PATH"
594+
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"
600+else
601+ LIBEVENT_CPPFLAGS=""
602+ LIBEVENT_LDFLAGS=""
603+fi
604+
605+# Required flag for libevent.
606+LIBEVENT_LIBS="-levent"
607+
608+# Prepare the environment for compilation.
609+CPPFLAGS="$CPPFLAGS $LIBEVENT_CPPFLAGS"
610+LDFLAGS="$LDFLAGS $LIBEVENT_LDFLAGS"
611+LIBS="$LIBS $LIBEVENT_LIBS"
612+export CPPFLAGS
613+export LDFLAGS
614+export LIBS
615+export LD_LIBRARY_PATH
616+
617+success=no
618+
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.
624+AC_TRY_RUN([
625+#include <sys/types.h>
626+#include <event.h>
627+
628+int main(int argc, char *argv[])
629+{
630+ const char* lib_version = event_get_version();
631+ const char* wnt_version = "$WANT_LIBEVENT_VERSION";
632+ for (;;) {
633+ /* If we reached the end of the want version. We have it. */
634+ if (*wnt_version == '\0' || *wnt_version == '-') {
635+ return 0;
636+ }
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 == '-') {
640+ return 1;
641+ }
642+
643+ /* In the 1.4 version numbering style, if there are more digits */
644+ /* in one version than the other, that one is higher. */
645+ int lib_digits;
646+ for (lib_digits = 0;
647+ lib_version[lib_digits] >= '0' &&
648+ lib_version[lib_digits] <= '9';
649+ lib_digits++)
650+ ;
651+ int wnt_digits;
652+ for (wnt_digits = 0;
653+ wnt_version[wnt_digits] >= '0' &&
654+ wnt_version[wnt_digits] <= '9';
655+ wnt_digits++)
656+ ;
657+ if (lib_digits > wnt_digits) {
658+ return 0;
659+ }
660+ if (lib_digits < wnt_digits) {
661+ return 1;
662+ }
663+ /* If we have greater than what we want. We have it. */
664+ if (*lib_version > *wnt_version) {
665+ return 0;
666+ }
667+ /* If we have less, we don't. */
668+ if (*lib_version < *wnt_version) {
669+ return 1;
670+ }
671+ lib_version++;
672+ wnt_version++;
673+ }
674+ return 0;
675+}
676+],[
677+success=yes
678+])
679+
680+# Restore flags.
681+LIBEVENT_LIBS=""
682+CPPFLAGS="$CPPFLAGS_SAVED"
683+LDFLAGS="$LDFLAGS_SAVED"
684+LIBS="$LIBS_SAVED"
685+LD_LIBRARY_PATH="$LD_LIBRARY_PATH_SAVED"
686+])
687+
688+AC_DEFUN([AC_LIB_EVENT],
689+[
690+
691+PHP_ARG_WITH(libevent,,
692+[ --with-libevent[=PATH] Path to the libevent, needed for fpm SAPI [/usr/local]], yes, yes)
693+
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)
697+
698+ # Default library search paths ($sys_lib_search_path_spec)
699+ AC_LIBTOOL_SYS_DYNAMIC_LINKER
700+
701+ libevent_prefix=$ac_default_prefix
702+ if test $prefix != "NONE" -a $prefix != "" -a $prefix != "no" ; then
703+ libevent_prefix=$prefix
704+ fi
705+
706+ if test "$PHP_LIBEVENT" = "yes"; then
707+ PHP_LIBEVENT=$libevent_prefix
708+ fi
709+
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
715+ break;
716+ fi
717+ done
718+ if test "$success" = "no"; then
719+
720+ AC_MSG_RESULT(no)
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.])
724+
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
730+ break;
731+ fi
732+ done
733+ if test "$success" = "no"; then
734+ AC_MSG_RESULT(no)
735+ LIBEVENT_LIBS=""
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.])
741+ fi
742+ fi
743+
744+ if test "$ext_shared" = "yes"; then
745+ if test -n "$ac_libevent_path"; then
746+ LIBEVENT_LIBS="-L$ac_libevent_path/lib -levent"
747+ else
748+ LIBEVENT_LIBS="-levent"
749+ fi
750+ else
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"
755+ fi
756+ if test -z "$LIBEVENT_LIBS"; then
757+ AC_MSG_RESULT(no)
758+ AC_MSG_WARN([libevent.a could not be found. We looked in:])
759+ AC_MSG_WARN([\"$ac_libevent_path\"])
760+ fi
761+ else
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"
765+ break;
766+ fi
767+ done
768+ if test -z "$LIBEVENT_LIBS"; then
769+ AC_MSG_RESULT(no)
770+ AC_MSG_WARN([libevent.a could not be found. We looked in:])
771+ AC_MSG_WARN([\"$sys_lib_search_path_spec\"])
772+ fi
773+ fi
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.])
780+ fi
781+ fi
782+
783+ if test "$success" = "yes" ; then
784+ AC_MSG_RESULT(yes)
785+ ac_have_libevent=yes
786+ AC_DEFINE(HAVE_LIBEVENT, 1, [define if libevent is available])
787+ fi
788+
789+ if test -n "$ac_libevent_path"; then
790+ LIBEVENT_CFLAGS="-I$ac_libevent_path/include"
791+ fi
792+
793+ AC_SUBST(LIBEVENT_CFLAGS)
794+ AC_SUBST(LIBEVENT_LIBS)
795+
796+else
797+ AC_MSG_ERROR([FPM Requires Libevent. You must build this target --with-libevent. Stop.])
798+fi
799+
800+])
801diff -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
804@@ -0,0 +1,61 @@
805+fpm: $(SAPI_FPM_PATH)
806+
807+$(SAPI_FPM_PATH): $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(SAPI_EXTRA_DEPS)
808+ $(BUILD_FPM)
809+
810+install: install-fpm
811+
812+install-fpm: all
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)
818+
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) || :
822+
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 || :
826+
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) || :
830+
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
834+
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) || :
839+
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 || :
844+
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 || :
849+
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 || :
854+
855+ @echo ""
856+ @echo "*** FPM Installation complete. ***"
857+ @echo ""
858+
859+ @test "$(php_fpm_init)" && \
860+ echo "run:" && \
861+ echo "\`update-rc.d $(php_fpm_init) defaults; invoke-rc.d $(php_fpm_init) start\`" && \
862+ echo "" && \
863+ echo "or system equivalent to start the $(php_fpm_init) service." && \
864+ echo "" || :
865+
866diff -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
869@@ -0,0 +1,1660 @@
870+/*
871+ +----------------------------------------------------------------------+
872+ | PHP Version 5 |
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+ +----------------------------------------------------------------------+
891+*/
892+
893+/* $Id$ */
894+
895+#include <php.h>
896+#include <php_globals.h>
897+#include <php_variables.h>
898+#include <zend_modules.h>
899+
900+#include <SAPI.h>
901+
902+#include <stdio.h>
903+
904+#ifdef PHP_WIN32
905+#include "win32/time.h"
906+#include "win32/signal.h"
907+#include <process.h>
908+#endif
909+#if HAVE_SYS_TIME_H
910+#include <sys/time.h>
911+#endif
912+#if HAVE_UNISTD_H
913+#include <unistd.h>
914+#endif
915+#if HAVE_SIGNAL_H
916+#include <signal.h>
917+#endif
918+#if HAVE_SETLOCALE
919+#include <locale.h>
920+#endif
921+#if HAVE_SYS_TYPES_H
922+#include <sys/types.h>
923+#endif
924+#if HAVE_SYS_WAIT_H
925+#include <sys/wait.h>
926+#endif
927+#if HAVE_FCNTL_H
928+#include <fcntl.h>
929+#endif
930+#include <zend.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>
936+#ifdef PHP_WIN32
937+#include <io.h>
938+#include <fcntl.h>
939+#include "win32/php_registry.h"
940+#endif
941+
942+#ifdef __riscos__
943+#include <unixlib/local.h>
944+int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS;
945+#endif
946+
947+#include "zend_compile.h"
948+#include "zend_execute.h"
949+#include "zend_highlight.h"
950+#include "zend_indent.h"
951+
952+#include "php_getopt.h"
953+
954+#include "fastcgi.h"
955+
956+#ifdef FPM_AUTOCONFIG_H
957+#include <fpm_autoconfig.h>
958+#else
959+#include <php_config.h>
960+#endif
961+#include <fpm/fpm.h>
962+#include <fpm/fpm_request.h>
963+
964+
965+static void (*php_php_import_environment_variables)(zval *array_ptr TSRMLS_DC);
966+
967+static int parent = 1;
968+
969+static int request_body_fd;
970+
971+static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC);
972+
973+static char *php_optarg = NULL;
974+static int php_optind = 1;
975+static zend_module_entry cgi_module_entry;
976+
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"},
984+ {'f', 1, "file"},
985+ {'h', 0, "help"},
986+ {'i', 0, "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"},
993+ {'w', 0, "strip"},
994+ {'?', 0, "usage"},/* help alias (both '?' and 'usage') */
995+ {'v', 0, "version"},
996+ {'x', 0, "fpm"},
997+ {'y', 1, "fpm-config"},
998+ {'z', 1, "zend-extension"},
999+ {'-', 0, NULL} /* end of args */
1000+};
1001+
1002+typedef struct _php_cgi_globals_struct {
1003+ zend_bool rfc2616_headers;
1004+ zend_bool nph;
1005+ zend_bool check_shebang_line;
1006+#if ENABLE_PATHINFO_CHECK
1007+ zend_bool fix_pathinfo;
1008+#endif
1009+ zend_bool fcgi_logging;
1010+# ifdef PHP_WIN32
1011+ zend_bool impersonate;
1012+# endif
1013+ char *error_header;
1014+} php_cgi_globals_struct;
1015+
1016+#ifdef ZTS
1017+static int php_cgi_globals_id;
1018+#define CGIG(v) TSRMG(php_cgi_globals_id, php_cgi_globals_struct *, v)
1019+#else
1020+static php_cgi_globals_struct php_cgi_globals;
1021+#define CGIG(v) (php_cgi_globals.v)
1022+#endif
1023+
1024+#ifdef PHP_WIN32
1025+#define TRANSLATE_SLASHES(path) \
1026+ { \
1027+ char *tmp = path; \
1028+ while (*tmp) { \
1029+ if (*tmp == '\\') *tmp = '/'; \
1030+ tmp++; \
1031+ } \
1032+ }
1033+#else
1034+#define TRANSLATE_SLASHES(path)
1035+#endif
1036+
1037+static int print_module_info(zend_module_entry *module, void *arg TSRMLS_DC)
1038+{
1039+ php_printf("%s\n", module->name);
1040+ return 0;
1041+}
1042+
1043+static int module_name_cmp(const void *a, const void *b TSRMLS_DC)
1044+{
1045+ Bucket *f = *((Bucket **) a);
1046+ Bucket *s = *((Bucket **) b);
1047+
1048+ return strcasecmp(((zend_module_entry *)f->pData)->name,
1049+ ((zend_module_entry *)s->pData)->name);
1050+}
1051+
1052+static void print_modules(TSRMLS_D)
1053+{
1054+ HashTable sorted_registry;
1055+ zend_module_entry tmp;
1056+
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);
1062+}
1063+
1064+static int print_extension_info(zend_extension *ext, void *arg TSRMLS_DC)
1065+{
1066+ php_printf("%s\n", ext->name);
1067+ return 0;
1068+}
1069+
1070+static int extension_name_cmp(const zend_llist_element **f,
1071+ const zend_llist_element **s TSRMLS_DC)
1072+{
1073+ return strcmp(((zend_extension *)(*f)->data)->name,
1074+ ((zend_extension *)(*s)->data)->name);
1075+}
1076+
1077+static void print_extensions(TSRMLS_D)
1078+{
1079+ zend_llist sorted_exts;
1080+
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);
1086+}
1087+
1088+#ifndef STDOUT_FILENO
1089+#define STDOUT_FILENO 1
1090+#endif
1091+
1092+static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC)
1093+{
1094+ long ret;
1095+
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);
1099+ if (ret <= 0) {
1100+ return 0;
1101+ }
1102+ return ret;
1103+ }
1104+ ret = write(STDOUT_FILENO, str, str_length);
1105+ if (ret <= 0) return 0;
1106+ return ret;
1107+}
1108+
1109+static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
1110+{
1111+ const char *ptr = str;
1112+ uint remaining = str_length;
1113+ size_t ret;
1114+
1115+ while (remaining > 0) {
1116+ ret = sapi_cgibin_single_write(ptr, remaining TSRMLS_CC);
1117+ if (!ret) {
1118+ php_handle_aborted_connection();
1119+ return str_length - remaining;
1120+ }
1121+ ptr += ret;
1122+ remaining -= ret;
1123+ }
1124+
1125+ return str_length;
1126+}
1127+
1128+
1129+static void sapi_cgibin_flush(void *server_context)
1130+{
1131+ if (fcgi_is_fastcgi()) {
1132+ fcgi_request *request = (fcgi_request*) server_context;
1133+ if (
1134+#ifndef PHP_WIN32
1135+ !parent &&
1136+#endif
1137+ request && !fcgi_flush(request, 0)) {
1138+ php_handle_aborted_connection();
1139+ }
1140+ return;
1141+ }
1142+ if (fflush(stdout) == EOF) {
1143+ php_handle_aborted_connection();
1144+ }
1145+}
1146+
1147+#define SAPI_CGI_MAX_HEADER_LENGTH 1024
1148+
1149+typedef struct _http_error {
1150+ int code;
1151+ const char* msg;
1152+} http_error;
1153+
1154+static const http_error http_error_codes[] = {
1155+ {100, "Continue"},
1156+ {101, "Switching Protocols"},
1157+ {200, "OK"},
1158+ {201, "Created"},
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"},
1180+ {410, "Gone"},
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"},
1192+ {0, NULL}
1193+};
1194+
1195+static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
1196+{
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;
1202+
1203+ if (SG(request_info).no_headers == 1) {
1204+ return SAPI_HEADER_SENT_SUCCESSFULLY;
1205+ }
1206+
1207+ if (CGIG(nph) || SG(sapi_headers).http_response_code != 200)
1208+ {
1209+ int len;
1210+ zend_bool has_status = 0;
1211+
1212+ if (CGIG(rfc2616_headers) && SG(sapi_headers).http_status_line) {
1213+ char *s;
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));
1217+ }
1218+
1219+ if (len > SAPI_CGI_MAX_HEADER_LENGTH) {
1220+ len = SAPI_CGI_MAX_HEADER_LENGTH;
1221+ }
1222+
1223+ } else {
1224+ char *s;
1225+
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));
1232+ } else {
1233+ h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
1234+ while (h) {
1235+ if (h->header_len > sizeof("Status:")-1 &&
1236+ strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0) {
1237+ has_status = 1;
1238+ break;
1239+ }
1240+ h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
1241+ }
1242+ if (!has_status) {
1243+ http_error *err = (http_error*)http_error_codes;
1244+
1245+ while (err->code != 0) {
1246+ if (err->code == SG(sapi_headers).http_response_code) {
1247+ break;
1248+ }
1249+ err++;
1250+ }
1251+ if (err->msg) {
1252+ len = slprintf(buf, sizeof(buf), "Status: %d %s\r\n", SG(sapi_headers).http_response_code, err->msg);
1253+ } else {
1254+ len = slprintf(buf, sizeof(buf), "Status: %d\r\n", SG(sapi_headers).http_response_code);
1255+ }
1256+ }
1257+ }
1258+ }
1259+ if (!has_status) {
1260+ PHPWRITE_H(buf, len);
1261+ ignore_status = 1;
1262+ }
1263+ }
1264+
1265+ h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
1266+ while (h) {
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);
1275+ }
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);
1279+ continue;
1280+ } else {
1281+ PHPWRITE_H(h->header, h->header_len);
1282+ PHPWRITE_H("\r\n", 2);
1283+ }
1284+ }
1285+ h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
1286+ }
1287+ PHPWRITE_H("\r\n", 2);
1288+
1289+ return SAPI_HEADER_SENT_SUCCESSFULLY;
1290+}
1291+
1292+
1293+static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
1294+{
1295+ int read_bytes=0, tmp_read_bytes;
1296+
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);
1301+
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);
1305+
1306+ if (request_body_filename && *request_body_filename) {
1307+ request_body_fd = open(request_body_filename, O_RDONLY);
1308+
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);
1312+ return 0;
1313+ }
1314+ }
1315+ }
1316+
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);
1320+ } else {
1321+ tmp_read_bytes = read(request_body_fd, buffer + read_bytes, count_bytes - read_bytes);
1322+ }
1323+ } else {
1324+ tmp_read_bytes = read(0, buffer + read_bytes, count_bytes - read_bytes);
1325+ }
1326+
1327+ if (tmp_read_bytes <= 0) {
1328+ break;
1329+ }
1330+ read_bytes += tmp_read_bytes;
1331+ }
1332+ return read_bytes;
1333+}
1334+
1335+static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
1336+{
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);
1344+ }
1345+ /* if cgi, or fastcgi and not found in fcgi env
1346+ check the regular environment */
1347+ return getenv(name);
1348+}
1349+
1350+static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC)
1351+{
1352+ int name_len;
1353+#if !HAVE_SETENV || !HAVE_UNSETENV
1354+ int len;
1355+ char *buf;
1356+#endif
1357+
1358+ if (!name) {
1359+ return NULL;
1360+ }
1361+ name_len = strlen(name);
1362+
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);
1370+ }
1371+#if HAVE_SETENV
1372+ if (value) {
1373+ setenv(name, value, 1);
1374+ }
1375+#endif
1376+#if HAVE_UNSETENV
1377+ if (!value) {
1378+ unsetenv(name);
1379+ }
1380+#endif
1381+
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
1386+ it for 5.0
1387+ */
1388+ len = name_len + (value ? strlen(value) : 0) + sizeof("=") + 2;
1389+ buf = (char *) malloc(len);
1390+ if (buf == NULL) {
1391+ return getenv(name);
1392+ }
1393+#endif
1394+#if !HAVE_SETENV
1395+ if (value) {
1396+ len = slprintf(buf, len - 1, "%s=%s", name, value);
1397+ putenv(buf);
1398+ }
1399+#endif
1400+#if !HAVE_UNSETENV
1401+ if (!value) {
1402+ len = slprintf(buf, len - 1, "%s=", name);
1403+ putenv(buf);
1404+ }
1405+#endif
1406+ return getenv(name);
1407+}
1408+
1409+static char *sapi_cgi_read_cookies(TSRMLS_D)
1410+{
1411+ return sapi_cgibin_getenv((char *) "HTTP_COOKIE", sizeof("HTTP_COOKIE")-1 TSRMLS_CC);
1412+}
1413+
1414+void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
1415+{
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);
1424+ return;
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);
1433+ return;
1434+ }
1435+
1436+ /* call php's original import as a catch-all */
1437+ php_php_import_environment_variables(array_ptr TSRMLS_CC);
1438+
1439+ if (fcgi_is_fastcgi()) {
1440+ fcgi_request *request = (fcgi_request*) SG(server_context);
1441+ HashPosition pos;
1442+ int magic_quotes_gpc = PG(magic_quotes_gpc);
1443+ char *var, **val;
1444+ uint var_len;
1445+ ulong idx;
1446+ int filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER;
1447+
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);
1457+ }
1458+ }
1459+ PG(magic_quotes_gpc) = magic_quotes_gpc;
1460+ }
1461+}
1462+
1463+static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
1464+{
1465+ unsigned int php_self_len;
1466+ char *php_self;
1467+
1468+ /* In CGI mode, we consider the environment to be a part of the server
1469+ * variables
1470+ */
1471+ php_import_environment_variables(track_vars_array TSRMLS_CC);
1472+
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;
1479+
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);
1484+ }
1485+ if (path_info) {
1486+ memcpy(php_self + script_name_len, path_info, path_info_len + 1);
1487+ }
1488+
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);
1492+ }
1493+ efree(php_self);
1494+ return;
1495+ }
1496+#endif
1497+
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);
1502+ }
1503+}
1504+
1505+static void sapi_cgi_log_message(char *message)
1506+{
1507+ TSRMLS_FETCH();
1508+
1509+ if (fcgi_is_fastcgi() && CGIG(fcgi_logging)) {
1510+ fcgi_request *request;
1511+
1512+ request = (fcgi_request*) SG(server_context);
1513+ if (request) {
1514+ int len = strlen(message);
1515+ char *buf = malloc(len+2);
1516+
1517+ memcpy(buf, message, len);
1518+ memcpy(buf + len, "\n", sizeof("\n"));
1519+ fcgi_write(request, FCGI_STDERR, buf, len+1);
1520+ free(buf);
1521+ } else {
1522+ fprintf(stderr, "%s\n", message);
1523+ }
1524+ /* ignore return code */
1525+ } else
1526+ fprintf(stderr, "%s\n", message);
1527+}
1528+
1529+static int sapi_cgi_deactivate(TSRMLS_D)
1530+{
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
1534+ FastCGI.
1535+ */
1536+ if (SG(sapi_started)) {
1537+ sapi_cgibin_flush(SG(server_context));
1538+ }
1539+ return SUCCESS;
1540+}
1541+
1542+static int php_cgi_startup(sapi_module_struct *sapi_module)
1543+{
1544+ if (php_module_startup(sapi_module, &cgi_module_entry, 1) == FAILURE) {
1545+ return FAILURE;
1546+ }
1547+ return SUCCESS;
1548+}
1549+
1550+
1551+/* {{{ sapi_module_struct cgi_sapi_module
1552+ */
1553+static sapi_module_struct cgi_sapi_module = {
1554+ "cgi-fcgi", /* name */
1555+ "CGI/FastCGI", /* pretty name */
1556+
1557+ php_cgi_startup, /* startup */
1558+ php_module_shutdown_wrapper, /* shutdown */
1559+
1560+ NULL, /* activate */
1561+ sapi_cgi_deactivate, /* deactivate */
1562+
1563+ sapi_cgibin_ub_write, /* unbuffered write */
1564+ sapi_cgibin_flush, /* flush */
1565+ NULL, /* get uid */
1566+ sapi_cgibin_getenv, /* getenv */
1567+
1568+ php_error, /* error handler */
1569+
1570+ NULL, /* header handler */
1571+ sapi_cgi_send_headers, /* send headers handler */
1572+ NULL, /* send header handler */
1573+
1574+ sapi_cgi_read_post, /* read POST data */
1575+ sapi_cgi_read_cookies, /* read Cookies */
1576+
1577+ sapi_cgi_register_variables, /* register server variables */
1578+ sapi_cgi_log_message, /* Log message */
1579+ NULL, /* Get request time */
1580+
1581+ STANDARD_SAPI_MODULE_PROPERTIES
1582+};
1583+/* }}} */
1584+
1585+/* {{{ php_cgi_usage
1586+ */
1587+static void php_cgi_usage(char *argv0)
1588+{
1589+ char *prog;
1590+
1591+ prog = strrchr(argv0, '/');
1592+ if (prog) {
1593+ prog++;
1594+ } else {
1595+ prog = "php";
1596+ }
1597+
1598+ php_printf("Usage: %s [options]\n"
1599+ "\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"
1605+ " -h This help\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"
1612+ ,
1613+ prog);
1614+}
1615+/* }}} */
1616+
1617+/* {{{ is_valid_path
1618+ *
1619+ * some server configurations allow '..' to slip through in the
1620+ * translated path. We'll just refuse to handle such a path.
1621+ */
1622+static int is_valid_path(const char *path)
1623+{
1624+ const char *p;
1625+
1626+ if (!path) {
1627+ return 0;
1628+ }
1629+ p = strstr(path, "..");
1630+ if (p) {
1631+ if ((p == path || IS_SLASH(*(p-1))) &&
1632+ (*(p+2) == 0 || IS_SLASH(*(p+2)))) {
1633+ return 0;
1634+ }
1635+ while (1) {
1636+ p = strstr(p+1, "..");
1637+ if (!p) {
1638+ break;
1639+ }
1640+ if (IS_SLASH(*(p-1)) &&
1641+ (*(p+2) == 0 || IS_SLASH(*(p+2)))) {
1642+ return 0;
1643+ }
1644+ }
1645+ }
1646+ return 1;
1647+}
1648+/* }}} */
1649+
1650+/* {{{ init_request_info
1651+
1652+ initializes request_info structure
1653+
1654+ specificly in this section we handle proper translations
1655+ for:
1656+
1657+ PATH_INFO
1658+ derived from the portion of the URI path following
1659+ the script name but preceding any query data
1660+ may be empty
1661+
1662+ PATH_TRANSLATED
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
1667+
1668+ empty if PATH_INFO is empty
1669+
1670+ The env var PATH_TRANSLATED **IS DIFFERENT** than the
1671+ request_info.path_translated variable, the latter should
1672+ match SCRIPT_FILENAME instead.
1673+
1674+ SCRIPT_NAME
1675+ set to a URL path that could identify the CGI script
1676+ rather than the interpreter. PHP_SELF is set to this.
1677+
1678+ REQUEST_URI
1679+ uri section following the domain:port part of a URI
1680+
1681+ SCRIPT_FILENAME
1682+ The virtual-to-physical translation of SCRIPT_NAME (as per
1683+ PATH_TRANSLATED)
1684+
1685+ These settings are documented at
1686+ http://cgi-spec.golux.com/
1687+
1688+
1689+ Based on the following URL request:
1690+
1691+ http://localhost/info.php/test?a=b
1692+
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):
1696+
1697+ PATH_INFO=/test
1698+ PATH_TRANSLATED=/docroot/test
1699+ SCRIPT_NAME=/info.php
1700+ REQUEST_URI=/info.php/test?a=b
1701+ SCRIPT_FILENAME=/docroot/info.php
1702+ QUERY_STRING=a=b
1703+
1704+ but what we get is (cgi/mod_fastcgi under apache):
1705+
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)
1711+ QUERY_STRING=a=b
1712+
1713+ Comments in the code below refer to using the above URL in a request
1714+
1715+ */
1716+static void init_request_info(TSRMLS_D)
1717+{
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;
1721+
1722+#if !DISCARD_PATH
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;
1728+ }
1729+#endif
1730+
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;
1740+
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) {
1746+ const char *auth;
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
1752+ struct stat st;
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;
1756+
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 &&
1761+ env_path_info &&
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;
1768+ }
1769+ env_path_info = _sapi_cgibin_putenv("PATH_INFO", env_path_info TSRMLS_CC);
1770+ }
1771+
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;
1778+
1779+ if (!env_document_root && PG(doc_root)) {
1780+ env_document_root = _sapi_cgibin_putenv("DOCUMENT_ROOT", PG(doc_root) TSRMLS_CC);
1781+ /* fix docroot */
1782+ TRANSLATE_SLASHES(env_document_root);
1783+ }
1784+
1785+ if (env_path_translated != NULL && env_redirect_url != NULL) {
1786+ /*
1787+ pretty much apache specific. If we have a redirect_url
1788+ then our script_filename and script_name point to the
1789+ php executable
1790+ */
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;
1794+ }
1795+
1796+#ifdef __riscos__
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);
1800+#endif
1801+
1802+ /*
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
1806+ */
1807+ if (script_path_translated &&
1808+ (script_path_translated_len = strlen(script_path_translated)) > 0 &&
1809+ (script_path_translated[script_path_translated_len-1] == '/' ||
1810+#ifdef PHP_WIN32
1811+ script_path_translated[script_path_translated_len-1] == '\\' ||
1812+#endif
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;
1816+ char *ptr;
1817+
1818+ while ((ptr = strrchr(pt, '/')) || (ptr = strrchr(pt, '\\'))) {
1819+ *ptr = 0;
1820+ if (stat(pt, &st) == 0 && S_ISREG(st.st_mode)) {
1821+ /*
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
1825+ * accordingly
1826+ *
1827+ * we now have the makings of
1828+ * PATH_INFO=/test
1829+ * SCRIPT_FILENAME=/docroot/info.php
1830+ *
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
1835+ */
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;
1839+
1840+ if (orig_path_info != path_info) {
1841+ if (orig_path_info) {
1842+ char old;
1843+
1844+ _sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
1845+ old = path_info[0];
1846+ path_info[0] = 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);
1851+ }
1852+ SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_path_info TSRMLS_CC);
1853+ } else {
1854+ SG(request_info).request_uri = orig_script_name;
1855+ }
1856+ path_info[0] = old;
1857+ }
1858+ env_path_info = _sapi_cgibin_putenv("PATH_INFO", path_info TSRMLS_CC);
1859+ }
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);
1864+ }
1865+ script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", pt TSRMLS_CC);
1866+ }
1867+ TRANSLATE_SLASHES(pt);
1868+
1869+ /* figure out docroot
1870+ SCRIPT_FILENAME minus SCRIPT_NAME
1871+ */
1872+
1873+ if (env_document_root) {
1874+ int l = strlen(env_document_root);
1875+ int path_translated_len = 0;
1876+ char *path_translated = NULL;
1877+
1878+ if (l && env_document_root[l - 1] == '/') {
1879+ --l;
1880+ }
1881+
1882+ /* we have docroot, so we should have:
1883+ * DOCUMENT_ROOT=/docroot
1884+ * SCRIPT_FILENAME=/docroot/info.php
1885+ */
1886+
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));
1893+ }
1894+ path_translated[path_translated_len] = '\0';
1895+ if (orig_path_translated) {
1896+ _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
1897+ }
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)
1902+ ) {
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;
1907+
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);
1912+ }
1913+ path_translated[path_translated_len] = '\0';
1914+ if (orig_path_translated) {
1915+ _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
1916+ }
1917+ env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
1918+ efree(path_translated);
1919+ }
1920+ break;
1921+ }
1922+ }
1923+ if (!ptr) {
1924+ /*
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.
1928+ */
1929+ if (orig_script_filename) {
1930+ _sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
1931+ }
1932+ script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", NULL TSRMLS_CC);
1933+ SG(sapi_headers).http_response_code = 404;
1934+ }
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);
1940+ }
1941+ SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
1942+ } else {
1943+ SG(request_info).request_uri = orig_script_name;
1944+ }
1945+ }
1946+ if (pt) {
1947+ efree(pt);
1948+ }
1949+ if (is_valid_path(script_path_translated)) {
1950+ SG(request_info).path_translated = estrdup(script_path_translated);
1951+ }
1952+ } else {
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);
1959+ }
1960+ script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", script_path_translated TSRMLS_CC);
1961+ }
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);
1966+ }
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);
1970+ }
1971+ }
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);
1975+ }
1976+ SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
1977+ } else {
1978+ SG(request_info).request_uri = env_script_name;
1979+ }
1980+ if (is_valid_path(script_path_translated)) {
1981+ SG(request_info).path_translated = estrdup(script_path_translated);
1982+ }
1983+ free(real_path);
1984+ }
1985+ } else {
1986+#endif
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;
1990+ } else {
1991+ SG(request_info).request_uri = env_script_name;
1992+ }
1993+#if !DISCARD_PATH
1994+ if (env_path_translated) {
1995+ script_path_translated = env_path_translated;
1996+ }
1997+#endif
1998+ if (is_valid_path(script_path_translated)) {
1999+ SG(request_info).path_translated = estrdup(script_path_translated);
2000+ }
2001+#if ENABLE_PATHINFO_CHECK
2002+ }
2003+#endif
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);
2009+
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);
2013+ }
2014+}
2015+/* }}} */
2016+
2017+
2018+PHP_INI_BEGIN()
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)
2024+#endif
2025+ STD_PHP_INI_ENTRY("fastcgi.logging", "1", PHP_INI_SYSTEM, OnUpdateBool, fcgi_logging, php_cgi_globals_struct, php_cgi_globals)
2026+# ifdef PHP_WIN32
2027+ STD_PHP_INI_ENTRY("fastcgi.impersonate", "0", PHP_INI_SYSTEM, OnUpdateBool, impersonate, php_cgi_globals_struct, php_cgi_globals)
2028+# endif
2029+ STD_PHP_INI_ENTRY("fastcgi.error_header", NULL, PHP_INI_SYSTEM, OnUpdateString, error_header, php_cgi_globals_struct, php_cgi_globals)
2030+PHP_INI_END()
2031+
2032+/* {{{ php_cgi_globals_ctor
2033+ */
2034+static void php_cgi_globals_ctor(php_cgi_globals_struct *php_cgi_globals TSRMLS_DC)
2035+{
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;
2041+#endif
2042+ php_cgi_globals->fcgi_logging = 1;
2043+# ifdef PHP_WIN32
2044+ php_cgi_globals->impersonate = 0;
2045+# endif
2046+ php_cgi_globals->error_header = NULL;
2047+}
2048+/* }}} */
2049+
2050+/* {{{ PHP_MINIT_FUNCTION
2051+ */
2052+static PHP_MINIT_FUNCTION(cgi)
2053+{
2054+#ifdef ZTS
2055+ ts_allocate_id(&php_cgi_globals_id, sizeof(php_cgi_globals_struct), (ts_allocate_ctor) php_cgi_globals_ctor, NULL);
2056+#else
2057+ php_cgi_globals_ctor(&php_cgi_globals TSRMLS_CC);
2058+#endif
2059+ REGISTER_INI_ENTRIES();
2060+ return SUCCESS;
2061+}
2062+/* }}} */
2063+
2064+/* {{{ PHP_MSHUTDOWN_FUNCTION
2065+ */
2066+static PHP_MSHUTDOWN_FUNCTION(cgi)
2067+{
2068+ UNREGISTER_INI_ENTRIES();
2069+ return SUCCESS;
2070+}
2071+/* }}} */
2072+
2073+/* {{{ PHP_MINFO_FUNCTION
2074+ */
2075+static PHP_MINFO_FUNCTION(cgi)
2076+{
2077+ DISPLAY_INI_ENTRIES();
2078+
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();
2083+
2084+}
2085+/* }}} */
2086+
2087+PHP_FUNCTION(fastcgi_finish_request)
2088+{
2089+ fcgi_request *request = (fcgi_request*) SG(server_context);
2090+
2091+ if (fcgi_is_fastcgi() && request->fd >= 0) {
2092+
2093+ php_end_ob_buffers(1 TSRMLS_CC);
2094+ php_header(TSRMLS_C);
2095+
2096+ fcgi_flush(request, 1);
2097+ fcgi_close(request, 0, 0);
2098+ RETURN_TRUE;
2099+ }
2100+
2101+ RETURN_FALSE;
2102+
2103+}
2104+
2105+function_entry cgi_fcgi_sapi_functions[] = {
2106+ PHP_FE(fastcgi_finish_request, NULL)
2107+ {NULL, NULL, NULL}
2108+};
2109+
2110+static zend_module_entry cgi_module_entry = {
2111+ STANDARD_MODULE_HEADER,
2112+ "cgi-fcgi",
2113+ cgi_fcgi_sapi_functions,
2114+ PHP_MINIT(cgi),
2115+ PHP_MSHUTDOWN(cgi),
2116+ NULL,
2117+ NULL,
2118+ PHP_MINFO(cgi),
2119+ NO_VERSION_YET,
2120+ STANDARD_MODULE_PROPERTIES
2121+};
2122+
2123+/* {{{ main
2124+ */
2125+int main(int argc, char *argv[])
2126+{
2127+ int free_query_string = 0;
2128+ int exit_status = SUCCESS;
2129+ int c;
2130+ zend_file_handle file_handle = {};
2131+ int retval;
2132+/* temporary locals */
2133+ int orig_optind = php_optind;
2134+ char *orig_optarg = php_optarg;
2135+ int ini_entries_len = 0;
2136+
2137+/* end of temporary locals */
2138+#ifdef ZTS
2139+ void ***tsrm_ls;
2140+#endif
2141+
2142+ int max_requests = 500;
2143+ int requests = 0;
2144+ int fcgi_fd = 0;
2145+ fcgi_request request;
2146+ char *fpm_config = NULL;
2147+
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
2155+ 20000419 */
2156+#endif
2157+#endif
2158+
2159+#ifdef ZTS
2160+ tsrm_startup(1, 1, 0, NULL);
2161+ tsrm_ls = ts_resource(0);
2162+#endif
2163+
2164+ sapi_startup(&cgi_sapi_module);
2165+ cgi_sapi_module.php_ini_path_override = NULL;
2166+
2167+#ifdef PHP_WIN32
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 */
2172+#endif
2173+
2174+ while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0)) != -1) {
2175+ switch (c) {
2176+
2177+ case 'c':
2178+ if (cgi_sapi_module.php_ini_path_override) {
2179+ free(cgi_sapi_module.php_ini_path_override);
2180+ }
2181+ cgi_sapi_module.php_ini_path_override = strdup(php_optarg);
2182+ break;
2183+
2184+ case 'n':
2185+ cgi_sapi_module.php_ini_ignore = 1;
2186+ break;
2187+
2188+ case 'C': /* don't chdir to the script directory */
2189+ SG(options) |= SAPI_OPTION_NO_CHDIR;
2190+ break;
2191+
2192+ case 'd': {
2193+ /* define ini entries on command line */
2194+ int len = strlen(php_optarg);
2195+ char *val;
2196+
2197+ if ((val = strchr(php_optarg, '='))) {
2198+ val++;
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;
2209+ } else {
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;
2214+ }
2215+ } else {
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;
2220+ }
2221+ break;
2222+ }
2223+
2224+ case 'y':
2225+ fpm_config = php_optarg;
2226+ break;
2227+
2228+ case 'e': /* enable extended info output */
2229+ /* CG(extended_info) = 1; */ /* 5_2 */
2230+ CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO; /* 5_3 */
2231+ break;
2232+
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);
2242+ php_printf("\n");
2243+ php_end_ob_buffers(1 TSRMLS_CC);
2244+ exit_status = 0;
2245+ goto out;
2246+
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);
2252+ return FAILURE;
2253+ }
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);
2258+ exit_status = 0;
2259+ goto out;
2260+
2261+ case 'h':
2262+ case '?':
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);
2269+ exit_status = 0;
2270+ goto out;
2271+
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);
2277+ return FAILURE;
2278+ }
2279+ SG(headers_sent) = 1;
2280+ SG(request_info).no_headers = 1;
2281+
2282+#if SUHOSIN_PATCH
2283+#if ZEND_DEBUG
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());
2285+#else
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());
2287+#endif
2288+#else
2289+#if ZEND_DEBUG
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());
2291+#else
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());
2293+#endif
2294+#endif
2295+ php_request_shutdown((void *) 0);
2296+ exit_status = 0;
2297+ goto out;
2298+
2299+ }
2300+
2301+ }
2302+ php_optind = orig_optind;
2303+ php_optarg = orig_optarg;
2304+
2305+#ifdef ZTS
2306+ SG(request_info).path_translated = NULL;
2307+#endif
2308+
2309+ cgi_sapi_module.executable_location = argv[0];
2310+
2311+ /* startup after we get the above ini override se we get things right */
2312+ if (cgi_sapi_module.startup(&cgi_sapi_module) == FAILURE) {
2313+#ifdef ZTS
2314+ tsrm_shutdown();
2315+#endif
2316+ return FAILURE;
2317+ }
2318+
2319+ if (0 > fpm_init(argc, argv, fpm_config)) {
2320+ return FAILURE;
2321+ }
2322+
2323+ fcgi_fd = fpm_run(&max_requests);
2324+
2325+ parent = 0;
2326+
2327+ fcgi_set_is_fastcgi(1);
2328+
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;
2332+
2333+ /* library is already initialized, now init our request */
2334+ fcgi_init_request(&request, fcgi_fd);
2335+
2336+ zend_first_try {
2337+
2338+ /* start of FAST CGI loop */
2339+ /* Initialise FastCGI request structure */
2340+#ifdef PHP_WIN32
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();
2345+ }
2346+#endif
2347+ while (fcgi_accept_request(&request) >= 0) {
2348+
2349+ request_body_fd = -1;
2350+
2351+ SG(server_context) = (void *) &request;
2352+
2353+ init_request_info(TSRMLS_C);
2354+
2355+ CG(interactive) = 0;
2356+
2357+ fpm_request_info();
2358+
2359+ /*
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.
2363+ */
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;
2368+ }
2369+ file_handle.opened_path = NULL;
2370+ file_handle.free_filename = 0;
2371+
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);
2378+ return FAILURE;
2379+ }
2380+
2381+ /*
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
2385+ */
2386+ retval = FAILURE;
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);
2390+ }
2391+ }
2392+ /*
2393+ if we are unable to open path_translated and we are not
2394+ running from shell (so fp == NULL), then fail.
2395+ */
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");
2400+ } else {
2401+ SG(sapi_headers).http_response_code = 404;
2402+ PUTS("No input file specified.\n");
2403+ }
2404+ /* we want to serve more requests if this is fastcgi
2405+ so cleanup and continue, request shutdown is
2406+ handled later */
2407+ goto fastcgi_request_done;
2408+
2409+ STR_FREE(SG(request_info).path_translated);
2410+
2411+ if (free_query_string && SG(request_info).query_string) {
2412+ free(SG(request_info).query_string);
2413+ SG(request_info).query_string = NULL;
2414+ }
2415+
2416+ php_request_shutdown((void *) 0);
2417+ SG(server_context) = NULL;
2418+ php_module_shutdown(TSRMLS_C);
2419+ sapi_shutdown();
2420+#ifdef ZTS
2421+ tsrm_shutdown();
2422+#endif
2423+ return FAILURE;
2424+ }
2425+
2426+ fpm_request_executing();
2427+
2428+ php_execute_script(&file_handle TSRMLS_CC);
2429+
2430+fastcgi_request_done:
2431+
2432+ if (request_body_fd != -1) close(request_body_fd);
2433+
2434+ request_body_fd = -2;
2435+
2436+ {
2437+ char *path_translated;
2438+
2439+ /* Go through this trouble so that the memory manager doesn't warn
2440+ * about SG(request_info).path_translated leaking
2441+ */
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;
2446+ }
2447+
2448+ if (EG(exit_status) == 255) {
2449+ if (CGIG(error_header) && *CGIG(error_header)) {
2450+ sapi_header_line ctr = {0};
2451+
2452+ ctr.line = CGIG(error_header);
2453+ ctr.line_len = strlen(CGIG(error_header));
2454+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
2455+ }
2456+ }
2457+
2458+ php_request_shutdown((void *) 0);
2459+ if (exit_status == 0) {
2460+ exit_status = EG(exit_status);
2461+ }
2462+
2463+ if (SG(request_info).path_translated) {
2464+ free(SG(request_info).path_translated);
2465+ SG(request_info).path_translated = NULL;
2466+ }
2467+ if (free_query_string && SG(request_info).query_string) {
2468+ free(SG(request_info).query_string);
2469+ SG(request_info).query_string = NULL;
2470+ }
2471+
2472+ }
2473+
2474+ requests++;
2475+ if (max_requests && (requests == max_requests)) {
2476+ fcgi_finish_request(&request);
2477+ break;
2478+ }
2479+
2480+ /* end of fastcgi loop */
2481+ }
2482+
2483+ fcgi_shutdown();
2484+
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 */
2487+ ) {
2488+ exit_status = 0;
2489+ }
2490+ else {
2491+ exit_status = 255;
2492+ }
2493+
2494+ if (cgi_sapi_module.php_ini_path_override) {
2495+ free(cgi_sapi_module.php_ini_path_override);
2496+ }
2497+ if (cgi_sapi_module.ini_entries) {
2498+ free(cgi_sapi_module.ini_entries);
2499+ }
2500+ } zend_catch {
2501+ exit_status = 255;
2502+ } zend_end_try();
2503+
2504+out:
2505+
2506+ SG(server_context) = NULL;
2507+ php_module_shutdown(TSRMLS_C);
2508+ sapi_shutdown();
2509+
2510+#ifdef ZTS
2511+ /*tsrm_shutdown();*/
2512+#endif
2513+
2514+#if defined(PHP_WIN32) && ZEND_DEBUG && 0
2515+ _CrtDumpMemoryLeaks();
2516+#endif
2517+
2518+ return exit_status;
2519+}
2520+/* }}} */
2521+
2522+/*
2523+ * Local variables:
2524+ * tab-width: 4
2525+ * c-basic-offset: 4
2526+ * End:
2527+ * vim600: sw=4 ts=4 fdm=marker
2528+ * vim<600: sw=4 ts=4
2529+ */
2530diff -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
2533@@ -0,0 +1,2 @@
2534+CGI / FastCGI
2535+Rasmus Lerdorf, Stig Bakken, Shane Caraveo, Dmitry Stogov
2536diff -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
2539@@ -0,0 +1,1319 @@
2540+/*
2541+ +----------------------------------------------------------------------+
2542+ | PHP Version 5 |
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+ +----------------------------------------------------------------------+
2556+*/
2557+
2558+/* $Id$ */
2559+
2560+#include <php.h>
2561+#include "fastcgi.h"
2562+
2563+#include <string.h>
2564+#include <stdlib.h>
2565+#include <stdio.h>
2566+#include <stdarg.h>
2567+#include <errno.h>
2568+
2569+#ifdef FPM_AUTOCONFIG_H
2570+#include <fpm_autoconfig.h>
2571+#else
2572+#include <php_config.h>
2573+#endif
2574+#include <fpm/fpm.h>
2575+#include <fpm/fpm_request.h>
2576+
2577+#ifdef _WIN32
2578+
2579+#include <windows.h>
2580+
2581+ typedef unsigned int in_addr_t;
2582+
2583+ struct sockaddr_un {
2584+ short sun_family;
2585+ char sun_path[MAXPATHLEN];
2586+ };
2587+
2588+ static HANDLE fcgi_accept_mutex = INVALID_HANDLE_VALUE;
2589+ static int is_impersonate = 0;
2590+
2591+#define FCGI_LOCK(fd) \
2592+ if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
2593+ DWORD ret; \
2594+ while ((ret = WaitForSingleObject(fcgi_accept_mutex, 1000)) == WAIT_TIMEOUT) { \
2595+ if (in_shutdown) return -1; \
2596+ } \
2597+ if (ret == WAIT_FAILED) { \
2598+ fprintf(stderr, "WaitForSingleObject() failed\n"); \
2599+ return -1; \
2600+ } \
2601+ }
2602+
2603+#define FCGI_UNLOCK(fd) \
2604+ if (fcgi_accept_mutex != INVALID_HANDLE_VALUE) { \
2605+ ReleaseMutex(fcgi_accept_mutex); \
2606+ }
2607+
2608+#else
2609+
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>
2620+
2621+# define closesocket(s) close(s)
2622+
2623+# if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
2624+# include <sys/poll.h>
2625+# endif
2626+# if defined(HAVE_SYS_SELECT_H)
2627+# include <sys/select.h>
2628+# endif
2629+
2630+#ifndef INADDR_NONE
2631+#define INADDR_NONE ((unsigned long) -1)
2632+#endif
2633+
2634+# ifndef HAVE_SOCKLEN_T
2635+ typedef unsigned int socklen_t;
2636+# endif
2637+
2638+# ifdef USE_LOCKING
2639+# define FCGI_LOCK(fd) \
2640+ do { \
2641+ struct flock lock; \
2642+ lock.l_type = F_WRLCK; \
2643+ lock.l_start = 0; \
2644+ lock.l_whence = SEEK_SET; \
2645+ lock.l_len = 0; \
2646+ if (fcntl(fd, F_SETLKW, &lock) != -1) { \
2647+ break; \
2648+ } else if (errno != EINTR || in_shutdown) { \
2649+ return -1; \
2650+ } \
2651+ } while (1)
2652+
2653+# define FCGI_UNLOCK(fd) \
2654+ do { \
2655+ int orig_errno = errno; \
2656+ while (1) { \
2657+ struct flock lock; \
2658+ lock.l_type = F_UNLCK; \
2659+ lock.l_start = 0; \
2660+ lock.l_whence = SEEK_SET; \
2661+ lock.l_len = 0; \
2662+ if (fcntl(fd, F_SETLK, &lock) != -1) { \
2663+ break; \
2664+ } else if (errno != EINTR) { \
2665+ return -1; \
2666+ } \
2667+ } \
2668+ errno = orig_errno; \
2669+ } while (0)
2670+# else
2671+# define FCGI_LOCK(fd)
2672+# define FCGI_UNLOCK(fd)
2673+# endif
2674+
2675+#endif
2676+
2677+typedef union _sa_t {
2678+ struct sockaddr sa;
2679+ struct sockaddr_un sa_unix;
2680+ struct sockaddr_in sa_inet;
2681+} sa_t;
2682+
2683+static HashTable *fcgi_mgmt_vars;
2684+
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;
2689+
2690+#ifdef _WIN32
2691+
2692+static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
2693+{
2694+ HANDLE shutdown_event = (HANDLE) arg;
2695+ WaitForSingleObject(shutdown_event, INFINITE);
2696+ in_shutdown = 1;
2697+ return 0;
2698+}
2699+
2700+#else
2701+
2702+static void fcgi_signal_handler(int signo)
2703+{
2704+ if (signo == SIGUSR1 || signo == SIGTERM) {
2705+ in_shutdown = 1;
2706+ }
2707+}
2708+
2709+static void fcgi_setup_signals(void)
2710+{
2711+ struct sigaction new_sa, old_sa;
2712+
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);
2721+ }
2722+}
2723+#endif
2724+
2725+int fcgi_in_shutdown(void)
2726+{
2727+ return in_shutdown;
2728+}
2729+
2730+int fcgi_init(void)
2731+{
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);
2738+#ifdef _WIN32
2739+# if 0
2740+ /* TODO: Support for TCP sockets */
2741+ WSADATA wsaData;
2742+
2743+ if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
2744+ fprintf(stderr, "Error starting Windows Sockets. Error: %d", WSAGetLastError());
2745+ return 0;
2746+ }
2747+# endif
2748+ is_initialized = 1;
2749+
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)) {
2753+ char *str;
2754+ DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
2755+ HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
2756+
2757+ SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
2758+
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)) {
2764+ return -1;
2765+ }
2766+ }
2767+ str = getenv("_FCGI_MUTEX_");
2768+ if (str != NULL) {
2769+ fcgi_accept_mutex = (HANDLE) atoi(str);
2770+ }
2771+ return is_fastcgi = 1;
2772+ } else {
2773+ return is_fastcgi = 0;
2774+ }
2775+#else
2776+ sa_t sa;
2777+ socklen_t len = sizeof(sa);
2778+
2779+ is_initialized = 1;
2780+ errno = 0;
2781+ if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
2782+ fcgi_setup_signals();
2783+ return is_fastcgi = 1;
2784+ } else {
2785+ return is_fastcgi = 0;
2786+ }
2787+
2788+ fcgi_set_allowed_clients(getenv("FCGI_WEB_SERVER_ADDRS"));
2789+#endif
2790+ }
2791+ return is_fastcgi;
2792+}
2793+
2794+
2795+int fcgi_is_fastcgi(void)
2796+{
2797+ if (!is_initialized) {
2798+ return fcgi_init();
2799+ } else {
2800+ return is_fastcgi;
2801+ }
2802+}
2803+
2804+void fcgi_set_is_fastcgi(int new_value)
2805+{
2806+ is_fastcgi = new_value;
2807+}
2808+
2809+void fcgi_set_in_shutdown(int new_value)
2810+{
2811+ in_shutdown = new_value;
2812+}
2813+
2814+void fcgi_shutdown(void)
2815+{
2816+ if (is_initialized) {
2817+ zend_hash_destroy(fcgi_mgmt_vars);
2818+ pefree(fcgi_mgmt_vars, 1);
2819+ }
2820+ is_fastcgi = 0;
2821+
2822+ if (allowed_clients) {
2823+ free(allowed_clients);
2824+ allowed_clients = 0;
2825+ }
2826+}
2827+
2828+#ifdef _WIN32
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.
2835+ */
2836+static PACL prepare_named_pipe_acl(PSECURITY_DESCRIPTOR sd, LPSECURITY_ATTRIBUTES sa)
2837+{
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;
2844+ PACL acl;
2845+
2846+ sid_everyone = (PSID)&everyone_buf;
2847+ sid_owner = (PSID)&owner_buf;
2848+
2849+ req_acl_size = sizeof(ACL) +
2850+ (2 * ((sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + GetSidLengthRequired(1)));
2851+
2852+ acl = malloc(req_acl_size);
2853+
2854+ if (acl == NULL) {
2855+ return NULL;
2856+ }
2857+
2858+ if (!InitializeSid(sid_everyone, &siaWorld, 1)) {
2859+ goto out_fail;
2860+ }
2861+ *GetSidSubAuthority(sid_everyone, 0) = SECURITY_WORLD_RID;
2862+
2863+ if (!InitializeSid(sid_owner, &siaCreator, 1)) {
2864+ goto out_fail;
2865+ }
2866+ *GetSidSubAuthority(sid_owner, 0) = SECURITY_CREATOR_OWNER_RID;
2867+
2868+ if (!InitializeAcl(acl, req_acl_size, ACL_REVISION)) {
2869+ goto out_fail;
2870+ }
2871+
2872+ if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_WRITE, sid_everyone)) {
2873+ goto out_fail;
2874+ }
2875+
2876+ if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, sid_owner)) {
2877+ goto out_fail;
2878+ }
2879+
2880+ if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION)) {
2881+ goto out_fail;
2882+ }
2883+
2884+ if (!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE)) {
2885+ goto out_fail;
2886+ }
2887+
2888+ sa->lpSecurityDescriptor = sd;
2889+
2890+ return acl;
2891+
2892+out_fail:
2893+ free(acl);
2894+ return NULL;
2895+}
2896+#endif
2897+
2898+void fcgi_set_allowed_clients(char *ip)
2899+{
2900+ char *cur, *end;
2901+ int n;
2902+
2903+ if (ip) {
2904+ ip = strdup(ip);
2905+ cur = ip;
2906+ n = 0;
2907+ while (*cur) {
2908+ if (*cur == ',') n++;
2909+ cur++;
2910+ }
2911+ if (allowed_clients) free(allowed_clients);
2912+ allowed_clients = malloc(sizeof(in_addr_t) * (n+2));
2913+ n = 0;
2914+ cur = ip;
2915+ while (cur) {
2916+ end = strchr(cur, ',');
2917+ if (end) {
2918+ *end = 0;
2919+ end++;
2920+ }
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);
2924+ }
2925+ n++;
2926+ cur = end;
2927+ }
2928+ allowed_clients[n] = INADDR_NONE;
2929+ free(ip);
2930+ }
2931+}
2932+
2933+static int is_port_number(const char *bindpath)
2934+{
2935+ while (*bindpath) {
2936+ if (*bindpath < '0' || *bindpath > '9') {
2937+ return 0;
2938+ }
2939+ bindpath++;
2940+ }
2941+ return 1;
2942+}
2943+
2944+int fcgi_listen(const char *path, int backlog)
2945+{
2946+ char *s;
2947+ int tcp = 0;
2948+ char host[MAXPATHLEN];
2949+ short port = 0;
2950+ int listen_socket;
2951+ sa_t sa;
2952+ socklen_t sock_len;
2953+#ifdef SO_REUSEADDR
2954+# ifdef _WIN32
2955+ BOOL reuse = 1;
2956+# else
2957+ int reuse = 1;
2958+# endif
2959+#endif
2960+
2961+ if ((s = strchr(path, ':'))) {
2962+ port = atoi(s+1);
2963+ if (port != 0 && (s-path) < MAXPATHLEN) {
2964+ strncpy(host, path, s-path);
2965+ host[s-path] = '\0';
2966+ tcp = 1;
2967+ }
2968+ } else if (is_port_number(path)) {
2969+ port = atoi(path);
2970+ if (port != 0) {
2971+ host[0] = '\0';
2972+ tcp = 1;
2973+ }
2974+ }
2975+
2976+ /* Prepare socket address */
2977+ if (tcp) {
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);
2982+
2983+ if (!*host || !strncmp(host, "*", sizeof("*")-1)) {
2984+ sa.sa_inet.sin_addr.s_addr = htonl(INADDR_ANY);
2985+ } else {
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;
2989+
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);
2993+ return -1;
2994+ } else if (hep->h_addr_list[1]) {
2995+ fprintf(stderr, "Host '%s' has multiple addresses. You must choose one explicitly!\n", host);
2996+ return -1;
2997+ }
2998+ sa.sa_inet.sin_addr.s_addr = ((struct in_addr*)hep->h_addr_list[0])->s_addr;
2999+ }
3000+ }
3001+ } else {
3002+#ifdef _WIN32
3003+ SECURITY_DESCRIPTOR sd;
3004+ SECURITY_ATTRIBUTES sa;
3005+ PACL acl;
3006+ HANDLE namedPipe;
3007+
3008+ memset(&sa, 0, sizeof(sa));
3009+ sa.nLength = sizeof(sa);
3010+ sa.bInheritHandle = FALSE;
3011+ acl = prepare_named_pipe_acl(&sd, &sa);
3012+
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) {
3019+ return -1;
3020+ }
3021+ listen_socket = _open_osfhandle((long)namedPipe, 0);
3022+ if (!is_initialized) {
3023+ fcgi_init();
3024+ }
3025+ is_fastcgi = 1;
3026+ return listen_socket;
3027+
3028+#else
3029+ int path_len = strlen(path);
3030+
3031+ if (path_len >= sizeof(sa.sa_unix.sun_path)) {
3032+ fprintf(stderr, "Listening socket's path name is too long.\n");
3033+ return -1;
3034+ }
3035+
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;
3042+#endif
3043+ unlink(path);
3044+#endif
3045+ }
3046+
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 ||
3051+#endif
3052+ bind(listen_socket, (struct sockaddr *) &sa, sock_len) < 0 ||
3053+ listen(listen_socket, backlog) < 0) {
3054+
3055+ fprintf(stderr, "Cannot bind/listen socket - [%d] %s.\n",errno, strerror(errno));
3056+ return -1;
3057+ }
3058+
3059+ if (!tcp) {
3060+ chmod(path, 0777);
3061+ }
3062+
3063+ if (!is_initialized) {
3064+ fcgi_init();
3065+ }
3066+ is_fastcgi = 1;
3067+
3068+#ifdef _WIN32
3069+ if (tcp) {
3070+ listen_socket = _open_osfhandle((long)listen_socket, 0);
3071+ }
3072+#else
3073+ fcgi_setup_signals();
3074+#endif
3075+ return listen_socket;
3076+}
3077+
3078+void fcgi_init_request(fcgi_request *req, int listen_socket)
3079+{
3080+ memset(req, 0, sizeof(fcgi_request));
3081+ req->listen_socket = listen_socket;
3082+ req->fd = -1;
3083+ req->id = -1;
3084+
3085+ req->in_len = 0;
3086+ req->in_pad = 0;
3087+
3088+ req->out_hdr = NULL;
3089+ req->out_pos = req->out_buf;
3090+
3091+#ifdef _WIN32
3092+ req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
3093+#endif
3094+}
3095+
3096+static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
3097+{
3098+ int ret;
3099+ size_t n = 0;
3100+
3101+ do {
3102+ errno = 0;
3103+#ifdef _WIN32
3104+ if (!req->tcp) {
3105+ ret = write(req->fd, ((char*)buf)+n, count-n);
3106+ } else {
3107+ ret = send(req->fd, ((char*)buf)+n, count-n, 0);
3108+ if (ret <= 0) {
3109+ errno = WSAGetLastError();
3110+ }
3111+ }
3112+#else
3113+ ret = write(req->fd, ((char*)buf)+n, count-n);
3114+#endif
3115+ if (ret > 0) {
3116+ n += ret;
3117+ } else if (ret <= 0 && errno != 0 && errno != EINTR) {
3118+ return ret;
3119+ }
3120+ } while (n != count);
3121+ return n;
3122+}
3123+
3124+static inline ssize_t safe_read(fcgi_request *req, const void *buf, size_t count)
3125+{
3126+ int ret;
3127+ size_t n = 0;
3128+
3129+ do {
3130+ errno = 0;
3131+#ifdef _WIN32
3132+ if (!req->tcp) {
3133+ ret = read(req->fd, ((char*)buf)+n, count-n);
3134+ } else {
3135+ ret = recv(req->fd, ((char*)buf)+n, count-n, 0);
3136+ if (ret <= 0) {
3137+ errno = WSAGetLastError();
3138+ }
3139+ }
3140+#else
3141+ ret = read(req->fd, ((char*)buf)+n, count-n);
3142+#endif
3143+ if (ret > 0) {
3144+ n += ret;
3145+ } else if (ret == 0 && errno == 0) {
3146+ return n;
3147+ } else if (ret <= 0 && errno != 0 && errno != EINTR) {
3148+ return ret;
3149+ }
3150+ } while (n != count);
3151+ return n;
3152+}
3153+
3154+static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int req_id, int len)
3155+{
3156+ int pad = ((len + 7) & ~7) - len;
3157+
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;
3164+ hdr->type = type;
3165+ hdr->version = FCGI_VERSION_1;
3166+ if (pad) {
3167+ memset(((unsigned char*)hdr) + sizeof(fcgi_header) + len, 0, pad);
3168+ }
3169+ return pad;
3170+}
3171+
3172+static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
3173+{
3174+ char buf[128];
3175+ char *tmp = buf;
3176+ int buf_size = sizeof(buf);
3177+ int name_len, val_len;
3178+ char *s;
3179+ int ret = 1;
3180+
3181+ while (p < end) {
3182+ name_len = *p++;
3183+ if (name_len >= 128) {
3184+ name_len = ((name_len & 0x7f) << 24);
3185+ name_len |= (*p++ << 16);
3186+ name_len |= (*p++ << 8);
3187+ name_len |= *p++;
3188+ }
3189+ val_len = *p++;
3190+ if (val_len >= 128) {
3191+ val_len = ((val_len & 0x7f) << 24);
3192+ val_len |= (*p++ << 16);
3193+ val_len |= (*p++ << 8);
3194+ val_len |= *p++;
3195+ }
3196+ if (name_len + val_len < 0 ||
3197+ name_len + val_len > end - p) {
3198+ /* Malformated request */
3199+ ret = 0;
3200+ break;
3201+ }
3202+ if (name_len+1 >= buf_size) {
3203+ buf_size = name_len + 64;
3204+ tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
3205+ }
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;
3211+ }
3212+ if (tmp != buf && tmp != NULL) {
3213+ efree(tmp);
3214+ }
3215+ return ret;
3216+}
3217+
3218+static void fcgi_free_var(char **s)
3219+{
3220+ free(*s);
3221+}
3222+
3223+static int fcgi_read_request(fcgi_request *req)
3224+{
3225+ fcgi_header hdr;
3226+ int len, padding;
3227+ unsigned char buf[FCGI_MAX_LENGTH+8];
3228+
3229+ req->keep = 0;
3230+ req->in_len = 0;
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);
3234+
3235+ if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
3236+ hdr.version < FCGI_VERSION_1) {
3237+ return 0;
3238+ }
3239+
3240+ len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
3241+ padding = hdr.paddingLength;
3242+
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) {
3246+ return 0;
3247+ }
3248+
3249+ len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
3250+ padding = hdr.paddingLength;
3251+ }
3252+
3253+ if (len + padding > FCGI_MAX_LENGTH) {
3254+ return 0;
3255+ }
3256+
3257+ req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
3258+
3259+ if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
3260+ char *val;
3261+
3262+ if (safe_read(req, buf, len+padding) != len+padding) {
3263+ return 0;
3264+ }
3265+
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);
3271+ break;
3272+ case FCGI_AUTHORIZER:
3273+ val = strdup("AUTHORIZER");
3274+ zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
3275+ break;
3276+ case FCGI_FILTER:
3277+ val = strdup("FILTER");
3278+ zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
3279+ break;
3280+ default:
3281+ return 0;
3282+ }
3283+
3284+ if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
3285+ hdr.version < FCGI_VERSION_1) {
3286+ return 0;
3287+ }
3288+
3289+ len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
3290+ padding = hdr.paddingLength;
3291+
3292+ while (hdr.type == FCGI_PARAMS && len > 0) {
3293+ if (len + padding > FCGI_MAX_LENGTH) {
3294+ return 0;
3295+ }
3296+
3297+ if (safe_read(req, buf, len+padding) != len+padding) {
3298+ req->keep = 0;
3299+ return 0;
3300+ }
3301+
3302+ if (!fcgi_get_params(req, buf, buf+len)) {
3303+ req->keep = 0;
3304+ return 0;
3305+ }
3306+
3307+ if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
3308+ hdr.version < FCGI_VERSION_1) {
3309+ req->keep = 0;
3310+ return 0;
3311+ }
3312+ len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
3313+ padding = hdr.paddingLength;
3314+ }
3315+ } else if (hdr.type == FCGI_GET_VALUES) {
3316+ unsigned char *p = buf + sizeof(fcgi_header);
3317+ HashPosition pos;
3318+ char * str_index;
3319+ uint str_length;
3320+ ulong num_index;
3321+ int key_type;
3322+ zval ** value;
3323+
3324+ if (safe_read(req, buf, len+padding) != len+padding) {
3325+ req->keep = 0;
3326+ return 0;
3327+ }
3328+
3329+ if (!fcgi_get_params(req, buf, buf+len)) {
3330+ req->keep = 0;
3331+ return 0;
3332+ }
3333+
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) {
3336+ int zlen;
3337+ zend_hash_move_forward_ex(&req->env, &pos);
3338+ if (key_type != HASH_KEY_IS_STRING) {
3339+ continue;
3340+ }
3341+ if (zend_hash_find(fcgi_mgmt_vars, str_index, str_length, (void**) &value) != SUCCESS) {
3342+ continue;
3343+ }
3344+ --str_length;
3345+ zlen = Z_STRLEN_PP(value);
3346+ if ((p + 4 + 4 + str_length + zlen) >= (buf + sizeof(buf))) {
3347+ break;
3348+ }
3349+ if (str_length < 0x80) {
3350+ *p++ = str_length;
3351+ } else {
3352+ *p++ = ((str_length >> 24) & 0xff) | 0x80;
3353+ *p++ = (str_length >> 16) & 0xff;
3354+ *p++ = (str_length >> 8) & 0xff;
3355+ *p++ = str_length & 0xff;
3356+ }
3357+ if (zlen < 0x80) {
3358+ *p++ = zlen;
3359+ } else {
3360+ *p++ = ((zlen >> 24) & 0xff) | 0x80;
3361+ *p++ = (zlen >> 16) & 0xff;
3362+ *p++ = (zlen >> 8) & 0xff;
3363+ *p++ = zlen & 0xff;
3364+ }
3365+ memcpy(p, str_index, str_length);
3366+ p += str_length;
3367+ memcpy(p, Z_STRVAL_PP(value), zlen);
3368+ p += zlen;
3369+ }
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) {
3373+ req->keep = 0;
3374+ return 0;
3375+ }
3376+ return 0;
3377+ } else {
3378+ return 0;
3379+ }
3380+
3381+ return 1;
3382+}
3383+
3384+int fcgi_read(fcgi_request *req, char *str, int len)
3385+{
3386+ int ret, n, rest;
3387+ fcgi_header hdr;
3388+ unsigned char buf[255];
3389+
3390+ n = 0;
3391+ rest = len;
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) {
3397+ req->keep = 0;
3398+ return 0;
3399+ }
3400+ req->in_len = (hdr.contentLengthB1 << 8) | hdr.contentLengthB0;
3401+ req->in_pad = hdr.paddingLength;
3402+ if (req->in_len == 0) {
3403+ return n;
3404+ }
3405+ }
3406+
3407+ if (req->in_len >= rest) {
3408+ ret = safe_read(req, str, rest);
3409+ } else {
3410+ ret = safe_read(req, str, req->in_len);
3411+ }
3412+ if (ret < 0) {
3413+ req->keep = 0;
3414+ return ret;
3415+ } else if (ret > 0) {
3416+ req->in_len -= ret;
3417+ rest -= ret;
3418+ n += ret;
3419+ str += ret;
3420+ if (req->in_len == 0) {
3421+ if (req->in_pad) {
3422+ if (safe_read(req, buf, req->in_pad) != req->in_pad) {
3423+ req->keep = 0;
3424+ return ret;
3425+ }
3426+ }
3427+ } else {
3428+ return n;
3429+ }
3430+ } else {
3431+ return n;
3432+ }
3433+ }
3434+ return n;
3435+}
3436+
3437+void fcgi_close(fcgi_request *req, int force, int destroy)
3438+{
3439+ if (destroy) {
3440+ zend_hash_destroy(&req->env);
3441+ }
3442+
3443+#ifdef _WIN32
3444+ if (is_impersonate && !req->tcp) {
3445+ RevertToSelf();
3446+ }
3447+#endif
3448+
3449+ if ((force || !req->keep) && req->fd >= 0) {
3450+#ifdef _WIN32
3451+ if (!req->tcp) {
3452+ HANDLE pipe = (HANDLE)_get_osfhandle(req->fd);
3453+
3454+ if (!force) {
3455+ FlushFileBuffers(pipe);
3456+ }
3457+ DisconnectNamedPipe(pipe);
3458+ } else {
3459+ if (!force) {
3460+ char buf[8];
3461+
3462+ shutdown(req->fd, 1);
3463+ while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
3464+ }
3465+ closesocket(req->fd);
3466+ }
3467+#else
3468+ if (!force) {
3469+ char buf[8];
3470+
3471+ shutdown(req->fd, 1);
3472+ while (recv(req->fd, buf, sizeof(buf), 0) > 0) {}
3473+ }
3474+ close(req->fd);
3475+#endif
3476+ req->fd = -1;
3477+
3478+ fpm_request_finished();
3479+ }
3480+}
3481+
3482+int fcgi_accept_request(fcgi_request *req)
3483+{
3484+#ifdef _WIN32
3485+ HANDLE pipe;
3486+ OVERLAPPED ov;
3487+#endif
3488+ fcgi_finish_request(req);
3489+
3490+ while (1) {
3491+ if (req->fd < 0) {
3492+ while (1) {
3493+ if (in_shutdown) {
3494+ return -1;
3495+ }
3496+#ifdef _WIN32
3497+ if (!req->tcp) {
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);
3508+ return -1;
3509+ }
3510+ }
3511+ } else if (errno != ERROR_PIPE_CONNECTED) {
3512+ }
3513+ }
3514+ CloseHandle(ov.hEvent);
3515+ req->fd = req->listen_socket;
3516+ FCGI_UNLOCK(req->listen_socket);
3517+ } else {
3518+ SOCKET listen_socket = (SOCKET)_get_osfhandle(req->listen_socket);
3519+#else
3520+ {
3521+ int listen_socket = req->listen_socket;
3522+#endif
3523+ sa_t sa;
3524+ socklen_t len = sizeof(sa);
3525+
3526+ fpm_request_accepting();
3527+
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) {
3532+ int n = 0;
3533+ int allowed = 0;
3534+
3535+ while (allowed_clients[n] != INADDR_NONE) {
3536+ if (allowed_clients[n] == sa.sa_inet.sin_addr.s_addr) {
3537+ allowed = 1;
3538+ break;
3539+ }
3540+ n++;
3541+ }
3542+ if (!allowed) {
3543+ fprintf(stderr, "Connection from disallowed IP address '%s' is dropped.\n", inet_ntoa(sa.sa_inet.sin_addr));
3544+ closesocket(req->fd);
3545+ req->fd = -1;
3546+ continue;
3547+ }
3548+ }
3549+ }
3550+
3551+#ifdef _WIN32
3552+ if (req->fd < 0 && (in_shutdown || errno != EINTR)) {
3553+#else
3554+ if (req->fd < 0 && (in_shutdown || (errno != EINTR && errno != ECONNABORTED))) {
3555+#endif
3556+ return -1;
3557+ }
3558+
3559+#ifdef _WIN32
3560+ break;
3561+#else
3562+ if (req->fd >= 0) {
3563+
3564+ fpm_request_reading_headers();
3565+
3566+#if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
3567+ struct pollfd fds;
3568+ int ret;
3569+
3570+ fds.fd = req->fd;
3571+ fds.events = POLLIN;
3572+ fds.revents = 0;
3573+ do {
3574+ errno = 0;
3575+ ret = poll(&fds, 1, 5000);
3576+ } while (ret < 0 && errno == EINTR);
3577+ if (ret > 0 && (fds.revents & POLLIN)) {
3578+ break;
3579+ }
3580+ fcgi_close(req, 1, 0);
3581+#else
3582+ if (req->fd < FD_SETSIZE) {
3583+ struct timeval tv = {5,0};
3584+ fd_set set;
3585+ int ret;
3586+
3587+ FD_ZERO(&set);
3588+ FD_SET(req->fd, &set);
3589+ do {
3590+ errno = 0;
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)) {
3594+ break;
3595+ }
3596+ fcgi_close(req, 1, 0);
3597+ } else {
3598+ fprintf(stderr, "Too many open file descriptors. FD_SETSIZE limit exceeded.");
3599+ fcgi_close(req, 1, 0);
3600+ }
3601+#endif
3602+ }
3603+#endif
3604+ }
3605+ } else if (in_shutdown) {
3606+ return -1;
3607+ }
3608+ if (fcgi_read_request(req)) {
3609+#ifdef _WIN32
3610+ if (is_impersonate && !req->tcp) {
3611+ pipe = (HANDLE)_get_osfhandle(req->fd);
3612+ if (!ImpersonateNamedPipeClient(pipe)) {
3613+ fcgi_close(req, 1, 1);
3614+ continue;
3615+ }
3616+ }
3617+#endif
3618+ return req->fd;
3619+ } else {
3620+ fcgi_close(req, 1, 1);
3621+ }
3622+ }
3623+}
3624+
3625+static inline fcgi_header* open_packet(fcgi_request *req, fcgi_request_type type)
3626+{
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;
3631+}
3632+
3633+static inline void close_packet(fcgi_request *req)
3634+{
3635+ if (req->out_hdr) {
3636+ int len = req->out_pos - ((unsigned char*)req->out_hdr + sizeof(fcgi_header));
3637+
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;
3640+ }
3641+}
3642+
3643+int fcgi_flush(fcgi_request *req, int close)
3644+{
3645+ int len;
3646+
3647+ close_packet(req);
3648+
3649+ len = req->out_pos - req->out_buf;
3650+
3651+ if (close) {
3652+ fcgi_end_request_rec *rec = (fcgi_end_request_rec*)(req->out_pos);
3653+
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);
3661+ }
3662+
3663+ if (safe_write(req, req->out_buf, len) != len) {
3664+ req->keep = 0;
3665+ return 0;
3666+ }
3667+
3668+ req->out_pos = req->out_buf;
3669+ return 1;
3670+}
3671+
3672+int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len)
3673+{
3674+ int limit, rest;
3675+
3676+ if (len <= 0) {
3677+ return 0;
3678+ }
3679+
3680+ if (req->out_hdr && req->out_hdr->type != type) {
3681+ close_packet(req);
3682+ }
3683+#if 0
3684+ /* Unoptimized, but clear version */
3685+ rest = len;
3686+ while (rest > 0) {
3687+ limit = sizeof(req->out_buf) - (req->out_pos - req->out_buf);
3688+
3689+ if (!req->out_hdr) {
3690+ if (limit < sizeof(fcgi_header)) {
3691+ if (!fcgi_flush(req, 0)) {
3692+ return -1;
3693+ }
3694+ }
3695+ open_packet(req, type);
3696+ }
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;
3701+ return len;
3702+ } else {
3703+ memcpy(req->out_pos, str, limit);
3704+ req->out_pos += limit;
3705+ rest -= limit;
3706+ str += limit;
3707+ if (!fcgi_flush(req, 0)) {
3708+ return -1;
3709+ }
3710+ }
3711+ }
3712+#else
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;
3718+ }
3719+
3720+ if (len < limit) {
3721+ if (!req->out_hdr) {
3722+ open_packet(req, type);
3723+ }
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);
3729+ }
3730+ if (limit > 0) {
3731+ memcpy(req->out_pos, str, limit);
3732+ req->out_pos += limit;
3733+ }
3734+ if (!fcgi_flush(req, 0)) {
3735+ return -1;
3736+ }
3737+ if (len > limit) {
3738+ open_packet(req, type);
3739+ memcpy(req->out_pos, str + limit, len - limit);
3740+ req->out_pos += len - limit;
3741+ }
3742+ } else {
3743+ int pos = 0;
3744+ int pad;
3745+
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)) {
3752+ return -1;
3753+ }
3754+ if (safe_write(req, str + pos, 0xfff8) != 0xfff8) {
3755+ req->keep = 0;
3756+ return -1;
3757+ }
3758+ pos += 0xfff8;
3759+ }
3760+
3761+ pad = (((len - pos) + 7) & ~7) - (len - pos);
3762+ rest = pad ? 8 - pad : 0;
3763+
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)) {
3768+ return -1;
3769+ }
3770+ if (safe_write(req, str + pos, (len - pos) - rest) != (len - pos) - rest) {
3771+ req->keep = 0;
3772+ return -1;
3773+ }
3774+ if (pad) {
3775+ open_packet(req, type);
3776+ memcpy(req->out_pos, str + len - rest, rest);
3777+ req->out_pos += rest;
3778+ }
3779+ }
3780+#endif
3781+ return len;
3782+}
3783+
3784+int fcgi_finish_request(fcgi_request *req)
3785+{
3786+ if (req->fd >= 0) {
3787+ fcgi_flush(req, 1);
3788+ fcgi_close(req, 0, 1);
3789+ }
3790+ return 1;
3791+}
3792+
3793+char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
3794+{
3795+ char **val;
3796+
3797+ if (!req) return NULL;
3798+
3799+ if (zend_hash_find(&req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
3800+ return *val;
3801+ }
3802+ return NULL;
3803+}
3804+
3805+char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
3806+{
3807+ if (var && req) {
3808+ if (val == NULL) {
3809+ zend_hash_del(&req->env, var, var_len+1);
3810+ } else {
3811+ char **ret;
3812+
3813+ val = strdup(val);
3814+ if (zend_hash_update(&req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
3815+ return *ret;
3816+ }
3817+ }
3818+ }
3819+ return NULL;
3820+}
3821+
3822+#ifdef _WIN32
3823+void fcgi_impersonate(void)
3824+{
3825+ char *os_name;
3826+
3827+ os_name = getenv("OS");
3828+ if (os_name && stricmp(os_name, "Windows_NT") == 0) {
3829+ is_impersonate = 1;
3830+ }
3831+}
3832+#endif
3833+
3834+void fcgi_set_mgmt_var(char * name, size_t name_len, const char * value, size_t value_len)
3835+{
3836+ zval * zvalue;
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);
3842+}
3843+
3844+void fcgi_free_mgmt_var_cb(void * ptr)
3845+{
3846+ zval ** var = (zval **)ptr;
3847+ pefree(Z_STRVAL_PP(var), 1);
3848+ pefree(*var, 1);
3849+}
3850+
3851+/*
3852+ * Local variables:
3853+ * tab-width: 4
3854+ * c-basic-offset: 4
3855+ * End:
3856+ * vim600: sw=4 ts=4 fdm=marker
3857+ * vim<600: sw=4 ts=4
3858+ */
3859diff -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
3862@@ -0,0 +1,150 @@
3863+/*
3864+ +----------------------------------------------------------------------+
3865+ | PHP Version 5 |
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+ +----------------------------------------------------------------------+
3879+*/
3880+
3881+/* $Id$ */
3882+
3883+/* FastCGI protocol */
3884+
3885+#define FCGI_VERSION_1 1
3886+
3887+#define FCGI_MAX_LENGTH 0xffff
3888+
3889+#define FCGI_KEEP_CONN 1
3890+
3891+typedef enum _fcgi_role {
3892+ FCGI_RESPONDER = 1,
3893+ FCGI_AUTHORIZER = 2,
3894+ FCGI_FILTER = 3
3895+} fcgi_role;
3896+
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;
3909+
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;
3916+
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;
3926+} fcgi_header;
3927+
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;
3934+
3935+typedef struct _fcgi_begin_request_rec {
3936+ fcgi_header hdr;
3937+ fcgi_begin_request body;
3938+} fcgi_begin_request_rec;
3939+
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;
3948+
3949+typedef struct _fcgi_end_request_rec {
3950+ fcgi_header hdr;
3951+ fcgi_end_request body;
3952+} fcgi_end_request_rec;
3953+
3954+/* FastCGI client API */
3955+
3956+typedef struct _fcgi_request {
3957+ int listen_socket;
3958+#ifdef _WIN32
3959+ int tcp;
3960+#endif
3961+ int fd;
3962+ int id;
3963+ int keep;
3964+
3965+ int in_len;
3966+ int in_pad;
3967+
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)];
3972+
3973+ HashTable env;
3974+} fcgi_request;
3975+
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);
3987+
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);
3990+
3991+int fcgi_read(fcgi_request *req, char *str, int len);
3992+
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);
3995+
3996+void fcgi_close(fcgi_request *req, int force, int destroy);
3997+
3998+#ifdef PHP_WIN32
3999+void fcgi_impersonate(void);
4000+#endif
4001+
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);
4004+
4005+/*
4006+ * Local variables:
4007+ * tab-width: 4
4008+ * c-basic-offset: 4
4009+ * End:
4010+ * vim600: sw=4 ts=4 fdm=marker
4011+ * vim<600: sw=4 ts=4
4012+ */
4013diff -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
4016@@ -0,0 +1,39 @@
4017+/*
4018+ +----------------------------------------------------------------------+
4019+ | PHP Version 5 |
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+ +----------------------------------------------------------------------+
4033+*/
4034+
4035+/* $Id$ */
4036+
4037+#include <php.h>
4038+
4039+#ifdef NETWARE
4040+/*
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
4042+*/
4043+#undef optarg
4044+#undef optind
4045+#endif
4046+/* Define structure for one recognized option (both single char and long name).
4047+ * If short_open is '-' this is the last option.
4048+ */
4049+typedef struct _opt_struct {
4050+ const char opt_char;
4051+ const int need_param;
4052+ const char * opt_name;
4053+} opt_struct;
4054+
4055+int php_getopt(int argc, char* const *argv, const opt_struct opts[], char **optarg, int *optind, int show_err);
4056diff -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
4059@@ -0,0 +1,135 @@
4060+#! /bin/sh
4061+
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
4070+### END INIT INFO
4071+
4072+php_fpm_BIN=@php_fpm_bin_path@
4073+php_fpm_CONF=@php_fpm_conf_path@
4074+php_fpm_PID=@php_fpm_pid_path@
4075+
4076+
4077+php_opts="--fpm-config $php_fpm_CONF"
4078+
4079+
4080+wait_for_pid () {
4081+ try=0
4082+
4083+ while test $try -lt 35 ; do
4084+
4085+ case "$1" in
4086+ 'created')
4087+ if [ -f "$2" ] ; then
4088+ try=''
4089+ break
4090+ fi
4091+ ;;
4092+
4093+ 'removed')
4094+ if [ ! -f "$2" ] ; then
4095+ try=''
4096+ break
4097+ fi
4098+ ;;
4099+ esac
4100+
4101+ echo -n .
4102+ try=`expr $try + 1`
4103+ sleep 1
4104+
4105+ done
4106+
4107+}
4108+
4109+case "$1" in
4110+ start)
4111+ echo -n "Starting @php_fpm_bin@ "
4112+
4113+ $php_fpm_BIN $php_opts
4114+
4115+ if [ "$?" != 0 ] ; then
4116+ echo " failed"
4117+ exit 1
4118+ fi
4119+
4120+ wait_for_pid created $php_fpm_PID
4121+
4122+ if [ -n "$try" ] ; then
4123+ echo " failed"
4124+ exit 1
4125+ else
4126+ echo " done"
4127+ fi
4128+ ;;
4129+
4130+ stop)
4131+ echo -n "Gracefully shutting down @php_fpm_bin@ "
4132+
4133+ if [ ! -r $php_fpm_PID ] ; then
4134+ echo "warning, no pid file found - php-fpm is not running ?"
4135+ exit 1
4136+ fi
4137+
4138+ kill -QUIT `cat $php_fpm_PID`
4139+
4140+ wait_for_pid removed $php_fpm_PID
4141+
4142+ if [ -n "$try" ] ; then
4143+ echo " failed. Use force-exit"
4144+ exit 1
4145+ else
4146+ echo " done"
4147+ fi
4148+ ;;
4149+
4150+ force-quit)
4151+ echo -n "Terminating @php_fpm_bin@ "
4152+
4153+ if [ ! -r $php_fpm_PID ] ; then
4154+ echo "warning, no pid file found - php-fpm is not running ?"
4155+ exit 1
4156+ fi
4157+
4158+ kill -TERM `cat $php_fpm_PID`
4159+
4160+ wait_for_pid removed $php_fpm_PID
4161+
4162+ if [ -n "$try" ] ; then
4163+ echo " failed"
4164+ exit 1
4165+ else
4166+ echo " done"
4167+ fi
4168+ ;;
4169+
4170+ restart)
4171+ $0 stop
4172+ $0 start
4173+ ;;
4174+
4175+ reload)
4176+
4177+ echo -n "Reload service @php_fpm_bin@ "
4178+
4179+ if [ ! -r $php_fpm_PID ] ; then
4180+ echo "warning, no pid file found - @php_fpm_bin@ is not running ?"
4181+ exit 1
4182+ fi
4183+
4184+ kill -USR2 `cat $php_fpm_PID`
4185+
4186+ echo " done"
4187+ ;;
4188+
4189+ *)
4190+ echo "Usage: $0 {start|stop|force-quit|restart|reload}"
4191+ exit 1
4192+ ;;
4193+
4194+esac
4195diff -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
4198@@ -0,0 +1,46 @@
4199+# @php_fpm_bin@ - PHP FastCGI Process Manager 'PHP-FPM'
4200+#
4201+# nginx-site-conf.sample:
4202+# Php Site configuration for nginx webserver
4203+#
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.
4208+#
4209+
4210+server {
4211+
4212+ root /var/www/nginx-site;
4213+
4214+ server_name localhost;
4215+ listen 80;
4216+
4217+ access_log /var/log/nginx/localhost.access.log;
4218+
4219+ location / {
4220+ index index.html index.htm;
4221+ }
4222+
4223+ #error_page 404 /404.html;
4224+
4225+ # redirect server error pages to the static page /50x.html
4226+ #
4227+ error_page 500 502 503 504 /50x.html;
4228+ location = /50x.html {
4229+ root /var/www/nginx-default;
4230+ }
4231+
4232+ # pass the *.php scripts to @php_fpm_bin@ listening on tcp port @php_fpm_port@
4233+ #
4234+ location ~ \.php$ {
4235+
4236+ fastcgi_pass 127.0.0.1:@php_fpm_port@;
4237+ fastcgi_index index.php;
4238+
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;
4243+ }
4244+}
4245diff -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
4248@@ -0,0 +1,159 @@
4249+<?xml version="1.0" ?>
4250+<configuration>
4251+
4252+ All relative paths in this config are relative to php's install prefix
4253+
4254+ <section name="global_options">
4255+
4256+ Pid file
4257+ <value name="pid_file">@php_fpm_pid_path@</value>
4258+
4259+ Error log file
4260+ <value name="error_log">@php_fpm_log_path@</value>
4261+
4262+ Log level
4263+ <value name="log_level">notice</value>
4264+
4265+ When this amount of php processes exited with SIGSEGV or SIGBUS ...
4266+ <value name="emergency_restart_threshold">10</value>
4267+
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>
4271+
4272+ Time limit on waiting child's reaction on signals from master
4273+ <value name="process_control_timeout">5s</value>
4274+
4275+ Set to 'no' to debug fpm
4276+ <value name="daemonize">yes</value>
4277+
4278+ </section>
4279+
4280+ <workers>
4281+
4282+ <section name="pool">
4283+
4284+ Name of pool. Used in logs and stats.
4285+ <value name="name">default</value>
4286+
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>
4290+
4291+ <value name="listen_options">
4292+
4293+ Set listen(2) backlog
4294+ <value name="backlog">-1</value>
4295+
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>
4302+ </value>
4303+
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> -->
4311+ </value>
4312+
4313+ Unix user of processes
4314+ <value name="user">@php_fpm_user@</value>
4315+
4316+ Unix group of processes
4317+ <value name="group">@php_fpm_group@</value>
4318+
4319+ Process manager settings
4320+ <value name="pm">
4321+
4322+ Sets style of controling worker process count.
4323+ Valid values are 'static' and 'apache-like'
4324+ <value name="style">static</value>
4325+
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>
4331+
4332+ Settings group for 'apache-like' pm style
4333+ <value name="apache_like">
4334+
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>
4338+
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>
4342+
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>
4346+
4347+ </value>
4348+
4349+ </value>
4350+
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
4353+ '0s' means 'off'
4354+ <value name="request_terminate_timeout">0s</value>
4355+
4356+ The timeout (in seconds) for serving of single request after which a php backtrace will be dumped to slow.log file
4357+ '0s' means 'off'
4358+ <value name="request_slowlog_timeout">0s</value>
4359+
4360+ The log file for slow requests
4361+ <value name="slowlog">@php_fpm_log_path@.slow</value>
4362+
4363+ Set open file desc rlimit
4364+ <value name="rlimit_files">1024</value>
4365+
4366+ Set max core size rlimit
4367+ <value name="rlimit_core">0</value>
4368+
4369+ Chroot to this directory at the start, absolute path
4370+ <value name="chroot"></value>
4371+
4372+ Chdir to this directory at the start, absolute path
4373+ <value name="chdir"></value>
4374+
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>
4378+
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>
4384+
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>
4389+
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>
4401+ </value>
4402+
4403+ </section>
4404+
4405+ </workers>
4406+
4407+</configuration>
4408diff -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
4411@@ -0,0 +1,26 @@
4412+dnl
4413+dnl $Id$
4414+dnl
4415+
4416+PHP_ARG_WITH(fpm,,
4417+[ --with-fpm Build PHP FastCGI - FPM executable], no)
4418+
4419+if test "$PHP_FPM" != "no"; then
4420+
4421+ PHP_CONFIGURE_PART(Configuring fpm)
4422+
4423+ sinclude(sapi/fpm/ac/fpm_libevent.m4)
4424+ AC_LIB_EVENT([1.4.3],[1.4.11])
4425+
4426+ sinclude(sapi/fpm/ac/fpm_checks.m4)
4427+ AC_FPM_CHECKS
4428+
4429+ sinclude(sapi/fpm/ac/fpm_conf.m4)
4430+ fpm_version="0.6"
4431+ AC_FPM_CONF
4432+
4433+ sinclude(sapi/fpm/ac/fpm_build.m4)
4434+ AC_FPM_BUILD_SAPI
4435+
4436+ AC_MSG_RESULT()
4437+fi
4438diff -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
4441@@ -0,0 +1,110 @@
4442+
4443+ /* $Id$ */
4444+ /* (c) 2007,2008 Andrei Nigmatulin */
4445+
4446+#ifndef FPM_ARRAYS_H
4447+#define FPM_ARRAYS_H 1
4448+
4449+#include <stdlib.h>
4450+#include <string.h>
4451+
4452+struct fpm_array_s {
4453+ void *data;
4454+ size_t sz;
4455+ size_t used;
4456+ size_t allocated;
4457+};
4458+
4459+static inline struct fpm_array_s *fpm_array_init(struct fpm_array_s *a, unsigned int sz, unsigned int initial_num)
4460+{
4461+ void *allocated = 0;
4462+
4463+ if (!a) {
4464+ a = malloc(sizeof(struct fpm_array_s));
4465+
4466+ if (!a) {
4467+ return 0;
4468+ }
4469+
4470+ allocated = a;
4471+ }
4472+
4473+ a->sz = sz;
4474+
4475+ a->data = calloc(sz, initial_num);
4476+
4477+ if (!a->data) {
4478+ free(allocated);
4479+ return 0;
4480+ }
4481+
4482+ a->allocated = initial_num;
4483+ a->used = 0;
4484+
4485+ return a;
4486+}
4487+
4488+static inline void *fpm_array_item(struct fpm_array_s *a, unsigned int n)
4489+{
4490+ char *ret;
4491+
4492+ ret = (char *) a->data + a->sz * n;
4493+
4494+ return ret;
4495+}
4496+
4497+static inline void *fpm_array_item_last(struct fpm_array_s *a)
4498+{
4499+ return fpm_array_item(a, a->used - 1);
4500+}
4501+
4502+static inline int fpm_array_item_remove(struct fpm_array_s *a, unsigned int n)
4503+{
4504+ int ret = -1;
4505+
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);
4509+
4510+ memcpy(to_remove, last, a->sz);
4511+
4512+ ret = n;
4513+ }
4514+
4515+ --a->used;
4516+
4517+ return ret;
4518+}
4519+
4520+static inline void *fpm_array_push(struct fpm_array_s *a)
4521+{
4522+ void *ret;
4523+
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);
4527+
4528+ if (!new_ptr) {
4529+ return 0;
4530+ }
4531+
4532+ a->data = new_ptr;
4533+ a->allocated = new_allocated;
4534+ }
4535+
4536+ ret = fpm_array_item(a, a->used);
4537+
4538+ ++a->used;
4539+
4540+ return ret;
4541+}
4542+
4543+static inline void fpm_array_free(struct fpm_array_s *a)
4544+{
4545+ free(a->data);
4546+ a->data = 0;
4547+ a->sz = 0;
4548+ a->used = a->allocated = 0;
4549+}
4550+
4551+#endif
4552diff -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
4555@@ -0,0 +1,139 @@
4556+
4557+ /* $Id$ */
4558+ /* (c) 2007,2008 Andrei Nigmatulin */
4559+
4560+#ifndef FPM_ATOMIC_H
4561+#define FPM_ATOMIC_H 1
4562+
4563+#if HAVE_INTTYPES_H
4564+#include <inttypes.h>
4565+#else
4566+#include <stdint.h>
4567+#endif
4568+#include <sched.h>
4569+
4570+#if ( __i386__ || __i386 )
4571+
4572+typedef int32_t atomic_int_t;
4573+typedef uint32_t atomic_uint_t;
4574+typedef volatile atomic_uint_t atomic_t;
4575+
4576+
4577+static inline atomic_int_t atomic_fetch_add(atomic_t *value, atomic_int_t add)
4578+{
4579+ __asm__ volatile ( "lock;" "xaddl %0, %1;" :
4580+ "+r" (add) : "m" (*value) : "memory");
4581+
4582+ return add;
4583+}
4584+
4585+static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set)
4586+{
4587+ unsigned char res;
4588+
4589+ __asm__ volatile ( "lock;" "cmpxchgl %3, %1;" "sete %0;" :
4590+ "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory");
4591+
4592+ return res;
4593+}
4594+
4595+#elif ( __amd64__ || __amd64 )
4596+
4597+typedef int64_t atomic_int_t;
4598+typedef uint64_t atomic_uint_t;
4599+typedef volatile atomic_uint_t atomic_t;
4600+
4601+static inline atomic_int_t atomic_fetch_add(atomic_t *value, atomic_int_t add)
4602+{
4603+ __asm__ volatile ( "lock;" "xaddq %0, %1;" :
4604+ "+r" (add) : "m" (*value) : "memory");
4605+
4606+ return add;
4607+}
4608+
4609+static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set)
4610+{
4611+ unsigned char res;
4612+
4613+ __asm__ volatile ( "lock;" "cmpxchgq %3, %1;" "sete %0;" :
4614+ "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory");
4615+
4616+ return res;
4617+}
4618+
4619+#if (__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
4620+
4621+#elif ( __arm__ || __arm ) /* W-Mark Kubacki */
4622+
4623+#if (__arch64__ || __arch64)
4624+typedef int64_t atomic_int_t;
4625+typedef uint64_t atomic_uint_t;
4626+#else
4627+typedef int32_t atomic_int_t;
4628+typedef uint32_t atomic_uint_t;
4629+#endif
4630+
4631+#define atomic_cmp_set(a,b,c) __sync_bool_compare_and_swap(a,b,c)
4632+
4633+#endif /* defined (__GNUC__) &&... */
4634+
4635+#elif ( __sparc__ || __sparc ) /* Marcin Ochab */
4636+
4637+#if (__arch64__ || __arch64)
4638+typedef uint64_t atomic_uint_t;
4639+typedef volatile atomic_uint_t atomic_t;
4640+
4641+static inline int atomic_cas_64(atomic_t *lock, atomic_uint_t old, atomic_uint_t new)
4642+{
4643+ __asm__ __volatile__("casx [%2], %3, %0 " : "=&r"(new) : "0"(new), "r"(lock), "r"(old): "memory");
4644+
4645+ return new;
4646+}
4647+
4648+static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set)
4649+{
4650+ return (atomic_cas_64(lock, old, set)==old);
4651+}
4652+#else
4653+typedef uint32_t atomic_uint_t;
4654+typedef volatile atomic_uint_t atomic_t;
4655+
4656+static inline int atomic_cas_32(atomic_t *lock, atomic_uint_t old, atomic_uint_t new)
4657+{
4658+ __asm__ __volatile__("cas [%2], %3, %0 " : "=&r"(new) : "0"(new), "r"(lock), "r"(old): "memory");
4659+
4660+ return new;
4661+}
4662+
4663+static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set)
4664+{
4665+ return (atomic_cas_32(lock, old, set)==old);
4666+}
4667+#endif
4668+
4669+#else
4670+
4671+#error unsupported architecture. please write a patch and send it in
4672+
4673+#endif
4674+
4675+static inline int fpm_spinlock(atomic_t *lock, int try_once)
4676+{
4677+ if (try_once) {
4678+ return atomic_cmp_set(lock, 0, 1) ? 0 : -1;
4679+ }
4680+
4681+ for (;;) {
4682+
4683+ if (atomic_cmp_set(lock, 0, 1)) {
4684+ break;
4685+ }
4686+
4687+ sched_yield();
4688+ }
4689+
4690+ return 0;
4691+}
4692+
4693+#endif
4694+
4695diff -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
4698@@ -0,0 +1,82 @@
4699+
4700+ /* $Id$ */
4701+ /* (c) 2007,2008 Andrei Nigmatulin */
4702+
4703+#include "fpm_config.h"
4704+
4705+#include <stdlib.h> /* for exit */
4706+
4707+#include "fpm.h"
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"
4720+#include "zlog.h"
4721+
4722+struct fpm_globals_s fpm_globals;
4723+
4724+int fpm_init(int argc, char **argv, char *config)
4725+{
4726+ fpm_globals.argc = argc;
4727+ fpm_globals.argv = argv;
4728+ fpm_globals.config = config;
4729+
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()) {
4741+ return -1;
4742+ }
4743+
4744+ if (0 > fpm_conf_write_pid()) {
4745+ return -1;
4746+ }
4747+
4748+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "fpm is running, pid %d", (int) fpm_globals.parent_pid);
4749+
4750+ return 0;
4751+}
4752+
4753+/* children: return listening socket
4754+ parent: never return */
4755+int fpm_run(int *max_requests)
4756+{
4757+ struct fpm_worker_pool_s *wp;
4758+
4759+ /* create initial children in all pools */
4760+ for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
4761+ int is_parent;
4762+
4763+ is_parent = fpm_children_create_initial(wp);
4764+
4765+ if (!is_parent) {
4766+ goto run_child;
4767+ }
4768+ }
4769+
4770+ /* run event loop forever */
4771+ fpm_event_loop();
4772+
4773+run_child: /* only workers reach this point */
4774+
4775+ fpm_cleanups_run(FPM_CLEANUP_CHILD);
4776+
4777+ *max_requests = fpm_globals.max_requests;
4778+ return fpm_globals.listening_socket;
4779+}
4780+
4781diff -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
4784@@ -0,0 +1,387 @@
4785+
4786+ /* $Id$ */
4787+ /* (c) 2007,2008 Andrei Nigmatulin */
4788+
4789+#include "fpm_config.h"
4790+
4791+#include <sys/types.h>
4792+#include <sys/wait.h>
4793+#include <time.h>
4794+#include <unistd.h>
4795+#include <string.h>
4796+#include <stdio.h>
4797+
4798+#include "fpm.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"
4813+
4814+#include "zlog.h"
4815+
4816+static time_t *last_faults;
4817+static int fault;
4818+
4819+static int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop);
4820+
4821+static void fpm_children_cleanup(int which, void *arg)
4822+{
4823+ free(last_faults);
4824+}
4825+
4826+static struct fpm_child_s *fpm_child_alloc()
4827+{
4828+ struct fpm_child_s *ret;
4829+
4830+ ret = malloc(sizeof(struct fpm_child_s));
4831+
4832+ if (!ret) { return 0; }
4833+
4834+ memset(ret, 0, sizeof(*ret));
4835+
4836+ return ret;
4837+}
4838+
4839+static void fpm_child_free(struct fpm_child_s *child)
4840+{
4841+ free(child);
4842+}
4843+
4844+static void fpm_child_close(struct fpm_child_s *child, int in_event_loop)
4845+{
4846+ if (child->fd_stdout != -1) {
4847+ if (in_event_loop) {
4848+ fpm_event_fire(&child->ev_stdout);
4849+ }
4850+ if (child->fd_stdout != -1) {
4851+ close(child->fd_stdout);
4852+ }
4853+ }
4854+
4855+ if (child->fd_stderr != -1) {
4856+ if (in_event_loop) {
4857+ fpm_event_fire(&child->ev_stderr);
4858+ }
4859+ if (child->fd_stderr != -1) {
4860+ close(child->fd_stderr);
4861+ }
4862+ }
4863+
4864+ fpm_child_free(child);
4865+}
4866+
4867+static void fpm_child_link(struct fpm_child_s *child)
4868+{
4869+ struct fpm_worker_pool_s *wp = child->wp;
4870+
4871+ ++wp->running_children;
4872+ ++fpm_globals.running_children;
4873+
4874+ child->next = wp->children;
4875+ if (child->next) { child->next->prev = child; }
4876+ child->prev = 0;
4877+ wp->children = child;
4878+}
4879+
4880+static void fpm_child_unlink(struct fpm_child_s *child)
4881+{
4882+ --child->wp->running_children;
4883+ --fpm_globals.running_children;
4884+
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; }
4888+
4889+}
4890+
4891+static struct fpm_child_s *fpm_child_find(pid_t pid)
4892+{
4893+ struct fpm_worker_pool_s *wp;
4894+ struct fpm_child_s *child = 0;
4895+
4896+ for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
4897+
4898+ for (child = wp->children; child; child = child->next) {
4899+ if (child->pid == pid) {
4900+ break;
4901+ }
4902+ }
4903+
4904+ if (child) {
4905+ break;
4906+ }
4907+ }
4908+
4909+ if (!child) {
4910+ return 0;
4911+ }
4912+
4913+ return child;
4914+}
4915+
4916+static void fpm_child_init(struct fpm_worker_pool_s *wp)
4917+{
4918+ fpm_globals.max_requests = wp->config->max_requests;
4919+
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)) {
4925+
4926+ zlog(ZLOG_STUFF, ZLOG_ERROR, "child failed to initialize (pool %s)", wp->config->name);
4927+ exit(255);
4928+ }
4929+}
4930+
4931+int fpm_children_free(struct fpm_child_s *child)
4932+{
4933+ struct fpm_child_s *next;
4934+
4935+ for (; child; child = next) {
4936+ next = child->next;
4937+ fpm_child_close(child, 0 /* in_event_loop */);
4938+ }
4939+
4940+ return 0;
4941+}
4942+
4943+void fpm_children_bury()
4944+{
4945+ int status;
4946+ pid_t pid;
4947+ struct fpm_child_s *child;
4948+
4949+ while ( (pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
4950+ char buf[128];
4951+ int severity = ZLOG_NOTICE;
4952+
4953+ child = fpm_child_find(pid);
4954+
4955+ if (WIFEXITED(status)) {
4956+
4957+ snprintf(buf, sizeof(buf), "with code %d", WEXITSTATUS(status));
4958+
4959+ if (WEXITSTATUS(status) != 0) {
4960+ severity = ZLOG_WARNING;
4961+ }
4962+
4963+ }
4964+ else if (WIFSIGNALED(status)) {
4965+ const char *signame = fpm_signal_names[WTERMSIG(status)];
4966+ const char *have_core = WCOREDUMP(status) ? " (core dumped)" : "";
4967+
4968+ if (signame == NULL) {
4969+ signame = "";
4970+ }
4971+
4972+ snprintf(buf, sizeof(buf), "on signal %d %s%s", WTERMSIG(status), signame, have_core);
4973+
4974+ if (WTERMSIG(status) != SIGQUIT) { /* possible request loss */
4975+ severity = ZLOG_WARNING;
4976+ }
4977+ }
4978+ else if (WIFSTOPPED(status)) {
4979+
4980+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "child %d stopped for tracing", (int) pid);
4981+
4982+ if (child && child->tracer) {
4983+ child->tracer(child);
4984+ }
4985+
4986+ continue;
4987+ }
4988+
4989+ if (child) {
4990+ struct fpm_worker_pool_s *wp = child->wp;
4991+ struct timeval tv1, tv2;
4992+
4993+ fpm_child_unlink(child);
4994+
4995+ fpm_shm_slots_discard_slot(child);
4996+
4997+ fpm_clock_get(&tv1);
4998+
4999+ timersub(&tv1, &child->started, &tv2);
5000+
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);
5003+
5004+ fpm_child_close(child, 1 /* in event_loop */);
5005+
5006+ fpm_pctl_child_exited();
5007+
5008+ if (last_faults && (WTERMSIG(status) == SIGSEGV || WTERMSIG(status) == SIGBUS)) {
5009+ time_t now = tv1.tv_sec;
5010+ int restart_condition = 1;
5011+ int i;
5012+
5013+ last_faults[fault++] = now;
5014+
5015+ if (fault == fpm_global_config.emergency_restart_threshold) {
5016+ fault = 0;
5017+ }
5018+
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;
5022+ break;
5023+ }
5024+ }
5025+
5026+ if (restart_condition) {
5027+
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);
5030+
5031+ fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET);
5032+ }
5033+ }
5034+
5035+ fpm_children_make(wp, 1 /* in event loop */);
5036+
5037+ if (fpm_globals.is_child) {
5038+ break;
5039+ }
5040+ }
5041+ else {
5042+ zlog(ZLOG_STUFF, ZLOG_ALERT, "oops, unknown child exited %s", buf);
5043+ }
5044+ }
5045+
5046+}
5047+
5048+static struct fpm_child_s *fpm_resources_prepare(struct fpm_worker_pool_s *wp)
5049+{
5050+ struct fpm_child_s *c;
5051+
5052+ c = fpm_child_alloc();
5053+
5054+ if (!c) {
5055+ zlog(ZLOG_STUFF, ZLOG_ERROR, "malloc failed (pool %s)", wp->config->name);
5056+ return 0;
5057+ }
5058+
5059+ c->wp = wp;
5060+ c->fd_stdout = -1; c->fd_stderr = -1;
5061+
5062+ if (0 > fpm_stdio_prepare_pipes(c)) {
5063+ fpm_child_free(c);
5064+ return 0;
5065+ }
5066+
5067+ if (0 > fpm_shm_slots_prepare_slot(c)) {
5068+ fpm_stdio_discard_pipes(c);
5069+ fpm_child_free(c);
5070+ return 0;
5071+ }
5072+
5073+ return c;
5074+}
5075+
5076+static void fpm_resources_discard(struct fpm_child_s *child)
5077+{
5078+ fpm_shm_slots_discard_slot(child);
5079+ fpm_stdio_discard_pipes(child);
5080+ fpm_child_free(child);
5081+}
5082+
5083+static void fpm_child_resources_use(struct fpm_child_s *child)
5084+{
5085+ fpm_shm_slots_child_use_slot(child);
5086+ fpm_stdio_child_use_pipes(child);
5087+ fpm_child_free(child);
5088+}
5089+
5090+static void fpm_parent_resources_use(struct fpm_child_s *child)
5091+{
5092+ fpm_shm_slots_parent_use_slot(child);
5093+ fpm_stdio_parent_use_pipes(child);
5094+ fpm_child_link(child);
5095+}
5096+
5097+static int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop)
5098+{
5099+ int enough = 0;
5100+ pid_t pid;
5101+ struct fpm_child_s *child;
5102+
5103+ while (!enough && fpm_pctl_can_spawn_children() && wp->running_children < wp->config->pm->max_children) {
5104+
5105+ child = fpm_resources_prepare(wp);
5106+
5107+ if (!child) {
5108+ enough = 1;
5109+ break;
5110+ }
5111+
5112+ pid = fork();
5113+
5114+ switch (pid) {
5115+
5116+ case 0 :
5117+ fpm_child_resources_use(child);
5118+ fpm_globals.is_child = 1;
5119+ if (in_event_loop) {
5120+ fpm_event_exit_loop();
5121+ }
5122+ fpm_child_init(wp);
5123+ return 0;
5124+
5125+ case -1 :
5126+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fork() failed");
5127+ enough = 1;
5128+
5129+ fpm_resources_discard(child);
5130+
5131+ break; /* dont try any more on error */
5132+
5133+ default :
5134+ child->pid = pid;
5135+ fpm_clock_get(&child->started);
5136+ fpm_parent_resources_use(child);
5137+
5138+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "child %d (pool %s) started", (int) pid, wp->config->name);
5139+ }
5140+
5141+ }
5142+
5143+ return 1; /* we are done */
5144+}
5145+
5146+int fpm_children_create_initial(struct fpm_worker_pool_s *wp)
5147+{
5148+ return fpm_children_make(wp, 0 /* not in event loop yet */);
5149+}
5150+
5151+int fpm_children_init_main()
5152+{
5153+ if (fpm_global_config.emergency_restart_threshold &&
5154+ fpm_global_config.emergency_restart_interval) {
5155+
5156+ last_faults = malloc(sizeof(time_t) * fpm_global_config.emergency_restart_threshold);
5157+
5158+ if (!last_faults) {
5159+ return -1;
5160+ }
5161+
5162+ memset(last_faults, 0, sizeof(time_t) * fpm_global_config.emergency_restart_threshold);
5163+ }
5164+
5165+ if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_children_cleanup, 0)) {
5166+ return -1;
5167+ }
5168+
5169+ return 0;
5170+}
5171+
5172diff -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
5175@@ -0,0 +1,33 @@
5176+
5177+ /* $Id$ */
5178+ /* (c) 2007,2008 Andrei Nigmatulin */
5179+
5180+#ifndef FPM_CHILDREN_H
5181+#define FPM_CHILDREN_H 1
5182+
5183+#include <sys/time.h>
5184+#include <sys/types.h>
5185+#include <event.h>
5186+
5187+#include "fpm_worker_pool.h"
5188+
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();
5193+
5194+struct fpm_child_s;
5195+
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;
5201+ int shm_slot_i;
5202+ int fd_stdout, fd_stderr;
5203+ void (*tracer)(struct fpm_child_s *);
5204+ struct timeval slow_logged;
5205+ pid_t pid;
5206+};
5207+
5208+#endif
5209diff -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
5212@@ -0,0 +1,51 @@
5213+
5214+ /* $Id$ */
5215+ /* (c) 2007,2008 Andrei Nigmatulin */
5216+
5217+#include "fpm_config.h"
5218+
5219+#include <stdlib.h>
5220+
5221+#include "fpm_arrays.h"
5222+#include "fpm_cleanup.h"
5223+#include "zlog.h"
5224+
5225+struct cleanup_s {
5226+ int type;
5227+ void (*cleanup)(int, void *);
5228+ void *arg;
5229+};
5230+
5231+static struct fpm_array_s cleanups = { .sz = sizeof(struct cleanup_s) };
5232+
5233+int fpm_cleanup_add(int type, void (*cleanup)(int, void *), void *arg)
5234+{
5235+ struct cleanup_s *c;
5236+
5237+ c = fpm_array_push(&cleanups);
5238+
5239+ if (!c) {
5240+ return -1;
5241+ }
5242+
5243+ c->type = type;
5244+ c->cleanup = cleanup;
5245+ c->arg = arg;
5246+
5247+ return 0;
5248+}
5249+
5250+void fpm_cleanups_run(int type)
5251+{
5252+ struct cleanup_s *c = fpm_array_item_last(&cleanups);
5253+ int cl = cleanups.used;
5254+
5255+ for ( ; cl--; c--) {
5256+ if (c->type & type) {
5257+ c->cleanup(type, c->arg);
5258+ }
5259+ }
5260+
5261+ fpm_array_free(&cleanups);
5262+}
5263+
5264diff -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
5267@@ -0,0 +1,21 @@
5268+
5269+ /* $Id$ */
5270+ /* (c) 2007,2008 Andrei Nigmatulin */
5271+
5272+#ifndef FPM_CLEANUP_H
5273+#define FPM_CLEANUP_H 1
5274+
5275+int fpm_cleanup_add(int type, void (*cleanup)(int, void *), void *);
5276+void fpm_cleanups_run(int type);
5277+
5278+enum {
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,
5285+};
5286+
5287+#endif
5288+
5289diff -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
5292@@ -0,0 +1,115 @@
5293+
5294+ /* $Id$ */
5295+ /* (c) 2007,2008 Andrei Nigmatulin */
5296+
5297+#include "fpm_config.h"
5298+
5299+#if defined(HAVE_CLOCK_GETTIME)
5300+#include <time.h> /* for CLOCK_MONOTONIC */
5301+#endif
5302+
5303+#include "fpm_clock.h"
5304+#include "zlog.h"
5305+
5306+
5307+/* posix monotonic clock - preferred source of time */
5308+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
5309+
5310+static int monotonic_works;
5311+
5312+int fpm_clock_init()
5313+{
5314+ struct timespec ts;
5315+
5316+ monotonic_works = 0;
5317+
5318+ if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) {
5319+ monotonic_works = 1;
5320+ }
5321+
5322+ return 0;
5323+}
5324+
5325+int fpm_clock_get(struct timeval *tv)
5326+{
5327+ if (monotonic_works) {
5328+ struct timespec ts;
5329+
5330+ if (0 > clock_gettime(CLOCK_MONOTONIC, &ts)) {
5331+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "clock_gettime() failed");
5332+ return -1;
5333+ }
5334+
5335+ tv->tv_sec = ts.tv_sec;
5336+ tv->tv_usec = ts.tv_nsec / 1000;
5337+ return 0;
5338+ }
5339+
5340+ return gettimeofday(tv, 0);
5341+}
5342+
5343+/* macosx clock */
5344+#elif defined(HAVE_CLOCK_GET_TIME)
5345+
5346+#include <mach/mach.h>
5347+#include <mach/clock.h>
5348+#include <mach/mach_error.h>
5349+
5350+static clock_serv_t mach_clock;
5351+
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()
5355+{
5356+ kern_return_t ret;
5357+ mach_timespec_t aTime;
5358+
5359+ ret = host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &mach_clock);
5360+
5361+ if (ret != KERN_SUCCESS) {
5362+ zlog(ZLOG_STUFF, ZLOG_ERROR, "host_get_clock_service() failed: %s", mach_error_string(ret));
5363+ return -1;
5364+ }
5365+
5366+ /* test if it works */
5367+ ret = clock_get_time(mach_clock, &aTime);
5368+
5369+ if (ret != KERN_SUCCESS) {
5370+ zlog(ZLOG_STUFF, ZLOG_ERROR, "clock_get_time() failed: %s", mach_error_string(ret));
5371+ return -1;
5372+ }
5373+
5374+ return 0;
5375+}
5376+
5377+int fpm_clock_get(struct timeval *tv)
5378+{
5379+ kern_return_t ret;
5380+ mach_timespec_t aTime;
5381+
5382+ ret = clock_get_time(mach_clock, &aTime);
5383+
5384+ if (ret != KERN_SUCCESS) {
5385+ zlog(ZLOG_STUFF, ZLOG_ERROR, "clock_get_time() failed: %s", mach_error_string(ret));
5386+ return -1;
5387+ }
5388+
5389+ tv->tv_sec = aTime.tv_sec;
5390+ tv->tv_usec = aTime.tv_nsec / 1000;
5391+
5392+ return 0;
5393+}
5394+
5395+#else /* no clock */
5396+
5397+int fpm_clock_init()
5398+{
5399+ return 0;
5400+}
5401+
5402+int fpm_clock_get(struct timeval *tv)
5403+{
5404+ return gettimeofday(tv, 0);
5405+}
5406+
5407+#endif
5408diff -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
5411@@ -0,0 +1,13 @@
5412+
5413+ /* $Id$ */
5414+ /* (c) 2007,2008 Andrei Nigmatulin */
5415+
5416+#ifndef FPM_CLOCK_H
5417+#define FPM_CLOCK_H 1
5418+
5419+#include <sys/time.h>
5420+
5421+int fpm_clock_init();
5422+int fpm_clock_get(struct timeval *tv);
5423+
5424+#endif
5425diff -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
5428@@ -0,0 +1,537 @@
5429+
5430+ /* $Id$ */
5431+ /* (c) 2007,2008 Andrei Nigmatulin */
5432+
5433+#include "fpm_config.h"
5434+
5435+#include <sys/types.h>
5436+#include <sys/stat.h>
5437+#include <fcntl.h>
5438+#include <string.h>
5439+#include <stdlib.h>
5440+#include <stddef.h>
5441+#if HAVE_INTTYPES_H
5442+#include <inttypes.h>
5443+#else
5444+#include <stdint.h>
5445+#endif
5446+
5447+#include <stdio.h>
5448+#include <unistd.h>
5449+
5450+#include "fpm.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"
5458+#include "zlog.h"
5459+
5460+
5461+struct fpm_global_config_s fpm_global_config;
5462+
5463+static void *fpm_global_config_ptr()
5464+{
5465+ return &fpm_global_config;
5466+}
5467+
5468+static char *fpm_conf_set_log_level(void **conf, char *name, void *vv, intptr_t offset)
5469+{
5470+ char *value = vv;
5471+
5472+ if (!strcmp(value, "debug")) {
5473+ fpm_globals.log_level = ZLOG_DEBUG;
5474+ }
5475+ else if (!strcmp(value, "notice")) {
5476+ fpm_globals.log_level = ZLOG_NOTICE;
5477+ }
5478+ else if (!strcmp(value, "warn")) {
5479+ fpm_globals.log_level = ZLOG_WARNING;
5480+ }
5481+ else if (!strcmp(value, "error")) {
5482+ fpm_globals.log_level = ZLOG_ERROR;
5483+ }
5484+ else if (!strcmp(value, "alert")) {
5485+ fpm_globals.log_level = ZLOG_ALERT;
5486+ }
5487+ else {
5488+ return "invalid value for 'log_level'";
5489+ }
5490+
5491+ return NULL;
5492+}
5493+
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 },
5505+ { 0, 0, 0, 0 }
5506+ }
5507+};
5508+
5509+static char *fpm_conf_set_pm_style(void **conf, char *name, void *vv, intptr_t offset)
5510+{
5511+ char *value = vv;
5512+ struct fpm_pm_s *c = *conf;
5513+
5514+ if (!strcmp(value, "static")) {
5515+ c->style = PM_STYLE_STATIC;
5516+ }
5517+ else if (!strcmp(value, "apache-like")) {
5518+ c->style = PM_STYLE_APACHE_LIKE;
5519+ }
5520+ else {
5521+ return "invalid value for 'style'";
5522+ }
5523+
5524+ return NULL;
5525+}
5526+
5527+static char *fpm_conf_set_rlimit_core(void **conf, char *name, void *vv, intptr_t offset)
5528+{
5529+ char *value = vv;
5530+ struct fpm_worker_pool_config_s *c = *conf;
5531+
5532+ if (!strcmp(value, "unlimited")) {
5533+ c->rlimit_core = -1;
5534+ }
5535+ else {
5536+ int int_value;
5537+ void *subconf = &int_value;
5538+ char *error;
5539+
5540+ error = xml_conf_set_slot_integer(&subconf, name, vv, 0);
5541+
5542+ if (error) { return error; }
5543+
5544+ if (int_value < 0) { return "invalid value for 'rlimit_core'"; }
5545+
5546+ c->rlimit_core = int_value;
5547+ }
5548+
5549+ return NULL;
5550+}
5551+
5552+static char *fpm_conf_set_catch_workers_output(void **conf, char *name, void *vv, intptr_t offset)
5553+{
5554+ struct fpm_worker_pool_config_s *c = *conf;
5555+ int int_value;
5556+ void *subconf = &int_value;
5557+ char *error;
5558+
5559+ error = xml_conf_set_slot_boolean(&subconf, name, vv, 0);
5560+
5561+ if (error) { return error; }
5562+
5563+ c->catch_workers_output = int_value;
5564+
5565+ return NULL;
5566+}
5567+
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) },
5574+ { 0, 0, 0, 0 }
5575+ }
5576+};
5577+
5578+static char *fpm_conf_set_apache_like_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
5579+{
5580+ return xml_conf_parse_section(conf, &fpm_conf_set_apache_like_subsection_conf, xml_node);
5581+}
5582+
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) },
5590+ { 0, 0, 0, 0 }
5591+ }
5592+};
5593+
5594+static char *fpm_conf_set_listen_options_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
5595+{
5596+ void *subconf = (char *) *conf + offset;
5597+ struct fpm_listen_options_s *lo;
5598+
5599+ lo = malloc(sizeof(*lo));
5600+
5601+ if (!lo) {
5602+ return "malloc() failed";
5603+ }
5604+
5605+ memset(lo, 0, sizeof(*lo));
5606+
5607+ lo->backlog = -1;
5608+
5609+ * (struct fpm_listen_options_s **) subconf = lo;
5610+
5611+ subconf = lo;
5612+
5613+ return xml_conf_parse_section(&subconf, &fpm_conf_set_listen_options_subsection_conf, xml_node);
5614+}
5615+
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) },
5622+ { 0, 0, 0, 0 }
5623+ }
5624+};
5625+
5626+static char *fpm_conf_set_pm_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
5627+{
5628+ void *subconf = (char *) *conf + offset;
5629+ struct fpm_pm_s *pm;
5630+
5631+ pm = malloc(sizeof(*pm));
5632+
5633+ if (!pm) {
5634+ return "fpm_conf_set_pm_subsection(): malloc failed";
5635+ }
5636+
5637+ memset(pm, 0, sizeof(*pm));
5638+
5639+ * (struct fpm_pm_s **) subconf = pm;
5640+
5641+ subconf = pm;
5642+
5643+ return xml_conf_parse_section(&subconf, &fpm_conf_set_pm_subsection_conf, xml_node);
5644+}
5645+
5646+static char *xml_conf_set_slot_key_value_pair(void **conf, char *name, void *vv, intptr_t offset)
5647+{
5648+ char *value = vv;
5649+ struct key_value_s *kv;
5650+ struct key_value_s ***parent = (struct key_value_s ***) conf;
5651+
5652+ kv = malloc(sizeof(*kv));
5653+
5654+ if (!kv) {
5655+ return "malloc() failed";
5656+ }
5657+
5658+ memset(kv, 0, sizeof(*kv));
5659+
5660+ kv->key = strdup(name);
5661+ kv->value = strdup(value);
5662+
5663+ if (!kv->key || !kv->value) {
5664+ return "xml_conf_set_slot_key_value_pair(): strdup() failed";
5665+ }
5666+
5667+ **parent = kv;
5668+
5669+ *parent = &kv->next;
5670+
5671+ return NULL;
5672+}
5673+
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 },
5678+ { 0, 0, 0, 0 }
5679+ }
5680+};
5681+
5682+static char *fpm_conf_set_key_value_pairs_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
5683+{
5684+ void *next_kv = (char *) *conf + offset;
5685+
5686+ return xml_conf_parse_section(&next_kv, &fpm_conf_set_key_value_pairs_subsection_conf, xml_node);
5687+}
5688+
5689+static void *fpm_worker_pool_config_alloc()
5690+{
5691+ static struct fpm_worker_pool_s *current_wp = 0;
5692+ struct fpm_worker_pool_s *wp;
5693+
5694+ wp = fpm_worker_pool_alloc();
5695+
5696+ if (!wp) { return 0; }
5697+
5698+ wp->config = malloc(sizeof(struct fpm_worker_pool_config_s));
5699+
5700+ if (!wp->config) { return 0; }
5701+
5702+ memset(wp->config, 0, sizeof(struct fpm_worker_pool_config_s));
5703+
5704+ if (current_wp) { current_wp->next = wp; }
5705+
5706+ current_wp = wp;
5707+
5708+ return wp->config;
5709+}
5710+
5711+int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc)
5712+{
5713+ struct key_value_s *kv, *kv_next;
5714+
5715+ free(wpc->name);
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);
5722+ }
5723+ for (kv = wpc->php_defines; kv; kv = kv_next) {
5724+ kv_next = kv->next;
5725+ free(kv->key);
5726+ free(kv->value);
5727+ free(kv);
5728+ }
5729+ for (kv = wpc->environment; kv; kv = kv_next) {
5730+ kv_next = kv->next;
5731+ free(kv->key);
5732+ free(kv->value);
5733+ free(kv);
5734+ }
5735+ free(wpc->pm);
5736+ free(wpc->user);
5737+ free(wpc->group);
5738+ free(wpc->chroot);
5739+ free(wpc->chdir);
5740+ free(wpc->allowed_clients);
5741+ free(wpc->slowlog);
5742+
5743+ return 0;
5744+}
5745+
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) },
5768+ { 0, 0, 0, 0 }
5769+ }
5770+};
5771+
5772+static struct xml_conf_section *fpm_conf_all_sections[] = {
5773+ &xml_section_fpm_global_options,
5774+ &xml_section_fpm_worker_pool_config,
5775+ 0
5776+};
5777+
5778+static int fpm_evaluate_full_path(char **path)
5779+{
5780+ if (**path != '/') {
5781+ char *full_path;
5782+
5783+ full_path = malloc(sizeof(PHP_PREFIX) + strlen(*path) + 1);
5784+
5785+ if (!full_path) { return -1; }
5786+
5787+ sprintf(full_path, "%s/%s", PHP_PREFIX, *path);
5788+
5789+ free(*path);
5790+
5791+ *path = full_path;
5792+ }
5793+
5794+ return 0;
5795+}
5796+
5797+static int fpm_conf_process_all_pools()
5798+{
5799+ struct fpm_worker_pool_s *wp;
5800+
5801+ if (!fpm_worker_all_pools) {
5802+ zlog(ZLOG_STUFF, ZLOG_ERROR, "at least one pool section must be specified in config file");
5803+ return -1;
5804+ }
5805+
5806+ for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
5807+
5808+ if (wp->config->listen_address && *wp->config->listen_address) {
5809+
5810+ wp->listen_address_domain = fpm_sockets_domain_from_address(wp->config->listen_address);
5811+
5812+ if (wp->listen_address_domain == FPM_AF_UNIX && *wp->config->listen_address != '/') {
5813+ fpm_evaluate_full_path(&wp->config->listen_address);
5814+ }
5815+
5816+ }
5817+ else {
5818+
5819+ wp->is_template = 1;
5820+
5821+ }
5822+
5823+ if (wp->config->request_slowlog_timeout) {
5824+#if HAVE_FPM_TRACE
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);
5828+ return -1;
5829+ }
5830+#else
5831+ static int warned = 0;
5832+
5833+ if (!warned) {
5834+ zlog(ZLOG_STUFF, ZLOG_WARNING, "pool %s: 'request_slowlog_timeout' is not supported on your system",
5835+ wp->config->name);
5836+ warned = 1;
5837+ }
5838+
5839+ wp->config->request_slowlog_timeout = 0;
5840+#endif
5841+ }
5842+
5843+ if (wp->config->request_slowlog_timeout && wp->config->slowlog && *wp->config->slowlog) {
5844+ int fd;
5845+
5846+ fpm_evaluate_full_path(&wp->config->slowlog);
5847+
5848+ if (wp->config->request_slowlog_timeout) {
5849+ fd = open(wp->config->slowlog, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
5850+
5851+ if (0 > fd) {
5852+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(%s) failed", wp->config->slowlog);
5853+ return -1;
5854+ }
5855+ close(fd);
5856+ }
5857+ }
5858+ }
5859+
5860+ return 0;
5861+}
5862+
5863+int fpm_conf_unlink_pid()
5864+{
5865+ if (fpm_global_config.pid_file) {
5866+
5867+ if (0 > unlink(fpm_global_config.pid_file)) {
5868+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "unlink(\"%s\") failed", fpm_global_config.pid_file);
5869+ return -1;
5870+ }
5871+
5872+ }
5873+
5874+ return 0;
5875+}
5876+
5877+int fpm_conf_write_pid()
5878+{
5879+ int fd;
5880+
5881+ if (fpm_global_config.pid_file) {
5882+ char buf[64];
5883+ int len;
5884+
5885+ unlink(fpm_global_config.pid_file);
5886+
5887+ fd = creat(fpm_global_config.pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
5888+
5889+ if (fd < 0) {
5890+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "creat(\"%s\") failed", fpm_global_config.pid_file);
5891+ return -1;
5892+ }
5893+
5894+ len = sprintf(buf, "%d", (int) fpm_globals.parent_pid);
5895+
5896+ if (len != write(fd, buf, len)) {
5897+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "write() failed");
5898+ return -1;
5899+ }
5900+
5901+ close(fd);
5902+ }
5903+
5904+ return 0;
5905+}
5906+
5907+static int fpm_conf_post_process()
5908+{
5909+ if (fpm_global_config.pid_file) {
5910+ fpm_evaluate_full_path(&fpm_global_config.pid_file);
5911+ }
5912+
5913+ if (!fpm_global_config.error_log) {
5914+ fpm_global_config.error_log = strdup(PHP_FPM_LOG_PATH);
5915+ }
5916+
5917+ fpm_evaluate_full_path(&fpm_global_config.error_log);
5918+
5919+ if (0 > fpm_stdio_open_error_log(0)) {
5920+ return -1;
5921+ }
5922+
5923+ return fpm_conf_process_all_pools();
5924+}
5925+
5926+static void fpm_conf_cleanup(int which, void *arg)
5927+{
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;
5932+}
5933+
5934+int fpm_conf_init_main()
5935+{
5936+ char *filename = fpm_globals.config;
5937+ char *err;
5938+
5939+ if (0 > xml_conf_sections_register(fpm_conf_all_sections)) {
5940+ return -1;
5941+ }
5942+
5943+ if (filename == NULL) {
5944+ filename = PHP_FPM_CONF_PATH;
5945+ }
5946+
5947+ err = xml_conf_load_file(filename);
5948+
5949+ if (err) {
5950+ zlog(ZLOG_STUFF, ZLOG_ERROR, "failed to load configuration file: %s", err);
5951+ return -1;
5952+ }
5953+
5954+ if (0 > fpm_conf_post_process()) {
5955+ return -1;
5956+ }
5957+
5958+ xml_conf_clean();
5959+
5960+ if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_conf_cleanup, 0)) {
5961+ return -1;
5962+ }
5963+
5964+ return 0;
5965+}
5966diff -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
5969@@ -0,0 +1,73 @@
5970+
5971+ /* $Id$ */
5972+ /* (c) 2007,2008 Andrei Nigmatulin */
5973+
5974+#ifndef FPM_CONF_H
5975+#define FPM_CONF_H 1
5976+
5977+struct key_value_s;
5978+
5979+struct key_value_s {
5980+ struct key_value_s *next;
5981+ char *key;
5982+ char *value;
5983+};
5984+
5985+struct fpm_global_config_s {
5986+ int emergency_restart_threshold;
5987+ int emergency_restart_interval;
5988+ int process_control_timeout;
5989+ int daemonize;
5990+ char *pid_file;
5991+ char *error_log;
5992+};
5993+
5994+extern struct fpm_global_config_s fpm_global_config;
5995+
5996+struct fpm_pm_s {
5997+ int style;
5998+ int max_children;
5999+ struct {
6000+ int StartServers;
6001+ int MinSpareServers;
6002+ int MaxSpareServers;
6003+ } options_apache_like;
6004+};
6005+
6006+struct fpm_listen_options_s {
6007+ int backlog;
6008+ char *owner;
6009+ char *group;
6010+ char *mode;
6011+};
6012+
6013+struct fpm_worker_pool_config_s {
6014+ char *name;
6015+ char *listen_address;
6016+ struct fpm_listen_options_s *listen_options;
6017+ struct key_value_s *php_defines;
6018+ char *user;
6019+ char *group;
6020+ char *chroot;
6021+ char *chdir;
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;
6027+ char *slowlog;
6028+ int max_requests;
6029+ int rlimit_files;
6030+ int rlimit_core;
6031+ unsigned catch_workers_output:1;
6032+};
6033+
6034+enum { PM_STYLE_STATIC = 1, PM_STYLE_APACHE_LIKE = 2 };
6035+
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();
6040+
6041+#endif
6042+
6043diff -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
6046@@ -0,0 +1,40 @@
6047+
6048+ /* $Id$ */
6049+ /* (c) 2007,2008 Andrei Nigmatulin */
6050+
6051+#include <php_config.h>
6052+#ifdef FPM_AUTOCONFIG_H
6053+#include <fpm_autoconfig.h>
6054+#endif
6055+
6056+/* Solaris does not have it */
6057+#ifndef INADDR_NONE
6058+#define INADDR_NONE (-1)
6059+#endif
6060+
6061+
6062+/* If we're not using GNU C, elide __attribute__ */
6063+#ifndef __GNUC__
6064+# define __attribute__(x) /*NOTHING*/
6065+#endif
6066+
6067+
6068+/* Solaris does not have it */
6069+#ifndef timersub
6070+#define timersub(tvp, uvp, vvp) \
6071+ do { \
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; \
6077+ } \
6078+ } while (0)
6079+#endif
6080+
6081+#if defined(HAVE_PTRACE) || defined(PROC_MEM_FILE) || defined(HAVE_MACH_VM_READ)
6082+#define HAVE_FPM_TRACE 1
6083+#else
6084+#define HAVE_FPM_TRACE 0
6085+#endif
6086+
6087diff -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
6090@@ -0,0 +1,175 @@
6091+
6092+ /* $Id$ */
6093+ /* (c) 2007,2008 Andrei Nigmatulin */
6094+
6095+#include "fpm_config.h"
6096+
6097+#ifdef HAVE_ALLOCA_H
6098+#include <alloca.h>
6099+#endif
6100+#include <stdio.h>
6101+#include <stdlib.h>
6102+#include <string.h>
6103+
6104+#include "fpm_env.h"
6105+#include "zlog.h"
6106+
6107+#ifndef HAVE_SETENV
6108+#ifdef (__sparc__ || __sparc)
6109+int setenv(name, value, clobber)
6110+char *name;
6111+char *value;
6112+int clobber;
6113+{
6114+ char *malloc();
6115+ char *getenv();
6116+ char *cp;
6117+
6118+ if (clobber == 0 && getenv(name) != 0)
6119+ { return (0); }
6120+ if ((cp = malloc(strlen(name) + strlen(value) + 2)) == 0)
6121+ { return (1); }
6122+ sprintf(cp, "%s=%s", name, value);
6123+ return (putenv(cp));
6124+}
6125+#else
6126+int setenv(char *name, char *value, int overwrite)
6127+{
6128+ int name_len = strlen(name);
6129+ int value_len = strlen(value);
6130+ char *var = alloca(name_len + 1 + value_len + 1);
6131+
6132+ memcpy(var, name, name_len);
6133+
6134+ var[name_len] = '=';
6135+
6136+ memcpy(var + name_len + 1, value, value_len);
6137+
6138+ var[name_len + 1 + value_len] = '\0';
6139+
6140+ return putenv(var);
6141+}
6142+#endif
6143+#endif
6144+
6145+#ifndef HAVE_CLEARENV
6146+void clearenv()
6147+{
6148+ char **envp;
6149+ char *s;
6150+
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, '=');
6155+
6156+ s = strdup(*envp);
6157+
6158+ if (eq) { s[eq - *envp] = '\0'; }
6159+
6160+ unsetenv(s);
6161+ free(s);
6162+ }
6163+
6164+}
6165+#endif
6166+
6167+#ifndef HAVE_UNSETENV
6168+void unsetenv(const char *name)
6169+{
6170+ if(getenv(name)!=NULL)
6171+ {
6172+ int ct=0;
6173+ int del=0;
6174+
6175+ while(environ[ct] != NULL)
6176+ {
6177+ if (nvmatch(name, environ[ct]) != 0) del=ct;
6178+ { ct++; }
6179+ }
6180+ /* isn't needed free here?? */
6181+ environ[del]=environ[ct-1];
6182+ environ[ct-1]=NULL;
6183+ }
6184+}
6185+static char * nvmatch(s1, s2)
6186+register char *s1, *s2;
6187+{
6188+ while(*s1 == *s2++)
6189+ {
6190+ if(*s1++ == '=')
6191+ { return(s2); }
6192+ }
6193+ if(*s1 == '\0' && *(s2-1) == '=')
6194+ { return(s2); }
6195+ return(NULL);
6196+}
6197+#endif
6198+
6199+int fpm_env_init_child(struct fpm_worker_pool_s *wp)
6200+{
6201+ struct key_value_s *kv;
6202+
6203+ clearenv();
6204+
6205+ for (kv = wp->config->environment; kv; kv = kv->next) {
6206+ setenv(kv->key, kv->value, 1);
6207+ }
6208+
6209+ if (wp->user) {
6210+ setenv("USER", wp->user, 1);
6211+ }
6212+
6213+ if (wp->home) {
6214+ setenv("HOME", wp->home, 1);
6215+ }
6216+
6217+ return 0;
6218+}
6219+
6220+static int fpm_env_conf_wp(struct fpm_worker_pool_s *wp)
6221+{
6222+ struct key_value_s *kv;
6223+
6224+ kv = wp->config->environment;
6225+
6226+ for (kv = wp->config->environment; kv; kv = kv->next) {
6227+ if (*kv->value == '$') {
6228+ char *value = getenv(kv->value + 1);
6229+
6230+ if (!value) { value = ""; }
6231+
6232+ free(kv->value);
6233+ kv->value = strdup(value);
6234+ }
6235+
6236+ /* autodetected values should be removed
6237+ if these vars specified in config */
6238+ if (!strcmp(kv->key, "USER")) {
6239+ free(wp->user);
6240+ wp->user = 0;
6241+ }
6242+
6243+ if (!strcmp(kv->key, "HOME")) {
6244+ free(wp->home);
6245+ wp->home = 0;
6246+ }
6247+ }
6248+
6249+ return 0;
6250+}
6251+
6252+int fpm_env_init_main()
6253+{
6254+ struct fpm_worker_pool_s *wp;
6255+
6256+ for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
6257+
6258+ if (0 > fpm_env_conf_wp(wp)) {
6259+ return -1;
6260+ }
6261+
6262+ }
6263+
6264+ return 0;
6265+}
6266diff -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
6269@@ -0,0 +1,24 @@
6270+
6271+ /* $Id$ */
6272+ /* (c) 2007,2008 Andrei Nigmatulin */
6273+
6274+#ifndef FPM_ENV_H
6275+#define FPM_ENV_H 1
6276+
6277+#include "fpm_worker_pool.h"
6278+
6279+int fpm_env_init_child(struct fpm_worker_pool_s *wp);
6280+int fpm_env_init_main();
6281+
6282+extern char **environ;
6283+
6284+#ifndef HAVE_SETENV
6285+int setenv(char *name, char *value, int overwrite);
6286+#endif
6287+
6288+#ifndef HAVE_CLEARENV
6289+void clearenv();
6290+#endif
6291+
6292+#endif
6293+
6294diff -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
6297@@ -0,0 +1,135 @@
6298+
6299+ /* $Id$ */
6300+ /* (c) 2007,2008 Andrei Nigmatulin */
6301+
6302+#include "fpm_config.h"
6303+
6304+#include <unistd.h>
6305+#include <errno.h>
6306+#include <stdlib.h> /* for putenv */
6307+#include <string.h>
6308+#include <sys/types.h> /* for event.h below */
6309+#include <event.h>
6310+
6311+#include "fpm.h"
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"
6318+#include "zlog.h"
6319+
6320+static void fpm_event_cleanup(int which, void *arg)
6321+{
6322+ event_base_free(0);
6323+}
6324+
6325+static void fpm_got_signal(int fd, short ev, void *arg)
6326+{
6327+ char c;
6328+ int res;
6329+
6330+ do {
6331+
6332+ do {
6333+ res = read(fd, &c, 1);
6334+ } while (res == -1 && errno == EINTR);
6335+
6336+ if (res <= 0) {
6337+ if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
6338+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "read() failed");
6339+ }
6340+ return;
6341+ }
6342+
6343+ switch (c) {
6344+ case 'C' : /* SIGCHLD */
6345+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGCHLD");
6346+ fpm_children_bury();
6347+ break;
6348+ case 'I' : /* SIGINT */
6349+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGINT");
6350+ fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
6351+ break;
6352+ case 'T' : /* SIGTERM */
6353+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGTERM");
6354+ fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
6355+ break;
6356+ case 'Q' : /* SIGQUIT */
6357+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGQUIT");
6358+ fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET);
6359+ break;
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");
6364+ }
6365+ break;
6366+ case '2' : /* SIGUSR2 */
6367+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGUSR2");
6368+ fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET);
6369+ break;
6370+ }
6371+
6372+ if (fpm_globals.is_child) {
6373+ break;
6374+ }
6375+
6376+ } while (1);
6377+
6378+ return;
6379+}
6380+
6381+int fpm_event_init_main()
6382+{
6383+ event_init();
6384+
6385+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "libevent: using %s", event_get_method());
6386+
6387+ if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, 0)) {
6388+ return -1;
6389+ }
6390+
6391+ return 0;
6392+}
6393+
6394+int fpm_event_loop()
6395+{
6396+ static struct event signal_fd_event;
6397+
6398+ event_set(&signal_fd_event, fpm_signals_get_fd(), EV_PERSIST | EV_READ, &fpm_got_signal, 0);
6399+
6400+ event_add(&signal_fd_event, 0);
6401+
6402+ fpm_pctl_heartbeat(-1, 0, 0);
6403+
6404+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "libevent: entering main loop");
6405+
6406+ event_loop(0);
6407+
6408+ return 0;
6409+}
6410+
6411+int fpm_event_add(int fd, struct event *ev, void (*callback)(int, short, void *), void *arg)
6412+{
6413+ event_set(ev, fd, EV_PERSIST | EV_READ, callback, arg);
6414+
6415+ return event_add(ev, 0);
6416+}
6417+
6418+int fpm_event_del(struct event *ev)
6419+{
6420+ return event_del(ev);
6421+}
6422+
6423+void fpm_event_exit_loop()
6424+{
6425+ event_loopbreak();
6426+}
6427+
6428+void fpm_event_fire(struct event *ev)
6429+{
6430+ (*ev->ev_callback)( (int) ev->ev_fd, (short) ev->ev_res, ev->ev_arg);
6431+}
6432+
6433diff -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
6436@@ -0,0 +1,16 @@
6437+
6438+ /* $Id$ */
6439+ /* (c) 2007,2008 Andrei Nigmatulin */
6440+
6441+#ifndef FPM_EVENTS_H
6442+#define FPM_EVENTS_H 1
6443+
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();
6450+
6451+
6452+#endif
6453diff -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
6456@@ -0,0 +1,28 @@
6457+
6458+ /* $Id$ */
6459+ /* (c) 2007,2008 Andrei Nigmatulin */
6460+
6461+#ifndef FPM_H
6462+#define FPM_H 1
6463+
6464+#include <unistd.h>
6465+
6466+int fpm_run(int *max_requests);
6467+int fpm_init(int argc, char **argv, char *config);
6468+
6469+struct fpm_globals_s {
6470+ pid_t parent_pid;
6471+ int argc;
6472+ char **argv;
6473+ char *config;
6474+ int running_children;
6475+ int error_log_fd;
6476+ int log_level;
6477+ int listening_socket; /* for this child */
6478+ int max_requests; /* for this child */
6479+ int is_child;
6480+};
6481+
6482+extern struct fpm_globals_s fpm_globals;
6483+
6484+#endif
6485diff -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
6488@@ -0,0 +1,189 @@
6489+
6490+ /* $Id$ */
6491+ /* (c) 2007,2008 Andrei Nigmatulin */
6492+
6493+#include "fpm_config.h"
6494+
6495+#include <stdlib.h>
6496+#include <string.h>
6497+#include <stdio.h>
6498+
6499+#include "php.h"
6500+#include "php_main.h"
6501+#include "php_ini.h"
6502+#include "ext/standard/dl.h"
6503+
6504+#include "cgi/fastcgi.h"
6505+
6506+#include "fpm.h"
6507+#include "fpm_php.h"
6508+#include "fpm_cleanup.h"
6509+#include "fpm_worker_pool.h"
6510+
6511+static int zend_ini_alter_master(char *name, int name_length, char *new_value, int new_value_length, int stage TSRMLS_DC)
6512+{
6513+ zend_ini_entry *ini_entry;
6514+ char *duplicate;
6515+
6516+ if (zend_hash_find(EG(ini_directives), name, name_length, (void **) &ini_entry) == FAILURE) {
6517+ return FAILURE;
6518+ }
6519+
6520+ duplicate = strdup(new_value);
6521+
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;
6527+ } else {
6528+ free(duplicate);
6529+ }
6530+
6531+ return SUCCESS;
6532+}
6533+
6534+static void fpm_php_disable(char *value, int (*zend_disable)(char *, uint TSRMLS_DC) TSRMLS_DC)
6535+{
6536+ char *s = 0, *e = value;
6537+
6538+ while (*e) {
6539+ switch (*e) {
6540+ case ' ':
6541+ case ',':
6542+ if (s) {
6543+ *e = '\0';
6544+ zend_disable(s, e - s TSRMLS_CC);
6545+ s = 0;
6546+ }
6547+ break;
6548+ default:
6549+ if (!s) {
6550+ s = e;
6551+ }
6552+ break;
6553+ }
6554+ e++;
6555+ }
6556+
6557+ if (s) {
6558+ zend_disable(s, e - s TSRMLS_CC);
6559+ }
6560+}
6561+
6562+static int fpm_php_apply_defines(struct fpm_worker_pool_s *wp)
6563+{
6564+ TSRMLS_FETCH();
6565+ struct key_value_s *kv;
6566+
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);
6572+
6573+ if (!strcmp(name, "extension") && *value) {
6574+ zval zv;
6575+
6576+#if defined(PHP_VERSION_ID) && (PHP_VERSION_ID >= 50300)
6577+ php_dl(value, MODULE_PERSISTENT, &zv, 1 TSRMLS_CC);
6578+#else
6579+ zval filename;
6580+ ZVAL_STRINGL(&filename, value, value_len, 0);
6581+#if (PHP_MAJOR_VERSION >= 5)
6582+ php_dl(&filename, MODULE_PERSISTENT, &zv, 1 TSRMLS_CC);
6583+#else
6584+ php_dl(&filename, MODULE_PERSISTENT, &zv TSRMLS_CC);
6585+#endif
6586+#endif
6587+ continue;
6588+ }
6589+
6590+ zend_ini_alter_master(name, name_len + 1, value, value_len, PHP_INI_STAGE_ACTIVATE TSRMLS_CC);
6591+
6592+ if (!strcmp(name, "disable_functions") && *value) {
6593+ char *v = strdup(value);
6594+#if (PHP_MAJOR_VERSION >= 5)
6595+ PG(disable_functions) = v;
6596+#endif
6597+ fpm_php_disable(v, zend_disable_function TSRMLS_CC);
6598+ }
6599+ else if (!strcmp(name, "disable_classes") && *value) {
6600+ char *v = strdup(value);
6601+#if (PHP_MAJOR_VERSION >= 5)
6602+ PG(disable_classes) = v;
6603+#endif
6604+ fpm_php_disable(v, zend_disable_class TSRMLS_CC);
6605+ }
6606+ }
6607+
6608+ return 0;
6609+}
6610+
6611+static int fpm_php_set_allowed_clients(struct fpm_worker_pool_s *wp)
6612+{
6613+ if (wp->listen_address_domain == FPM_AF_INET) {
6614+ fcgi_set_allowed_clients(wp->config->allowed_clients);
6615+ }
6616+
6617+ return 0;
6618+}
6619+
6620+static int fpm_php_set_fcgi_mgmt_vars(struct fpm_worker_pool_s *wp)
6621+{
6622+ char max_workers[10 + 1]; /* 4294967295 */
6623+ int len;
6624+
6625+ len = sprintf(max_workers, "%u", (unsigned int) wp->config->pm->max_children);
6626+
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);
6629+
6630+ return 0;
6631+}
6632+
6633+char *fpm_php_script_filename(TSRMLS_D)
6634+{
6635+ return SG(request_info).path_translated;
6636+}
6637+
6638+char *fpm_php_request_method(TSRMLS_D)
6639+{
6640+ return (char *) SG(request_info).request_method;
6641+}
6642+
6643+size_t fpm_php_content_length(TSRMLS_D)
6644+{
6645+ return SG(request_info).content_length;
6646+}
6647+
6648+static void fpm_php_cleanup(int which, void *arg)
6649+{
6650+ TSRMLS_FETCH();
6651+ php_module_shutdown(TSRMLS_C);
6652+ sapi_shutdown();
6653+}
6654+
6655+void fpm_php_soft_quit()
6656+{
6657+ fcgi_set_in_shutdown(1);
6658+}
6659+
6660+int fpm_php_init_main()
6661+{
6662+ if (0 > fpm_cleanup_add(FPM_CLEANUP_PARENT, fpm_php_cleanup, 0)) {
6663+ return -1;
6664+ }
6665+
6666+ return 0;
6667+}
6668+
6669+int fpm_php_init_child(struct fpm_worker_pool_s *wp)
6670+{
6671+ if (0 > fpm_php_apply_defines(wp) ||
6672+ 0 > fpm_php_set_allowed_clients(wp)) {
6673+ return -1;
6674+ }
6675+
6676+ return 0;
6677+}
6678diff -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
6681@@ -0,0 +1,22 @@
6682+
6683+ /* $Id$ */
6684+ /* (c) 2007,2008 Andrei Nigmatulin */
6685+
6686+#ifndef FPM_PHP_H
6687+#define FPM_PHP_H 1
6688+
6689+#include <TSRM.h>
6690+
6691+#include "build-defs.h" /* for PHP_ defines */
6692+
6693+struct fpm_worker_pool_s;
6694+
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();
6701+
6702+#endif
6703+
6704diff -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
6707@@ -0,0 +1,176 @@
6708+
6709+ /* $Id$ */
6710+ /* (c) 2007,2008 Andrei Nigmatulin */
6711+
6712+#include "fpm_config.h"
6713+
6714+#if HAVE_FPM_TRACE
6715+
6716+#include "php.h"
6717+#include "php_main.h"
6718+
6719+#include <stdio.h>
6720+#include <stddef.h>
6721+#if HAVE_INTTYPES_H
6722+#include <inttypes.h>
6723+#else
6724+#include <stdint.h>
6725+#endif
6726+
6727+#include <unistd.h>
6728+#include <sys/time.h>
6729+#include <sys/types.h>
6730+#include <errno.h>
6731+
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"
6737+
6738+#include "zlog.h"
6739+
6740+
6741+#define valid_ptr(p) ((p) && 0 == ((p) & (sizeof(long) - 1)))
6742+
6743+#if SIZEOF_LONG == 4
6744+#define PTR_FMT "08"
6745+#elif SIZEOF_LONG == 8
6746+#define PTR_FMT "016"
6747+#endif
6748+
6749+
6750+static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC)
6751+{
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;
6758+ long l;
6759+
6760+ gettimeofday(&tv, 0);
6761+
6762+ zlog_print_time(&tv, buf, buf_size);
6763+
6764+ fprintf(slowlog, "\n%s pid %d (pool %s)\n", buf, (int) pid, child->wp->config->name);
6765+
6766+ if (0 > fpm_trace_get_strz(buf, buf_size, (long) &SG(request_info).path_translated)) {
6767+ return -1;
6768+ }
6769+
6770+ fprintf(slowlog, "script_filename = %s\n", buf);
6771+
6772+ if (0 > fpm_trace_get_long((long) &EG(current_execute_data), &l)) {
6773+ return -1;
6774+ }
6775+
6776+ execute_data = l;
6777+
6778+ while (execute_data) {
6779+ long function;
6780+ uint lineno = 0;
6781+
6782+ fprintf(slowlog, "[0x%" PTR_FMT "lx] ", execute_data);
6783+
6784+ if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, function_state.function), &l)) {
6785+ return -1;
6786+ }
6787+
6788+ function = l;
6789+
6790+ if (valid_ptr(function)) {
6791+ if (0 > fpm_trace_get_strz(buf, buf_size, function + offsetof(zend_function, common.function_name))) {
6792+ return -1;
6793+ }
6794+
6795+ fprintf(slowlog, "%s()", buf);
6796+ }
6797+ else {
6798+ fprintf(slowlog, "???");
6799+ }
6800+
6801+ if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, op_array), &l)) {
6802+ return -1;
6803+ }
6804+
6805+ *buf = '\0';
6806+
6807+ if (valid_ptr(l)) {
6808+ long op_array = l;
6809+
6810+ if (0 > fpm_trace_get_strz(buf, buf_size, op_array + offsetof(zend_op_array, filename))) {
6811+ return -1;
6812+ }
6813+ }
6814+
6815+ if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, opline), &l)) {
6816+ return -1;
6817+ }
6818+
6819+ if (valid_ptr(l)) {
6820+ long opline = l;
6821+ uint *lu = (uint *) &l;
6822+
6823+ if (0 > fpm_trace_get_long(opline + offsetof(struct _zend_op, lineno), &l)) {
6824+ return -1;
6825+ }
6826+
6827+ lineno = *lu;
6828+ }
6829+
6830+ fprintf(slowlog, " %s:%u\n", *buf ? buf : "unknown", lineno);
6831+
6832+ if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, prev_execute_data), &l)) {
6833+ return -1;
6834+ }
6835+
6836+ execute_data = l;
6837+
6838+ if (0 == --callers_limit) {
6839+ break;
6840+ }
6841+ }
6842+
6843+ return 0;
6844+}
6845+
6846+void fpm_php_trace(struct fpm_child_s *child)
6847+{
6848+ TSRMLS_FETCH();
6849+ FILE *slowlog;
6850+
6851+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "about to trace %d", (int) child->pid);
6852+
6853+ slowlog = fopen(child->wp->config->slowlog, "a+");
6854+
6855+ if (!slowlog) {
6856+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fopen(%s) failed", child->wp->config->slowlog);
6857+ goto done0;
6858+ }
6859+
6860+ if (0 > fpm_trace_ready(child->pid)) {
6861+ goto done1;
6862+ }
6863+
6864+ if (0 > fpm_php_trace_dump(child, slowlog TSRMLS_CC)) {
6865+ fprintf(slowlog, "+++ dump failed\n");
6866+ }
6867+
6868+ if (0 > fpm_trace_close(child->pid)) {
6869+ goto done1;
6870+ }
6871+
6872+done1:
6873+ fclose(slowlog);
6874+
6875+done0:
6876+ fpm_pctl_kill(child->pid, FPM_PCTL_CONT);
6877+ child->tracer = 0;
6878+
6879+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "finished trace of %d", (int) child->pid);
6880+}
6881+
6882+#endif
6883+
6884diff -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
6887@@ -0,0 +1,13 @@
6888+
6889+ /* $Id$ */
6890+ /* (c) 2007,2008 Andrei Nigmatulin */
6891+
6892+#ifndef FPM_PHP_TRACE_H
6893+#define FPM_PHP_TRACE_H 1
6894+
6895+struct fpm_child_s;
6896+
6897+void fpm_php_trace(struct fpm_child_s *);
6898+
6899+#endif
6900+
6901diff -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
6904@@ -0,0 +1,354 @@
6905+
6906+ /* $Id$ */
6907+ /* (c) 2007,2008 Andrei Nigmatulin */
6908+
6909+#include "fpm_config.h"
6910+
6911+#include <sys/types.h>
6912+#include <signal.h>
6913+#include <unistd.h>
6914+#include <stdlib.h>
6915+
6916+#include "fpm.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"
6925+#include "zlog.h"
6926+
6927+
6928+static int fpm_state = FPM_PCTL_STATE_NORMAL;
6929+static int fpm_signal_sent = 0;
6930+
6931+
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"
6937+};
6938+
6939+static int saved_argc;
6940+static char **saved_argv;
6941+
6942+static void fpm_pctl_cleanup(int which, void *arg)
6943+{
6944+ int i;
6945+
6946+ if (which != FPM_CLEANUP_PARENT_EXEC) {
6947+
6948+ for (i = 0; i < saved_argc; i++) {
6949+ free(saved_argv[i]);
6950+ }
6951+
6952+ free(saved_argv);
6953+
6954+ }
6955+}
6956+
6957+static struct event pctl_event;
6958+
6959+static void fpm_pctl_action(int fd, short which, void *arg)
6960+{
6961+ evtimer_del(&pctl_event);
6962+
6963+ memset(&pctl_event, 0, sizeof(pctl_event));
6964+
6965+ fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_TIMEOUT);
6966+}
6967+
6968+static int fpm_pctl_timeout_set(int sec)
6969+{
6970+ struct timeval tv = { .tv_sec = sec, .tv_usec = 0 };
6971+
6972+ if (evtimer_initialized(&pctl_event)) {
6973+ evtimer_del(&pctl_event);
6974+ }
6975+
6976+ evtimer_set(&pctl_event, &fpm_pctl_action, 0);
6977+
6978+ evtimer_add(&pctl_event, &tv);
6979+
6980+ return 0;
6981+}
6982+
6983+static void fpm_pctl_exit()
6984+{
6985+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "exiting, bye-bye!");
6986+
6987+ fpm_conf_unlink_pid();
6988+
6989+ fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT_MAIN);
6990+
6991+ exit(0);
6992+}
6993+
6994+#define optional_arg(c) (saved_argc > c ? ", \"" : ""), (saved_argc > c ? saved_argv[c] : ""), (saved_argc > c ? "\"" : "")
6995+
6996+static void fpm_pctl_exec()
6997+{
6998+
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"
7002+ "})",
7003+ saved_argv[0], saved_argv[0],
7004+ optional_arg(1),
7005+ optional_arg(2),
7006+ optional_arg(3),
7007+ optional_arg(4),
7008+ optional_arg(5),
7009+ optional_arg(6),
7010+ optional_arg(7),
7011+ optional_arg(8),
7012+ optional_arg(9),
7013+ optional_arg(10)
7014+ );
7015+
7016+ fpm_cleanups_run(FPM_CLEANUP_PARENT_EXEC);
7017+
7018+ execvp(saved_argv[0], saved_argv);
7019+
7020+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "execvp() failed");
7021+
7022+ exit(1);
7023+}
7024+
7025+static void fpm_pctl_action_last()
7026+{
7027+ switch (fpm_state) {
7028+
7029+ case FPM_PCTL_STATE_RELOADING :
7030+
7031+ fpm_pctl_exec();
7032+ break;
7033+
7034+ case FPM_PCTL_STATE_FINISHING :
7035+
7036+ case FPM_PCTL_STATE_TERMINATING :
7037+
7038+ fpm_pctl_exit();
7039+ break;
7040+ }
7041+}
7042+
7043+int fpm_pctl_kill(pid_t pid, int how)
7044+{
7045+ int s = 0;
7046+
7047+ switch (how) {
7048+ case FPM_PCTL_TERM :
7049+ s = SIGTERM;
7050+ break;
7051+ case FPM_PCTL_STOP :
7052+ s = SIGSTOP;
7053+ break;
7054+ case FPM_PCTL_CONT :
7055+ s = SIGCONT;
7056+ break;
7057+ default :
7058+ break;
7059+ }
7060+
7061+ return kill(pid, s);
7062+}
7063+
7064+static void fpm_pctl_kill_all(int signo)
7065+{
7066+ struct fpm_worker_pool_s *wp;
7067+ int alive_children = 0;
7068+
7069+ for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
7070+ struct fpm_child_s *child;
7071+
7072+ for (child = wp->children; child; child = child->next) {
7073+
7074+ int res = kill(child->pid, signo);
7075+
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);
7079+
7080+ if (res == 0) { ++alive_children; }
7081+ }
7082+ }
7083+
7084+ if (alive_children) {
7085+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "%d %s still alive", alive_children, alive_children == 1 ? "child is" : "children are");
7086+ }
7087+}
7088+
7089+static void fpm_pctl_action_next()
7090+{
7091+ int sig, timeout;
7092+
7093+ if (!fpm_globals.running_children) { fpm_pctl_action_last(); }
7094+
7095+ if (fpm_signal_sent == 0) {
7096+ if (fpm_state == FPM_PCTL_STATE_TERMINATING) {
7097+ sig = SIGTERM;
7098+ }
7099+ else {
7100+ sig = SIGQUIT;
7101+ }
7102+ timeout = fpm_global_config.process_control_timeout;
7103+ }
7104+ else {
7105+ if (fpm_signal_sent == SIGQUIT) {
7106+ sig = SIGTERM;
7107+ }
7108+ else {
7109+ sig = SIGKILL;
7110+ }
7111+ timeout = 1;
7112+ }
7113+
7114+ fpm_pctl_kill_all(sig);
7115+
7116+ fpm_signal_sent = sig;
7117+
7118+ fpm_pctl_timeout_set(timeout);
7119+}
7120+
7121+void fpm_pctl(int new_state, int action)
7122+{
7123+ switch (action) {
7124+
7125+ case FPM_PCTL_ACTION_SET :
7126+
7127+ if (fpm_state == new_state) { /* already in progress - just ignore duplicate signal */
7128+ return;
7129+ }
7130+
7131+ switch (fpm_state) { /* check which states can be overridden */
7132+
7133+ case FPM_PCTL_STATE_NORMAL :
7134+
7135+ /* 'normal' can be overridden by any other state */
7136+ break;
7137+
7138+ case FPM_PCTL_STATE_RELOADING :
7139+
7140+ /* 'reloading' can be overridden by 'finishing' */
7141+ if (new_state == FPM_PCTL_STATE_FINISHING) { break; }
7142+
7143+ case FPM_PCTL_STATE_FINISHING :
7144+
7145+ /* 'reloading' and 'finishing' can be overridden by 'terminating' */
7146+ if (new_state == FPM_PCTL_STATE_TERMINATING) { break; }
7147+
7148+ case FPM_PCTL_STATE_TERMINATING :
7149+
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]);
7153+
7154+ return;
7155+ }
7156+
7157+ fpm_signal_sent = 0;
7158+ fpm_state = new_state;
7159+
7160+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "switching to '%s' state", fpm_state_names[fpm_state]);
7161+
7162+ /* fall down */
7163+
7164+ case FPM_PCTL_ACTION_TIMEOUT :
7165+
7166+ fpm_pctl_action_next();
7167+
7168+ break;
7169+
7170+ case FPM_PCTL_ACTION_LAST_CHILD_EXITED :
7171+
7172+ fpm_pctl_action_last();
7173+
7174+ break;
7175+
7176+ }
7177+}
7178+
7179+int fpm_pctl_can_spawn_children()
7180+{
7181+ return fpm_state == FPM_PCTL_STATE_NORMAL;
7182+}
7183+
7184+int fpm_pctl_child_exited()
7185+{
7186+ if (fpm_state == FPM_PCTL_STATE_NORMAL) { return 0; }
7187+
7188+ if (!fpm_globals.running_children) {
7189+ fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_LAST_CHILD_EXITED);
7190+ }
7191+
7192+ return 0;
7193+}
7194+
7195+int fpm_pctl_init_main()
7196+{
7197+ int i;
7198+
7199+ saved_argc = fpm_globals.argc;
7200+
7201+ saved_argv = malloc(sizeof(char *) * (saved_argc + 1));
7202+
7203+ if (!saved_argv) {
7204+ return -1;
7205+ }
7206+
7207+ for (i = 0; i < saved_argc; i++) {
7208+ saved_argv[i] = strdup(fpm_globals.argv[i]);
7209+
7210+ if (!saved_argv[i]) {
7211+ return -1;
7212+ }
7213+ }
7214+
7215+ saved_argv[i] = 0;
7216+
7217+ if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_pctl_cleanup, 0)) {
7218+ return -1;
7219+ }
7220+
7221+ return 0;
7222+}
7223+
7224+static void fpm_pctl_check_request_timeout(struct timeval *now)
7225+{
7226+ struct fpm_worker_pool_s *wp;
7227+
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;
7232+
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);
7236+ }
7237+ }
7238+ }
7239+
7240+}
7241+
7242+void fpm_pctl_heartbeat(int fd, short which, void *arg)
7243+{
7244+ static struct event heartbeat;
7245+ struct timeval tv = { .tv_sec = 0, .tv_usec = 130000 };
7246+ struct timeval now;
7247+
7248+ if (which == EV_TIMEOUT) {
7249+ evtimer_del(&heartbeat);
7250+ fpm_clock_get(&now);
7251+ fpm_pctl_check_request_timeout(&now);
7252+ }
7253+
7254+ evtimer_set(&heartbeat, &fpm_pctl_heartbeat, 0);
7255+
7256+ evtimer_add(&heartbeat, &tv);
7257+}
7258+
7259diff -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
7262@@ -0,0 +1,39 @@
7263+
7264+ /* $Id$ */
7265+ /* (c) 2007,2008 Andrei Nigmatulin */
7266+
7267+#ifndef FPM_PROCESS_CTL_H
7268+#define FPM_PROCESS_CTL_H 1
7269+
7270+struct fpm_child_s;
7271+
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();
7278+
7279+
7280+enum {
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
7286+};
7287+
7288+enum {
7289+ FPM_PCTL_ACTION_SET,
7290+ FPM_PCTL_ACTION_TIMEOUT,
7291+ FPM_PCTL_ACTION_LAST_CHILD_EXITED
7292+};
7293+
7294+enum {
7295+ FPM_PCTL_TERM,
7296+ FPM_PCTL_STOP,
7297+ FPM_PCTL_CONT
7298+};
7299+
7300+#endif
7301+
7302diff -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
7305@@ -0,0 +1,164 @@
7306+
7307+ /* $Id$ */
7308+ /* (c) 2007,2008 Andrei Nigmatulin */
7309+
7310+#include "fpm_config.h"
7311+
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"
7322+
7323+#include "zlog.h"
7324+
7325+void fpm_request_accepting()
7326+{
7327+ struct fpm_shm_slot_s *slot;
7328+
7329+ slot = fpm_shm_slots_acquire(0, 0);
7330+
7331+ slot->request_stage = FPM_REQUEST_ACCEPTING;
7332+
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));
7337+
7338+ fpm_shm_slots_release(slot);
7339+}
7340+
7341+void fpm_request_reading_headers()
7342+{
7343+ struct fpm_shm_slot_s *slot;
7344+
7345+ slot = fpm_shm_slots_acquire(0, 0);
7346+
7347+ slot->request_stage = FPM_REQUEST_READING_HEADERS;
7348+
7349+ fpm_clock_get(&slot->tv);
7350+ slot->accepted = slot->tv;
7351+
7352+ fpm_shm_slots_release(slot);
7353+}
7354+
7355+void fpm_request_info()
7356+{
7357+ TSRMLS_FETCH();
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);
7361+
7362+ slot = fpm_shm_slots_acquire(0, 0);
7363+
7364+ slot->request_stage = FPM_REQUEST_INFO;
7365+
7366+ fpm_clock_get(&slot->tv);
7367+
7368+ if (request_method) {
7369+ cpystrn(slot->request_method, request_method, sizeof(slot->request_method));
7370+ }
7371+
7372+ slot->content_length = fpm_php_content_length(TSRMLS_C);
7373+
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));
7378+ }
7379+
7380+ fpm_shm_slots_release(slot);
7381+}
7382+
7383+void fpm_request_executing()
7384+{
7385+ struct fpm_shm_slot_s *slot;
7386+
7387+ slot = fpm_shm_slots_acquire(0, 0);
7388+
7389+ slot->request_stage = FPM_REQUEST_EXECUTING;
7390+
7391+ fpm_clock_get(&slot->tv);
7392+
7393+ fpm_shm_slots_release(slot);
7394+}
7395+
7396+void fpm_request_finished()
7397+{
7398+ struct fpm_shm_slot_s *slot;
7399+
7400+ slot = fpm_shm_slots_acquire(0, 0);
7401+
7402+ slot->request_stage = FPM_REQUEST_FINISHED;
7403+
7404+ fpm_clock_get(&slot->tv);
7405+ memset(&slot->accepted, 0, sizeof(slot->accepted));
7406+
7407+ fpm_shm_slots_release(slot);
7408+}
7409+
7410+void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *now, int terminate_timeout, int slowlog_timeout)
7411+{
7412+ struct fpm_shm_slot_s *slot;
7413+ struct fpm_shm_slot_s slot_c;
7414+
7415+ slot = fpm_shm_slot(child);
7416+
7417+ if (!fpm_shm_slots_acquire(slot, 1)) {
7418+ return;
7419+ }
7420+
7421+ slot_c = *slot;
7422+
7423+ fpm_shm_slots_release(slot);
7424+
7425+#if HAVE_FPM_TRACE
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;
7430+ }
7431+ }
7432+#endif
7433+
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;
7437+
7438+ timersub(now, &slot_c.accepted, &tv);
7439+
7440+#if HAVE_FPM_TRACE
7441+ if (child->slow_logged.tv_sec == 0 && slowlog_timeout &&
7442+ slot_c.request_stage == FPM_REQUEST_EXECUTING && tv.tv_sec >= slowlog_timeout) {
7443+
7444+ str_purify_filename(purified_script_filename, slot_c.script_filename, sizeof(slot_c.script_filename));
7445+
7446+ child->slow_logged = slot_c.accepted;
7447+ child->tracer = fpm_php_trace;
7448+
7449+ fpm_trace_signal(child->pid);
7450+
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);
7453+ }
7454+
7455+ else
7456+#endif
7457+ if (terminate_timeout && tv.tv_sec >= terminate_timeout) {
7458+
7459+ str_purify_filename(purified_script_filename, slot_c.script_filename, sizeof(slot_c.script_filename));
7460+
7461+ fpm_pctl_kill(child->pid, FPM_PCTL_TERM);
7462+
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);
7465+ }
7466+ }
7467+
7468+}
7469+
7470diff -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
7473@@ -0,0 +1,27 @@
7474+
7475+ /* $Id$ */
7476+ /* (c) 2007,2008 Andrei Nigmatulin */
7477+
7478+#ifndef FPM_REQUEST_H
7479+#define FPM_REQUEST_H 1
7480+
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 */
7486+
7487+struct fpm_child_s;
7488+struct timeval;
7489+
7490+void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *tv, int terminate_timeout, int slowlog_timeout);
7491+
7492+enum fpm_request_stage_e {
7493+ FPM_REQUEST_ACCEPTING = 1,
7494+ FPM_REQUEST_READING_HEADERS,
7495+ FPM_REQUEST_INFO,
7496+ FPM_REQUEST_EXECUTING,
7497+ FPM_REQUEST_FINISHED
7498+};
7499+
7500+#endif
7501diff -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
7504@@ -0,0 +1,100 @@
7505+
7506+ /* $Id$ */
7507+ /* (c) 2007,2008 Andrei Nigmatulin */
7508+
7509+#include "fpm_config.h"
7510+
7511+#include <unistd.h>
7512+#include <sys/mman.h>
7513+#include <stdlib.h>
7514+
7515+#include "fpm_shm.h"
7516+#include "zlog.h"
7517+
7518+
7519+/* MAP_ANON is depricated, but not in macosx */
7520+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
7521+#define MAP_ANONYMOUS MAP_ANON
7522+#endif
7523+
7524+
7525+struct fpm_shm_s *fpm_shm_alloc(size_t sz)
7526+{
7527+ struct fpm_shm_s *shm;
7528+
7529+ shm = malloc(sizeof(*shm));
7530+
7531+ if (!shm) {
7532+ return 0;
7533+ }
7534+
7535+ shm->mem = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
7536+
7537+ if (!shm->mem) {
7538+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "mmap(MAP_ANONYMOUS | MAP_SHARED) failed");
7539+ free(shm);
7540+ return 0;
7541+ }
7542+
7543+ shm->used = 0;
7544+ shm->sz = sz;
7545+
7546+ return shm;
7547+}
7548+
7549+static void fpm_shm_free(struct fpm_shm_s *shm, int do_unmap)
7550+{
7551+ if (do_unmap) {
7552+ munmap(shm->mem, shm->sz);
7553+ }
7554+
7555+ free(shm);
7556+}
7557+
7558+void fpm_shm_free_list(struct fpm_shm_s *shm, void *mem)
7559+{
7560+ struct fpm_shm_s *next;
7561+
7562+ for (; shm; shm = next) {
7563+ next = shm->next;
7564+
7565+ fpm_shm_free(shm, mem != shm->mem);
7566+ }
7567+}
7568+
7569+void *fpm_shm_alloc_chunk(struct fpm_shm_s **head, size_t sz, void **mem)
7570+{
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;
7575+ void *ret;
7576+
7577+ sz = (sz + cache_line_size - 1) & -cache_line_size;
7578+
7579+ shm = *head;
7580+
7581+ if (0 == shm || shm->sz - shm->used < sz) {
7582+ /* allocate one more shm segment */
7583+
7584+ aligned_sz = (sz + pagesize - 1) & -pagesize;
7585+
7586+ shm = fpm_shm_alloc(aligned_sz);
7587+
7588+ if (!shm) {
7589+ return 0;
7590+ }
7591+
7592+ shm->next = *head;
7593+ if (shm->next) { shm->next->prev = shm; }
7594+ shm->prev = 0;
7595+ *head = shm;
7596+ }
7597+
7598+ *mem = shm->mem;
7599+ ret = (char *) shm->mem + shm->used;
7600+ shm->used += sz;
7601+
7602+ return ret;
7603+}
7604+
7605diff -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
7608@@ -0,0 +1,22 @@
7609+
7610+ /* $Id$ */
7611+ /* (c) 2007,2008 Andrei Nigmatulin */
7612+
7613+#ifndef FPM_SHM_H
7614+#define FPM_SHM_H 1
7615+
7616+struct fpm_shm_s;
7617+
7618+struct fpm_shm_s {
7619+ struct fpm_shm_s *prev, *next;
7620+ void *mem;
7621+ size_t sz;
7622+ size_t used;
7623+};
7624+
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);
7628+
7629+#endif
7630+
7631diff -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
7634@@ -0,0 +1,127 @@
7635+
7636+ /* $Id$ */
7637+ /* (c) 2007,2008 Andrei Nigmatulin */
7638+
7639+#include "fpm_config.h"
7640+
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"
7646+#include "zlog.h"
7647+
7648+static void *shm_mem;
7649+static struct fpm_shm_slot_s *shm_slot;
7650+
7651+int fpm_shm_slots_prepare_slot(struct fpm_child_s *child)
7652+{
7653+ struct fpm_worker_pool_s *wp = child->wp;
7654+ struct fpm_shm_slot_ptr_s *shm_slot_ptr;
7655+
7656+ child->shm_slot_i = wp->slots_used.used;
7657+
7658+ shm_slot_ptr = fpm_array_push(&wp->slots_used);
7659+
7660+ if (0 == shm_slot_ptr) {
7661+ return -1;
7662+ }
7663+
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);
7666+
7667+ if (!shm_slot_ptr->shm_slot) {
7668+ return -1;
7669+ }
7670+ }
7671+ else {
7672+ *shm_slot_ptr = *(struct fpm_shm_slot_ptr_s *) fpm_array_item_last(&wp->slots_free);
7673+
7674+ --wp->slots_free.used;
7675+ }
7676+
7677+ memset(shm_slot_ptr->shm_slot, 0, sizeof(struct fpm_shm_slot_s));
7678+
7679+ shm_slot_ptr->child = child;
7680+
7681+ return 0;
7682+}
7683+
7684+void fpm_shm_slots_discard_slot(struct fpm_child_s *child)
7685+{
7686+ struct fpm_shm_slot_ptr_s *shm_slot_ptr;
7687+ struct fpm_worker_pool_s *wp = child->wp;
7688+ int n;
7689+
7690+ shm_slot_ptr = fpm_array_push(&wp->slots_free);
7691+
7692+ if (shm_slot_ptr) {
7693+
7694+ struct fpm_shm_slot_ptr_s *shm_slot_ptr_used;
7695+
7696+ shm_slot_ptr_used = fpm_array_item(&wp->slots_used, child->shm_slot_i);
7697+
7698+ *shm_slot_ptr = *shm_slot_ptr_used;
7699+
7700+ shm_slot_ptr->child = 0;
7701+
7702+ }
7703+
7704+ n = fpm_array_item_remove(&wp->slots_used, child->shm_slot_i);
7705+
7706+ if (n > -1) {
7707+ shm_slot_ptr = fpm_array_item(&wp->slots_used, n);
7708+
7709+ shm_slot_ptr->child->shm_slot_i = n;
7710+ }
7711+}
7712+
7713+void fpm_shm_slots_child_use_slot(struct fpm_child_s *child)
7714+{
7715+ struct fpm_shm_slot_ptr_s *shm_slot_ptr;
7716+ struct fpm_worker_pool_s *wp = child->wp;
7717+
7718+ shm_slot_ptr = fpm_array_item(&wp->slots_used, child->shm_slot_i);
7719+
7720+ shm_slot = shm_slot_ptr->shm_slot;
7721+ shm_mem = shm_slot_ptr->mem;
7722+}
7723+
7724+void fpm_shm_slots_parent_use_slot(struct fpm_child_s *child)
7725+{
7726+ /* nothing to do */
7727+}
7728+
7729+void *fpm_shm_slots_mem()
7730+{
7731+ return shm_mem;
7732+}
7733+
7734+struct fpm_shm_slot_s *fpm_shm_slot(struct fpm_child_s *child)
7735+{
7736+ struct fpm_shm_slot_ptr_s *shm_slot_ptr;
7737+ struct fpm_worker_pool_s *wp = child->wp;
7738+
7739+ shm_slot_ptr = fpm_array_item(&wp->slots_used, child->shm_slot_i);
7740+
7741+ return shm_slot_ptr->shm_slot;
7742+}
7743+
7744+struct fpm_shm_slot_s *fpm_shm_slots_acquire(struct fpm_shm_slot_s *s, int nohang)
7745+{
7746+ if (s == 0) {
7747+ s = shm_slot;
7748+ }
7749+
7750+ if (0 > fpm_spinlock(&s->lock, nohang)) {
7751+ return 0;
7752+ }
7753+
7754+ return s;
7755+}
7756+
7757+void fpm_shm_slots_release(struct fpm_shm_slot_s *s)
7758+{
7759+ s->lock = 0;
7760+}
7761+
7762diff -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
7765@@ -0,0 +1,43 @@
7766+
7767+ /* $Id$ */
7768+ /* (c) 2007,2008 Andrei Nigmatulin */
7769+
7770+#ifndef FPM_SHM_SLOTS_H
7771+#define FPM_SHM_SLOTS_H 1
7772+
7773+#include "fpm_atomic.h"
7774+#include "fpm_worker_pool.h"
7775+#include "fpm_request.h"
7776+
7777+struct fpm_child_s;
7778+
7779+struct fpm_shm_slot_s {
7780+ union {
7781+ atomic_t lock;
7782+ char dummy[16];
7783+ };
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];
7790+};
7791+
7792+struct fpm_shm_slot_ptr_s {
7793+ void *mem;
7794+ struct fpm_shm_slot_s *shm_slot;
7795+ struct fpm_child_s *child;
7796+};
7797+
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 *);
7806+
7807+#endif
7808+
7809diff -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
7812@@ -0,0 +1,252 @@
7813+
7814+ /* $Id$ */
7815+ /* (c) 2007,2008 Andrei Nigmatulin */
7816+
7817+#include "fpm_config.h"
7818+
7819+#include <signal.h>
7820+#include <stdio.h>
7821+#include <sys/types.h>
7822+#include <sys/socket.h>
7823+#include <stdlib.h>
7824+#include <string.h>
7825+#include <fcntl.h>
7826+#include <unistd.h>
7827+#include <errno.h>
7828+
7829+#include "fpm.h"
7830+#include "fpm_signals.h"
7831+#include "fpm_sockets.h"
7832+#include "fpm_php.h"
7833+#include "zlog.h"
7834+
7835+static int sp[2];
7836+
7837+const char *fpm_signal_names[NSIG + 1] = {
7838+#ifdef SIGHUP
7839+ [SIGHUP] = "SIGHUP",
7840+#endif
7841+#ifdef SIGINT
7842+ [SIGINT] = "SIGINT",
7843+#endif
7844+#ifdef SIGQUIT
7845+ [SIGQUIT] = "SIGQUIT",
7846+#endif
7847+#ifdef SIGILL
7848+ [SIGILL] = "SIGILL",
7849+#endif
7850+#ifdef SIGTRAP
7851+ [SIGTRAP] = "SIGTRAP",
7852+#endif
7853+#ifdef SIGABRT
7854+ [SIGABRT] = "SIGABRT",
7855+#endif
7856+#ifdef SIGEMT
7857+ [SIGEMT] = "SIGEMT",
7858+#endif
7859+#ifdef SIGBUS
7860+ [SIGBUS] = "SIGBUS",
7861+#endif
7862+#ifdef SIGFPE
7863+ [SIGFPE] = "SIGFPE",
7864+#endif
7865+#ifdef SIGKILL
7866+ [SIGKILL] = "SIGKILL",
7867+#endif
7868+#ifdef SIGUSR1
7869+ [SIGUSR1] = "SIGUSR1",
7870+#endif
7871+#ifdef SIGSEGV
7872+ [SIGSEGV] = "SIGSEGV",
7873+#endif
7874+#ifdef SIGUSR2
7875+ [SIGUSR2] = "SIGUSR2",
7876+#endif
7877+#ifdef SIGPIPE
7878+ [SIGPIPE] = "SIGPIPE",
7879+#endif
7880+#ifdef SIGALRM
7881+ [SIGALRM] = "SIGALRM",
7882+#endif
7883+#ifdef SIGTERM
7884+ [SIGTERM] = "SIGTERM",
7885+#endif
7886+#ifdef SIGCHLD
7887+ [SIGCHLD] = "SIGCHLD",
7888+#endif
7889+#ifdef SIGCONT
7890+ [SIGCONT] = "SIGCONT",
7891+#endif
7892+#ifdef SIGSTOP
7893+ [SIGSTOP] = "SIGSTOP",
7894+#endif
7895+#ifdef SIGTSTP
7896+ [SIGTSTP] = "SIGTSTP",
7897+#endif
7898+#ifdef SIGTTIN
7899+ [SIGTTIN] = "SIGTTIN",
7900+#endif
7901+#ifdef SIGTTOU
7902+ [SIGTTOU] = "SIGTTOU",
7903+#endif
7904+#ifdef SIGURG
7905+ [SIGURG] = "SIGURG",
7906+#endif
7907+#ifdef SIGXCPU
7908+ [SIGXCPU] = "SIGXCPU",
7909+#endif
7910+#ifdef SIGXFSZ
7911+ [SIGXFSZ] = "SIGXFSZ",
7912+#endif
7913+#ifdef SIGVTALRM
7914+ [SIGVTALRM] = "SIGVTALRM",
7915+#endif
7916+#ifdef SIGPROF
7917+ [SIGPROF] = "SIGPROF",
7918+#endif
7919+#ifdef SIGWINCH
7920+ [SIGWINCH] = "SIGWINCH",
7921+#endif
7922+#ifdef SIGINFO
7923+ [SIGINFO] = "SIGINFO",
7924+#endif
7925+#ifdef SIGIO
7926+ [SIGIO] = "SIGIO",
7927+#endif
7928+#ifdef SIGPWR
7929+ [SIGPWR] = "SIGPWR",
7930+#endif
7931+#ifdef SIGSYS
7932+ [SIGSYS] = "SIGSYS",
7933+#endif
7934+#ifdef SIGWAITING
7935+ [SIGWAITING] = "SIGWAITING",
7936+#endif
7937+#ifdef SIGLWP
7938+ [SIGLWP] = "SIGLWP",
7939+#endif
7940+#ifdef SIGFREEZE
7941+ [SIGFREEZE] = "SIGFREEZE",
7942+#endif
7943+#ifdef SIGTHAW
7944+ [SIGTHAW] = "SIGTHAW",
7945+#endif
7946+#ifdef SIGCANCEL
7947+ [SIGCANCEL] = "SIGCANCEL",
7948+#endif
7949+#ifdef SIGLOST
7950+ [SIGLOST] = "SIGLOST",
7951+#endif
7952+};
7953+
7954+static void sig_soft_quit(int signo)
7955+{
7956+ int saved_errno = errno;
7957+
7958+ /* closing fastcgi listening socket will force fcgi_accept() exit immediately */
7959+ close(0);
7960+ socket(AF_UNIX, SOCK_STREAM, 0);
7961+
7962+ fpm_php_soft_quit();
7963+
7964+ errno = saved_errno;
7965+}
7966+
7967+static void sig_handler(int signo)
7968+{
7969+ static const char sig_chars[NSIG + 1] = {
7970+ [SIGTERM] = 'T',
7971+ [SIGINT] = 'I',
7972+ [SIGUSR1] = '1',
7973+ [SIGUSR2] = '2',
7974+ [SIGQUIT] = 'Q',
7975+ [SIGCHLD] = 'C'
7976+ };
7977+ char s;
7978+ int saved_errno;
7979+
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 */
7983+ return;
7984+ }
7985+
7986+ saved_errno = errno;
7987+
7988+ s = sig_chars[signo];
7989+
7990+ write(sp[1], &s, sizeof(s));
7991+
7992+ errno = saved_errno;
7993+}
7994+
7995+int fpm_signals_init_main()
7996+{
7997+ struct sigaction act;
7998+
7999+ if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) {
8000+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "socketpair() failed");
8001+ return -1;
8002+ }
8003+
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");
8006+ return -1;
8007+ }
8008+
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");
8011+ return -1;
8012+ }
8013+
8014+ memset(&act, 0, sizeof(act));
8015+ act.sa_handler = sig_handler;
8016+ sigfillset(&act.sa_mask);
8017+
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)) {
8024+
8025+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "sigaction() failed");
8026+ return -1;
8027+ }
8028+
8029+ return 0;
8030+}
8031+
8032+int fpm_signals_init_child()
8033+{
8034+ struct sigaction act, act_dfl;
8035+
8036+ memset(&act, 0, sizeof(act));
8037+ memset(&act_dfl, 0, sizeof(act_dfl));
8038+
8039+ act.sa_handler = &sig_soft_quit;
8040+ act.sa_flags |= SA_RESTART;
8041+
8042+ act_dfl.sa_handler = SIG_DFL;
8043+
8044+ close(sp[0]);
8045+ close(sp[1]);
8046+
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)) {
8053+
8054+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "sigaction() failed");
8055+ return -1;
8056+ }
8057+
8058+ return 0;
8059+}
8060+
8061+int fpm_signals_get_fd()
8062+{
8063+ return sp[0];
8064+}
8065diff -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
8068@@ -0,0 +1,16 @@
8069+
8070+ /* $Id$ */
8071+ /* (c) 2007,2008 Andrei Nigmatulin */
8072+
8073+#ifndef FPM_SIGNALS_H
8074+#define FPM_SIGNALS_H 1
8075+
8076+#include <signal.h>
8077+
8078+int fpm_signals_init_main();
8079+int fpm_signals_init_child();
8080+int fpm_signals_get_fd();
8081+
8082+extern const char *fpm_signal_names[NSIG + 1];
8083+
8084+#endif
8085diff -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
8088@@ -0,0 +1,427 @@
8089+
8090+ /* $Id$ */
8091+ /* (c) 2007,2008 Andrei Nigmatulin */
8092+
8093+#include "fpm_config.h"
8094+
8095+#ifdef HAVE_ALLOCA_H
8096+#include <alloca.h>
8097+#endif
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>
8104+#include <netdb.h>
8105+#include <stdio.h>
8106+#include <stdlib.h>
8107+#include <string.h>
8108+#include <errno.h>
8109+#include <unistd.h>
8110+
8111+#include "zlog.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"
8119+
8120+struct listening_socket_s {
8121+ int refcount;
8122+ int sock;
8123+ int type;
8124+ char *key;
8125+};
8126+
8127+static struct fpm_array_s sockets_list;
8128+
8129+static int fpm_sockets_resolve_af_inet(char *node, char *service, struct sockaddr_in *addr)
8130+{
8131+ struct addrinfo *res;
8132+ struct addrinfo hints;
8133+ int ret;
8134+
8135+ memset(&hints, 0, sizeof(hints));
8136+
8137+ hints.ai_family = AF_INET;
8138+
8139+ ret = getaddrinfo(node, service, &hints, &res);
8140+
8141+ if (ret != 0) {
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) : "");
8145+ return -1;
8146+ }
8147+
8148+ *addr = *(struct sockaddr_in *) res->ai_addr;
8149+
8150+ freeaddrinfo(res);
8151+
8152+ return 0;
8153+}
8154+
8155+enum { FPM_GET_USE_SOCKET = 1, FPM_STORE_SOCKET = 2, FPM_STORE_USE_SOCKET = 3 };
8156+
8157+static void fpm_sockets_cleanup(int which, void *arg)
8158+{
8159+ int i;
8160+ char *env_value = 0;
8161+ int p = 0;
8162+ struct listening_socket_s *ls = sockets_list.data;
8163+
8164+ for (i = 0; i < sockets_list.used; i++, ls++) {
8165+
8166+ if (which != FPM_CLEANUP_PARENT_EXEC) {
8167+
8168+ close(ls->sock);
8169+
8170+ }
8171+ else { /* on PARENT EXEC we want socket fds to be inherited through environment variable */
8172+ char fd[32];
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);
8176+ }
8177+
8178+ if (which == FPM_CLEANUP_PARENT_EXIT_MAIN) {
8179+
8180+ if (ls->type == FPM_AF_UNIX) {
8181+ unlink(ls->key);
8182+ }
8183+
8184+ }
8185+
8186+ free(ls->key);
8187+ }
8188+
8189+ if (env_value) {
8190+ setenv("FPM_SOCKETS", env_value, 1);
8191+ free(env_value);
8192+ }
8193+
8194+ fpm_array_free(&sockets_list);
8195+}
8196+
8197+static int fpm_sockets_hash_op(int sock, struct sockaddr *sa, char *key, int type, int op)
8198+{
8199+
8200+ if (key == NULL) {
8201+
8202+ switch (type) {
8203+
8204+ case FPM_AF_INET : {
8205+ struct sockaddr_in *sa_in = (struct sockaddr_in *) sa;
8206+
8207+ key = alloca(sizeof("xxx.xxx.xxx.xxx:ppppp"));
8208+
8209+ sprintf(key, "%u.%u.%u.%u:%u", IPQUAD(&sa_in->sin_addr), (unsigned int) ntohs(sa_in->sin_port));
8210+
8211+ break;
8212+ }
8213+
8214+ case FPM_AF_UNIX : {
8215+ struct sockaddr_un *sa_un = (struct sockaddr_un *) sa;
8216+
8217+ key = alloca(strlen(sa_un->sun_path) + 1);
8218+
8219+ strcpy(key, sa_un->sun_path);
8220+
8221+ break;
8222+ }
8223+
8224+ default :
8225+
8226+ return -1;
8227+ }
8228+
8229+ }
8230+
8231+ switch (op) {
8232+
8233+ case FPM_GET_USE_SOCKET :
8234+ {
8235+
8236+ int i;
8237+ struct listening_socket_s *ls = sockets_list.data;
8238+
8239+ for (i = 0; i < sockets_list.used; i++, ls++) {
8240+
8241+ if (!strcmp(ls->key, key)) {
8242+ ++ls->refcount;
8243+ return ls->sock;
8244+ }
8245+ }
8246+
8247+ break;
8248+ }
8249+
8250+ case FPM_STORE_SOCKET : /* inherited socket */
8251+ case FPM_STORE_USE_SOCKET : /* just created */
8252+ {
8253+
8254+ struct listening_socket_s *ls;
8255+
8256+ ls = fpm_array_push(&sockets_list);
8257+
8258+ if (!ls) {
8259+ break;
8260+ }
8261+
8262+ if (op == FPM_STORE_SOCKET) {
8263+ ls->refcount = 0;
8264+ }
8265+ else {
8266+ ls->refcount = 1;
8267+ }
8268+ ls->type = type;
8269+ ls->sock = sock;
8270+ ls->key = strdup(key);
8271+
8272+ return 0;
8273+
8274+ }
8275+ }
8276+
8277+ return -1;
8278+
8279+}
8280+
8281+static int fpm_sockets_new_listening_socket(struct fpm_worker_pool_s *wp, struct sockaddr *sa, int socklen)
8282+{
8283+ int backlog = -1;
8284+ int flags = 1;
8285+ int sock;
8286+ mode_t saved_umask;
8287+
8288+ /* we have custom backlog value */
8289+ if (wp->config->listen_options) {
8290+ backlog = wp->config->listen_options->backlog;
8291+ }
8292+
8293+ sock = socket(sa->sa_family, SOCK_STREAM, 0);
8294+
8295+ if (0 > sock) {
8296+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "socket() failed");
8297+ return -1;
8298+ }
8299+
8300+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
8301+
8302+ if (wp->listen_address_domain == FPM_AF_UNIX) {
8303+ unlink( ((struct sockaddr_un *) sa)->sun_path);
8304+ }
8305+
8306+ saved_umask = umask(0777 ^ wp->socket_mode);
8307+
8308+ if (0 > bind(sock, sa, socklen)) {
8309+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "bind() for address '%s' failed", wp->config->listen_address);
8310+ return -1;
8311+ }
8312+
8313+ if (wp->listen_address_domain == FPM_AF_UNIX) {
8314+
8315+ char *path = ((struct sockaddr_un *) sa)->sun_path;
8316+
8317+ if (wp->socket_uid != -1 || wp->socket_gid != -1) {
8318+
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);
8321+ return -1;
8322+ }
8323+
8324+ }
8325+
8326+ }
8327+
8328+ umask(saved_umask);
8329+
8330+ if (0 > listen(sock, backlog)) {
8331+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "listen() for address '%s' failed", wp->config->listen_address);
8332+ return -1;
8333+ }
8334+
8335+ return sock;
8336+}
8337+
8338+static int fpm_sockets_get_listening_socket(struct fpm_worker_pool_s *wp, struct sockaddr *sa, int socklen)
8339+{
8340+ int sock;
8341+
8342+ sock = fpm_sockets_hash_op(0, sa, 0, wp->listen_address_domain, FPM_GET_USE_SOCKET);
8343+
8344+ if (sock >= 0) { return sock; }
8345+
8346+ sock = fpm_sockets_new_listening_socket(wp, sa, socklen);
8347+
8348+ fpm_sockets_hash_op(sock, sa, 0, wp->listen_address_domain, FPM_STORE_USE_SOCKET);
8349+
8350+ return sock;
8351+}
8352+
8353+enum fpm_address_domain fpm_sockets_domain_from_address(char *address)
8354+{
8355+ if (strchr(address, ':')) { return FPM_AF_INET; }
8356+
8357+ if (strlen(address) == strspn(address, "0123456789")) { return FPM_AF_INET; }
8358+
8359+ return FPM_AF_UNIX;
8360+}
8361+
8362+static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp)
8363+{
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;
8368+ int port = 0;
8369+
8370+ if (port_str) { /* this is host:port pair */
8371+ *port_str++ = '\0';
8372+ port = atoi(port_str);
8373+ addr = dup_address;
8374+ }
8375+ else if (strlen(dup_address) == strspn(dup_address, "0123456789")) { /* this is port */
8376+ port = atoi(dup_address);
8377+ port_str = dup_address;
8378+ }
8379+
8380+ if (port == 0) {
8381+ zlog(ZLOG_STUFF, ZLOG_ERROR, "invalid port value '%s'", port_str);
8382+ return -1;
8383+ }
8384+
8385+ memset(&sa_in, 0, sizeof(sa_in));
8386+
8387+ if (addr) {
8388+
8389+ sa_in.sin_addr.s_addr = inet_addr(addr);
8390+
8391+ if (sa_in.sin_addr.s_addr == INADDR_NONE) { /* do resolve */
8392+ if (0 > fpm_sockets_resolve_af_inet(addr, NULL, &sa_in)) {
8393+ return -1;
8394+ }
8395+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "address '%s' resolved as %u.%u.%u.%u", addr, IPQUAD(&sa_in.sin_addr));
8396+ }
8397+ }
8398+ else {
8399+
8400+ sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
8401+
8402+ }
8403+
8404+ sa_in.sin_family = AF_INET;
8405+ sa_in.sin_port = htons(port);
8406+
8407+ free(dup_address);
8408+
8409+ return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_in, sizeof(struct sockaddr_in));
8410+}
8411+
8412+static int fpm_socket_af_unix_listening_socket(struct fpm_worker_pool_s *wp)
8413+{
8414+ struct sockaddr_un sa_un;
8415+
8416+ memset(&sa_un, 0, sizeof(sa_un));
8417+
8418+ cpystrn(sa_un.sun_path, wp->config->listen_address, sizeof(sa_un.sun_path));
8419+ sa_un.sun_family = AF_UNIX;
8420+
8421+ return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_un, sizeof(struct sockaddr_un));
8422+}
8423+
8424+int fpm_sockets_init_main()
8425+{
8426+ int i;
8427+ struct fpm_worker_pool_s *wp;
8428+ char *inherited = getenv("FPM_SOCKETS");
8429+ struct listening_socket_s *ls;
8430+
8431+ if (0 == fpm_array_init(&sockets_list, sizeof(struct listening_socket_s), 10)) {
8432+ return -1;
8433+ }
8434+
8435+ /* import inherited sockets */
8436+ while (inherited && *inherited) {
8437+ char *comma = strchr(inherited, ',');
8438+ int type, fd_no;
8439+ char *eq;
8440+
8441+ if (comma) { *comma = '\0'; }
8442+
8443+ eq = strchr(inherited, '=');
8444+
8445+ if (eq) {
8446+ *eq = '\0';
8447+
8448+ fd_no = atoi(eq + 1);
8449+
8450+ type = fpm_sockets_domain_from_address(inherited);
8451+
8452+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "using inherited socket fd=%d, \"%s\"", fd_no, inherited);
8453+
8454+ fpm_sockets_hash_op(fd_no, 0, inherited, type, FPM_STORE_SOCKET);
8455+ }
8456+
8457+ if (comma) { inherited = comma + 1; }
8458+ else { inherited = 0; }
8459+ }
8460+
8461+ /* create all required sockets */
8462+ for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
8463+
8464+ if (!wp->is_template) {
8465+
8466+ switch (wp->listen_address_domain) {
8467+
8468+ case FPM_AF_INET :
8469+
8470+ wp->listening_socket = fpm_socket_af_inet_listening_socket(wp);
8471+ break;
8472+
8473+ case FPM_AF_UNIX :
8474+
8475+ if (0 > fpm_unix_resolve_socket_premissions(wp)) {
8476+ return -1;
8477+ }
8478+
8479+ wp->listening_socket = fpm_socket_af_unix_listening_socket(wp);
8480+ break;
8481+
8482+ }
8483+
8484+ if (wp->listening_socket == -1) {
8485+ return -1;
8486+ }
8487+ }
8488+
8489+ }
8490+
8491+ /* close unused sockets that was inherited */
8492+ ls = sockets_list.data;
8493+
8494+ for (i = 0; i < sockets_list.used; ) {
8495+
8496+ if (ls->refcount == 0) {
8497+ close(ls->sock);
8498+ if (ls->type == FPM_AF_UNIX) {
8499+ unlink(ls->key);
8500+ }
8501+ free(ls->key);
8502+ fpm_array_item_remove(&sockets_list, i);
8503+ }
8504+ else {
8505+ ++i;
8506+ ++ls;
8507+ }
8508+ }
8509+
8510+ if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_sockets_cleanup, 0)) {
8511+ return -1;
8512+ }
8513+
8514+ return 0;
8515+}
8516diff -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
8519@@ -0,0 +1,37 @@
8520+
8521+ /* $Id$ */
8522+ /* (c) 2007,2008 Andrei Nigmatulin */
8523+
8524+#ifndef FPM_MISC_H
8525+#define FPM_MISC_H 1
8526+
8527+#include <unistd.h>
8528+#include <fcntl.h>
8529+
8530+#include "fpm_worker_pool.h"
8531+
8532+enum fpm_address_domain fpm_sockets_domain_from_address(char *addr);
8533+int fpm_sockets_init_main();
8534+
8535+
8536+static inline int fd_set_blocked(int fd, int blocked)
8537+{
8538+ int flags = fcntl(fd, F_GETFL);
8539+
8540+ if (flags < 0) { return -1; }
8541+
8542+ if (blocked)
8543+ { flags &= ~O_NONBLOCK; }
8544+ else
8545+ { flags |= O_NONBLOCK; }
8546+
8547+ return fcntl(fd, F_SETFL, flags);
8548+}
8549+
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]
8555+
8556+#endif
8557diff -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
8560@@ -0,0 +1,286 @@
8561+
8562+ /* $Id$ */
8563+ /* (c) 2007,2008 Andrei Nigmatulin */
8564+
8565+#include "fpm_config.h"
8566+
8567+#include <sys/types.h>
8568+#include <sys/stat.h>
8569+#include <string.h>
8570+#include <fcntl.h>
8571+#include <unistd.h>
8572+#include <errno.h>
8573+
8574+#include "fpm.h"
8575+#include "fpm_children.h"
8576+#include "fpm_events.h"
8577+#include "fpm_sockets.h"
8578+#include "fpm_stdio.h"
8579+#include "zlog.h"
8580+
8581+static int fd_stdout[2];
8582+static int fd_stderr[2];
8583+
8584+int fpm_stdio_init_main()
8585+{
8586+ int fd = open("/dev/null", O_RDWR);
8587+
8588+ if (0 > fd) {
8589+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(\"/dev/null\") failed");
8590+ return -1;
8591+ }
8592+
8593+ if (0 > dup2(fd, STDIN_FILENO) || 0 > dup2(fd, STDOUT_FILENO)) {
8594+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed");
8595+ return -1;
8596+ }
8597+
8598+ close(fd);
8599+
8600+ return 0;
8601+}
8602+
8603+int fpm_stdio_init_final()
8604+{
8605+ if (fpm_global_config.daemonize) {
8606+
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");
8611+ return -1;
8612+ }
8613+ }
8614+
8615+ zlog_set_level(fpm_globals.log_level);
8616+
8617+ zlog_set_fd(fpm_globals.error_log_fd);
8618+ }
8619+
8620+ return 0;
8621+}
8622+
8623+int fpm_stdio_init_child(struct fpm_worker_pool_s *wp)
8624+{
8625+ close(fpm_globals.error_log_fd);
8626+ fpm_globals.error_log_fd = -1;
8627+ zlog_set_fd(-1);
8628+
8629+ if (wp->listening_socket != STDIN_FILENO) {
8630+ if (0 > dup2(wp->listening_socket, STDIN_FILENO)) {
8631+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed");
8632+ return -1;
8633+ }
8634+ }
8635+
8636+ return 0;
8637+}
8638+
8639+static void fpm_stdio_child_said(int fd, short which, void *arg)
8640+{
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;
8648+ int in_buf = 0;
8649+ int res;
8650+
8651+#if 0
8652+ zlog(ZLOG_STUFF, ZLOG_DEBUG, "child %d said %s", (int) child->pid, is_stdout ? "stdout" : "stderr");
8653+#endif
8654+
8655+ while (fifo_in || fifo_out) {
8656+
8657+ if (fifo_in) {
8658+
8659+ res = read(fd, buf + in_buf, max_buf_size - 1 - in_buf);
8660+
8661+ if (res <= 0) { /* no data */
8662+ fifo_in = 0;
8663+
8664+ if (res < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
8665+ /* just no more data ready */
8666+ }
8667+ else { /* error or pipe is closed */
8668+
8669+ if (res < 0) { /* error */
8670+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "read() failed");
8671+ }
8672+
8673+ fpm_event_del(ev);
8674+ is_last_message = 1;
8675+
8676+ if (is_stdout) {
8677+ close(child->fd_stdout);
8678+ child->fd_stdout = -1;
8679+ }
8680+ else {
8681+ close(child->fd_stderr);
8682+ child->fd_stderr = -1;
8683+ }
8684+
8685+#if 0
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");
8689+ }
8690+#endif
8691+ }
8692+ }
8693+ else {
8694+ in_buf += res;
8695+ }
8696+ }
8697+
8698+ if (fifo_out) {
8699+ if (in_buf == 0) {
8700+ fifo_out = 0;
8701+ }
8702+ else {
8703+ char *nl;
8704+ int should_print = 0;
8705+ buf[in_buf] = '\0';
8706+
8707+ /* FIXME: there might be binary data */
8708+
8709+ /* we should print if no more space in the buffer */
8710+ if (in_buf == max_buf_size - 1) {
8711+ should_print = 1;
8712+ }
8713+
8714+ /* we should print if no more data to come */
8715+ if (!fifo_in) {
8716+ should_print = 1;
8717+ }
8718+
8719+ nl = strchr(buf, '\n');
8720+
8721+ if (nl || should_print) {
8722+
8723+ if (nl) {
8724+ *nl = '\0';
8725+ }
8726+
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" : "");
8729+
8730+ if (nl) {
8731+ int out_buf = 1 + nl - buf;
8732+ memmove(buf, buf + out_buf, in_buf - out_buf);
8733+ in_buf -= out_buf;
8734+ }
8735+ else {
8736+ in_buf = 0;
8737+ }
8738+ }
8739+ }
8740+ }
8741+ }
8742+
8743+}
8744+
8745+int fpm_stdio_prepare_pipes(struct fpm_child_s *child)
8746+{
8747+ if (0 == child->wp->config->catch_workers_output) { /* not required */
8748+ return 0;
8749+ }
8750+
8751+ if (0 > pipe(fd_stdout)) {
8752+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pipe() failed");
8753+ return -1;
8754+ }
8755+
8756+ if (0 > pipe(fd_stderr)) {
8757+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pipe() failed");
8758+ close(fd_stdout[0]); close(fd_stdout[1]);
8759+ return -1;
8760+ }
8761+
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]);
8766+ return -1;
8767+ }
8768+
8769+ return 0;
8770+}
8771+
8772+int fpm_stdio_parent_use_pipes(struct fpm_child_s *child)
8773+{
8774+ if (0 == child->wp->config->catch_workers_output) { /* not required */
8775+ return 0;
8776+ }
8777+
8778+ close(fd_stdout[1]);
8779+ close(fd_stderr[1]);
8780+
8781+ child->fd_stdout = fd_stdout[0];
8782+ child->fd_stderr = fd_stderr[0];
8783+
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);
8786+
8787+ return 0;
8788+}
8789+
8790+int fpm_stdio_discard_pipes(struct fpm_child_s *child)
8791+{
8792+ if (0 == child->wp->config->catch_workers_output) { /* not required */
8793+ return 0;
8794+ }
8795+
8796+ close(fd_stdout[1]);
8797+ close(fd_stderr[1]);
8798+
8799+ close(fd_stdout[0]);
8800+ close(fd_stderr[0]);
8801+
8802+ return 0;
8803+}
8804+
8805+void fpm_stdio_child_use_pipes(struct fpm_child_s *child)
8806+{
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]);
8812+ }
8813+ else {
8814+ /* stdout of parent is always /dev/null */
8815+ dup2(STDOUT_FILENO, STDERR_FILENO);
8816+ }
8817+}
8818+
8819+int fpm_stdio_open_error_log(int reopen)
8820+{
8821+ int fd;
8822+
8823+ fd = open(fpm_global_config.error_log, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
8824+
8825+ if (0 > fd) {
8826+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(\"%s\") failed", fpm_global_config.error_log);
8827+ return -1;
8828+ }
8829+
8830+ if (reopen) {
8831+ if (fpm_global_config.daemonize) {
8832+ dup2(fd, STDERR_FILENO);
8833+ }
8834+
8835+ dup2(fd, fpm_globals.error_log_fd);
8836+ close(fd);
8837+ fd = fpm_globals.error_log_fd; /* for FD_CLOSEXEC to work */
8838+ }
8839+ else {
8840+ fpm_globals.error_log_fd = fd;
8841+ }
8842+
8843+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
8844+
8845+ return 0;
8846+}
8847diff -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
8850@@ -0,0 +1,20 @@
8851+
8852+ /* $Id$ */
8853+ /* (c) 2007,2008 Andrei Nigmatulin */
8854+
8855+#ifndef FPM_STDIO_H
8856+#define FPM_STDIO_H 1
8857+
8858+#include "fpm_worker_pool.h"
8859+
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);
8868+
8869+#endif
8870+
8871diff -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
8874@@ -0,0 +1,49 @@
8875+
8876+ /* $Id$ */
8877+ /* (c) 2007,2008 Andrei Nigmatulin */
8878+
8879+#ifndef FPM_STR_H
8880+#define FPM_STR_H 1
8881+
8882+static inline char *cpystrn(char *dst, const char *src, size_t dst_size)
8883+{
8884+ char *d, *end;
8885+
8886+ if (!dst_size) { return dst; }
8887+
8888+ d = dst;
8889+ end = dst + dst_size - 1;
8890+
8891+ for (; d < end; ++d, ++src) {
8892+ if (!(*d = *src)) {
8893+ return d;
8894+ }
8895+ }
8896+
8897+ *d = '\0';
8898+
8899+ return d;
8900+}
8901+
8902+static inline char *str_purify_filename(char *dst, char *src, size_t size)
8903+{
8904+ char *d, *end;
8905+
8906+ d = dst;
8907+ end = dst + size - 1;
8908+
8909+ for (; d < end && *src; ++d, ++src) {
8910+ if (* (unsigned char *) src < ' ' || * (unsigned char *) src > '\x7f') {
8911+ *d = '.';
8912+ }
8913+ else {
8914+ *d = *src;
8915+ }
8916+ }
8917+
8918+ *d = '\0';
8919+
8920+ return d;
8921+}
8922+
8923+#endif
8924diff -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
8927@@ -0,0 +1,46 @@
8928+
8929+ /* $Id$ */
8930+ /* (c) 2007,2008 Andrei Nigmatulin */
8931+
8932+#include "fpm_config.h"
8933+
8934+#include <sys/types.h>
8935+
8936+#include "fpm_trace.h"
8937+
8938+int fpm_trace_get_strz(char *buf, size_t sz, long addr)
8939+{
8940+ int i;
8941+ long l;
8942+ char *lc = (char *) &l;
8943+
8944+ if (0 > fpm_trace_get_long(addr, &l)) {
8945+ return -1;
8946+ }
8947+
8948+ i = l % SIZEOF_LONG;
8949+
8950+ l -= i;
8951+
8952+ for (addr = l; ; addr += SIZEOF_LONG) {
8953+
8954+ if (0 > fpm_trace_get_long(addr, &l)) {
8955+ return -1;
8956+ }
8957+
8958+ for ( ; i < SIZEOF_LONG; i++) {
8959+ --sz;
8960+
8961+ if (sz && lc[i]) {
8962+ *buf++ = lc[i];
8963+ continue;
8964+ }
8965+
8966+ *buf = '\0';
8967+ return 0;
8968+ }
8969+
8970+ i = 0;
8971+ }
8972+}
8973+
8974diff -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
8977@@ -0,0 +1,17 @@
8978+
8979+ /* $Id$ */
8980+ /* (c) 2007,2008 Andrei Nigmatulin */
8981+
8982+#ifndef FPM_TRACE_H
8983+#define FPM_TRACE_H 1
8984+
8985+#include <unistd.h>
8986+
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);
8992+
8993+#endif
8994+
8995diff -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
8998@@ -0,0 +1,102 @@
8999+
9000+ /* $Id$ */
9001+ /* (c) 2007,2008 Andrei Nigmatulin */
9002+
9003+#include "fpm_config.h"
9004+
9005+#include <mach/mach.h>
9006+#include <mach/mach_vm.h>
9007+
9008+#include <unistd.h>
9009+
9010+#include "fpm_trace.h"
9011+#include "fpm_process_ctl.h"
9012+#include "fpm_unix.h"
9013+#include "zlog.h"
9014+
9015+
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;
9020+
9021+static void fpm_mach_vm_deallocate()
9022+{
9023+ if (local_page) {
9024+ mach_vm_deallocate(mach_task_self(), local_page, local_size);
9025+ target_page_base = 0;
9026+ local_page = 0;
9027+ local_size = 0;
9028+ }
9029+}
9030+
9031+static int fpm_mach_vm_read_page(vm_offset_t page)
9032+{
9033+ kern_return_t kr;
9034+
9035+ kr = mach_vm_read(target, page, fpm_pagesize, &local_page, &local_size);
9036+
9037+ if (kr != KERN_SUCCESS) {
9038+ zlog(ZLOG_STUFF, ZLOG_ERROR, "mach_vm_read() failed: %s (%d)", mach_error_string(kr), kr);
9039+ return -1;
9040+ }
9041+
9042+ return 0;
9043+}
9044+
9045+int fpm_trace_signal(pid_t pid)
9046+{
9047+ if (0 > fpm_pctl_kill(pid, FPM_PCTL_STOP)) {
9048+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "kill(SIGSTOP) failed");
9049+ return -1;
9050+ }
9051+
9052+ return 0;
9053+}
9054+
9055+int fpm_trace_ready(pid_t pid)
9056+{
9057+ kern_return_t kr;
9058+
9059+ kr = task_for_pid(mach_task_self(), pid, &target);
9060+
9061+ if (kr != KERN_SUCCESS) {
9062+ char *msg = "";
9063+
9064+ if (kr == KERN_FAILURE) {
9065+ msg = " It seems that master process does not have enough privileges to trace processes.";
9066+ }
9067+
9068+ zlog(ZLOG_STUFF, ZLOG_ERROR, "task_for_pid() failed: %s (%d)%s", mach_error_string(kr), kr, msg);
9069+ return -1;
9070+ }
9071+
9072+ return 0;
9073+}
9074+
9075+int fpm_trace_close(pid_t pid)
9076+{
9077+ fpm_mach_vm_deallocate();
9078+
9079+ target = 0;
9080+
9081+ return 0;
9082+}
9083+
9084+int fpm_trace_get_long(long addr, long *data)
9085+{
9086+ size_t offset = ((uintptr_t) (addr) % fpm_pagesize);
9087+ vm_offset_t base = (uintptr_t) (addr) - offset;
9088+
9089+ if (base != target_page_base) {
9090+ fpm_mach_vm_deallocate();
9091+ if (0 > fpm_mach_vm_read_page(base)) {
9092+ return -1;
9093+ }
9094+ }
9095+
9096+ *data = * (long *) (local_page + offset);
9097+
9098+ return 0;
9099+}
9100+
9101diff -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
9104@@ -0,0 +1,72 @@
9105+
9106+ /* $Id$ */
9107+ /* (c) 2007,2008 Andrei Nigmatulin */
9108+
9109+#define _GNU_SOURCE
9110+#define _FILE_OFFSET_BITS 64
9111+
9112+#include "fpm_config.h"
9113+
9114+#include <unistd.h>
9115+
9116+#include <fcntl.h>
9117+#include <stdio.h>
9118+#if HAVE_INTTYPES_H
9119+#include <inttypes.h>
9120+#else
9121+#include <stdint.h>
9122+#endif
9123+
9124+
9125+#include "fpm_trace.h"
9126+#include "fpm_process_ctl.h"
9127+#include "zlog.h"
9128+
9129+
9130+static int mem_file = -1;
9131+
9132+int fpm_trace_signal(pid_t pid)
9133+{
9134+ if (0 > fpm_pctl_kill(pid, FPM_PCTL_STOP)) {
9135+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "kill(SIGSTOP) failed");
9136+ return -1;
9137+ }
9138+
9139+ return 0;
9140+}
9141+
9142+int fpm_trace_ready(pid_t pid)
9143+{
9144+ char buf[128];
9145+
9146+ sprintf(buf, "/proc/%d/" PROC_MEM_FILE, (int) pid);
9147+
9148+ mem_file = open(buf, O_RDONLY);
9149+
9150+ if (0 > mem_file) {
9151+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(%s) failed", buf);
9152+ return -1;
9153+ }
9154+
9155+ return 0;
9156+}
9157+
9158+int fpm_trace_close(pid_t pid)
9159+{
9160+ close(mem_file);
9161+
9162+ mem_file = -1;
9163+
9164+ return 0;
9165+}
9166+
9167+int fpm_trace_get_long(long addr, long *data)
9168+{
9169+ if (sizeof(*data) != pread(mem_file, (void *) data, sizeof(*data), (uintptr_t) addr)) {
9170+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pread() failed");
9171+ return -1;
9172+ }
9173+
9174+ return 0;
9175+}
9176+
9177diff -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
9180@@ -0,0 +1,85 @@
9181+
9182+ /* $Id$ */
9183+ /* (c) 2007,2008 Andrei Nigmatulin */
9184+
9185+#include "fpm_config.h"
9186+
9187+#include <sys/wait.h>
9188+#include <sys/ptrace.h>
9189+#include <unistd.h>
9190+#include <errno.h>
9191+
9192+#if defined(PT_ATTACH) && !defined(PTRACE_ATTACH)
9193+#define PTRACE_ATTACH PT_ATTACH
9194+#endif
9195+
9196+#if defined(PT_DETACH) && !defined(PTRACE_DETACH)
9197+#define PTRACE_DETACH PT_DETACH
9198+#endif
9199+
9200+#if defined(PT_READ_D) && !defined(PTRACE_PEEKDATA)
9201+#define PTRACE_PEEKDATA PT_READ_D
9202+#endif
9203+
9204+#include "fpm_trace.h"
9205+#include "zlog.h"
9206+
9207+static pid_t traced_pid;
9208+
9209+int fpm_trace_signal(pid_t pid)
9210+{
9211+ if (0 > ptrace(PTRACE_ATTACH, pid, 0, 0)) {
9212+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(ATTACH) failed");
9213+ return -1;
9214+ }
9215+
9216+ return 0;
9217+}
9218+
9219+int fpm_trace_ready(pid_t pid)
9220+{
9221+ traced_pid = pid;
9222+
9223+ return 0;
9224+}
9225+
9226+int fpm_trace_close(pid_t pid)
9227+{
9228+ if (0 > ptrace(PTRACE_DETACH, pid, (void *) 1, 0)) {
9229+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(DETACH) failed");
9230+ return -1;
9231+ }
9232+
9233+ traced_pid = 0;
9234+
9235+ return 0;
9236+}
9237+
9238+int fpm_trace_get_long(long addr, long *data)
9239+{
9240+#ifdef PT_IO
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)
9246+ };
9247+
9248+ if (0 > ptrace(PT_IO, traced_pid, (void *) &ptio, 0)) {
9249+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(PT_IO) failed");
9250+ return -1;
9251+ }
9252+#else
9253+ errno = 0;
9254+
9255+ *data = ptrace(PTRACE_PEEKDATA, traced_pid, (void *) addr, 0);
9256+
9257+ if (errno) {
9258+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(PEEKDATA) failed");
9259+ return -1;
9260+ }
9261+#endif
9262+
9263+ return 0;
9264+}
9265+
9266diff -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
9269@@ -0,0 +1,289 @@
9270+
9271+ /* $Id$ */
9272+ /* (c) 2007,2008 Andrei Nigmatulin */
9273+
9274+#include "fpm_config.h"
9275+
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>
9282+#include <pwd.h>
9283+#include <grp.h>
9284+
9285+#ifdef HAVE_PRCTL
9286+#include <sys/prctl.h>
9287+#endif
9288+
9289+#include "fpm.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"
9295+#include "zlog.h"
9296+
9297+size_t fpm_pagesize;
9298+
9299+int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp)
9300+{
9301+ struct fpm_listen_options_s *lo = wp->config->listen_options;
9302+
9303+ /* uninitialized */
9304+ wp->socket_uid = -1;
9305+ wp->socket_gid = -1;
9306+ wp->socket_mode = 0666;
9307+
9308+ if (!lo) { return 0; }
9309+
9310+ if (lo->owner && *lo->owner) {
9311+ struct passwd *pwd;
9312+
9313+ pwd = getpwnam(lo->owner);
9314+
9315+ if (!pwd) {
9316+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "cannot get uid for user '%s', pool '%s'", lo->owner, wp->config->name);
9317+ return -1;
9318+ }
9319+
9320+ wp->socket_uid = pwd->pw_uid;
9321+ wp->socket_gid = pwd->pw_gid;
9322+ }
9323+
9324+ if (lo->group && *lo->group) {
9325+ struct group *grp;
9326+
9327+ grp = getgrnam(lo->group);
9328+
9329+ if (!grp) {
9330+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "cannot get gid for group '%s', pool '%s'", lo->group, wp->config->name);
9331+ return -1;
9332+ }
9333+
9334+ wp->socket_gid = grp->gr_gid;
9335+ }
9336+
9337+ if (lo->mode && *lo->mode) {
9338+ wp->socket_mode = strtoul(lo->mode, 0, 8);
9339+ }
9340+
9341+ return 0;
9342+}
9343+
9344+static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp)
9345+{
9346+ int is_root = !geteuid();
9347+
9348+ if (is_root) {
9349+ if (wp->config->user && *wp->config->user) {
9350+
9351+ if (strlen(wp->config->user) == strspn(wp->config->user, "0123456789")) {
9352+ wp->set_uid = strtoul(wp->config->user, 0, 10);
9353+ }
9354+ else {
9355+ struct passwd *pwd;
9356+
9357+ pwd = getpwnam(wp->config->user);
9358+
9359+ if (!pwd) {
9360+ zlog(ZLOG_STUFF, ZLOG_ERROR, "cannot get uid for user '%s', pool '%s'", wp->config->user, wp->config->name);
9361+ return -1;
9362+ }
9363+
9364+ wp->set_uid = pwd->pw_uid;
9365+ wp->set_gid = pwd->pw_gid;
9366+
9367+ wp->user = strdup(pwd->pw_name);
9368+ wp->home = strdup(pwd->pw_dir);
9369+ }
9370+ }
9371+
9372+ if (wp->config->group && *wp->config->group) {
9373+
9374+ if (strlen(wp->config->group) == strspn(wp->config->group, "0123456789")) {
9375+ wp->set_gid = strtoul(wp->config->group, 0, 10);
9376+ }
9377+ else {
9378+ struct group *grp;
9379+
9380+ grp = getgrnam(wp->config->group);
9381+
9382+ if (!grp) {
9383+ zlog(ZLOG_STUFF, ZLOG_ERROR, "cannot get gid for group '%s', pool '%s'", wp->config->group, wp->config->name);
9384+ return -1;
9385+ }
9386+
9387+ wp->set_gid = grp->gr_gid;
9388+ }
9389+ }
9390+
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);
9394+ return -1;
9395+ }
9396+#endif
9397+ }
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);
9401+ }
9402+ if (wp->config->group && *wp->config->group) {
9403+ zlog(ZLOG_STUFF, ZLOG_WARNING, "'group' directive is ignored, pool '%s'", wp->config->name);
9404+ }
9405+ if (wp->config->chroot && *wp->config->chroot) {
9406+ zlog(ZLOG_STUFF, ZLOG_WARNING, "'chroot' directive is ignored, pool '%s'", wp->config->name);
9407+ }
9408+
9409+ { /* set up HOME and USER anyway */
9410+ struct passwd *pwd;
9411+
9412+ pwd = getpwuid(getuid());
9413+
9414+ if (pwd) {
9415+ wp->user = strdup(pwd->pw_name);
9416+ wp->home = strdup(pwd->pw_dir);
9417+ }
9418+ }
9419+ }
9420+
9421+ return 0;
9422+}
9423+
9424+int fpm_unix_init_child(struct fpm_worker_pool_s *wp)
9425+{
9426+ int is_root = !geteuid();
9427+ int made_chroot = 0;
9428+
9429+ if (wp->config->rlimit_files) {
9430+ struct rlimit r;
9431+
9432+ getrlimit(RLIMIT_NOFILE, &r);
9433+
9434+ r.rlim_cur = (rlim_t) wp->config->rlimit_files;
9435+
9436+ if (0 > setrlimit(RLIMIT_NOFILE, &r)) {
9437+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setrlimit(RLIMIT_NOFILE) failed");
9438+ }
9439+ }
9440+
9441+ if (wp->config->rlimit_core) {
9442+ struct rlimit r;
9443+
9444+ getrlimit(RLIMIT_CORE, &r);
9445+
9446+ r.rlim_cur = wp->config->rlimit_core == -1 ? (rlim_t) RLIM_INFINITY : (rlim_t) wp->config->rlimit_core;
9447+
9448+ if (0 > setrlimit(RLIMIT_CORE, &r)) {
9449+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setrlimit(RLIMIT_CORE) failed");
9450+ }
9451+ }
9452+
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);
9456+ return -1;
9457+ }
9458+ made_chroot = 1;
9459+ }
9460+
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);
9464+ return -1;
9465+ }
9466+ }
9467+ else if (made_chroot) {
9468+ chdir("/");
9469+ }
9470+
9471+ if (is_root) {
9472+ if (wp->set_gid) {
9473+ if (0 > setgid(wp->set_gid)) {
9474+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setgid(%d) failed", wp->set_gid);
9475+ return -1;
9476+ }
9477+ }
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);
9481+ return -1;
9482+ }
9483+ if (0 > setuid(wp->set_uid)) {
9484+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setuid(%d) failed", wp->set_uid);
9485+ return -1;
9486+ }
9487+ }
9488+ }
9489+
9490+#ifdef HAVE_PRCTL
9491+ if (0 > prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) {
9492+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "prctl(PR_SET_DUMPABLE) failed");
9493+ }
9494+#endif
9495+
9496+ if (0 > fpm_clock_init()) {
9497+ return -1;
9498+ }
9499+
9500+ return 0;
9501+}
9502+
9503+int fpm_unix_init_main()
9504+{
9505+ struct fpm_worker_pool_s *wp;
9506+
9507+ fpm_pagesize = getpagesize();
9508+
9509+ if (fpm_global_config.daemonize) {
9510+
9511+ switch (fork()) {
9512+
9513+ case -1 :
9514+
9515+ zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fork() failed");
9516+ return -1;
9517+
9518+ case 0 :
9519+
9520+ break;
9521+
9522+ default :
9523+
9524+ fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT);
9525+ exit(0);
9526+
9527+ }
9528+
9529+ }
9530+
9531+ setsid();
9532+
9533+ if (0 > fpm_clock_init()) {
9534+ return -1;
9535+ }
9536+
9537+ fpm_globals.parent_pid = getpid();
9538+
9539+ for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
9540+
9541+ if (0 > fpm_unix_conf_wp(wp)) {
9542+ return -1;
9543+ }
9544+
9545+ }
9546+
9547+ fpm_stdio_init_final();
9548+
9549+ {
9550+ struct rlimit r;
9551+ getrlimit(RLIMIT_NOFILE, &r);
9552+
9553+ zlog(ZLOG_STUFF, ZLOG_NOTICE, "getrlimit(nofile): max:%lld, cur:%lld",
9554+ (long long) r.rlim_max, (long long) r.rlim_cur);
9555+ }
9556+
9557+ return 0;
9558+}
9559diff -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
9562@@ -0,0 +1,17 @@
9563+
9564+ /* $Id$ */
9565+ /* (c) 2007,2008 Andrei Nigmatulin */
9566+
9567+#ifndef FPM_UNIX_H
9568+#define FPM_UNIX_H 1
9569+
9570+#include "fpm_worker_pool.h"
9571+
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();
9575+
9576+extern size_t fpm_pagesize;
9577+
9578+#endif
9579+
9580diff -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
9583@@ -0,0 +1,69 @@
9584+
9585+ /* $Id$ */
9586+ /* (c) 2007,2008 Andrei Nigmatulin */
9587+
9588+#include "fpm_config.h"
9589+
9590+#include <string.h>
9591+#include <stdlib.h>
9592+#include <unistd.h>
9593+
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"
9600+
9601+struct fpm_worker_pool_s *fpm_worker_all_pools;
9602+
9603+static void fpm_worker_pool_cleanup(int which, void *arg)
9604+{
9605+ struct fpm_worker_pool_s *wp, *wp_next;
9606+
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);
9614+ free(wp->config);
9615+ free(wp->user);
9616+ free(wp->home);
9617+ free(wp);
9618+ }
9619+
9620+ fpm_worker_all_pools = 0;
9621+}
9622+
9623+struct fpm_worker_pool_s *fpm_worker_pool_alloc()
9624+{
9625+ struct fpm_worker_pool_s *ret;
9626+
9627+ ret = malloc(sizeof(struct fpm_worker_pool_s));
9628+
9629+ if (!ret) {
9630+ return 0;
9631+ }
9632+
9633+ memset(ret, 0, sizeof(struct fpm_worker_pool_s));
9634+
9635+ if (!fpm_worker_all_pools) {
9636+ fpm_worker_all_pools = ret;
9637+ }
9638+
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);
9641+
9642+ return ret;
9643+}
9644+
9645+int fpm_worker_pool_init_main()
9646+{
9647+ if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_worker_pool_cleanup, 0)) {
9648+ return -1;
9649+ }
9650+
9651+ return 0;
9652+}
9653diff -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
9656@@ -0,0 +1,46 @@
9657+
9658+ /* $Id$ */
9659+ /* (c) 2007,2008 Andrei Nigmatulin */
9660+
9661+#ifndef FPM_WORKER_POOL_H
9662+#define FPM_WORKER_POOL_H 1
9663+
9664+#include "fpm_conf.h"
9665+#include "fpm_arrays.h"
9666+
9667+struct fpm_worker_pool_s;
9668+struct fpm_child_s;
9669+struct fpm_child_stat_s;
9670+struct fpm_shm_s;
9671+
9672+enum fpm_address_domain {
9673+ FPM_AF_UNIX = 1,
9674+ FPM_AF_INET = 2
9675+};
9676+
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;
9686+
9687+ struct fpm_shm_s *shm_list;
9688+ struct fpm_array_s slots_used;
9689+ struct fpm_array_s slots_free;
9690+
9691+ /* runtime */
9692+ struct fpm_child_s *children;
9693+ int running_children;
9694+};
9695+
9696+struct fpm_worker_pool_s *fpm_worker_pool_alloc();
9697+int fpm_worker_pool_init_main();
9698+
9699+extern struct fpm_worker_pool_s *fpm_worker_all_pools;
9700+
9701+#endif
9702+
9703diff -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
9706@@ -0,0 +1,278 @@
9707+
9708+ /* $Id$ */
9709+ /* (c) 2004-2007 Andrei Nigmatulin */
9710+
9711+#include "fpm_config.h"
9712+
9713+#ifdef HAVE_ALLOCA_H
9714+#include <alloca.h>
9715+#endif
9716+#include <string.h>
9717+#include <stdio.h>
9718+#include <stddef.h>
9719+#include <stdlib.h>
9720+
9721+#include <libxml/parser.h>
9722+#include <libxml/tree.h>
9723+
9724+#include "xml_config.h"
9725+
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;
9729+
9730+char *xml_conf_set_slot_boolean(void **conf, char *name, void *vv, intptr_t offset)
9731+{
9732+ char *value = vv;
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");
9735+
9736+ if (!value_y && !value_n) {
9737+ return "xml_conf_set_slot(): invalid boolean value";
9738+ }
9739+
9740+#ifdef XML_CONF_DEBUG
9741+ fprintf(stderr, "setting boolean '%s' => %s\n", name, value_y ? "TRUE" : "FALSE");
9742+#endif
9743+
9744+ * (int *) ((char *) *conf + offset) = value_y ? 1 : 0;
9745+
9746+ return NULL;
9747+}
9748+
9749+char *xml_conf_set_slot_string(void **conf, char *name, void *vv, intptr_t offset)
9750+{
9751+ char *value = vv;
9752+ char *v = strdup(value);
9753+
9754+ if (!v) { return "xml_conf_set_slot_string(): strdup() failed"; }
9755+
9756+#ifdef XML_CONF_DEBUG
9757+ fprintf(stderr, "setting string '%s' => '%s'\n", name, v);
9758+#endif
9759+
9760+ * (char **) ((char *) *conf + offset) = v;
9761+
9762+ return NULL;
9763+}
9764+
9765+char *xml_conf_set_slot_integer(void **conf, char *name, void *vv, intptr_t offset)
9766+{
9767+ char *value = vv;
9768+ int v = atoi(value);
9769+
9770+ * (int *) ((char *) *conf + offset) = v;
9771+
9772+#ifdef XML_CONF_DEBUG
9773+ fprintf(stderr, "setting integer '%s' => %d\n", name, v);
9774+#endif
9775+
9776+ return NULL;
9777+}
9778+
9779+char *xml_conf_set_slot_time(void **conf, char *name, void *vv, intptr_t offset)
9780+{
9781+ char *value = vv;
9782+ int len = strlen(value);
9783+ char suffix;
9784+ int seconds;
9785+
9786+ if (!len) { return "xml_conf_set_slot_timeval(): invalid timeval value"; }
9787+
9788+ suffix = value[len-1];
9789+
9790+ value[len-1] = '\0';
9791+
9792+ switch (suffix) {
9793+ case 's' :
9794+ seconds = atoi(value);
9795+ break;
9796+ case 'm' :
9797+ seconds = 60 * atoi(value);
9798+ break;
9799+ case 'h' :
9800+ seconds = 60 * 60 * atoi(value);
9801+ break;
9802+ case 'd' :
9803+ seconds = 24 * 60 * 60 * atoi(value);
9804+ break;
9805+ default :
9806+ return "xml_conf_set_slot_timeval(): unknown suffix used in timeval value";
9807+ }
9808+
9809+ * (int *) ((char *) *conf + offset) = seconds;
9810+
9811+#ifdef XML_CONF_DEBUG
9812+ fprintf(stderr, "setting time '%s' => %d:%02d:%02d:%02d\n", name, expand_dhms(seconds));
9813+#endif
9814+
9815+ return NULL;
9816+}
9817+
9818+char *xml_conf_parse_section(void **conf, struct xml_conf_section *section, void *xml_node)
9819+{
9820+ xmlNode *element = xml_node;
9821+ char *ret = 0;
9822+
9823+#ifdef XML_CONF_DEBUG
9824+ fprintf(stderr, "processing a section %s\n", section->path);
9825+#endif
9826+
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");
9830+
9831+ if (name) {
9832+ int i;
9833+
9834+#ifdef XML_CONF_DEBUG
9835+ fprintf(stderr, "found a value: %s\n", name);
9836+#endif
9837+ for (i = 0; section->parsers[i].parser; i++) {
9838+ if (!section->parsers[i].name || !strcmp(section->parsers[i].name, (char *) name)) {
9839+ break;
9840+ }
9841+ }
9842+
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);
9847+ }
9848+ else {
9849+ ret = "XML_TEXT_NODE is expected, something different is given";
9850+ }
9851+ }
9852+ else {
9853+ ret = section->parsers[i].parser(conf, (char *) name, element->children, section->parsers[i].offset);
9854+ }
9855+
9856+ xmlFree(name);
9857+ if (ret) { return ret; }
9858+ else { continue; }
9859+ }
9860+
9861+ fprintf(stderr, "Warning, unknown setting '%s' in section '%s'\n", (char *) name, section->path);
9862+
9863+ xmlFree(name);
9864+ }
9865+ }
9866+ }
9867+
9868+ return NULL;
9869+}
9870+
9871+static char *xml_conf_parse_file(xmlNode *element)
9872+{
9873+ char *ret = 0;
9874+
9875+ for ( ; element; element = element->next) {
9876+
9877+ if (element->parent && element->type == XML_ELEMENT_NODE && !strcmp((const char *) element->name, "section")) {
9878+ xmlChar *name = xmlGetProp(element, (unsigned char *) "name");
9879+
9880+ if (name) {
9881+ char *parent_name = (char *) xmlGetNodePath(element->parent);
9882+ char *full_name;
9883+ int i;
9884+ struct xml_conf_section *section = NULL;
9885+
9886+#ifdef XML_CONF_DEBUG
9887+ fprintf(stderr, "got a section: %s/%s\n", parent_name, name);
9888+#endif
9889+ full_name = alloca(strlen(parent_name) + strlen((char *) name) + 1 + 1);
9890+
9891+ sprintf(full_name, "%s/%s", parent_name, (char *) name);
9892+
9893+ xmlFree(parent_name);
9894+ xmlFree(name);
9895+
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];
9899+ }
9900+ }
9901+
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; }
9906+ }
9907+
9908+ }
9909+ }
9910+
9911+ if (element->children) {
9912+ ret = xml_conf_parse_file(element->children);
9913+ if (ret) { break; }
9914+ }
9915+ }
9916+
9917+ return ret;
9918+}
9919+
9920+char *xml_conf_load_file(char *file)
9921+{
9922+ char *ret = 0;
9923+ xmlDoc *doc;
9924+
9925+ LIBXML_TEST_VERSION
9926+
9927+ doc = xmlParseFile(file);
9928+
9929+ if (doc) {
9930+ ret = xml_conf_parse_file(doc->children);
9931+ xmlFreeDoc(doc);
9932+ }
9933+ else {
9934+ ret = "failed to parse conf file";
9935+ }
9936+
9937+ xmlCleanupParser();
9938+ return ret;
9939+}
9940+
9941+int xml_conf_init()
9942+{
9943+ return 0;
9944+}
9945+
9946+void xml_conf_clean()
9947+{
9948+ if (xml_conf_sections) {
9949+ free(xml_conf_sections);
9950+ }
9951+}
9952+
9953+int xml_conf_section_register(struct xml_conf_section *section)
9954+{
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);
9958+
9959+ if (new_ptr) {
9960+ xml_conf_sections = new_ptr;
9961+ xml_conf_sections_allocated = new_size;
9962+ }
9963+ else {
9964+ fprintf(stderr, "xml_conf_section_register(): out of memory\n");
9965+ return -1;
9966+ }
9967+ }
9968+
9969+ xml_conf_sections[xml_conf_sections_used++] = section;
9970+
9971+ return 0;
9972+}
9973+
9974+int xml_conf_sections_register(struct xml_conf_section *sections[])
9975+{
9976+ for ( ; sections && *sections; sections++) {
9977+ if (0 > xml_conf_section_register(*sections)) {
9978+ return -1;
9979+ }
9980+ }
9981+
9982+ return 0;
9983+}
9984+
9985diff -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
9988@@ -0,0 +1,48 @@
9989+
9990+ /* $Id$ */
9991+ /* (c) 2004-2007 Andrei Nigmatulin */
9992+
9993+#ifndef XML_CONFIG_H
9994+#define XML_CONFIG_H 1
9995+
9996+#if HAVE_INTTYPES_H
9997+#include <inttypes.h>
9998+#else
9999+#include <stdint.h>
10000+#endif
10001+
10002+
10003+struct xml_value_parser;
10004+
10005+struct xml_value_parser {
10006+ int type;
10007+ char *name;
10008+ char *(*parser)(void **, char *, void *, intptr_t offset);
10009+ intptr_t offset;
10010+};
10011+
10012+struct xml_conf_section {
10013+ void *(*conf)();
10014+ char *path;
10015+ struct xml_value_parser *parsers;
10016+};
10017+
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);
10022+
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[]);
10029+
10030+#define expand_hms(value) (value) / 3600, ((value) % 3600) / 60, (value) % 60
10031+
10032+#define expand_dhms(value) (value) / 86400, ((value) % 86400) / 3600, ((value) % 3600) / 60, (value) % 60
10033+
10034+enum { XML_CONF_SCALAR = 1, XML_CONF_SUBSECTION = 2 };
10035+
10036+#endif
10037diff -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
10040@@ -0,0 +1,113 @@
10041+
10042+ /* $Id$ */
10043+ /* (c) 2004-2007 Andrei Nigmatulin */
10044+
10045+#include "fpm_config.h"
10046+
10047+#include <stdio.h>
10048+#include <unistd.h>
10049+#include <time.h>
10050+#include <string.h>
10051+#include <stdarg.h>
10052+#include <sys/time.h>
10053+#include <errno.h>
10054+
10055+#include "zlog.h"
10056+
10057+#define MAX_LINE_LENGTH 1024
10058+
10059+static int zlog_fd = -1;
10060+static int zlog_level = ZLOG_NOTICE;
10061+
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",
10068+};
10069+
10070+size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len)
10071+{
10072+ struct tm t;
10073+ size_t len;
10074+
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);
10077+
10078+ return len;
10079+}
10080+
10081+int zlog_set_fd(int new_fd)
10082+{
10083+ int old_fd = zlog_fd;
10084+ zlog_fd = new_fd;
10085+
10086+ return old_fd;
10087+}
10088+
10089+int zlog_set_level(int new_value)
10090+{
10091+ int old_value = zlog_level;
10092+
10093+ zlog_level = new_value;
10094+
10095+ return old_value;
10096+}
10097+
10098+void zlog(const char *function, int line, int flags, const char *fmt, ...)
10099+{
10100+ struct timeval tv;
10101+ char buf[MAX_LINE_LENGTH];
10102+ const size_t buf_size = MAX_LINE_LENGTH;
10103+ va_list args;
10104+ size_t len;
10105+ int truncated = 0;
10106+ int saved_errno;
10107+
10108+ if ((flags & ZLOG_LEVEL_MASK) < zlog_level) {
10109+ return;
10110+ }
10111+
10112+ saved_errno = errno;
10113+
10114+ gettimeofday(&tv, 0);
10115+
10116+ len = zlog_print_time(&tv, buf, buf_size);
10117+
10118+ len += snprintf(buf + len, buf_size - len, " [%s] %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line);
10119+
10120+ if (len > buf_size - 1) {
10121+ truncated = 1;
10122+ }
10123+
10124+ if (!truncated) {
10125+ va_start(args, fmt);
10126+
10127+ len += vsnprintf(buf + len, buf_size - len, fmt, args);
10128+
10129+ va_end(args);
10130+
10131+ if (len >= buf_size) {
10132+ truncated = 1;
10133+ }
10134+ }
10135+
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) {
10140+ truncated = 1;
10141+ }
10142+ }
10143+ }
10144+
10145+ if (truncated) {
10146+ memcpy(buf + buf_size - sizeof("..."), "...", sizeof("...") - 1);
10147+ len = buf_size - 1;
10148+ }
10149+
10150+ buf[len++] = '\n';
10151+
10152+ write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len);
10153+}
10154diff -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
10157@@ -0,0 +1,34 @@
10158+
10159+ /* $Id$ */
10160+ /* (c) 2004-2007 Andrei Nigmatulin */
10161+
10162+#ifndef ZLOG_H
10163+#define ZLOG_H 1
10164+
10165+#define ZLOG_STUFF __func__, __LINE__
10166+
10167+struct timeval;
10168+
10169+int zlog_set_fd(int new_fd);
10170+int zlog_set_level(int new_value);
10171+
10172+size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len);
10173+
10174+void zlog(const char *function, int line, int flags, const char *fmt, ...)
10175+ __attribute__ ((format(printf,4,5)));
10176+
10177+enum {
10178+ ZLOG_DEBUG = 1,
10179+ ZLOG_NOTICE = 2,
10180+ ZLOG_WARNING = 3,
10181+ ZLOG_ERROR = 4,
10182+ ZLOG_ALERT = 5,
10183+};
10184+
10185+#define ZLOG_LEVEL_MASK 7
10186+
10187+#define ZLOG_HAVE_ERRNO 0x100
10188+
10189+#define ZLOG_SYSERROR (ZLOG_ERROR | ZLOG_HAVE_ERRNO)
10190+
10191+#endif
10192diff -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
10195@@ -0,0 +1,23 @@
10196+Copyright (c) 2007-2009, Andrei Nigmatulin
10197+All rights reserved.
10198+
10199+Redistribution and use in source and binary forms, with or without
10200+modification, are permitted provided that the following conditions
10201+are met:
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.
10207+
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
10218+SUCH DAMAGE.
10219diff -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
10222@@ -0,0 +1,186 @@
10223+.TH PHP-FPM 1 "2009" "The PHP Group" "Scripting Language"
10224+.SH NAME
10225+.TP 15
10226+@php_fpm_bin@ \- PHP FastCGI Process Manager 'PHP-FPM'
10227+.SH SYNOPSIS
10228+.B @php_fpm_bin@
10229+[options]
10230+.LP
10231+.SH DESCRIPTION
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@.
10234+.LP
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.
10236+.SH OPTIONS
10237+.TP 15
10238+.B \-C
10239+Do not chdir to the script's directory
10240+.TP
10241+.PD 0
10242+.B \-\-php\-ini \fIpath\fP|\fIfile\fP
10243+.TP
10244+.PD 1
10245+.B \-c \fIpath\fP|\fIfile\fP
10246+Look for
10247+.B php.ini
10248+file in the directory
10249+.IR path
10250+or use the specified
10251+.IR file
10252+.TP
10253+.PD 0
10254+.B \-\-no\-php\-ini
10255+.TP
10256+.PD 1
10257+.B \-n
10258+No
10259+.B php.ini
10260+file will be used
10261+.TP
10262+.PD 0
10263+.B \-\-define \fIfoo\fP[=\fIbar\fP]
10264+.TP
10265+.PD 1
10266+.B \-d \fIfoo\fP[=\fIbar\fP]
10267+Define INI entry
10268+.IR foo
10269+with value
10270+.IR bar
10271+.TP
10272+.B \-e
10273+Generate extended information for debugger/profiler
10274+.TP
10275+.PD 0
10276+.B \-\-help
10277+.TP
10278+.PD 1
10279+.B \-h
10280+This help
10281+.TP
10282+.PD 0
10283+.B \-\-info
10284+.TP
10285+.PD 1
10286+.B \-i
10287+PHP information and configuration
10288+.TP
10289+.PD 0
10290+.B \-\-modules
10291+.TP
10292+.PD 1
10293+.B \-m
10294+Show compiled in modules
10295+.TP
10296+.PD 0
10297+.B \-\-version
10298+.TP
10299+.PD 1
10300+.B \-v
10301+Version number
10302+.TP
10303+.PD 0
10304+.B \-\-fpm\-config \fIfile\fP
10305+.TP
10306+.PD 1
10307+.B \-\-y
10308+Specify alternative path to FastCGI process manager configuration file (the default is @php_fpm_conf_path@)
10309+.TP
10310+.PD 0
10311+.B \-\-zend\-extension \fIfile\fP
10312+.TP
10313+.PD 1
10314+.B \-z \fIfile\fP
10315+Load Zend extension
10316+.IR file
10317+.SH FILES
10318+.TP 15
10319+.B @php_fpm_bin@.conf
10320+The configuration file for the @php_fpm_bin@ daemon.
10321+.TP
10322+.B php.ini
10323+The standard php configuration file.
10324+.SH EXAMPLES
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.
10326+.P
10327+.PD 1
10328+.RS
10329+sudo /etc/init.d/@php_fpm_bin@ start
10330+.RE
10331+.TP
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:
10333+.P
10334+.PD 0
10335+.RS
10336+.B SIGINT,SIGTERM \fPimmediate termination
10337+.TP
10338+.B SIGQUIT \fPgraceful stop
10339+.TP
10340+.B SIGUSR1 \fPre-open log file
10341+.TP
10342+.B SIGUSR2 \fPgraceful reload of all workers + reload of fpm conf/binary
10343+.RE
10344+.PD 1
10345+.P
10346+.SH TIPS
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').
10348+.PD 1
10349+.P
10350+.SH SEE ALSO
10351+The PHP-FPM website:
10352+.PD 0
10353+.P
10354+.B http://php-fpm.org
10355+.PD 1
10356+.P
10357+For a more or less complete description of PHP look here:
10358+.PD 0
10359+.P
10360+.B http://www.php.net/manual/
10361+.PD 1
10362+.P
10363+A nice introduction to PHP by Stig Bakken can be found here:
10364+.PD 0
10365+.P
10366+.B http://www.zend.com/zend/art/intro.php
10367+.PD 1
10368+.SH BUGS
10369+You can view the list of known bugs or report any new bug you
10370+found at:
10371+.PD 0
10372+.P
10373+.B http://bugs.php.net
10374+.PD 1
10375+.SH AUTHORS
10376+PHP-FPM Sapi was written by Andrei Nigmatulin. The mailing-lists are highload-php-en (English) and highload-php-ru (Russion).
10377+.P
10378+The PHP Group: Thies C. Arntzen, Stig Bakken, Andi Gutmans, Rasmus Lerdorf, Sam Ruby, Sascha Schumann, Zeev Suraski, Jim Winstead, Andrei Zmievski.
10379+.P
10380+A List of active developers can be found here:
10381+.PD 0
10382+.P
10383+.B http://www.php.net/credits.php
10384+.PD 1
10385+.P
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@.
10390+.SH COPYRIGHT
10391+Copyright \(co 1997\-2009 The PHP Group
10392+.PD 0
10393+.P
10394+Copyright (c) 2007-2009, Andrei Nigmatulin
10395+.PD 1
10396+.LP
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:
10400+.PD 0
10401+.P
10402+.B http://www.php.net/license/3_01.txt
10403+.PD 1
10404+.P
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.
10409diff -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
10412@@ -0,0 +1,127 @@
10413+# PHP FastCGI Менеджер процессов (PHP-FPM)
10414+
10415+PHP-FPM это Fast-CGI фронтэнд для php и расширение php-cgi. Проект находится на [Launchpad](https://launchpad.net/php-fpm)
10416+
10417+## Быстрый старт:
10418+
10419+Выберите один из 2 путей сборки fpm: Или `встроенный`, или `отдельный`. Если вы не разработчик или не системный администратор, то мы рекомендуем `встроенный` вариант компиляции. Для дополнительной информации смотрите файл `readme.markdown`.
10420+
10421+## Зависимости
10422+Если вы до этого не устанавливали php, то вам придётся установить пакет `libxml2-dev`. FPM также необходим `libevent-dev`. Debian / ubuntu:
10423+
10424+ sudo aptitude install -y libxml2-dev libevent-dev
10425+
10426+Рекомендуется использовать libevent 1.4.12-stable или позднее, но необходим, как минимум, libevent 1.4.3-stable. Если нет подходящей версии, скайте и скомпилируйте с [сайта Libevent](http://www.monkey.org/~provos/libevent/).
10427+
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"
10435+
10436+## Встроенная сборка
10437+
10438+Скачайте fpm и сгенерируйте патч
10439+
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"
10444+
10445+Скачайте и распакуйте исходный код PHP
10446+
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"
10450+
10451+Примените патч и компилируйте
10452+
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
10458+
10459+## Отдельная сборка
10460+
10461+Скачайте и распакуйте исходный код PHP
10462+
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
10469+
10470+Теперь можете скачать, конфигурировать и компилировать FPM фронтэнд
10471+
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
10480+
10481+## Флаги конфигурирования
10482+
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]
10493+
10494+## Установка
10495+
10496+Если вы делали `встроенную` сборку, то вы получите полный php, включая исполнитель коммандной строки `php-cli` и библиотеку PEAR. `Отдельная` или `независимая` сборка установит только демон `php-fpm` и минимум файлов, необходимых для его запуска.
10497+
10498+ # Посмотреть, какие файлы будут установлены
10499+ make install --dry-run
10500+
10501+ # Установить в '/'
10502+ sudo make install
10503+
10504+ # Установить в '/opt'
10505+ sudo INSTALL_ROOT=/opt make install
10506+
10507+Notes:
10508+
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.
10510+
10511+* (BSD) the default init.d path is `/usr/local/etc/rc.d/php-fpm` or disable: `--without-fpm-init`
10512+
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`
10514+
10515+## Больше о процессе сборки PHP-FPM
10516+
10517+Процесс сборки можно описать так:
10518+
10519+ 1) Компилируются исходники php в объектные файлы
10520+ 2) Компилируются исходники fpm в объектные файлы
10521+ 3) Линковка php и fpm объектных файлов
10522+ 4) Результат: исполняемый php5, в основе которого php и fast-CGI от fpm как фронтэнд
10523+
10524+Fpm подмешивается в php при линковке (link-level). Андрей разделил исходный код fpm, сделав SAPI чем-то менее чуствительным к изменениям в остальном коде php. Код cgi-main.c из PHP-FPM - конктроллер запросов - вырезан из оригинального fcgi-sapi. Мы отправляем билд 0.6 в PHP Group. Мы будем отслеживать развитие PHP и периодически синхронизировать изменения с проектами встроенной / отдельной сборки.
10525+
10526+## Buildconf
10527+
10528+Для сборки fpm отдельно, конфигурирование (`./configure`) требует некоторой версии набора инструментов autoconf. Buildconf запустит `./generate-autotools` и попробует установить эти инструменты самостоятельно. Если `./buildconf` не работает, смотрите лог ошибок.
10529+
10530+
10531+## Обсуждение
10532+
10533+Есть 2 группы для обсуждения php-fpm,
10534+
10535+- [highload-php-ru](http://groups.google.com/group/highload-php-en) (english)
10536+
10537+- [highload-php-ru](http://groups.google.com/group/highload-php-ru) (русская)
10538+
10539+Translated by Anatoly Pashin
This page took 1.864228 seconds and 4 git commands to generate.