]>
Commit | Line | Data |
---|---|---|
37d32ffb ER |
1 | diff --git a/configure b/configure |
2 | index 2d88ed7..c490abf 100755 | |
3 | diff --git a/configure.in b/configure.in | |
4 | index e181ac9..4424930 100644 | |
5 | --- a/configure.in | |
6 | +++ b/configure.in | |
7 | @@ -295,6 +295,12 @@ if test "$enable_maintainer_zts" = "yes"; then | |
e327cc0e | 8 | PTHREADS_FLAGS |
fd1be940 ER |
9 | fi |
10 | ||
e327cc0e ER |
11 | +if test "$PHP_FASTCGI" = "yes" -a "$PHP_FPM" = "yes"; then |
12 | + PHP_CONFIGURE_PART(Running FastCGI Process Manager checks) | |
8c0dac15 ER |
13 | + sinclude(sapi/cgi/fpm/acinclude.m4) |
14 | + sinclude(sapi/cgi/fpm/config.m4) | |
fd1be940 ER |
15 | +fi |
16 | + | |
e327cc0e | 17 | divert(3) |
fd1be940 | 18 | |
e327cc0e | 19 | dnl ## In diversion 3 we check for compile-time options to the PHP |
37d32ffb | 20 | @@ -511,6 +517,7 @@ AC_CHECK_FUNCS( |
e327cc0e ER |
21 | alphasort \ |
22 | asctime_r \ | |
23 | chroot \ | |
24 | +clearenv \ | |
25 | ctime_r \ | |
26 | cuserid \ | |
27 | crypt \ | |
37d32ffb | 28 | @@ -1253,6 +1260,8 @@ PHP_SUBST_OLD(EXTENSION_DIR) |
e327cc0e ER |
29 | PHP_SUBST_OLD(EXTRA_LDFLAGS) |
30 | PHP_SUBST_OLD(EXTRA_LDFLAGS_PROGRAM) | |
31 | PHP_SUBST_OLD(EXTRA_LIBS) | |
32 | +PHP_SUBST_OLD(SAPI_EXTRA_LIBS) | |
33 | +PHP_SUBST_OLD(SAPI_EXTRA_DEPS) | |
34 | PHP_SUBST_OLD(ZEND_EXTRA_LIBS) | |
35 | PHP_SUBST_OLD(INCLUDES) | |
36 | PHP_SUBST_OLD(EXTRA_INCLUDES) | |
37d32ffb | 37 | @@ -1364,7 +1373,7 @@ case $PHP_SAPI in |
e327cc0e ER |
38 | install_targets="$PHP_INSTALL_CLI_TARGET $install_targets" |
39 | ;; | |
40 | *) | |
41 | - install_targets="install-sapi $PHP_INSTALL_CLI_TARGET $install_targets" | |
42 | + install_targets="install-sapi $install_fpm $PHP_INSTALL_CLI_TARGET $install_targets" | |
43 | ;; | |
44 | esac | |
fd1be940 | 45 | |
37d32ffb ER |
46 | diff --git a/libevent/ChangeLog b/libevent/ChangeLog |
47 | new file mode 100644 | |
48 | index 0000000..c592139 | |
49 | diff --git a/libevent/Makefile.am b/libevent/Makefile.am | |
50 | new file mode 100644 | |
51 | index 0000000..5ccfd2c | |
52 | diff --git a/libevent/Makefile.in b/libevent/Makefile.in | |
53 | new file mode 100644 | |
54 | index 0000000..0600dcc | |
55 | diff --git a/libevent/README b/libevent/README | |
56 | new file mode 100644 | |
57 | index 0000000..b065039 | |
58 | diff --git a/libevent/aclocal.m4 b/libevent/aclocal.m4 | |
59 | new file mode 100644 | |
60 | index 0000000..74de4a1 | |
61 | diff --git a/libevent/autogen.sh b/libevent/autogen.sh | |
62 | new file mode 100644 | |
63 | index 0000000..218dbf4 | |
64 | diff --git a/libevent/buffer.c b/libevent/buffer.c | |
65 | new file mode 100644 | |
66 | index 0000000..e66080f | |
67 | diff --git a/libevent/compat/sys/_time.h b/libevent/compat/sys/_time.h | |
68 | new file mode 100644 | |
69 | index 0000000..8cabb0d | |
70 | diff --git a/libevent/compat/sys/queue.h b/libevent/compat/sys/queue.h | |
71 | new file mode 100644 | |
72 | index 0000000..c0956dd | |
73 | diff --git a/libevent/config.h.in b/libevent/config.h.in | |
74 | new file mode 100644 | |
75 | index 0000000..d151f87 | |
76 | diff --git a/libevent/configure b/libevent/configure | |
77 | new file mode 100644 | |
78 | index 0000000..0a74aec | |
79 | diff --git a/libevent/configure.in b/libevent/configure.in | |
80 | new file mode 100644 | |
81 | index 0000000..852d3c5 | |
82 | diff --git a/libevent/depcomp b/libevent/depcomp | |
83 | new file mode 100644 | |
84 | index 0000000..ffcd540 | |
85 | diff --git a/libevent/devpoll.c b/libevent/devpoll.c | |
86 | new file mode 100644 | |
87 | index 0000000..cbd2730 | |
88 | diff --git a/libevent/epoll.c b/libevent/epoll.c | |
89 | new file mode 100644 | |
90 | index 0000000..cf3c859 | |
91 | diff --git a/libevent/epoll_sub.c b/libevent/epoll_sub.c | |
92 | new file mode 100644 | |
93 | index 0000000..431970c | |
94 | diff --git a/libevent/evbuffer.c b/libevent/evbuffer.c | |
95 | new file mode 100644 | |
96 | index 0000000..f2179a5 | |
97 | diff --git a/libevent/event-config.h b/libevent/event-config.h | |
98 | new file mode 100644 | |
99 | index 0000000..0a278b3 | |
100 | diff --git a/libevent/event-fpm.h b/libevent/event-fpm.h | |
101 | new file mode 100644 | |
102 | index 0000000..8625ca5 | |
103 | diff --git a/libevent/event-internal.h b/libevent/event-internal.h | |
104 | new file mode 100644 | |
105 | index 0000000..7485f21 | |
106 | diff --git a/libevent/event.3 b/libevent/event.3 | |
107 | new file mode 100644 | |
108 | index 0000000..5b33ec6 | |
109 | diff --git a/libevent/event.c b/libevent/event.c | |
110 | new file mode 100644 | |
111 | index 0000000..826b7db | |
112 | diff --git a/libevent/event.h b/libevent/event.h | |
113 | new file mode 100644 | |
114 | index 0000000..d67ecb5 | |
115 | diff --git a/libevent/evhttp.h b/libevent/evhttp.h | |
116 | new file mode 100644 | |
117 | index 0000000..0d35f9e | |
118 | diff --git a/libevent/evport.c b/libevent/evport.c | |
119 | new file mode 100644 | |
120 | index 0000000..31523b4 | |
121 | diff --git a/libevent/evsignal.h b/libevent/evsignal.h | |
122 | new file mode 100644 | |
123 | index 0000000..8be9cbd | |
124 | diff --git a/libevent/evutil.c b/libevent/evutil.c | |
125 | new file mode 100644 | |
126 | index 0000000..86205b2 | |
127 | diff --git a/libevent/evutil.h b/libevent/evutil.h | |
128 | new file mode 100644 | |
129 | index 0000000..0a018b8 | |
130 | diff --git a/libevent/http-internal.h b/libevent/http-internal.h | |
131 | new file mode 100644 | |
132 | index 0000000..bc9a1ed | |
133 | diff --git a/libevent/http.c b/libevent/http.c | |
134 | new file mode 100644 | |
135 | index 0000000..1d60fc5 | |
136 | diff --git a/libevent/install-sh b/libevent/install-sh | |
137 | new file mode 100644 | |
138 | index 0000000..1a83534 | |
139 | diff --git a/libevent/kqueue.c b/libevent/kqueue.c | |
140 | new file mode 100644 | |
141 | index 0000000..38a1819 | |
142 | diff --git a/libevent/log.c b/libevent/log.c | |
143 | new file mode 100644 | |
144 | index 0000000..b62a619 | |
145 | diff --git a/libevent/log.h b/libevent/log.h | |
146 | new file mode 100644 | |
147 | index 0000000..7bc6632 | |
148 | diff --git a/libevent/min_heap.h b/libevent/min_heap.h | |
149 | new file mode 100644 | |
150 | index 0000000..d47e563 | |
151 | diff --git a/libevent/missing b/libevent/missing | |
152 | new file mode 100644 | |
153 | index 0000000..09edd88 | |
154 | diff --git a/libevent/poll.c b/libevent/poll.c | |
155 | new file mode 100644 | |
156 | index 0000000..b67c6ff | |
157 | diff --git a/libevent/select.c b/libevent/select.c | |
158 | new file mode 100644 | |
159 | index 0000000..7faafe4 | |
160 | diff --git a/libevent/signal.c b/libevent/signal.c | |
161 | new file mode 100644 | |
162 | index 0000000..bcaa3f9 | |
163 | diff --git a/libevent/strlcpy-internal.h b/libevent/strlcpy-internal.h | |
164 | new file mode 100644 | |
165 | index 0000000..22b5f61 | |
166 | diff --git a/libevent/strlcpy.c b/libevent/strlcpy.c | |
167 | new file mode 100644 | |
168 | index 0000000..a1a413d | |
169 | diff --git a/main/php_config.h.in b/main/php_config.h.in | |
37d32ffb ER |
170 | --- a/main/php_config.h.in |
171 | +++ b/main/php_config.h.in | |
fd1be940 ER |
172 | @@ -170,6 +170,9 @@ |
173 | /* Define if you have the chroot function. */ | |
174 | #undef HAVE_CHROOT | |
175 | ||
176 | +/* Define if you have the clearenv function. */ | |
177 | +#undef HAVE_CLEARENV | |
178 | + | |
179 | /* Define if you have the crypt function. */ | |
180 | #undef HAVE_CRYPT | |
181 | ||
37d32ffb | 182 | @@ -935,6 +938,9 @@ |
fd1be940 ER |
183 | /* */ |
184 | #undef PHP_FASTCGI | |
185 | ||
186 | +/* Is experimental fastcgi process manager code activated */ | |
187 | +#undef PHP_FASTCGI_PM | |
188 | + | |
189 | /* */ | |
190 | #undef FORCE_CGI_REDIRECT | |
191 | ||
37d32ffb | 192 | @@ -944,6 +950,27 @@ |
fd1be940 ER |
193 | /* */ |
194 | #undef ENABLE_PATHINFO_CHECK | |
195 | ||
196 | +/* do we have libxml? */ | |
197 | +#undef HAVE_LIBXML | |
c6a6bfc9 ER |
198 | + |
199 | +/* do we have prctl? */ | |
200 | +#undef HAVE_PRCTL | |
201 | + | |
202 | +/* do we have clock_gettime? */ | |
203 | +#undef HAVE_CLOCK_GETTIME | |
204 | + | |
205 | +/* do we have clock_get_time? */ | |
206 | +#undef HAVE_CLOCK_GET_TIME | |
207 | + | |
208 | +/* do we have ptrace? */ | |
209 | +#undef HAVE_PTRACE | |
210 | + | |
211 | +/* do we have mach_vm_read? */ | |
212 | +#undef HAVE_MACH_VM_READ | |
213 | + | |
214 | +/* /proc/pid/mem interface */ | |
215 | +#undef PROC_MEM_FILE | |
fd1be940 ER |
216 | + |
217 | /* Define if system uses EBCDIC */ | |
218 | #undef CHARSET_EBCDIC | |
219 | ||
873ee61a ER |
220 | --- php-5.2.17/sapi/cgi/Makefile.frag~ 2012-02-27 14:44:23.000000000 +0200 |
221 | +++ php-5.2.17/sapi/cgi/Makefile.frag 2012-02-27 14:46:13.037731342 +0200 | |
37d32ffb | 222 | @@ -1,2 +1,2 @@ |
873ee61a ER |
223 | -$(SAPI_CGI_PATH): libphp_common.la $(PHP_SAPI_OBJS) |
224 | +$(SAPI_CGI_PATH): libphp_common.la $(PHP_SAPI_OBJS) $(SAPI_EXTRA_DEPS) | |
37d32ffb ER |
225 | $(BUILD_CGI) |
226 | diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c | |
37d32ffb ER |
227 | --- a/sapi/cgi/cgi_main.c |
228 | +++ b/sapi/cgi/cgi_main.c | |
fd1be940 ER |
229 | @@ -55,6 +55,9 @@ |
230 | #if HAVE_SYS_WAIT_H | |
231 | #include <sys/wait.h> | |
232 | #endif | |
233 | +#if HAVE_FCNTL_H | |
234 | +#include <fcntl.h> | |
235 | +#endif | |
236 | #include "zend.h" | |
237 | #include "zend_extensions.h" | |
238 | #include "php_ini.h" | |
37d32ffb | 239 | @@ -83,6 +86,11 @@ int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS; |
fd1be940 ER |
240 | #if PHP_FASTCGI |
241 | #include "fastcgi.h" | |
242 | ||
243 | +#if PHP_FASTCGI_PM | |
244 | +#include "fpm/fpm.h" | |
c6a6bfc9 | 245 | +#include "fpm/fpm_request.h" |
fd1be940 ER |
246 | +#endif |
247 | + | |
248 | #ifndef PHP_WIN32 | |
249 | /* XXX this will need to change later when threaded fastcgi is | |
250 | implemented. shane */ | |
37d32ffb | 251 | @@ -115,8 +123,12 @@ static int parent_waiting = 0; |
fd1be940 ER |
252 | static pid_t pgroup; |
253 | #endif | |
254 | ||
255 | +static int request_body_fd; | |
256 | + | |
257 | #endif | |
258 | ||
259 | +static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC); | |
260 | + | |
261 | #define PHP_MODE_STANDARD 1 | |
262 | #define PHP_MODE_HIGHLIGHT 2 | |
263 | #define PHP_MODE_INDENT 3 | |
37d32ffb | 264 | @@ -146,6 +158,10 @@ static const opt_struct OPTIONS[] = { |
fd1be940 ER |
265 | {'w', 0, "strip"}, |
266 | {'?', 0, "usage"},/* help alias (both '?' and 'usage') */ | |
267 | {'v', 0, "version"}, | |
268 | +#if PHP_FASTCGI_PM | |
269 | + {'x', 0, "fpm"}, | |
270 | + {'y', 1, "fpm-config"}, | |
271 | +#endif | |
272 | {'z', 1, "zend-extension"}, | |
c6a6bfc9 ER |
273 | #if PHP_FASTCGI |
274 | {'T', 1, "timing"}, | |
37d32ffb | 275 | @@ -170,6 +186,7 @@ typedef struct _php_cgi_globals_struct { |
fd1be940 ER |
276 | zend_bool impersonate; |
277 | # endif | |
fd1be940 | 278 | #endif |
c6a6bfc9 | 279 | + char *error_header; |
fd1be940 ER |
280 | } php_cgi_globals_struct; |
281 | ||
c6a6bfc9 | 282 | #ifdef ZTS |
37d32ffb | 283 | @@ -474,7 +491,28 @@ static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC) |
fd1be940 ER |
284 | #if PHP_FASTCGI |
285 | if (fcgi_is_fastcgi()) { | |
286 | fcgi_request *request = (fcgi_request*) SG(server_context); | |
287 | - tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes); | |
288 | + | |
289 | + if (request_body_fd == -1) { | |
c6a6bfc9 ER |
290 | + char *request_body_filename = sapi_cgibin_getenv((char *) "REQUEST_BODY_FILE", |
291 | + sizeof("REQUEST_BODY_FILE")-1 TSRMLS_CC); | |
292 | + | |
fd1be940 ER |
293 | + if (request_body_filename && *request_body_filename) { |
294 | + request_body_fd = open(request_body_filename, O_RDONLY); | |
c6a6bfc9 ER |
295 | + |
296 | + if (0 > request_body_fd) { | |
297 | + php_error(E_WARNING, "REQUEST_BODY_FILE: open('%s') failed: %s (%d)", | |
298 | + request_body_filename, strerror(errno), errno); | |
299 | + return 0; | |
300 | + } | |
fd1be940 ER |
301 | + } |
302 | + } | |
303 | + | |
304 | + /* If REQUEST_BODY_FILE variable not available - read post body from fastcgi stream */ | |
fd1be940 ER |
305 | + if (request_body_fd < 0) { |
306 | + tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes); | |
307 | + } else { | |
308 | + tmp_read_bytes = read(request_body_fd, buffer + read_bytes, count_bytes - read_bytes); | |
309 | + } | |
310 | } else { | |
37d32ffb | 311 | tmp_read_bytes = read(STDIN_FILENO, buffer + read_bytes, count_bytes - read_bytes); |
fd1be940 | 312 | } |
37d32ffb | 313 | @@ -786,7 +824,12 @@ static void php_cgi_usage(char *argv0) |
fd1be940 ER |
314 | " -s Display colour syntax highlighted source.\n" |
315 | " -v Version number\n" | |
316 | " -w Display source with stripped comments and whitespace.\n" | |
c6a6bfc9 | 317 | - " -z <file> Load Zend extension <file>.\n" |
fd1be940 ER |
318 | +#if PHP_FASTCGI_PM |
319 | + " -x, --fpm Run in FastCGI process manager mode.\n" | |
320 | + " -y, --fpm-config <file>\n" | |
321 | + " Specify alternative path to FastCGI process manager config file.\n" | |
322 | +#endif | |
c6a6bfc9 ER |
323 | + " -z <file> Load Zend extension <file>.\n" |
324 | #if PHP_FASTCGI | |
325 | " -T <count> Measure execution time of script repeated <count> times.\n" | |
326 | #endif | |
37d32ffb | 327 | @@ -1236,6 +1279,7 @@ PHP_INI_BEGIN() |
fd1be940 ER |
328 | # ifdef PHP_WIN32 |
329 | STD_PHP_INI_ENTRY("fastcgi.impersonate", "0", PHP_INI_SYSTEM, OnUpdateBool, impersonate, php_cgi_globals_struct, php_cgi_globals) | |
330 | # endif | |
331 | + STD_PHP_INI_ENTRY("fastcgi.error_header", NULL, PHP_INI_SYSTEM, OnUpdateString, error_header, php_cgi_globals_struct, php_cgi_globals) | |
332 | #endif | |
333 | PHP_INI_END() | |
334 | ||
37d32ffb | 335 | @@ -1258,6 +1302,7 @@ static void php_cgi_globals_ctor(php_cgi_globals_struct *php_cgi_globals TSRMLS_ |
fd1be940 ER |
336 | # ifdef PHP_WIN32 |
337 | php_cgi_globals->impersonate = 0; | |
338 | # endif | |
339 | + php_cgi_globals->error_header = NULL; | |
340 | #endif | |
341 | } | |
342 | /* }}} */ | |
37d32ffb | 343 | @@ -1290,9 +1335,47 @@ static PHP_MSHUTDOWN_FUNCTION(cgi) |
c6a6bfc9 ER |
344 | static PHP_MINFO_FUNCTION(cgi) |
345 | { | |
346 | DISPLAY_INI_ENTRIES(); | |
347 | + | |
348 | +#if PHP_FASTCGI_PM | |
349 | + | |
350 | +#include "fpm/fpm_autoconf.h" | |
351 | + | |
352 | + php_info_print_table_start(); | |
353 | + php_info_print_table_row(2, "php-fpm", fpm ? "active" : "inactive"); | |
354 | + php_info_print_table_row(2, "php-fpm version", PHP_FPM_VERSION); | |
355 | + php_info_print_table_end(); | |
356 | +#endif | |
357 | + | |
fd1be940 ER |
358 | } |
359 | /* }}} */ | |
360 | ||
361 | +#if PHP_FASTCGI | |
362 | +PHP_FUNCTION(fastcgi_finish_request) | |
363 | +{ | |
364 | + fcgi_request *request = (fcgi_request*) SG(server_context); | |
365 | + | |
366 | + if (fcgi_is_fastcgi() && request->fd >= 0) { | |
367 | + | |
368 | + php_end_ob_buffers(1 TSRMLS_CC); | |
369 | + php_header(TSRMLS_C); | |
370 | + | |
371 | + fcgi_flush(request, 1); | |
372 | + fcgi_close(request, 0, 0); | |
373 | + RETURN_TRUE; | |
374 | + } | |
375 | + | |
376 | + RETURN_FALSE; | |
377 | + | |
378 | +} | |
379 | +#endif | |
380 | + | |
381 | +function_entry cgi_fcgi_sapi_functions[] = { | |
382 | +#if PHP_FASTCGI | |
383 | + PHP_FE(fastcgi_finish_request, NULL) | |
384 | +#endif | |
385 | + {NULL, NULL, NULL} | |
386 | +}; | |
387 | + | |
388 | static zend_module_entry cgi_module_entry = { | |
389 | STANDARD_MODULE_HEADER, | |
390 | #if PHP_FASTCGI | |
37d32ffb | 391 | @@ -1300,7 +1383,7 @@ static zend_module_entry cgi_module_entry = { |
fd1be940 ER |
392 | #else |
393 | "cgi", | |
394 | #endif | |
395 | - NULL, | |
396 | + cgi_fcgi_sapi_functions, | |
397 | PHP_MINIT(cgi), | |
398 | PHP_MSHUTDOWN(cgi), | |
399 | NULL, | |
37d32ffb | 400 | @@ -1340,6 +1423,7 @@ int main(int argc, char *argv[]) |
fd1be940 ER |
401 | char *bindpath = NULL; |
402 | int fcgi_fd = 0; | |
403 | fcgi_request request; | |
fd1be940 | 404 | + char *fpm_config = NULL; |
c6a6bfc9 ER |
405 | int repeats = 1; |
406 | int benchmark = 0; | |
407 | #if HAVE_GETTIMEOFDAY | |
37d32ffb | 408 | @@ -1460,6 +1544,14 @@ int main(int argc, char *argv[]) |
fd1be940 ER |
409 | case 's': /* generate highlighted HTML from source */ |
410 | behavior = PHP_MODE_HIGHLIGHT; | |
411 | break; | |
412 | +#if PHP_FASTCGI_PM | |
413 | + case 'y': | |
414 | + fpm_config = php_optarg; | |
415 | + break; | |
416 | + case 'x': | |
417 | + fpm = 1; | |
418 | + break; | |
419 | +#endif | |
420 | ||
421 | } | |
422 | ||
37d32ffb | 423 | @@ -1524,6 +1616,19 @@ consult the installation file that came with this distribution, or visit \n\ |
fd1be940 ER |
424 | #endif /* FORCE_CGI_REDIRECT */ |
425 | ||
426 | #if PHP_FASTCGI | |
427 | +#if PHP_FASTCGI_PM | |
428 | + if (fpm) { | |
429 | + if (0 > fpm_init(argc, argv, fpm_config)) { | |
430 | + return FAILURE; | |
431 | + } | |
432 | + | |
433 | + fcgi_fd = fpm_run(&max_requests); | |
434 | + | |
435 | + fcgi_set_is_fastcgi(fastcgi = 1); | |
436 | + } | |
437 | + else | |
438 | +#endif | |
439 | + | |
440 | if (bindpath) { | |
441 | fcgi_fd = fcgi_listen(bindpath, 128); | |
442 | if (fcgi_fd < 0) { | |
37d32ffb | 443 | @@ -1538,6 +1643,9 @@ consult the installation file that came with this distribution, or visit \n\ |
fd1be940 ER |
444 | |
445 | if (fastcgi) { | |
446 | /* How many times to run PHP scripts before dying */ | |
5659f47e | 447 | +#if PHP_FASTCGI_PM |
48b142c9 | 448 | + if (!fpm) |
5659f47e | 449 | +#endif |
48b142c9 | 450 | if (getenv("PHP_FCGI_MAX_REQUESTS")) { |
5659f47e ER |
451 | max_requests = atoi(getenv("PHP_FCGI_MAX_REQUESTS")); |
452 | if (max_requests < 0) { | |
37d32ffb | 453 | @@ -1555,6 +1663,9 @@ consult the installation file that came with this distribution, or visit \n\ |
5659f47e ER |
454 | |
455 | #ifndef PHP_WIN32 | |
456 | /* Pre-fork, if required */ | |
5659f47e | 457 | +#if PHP_FASTCGI_PM |
48b142c9 | 458 | + if (!fpm) |
5659f47e | 459 | +#endif |
48b142c9 | 460 | if (getenv("PHP_FCGI_CHILDREN")) { |
633983a3 AM |
461 | char * children_str = getenv("PHP_FCGI_CHILDREN"); |
462 | children = atoi(children_str); | |
37d32ffb | 463 | @@ -1704,6 +1815,8 @@ consult the installation file that came with this distribution, or visit \n\ |
fd1be940 ER |
464 | #endif |
465 | ||
466 | #if PHP_FASTCGI | |
467 | + request_body_fd = -1; | |
468 | + | |
469 | SG(server_context) = (void *) &request; | |
470 | #else | |
471 | SG(server_context) = (void *) 1; /* avoid server_context==NULL checks */ | |
37d32ffb | 472 | @@ -1711,6 +1824,10 @@ consult the installation file that came with this distribution, or visit \n\ |
c6a6bfc9 ER |
473 | init_request_info(TSRMLS_C); |
474 | CG(interactive) = 0; | |
475 | ||
476 | +#if PHP_FASTCGI_PM | |
477 | + if (fpm) fpm_request_info(); | |
478 | +#endif | |
479 | + | |
480 | if (!cgi | |
481 | #if PHP_FASTCGI | |
482 | && !fastcgi | |
37d32ffb | 483 | @@ -1994,6 +2111,10 @@ consult the installation file that came with this distribution, or visit \n\ |
c6a6bfc9 ER |
484 | } |
485 | } | |
486 | ||
487 | +#if PHP_FASTCGI_PM | |
488 | + if (fpm) fpm_request_executing(); | |
489 | +#endif | |
490 | + | |
491 | switch (behavior) { | |
492 | case PHP_MODE_STANDARD: | |
493 | php_execute_script(&file_handle TSRMLS_CC); | |
37d32ffb | 494 | @@ -2046,6 +2167,10 @@ consult the installation file that came with this distribution, or visit \n\ |
fd1be940 ER |
495 | |
496 | #if PHP_FASTCGI | |
497 | fastcgi_request_done: | |
498 | + | |
499 | + if (request_body_fd != -1) close(request_body_fd); | |
500 | + | |
501 | + request_body_fd = -2; | |
502 | #endif | |
503 | { | |
504 | char *path_translated; | |
37d32ffb | 505 | @@ -2059,6 +2184,16 @@ fastcgi_request_done: |
fd1be940 ER |
506 | SG(request_info).path_translated = path_translated; |
507 | } | |
508 | ||
509 | + if (EG(exit_status) == 255) { | |
510 | + if (CGIG(error_header) && *CGIG(error_header)) { | |
511 | + sapi_header_line ctr = {0}; | |
512 | + | |
513 | + ctr.line = CGIG(error_header); | |
514 | + ctr.line_len = strlen(CGIG(error_header)); | |
515 | + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); | |
516 | + } | |
517 | + } | |
518 | + | |
519 | php_request_shutdown((void *) 0); | |
520 | if (exit_status == 0) { | |
521 | exit_status = EG(exit_status); | |
37d32ffb | 522 | @@ -2096,15 +2231,20 @@ fastcgi_request_done: |
c6a6bfc9 ER |
523 | if (bindpath) { |
524 | free(bindpath); | |
525 | } | |
526 | - if (max_requests != 1) { | |
527 | - /* no need to return exit_status of the last request */ | |
528 | - exit_status = 0; | |
529 | - } | |
530 | break; | |
fd1be940 | 531 | } |
c6a6bfc9 ER |
532 | /* end of fastcgi loop */ |
533 | } | |
534 | fcgi_shutdown(); | |
fd1be940 | 535 | + |
c6a6bfc9 ER |
536 | + if (fcgi_in_shutdown() || /* graceful shutdown by a signal */ |
537 | + (max_requests && (requests == max_requests)) /* we were told to process max_requests and we are done */ | |
538 | + ) { | |
539 | + exit_status = 0; | |
540 | + } | |
541 | + else { | |
542 | + exit_status = 255; | |
543 | + } | |
544 | #endif | |
545 | ||
546 | if (cgi_sapi_module.php_ini_path_override) { | |
873ee61a ER |
547 | --- php-5.2.17/sapi/cgi/config9.m4~ 2012-02-27 14:44:23.000000000 +0200 |
548 | +++ php-5.2.17/sapi/cgi/config9.m4 2012-02-27 14:48:07.279580606 +0200 | |
37d32ffb | 549 | @@ -22,6 +22,10 @@ PHP_ARG_ENABLE(path-info-check,, |
fd1be940 ER |
550 | [ --disable-path-info-check CGI: If this is disabled, paths such as |
551 | /info.php/test?a=b will fail to work], yes, no) | |
552 | ||
553 | +PHP_ARG_ENABLE(fpm,, | |
554 | +[ --enable-fpm FastCGI: If this is enabled, the fastcgi support | |
555 | + will include experimental process manager code], no, no) | |
556 | + | |
557 | dnl | |
558 | dnl CGI setup | |
559 | dnl | |
37d32ffb | 560 | @@ -54,6 +58,20 @@ if test "$PHP_SAPI" = "default"; then |
fd1be940 ER |
561 | AC_DEFINE_UNQUOTED(PHP_FASTCGI, $PHP_ENABLE_FASTCGI, [ ]) |
562 | AC_MSG_RESULT($PHP_FASTCGI) | |
563 | ||
564 | + dnl --enable-fpm | |
565 | + if test "$PHP_FASTCGI" = "yes"; then | |
c6a6bfc9 | 566 | + AC_MSG_CHECKING(whether to enable FastCGI Process Manager) |
fd1be940 ER |
567 | + if test "$PHP_FPM" = "yes"; then |
568 | + PHP_FASTCGI_PM=1 | |
569 | + else | |
570 | + PHP_FASTCGI_PM=0 | |
571 | + fi | |
572 | + AC_MSG_RESULT($PHP_FPM) | |
573 | + else | |
574 | + PHP_FASTCGI_PM=0 | |
575 | + fi | |
576 | + AC_DEFINE_UNQUOTED(PHP_FASTCGI_PM, $PHP_FASTCGI_PM, [Is experimental fastcgi process manager code activated]) | |
577 | + | |
578 | dnl --enable-force-cgi-redirect | |
579 | AC_MSG_CHECKING(whether to force Apache CGI redirect) | |
580 | if test "$PHP_FORCE_CGI_REDIRECT" = "yes"; then | |
873ee61a | 581 | @@ -111,10 +111,10 @@ |
48b142c9 | 582 | BUILD_CGI="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) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_CGI_PATH)" |
fd1be940 ER |
583 | ;; |
584 | *darwin*) | |
48b142c9 | 585 | - BUILD_CGI="\$(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) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_CGI_PATH)" |
37d32ffb | 586 | + BUILD_CGI="\$(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_CGI_PATH)" |
fd1be940 ER |
587 | ;; |
588 | *) | |
873ee61a ER |
589 | - BUILD_CGI="\$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) libphp_common.la \$(PHP_SAPI_OBJS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_CGI_PATH)" |
590 | + BUILD_CGI="\$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) libphp_common.la \$(PHP_SAPI_OBJS) \$(EXTRA_LIBS) \$(SAPI_EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_CGI_PATH)" | |
fd1be940 ER |
591 | ;; |
592 | esac | |
593 | ||
37d32ffb | 594 | diff --git a/sapi/cgi/fastcgi.c b/sapi/cgi/fastcgi.c |
37d32ffb ER |
595 | --- a/sapi/cgi/fastcgi.c |
596 | +++ b/sapi/cgi/fastcgi.c | |
c6a6bfc9 ER |
597 | @@ -27,6 +27,11 @@ |
598 | #include <stdarg.h> | |
599 | #include <errno.h> | |
600 | ||
601 | +#if PHP_FASTCGI_PM | |
602 | +#include "fpm/fpm.h" | |
603 | +#include "fpm/fpm_request.h" | |
604 | +#endif | |
605 | + | |
606 | #ifdef _WIN32 | |
607 | ||
608 | #include <windows.h> | |
37d32ffb | 609 | @@ -234,6 +239,8 @@ int fcgi_init(void) |
fd1be940 ER |
610 | } else { |
611 | return is_fastcgi = 0; | |
612 | } | |
613 | + | |
614 | + fcgi_set_allowed_clients(getenv("FCGI_WEB_SERVER_ADDRS")); | |
615 | #endif | |
616 | } | |
617 | return is_fastcgi; | |
37d32ffb | 618 | @@ -249,14 +256,26 @@ int fcgi_is_fastcgi(void) |
fd1be940 ER |
619 | } |
620 | } | |
621 | ||
622 | +void fcgi_set_is_fastcgi(int new_value) | |
623 | +{ | |
624 | + is_fastcgi = new_value; | |
625 | +} | |
c6a6bfc9 ER |
626 | + |
627 | +void fcgi_set_in_shutdown(int new_value) | |
628 | +{ | |
629 | + in_shutdown = new_value; | |
630 | +} | |
fd1be940 ER |
631 | + |
632 | void fcgi_shutdown(void) | |
633 | { | |
633983a3 | 634 | if (is_initialized) { |
37d32ffb ER |
635 | zend_hash_destroy(&fcgi_mgmt_vars); |
636 | } | |
637 | is_fastcgi = 0; | |
638 | + | |
639 | if (allowed_clients) { | |
640 | free(allowed_clients); | |
641 | + allowed_clients = 0; | |
642 | } | |
643 | } | |
644 | ||
645 | @@ -330,6 +349,41 @@ out_fail: | |
fd1be940 ER |
646 | } |
647 | #endif | |
648 | ||
649 | +void fcgi_set_allowed_clients(char *ip) | |
650 | +{ | |
651 | + char *cur, *end; | |
652 | + int n; | |
653 | + | |
654 | + if (ip) { | |
655 | + ip = strdup(ip); | |
656 | + cur = ip; | |
657 | + n = 0; | |
658 | + while (*cur) { | |
659 | + if (*cur == ',') n++; | |
660 | + cur++; | |
661 | + } | |
662 | + if (allowed_clients) free(allowed_clients); | |
663 | + allowed_clients = malloc(sizeof(in_addr_t) * (n+2)); | |
664 | + n = 0; | |
665 | + cur = ip; | |
666 | + while (cur) { | |
667 | + end = strchr(cur, ','); | |
668 | + if (end) { | |
669 | + *end = 0; | |
670 | + end++; | |
671 | + } | |
672 | + allowed_clients[n] = inet_addr(cur); | |
673 | + if (allowed_clients[n] == INADDR_NONE) { | |
674 | + fprintf(stderr, "Wrong IP address '%s' in FCGI_WEB_SERVER_ADDRS\n", cur); | |
675 | + } | |
676 | + n++; | |
677 | + cur = end; | |
678 | + } | |
679 | + allowed_clients[n] = INADDR_NONE; | |
680 | + free(ip); | |
681 | + } | |
682 | +} | |
683 | + | |
684 | static int is_port_number(const char *bindpath) | |
685 | { | |
686 | while (*bindpath) { | |
37d32ffb | 687 | @@ -458,38 +512,6 @@ int fcgi_listen(const char *path, int backlog) |
fd1be940 ER |
688 | |
689 | if (!tcp) { | |
690 | chmod(path, 0777); | |
691 | - } else { | |
ed74ad62 AG |
692 | - char *ip = getenv("FCGI_WEB_SERVER_ADDRS"); |
693 | - char *cur, *end; | |
694 | - int n; | |
695 | - | |
696 | - if (ip) { | |
697 | - ip = strdup(ip); | |
698 | - cur = ip; | |
699 | - n = 0; | |
700 | - while (*cur) { | |
701 | - if (*cur == ',') n++; | |
702 | - cur++; | |
703 | - } | |
704 | - allowed_clients = malloc(sizeof(in_addr_t) * (n+2)); | |
705 | - n = 0; | |
706 | - cur = ip; | |
707 | - while (cur) { | |
708 | - end = strchr(cur, ','); | |
709 | - if (end) { | |
710 | - *end = 0; | |
711 | - end++; | |
712 | - } | |
713 | - allowed_clients[n] = inet_addr(cur); | |
714 | - if (allowed_clients[n] == INADDR_NONE) { | |
fd1be940 | 715 | - fprintf(stderr, "Wrong IP address '%s' in FCGI_WEB_SERVER_ADDRS\n", cur); |
ed74ad62 AG |
716 | - } |
717 | - n++; | |
718 | - cur = end; | |
719 | - } | |
720 | - allowed_clients[n] = INADDR_NONE; | |
fd1be940 ER |
721 | - free(ip); |
722 | - } | |
723 | } | |
724 | ||
725 | if (!is_initialized) { | |
37d32ffb | 726 | @@ -866,7 +888,7 @@ int fcgi_read(fcgi_request *req, char *str, int len) |
fd1be940 ER |
727 | return n; |
728 | } | |
729 | ||
730 | -static inline void fcgi_close(fcgi_request *req, int force, int destroy) | |
731 | +void fcgi_close(fcgi_request *req, int force, int destroy) | |
732 | { | |
733 | if (destroy) { | |
734 | zend_hash_destroy(&req->env); | |
37d32ffb | 735 | @@ -906,6 +928,10 @@ static inline void fcgi_close(fcgi_request *req, int force, int destroy) |
c6a6bfc9 ER |
736 | close(req->fd); |
737 | #endif | |
738 | req->fd = -1; | |
739 | + | |
740 | +#if PHP_FASTCGI_PM | |
741 | + if (fpm) fpm_request_finished(); | |
742 | +#endif | |
743 | } | |
744 | } | |
745 | ||
37d32ffb | 746 | @@ -953,6 +979,10 @@ int fcgi_accept_request(fcgi_request *req) |
c6a6bfc9 ER |
747 | sa_t sa; |
748 | socklen_t len = sizeof(sa); | |
749 | ||
750 | +#if PHP_FASTCGI_PM | |
751 | + if (fpm) fpm_request_accepting(); | |
752 | +#endif | |
753 | + | |
754 | FCGI_LOCK(req->listen_socket); | |
755 | req->fd = accept(listen_socket, (struct sockaddr *)&sa, &len); | |
756 | FCGI_UNLOCK(req->listen_socket); | |
37d32ffb | 757 | @@ -988,6 +1018,11 @@ int fcgi_accept_request(fcgi_request *req) |
c6a6bfc9 ER |
758 | break; |
759 | #else | |
760 | if (req->fd >= 0) { | |
761 | + | |
762 | +#if PHP_FASTCGI_PM | |
763 | + if (fpm) fpm_request_reading_headers(); | |
764 | +#endif | |
765 | + | |
766 | #if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL) | |
767 | struct pollfd fds; | |
768 | int ret; | |
37d32ffb | 769 | diff --git a/sapi/cgi/fastcgi.h b/sapi/cgi/fastcgi.h |
37d32ffb ER |
770 | --- a/sapi/cgi/fastcgi.h |
771 | +++ b/sapi/cgi/fastcgi.h | |
772 | @@ -114,6 +114,9 @@ typedef struct _fcgi_request { | |
fd1be940 ER |
773 | int fcgi_init(void); |
774 | void fcgi_shutdown(void); | |
775 | int fcgi_is_fastcgi(void); | |
776 | +void fcgi_set_is_fastcgi(int); | |
c6a6bfc9 | 777 | +void fcgi_set_in_shutdown(int); |
fd1be940 ER |
778 | +void fcgi_set_allowed_clients(char *); |
779 | int fcgi_in_shutdown(void); | |
780 | int fcgi_listen(const char *path, int backlog); | |
781 | void fcgi_init_request(fcgi_request *req, int listen_socket); | |
37d32ffb | 782 | @@ -128,6 +131,8 @@ int fcgi_read(fcgi_request *req, char *str, int len); |
fd1be940 ER |
783 | int fcgi_write(fcgi_request *req, fcgi_request_type type, const char *str, int len); |
784 | int fcgi_flush(fcgi_request *req, int close); | |
785 | ||
786 | +void fcgi_close(fcgi_request *req, int force, int destroy); | |
787 | + | |
788 | #ifdef PHP_WIN32 | |
789 | void fcgi_impersonate(void); | |
790 | #endif | |
37d32ffb ER |
791 | diff --git a/sapi/cgi/fpm/Makefile.frag b/sapi/cgi/fpm/Makefile.frag |
792 | new file mode 100644 | |
37d32ffb ER |
793 | --- /dev/null |
794 | +++ b/sapi/cgi/fpm/Makefile.frag | |
795 | @@ -0,0 +1,21 @@ | |
796 | + | |
797 | +install-fpm: sapi/cgi/fpm/php-fpm.conf sapi/cgi/fpm/php-fpm | |
798 | + @echo "Installing FPM config: $(INSTALL_ROOT)$(php_fpm_conf_path)" | |
799 | + -@$(mkinstalldirs) \ | |
800 | + $(INSTALL_ROOT)$(prefix)/sbin \ | |
801 | + `dirname "$(INSTALL_ROOT)$(php_fpm_conf_path)"` \ | |
802 | + `dirname "$(INSTALL_ROOT)$(php_fpm_log_path)"` \ | |
803 | + `dirname "$(INSTALL_ROOT)$(php_fpm_pid_path)"` | |
804 | + -@if test -r "$(INSTALL_ROOT)$(php_fpm_conf_path)" ; then \ | |
805 | + dest=`basename "$(php_fpm_conf_path)"`.default ; \ | |
806 | + echo " (installing as $$dest)" ; \ | |
807 | + else \ | |
808 | + dest=`basename "$(php_fpm_conf_path)"` ; \ | |
809 | + fi ; \ | |
810 | + $(INSTALL_DATA) $(top_builddir)/sapi/cgi/fpm/php-fpm.conf $(INSTALL_ROOT)`dirname "$(php_fpm_conf_path)"`/$$dest | |
811 | + @echo "Installing init.d script: $(INSTALL_ROOT)$(prefix)/sbin/php-fpm" | |
812 | + -@$(INSTALL) -m 0755 $(top_builddir)/sapi/cgi/fpm/php-fpm $(INSTALL_ROOT)$(prefix)/sbin/php-fpm | |
813 | + | |
814 | +$(top_builddir)/libevent/libevent.a: $(top_builddir)/libevent/Makefile | |
815 | + cd $(top_builddir)/libevent && $(MAKE) libevent.a | |
816 | + | |
817 | diff --git a/sapi/cgi/fpm/acinclude.m4 b/sapi/cgi/fpm/acinclude.m4 | |
818 | new file mode 100644 | |
37d32ffb ER |
819 | --- /dev/null |
820 | +++ b/sapi/cgi/fpm/acinclude.m4 | |
48b142c9 | 821 | @@ -0,0 +1,377 @@ |
fd1be940 ER |
822 | + |
823 | +AC_DEFUN([AC_FPM_CHECK_FUNC], | |
824 | +[ | |
825 | + SAVED_CFLAGS="$CFLAGS" | |
826 | + CFLAGS="$CFLAGS $2" | |
827 | + SAVED_LIBS="$LIBS" | |
828 | + LIBS="$LIBS $3" | |
829 | + | |
830 | + AC_CHECK_FUNC([$1],[$4],[$5]) | |
831 | + | |
832 | + CFLAGS="$SAVED_CFLAGS" | |
833 | + LIBS="$SAVED_LIBS" | |
834 | +]) | |
835 | + | |
836 | +AC_DEFUN([AC_FPM_LIBEVENT], | |
837 | +[ | |
838 | + AC_ARG_WITH([libevent], | |
839 | + [ --with-libevent=DIR FPM: libevent install directory]) | |
840 | + | |
841 | + LIBEVENT_CFLAGS="" | |
842 | + LIBEVENT_LIBS="-levent" | |
843 | + LIBEVENT_INCLUDE_PATH="" | |
844 | + | |
845 | + if test "$with_libevent" != "no" -a -n "$with_libevent"; then | |
846 | + LIBEVENT_CFLAGS="-I$with_libevent/include" | |
847 | + LIBEVENT_LIBS="-L$with_libevent/lib $LIBEVENT_LIBS" | |
848 | + LIBEVENT_INCLUDE_PATH="$with_libevent/include" | |
849 | + fi | |
850 | + | |
851 | + AC_MSG_CHECKING([for event.h]) | |
852 | + | |
853 | + found=no | |
854 | + | |
855 | + for dir in "$LIBEVENT_INCLUDE_PATH" /usr/include ; do | |
c6a6bfc9 | 856 | + if test -r "$dir/event.h" ; then |
fd1be940 ER |
857 | + found=yes |
858 | + break | |
859 | + fi | |
860 | + done | |
861 | + | |
862 | + AC_MSG_RESULT([$found]) | |
863 | + | |
864 | + AC_FPM_CHECK_FUNC([event_set], [$LIBEVENT_CFLAGS], [$LIBEVENT_LIBS], , | |
865 | + [AC_MSG_ERROR([Failed to link with libevent. Perhaps --with-libevent=DIR option could help.])]) | |
866 | + | |
867 | + AC_FPM_CHECK_FUNC([event_base_free], [$LIBEVENT_CFLAGS], [$LIBEVENT_LIBS], , | |
868 | + [AC_MSG_ERROR([You have too old version. libevent version >= 1.2 is required.])]) | |
869 | + | |
870 | +]) | |
871 | + | |
872 | +AC_DEFUN([AC_FPM_LIBXML], | |
873 | +[ | |
874 | + AC_MSG_RESULT([checking for XML configuration]) | |
875 | + | |
876 | + AC_ARG_WITH(xml-config, | |
877 | + [ --with-xml-config=PATH FPM: use xml-config in PATH to find libxml], | |
878 | + [XMLCONFIG="$withval"], | |
879 | + [AC_PATH_PROGS(XMLCONFIG, [xml2-config xml-config], "")] | |
880 | + ) | |
881 | + | |
882 | + if test "x$XMLCONFIG" = "x"; then | |
883 | + AC_MSG_ERROR([XML configuration could not be found]) | |
884 | + else | |
885 | + AC_MSG_CHECKING([for libxml library]) | |
886 | + | |
887 | + if test ! -x "$XMLCONFIG"; then | |
888 | + AC_MSG_ERROR([$XMLCONFIG cannot be executed]) | |
889 | + fi | |
890 | + | |
891 | + LIBXML_LIBS="`$XMLCONFIG --libs`" | |
892 | + LIBXML_CFLAGS="`$XMLCONFIG --cflags`" | |
893 | + LIBXML_VERSION="`$XMLCONFIG --version`" | |
894 | + | |
895 | + AC_MSG_RESULT([yes, $LIBXML_VERSION]) | |
896 | + | |
897 | + AC_FPM_CHECK_FUNC([xmlParseFile], [$LIBXML_CFLAGS], [$LIBXML_LIBS], , | |
898 | + [AC_MSG_ERROR([Failed to link with libxml])]) | |
899 | + | |
900 | + AC_DEFINE(HAVE_LIBXML, 1, [do we have libxml?]) | |
901 | + fi | |
902 | +]) | |
903 | + | |
904 | +AC_DEFUN([AC_FPM_JUDY], | |
905 | +[ | |
906 | + AC_ARG_WITH([Judy], | |
907 | + [ --with-Judy=DIR FPM: Judy install directory]) | |
908 | + | |
909 | + JUDY_CFLAGS="" | |
910 | + JUDY_LIBS="-lJudy" | |
911 | + JUDY_INCLUDE_PATH="" | |
912 | + | |
913 | + if test "$with_Judy" != "no" -a -n "$with_Judy"; then | |
914 | + JUDY_INCLUDE_PATH="$with_Judy/include" | |
915 | + JUDY_CFLAGS="-I$with_Judy/include $JUDY_CFLAGS" | |
916 | + JUDY_LIBS="-L$with_Judy/lib $JUDY_LIBS" | |
917 | + fi | |
918 | + | |
919 | + AC_MSG_CHECKING([for Judy.h]) | |
920 | + | |
921 | + found=no | |
922 | + | |
923 | + for dir in "$JUDY_INCLUDE_PATH" /usr/include ; do | |
c6a6bfc9 | 924 | + if test -r "$dir/Judy.h" ; then |
fd1be940 ER |
925 | + found=yes |
926 | + break | |
927 | + fi | |
928 | + done | |
929 | + | |
930 | + AC_MSG_RESULT([$found]) | |
931 | + | |
932 | + AC_FPM_CHECK_FUNC([JudyLCount], [$JUDY_CFLAGS], [$JUDY_LIBS], , | |
933 | + [AC_MSG_ERROR([Failed to link with Judy])]) | |
934 | + | |
935 | +]) | |
936 | + | |
c6a6bfc9 ER |
937 | +AC_DEFUN([AC_FPM_CLOCK], |
938 | +[ | |
939 | + have_clock_gettime=no | |
940 | + | |
941 | + AC_MSG_CHECKING([for clock_gettime]) | |
942 | + | |
48b142c9 | 943 | + AC_TRY_LINK([ #include <time.h> ], [struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);], [ |
c6a6bfc9 ER |
944 | + have_clock_gettime=yes |
945 | + AC_MSG_RESULT([yes]) | |
946 | + ], [ | |
947 | + AC_MSG_RESULT([no]) | |
948 | + ]) | |
949 | + | |
950 | + if test "$have_clock_gettime" = "no"; then | |
951 | + AC_MSG_CHECKING([for clock_gettime in -lrt]) | |
952 | + | |
953 | + SAVED_LIBS="$LIBS" | |
954 | + LIBS="$LIBS -lrt" | |
955 | + | |
48b142c9 | 956 | + AC_TRY_LINK([ #include <time.h> ], [struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);], [ |
c6a6bfc9 ER |
957 | + have_clock_gettime=yes |
958 | + AC_MSG_RESULT([yes]) | |
959 | + ], [ | |
960 | + LIBS="$SAVED_LIBS" | |
961 | + AC_MSG_RESULT([no]) | |
962 | + ]) | |
963 | + fi | |
964 | + | |
965 | + if test "$have_clock_gettime" = "yes"; then | |
966 | + AC_DEFINE([HAVE_CLOCK_GETTIME], 1, [do we have clock_gettime?]) | |
967 | + fi | |
968 | + | |
969 | + have_clock_get_time=no | |
970 | + | |
971 | + if test "$have_clock_gettime" = "no"; then | |
972 | + AC_MSG_CHECKING([for clock_get_time]) | |
973 | + | |
974 | + AC_TRY_RUN([ #include <mach/mach.h> | |
975 | + #include <mach/clock.h> | |
976 | + #include <mach/mach_error.h> | |
977 | + | |
978 | + int main() | |
979 | + { | |
980 | + kern_return_t ret; clock_serv_t aClock; mach_timespec_t aTime; | |
981 | + ret = host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &aClock); | |
982 | + | |
983 | + if (ret != KERN_SUCCESS) { | |
984 | + return 1; | |
985 | + } | |
986 | + | |
987 | + ret = clock_get_time(aClock, &aTime); | |
988 | + if (ret != KERN_SUCCESS) { | |
989 | + return 2; | |
990 | + } | |
991 | + | |
992 | + return 0; | |
993 | + } | |
994 | + ], [ | |
995 | + have_clock_get_time=yes | |
996 | + AC_MSG_RESULT([yes]) | |
997 | + ], [ | |
998 | + AC_MSG_RESULT([no]) | |
999 | + ]) | |
1000 | + fi | |
1001 | + | |
1002 | + if test "$have_clock_get_time" = "yes"; then | |
1003 | + AC_DEFINE([HAVE_CLOCK_GET_TIME], 1, [do we have clock_get_time?]) | |
1004 | + fi | |
1005 | +]) | |
1006 | + | |
1007 | +AC_DEFUN([AC_FPM_TRACE], | |
1008 | +[ | |
1009 | + have_ptrace=no | |
1010 | + have_broken_ptrace=no | |
1011 | + | |
1012 | + AC_MSG_CHECKING([for ptrace]) | |
1013 | + | |
1014 | + AC_TRY_COMPILE([ | |
1015 | + #include <sys/types.h> | |
1016 | + #include <sys/ptrace.h> ], [ptrace(0, 0, (void *) 0, 0);], [ | |
1017 | + have_ptrace=yes | |
1018 | + AC_MSG_RESULT([yes]) | |
1019 | + ], [ | |
1020 | + AC_MSG_RESULT([no]) | |
1021 | + ]) | |
1022 | + | |
1023 | + if test "$have_ptrace" = "yes"; then | |
1024 | + AC_MSG_CHECKING([whether ptrace works]) | |
1025 | + | |
1026 | + AC_TRY_RUN([ | |
1027 | + #include <unistd.h> | |
1028 | + #include <signal.h> | |
1029 | + #include <sys/wait.h> | |
1030 | + #include <sys/types.h> | |
1031 | + #include <sys/ptrace.h> | |
1032 | + #include <errno.h> | |
1033 | + | |
1034 | + #if !defined(PTRACE_ATTACH) && defined(PT_ATTACH) | |
1035 | + #define PTRACE_ATTACH PT_ATTACH | |
1036 | + #endif | |
1037 | + | |
1038 | + #if !defined(PTRACE_DETACH) && defined(PT_DETACH) | |
1039 | + #define PTRACE_DETACH PT_DETACH | |
1040 | + #endif | |
1041 | + | |
1042 | + #if !defined(PTRACE_PEEKDATA) && defined(PT_READ_D) | |
1043 | + #define PTRACE_PEEKDATA PT_READ_D | |
1044 | + #endif | |
1045 | + | |
1046 | + int main() | |
1047 | + { | |
1048 | + long v1 = (unsigned int) -1; /* copy will fail if sizeof(long) == 8 and we've got "int ptrace()" */ | |
1049 | + long v2; | |
1050 | + pid_t child; | |
1051 | + int status; | |
1052 | + | |
1053 | + if ( (child = fork()) ) { /* parent */ | |
1054 | + int ret = 0; | |
1055 | + | |
1056 | + if (0 > ptrace(PTRACE_ATTACH, child, 0, 0)) { | |
1057 | + return 1; | |
1058 | + } | |
1059 | + | |
1060 | + waitpid(child, &status, 0); | |
1061 | + | |
1062 | + #ifdef PT_IO | |
1063 | + struct ptrace_io_desc ptio = { | |
1064 | + .piod_op = PIOD_READ_D, | |
1065 | + .piod_offs = &v1, | |
1066 | + .piod_addr = &v2, | |
1067 | + .piod_len = sizeof(v1) | |
1068 | + }; | |
1069 | + | |
1070 | + if (0 > ptrace(PT_IO, child, (void *) &ptio, 0)) { | |
1071 | + ret = 1; | |
1072 | + } | |
1073 | + #else | |
1074 | + errno = 0; | |
1075 | + | |
1076 | + v2 = ptrace(PTRACE_PEEKDATA, child, (void *) &v1, 0); | |
1077 | + | |
1078 | + if (errno) { | |
1079 | + ret = 1; | |
1080 | + } | |
1081 | + #endif | |
1082 | + ptrace(PTRACE_DETACH, child, (void *) 1, 0); | |
1083 | + | |
1084 | + kill(child, SIGKILL); | |
1085 | + | |
1086 | + return ret ? ret : (v1 != v2); | |
1087 | + } | |
1088 | + else { /* child */ | |
1089 | + sleep(10); | |
1090 | + return 0; | |
1091 | + } | |
1092 | + } | |
1093 | + ], [ | |
1094 | + AC_MSG_RESULT([yes]) | |
1095 | + ], [ | |
1096 | + have_ptrace=no | |
1097 | + have_broken_ptrace=yes | |
1098 | + AC_MSG_RESULT([no]) | |
1099 | + ]) | |
1100 | + fi | |
1101 | + | |
1102 | + if test "$have_ptrace" = "yes"; then | |
1103 | + AC_DEFINE([HAVE_PTRACE], 1, [do we have ptrace?]) | |
1104 | + fi | |
1105 | + | |
1106 | + have_mach_vm_read=no | |
1107 | + | |
1108 | + if test "$have_broken_ptrace" = "yes"; then | |
1109 | + AC_MSG_CHECKING([for mach_vm_read]) | |
1110 | + | |
1111 | + AC_TRY_COMPILE([ #include <mach/mach.h> | |
1112 | + #include <mach/mach_vm.h> | |
1113 | + ], [ | |
1114 | + 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); | |
1115 | + ], [ | |
1116 | + have_mach_vm_read=yes | |
1117 | + AC_MSG_RESULT([yes]) | |
1118 | + ], [ | |
1119 | + AC_MSG_RESULT([no]) | |
1120 | + ]) | |
1121 | + fi | |
1122 | + | |
1123 | + if test "$have_mach_vm_read" = "yes"; then | |
1124 | + AC_DEFINE([HAVE_MACH_VM_READ], 1, [do we have mach_vm_read?]) | |
1125 | + fi | |
1126 | + | |
1127 | + proc_mem_file="" | |
1128 | + | |
1129 | + if test -r /proc/$$/mem ; then | |
1130 | + proc_mem_file="mem" | |
1131 | + else | |
1132 | + if test -r /proc/$$/as ; then | |
1133 | + proc_mem_file="as" | |
1134 | + fi | |
1135 | + fi | |
1136 | + | |
1137 | + if test -n "$proc_mem_file" ; then | |
1138 | + AC_MSG_CHECKING([for proc mem file]) | |
1139 | + | |
1140 | + AC_TRY_RUN([ | |
1141 | + #define _GNU_SOURCE | |
1142 | + #define _FILE_OFFSET_BITS 64 | |
1143 | + #include <stdint.h> | |
1144 | + #include <unistd.h> | |
1145 | + #include <sys/types.h> | |
1146 | + #include <sys/stat.h> | |
1147 | + #include <fcntl.h> | |
1148 | + #include <stdio.h> | |
1149 | + int main() | |
1150 | + { | |
1151 | + long v1 = (unsigned int) -1, v2 = 0; | |
1152 | + char buf[128]; | |
1153 | + int fd; | |
1154 | + sprintf(buf, "/proc/%d/$proc_mem_file", getpid()); | |
1155 | + fd = open(buf, O_RDONLY); | |
1156 | + if (0 > fd) { | |
1157 | + return 1; | |
1158 | + } | |
1159 | + if (sizeof(long) != pread(fd, &v2, sizeof(long), (uintptr_t) &v1)) { | |
1160 | + close(fd); | |
1161 | + return 1; | |
1162 | + } | |
1163 | + close(fd); | |
1164 | + return v1 != v2; | |
1165 | + } | |
1166 | + ], [ | |
1167 | + AC_MSG_RESULT([$proc_mem_file]) | |
1168 | + ], [ | |
1169 | + proc_mem_file="" | |
1170 | + AC_MSG_RESULT([no]) | |
1171 | + ]) | |
1172 | + fi | |
1173 | + | |
1174 | + if test -n "$proc_mem_file"; then | |
1175 | + AC_DEFINE_UNQUOTED([PROC_MEM_FILE], "$proc_mem_file", [/proc/pid/mem interface]) | |
1176 | + fi | |
1177 | + | |
c6a6bfc9 | 1178 | + if test "$have_ptrace" = "yes"; then |
48b142c9 | 1179 | + FPM_SOURCES="$FPM_SOURCES fpm_trace.c fpm_trace_ptrace.c" |
c6a6bfc9 | 1180 | + elif test -n "$proc_mem_file"; then |
48b142c9 | 1181 | + FPM_SOURCES="$FPM_SOURCES fpm_trace.c fpm_trace_pread.c" |
c6a6bfc9 | 1182 | + elif test "$have_mach_vm_read" = "yes" ; then |
48b142c9 | 1183 | + FPM_SOURCES="$FPM_SOURCES fpm_trace.c fpm_trace_mach.c" |
c6a6bfc9 ER |
1184 | + fi |
1185 | + | |
1186 | +]) | |
1187 | + | |
1188 | +AC_DEFUN([AC_FPM_PRCTL], | |
1189 | +[ | |
1190 | + AC_MSG_CHECKING([for prctl]) | |
1191 | + | |
1192 | + AC_TRY_COMPILE([ #include <sys/prctl.h> ], [prctl(0, 0, 0, 0, 0);], [ | |
1193 | + AC_DEFINE([HAVE_PRCTL], 1, [do we have prctl?]) | |
1194 | + AC_MSG_RESULT([yes]) | |
1195 | + ], [ | |
1196 | + AC_MSG_RESULT([no]) | |
1197 | + ]) | |
1198 | +]) | |
37d32ffb ER |
1199 | diff --git a/sapi/cgi/fpm/conf/php-fpm.conf.in b/sapi/cgi/fpm/conf/php-fpm.conf.in |
1200 | new file mode 100644 | |
37d32ffb ER |
1201 | --- /dev/null |
1202 | +++ b/sapi/cgi/fpm/conf/php-fpm.conf.in | |
c6a6bfc9 | 1203 | @@ -0,0 +1,156 @@ |
fd1be940 ER |
1204 | +<?xml version="1.0" ?> |
1205 | +<configuration> | |
1206 | + | |
1207 | + All relative paths in this config are relative to php's install prefix | |
1208 | + | |
1209 | + <section name="global_options"> | |
1210 | + | |
1211 | + Pid file | |
c6a6bfc9 | 1212 | + <value name="pid_file">@php_fpm_pid_path@</value> |
fd1be940 ER |
1213 | + |
1214 | + Error log file | |
c6a6bfc9 ER |
1215 | + <value name="error_log">@php_fpm_log_path@</value> |
1216 | + | |
1217 | + Log level | |
1218 | + <value name="log_level">notice</value> | |
fd1be940 ER |
1219 | + |
1220 | + When this amount of php processes exited with SIGSEGV or SIGBUS ... | |
1221 | + <value name="emergency_restart_threshold">10</value> | |
1222 | + | |
c6a6bfc9 | 1223 | + ... in a less than this interval of time, a graceful restart will be initiated. |
fd1be940 ER |
1224 | + Useful to work around accidental curruptions in accelerator's shared memory. |
1225 | + <value name="emergency_restart_interval">1m</value> | |
1226 | + | |
1227 | + Time limit on waiting child's reaction on signals from master | |
1228 | + <value name="process_control_timeout">5s</value> | |
1229 | + | |
1230 | + Set to 'no' to debug fpm | |
1231 | + <value name="daemonize">yes</value> | |
1232 | + | |
1233 | + </section> | |
1234 | + | |
1235 | + <workers> | |
1236 | + | |
1237 | + <section name="pool"> | |
1238 | + | |
1239 | + Name of pool. Used in logs and stats. | |
c6a6bfc9 | 1240 | + <value name="name">default</value> |
fd1be940 ER |
1241 | + |
1242 | + Address to accept fastcgi requests on. | |
1243 | + Valid syntax is 'ip.ad.re.ss:port' or just 'port' or '/path/to/unix/socket' | |
1244 | + <value name="listen_address">127.0.0.1:9000</value> | |
1245 | + | |
1246 | + <value name="listen_options"> | |
1247 | + | |
1248 | + Set listen(2) backlog | |
1249 | + <value name="backlog">-1</value> | |
1250 | + | |
1251 | + Set permissions for unix socket, if one used. | |
1252 | + In Linux read/write permissions must be set in order to allow connections from web server. | |
1253 | + Many BSD-derrived systems allow connections regardless of permissions. | |
1254 | + <value name="owner"></value> | |
1255 | + <value name="group"></value> | |
1256 | + <value name="mode">0666</value> | |
1257 | + </value> | |
1258 | + | |
1259 | + Additional php.ini defines, specific to this pool of workers. | |
1260 | + <value name="php_defines"> | |
1261 | + <!-- <value name="sendmail_path">/usr/sbin/sendmail -t -i</value> --> | |
1262 | + <!-- <value name="display_errors">0</value> --> | |
1263 | + </value> | |
1264 | + | |
1265 | + Unix user of processes | |
c6a6bfc9 | 1266 | + <!-- <value name="user">nobody</value> --> |
fd1be940 ER |
1267 | + |
1268 | + Unix group of processes | |
c6a6bfc9 | 1269 | + <!-- <value name="group">@php_fpm_group@</value> --> |
fd1be940 ER |
1270 | + |
1271 | + Process manager settings | |
1272 | + <value name="pm"> | |
1273 | + | |
1274 | + Sets style of controling worker process count. | |
1275 | + Valid values are 'static' and 'apache-like' | |
1276 | + <value name="style">static</value> | |
1277 | + | |
1278 | + Sets the limit on the number of simultaneous requests that will be served. | |
1279 | + Equivalent to Apache MaxClients directive. | |
1280 | + Equivalent to PHP_FCGI_CHILDREN environment in original php.fcgi | |
1281 | + Used with any pm_style. | |
1282 | + <value name="max_children">5</value> | |
1283 | + | |
1284 | + Settings group for 'apache-like' pm style | |
1285 | + <value name="apache_like"> | |
1286 | + | |
1287 | + Sets the number of server processes created on startup. | |
1288 | + Used only when 'apache-like' pm_style is selected | |
1289 | + <value name="StartServers">20</value> | |
1290 | + | |
1291 | + Sets the desired minimum number of idle server processes. | |
1292 | + Used only when 'apache-like' pm_style is selected | |
1293 | + <value name="MinSpareServers">5</value> | |
1294 | + | |
1295 | + Sets the desired maximum number of idle server processes. | |
1296 | + Used only when 'apache-like' pm_style is selected | |
1297 | + <value name="MaxSpareServers">35</value> | |
1298 | + | |
1299 | + </value> | |
1300 | + | |
1301 | + </value> | |
1302 | + | |
c6a6bfc9 ER |
1303 | + The timeout (in seconds) for serving a single request after which the worker process will be terminated |
1304 | + Should be used when 'max_execution_time' ini option does not stop script execution for some reason | |
1305 | + '0s' means 'off' | |
1306 | + <value name="request_terminate_timeout">0s</value> | |
1307 | + | |
1308 | + The timeout (in seconds) for serving of single request after which a php backtrace will be dumped to slow.log file | |
1309 | + '0s' means 'off' | |
1310 | + <value name="request_slowlog_timeout">0s</value> | |
1311 | + | |
1312 | + The log file for slow requests | |
1313 | + <value name="slowlog">logs/slow.log</value> | |
fd1be940 ER |
1314 | + |
1315 | + Set open file desc rlimit | |
1316 | + <value name="rlimit_files">1024</value> | |
1317 | + | |
1318 | + Set max core size rlimit | |
c6a6bfc9 | 1319 | + <value name="rlimit_core">0</value> |
fd1be940 | 1320 | + |
c6a6bfc9 | 1321 | + Chroot to this directory at the start, absolute path |
fd1be940 ER |
1322 | + <value name="chroot"></value> |
1323 | + | |
c6a6bfc9 | 1324 | + Chdir to this directory at the start, absolute path |
fd1be940 ER |
1325 | + <value name="chdir"></value> |
1326 | + | |
c6a6bfc9 | 1327 | + Redirect workers' stdout and stderr into main error log. |
fd1be940 ER |
1328 | + If not set, they will be redirected to /dev/null, according to FastCGI specs |
1329 | + <value name="catch_workers_output">yes</value> | |
1330 | + | |
1331 | + How much requests each process should execute before respawn. | |
1332 | + Useful to work around memory leaks in 3rd party libraries. | |
1333 | + For endless request processing please specify 0 | |
1334 | + Equivalent to PHP_FCGI_MAX_REQUESTS | |
1335 | + <value name="max_requests">500</value> | |
1336 | + | |
1337 | + Comma separated list of ipv4 addresses of FastCGI clients that allowed to connect. | |
1338 | + Equivalent to FCGI_WEB_SERVER_ADDRS environment in original php.fcgi (5.2.2+) | |
1339 | + Makes sense only with AF_INET listening socket. | |
1340 | + <value name="allowed_clients">127.0.0.1</value> | |
1341 | + | |
1342 | + Pass environment variables like LD_LIBRARY_PATH | |
1343 | + All $VARIABLEs are taken from current environment | |
1344 | + <value name="environment"> | |
1345 | + <value name="HOSTNAME">$HOSTNAME</value> | |
1346 | + <value name="PATH">/usr/local/bin:/usr/bin:/bin</value> | |
1347 | + <value name="TMP">/tmp</value> | |
1348 | + <value name="TMPDIR">/tmp</value> | |
1349 | + <value name="TEMP">/tmp</value> | |
1350 | + <value name="OSTYPE">$OSTYPE</value> | |
1351 | + <value name="MACHTYPE">$MACHTYPE</value> | |
1352 | + <value name="MALLOC_CHECK_">2</value> | |
1353 | + </value> | |
1354 | + | |
1355 | + </section> | |
1356 | + | |
1357 | + </workers> | |
1358 | + | |
1359 | +</configuration> | |
37d32ffb ER |
1360 | diff --git a/sapi/cgi/fpm/config.m4 b/sapi/cgi/fpm/config.m4 |
1361 | new file mode 100644 | |
37d32ffb ER |
1362 | --- /dev/null |
1363 | +++ b/sapi/cgi/fpm/config.m4 | |
873ee61a | 1364 | @@ -0,0 +1,117 @@ |
c6a6bfc9 | 1365 | + |
37d32ffb | 1366 | +FPM_VERSION="0.5.14" |
c6a6bfc9 ER |
1367 | + |
1368 | +PHP_ARG_WITH(fpm-conf, for php-fpm config file path, | |
1369 | +[ --with-fpm-conf=PATH Set the path for php-fpm configuration file [PREFIX/etc/php-fpm.conf]], \$prefix/etc/php-fpm.conf, no) | |
1370 | + | |
1371 | +PHP_ARG_WITH(fpm-log, for php-fpm log file path, | |
1372 | +[ --with-fpm-log=PATH Set the path for php-fpm log file [PREFIX/logs/php-fpm.log]], \$prefix/logs/php-fpm.log, no) | |
1373 | + | |
1374 | +PHP_ARG_WITH(fpm-pid, for php-fpm pid file path, | |
1375 | +[ --with-fpm-pid=PATH Set the path for php-fpm pid file [PREFIX/logs/php-fpm.pid]], \$prefix/logs/php-fpm.pid, no) | |
fd1be940 | 1376 | + |
c6a6bfc9 ER |
1377 | +FPM_SOURCES="fpm.c \ |
1378 | + fpm_conf.c \ | |
1379 | + fpm_signals.c \ | |
1380 | + fpm_children.c \ | |
1381 | + fpm_worker_pool.c \ | |
1382 | + fpm_unix.c \ | |
1383 | + fpm_cleanup.c \ | |
1384 | + fpm_sockets.c \ | |
1385 | + fpm_stdio.c \ | |
1386 | + fpm_env.c \ | |
1387 | + fpm_events.c \ | |
1388 | + fpm_php.c \ | |
1389 | + fpm_php_trace.c \ | |
c6a6bfc9 ER |
1390 | + fpm_process_ctl.c \ |
1391 | + fpm_request.c \ | |
1392 | + fpm_clock.c \ | |
1393 | + fpm_shm.c \ | |
1394 | + fpm_shm_slots.c \ | |
1395 | + xml_config.c \ | |
1396 | + zlog.c" | |
fd1be940 | 1397 | + |
48b142c9 ER |
1398 | +dnl AC_FPM_LIBEVENT |
1399 | +AC_FPM_LIBXML | |
1400 | +AC_FPM_PRCTL | |
1401 | +AC_FPM_CLOCK | |
1402 | +AC_FPM_TRACE | |
1403 | +dnl AC_FPM_JUDY | |
1404 | + | |
873ee61a ER |
1405 | +LIBEVENT_CFLAGS="" |
1406 | +LIBEVENT_LIBS="-levent" | |
48b142c9 ER |
1407 | + |
1408 | +SAPI_EXTRA_DEPS="$LIBEVENT_LIBS" | |
1409 | + | |
fd1be940 | 1410 | +FPM_CFLAGS="$LIBEVENT_CFLAGS $LIBXML_CFLAGS $JUDY_CFLAGS" |
fd1be940 ER |
1411 | + |
1412 | +dnl FPM_CFLAGS="$FPM_CFLAGS -DJUDYERROR_NOTEST" # for Judy | |
8c0dac15 | 1413 | +FPM_CFLAGS="$FPM_CFLAGS -I$abs_srcdir/sapi/cgi" # for fastcgi.h |
fd1be940 | 1414 | + |
c6a6bfc9 ER |
1415 | +if test "$ICC" = "yes" ; then |
1416 | + FPM_ADD_CFLAGS="-Wall -wd279,310,869,810,981" | |
1417 | +elif test "$GCC" = "yes" ; then | |
1418 | + FPM_ADD_CFLAGS="-Wall -Wpointer-arith -Wno-unused-parameter -Wunused-variable -Wunused-value -fno-strict-aliasing" | |
1419 | +fi | |
1420 | + | |
1421 | +if test -n "$FPM_WERROR" ; then | |
1422 | + FPM_ADD_CFLAGS="$FPM_ADD_CFLAGS -Werror" | |
fd1be940 ER |
1423 | +fi |
1424 | + | |
c6a6bfc9 ER |
1425 | +FPM_CFLAGS="$FPM_ADD_CFLAGS $FPM_CFLAGS" |
1426 | + | |
8c0dac15 | 1427 | +PHP_ADD_MAKEFILE_FRAGMENT($abs_srcdir/sapi/cgi/fpm/Makefile.frag) |
fd1be940 | 1428 | + |
8c0dac15 | 1429 | +PHP_ADD_SOURCES(sapi/cgi/fpm, $FPM_SOURCES, $FPM_CFLAGS, sapi) |
fd1be940 | 1430 | + |
8c0dac15 | 1431 | +PHP_ADD_BUILD_DIR(sapi/cgi/fpm) |
fd1be940 ER |
1432 | + |
1433 | +install_fpm="install-fpm" | |
1434 | + | |
c6a6bfc9 ER |
1435 | +SAPI_EXTRA_LIBS="$LIBEVENT_LIBS $LIBXML_LIBS $JUDY_LIBS" |
1436 | + | |
1437 | + | |
1438 | +if test "$prefix" = "NONE" ; then | |
1439 | + fpm_prefix=/usr/local | |
1440 | +else | |
1441 | + fpm_prefix="$prefix" | |
1442 | +fi | |
1443 | + | |
1444 | +if test "$PHP_FPM_CONF" = "\$prefix/etc/php-fpm.conf" ; then | |
1445 | + php_fpm_conf_path="$fpm_prefix/etc/php-fpm.conf" | |
1446 | +else | |
1447 | + php_fpm_conf_path="$PHP_FPM_CONF" | |
1448 | +fi | |
1449 | + | |
1450 | +if test "$PHP_FPM_LOG" = "\$prefix/logs/php-fpm.log" ; then | |
1451 | + php_fpm_log_path="$fpm_prefix/logs/php-fpm.log" | |
1452 | +else | |
1453 | + php_fpm_log_path="$PHP_FPM_LOG" | |
1454 | +fi | |
1455 | + | |
1456 | +if test "$PHP_FPM_PID" = "\$prefix/logs/php-fpm.pid" ; then | |
1457 | + php_fpm_pid_path="$fpm_prefix/logs/php-fpm.pid" | |
1458 | +else | |
1459 | + php_fpm_pid_path="$PHP_FPM_PID" | |
1460 | +fi | |
1461 | + | |
1462 | + | |
1463 | +if grep nobody /etc/group >/dev/null 2>&1; then | |
1464 | + php_fpm_group=nobody | |
1465 | +else | |
1466 | + if grep nogroup /etc/group >/dev/null 2>&1; then | |
1467 | + php_fpm_group=nogroup | |
1468 | + else | |
1469 | + php_fpm_group=nobody | |
1470 | + fi | |
1471 | +fi | |
1472 | + | |
1473 | +PHP_SUBST_OLD(php_fpm_conf_path) | |
1474 | +PHP_SUBST_OLD(php_fpm_log_path) | |
1475 | +PHP_SUBST_OLD(php_fpm_pid_path) | |
1476 | +PHP_SUBST_OLD(php_fpm_group) | |
1477 | +PHP_SUBST_OLD(FPM_VERSION) | |
1478 | + | |
8c0dac15 ER |
1479 | +PHP_OUTPUT(sapi/cgi/fpm/fpm_autoconf.h) |
1480 | +PHP_OUTPUT(sapi/cgi/fpm/php-fpm.conf:sapi/cgi/fpm/conf/php-fpm.conf.in) | |
1481 | +PHP_OUTPUT(sapi/cgi/fpm/php-fpm:sapi/cgi/fpm/init.d/php-fpm.in) | |
37d32ffb ER |
1482 | diff --git a/sapi/cgi/fpm/fpm.c b/sapi/cgi/fpm/fpm.c |
1483 | new file mode 100644 | |
1484 | index 0000000..9db2c9b | |
1485 | --- /dev/null | |
1486 | +++ b/sapi/cgi/fpm/fpm.c | |
1487 | @@ -0,0 +1,84 @@ | |
1488 | + | |
1489 | + /* $Id$ */ | |
1490 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
1491 | + | |
1492 | +#include "fpm_config.h" | |
1493 | + | |
1494 | +#include <stdlib.h> /* for exit */ | |
1495 | + | |
1496 | +#include "fpm.h" | |
1497 | +#include "fpm_children.h" | |
1498 | +#include "fpm_signals.h" | |
1499 | +#include "fpm_env.h" | |
1500 | +#include "fpm_events.h" | |
1501 | +#include "fpm_cleanup.h" | |
1502 | +#include "fpm_php.h" | |
1503 | +#include "fpm_sockets.h" | |
1504 | +#include "fpm_unix.h" | |
1505 | +#include "fpm_process_ctl.h" | |
1506 | +#include "fpm_conf.h" | |
1507 | +#include "fpm_worker_pool.h" | |
1508 | +#include "fpm_stdio.h" | |
1509 | +#include "zlog.h" | |
1510 | + | |
1511 | +int fpm; | |
1512 | + | |
1513 | +struct fpm_globals_s fpm_globals; | |
1514 | + | |
1515 | +int fpm_init(int argc, char **argv, char *config) | |
1516 | +{ | |
1517 | + fpm_globals.argc = argc; | |
1518 | + fpm_globals.argv = argv; | |
1519 | + fpm_globals.config = config; | |
1520 | + | |
1521 | + if (0 > fpm_php_init_main() || | |
1522 | + 0 > fpm_stdio_init_main() || | |
1523 | + 0 > fpm_conf_init_main() || | |
1524 | + 0 > fpm_unix_init_main() || | |
1525 | + 0 > fpm_env_init_main() || | |
1526 | + 0 > fpm_signals_init_main() || | |
1527 | + 0 > fpm_pctl_init_main() || | |
1528 | + 0 > fpm_children_init_main() || | |
1529 | + 0 > fpm_sockets_init_main() || | |
1530 | + 0 > fpm_worker_pool_init_main() || | |
1531 | + 0 > fpm_event_init_main()) { | |
1532 | + return -1; | |
1533 | + } | |
1534 | + | |
1535 | + if (0 > fpm_conf_write_pid()) { | |
1536 | + return -1; | |
1537 | + } | |
1538 | + | |
1539 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "fpm is running, pid %d", (int) fpm_globals.parent_pid); | |
1540 | + | |
1541 | + return 0; | |
1542 | +} | |
1543 | + | |
1544 | +/* children: return listening socket | |
1545 | + parent: never return */ | |
1546 | +int fpm_run(int *max_requests) | |
1547 | +{ | |
1548 | + struct fpm_worker_pool_s *wp; | |
1549 | + | |
1550 | + /* create initial children in all pools */ | |
1551 | + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { | |
1552 | + int is_parent; | |
1553 | + | |
1554 | + is_parent = fpm_children_create_initial(wp); | |
1555 | + | |
1556 | + if (!is_parent) { | |
1557 | + goto run_child; | |
1558 | + } | |
1559 | + } | |
1560 | + | |
1561 | + /* run event loop forever */ | |
1562 | + fpm_event_loop(); | |
1563 | + | |
1564 | +run_child: /* only workers reach this point */ | |
1565 | + | |
1566 | + fpm_cleanups_run(FPM_CLEANUP_CHILD); | |
1567 | + | |
1568 | + *max_requests = fpm_globals.max_requests; | |
1569 | + return fpm_globals.listening_socket; | |
1570 | +} | |
1571 | + | |
1572 | diff --git a/sapi/cgi/fpm/fpm.h b/sapi/cgi/fpm/fpm.h | |
1573 | new file mode 100644 | |
37d32ffb ER |
1574 | --- /dev/null |
1575 | +++ b/sapi/cgi/fpm/fpm.h | |
1576 | @@ -0,0 +1,30 @@ | |
1577 | + | |
1578 | + /* $Id$ */ | |
1579 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
1580 | + | |
1581 | +#ifndef FPM_H | |
1582 | +#define FPM_H 1 | |
1583 | + | |
1584 | +#include <unistd.h> | |
1585 | + | |
1586 | +int fpm_run(int *max_requests); | |
1587 | +int fpm_init(int argc, char **argv, char *config); | |
1588 | + | |
1589 | +struct fpm_globals_s { | |
1590 | + pid_t parent_pid; | |
1591 | + int argc; | |
1592 | + char **argv; | |
1593 | + char *config; | |
1594 | + int running_children; | |
1595 | + int error_log_fd; | |
1596 | + int log_level; | |
1597 | + int listening_socket; /* for this child */ | |
1598 | + int max_requests; /* for this child */ | |
1599 | + int is_child; | |
1600 | +}; | |
1601 | + | |
1602 | +extern struct fpm_globals_s fpm_globals; | |
1603 | + | |
1604 | +extern int fpm; | |
1605 | + | |
1606 | +#endif | |
1607 | diff --git a/sapi/cgi/fpm/fpm_arrays.h b/sapi/cgi/fpm/fpm_arrays.h | |
1608 | new file mode 100644 | |
37d32ffb ER |
1609 | --- /dev/null |
1610 | +++ b/sapi/cgi/fpm/fpm_arrays.h | |
c6a6bfc9 ER |
1611 | @@ -0,0 +1,110 @@ |
1612 | + | |
1613 | + /* $Id$ */ | |
1614 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
1615 | + | |
1616 | +#ifndef FPM_ARRAYS_H | |
1617 | +#define FPM_ARRAYS_H 1 | |
1618 | + | |
1619 | +#include <stdlib.h> | |
1620 | +#include <string.h> | |
1621 | + | |
1622 | +struct fpm_array_s { | |
1623 | + void *data; | |
1624 | + size_t sz; | |
1625 | + size_t used; | |
1626 | + size_t allocated; | |
1627 | +}; | |
1628 | + | |
1629 | +static inline struct fpm_array_s *fpm_array_init(struct fpm_array_s *a, unsigned int sz, unsigned int initial_num) | |
1630 | +{ | |
1631 | + void *allocated = 0; | |
1632 | + | |
1633 | + if (!a) { | |
1634 | + a = malloc(sizeof(struct fpm_array_s)); | |
1635 | + | |
1636 | + if (!a) { | |
1637 | + return 0; | |
1638 | + } | |
1639 | + | |
1640 | + allocated = a; | |
1641 | + } | |
1642 | + | |
1643 | + a->sz = sz; | |
1644 | + | |
1645 | + a->data = calloc(sz, initial_num); | |
1646 | + | |
1647 | + if (!a->data) { | |
1648 | + free(allocated); | |
1649 | + return 0; | |
1650 | + } | |
1651 | + | |
1652 | + a->allocated = initial_num; | |
1653 | + a->used = 0; | |
1654 | + | |
1655 | + return a; | |
1656 | +} | |
1657 | + | |
1658 | +static inline void *fpm_array_item(struct fpm_array_s *a, unsigned int n) | |
1659 | +{ | |
1660 | + char *ret; | |
1661 | + | |
1662 | + ret = (char *) a->data + a->sz * n; | |
1663 | + | |
1664 | + return ret; | |
1665 | +} | |
1666 | + | |
1667 | +static inline void *fpm_array_item_last(struct fpm_array_s *a) | |
1668 | +{ | |
1669 | + return fpm_array_item(a, a->used - 1); | |
1670 | +} | |
1671 | + | |
1672 | +static inline int fpm_array_item_remove(struct fpm_array_s *a, unsigned int n) | |
1673 | +{ | |
1674 | + int ret = -1; | |
1675 | + | |
1676 | + if (n < a->used - 1) { | |
1677 | + void *last = fpm_array_item(a, a->used - 1); | |
1678 | + void *to_remove = fpm_array_item(a, n); | |
1679 | + | |
1680 | + memcpy(to_remove, last, a->sz); | |
1681 | + | |
1682 | + ret = n; | |
1683 | + } | |
1684 | + | |
1685 | + --a->used; | |
1686 | + | |
1687 | + return ret; | |
1688 | +} | |
1689 | + | |
1690 | +static inline void *fpm_array_push(struct fpm_array_s *a) | |
1691 | +{ | |
1692 | + void *ret; | |
1693 | + | |
1694 | + if (a->used == a->allocated) { | |
1695 | + size_t new_allocated = a->allocated ? a->allocated * 2 : 20; | |
1696 | + void *new_ptr = realloc(a->data, a->sz * new_allocated); | |
1697 | + | |
1698 | + if (!new_ptr) { | |
1699 | + return 0; | |
1700 | + } | |
1701 | + | |
1702 | + a->data = new_ptr; | |
1703 | + a->allocated = new_allocated; | |
1704 | + } | |
1705 | + | |
1706 | + ret = fpm_array_item(a, a->used); | |
1707 | + | |
1708 | + ++a->used; | |
1709 | + | |
1710 | + return ret; | |
1711 | +} | |
1712 | + | |
1713 | +static inline void fpm_array_free(struct fpm_array_s *a) | |
1714 | +{ | |
1715 | + free(a->data); | |
1716 | + a->data = 0; | |
1717 | + a->sz = 0; | |
1718 | + a->used = a->allocated = 0; | |
1719 | +} | |
1720 | + | |
1721 | +#endif | |
37d32ffb ER |
1722 | diff --git a/sapi/cgi/fpm/fpm_atomic.h b/sapi/cgi/fpm/fpm_atomic.h |
1723 | new file mode 100644 | |
37d32ffb ER |
1724 | --- /dev/null |
1725 | +++ b/sapi/cgi/fpm/fpm_atomic.h | |
c6a6bfc9 | 1726 | @@ -0,0 +1,85 @@ |
fd1be940 ER |
1727 | + |
1728 | + /* $Id$ */ | |
c6a6bfc9 ER |
1729 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
1730 | + | |
1731 | +#ifndef FPM_ATOMIC_H | |
1732 | +#define FPM_ATOMIC_H 1 | |
1733 | + | |
1734 | +#include <stdint.h> | |
1735 | +#include <sched.h> | |
1736 | + | |
1737 | +#if ( __i386__ || __i386 ) | |
1738 | + | |
1739 | +typedef int32_t atomic_int_t; | |
1740 | +typedef uint32_t atomic_uint_t; | |
1741 | +typedef volatile atomic_uint_t atomic_t; | |
1742 | + | |
1743 | + | |
1744 | +static inline atomic_int_t atomic_fetch_add(atomic_t *value, atomic_int_t add) | |
1745 | +{ | |
1746 | + __asm__ volatile ( "lock;" "xaddl %0, %1;" : | |
1747 | + "+r" (add) : "m" (*value) : "memory"); | |
1748 | + | |
1749 | + return add; | |
1750 | +} | |
1751 | + | |
1752 | +static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set) | |
1753 | +{ | |
1754 | + unsigned char res; | |
1755 | + | |
1756 | + __asm__ volatile ( "lock;" "cmpxchgl %3, %1;" "sete %0;" : | |
1757 | + "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory"); | |
1758 | + | |
1759 | + return res; | |
1760 | +} | |
1761 | + | |
1762 | +#elif ( __amd64__ || __amd64 ) | |
1763 | + | |
1764 | +typedef int64_t atomic_int_t; | |
1765 | +typedef uint64_t atomic_uint_t; | |
1766 | +typedef volatile atomic_uint_t atomic_t; | |
1767 | + | |
1768 | +static inline atomic_int_t atomic_fetch_add(atomic_t *value, atomic_int_t add) | |
1769 | +{ | |
1770 | + __asm__ volatile ( "lock;" "xaddq %0, %1;" : | |
1771 | + "+r" (add) : "m" (*value) : "memory"); | |
1772 | + | |
1773 | + return add; | |
1774 | +} | |
1775 | + | |
1776 | +static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set) | |
1777 | +{ | |
1778 | + unsigned char res; | |
1779 | + | |
1780 | + __asm__ volatile ( "lock;" "cmpxchgq %3, %1;" "sete %0;" : | |
1781 | + "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory"); | |
1782 | + | |
1783 | + return res; | |
1784 | +} | |
1785 | + | |
1786 | +#else | |
1787 | + | |
1788 | +#error unsupported processor. please write a patch and send it to me | |
1789 | + | |
1790 | +#endif | |
1791 | + | |
1792 | +static inline int fpm_spinlock(atomic_t *lock, int try_once) | |
1793 | +{ | |
1794 | + if (try_once) { | |
1795 | + return atomic_cmp_set(lock, 0, 1) ? 0 : -1; | |
1796 | + } | |
1797 | + | |
1798 | + for (;;) { | |
1799 | + | |
1800 | + if (atomic_cmp_set(lock, 0, 1)) { | |
1801 | + break; | |
1802 | + } | |
1803 | + | |
1804 | + sched_yield(); | |
1805 | + } | |
1806 | + | |
1807 | + return 0; | |
1808 | +} | |
1809 | + | |
1810 | +#endif | |
1811 | + | |
37d32ffb ER |
1812 | diff --git a/sapi/cgi/fpm/fpm_autoconf.h.in b/sapi/cgi/fpm/fpm_autoconf.h.in |
1813 | new file mode 100644 | |
37d32ffb ER |
1814 | --- /dev/null |
1815 | +++ b/sapi/cgi/fpm/fpm_autoconf.h.in | |
c6a6bfc9 ER |
1816 | @@ -0,0 +1,9 @@ |
1817 | + | |
1818 | + /* $Id$ */ | |
1819 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
1820 | + | |
1821 | +#define PHP_FPM_VERSION "@FPM_VERSION@" | |
1822 | +#define PHP_FPM_CONF_PATH "@php_fpm_conf_path@" | |
1823 | +#define PHP_FPM_LOG_PATH "@php_fpm_log_path@" | |
1824 | +#define PHP_FPM_PID_PATH "@php_fpm_pid_path@" | |
1825 | + | |
37d32ffb ER |
1826 | diff --git a/sapi/cgi/fpm/fpm_children.c b/sapi/cgi/fpm/fpm_children.c |
1827 | new file mode 100644 | |
37d32ffb ER |
1828 | --- /dev/null |
1829 | +++ b/sapi/cgi/fpm/fpm_children.c | |
48b142c9 | 1830 | @@ -0,0 +1,385 @@ |
fd1be940 ER |
1831 | + |
1832 | + /* $Id$ */ | |
c6a6bfc9 | 1833 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
1834 | + |
1835 | +#include "fpm_config.h" | |
1836 | + | |
1837 | +#include <sys/types.h> | |
1838 | +#include <sys/wait.h> | |
1839 | +#include <time.h> | |
1840 | +#include <unistd.h> | |
1841 | +#include <string.h> | |
1842 | +#include <stdio.h> | |
1843 | + | |
1844 | +#include "fpm.h" | |
1845 | +#include "fpm_children.h" | |
1846 | +#include "fpm_signals.h" | |
1847 | +#include "fpm_worker_pool.h" | |
1848 | +#include "fpm_sockets.h" | |
1849 | +#include "fpm_process_ctl.h" | |
1850 | +#include "fpm_php.h" | |
1851 | +#include "fpm_conf.h" | |
1852 | +#include "fpm_cleanup.h" | |
1853 | +#include "fpm_events.h" | |
c6a6bfc9 | 1854 | +#include "fpm_clock.h" |
fd1be940 ER |
1855 | +#include "fpm_stdio.h" |
1856 | +#include "fpm_unix.h" | |
1857 | +#include "fpm_env.h" | |
c6a6bfc9 | 1858 | +#include "fpm_shm_slots.h" |
fd1be940 ER |
1859 | + |
1860 | +#include "zlog.h" | |
1861 | + | |
1862 | +static time_t *last_faults; | |
1863 | +static int fault; | |
1864 | + | |
fd1be940 ER |
1865 | +static int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop); |
1866 | + | |
1867 | +static void fpm_children_cleanup(int which, void *arg) | |
1868 | +{ | |
fd1be940 | 1869 | + free(last_faults); |
fd1be940 ER |
1870 | +} |
1871 | + | |
1872 | +static struct fpm_child_s *fpm_child_alloc() | |
1873 | +{ | |
1874 | + struct fpm_child_s *ret; | |
1875 | + | |
fd1be940 ER |
1876 | + ret = malloc(sizeof(struct fpm_child_s)); |
1877 | + | |
1878 | + if (!ret) return 0; | |
1879 | + | |
fd1be940 ER |
1880 | + memset(ret, 0, sizeof(*ret)); |
1881 | + | |
1882 | + return ret; | |
1883 | +} | |
1884 | + | |
c6a6bfc9 | 1885 | +static void fpm_child_free(struct fpm_child_s *child) |
fd1be940 | 1886 | +{ |
c6a6bfc9 ER |
1887 | + free(child); |
1888 | +} | |
fd1be940 | 1889 | + |
c6a6bfc9 ER |
1890 | +static void fpm_child_close(struct fpm_child_s *child, int in_event_loop) |
1891 | +{ | |
fd1be940 ER |
1892 | + if (child->fd_stdout != -1) { |
1893 | + if (in_event_loop) { | |
1894 | + fpm_event_fire(&child->ev_stdout); | |
1895 | + } | |
1896 | + if (child->fd_stdout != -1) { | |
1897 | + close(child->fd_stdout); | |
1898 | + } | |
1899 | + } | |
1900 | + | |
1901 | + if (child->fd_stderr != -1) { | |
1902 | + if (in_event_loop) { | |
1903 | + fpm_event_fire(&child->ev_stderr); | |
1904 | + } | |
1905 | + if (child->fd_stderr != -1) { | |
1906 | + close(child->fd_stderr); | |
1907 | + } | |
1908 | + } | |
1909 | + | |
c6a6bfc9 | 1910 | + fpm_child_free(child); |
fd1be940 ER |
1911 | +} |
1912 | + | |
c6a6bfc9 | 1913 | +static void fpm_child_link(struct fpm_child_s *child) |
fd1be940 | 1914 | +{ |
c6a6bfc9 | 1915 | + struct fpm_worker_pool_s *wp = child->wp; |
fd1be940 | 1916 | + |
c6a6bfc9 | 1917 | + ++wp->running_children; |
fd1be940 ER |
1918 | + ++fpm_globals.running_children; |
1919 | + | |
c6a6bfc9 | 1920 | + child->next = wp->children; |
fd1be940 ER |
1921 | + if (child->next) child->next->prev = child; |
1922 | + child->prev = 0; | |
c6a6bfc9 ER |
1923 | + wp->children = child; |
1924 | +} | |
1925 | + | |
1926 | +static void fpm_child_unlink(struct fpm_child_s *child) | |
1927 | +{ | |
1928 | + --child->wp->running_children; | |
1929 | + --fpm_globals.running_children; | |
1930 | + | |
1931 | + if (child->prev) child->prev->next = child->next; | |
1932 | + else child->wp->children = child->next; | |
1933 | + if (child->next) child->next->prev = child->prev; | |
fd1be940 | 1934 | + |
fd1be940 ER |
1935 | +} |
1936 | + | |
c6a6bfc9 | 1937 | +static struct fpm_child_s *fpm_child_find(pid_t pid) |
fd1be940 | 1938 | +{ |
c6a6bfc9 | 1939 | + struct fpm_worker_pool_s *wp; |
fd1be940 ER |
1940 | + struct fpm_child_s *child = 0; |
1941 | + | |
c6a6bfc9 ER |
1942 | + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { |
1943 | + | |
1944 | + for (child = wp->children; child; child = child->next) { | |
1945 | + if (child->pid == pid) { | |
1946 | + break; | |
1947 | + } | |
fd1be940 | 1948 | + } |
c6a6bfc9 ER |
1949 | + |
1950 | + if (child) break; | |
fd1be940 ER |
1951 | + } |
1952 | + | |
1953 | + if (!child) { | |
1954 | + return 0; | |
1955 | + } | |
1956 | + | |
fd1be940 ER |
1957 | + return child; |
1958 | +} | |
1959 | + | |
1960 | +static void fpm_child_init(struct fpm_worker_pool_s *wp) | |
1961 | +{ | |
1962 | + fpm_globals.max_requests = wp->config->max_requests; | |
c6a6bfc9 ER |
1963 | + |
1964 | + if (0 > fpm_stdio_init_child(wp) || | |
1965 | + 0 > fpm_unix_init_child(wp) || | |
1966 | + 0 > fpm_signals_init_child() || | |
1967 | + 0 > fpm_env_init_child(wp) || | |
1968 | + 0 > fpm_php_init_child(wp)) { | |
1969 | + | |
1970 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "child failed to initialize (pool %s)", wp->config->name); | |
1971 | + exit(255); | |
1972 | + } | |
fd1be940 ER |
1973 | +} |
1974 | + | |
1975 | +int fpm_children_free(struct fpm_child_s *child) | |
1976 | +{ | |
1977 | + struct fpm_child_s *next; | |
1978 | + | |
1979 | + for (; child; child = next) { | |
1980 | + next = child->next; | |
c6a6bfc9 | 1981 | + fpm_child_close(child, 0 /* in_event_loop */); |
fd1be940 ER |
1982 | + } |
1983 | + | |
1984 | + return 0; | |
1985 | +} | |
1986 | + | |
fd1be940 ER |
1987 | +void fpm_children_bury() |
1988 | +{ | |
1989 | + int status; | |
1990 | + pid_t pid; | |
1991 | + struct fpm_child_s *child; | |
1992 | + | |
c6a6bfc9 | 1993 | + while ( (pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { |
fd1be940 ER |
1994 | + char buf[128]; |
1995 | + int severity = ZLOG_NOTICE; | |
1996 | + | |
c6a6bfc9 ER |
1997 | + child = fpm_child_find(pid); |
1998 | + | |
fd1be940 ER |
1999 | + if (WIFEXITED(status)) { |
2000 | + | |
2001 | + snprintf(buf, sizeof(buf), "with code %d", WEXITSTATUS(status)); | |
2002 | + | |
2003 | + if (WEXITSTATUS(status) != 0) { | |
2004 | + severity = ZLOG_WARNING; | |
2005 | + } | |
2006 | + | |
2007 | + } | |
c6a6bfc9 ER |
2008 | + else if (WIFSIGNALED(status)) { |
2009 | + const char *signame = fpm_signal_names[WTERMSIG(status)]; | |
2010 | + const char *have_core = WCOREDUMP(status) ? " (core dumped)" : ""; | |
fd1be940 | 2011 | + |
c6a6bfc9 ER |
2012 | + if (signame == NULL) { |
2013 | + signame = ""; | |
2014 | + } | |
2015 | + | |
2016 | + snprintf(buf, sizeof(buf), "on signal %d %s%s", WTERMSIG(status), signame, have_core); | |
fd1be940 ER |
2017 | + |
2018 | + if (WTERMSIG(status) != SIGQUIT) { /* possible request loss */ | |
2019 | + severity = ZLOG_WARNING; | |
2020 | + } | |
2021 | + } | |
c6a6bfc9 ER |
2022 | + else if (WIFSTOPPED(status)) { |
2023 | + | |
2024 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "child %d stopped for tracing", (int) pid); | |
2025 | + | |
2026 | + if (child && child->tracer) { | |
2027 | + child->tracer(child); | |
2028 | + } | |
fd1be940 | 2029 | + |
c6a6bfc9 ER |
2030 | + continue; |
2031 | + } | |
fd1be940 ER |
2032 | + |
2033 | + if (child) { | |
2034 | + struct fpm_worker_pool_s *wp = child->wp; | |
2035 | + struct timeval tv1, tv2; | |
2036 | + | |
c6a6bfc9 ER |
2037 | + fpm_child_unlink(child); |
2038 | + | |
2039 | + fpm_shm_slots_discard_slot(child); | |
2040 | + | |
2041 | + fpm_clock_get(&tv1); | |
fd1be940 ER |
2042 | + |
2043 | + timersub(&tv1, &child->started, &tv2); | |
2044 | + | |
c6a6bfc9 | 2045 | + zlog(ZLOG_STUFF, severity, "child %d (pool %s) exited %s after %ld.%06d seconds from start", (int) pid, |
fd1be940 ER |
2046 | + child->wp->config->name, buf, tv2.tv_sec, (int) tv2.tv_usec); |
2047 | + | |
c6a6bfc9 | 2048 | + fpm_child_close(child, 1 /* in event_loop */); |
fd1be940 ER |
2049 | + |
2050 | + fpm_pctl_child_exited(); | |
2051 | + | |
2052 | + if (last_faults && (WTERMSIG(status) == SIGSEGV || WTERMSIG(status) == SIGBUS)) { | |
2053 | + time_t now = tv1.tv_sec; | |
2054 | + int restart_condition = 1; | |
2055 | + int i; | |
2056 | + | |
2057 | + last_faults[fault++] = now; | |
2058 | + | |
48b142c9 | 2059 | + if (fault == fpm_global_config.emergency_restart_threshold) { |
fd1be940 ER |
2060 | + fault = 0; |
2061 | + } | |
2062 | + | |
48b142c9 ER |
2063 | + for (i = 0; i < fpm_global_config.emergency_restart_threshold; i++) { |
2064 | + if (now - last_faults[i] > fpm_global_config.emergency_restart_interval) { | |
fd1be940 ER |
2065 | + restart_condition = 0; |
2066 | + break; | |
2067 | + } | |
2068 | + } | |
2069 | + | |
2070 | + if (restart_condition) { | |
2071 | + | |
2072 | + zlog(ZLOG_STUFF, ZLOG_WARNING, "failed processes threshold (%d in %d sec) is reached, initiating reload", | |
48b142c9 | 2073 | + fpm_global_config.emergency_restart_threshold, fpm_global_config.emergency_restart_interval); |
fd1be940 ER |
2074 | + |
2075 | + fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET); | |
2076 | + } | |
2077 | + } | |
2078 | + | |
2079 | + fpm_children_make(wp, 1 /* in event loop */); | |
c6a6bfc9 ER |
2080 | + |
2081 | + if (fpm_globals.is_child) { | |
2082 | + break; | |
2083 | + } | |
fd1be940 ER |
2084 | + } |
2085 | + else { | |
2086 | + zlog(ZLOG_STUFF, ZLOG_ALERT, "oops, unknown child exited %s", buf); | |
2087 | + } | |
2088 | + } | |
2089 | + | |
2090 | +} | |
2091 | + | |
c6a6bfc9 ER |
2092 | +static struct fpm_child_s *fpm_resources_prepare(struct fpm_worker_pool_s *wp) |
2093 | +{ | |
2094 | + struct fpm_child_s *c; | |
2095 | + | |
2096 | + c = fpm_child_alloc(); | |
2097 | + | |
2098 | + if (!c) { | |
2099 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "malloc failed (pool %s)", wp->config->name); | |
2100 | + return 0; | |
2101 | + } | |
2102 | + | |
2103 | + c->wp = wp; | |
2104 | + c->fd_stdout = -1; c->fd_stderr = -1; | |
2105 | + | |
2106 | + if (0 > fpm_stdio_prepare_pipes(c)) { | |
2107 | + fpm_child_free(c); | |
2108 | + return 0; | |
2109 | + } | |
2110 | + | |
2111 | + if (0 > fpm_shm_slots_prepare_slot(c)) { | |
2112 | + fpm_stdio_discard_pipes(c); | |
2113 | + fpm_child_free(c); | |
2114 | + return 0; | |
2115 | + } | |
2116 | + | |
2117 | + return c; | |
2118 | +} | |
2119 | + | |
2120 | +static void fpm_resources_discard(struct fpm_child_s *child) | |
2121 | +{ | |
2122 | + fpm_shm_slots_discard_slot(child); | |
2123 | + fpm_stdio_discard_pipes(child); | |
2124 | + fpm_child_free(child); | |
2125 | +} | |
2126 | + | |
2127 | +static void fpm_child_resources_use(struct fpm_child_s *child) | |
2128 | +{ | |
2129 | + fpm_shm_slots_child_use_slot(child); | |
2130 | + fpm_stdio_child_use_pipes(child); | |
2131 | + fpm_child_free(child); | |
2132 | +} | |
2133 | + | |
2134 | +static void fpm_parent_resources_use(struct fpm_child_s *child) | |
2135 | +{ | |
2136 | + fpm_shm_slots_parent_use_slot(child); | |
2137 | + fpm_stdio_parent_use_pipes(child); | |
2138 | + fpm_child_link(child); | |
2139 | +} | |
2140 | + | |
fd1be940 ER |
2141 | +static int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop) |
2142 | +{ | |
2143 | + int enough = 0; | |
c6a6bfc9 ER |
2144 | + pid_t pid; |
2145 | + struct fpm_child_s *child; | |
fd1be940 ER |
2146 | + |
2147 | + while (!enough && fpm_pctl_can_spawn_children() && wp->running_children < wp->config->pm->max_children) { | |
fd1be940 | 2148 | + |
c6a6bfc9 ER |
2149 | + child = fpm_resources_prepare(wp); |
2150 | + | |
2151 | + if (!child) { | |
fd1be940 ER |
2152 | + enough = 1; |
2153 | + break; | |
2154 | + } | |
2155 | + | |
2156 | + pid = fork(); | |
2157 | + | |
2158 | + switch (pid) { | |
2159 | + | |
2160 | + case 0 : | |
c6a6bfc9 | 2161 | + fpm_child_resources_use(child); |
fd1be940 ER |
2162 | + fpm_globals.is_child = 1; |
2163 | + if (in_event_loop) { | |
2164 | + fpm_event_exit_loop(); | |
2165 | + } | |
2166 | + fpm_child_init(wp); | |
2167 | + return 0; | |
2168 | + | |
2169 | + case -1 : | |
2170 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fork() failed"); | |
2171 | + enough = 1; | |
c6a6bfc9 ER |
2172 | + |
2173 | + fpm_resources_discard(child); | |
2174 | + | |
fd1be940 ER |
2175 | + break; /* dont try any more on error */ |
2176 | + | |
2177 | + default : | |
c6a6bfc9 ER |
2178 | + child->pid = pid; |
2179 | + fpm_clock_get(&child->started); | |
2180 | + fpm_parent_resources_use(child); | |
fd1be940 | 2181 | + |
c6a6bfc9 | 2182 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "child %d (pool %s) started", (int) pid, wp->config->name); |
fd1be940 ER |
2183 | + } |
2184 | + | |
2185 | + } | |
2186 | + | |
2187 | + return 1; /* we are done */ | |
2188 | +} | |
2189 | + | |
2190 | +int fpm_children_create_initial(struct fpm_worker_pool_s *wp) | |
2191 | +{ | |
2192 | + return fpm_children_make(wp, 0 /* not in event loop yet */); | |
2193 | +} | |
2194 | + | |
2195 | +int fpm_children_init_main() | |
2196 | +{ | |
48b142c9 ER |
2197 | + if (fpm_global_config.emergency_restart_threshold && |
2198 | + fpm_global_config.emergency_restart_interval) { | |
fd1be940 | 2199 | + |
48b142c9 | 2200 | + last_faults = malloc(sizeof(time_t) * fpm_global_config.emergency_restart_threshold); |
fd1be940 ER |
2201 | + |
2202 | + if (!last_faults) { | |
2203 | + return -1; | |
2204 | + } | |
2205 | + | |
48b142c9 | 2206 | + memset(last_faults, 0, sizeof(time_t) * fpm_global_config.emergency_restart_threshold); |
fd1be940 ER |
2207 | + } |
2208 | + | |
48b142c9 ER |
2209 | + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_children_cleanup, 0)) { |
2210 | + return -1; | |
2211 | + } | |
fd1be940 ER |
2212 | + |
2213 | + return 0; | |
2214 | +} | |
c6a6bfc9 | 2215 | + |
37d32ffb ER |
2216 | diff --git a/sapi/cgi/fpm/fpm_children.h b/sapi/cgi/fpm/fpm_children.h |
2217 | new file mode 100644 | |
37d32ffb ER |
2218 | --- /dev/null |
2219 | +++ b/sapi/cgi/fpm/fpm_children.h | |
c6a6bfc9 | 2220 | @@ -0,0 +1,33 @@ |
fd1be940 ER |
2221 | + |
2222 | + /* $Id$ */ | |
c6a6bfc9 | 2223 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
2224 | + |
2225 | +#ifndef FPM_CHILDREN_H | |
2226 | +#define FPM_CHILDREN_H 1 | |
2227 | + | |
2228 | +#include <sys/time.h> | |
2229 | +#include <sys/types.h> | |
2230 | +#include <event.h> | |
2231 | + | |
2232 | +#include "fpm_worker_pool.h" | |
2233 | + | |
2234 | +int fpm_children_create_initial(struct fpm_worker_pool_s *wp); | |
2235 | +int fpm_children_free(struct fpm_child_s *child); | |
2236 | +void fpm_children_bury(); | |
2237 | +int fpm_children_init_main(); | |
2238 | + | |
2239 | +struct fpm_child_s; | |
2240 | + | |
2241 | +struct fpm_child_s { | |
2242 | + struct fpm_child_s *prev, *next; | |
2243 | + struct timeval started; | |
2244 | + struct fpm_worker_pool_s *wp; | |
2245 | + struct event ev_stdout, ev_stderr; | |
c6a6bfc9 | 2246 | + int shm_slot_i; |
fd1be940 | 2247 | + int fd_stdout, fd_stderr; |
c6a6bfc9 ER |
2248 | + void (*tracer)(struct fpm_child_s *); |
2249 | + struct timeval slow_logged; | |
fd1be940 ER |
2250 | + pid_t pid; |
2251 | +}; | |
2252 | + | |
2253 | +#endif | |
37d32ffb ER |
2254 | diff --git a/sapi/cgi/fpm/fpm_cleanup.c b/sapi/cgi/fpm/fpm_cleanup.c |
2255 | new file mode 100644 | |
37d32ffb ER |
2256 | --- /dev/null |
2257 | +++ b/sapi/cgi/fpm/fpm_cleanup.c | |
c6a6bfc9 | 2258 | @@ -0,0 +1,51 @@ |
fd1be940 ER |
2259 | + |
2260 | + /* $Id$ */ | |
c6a6bfc9 | 2261 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
2262 | + |
2263 | +#include "fpm_config.h" | |
2264 | + | |
2265 | +#include <stdlib.h> | |
2266 | + | |
c6a6bfc9 | 2267 | +#include "fpm_arrays.h" |
fd1be940 ER |
2268 | +#include "fpm_cleanup.h" |
2269 | +#include "zlog.h" | |
2270 | + | |
2271 | +struct cleanup_s { | |
2272 | + int type; | |
2273 | + void (*cleanup)(int, void *); | |
2274 | + void *arg; | |
2275 | +}; | |
2276 | + | |
c6a6bfc9 | 2277 | +static struct fpm_array_s cleanups = { .sz = sizeof(struct cleanup_s) }; |
fd1be940 ER |
2278 | + |
2279 | +int fpm_cleanup_add(int type, void (*cleanup)(int, void *), void *arg) | |
2280 | +{ | |
c6a6bfc9 | 2281 | + struct cleanup_s *c; |
fd1be940 | 2282 | + |
c6a6bfc9 | 2283 | + c = fpm_array_push(&cleanups); |
fd1be940 | 2284 | + |
c6a6bfc9 ER |
2285 | + if (!c) { |
2286 | + return -1; | |
fd1be940 ER |
2287 | + } |
2288 | + | |
c6a6bfc9 ER |
2289 | + c->type = type; |
2290 | + c->cleanup = cleanup; | |
2291 | + c->arg = arg; | |
fd1be940 ER |
2292 | + |
2293 | + return 0; | |
2294 | +} | |
2295 | + | |
2296 | +void fpm_cleanups_run(int type) | |
2297 | +{ | |
c6a6bfc9 ER |
2298 | + struct cleanup_s *c = fpm_array_item_last(&cleanups); |
2299 | + int cl = cleanups.used; | |
fd1be940 | 2300 | + |
c6a6bfc9 | 2301 | + for ( ; cl--; c--) { |
fd1be940 ER |
2302 | + if (c->type & type) { |
2303 | + c->cleanup(type, c->arg); | |
2304 | + } | |
2305 | + } | |
2306 | + | |
c6a6bfc9 | 2307 | + fpm_array_free(&cleanups); |
fd1be940 | 2308 | +} |
c6a6bfc9 | 2309 | + |
37d32ffb ER |
2310 | diff --git a/sapi/cgi/fpm/fpm_cleanup.h b/sapi/cgi/fpm/fpm_cleanup.h |
2311 | new file mode 100644 | |
37d32ffb ER |
2312 | --- /dev/null |
2313 | +++ b/sapi/cgi/fpm/fpm_cleanup.h | |
fd1be940 ER |
2314 | @@ -0,0 +1,21 @@ |
2315 | + | |
2316 | + /* $Id$ */ | |
c6a6bfc9 | 2317 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
2318 | + |
2319 | +#ifndef FPM_CLEANUP_H | |
2320 | +#define FPM_CLEANUP_H 1 | |
2321 | + | |
2322 | +int fpm_cleanup_add(int type, void (*cleanup)(int, void *), void *); | |
2323 | +void fpm_cleanups_run(int type); | |
2324 | + | |
2325 | +enum { | |
2326 | + FPM_CLEANUP_CHILD = (1 << 0), | |
2327 | + FPM_CLEANUP_PARENT_EXIT = (1 << 1), | |
2328 | + FPM_CLEANUP_PARENT_EXIT_MAIN = (1 << 2), | |
2329 | + FPM_CLEANUP_PARENT_EXEC = (1 << 3), | |
2330 | + FPM_CLEANUP_PARENT = (1 << 1) | (1 << 2) | (1 << 3), | |
2331 | + FPM_CLEANUP_ALL = ~0, | |
2332 | +}; | |
2333 | + | |
2334 | +#endif | |
2335 | + | |
37d32ffb ER |
2336 | diff --git a/sapi/cgi/fpm/fpm_clock.c b/sapi/cgi/fpm/fpm_clock.c |
2337 | new file mode 100644 | |
37d32ffb ER |
2338 | --- /dev/null |
2339 | +++ b/sapi/cgi/fpm/fpm_clock.c | |
c6a6bfc9 ER |
2340 | @@ -0,0 +1,115 @@ |
2341 | + | |
2342 | + /* $Id$ */ | |
2343 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
2344 | + | |
2345 | +#include "fpm_config.h" | |
2346 | + | |
2347 | +#if defined(HAVE_CLOCK_GETTIME) | |
2348 | +#include <time.h> /* for CLOCK_MONOTONIC */ | |
2349 | +#endif | |
2350 | + | |
2351 | +#include "fpm_clock.h" | |
2352 | +#include "zlog.h" | |
2353 | + | |
2354 | + | |
2355 | +/* posix monotonic clock - preferred source of time */ | |
2356 | +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) | |
2357 | + | |
2358 | +static int monotonic_works; | |
2359 | + | |
2360 | +int fpm_clock_init() | |
2361 | +{ | |
2362 | + struct timespec ts; | |
2363 | + | |
2364 | + monotonic_works = 0; | |
2365 | + | |
2366 | + if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) { | |
2367 | + monotonic_works = 1; | |
2368 | + } | |
2369 | + | |
2370 | + return 0; | |
2371 | +} | |
2372 | + | |
2373 | +int fpm_clock_get(struct timeval *tv) | |
2374 | +{ | |
2375 | + if (monotonic_works) { | |
2376 | + struct timespec ts; | |
2377 | + | |
2378 | + if (0 > clock_gettime(CLOCK_MONOTONIC, &ts)) { | |
2379 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "clock_gettime() failed"); | |
2380 | + return -1; | |
2381 | + } | |
2382 | + | |
2383 | + tv->tv_sec = ts.tv_sec; | |
2384 | + tv->tv_usec = ts.tv_nsec / 1000; | |
2385 | + return 0; | |
2386 | + } | |
2387 | + | |
2388 | + return gettimeofday(tv, 0); | |
2389 | +} | |
2390 | + | |
2391 | +/* macosx clock */ | |
2392 | +#elif defined(HAVE_CLOCK_GET_TIME) | |
2393 | + | |
2394 | +#include <mach/mach.h> | |
2395 | +#include <mach/clock.h> | |
2396 | +#include <mach/mach_error.h> | |
2397 | + | |
2398 | +static clock_serv_t mach_clock; | |
2399 | + | |
2400 | +/* this code borrowed from here: http://lists.apple.com/archives/Darwin-development/2002/Mar/msg00746.html */ | |
2401 | +/* mach_clock also should be re-initialized in child process after fork */ | |
2402 | +int fpm_clock_init() | |
2403 | +{ | |
2404 | + kern_return_t ret; | |
2405 | + mach_timespec_t aTime; | |
2406 | + | |
2407 | + ret = host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &mach_clock); | |
2408 | + | |
2409 | + if (ret != KERN_SUCCESS) { | |
2410 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "host_get_clock_service() failed: %s", mach_error_string(ret)); | |
2411 | + return -1; | |
2412 | + } | |
2413 | + | |
2414 | + /* test if it works */ | |
2415 | + ret = clock_get_time(mach_clock, &aTime); | |
2416 | + | |
2417 | + if (ret != KERN_SUCCESS) { | |
2418 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "clock_get_time() failed: %s", mach_error_string(ret)); | |
2419 | + return -1; | |
2420 | + } | |
2421 | + | |
2422 | + return 0; | |
2423 | +} | |
2424 | + | |
2425 | +int fpm_clock_get(struct timeval *tv) | |
2426 | +{ | |
2427 | + kern_return_t ret; | |
2428 | + mach_timespec_t aTime; | |
2429 | + | |
2430 | + ret = clock_get_time(mach_clock, &aTime); | |
2431 | + | |
2432 | + if (ret != KERN_SUCCESS) { | |
2433 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "clock_get_time() failed: %s", mach_error_string(ret)); | |
2434 | + return -1; | |
2435 | + } | |
2436 | + | |
2437 | + tv->tv_sec = aTime.tv_sec; | |
2438 | + tv->tv_usec = aTime.tv_nsec / 1000; | |
2439 | + | |
2440 | + return 0; | |
2441 | +} | |
2442 | + | |
2443 | +#else /* no clock */ | |
2444 | + | |
2445 | +int fpm_clock_init() | |
2446 | +{ | |
2447 | + return 0; | |
2448 | +} | |
2449 | + | |
2450 | +int fpm_clock_get(struct timeval *tv) | |
2451 | +{ | |
2452 | + return gettimeofday(tv, 0); | |
2453 | +} | |
2454 | + | |
2455 | +#endif | |
37d32ffb ER |
2456 | diff --git a/sapi/cgi/fpm/fpm_clock.h b/sapi/cgi/fpm/fpm_clock.h |
2457 | new file mode 100644 | |
37d32ffb ER |
2458 | --- /dev/null |
2459 | +++ b/sapi/cgi/fpm/fpm_clock.h | |
c6a6bfc9 ER |
2460 | @@ -0,0 +1,13 @@ |
2461 | + | |
2462 | + /* $Id$ */ | |
2463 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
2464 | + | |
2465 | +#ifndef FPM_CLOCK_H | |
2466 | +#define FPM_CLOCK_H 1 | |
2467 | + | |
2468 | +#include <sys/time.h> | |
2469 | + | |
2470 | +int fpm_clock_init(); | |
2471 | +int fpm_clock_get(struct timeval *tv); | |
2472 | + | |
2473 | +#endif | |
37d32ffb ER |
2474 | diff --git a/sapi/cgi/fpm/fpm_conf.c b/sapi/cgi/fpm/fpm_conf.c |
2475 | new file mode 100644 | |
37d32ffb ER |
2476 | --- /dev/null |
2477 | +++ b/sapi/cgi/fpm/fpm_conf.c | |
48b142c9 | 2478 | @@ -0,0 +1,532 @@ |
fd1be940 ER |
2479 | + |
2480 | + /* $Id$ */ | |
c6a6bfc9 | 2481 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
2482 | + |
2483 | +#include "fpm_config.h" | |
2484 | + | |
2485 | +#include <sys/types.h> | |
2486 | +#include <sys/stat.h> | |
2487 | +#include <fcntl.h> | |
2488 | +#include <string.h> | |
2489 | +#include <stdlib.h> | |
2490 | +#include <stddef.h> | |
2491 | +#include <stdint.h> | |
2492 | +#include <stdio.h> | |
2493 | +#include <unistd.h> | |
2494 | + | |
2495 | +#include "fpm.h" | |
2496 | +#include "fpm_conf.h" | |
c6a6bfc9 | 2497 | +#include "fpm_stdio.h" |
fd1be940 ER |
2498 | +#include "fpm_worker_pool.h" |
2499 | +#include "fpm_cleanup.h" | |
2500 | +#include "fpm_php.h" | |
2501 | +#include "fpm_sockets.h" | |
2502 | +#include "xml_config.h" | |
2503 | +#include "zlog.h" | |
2504 | + | |
2505 | + | |
48b142c9 | 2506 | +struct fpm_global_config_s fpm_global_config; |
fd1be940 | 2507 | + |
48b142c9 | 2508 | +static void *fpm_global_config_ptr() |
fd1be940 | 2509 | +{ |
48b142c9 | 2510 | + return &fpm_global_config; |
fd1be940 ER |
2511 | +} |
2512 | + | |
c6a6bfc9 ER |
2513 | +static char *fpm_conf_set_log_level(void **conf, char *name, void *vv, intptr_t offset) |
2514 | +{ | |
2515 | + char *value = vv; | |
2516 | + | |
2517 | + if (!strcmp(value, "debug")) { | |
2518 | + fpm_globals.log_level = ZLOG_DEBUG; | |
2519 | + } | |
2520 | + else if (!strcmp(value, "notice")) { | |
2521 | + fpm_globals.log_level = ZLOG_NOTICE; | |
2522 | + } | |
2523 | + else if (!strcmp(value, "warn")) { | |
2524 | + fpm_globals.log_level = ZLOG_WARNING; | |
2525 | + } | |
2526 | + else if (!strcmp(value, "error")) { | |
2527 | + fpm_globals.log_level = ZLOG_ERROR; | |
2528 | + } | |
2529 | + else if (!strcmp(value, "alert")) { | |
2530 | + fpm_globals.log_level = ZLOG_ALERT; | |
2531 | + } | |
2532 | + else { | |
2533 | + return "invalid value for 'log_level'"; | |
2534 | + } | |
2535 | + | |
2536 | + return NULL; | |
2537 | +} | |
2538 | + | |
fd1be940 | 2539 | +static struct xml_conf_section xml_section_fpm_global_options = { |
48b142c9 | 2540 | + .conf = &fpm_global_config_ptr, |
fd1be940 | 2541 | + .path = "/configuration/global_options", |
c6a6bfc9 | 2542 | + .parsers = (struct xml_value_parser []) { |
48b142c9 ER |
2543 | + { XML_CONF_SCALAR, "emergency_restart_threshold", &xml_conf_set_slot_integer, offsetof(struct fpm_global_config_s, emergency_restart_threshold) }, |
2544 | + { XML_CONF_SCALAR, "emergency_restart_interval", &xml_conf_set_slot_time, offsetof(struct fpm_global_config_s, emergency_restart_interval) }, | |
2545 | + { XML_CONF_SCALAR, "process_control_timeout", &xml_conf_set_slot_time, offsetof(struct fpm_global_config_s, process_control_timeout) }, | |
2546 | + { XML_CONF_SCALAR, "daemonize", &xml_conf_set_slot_boolean, offsetof(struct fpm_global_config_s, daemonize) }, | |
2547 | + { XML_CONF_SCALAR, "pid_file", &xml_conf_set_slot_string, offsetof(struct fpm_global_config_s, pid_file) }, | |
2548 | + { XML_CONF_SCALAR, "error_log", &xml_conf_set_slot_string, offsetof(struct fpm_global_config_s, error_log) }, | |
c6a6bfc9 | 2549 | + { XML_CONF_SCALAR, "log_level", &fpm_conf_set_log_level, 0 }, |
fd1be940 ER |
2550 | + { 0, 0, 0, 0 } |
2551 | + } | |
2552 | +}; | |
2553 | + | |
2554 | +static char *fpm_conf_set_pm_style(void **conf, char *name, void *vv, intptr_t offset) | |
2555 | +{ | |
2556 | + char *value = vv; | |
2557 | + struct fpm_pm_s *c = *conf; | |
2558 | + | |
2559 | + if (!strcmp(value, "static")) { | |
2560 | + c->style = PM_STYLE_STATIC; | |
2561 | + } | |
2562 | + else if (!strcmp(value, "apache-like")) { | |
2563 | + c->style = PM_STYLE_APACHE_LIKE; | |
2564 | + } | |
2565 | + else { | |
2566 | + return "invalid value for 'style'"; | |
2567 | + } | |
2568 | + | |
2569 | + return NULL; | |
2570 | +} | |
2571 | + | |
2572 | +static char *fpm_conf_set_rlimit_core(void **conf, char *name, void *vv, intptr_t offset) | |
2573 | +{ | |
2574 | + char *value = vv; | |
2575 | + struct fpm_worker_pool_config_s *c = *conf; | |
2576 | + | |
2577 | + if (!strcmp(value, "unlimited")) { | |
2578 | + c->rlimit_core = -1; | |
2579 | + } | |
2580 | + else { | |
2581 | + int int_value; | |
2582 | + void *subconf = &int_value; | |
2583 | + char *error; | |
2584 | + | |
2585 | + error = xml_conf_set_slot_integer(&subconf, name, vv, 0); | |
2586 | + | |
2587 | + if (error) return error; | |
2588 | + | |
2589 | + if (int_value < 0) return "invalid value for 'rlimit_core'"; | |
2590 | + | |
2591 | + c->rlimit_core = int_value; | |
2592 | + } | |
2593 | + | |
2594 | + return NULL; | |
2595 | +} | |
2596 | + | |
2597 | +static char *fpm_conf_set_catch_workers_output(void **conf, char *name, void *vv, intptr_t offset) | |
2598 | +{ | |
2599 | + struct fpm_worker_pool_config_s *c = *conf; | |
2600 | + int int_value; | |
2601 | + void *subconf = &int_value; | |
2602 | + char *error; | |
2603 | + | |
2604 | + error = xml_conf_set_slot_boolean(&subconf, name, vv, 0); | |
2605 | + | |
2606 | + if (error) return error; | |
2607 | + | |
2608 | + c->catch_workers_output = int_value; | |
2609 | + | |
2610 | + return NULL; | |
2611 | +} | |
2612 | + | |
c6a6bfc9 ER |
2613 | +static struct xml_conf_section fpm_conf_set_apache_like_subsection_conf = { |
2614 | + .path = "apache_like somewhere", /* fixme */ | |
2615 | + .parsers = (struct xml_value_parser []) { | |
2616 | + { XML_CONF_SCALAR, "StartServers", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, options_apache_like.StartServers) }, | |
2617 | + { XML_CONF_SCALAR, "MinSpareServers", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, options_apache_like.MinSpareServers) }, | |
2618 | + { XML_CONF_SCALAR, "MaxSpareServers", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, options_apache_like.MaxSpareServers) }, | |
2619 | + { 0, 0, 0, 0 } | |
2620 | + } | |
2621 | +}; | |
2622 | + | |
fd1be940 ER |
2623 | +static char *fpm_conf_set_apache_like_subsection(void **conf, char *name, void *xml_node, intptr_t offset) |
2624 | +{ | |
fd1be940 ER |
2625 | + return xml_conf_parse_section(conf, &fpm_conf_set_apache_like_subsection_conf, xml_node); |
2626 | +} | |
2627 | + | |
c6a6bfc9 ER |
2628 | +static struct xml_conf_section fpm_conf_set_listen_options_subsection_conf = { |
2629 | + .path = "listen options somewhere", /* fixme */ | |
2630 | + .parsers = (struct xml_value_parser []) { | |
2631 | + { XML_CONF_SCALAR, "backlog", &xml_conf_set_slot_integer, offsetof(struct fpm_listen_options_s, backlog) }, | |
2632 | + { XML_CONF_SCALAR, "owner", &xml_conf_set_slot_string, offsetof(struct fpm_listen_options_s, owner) }, | |
2633 | + { XML_CONF_SCALAR, "group", &xml_conf_set_slot_string, offsetof(struct fpm_listen_options_s, group) }, | |
2634 | + { XML_CONF_SCALAR, "mode", &xml_conf_set_slot_string, offsetof(struct fpm_listen_options_s, mode) }, | |
2635 | + { 0, 0, 0, 0 } | |
2636 | + } | |
2637 | +}; | |
2638 | + | |
fd1be940 ER |
2639 | +static char *fpm_conf_set_listen_options_subsection(void **conf, char *name, void *xml_node, intptr_t offset) |
2640 | +{ | |
2641 | + void *subconf = (char *) *conf + offset; | |
2642 | + struct fpm_listen_options_s *lo; | |
2643 | + | |
fd1be940 ER |
2644 | + lo = malloc(sizeof(*lo)); |
2645 | + | |
2646 | + if (!lo) { | |
c6a6bfc9 | 2647 | + return "malloc() failed"; |
fd1be940 ER |
2648 | + } |
2649 | + | |
2650 | + memset(lo, 0, sizeof(*lo)); | |
2651 | + | |
2652 | + lo->backlog = -1; | |
2653 | + | |
2654 | + * (struct fpm_listen_options_s **) subconf = lo; | |
2655 | + | |
2656 | + subconf = lo; | |
2657 | + | |
2658 | + return xml_conf_parse_section(&subconf, &fpm_conf_set_listen_options_subsection_conf, xml_node); | |
2659 | +} | |
2660 | + | |
c6a6bfc9 ER |
2661 | +static struct xml_conf_section fpm_conf_set_pm_subsection_conf = { |
2662 | + .path = "pm settings somewhere", /* fixme */ | |
2663 | + .parsers = (struct xml_value_parser []) { | |
2664 | + { XML_CONF_SCALAR, "style", &fpm_conf_set_pm_style, 0 }, | |
2665 | + { XML_CONF_SCALAR, "max_children", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, max_children) }, | |
2666 | + { XML_CONF_SUBSECTION, "apache_like", &fpm_conf_set_apache_like_subsection, offsetof(struct fpm_pm_s, options_apache_like) }, | |
2667 | + { 0, 0, 0, 0 } | |
2668 | + } | |
2669 | +}; | |
2670 | + | |
fd1be940 ER |
2671 | +static char *fpm_conf_set_pm_subsection(void **conf, char *name, void *xml_node, intptr_t offset) |
2672 | +{ | |
2673 | + void *subconf = (char *) *conf + offset; | |
2674 | + struct fpm_pm_s *pm; | |
2675 | + | |
fd1be940 ER |
2676 | + pm = malloc(sizeof(*pm)); |
2677 | + | |
2678 | + if (!pm) { | |
2679 | + return "fpm_conf_set_pm_subsection(): malloc failed"; | |
2680 | + } | |
2681 | + | |
2682 | + memset(pm, 0, sizeof(*pm)); | |
2683 | + | |
2684 | + * (struct fpm_pm_s **) subconf = pm; | |
2685 | + | |
2686 | + subconf = pm; | |
2687 | + | |
2688 | + return xml_conf_parse_section(&subconf, &fpm_conf_set_pm_subsection_conf, xml_node); | |
2689 | +} | |
2690 | + | |
2691 | +static char *xml_conf_set_slot_key_value_pair(void **conf, char *name, void *vv, intptr_t offset) | |
2692 | +{ | |
2693 | + char *value = vv; | |
2694 | + struct key_value_s *kv; | |
2695 | + struct key_value_s ***parent = (struct key_value_s ***) conf; | |
2696 | + | |
2697 | + kv = malloc(sizeof(*kv)); | |
2698 | + | |
2699 | + if (!kv) { | |
c6a6bfc9 | 2700 | + return "malloc() failed"; |
fd1be940 ER |
2701 | + } |
2702 | + | |
2703 | + memset(kv, 0, sizeof(*kv)); | |
2704 | + | |
2705 | + kv->key = strdup(name); | |
2706 | + kv->value = strdup(value); | |
2707 | + | |
2708 | + if (!kv->key || !kv->value) { | |
2709 | + return "xml_conf_set_slot_key_value_pair(): strdup() failed"; | |
2710 | + } | |
2711 | + | |
2712 | + **parent = kv; | |
2713 | + | |
2714 | + *parent = &kv->next; | |
2715 | + | |
2716 | + return NULL; | |
2717 | +} | |
2718 | + | |
c6a6bfc9 ER |
2719 | +static struct xml_conf_section fpm_conf_set_key_value_pairs_subsection_conf = { |
2720 | + .path = "key_value_pairs somewhere", /* fixme */ | |
2721 | + .parsers = (struct xml_value_parser []) { | |
2722 | + { XML_CONF_SCALAR, 0, &xml_conf_set_slot_key_value_pair, 0 }, | |
2723 | + { 0, 0, 0, 0 } | |
2724 | + } | |
2725 | +}; | |
2726 | + | |
fd1be940 ER |
2727 | +static char *fpm_conf_set_key_value_pairs_subsection(void **conf, char *name, void *xml_node, intptr_t offset) |
2728 | +{ | |
2729 | + void *next_kv = (char *) *conf + offset; | |
2730 | + | |
fd1be940 ER |
2731 | + return xml_conf_parse_section(&next_kv, &fpm_conf_set_key_value_pairs_subsection_conf, xml_node); |
2732 | +} | |
2733 | + | |
2734 | +static void *fpm_worker_pool_config_alloc() | |
2735 | +{ | |
2736 | + static struct fpm_worker_pool_s *current_wp = 0; | |
2737 | + struct fpm_worker_pool_s *wp; | |
2738 | + | |
2739 | + wp = fpm_worker_pool_alloc(); | |
2740 | + | |
2741 | + if (!wp) return 0; | |
2742 | + | |
2743 | + wp->config = malloc(sizeof(struct fpm_worker_pool_config_s)); | |
2744 | + | |
2745 | + if (!wp->config) return 0; | |
2746 | + | |
2747 | + memset(wp->config, 0, sizeof(struct fpm_worker_pool_config_s)); | |
2748 | + | |
2749 | + if (current_wp) current_wp->next = wp; | |
2750 | + | |
2751 | + current_wp = wp; | |
2752 | + | |
2753 | + return wp->config; | |
2754 | +} | |
2755 | + | |
2756 | +int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc) | |
2757 | +{ | |
2758 | + struct key_value_s *kv, *kv_next; | |
2759 | + | |
2760 | + free(wpc->name); | |
2761 | + free(wpc->listen_address); | |
2762 | + if (wpc->listen_options) { | |
2763 | + free(wpc->listen_options->owner); | |
2764 | + free(wpc->listen_options->group); | |
2765 | + free(wpc->listen_options->mode); | |
2766 | + free(wpc->listen_options); | |
2767 | + } | |
2768 | + for (kv = wpc->php_defines; kv; kv = kv_next) { | |
2769 | + kv_next = kv->next; | |
2770 | + free(kv->key); | |
2771 | + free(kv->value); | |
2772 | + free(kv); | |
2773 | + } | |
2774 | + for (kv = wpc->environment; kv; kv = kv_next) { | |
2775 | + kv_next = kv->next; | |
2776 | + free(kv->key); | |
2777 | + free(kv->value); | |
2778 | + free(kv); | |
2779 | + } | |
2780 | + free(wpc->pm); | |
2781 | + free(wpc->user); | |
2782 | + free(wpc->group); | |
2783 | + free(wpc->chroot); | |
2784 | + free(wpc->chdir); | |
2785 | + free(wpc->allowed_clients); | |
c6a6bfc9 | 2786 | + free(wpc->slowlog); |
fd1be940 ER |
2787 | + |
2788 | + return 0; | |
2789 | +} | |
2790 | + | |
2791 | +static struct xml_conf_section xml_section_fpm_worker_pool_config = { | |
2792 | + .conf = &fpm_worker_pool_config_alloc, | |
2793 | + .path = "/configuration/workers/pool", | |
c6a6bfc9 | 2794 | + .parsers = (struct xml_value_parser []) { |
fd1be940 ER |
2795 | + { XML_CONF_SCALAR, "name", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, name) }, |
2796 | + { XML_CONF_SCALAR, "listen_address", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, listen_address) }, | |
2797 | + { XML_CONF_SUBSECTION, "listen_options", &fpm_conf_set_listen_options_subsection, offsetof(struct fpm_worker_pool_config_s, listen_options) }, | |
2798 | + { XML_CONF_SUBSECTION, "php_defines", &fpm_conf_set_key_value_pairs_subsection, offsetof(struct fpm_worker_pool_config_s, php_defines) }, | |
2799 | + { XML_CONF_SCALAR, "user", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, user) }, | |
2800 | + { XML_CONF_SCALAR, "group", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, group) }, | |
2801 | + { XML_CONF_SCALAR, "chroot", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, chroot) }, | |
2802 | + { XML_CONF_SCALAR, "chdir", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, chdir) }, | |
2803 | + { XML_CONF_SCALAR, "allowed_clients", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, allowed_clients) }, | |
2804 | + { XML_CONF_SUBSECTION, "environment", &fpm_conf_set_key_value_pairs_subsection, offsetof(struct fpm_worker_pool_config_s, environment) }, | |
c6a6bfc9 ER |
2805 | + { XML_CONF_SCALAR, "request_terminate_timeout", &xml_conf_set_slot_time, offsetof(struct fpm_worker_pool_config_s, request_terminate_timeout) }, |
2806 | + { XML_CONF_SCALAR, "request_slowlog_timeout", &xml_conf_set_slot_time, offsetof(struct fpm_worker_pool_config_s, request_slowlog_timeout) }, | |
2807 | + { XML_CONF_SCALAR, "slowlog", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, slowlog) }, | |
fd1be940 ER |
2808 | + { XML_CONF_SCALAR, "rlimit_files", &xml_conf_set_slot_integer, offsetof(struct fpm_worker_pool_config_s, rlimit_files) }, |
2809 | + { XML_CONF_SCALAR, "rlimit_core", &fpm_conf_set_rlimit_core, 0 }, | |
2810 | + { XML_CONF_SCALAR, "max_requests", &xml_conf_set_slot_integer, offsetof(struct fpm_worker_pool_config_s, max_requests) }, | |
2811 | + { XML_CONF_SCALAR, "catch_workers_output", &fpm_conf_set_catch_workers_output, 0 }, | |
2812 | + { XML_CONF_SUBSECTION, "pm", &fpm_conf_set_pm_subsection, offsetof(struct fpm_worker_pool_config_s, pm) }, | |
2813 | + { 0, 0, 0, 0 } | |
2814 | + } | |
2815 | +}; | |
2816 | + | |
2817 | +static struct xml_conf_section *fpm_conf_all_sections[] = { | |
2818 | + &xml_section_fpm_global_options, | |
2819 | + &xml_section_fpm_worker_pool_config, | |
2820 | + 0 | |
2821 | +}; | |
2822 | + | |
2823 | +static int fpm_evaluate_full_path(char **path) | |
2824 | +{ | |
2825 | + if (**path != '/') { | |
2826 | + char *full_path; | |
2827 | + | |
2828 | + full_path = malloc(sizeof(PHP_PREFIX) + strlen(*path) + 1); | |
2829 | + | |
2830 | + if (!full_path) return -1; | |
2831 | + | |
2832 | + sprintf(full_path, "%s/%s", PHP_PREFIX, *path); | |
2833 | + | |
2834 | + free(*path); | |
2835 | + | |
2836 | + *path = full_path; | |
2837 | + } | |
2838 | + | |
2839 | + return 0; | |
2840 | +} | |
2841 | + | |
2842 | +static int fpm_conf_process_all_pools() | |
2843 | +{ | |
2844 | + struct fpm_worker_pool_s *wp; | |
2845 | + | |
2846 | + if (!fpm_worker_all_pools) { | |
2847 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "at least one pool section must be specified in config file"); | |
2848 | + return -1; | |
2849 | + } | |
2850 | + | |
2851 | + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { | |
2852 | + | |
2853 | + if (wp->config->listen_address && *wp->config->listen_address) { | |
2854 | + | |
2855 | + wp->listen_address_domain = fpm_sockets_domain_from_address(wp->config->listen_address); | |
2856 | + | |
2857 | + if (wp->listen_address_domain == FPM_AF_UNIX && *wp->config->listen_address != '/') { | |
2858 | + fpm_evaluate_full_path(&wp->config->listen_address); | |
2859 | + } | |
2860 | + | |
2861 | + } | |
2862 | + else { | |
2863 | + | |
2864 | + wp->is_template = 1; | |
2865 | + | |
2866 | + } | |
c6a6bfc9 ER |
2867 | + |
2868 | + if (wp->config->request_slowlog_timeout) { | |
2869 | +#if HAVE_FPM_TRACE | |
2870 | + if (! (wp->config->slowlog && *wp->config->slowlog)) { | |
2871 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "pool %s: 'slowlog' must be specified for use with 'request_slowlog_timeout'", | |
2872 | + wp->config->name); | |
2873 | + return -1; | |
2874 | + } | |
2875 | +#else | |
2876 | + static int warned = 0; | |
2877 | + | |
2878 | + if (!warned) { | |
2879 | + zlog(ZLOG_STUFF, ZLOG_WARNING, "pool %s: 'request_slowlog_timeout' is not supported on your system", | |
2880 | + wp->config->name); | |
2881 | + warned = 1; | |
2882 | + } | |
2883 | + | |
2884 | + wp->config->request_slowlog_timeout = 0; | |
2885 | +#endif | |
2886 | + } | |
2887 | + | |
2888 | + if (wp->config->request_slowlog_timeout && wp->config->slowlog && *wp->config->slowlog) { | |
2889 | + int fd; | |
2890 | + | |
2891 | + fpm_evaluate_full_path(&wp->config->slowlog); | |
2892 | + | |
2893 | + if (wp->config->request_slowlog_timeout) { | |
2894 | + fd = open(wp->config->slowlog, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); | |
2895 | + | |
2896 | + if (0 > fd) { | |
2897 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(%s) failed", wp->config->slowlog); | |
2898 | + return -1; | |
2899 | + } | |
2900 | + close(fd); | |
2901 | + } | |
2902 | + } | |
fd1be940 ER |
2903 | + } |
2904 | + | |
2905 | + return 0; | |
2906 | +} | |
2907 | + | |
2908 | +int fpm_conf_unlink_pid() | |
2909 | +{ | |
48b142c9 | 2910 | + if (fpm_global_config.pid_file) { |
c6a6bfc9 | 2911 | + |
48b142c9 ER |
2912 | + if (0 > unlink(fpm_global_config.pid_file)) { |
2913 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "unlink(\"%s\") failed", fpm_global_config.pid_file); | |
c6a6bfc9 ER |
2914 | + return -1; |
2915 | + } | |
2916 | + | |
fd1be940 ER |
2917 | + } |
2918 | + | |
2919 | + return 0; | |
2920 | +} | |
2921 | + | |
2922 | +int fpm_conf_write_pid() | |
2923 | +{ | |
2924 | + int fd; | |
2925 | + | |
48b142c9 | 2926 | + if (fpm_global_config.pid_file) { |
fd1be940 ER |
2927 | + char buf[64]; |
2928 | + int len; | |
2929 | + | |
48b142c9 | 2930 | + unlink(fpm_global_config.pid_file); |
fd1be940 | 2931 | + |
48b142c9 | 2932 | + fd = creat(fpm_global_config.pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
fd1be940 | 2933 | + |
c6a6bfc9 | 2934 | + if (fd < 0) { |
48b142c9 | 2935 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "creat(\"%s\") failed", fpm_global_config.pid_file); |
fd1be940 ER |
2936 | + return -1; |
2937 | + } | |
2938 | + | |
c6a6bfc9 | 2939 | + len = sprintf(buf, "%d", (int) fpm_globals.parent_pid); |
fd1be940 ER |
2940 | + |
2941 | + if (len != write(fd, buf, len)) { | |
2942 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "write() failed"); | |
2943 | + return -1; | |
2944 | + } | |
2945 | + | |
2946 | + close(fd); | |
2947 | + } | |
2948 | + | |
2949 | + return 0; | |
2950 | +} | |
2951 | + | |
2952 | +static int fpm_conf_post_process() | |
2953 | +{ | |
48b142c9 ER |
2954 | + if (fpm_global_config.pid_file) { |
2955 | + fpm_evaluate_full_path(&fpm_global_config.pid_file); | |
fd1be940 ER |
2956 | + } |
2957 | + | |
48b142c9 ER |
2958 | + if (!fpm_global_config.error_log) { |
2959 | + fpm_global_config.error_log = strdup(PHP_FPM_LOG_PATH); | |
fd1be940 ER |
2960 | + } |
2961 | + | |
48b142c9 | 2962 | + fpm_evaluate_full_path(&fpm_global_config.error_log); |
fd1be940 | 2963 | + |
c6a6bfc9 | 2964 | + if (0 > fpm_stdio_open_error_log(0)) { |
fd1be940 ER |
2965 | + return -1; |
2966 | + } | |
2967 | + | |
fd1be940 ER |
2968 | + return fpm_conf_process_all_pools(); |
2969 | +} | |
2970 | + | |
2971 | +static void fpm_conf_cleanup(int which, void *arg) | |
2972 | +{ | |
48b142c9 ER |
2973 | + free(fpm_global_config.pid_file); |
2974 | + free(fpm_global_config.error_log); | |
2975 | + fpm_global_config.pid_file = 0; | |
2976 | + fpm_global_config.error_log = 0; | |
fd1be940 ER |
2977 | +} |
2978 | + | |
c6a6bfc9 | 2979 | +int fpm_conf_init_main() |
fd1be940 | 2980 | +{ |
c6a6bfc9 | 2981 | + char *filename = fpm_globals.config; |
fd1be940 ER |
2982 | + char *err; |
2983 | + | |
2984 | + if (0 > xml_conf_sections_register(fpm_conf_all_sections)) { | |
2985 | + return -1; | |
2986 | + } | |
2987 | + | |
2988 | + if (filename == NULL) { | |
c6a6bfc9 | 2989 | + filename = PHP_FPM_CONF_PATH; |
fd1be940 ER |
2990 | + } |
2991 | + | |
2992 | + err = xml_conf_load_file(filename); | |
2993 | + | |
2994 | + if (err) { | |
2995 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "failed to load configuration file: %s", err); | |
2996 | + return -1; | |
2997 | + } | |
2998 | + | |
2999 | + if (0 > fpm_conf_post_process()) { | |
3000 | + return -1; | |
3001 | + } | |
3002 | + | |
3003 | + xml_conf_clean(); | |
3004 | + | |
48b142c9 ER |
3005 | + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_conf_cleanup, 0)) { |
3006 | + return -1; | |
3007 | + } | |
fd1be940 ER |
3008 | + |
3009 | + return 0; | |
3010 | +} | |
37d32ffb ER |
3011 | diff --git a/sapi/cgi/fpm/fpm_conf.h b/sapi/cgi/fpm/fpm_conf.h |
3012 | new file mode 100644 | |
37d32ffb ER |
3013 | --- /dev/null |
3014 | +++ b/sapi/cgi/fpm/fpm_conf.h | |
c6a6bfc9 | 3015 | @@ -0,0 +1,73 @@ |
fd1be940 ER |
3016 | + |
3017 | + /* $Id$ */ | |
c6a6bfc9 | 3018 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
3019 | + |
3020 | +#ifndef FPM_CONF_H | |
3021 | +#define FPM_CONF_H 1 | |
3022 | + | |
fd1be940 ER |
3023 | +struct key_value_s; |
3024 | + | |
3025 | +struct key_value_s { | |
3026 | + struct key_value_s *next; | |
3027 | + char *key; | |
3028 | + char *value; | |
3029 | +}; | |
3030 | + | |
48b142c9 | 3031 | +struct fpm_global_config_s { |
fd1be940 ER |
3032 | + int emergency_restart_threshold; |
3033 | + int emergency_restart_interval; | |
3034 | + int process_control_timeout; | |
3035 | + int daemonize; | |
3036 | + char *pid_file; | |
3037 | + char *error_log; | |
3038 | +}; | |
3039 | + | |
48b142c9 | 3040 | +extern struct fpm_global_config_s fpm_global_config; |
fd1be940 ER |
3041 | + |
3042 | +struct fpm_pm_s { | |
3043 | + int style; | |
3044 | + int max_children; | |
3045 | + struct { | |
3046 | + int StartServers; | |
3047 | + int MinSpareServers; | |
3048 | + int MaxSpareServers; | |
3049 | + } options_apache_like; | |
3050 | +}; | |
3051 | + | |
3052 | +struct fpm_listen_options_s { | |
3053 | + int backlog; | |
3054 | + char *owner; | |
3055 | + char *group; | |
3056 | + char *mode; | |
3057 | +}; | |
3058 | + | |
3059 | +struct fpm_worker_pool_config_s { | |
3060 | + char *name; | |
3061 | + char *listen_address; | |
3062 | + struct fpm_listen_options_s *listen_options; | |
3063 | + struct key_value_s *php_defines; | |
3064 | + char *user; | |
3065 | + char *group; | |
3066 | + char *chroot; | |
3067 | + char *chdir; | |
3068 | + char *allowed_clients; | |
3069 | + struct key_value_s *environment; | |
3070 | + struct fpm_pm_s *pm; | |
c6a6bfc9 ER |
3071 | + int request_terminate_timeout; |
3072 | + int request_slowlog_timeout; | |
3073 | + char *slowlog; | |
fd1be940 ER |
3074 | + int max_requests; |
3075 | + int rlimit_files; | |
3076 | + int rlimit_core; | |
c6a6bfc9 | 3077 | + unsigned catch_workers_output:1; |
fd1be940 ER |
3078 | +}; |
3079 | + | |
3080 | +enum { PM_STYLE_STATIC = 1, PM_STYLE_APACHE_LIKE = 2 }; | |
3081 | + | |
c6a6bfc9 | 3082 | +int fpm_conf_init_main(); |
fd1be940 ER |
3083 | +int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc); |
3084 | +int fpm_conf_write_pid(); | |
3085 | +int fpm_conf_unlink_pid(); | |
3086 | + | |
3087 | +#endif | |
3088 | + | |
37d32ffb ER |
3089 | diff --git a/sapi/cgi/fpm/fpm_config.h b/sapi/cgi/fpm/fpm_config.h |
3090 | new file mode 100644 | |
37d32ffb ER |
3091 | --- /dev/null |
3092 | +++ b/sapi/cgi/fpm/fpm_config.h | |
c6a6bfc9 | 3093 | @@ -0,0 +1,39 @@ |
fd1be940 ER |
3094 | + |
3095 | + /* $Id$ */ | |
c6a6bfc9 | 3096 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
3097 | + |
3098 | +#include "php_config.h" | |
c6a6bfc9 | 3099 | +#include "fpm_autoconf.h" |
fd1be940 ER |
3100 | + |
3101 | + | |
3102 | +/* Solaris does not have it */ | |
3103 | +#ifndef INADDR_NONE | |
3104 | +#define INADDR_NONE (-1) | |
3105 | +#endif | |
3106 | + | |
3107 | + | |
3108 | +/* If we're not using GNU C, elide __attribute__ */ | |
3109 | +#ifndef __GNUC__ | |
3110 | +# define __attribute__(x) /*NOTHING*/ | |
3111 | +#endif | |
3112 | + | |
3113 | + | |
3114 | +/* Solaris does not have it */ | |
3115 | +#ifndef timersub | |
3116 | +#define timersub(tvp, uvp, vvp) \ | |
3117 | + do { \ | |
3118 | + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ | |
3119 | + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ | |
3120 | + if ((vvp)->tv_usec < 0) { \ | |
3121 | + (vvp)->tv_sec--; \ | |
3122 | + (vvp)->tv_usec += 1000000; \ | |
3123 | + } \ | |
3124 | + } while (0) | |
3125 | +#endif | |
c6a6bfc9 ER |
3126 | + |
3127 | +#if defined(HAVE_PTRACE) || defined(PROC_MEM_FILE) || defined(HAVE_MACH_VM_READ) | |
3128 | +#define HAVE_FPM_TRACE 1 | |
3129 | +#else | |
3130 | +#define HAVE_FPM_TRACE 0 | |
3131 | +#endif | |
3132 | + | |
37d32ffb ER |
3133 | diff --git a/sapi/cgi/fpm/fpm_env.c b/sapi/cgi/fpm/fpm_env.c |
3134 | new file mode 100644 | |
37d32ffb ER |
3135 | --- /dev/null |
3136 | +++ b/sapi/cgi/fpm/fpm_env.c | |
fd1be940 ER |
3137 | @@ -0,0 +1,125 @@ |
3138 | + | |
3139 | + /* $Id$ */ | |
c6a6bfc9 | 3140 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
3141 | + |
3142 | +#include "fpm_config.h" | |
3143 | + | |
3144 | +#ifdef HAVE_ALLOCA_H | |
3145 | +#include <alloca.h> | |
3146 | +#endif | |
3147 | +#include <stdio.h> | |
3148 | +#include <stdlib.h> | |
3149 | +#include <string.h> | |
3150 | + | |
3151 | +#include "fpm_env.h" | |
3152 | +#include "zlog.h" | |
3153 | + | |
c6a6bfc9 | 3154 | +#ifndef HAVE_SETENV |
fd1be940 ER |
3155 | +int setenv(char *name, char *value, int overwrite) |
3156 | +{ | |
3157 | + int name_len = strlen(name); | |
3158 | + int value_len = strlen(value); | |
3159 | + char *var = alloca(name_len + 1 + value_len + 1); | |
3160 | + | |
3161 | + memcpy(var, name, name_len); | |
3162 | + | |
3163 | + var[name_len] = '='; | |
3164 | + | |
3165 | + memcpy(var + name_len + 1, value, value_len); | |
3166 | + | |
3167 | + var[name_len + 1 + value_len] = '\0'; | |
3168 | + | |
3169 | + return putenv(var); | |
3170 | +} | |
3171 | +#endif | |
3172 | + | |
c6a6bfc9 | 3173 | +#ifndef HAVE_CLEARENV |
fd1be940 ER |
3174 | +void clearenv() |
3175 | +{ | |
3176 | + char **envp; | |
3177 | + char *s; | |
3178 | + | |
3179 | + /* this algo is the only one known to me | |
3180 | + that works well on all systems */ | |
3181 | + while (*(envp = environ)) { | |
3182 | + char *eq = strchr(*envp, '='); | |
3183 | + | |
3184 | + s = strdup(*envp); | |
3185 | + | |
3186 | + if (eq) s[eq - *envp] = '\0'; | |
3187 | + | |
3188 | + unsetenv(s); | |
3189 | + free(s); | |
3190 | + } | |
3191 | + | |
3192 | +} | |
3193 | +#endif | |
3194 | + | |
3195 | + | |
3196 | +int fpm_env_init_child(struct fpm_worker_pool_s *wp) | |
3197 | +{ | |
3198 | + struct key_value_s *kv; | |
3199 | + | |
3200 | + clearenv(); | |
3201 | + | |
3202 | + for (kv = wp->config->environment; kv; kv = kv->next) { | |
3203 | + setenv(kv->key, kv->value, 1); | |
3204 | + } | |
3205 | + | |
3206 | + if (wp->user) { | |
3207 | + setenv("USER", wp->user, 1); | |
3208 | + } | |
3209 | + | |
3210 | + if (wp->home) { | |
3211 | + setenv("HOME", wp->home, 1); | |
3212 | + } | |
3213 | + | |
3214 | + return 0; | |
3215 | +} | |
3216 | + | |
3217 | +static int fpm_env_conf_wp(struct fpm_worker_pool_s *wp) | |
3218 | +{ | |
3219 | + struct key_value_s *kv; | |
3220 | + | |
3221 | + kv = wp->config->environment; | |
3222 | + | |
3223 | + for (kv = wp->config->environment; kv; kv = kv->next) { | |
3224 | + if (*kv->value == '$') { | |
3225 | + char *value = getenv(kv->value + 1); | |
3226 | + | |
3227 | + if (!value) value = ""; | |
3228 | + | |
3229 | + free(kv->value); | |
3230 | + kv->value = strdup(value); | |
3231 | + } | |
3232 | + | |
3233 | + /* autodetected values should be removed | |
3234 | + if these vars specified in config */ | |
3235 | + if (!strcmp(kv->key, "USER")) { | |
3236 | + free(wp->user); | |
3237 | + wp->user = 0; | |
3238 | + } | |
3239 | + | |
3240 | + if (!strcmp(kv->key, "HOME")) { | |
3241 | + free(wp->home); | |
3242 | + wp->home = 0; | |
3243 | + } | |
3244 | + } | |
3245 | + | |
3246 | + return 0; | |
3247 | +} | |
3248 | + | |
3249 | +int fpm_env_init_main() | |
3250 | +{ | |
3251 | + struct fpm_worker_pool_s *wp; | |
3252 | + | |
3253 | + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { | |
3254 | + | |
3255 | + if (0 > fpm_env_conf_wp(wp)) { | |
3256 | + return -1; | |
3257 | + } | |
3258 | + | |
3259 | + } | |
3260 | + | |
3261 | + return 0; | |
3262 | +} | |
37d32ffb ER |
3263 | diff --git a/sapi/cgi/fpm/fpm_env.h b/sapi/cgi/fpm/fpm_env.h |
3264 | new file mode 100644 | |
37d32ffb ER |
3265 | --- /dev/null |
3266 | +++ b/sapi/cgi/fpm/fpm_env.h | |
fd1be940 ER |
3267 | @@ -0,0 +1,24 @@ |
3268 | + | |
3269 | + /* $Id$ */ | |
c6a6bfc9 | 3270 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
3271 | + |
3272 | +#ifndef FPM_ENV_H | |
3273 | +#define FPM_ENV_H 1 | |
3274 | + | |
3275 | +#include "fpm_worker_pool.h" | |
3276 | + | |
3277 | +int fpm_env_init_child(struct fpm_worker_pool_s *wp); | |
3278 | +int fpm_env_init_main(); | |
3279 | + | |
3280 | +extern char **environ; | |
3281 | + | |
c6a6bfc9 | 3282 | +#ifndef HAVE_SETENV |
fd1be940 ER |
3283 | +int setenv(char *name, char *value, int overwrite); |
3284 | +#endif | |
3285 | + | |
c6a6bfc9 | 3286 | +#ifndef HAVE_CLEARENV |
fd1be940 ER |
3287 | +void clearenv(); |
3288 | +#endif | |
3289 | + | |
3290 | +#endif | |
3291 | + | |
37d32ffb ER |
3292 | diff --git a/sapi/cgi/fpm/fpm_events.c b/sapi/cgi/fpm/fpm_events.c |
3293 | new file mode 100644 | |
37d32ffb ER |
3294 | --- /dev/null |
3295 | +++ b/sapi/cgi/fpm/fpm_events.c | |
48b142c9 | 3296 | @@ -0,0 +1,135 @@ |
fd1be940 ER |
3297 | + |
3298 | + /* $Id$ */ | |
c6a6bfc9 | 3299 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
3300 | + |
3301 | +#include "fpm_config.h" | |
3302 | + | |
3303 | +#include <unistd.h> | |
3304 | +#include <errno.h> | |
3305 | +#include <stdlib.h> /* for putenv */ | |
3306 | +#include <string.h> | |
3307 | +#include <sys/types.h> /* for event.h below */ | |
3308 | +#include <event.h> | |
3309 | + | |
c6a6bfc9 | 3310 | +#include "fpm.h" |
fd1be940 ER |
3311 | +#include "fpm_process_ctl.h" |
3312 | +#include "fpm_events.h" | |
3313 | +#include "fpm_cleanup.h" | |
c6a6bfc9 | 3314 | +#include "fpm_stdio.h" |
fd1be940 ER |
3315 | +#include "fpm_signals.h" |
3316 | +#include "fpm_children.h" | |
3317 | +#include "zlog.h" | |
3318 | + | |
fd1be940 ER |
3319 | +static void fpm_event_cleanup(int which, void *arg) |
3320 | +{ | |
3321 | + event_base_free(0); | |
3322 | +} | |
3323 | + | |
3324 | +static void fpm_got_signal(int fd, short ev, void *arg) | |
3325 | +{ | |
3326 | + char c; | |
3327 | + int res; | |
3328 | + | |
3329 | + do { | |
fd1be940 | 3330 | + |
c6a6bfc9 ER |
3331 | + do { |
3332 | + res = read(fd, &c, 1); | |
3333 | + } while (res == -1 && errno == EINTR); | |
3334 | + | |
3335 | + if (res <= 0) { | |
3336 | + if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { | |
3337 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "read() failed"); | |
3338 | + } | |
3339 | + return; | |
fd1be940 | 3340 | + } |
fd1be940 | 3341 | + |
c6a6bfc9 ER |
3342 | + switch (c) { |
3343 | + case 'C' : /* SIGCHLD */ | |
3344 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGCHLD"); | |
3345 | + fpm_children_bury(); | |
3346 | + break; | |
3347 | + case 'I' : /* SIGINT */ | |
3348 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGINT"); | |
3349 | + fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET); | |
3350 | + break; | |
3351 | + case 'T' : /* SIGTERM */ | |
3352 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGTERM"); | |
3353 | + fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET); | |
3354 | + break; | |
3355 | + case 'Q' : /* SIGQUIT */ | |
3356 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGQUIT"); | |
3357 | + fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET); | |
3358 | + break; | |
3359 | + case '1' : /* SIGUSR1 */ | |
3360 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGUSR1"); | |
3361 | + if (0 == fpm_stdio_open_error_log(1)) { | |
3362 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "log file re-opened"); | |
3363 | + } | |
3364 | + break; | |
3365 | + case '2' : /* SIGUSR2 */ | |
3366 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "received SIGUSR2"); | |
3367 | + fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET); | |
3368 | + break; | |
3369 | + } | |
3370 | + | |
3371 | + if (fpm_globals.is_child) { | |
fd1be940 | 3372 | + break; |
c6a6bfc9 ER |
3373 | + } |
3374 | + | |
3375 | + } while (1); | |
fd1be940 ER |
3376 | + |
3377 | + return; | |
3378 | +} | |
3379 | + | |
3380 | +int fpm_event_init_main() | |
3381 | +{ | |
3382 | + event_init(); | |
3383 | + | |
3384 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "libevent: using %s", event_get_method()); | |
3385 | + | |
48b142c9 ER |
3386 | + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, 0)) { |
3387 | + return -1; | |
3388 | + } | |
fd1be940 ER |
3389 | + |
3390 | + return 0; | |
3391 | +} | |
3392 | + | |
3393 | +int fpm_event_loop() | |
3394 | +{ | |
3395 | + static struct event signal_fd_event; | |
3396 | + | |
3397 | + event_set(&signal_fd_event, fpm_signals_get_fd(), EV_PERSIST | EV_READ, &fpm_got_signal, 0); | |
3398 | + | |
3399 | + event_add(&signal_fd_event, 0); | |
3400 | + | |
c6a6bfc9 ER |
3401 | + fpm_pctl_heartbeat(-1, 0, 0); |
3402 | + | |
fd1be940 ER |
3403 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "libevent: entering main loop"); |
3404 | + | |
3405 | + event_loop(0); | |
3406 | + | |
fd1be940 ER |
3407 | + return 0; |
3408 | +} | |
3409 | + | |
3410 | +int fpm_event_add(int fd, struct event *ev, void (*callback)(int, short, void *), void *arg) | |
3411 | +{ | |
3412 | + event_set(ev, fd, EV_PERSIST | EV_READ, callback, arg); | |
3413 | + | |
3414 | + return event_add(ev, 0); | |
3415 | +} | |
3416 | + | |
3417 | +int fpm_event_del(struct event *ev) | |
3418 | +{ | |
3419 | + return event_del(ev); | |
3420 | +} | |
3421 | + | |
3422 | +void fpm_event_exit_loop() | |
3423 | +{ | |
48b142c9 | 3424 | + event_loopbreak(); |
fd1be940 ER |
3425 | +} |
3426 | + | |
3427 | +void fpm_event_fire(struct event *ev) | |
3428 | +{ | |
c6a6bfc9 | 3429 | + (*ev->ev_callback)( (int) ev->ev_fd, (short) ev->ev_res, ev->ev_arg); |
fd1be940 | 3430 | +} |
c6a6bfc9 | 3431 | + |
37d32ffb ER |
3432 | diff --git a/sapi/cgi/fpm/fpm_events.h b/sapi/cgi/fpm/fpm_events.h |
3433 | new file mode 100644 | |
37d32ffb ER |
3434 | --- /dev/null |
3435 | +++ b/sapi/cgi/fpm/fpm_events.h | |
c6a6bfc9 | 3436 | @@ -0,0 +1,16 @@ |
fd1be940 ER |
3437 | + |
3438 | + /* $Id$ */ | |
c6a6bfc9 | 3439 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
3440 | + |
3441 | +#ifndef FPM_EVENTS_H | |
3442 | +#define FPM_EVENTS_H 1 | |
3443 | + | |
fd1be940 ER |
3444 | +void fpm_event_exit_loop(); |
3445 | +int fpm_event_loop(); | |
3446 | +int fpm_event_add(int fd, struct event *ev, void (*callback)(int, short, void *), void *arg); | |
3447 | +int fpm_event_del(struct event *ev); | |
3448 | +void fpm_event_fire(struct event *ev); | |
3449 | +int fpm_event_init_main(); | |
3450 | + | |
3451 | + | |
3452 | +#endif | |
37d32ffb ER |
3453 | diff --git a/sapi/cgi/fpm/fpm_php.c b/sapi/cgi/fpm/fpm_php.c |
3454 | new file mode 100644 | |
37d32ffb ER |
3455 | --- /dev/null |
3456 | +++ b/sapi/cgi/fpm/fpm_php.c | |
48b142c9 | 3457 | @@ -0,0 +1,190 @@ |
fd1be940 ER |
3458 | + |
3459 | + /* $Id$ */ | |
c6a6bfc9 | 3460 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
3461 | + |
3462 | +#include "fpm_config.h" | |
3463 | + | |
fd1be940 ER |
3464 | +#include <stdlib.h> |
3465 | +#include <string.h> | |
48b142c9 | 3466 | +#include <stdio.h> |
fd1be940 ER |
3467 | + |
3468 | +#include "php.h" | |
3469 | +#include "php_main.h" | |
3470 | +#include "php_ini.h" | |
c6a6bfc9 | 3471 | +#include "ext/standard/dl.h" |
fd1be940 ER |
3472 | + |
3473 | +#include "fastcgi.h" | |
3474 | + | |
3475 | +#include "fpm.h" | |
3476 | +#include "fpm_php.h" | |
3477 | +#include "fpm_cleanup.h" | |
3478 | +#include "fpm_worker_pool.h" | |
3479 | + | |
48b142c9 | 3480 | +static int zend_ini_alter_master(char *name, int name_length, char *new_value, int new_value_length, int stage TSRMLS_DC) |
fd1be940 ER |
3481 | +{ |
3482 | + zend_ini_entry *ini_entry; | |
3483 | + char *duplicate; | |
3484 | + | |
3485 | + if (zend_hash_find(EG(ini_directives), name, name_length, (void **) &ini_entry) == FAILURE) { | |
3486 | + return FAILURE; | |
3487 | + } | |
3488 | + | |
3489 | + duplicate = strdup(new_value); | |
3490 | + | |
3491 | + if (!ini_entry->on_modify | |
3492 | + || ini_entry->on_modify(ini_entry, duplicate, new_value_length, | |
48b142c9 | 3493 | + ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage TSRMLS_CC) == SUCCESS) { |
fd1be940 ER |
3494 | + ini_entry->value = duplicate; |
3495 | + ini_entry->value_length = new_value_length; | |
3496 | + } else { | |
3497 | + free(duplicate); | |
3498 | + } | |
3499 | + | |
3500 | + return SUCCESS; | |
3501 | +} | |
3502 | + | |
48b142c9 | 3503 | +static void fpm_php_disable(char *value, int (*zend_disable)(char *, uint TSRMLS_DC) TSRMLS_DC) |
c6a6bfc9 ER |
3504 | +{ |
3505 | + char *s = 0, *e = value; | |
3506 | + | |
3507 | + while (*e) { | |
3508 | + switch (*e) { | |
3509 | + case ' ': | |
3510 | + case ',': | |
3511 | + if (s) { | |
3512 | + *e = '\0'; | |
48b142c9 | 3513 | + zend_disable(s, e - s TSRMLS_CC); |
c6a6bfc9 ER |
3514 | + s = 0; |
3515 | + } | |
3516 | + break; | |
3517 | + default: | |
3518 | + if (!s) { | |
3519 | + s = e; | |
3520 | + } | |
3521 | + break; | |
3522 | + } | |
3523 | + e++; | |
3524 | + } | |
3525 | + | |
3526 | + if (s) { | |
48b142c9 | 3527 | + zend_disable(s, e - s TSRMLS_CC); |
c6a6bfc9 ER |
3528 | + } |
3529 | +} | |
3530 | + | |
fd1be940 ER |
3531 | +static int fpm_php_apply_defines(struct fpm_worker_pool_s *wp) |
3532 | +{ | |
48b142c9 | 3533 | + TSRMLS_FETCH(); |
c6a6bfc9 ER |
3534 | + struct key_value_s *kv; |
3535 | + | |
3536 | + for (kv = wp->config->php_defines; kv; kv = kv->next) { | |
3537 | + char *name = kv->key; | |
3538 | + char *value = kv->value; | |
3539 | + int name_len = strlen(name); | |
3540 | + int value_len = strlen(value); | |
fd1be940 | 3541 | + |
c6a6bfc9 ER |
3542 | + if (!strcmp(name, "extension") && *value) { |
3543 | + zval zv; | |
fd1be940 | 3544 | + |
c6a6bfc9 | 3545 | +#if defined(PHP_VERSION_ID) && (PHP_VERSION_ID >= 50300) |
48b142c9 | 3546 | + php_dl(value, MODULE_PERSISTENT, &zv, 1 TSRMLS_CC); |
c6a6bfc9 ER |
3547 | +#else |
3548 | + zval filename; | |
3549 | + ZVAL_STRINGL(&filename, value, value_len, 0); | |
3550 | +#if (PHP_MAJOR_VERSION >= 5) | |
48b142c9 | 3551 | + php_dl(&filename, MODULE_PERSISTENT, &zv, 1 TSRMLS_CC); |
c6a6bfc9 | 3552 | +#else |
48b142c9 | 3553 | + php_dl(&filename, MODULE_PERSISTENT, &zv TSRMLS_CC); |
c6a6bfc9 ER |
3554 | +#endif |
3555 | +#endif | |
3556 | + continue; | |
3557 | + } | |
fd1be940 | 3558 | + |
48b142c9 | 3559 | + zend_ini_alter_master(name, name_len + 1, value, value_len, PHP_INI_STAGE_ACTIVATE TSRMLS_CC); |
fd1be940 | 3560 | + |
c6a6bfc9 ER |
3561 | + if (!strcmp(name, "disable_functions") && *value) { |
3562 | + char *v = strdup(value); | |
3563 | +#if (PHP_MAJOR_VERSION >= 5) | |
3564 | + PG(disable_functions) = v; | |
3565 | +#endif | |
48b142c9 | 3566 | + fpm_php_disable(v, zend_disable_function TSRMLS_CC); |
c6a6bfc9 ER |
3567 | + } |
3568 | + else if (!strcmp(name, "disable_classes") && *value) { | |
3569 | + char *v = strdup(value); | |
3570 | +#if (PHP_MAJOR_VERSION >= 5) | |
3571 | + PG(disable_classes) = v; | |
3572 | +#endif | |
48b142c9 | 3573 | + fpm_php_disable(v, zend_disable_class TSRMLS_CC); |
c6a6bfc9 | 3574 | + } |
fd1be940 ER |
3575 | + } |
3576 | + | |
3577 | + return 0; | |
3578 | +} | |
3579 | + | |
3580 | +static int fpm_php_set_allowed_clients(struct fpm_worker_pool_s *wp) | |
3581 | +{ | |
3582 | + if (wp->listen_address_domain == FPM_AF_INET) { | |
3583 | + fcgi_set_allowed_clients(wp->config->allowed_clients); | |
3584 | + } | |
3585 | + | |
3586 | + return 0; | |
3587 | +} | |
3588 | + | |
48b142c9 ER |
3589 | +static int fpm_php_set_fcgi_mgmt_vars(struct fpm_worker_pool_s *wp) |
3590 | +{ | |
3591 | + char max_workers[10 + 1]; /* 4294967295 */ | |
3592 | + int len; | |
3593 | + | |
3594 | + len = sprintf(max_workers, "%u", (unsigned int) wp->config->pm->max_children); | |
3595 | + | |
3596 | + fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, max_workers, len); | |
3597 | + fcgi_set_mgmt_var("FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, max_workers, len); | |
3598 | + | |
3599 | + return 0; | |
3600 | +} | |
3601 | + | |
3602 | +char *fpm_php_script_filename(TSRMLS_D) | |
c6a6bfc9 ER |
3603 | +{ |
3604 | + return SG(request_info).path_translated; | |
3605 | +} | |
3606 | + | |
48b142c9 | 3607 | +char *fpm_php_request_method(TSRMLS_D) |
c6a6bfc9 ER |
3608 | +{ |
3609 | + return (char *) SG(request_info).request_method; | |
3610 | +} | |
3611 | + | |
48b142c9 | 3612 | +size_t fpm_php_content_length(TSRMLS_D) |
c6a6bfc9 ER |
3613 | +{ |
3614 | + return SG(request_info).content_length; | |
3615 | +} | |
3616 | + | |
fd1be940 ER |
3617 | +static void fpm_php_cleanup(int which, void *arg) |
3618 | +{ | |
48b142c9 ER |
3619 | + TSRMLS_FETCH(); |
3620 | + php_module_shutdown(TSRMLS_C); | |
fd1be940 ER |
3621 | + sapi_shutdown(); |
3622 | +} | |
3623 | + | |
c6a6bfc9 ER |
3624 | +void fpm_php_soft_quit() |
3625 | +{ | |
3626 | + fcgi_set_in_shutdown(1); | |
3627 | +} | |
3628 | + | |
fd1be940 ER |
3629 | +int fpm_php_init_main() |
3630 | +{ | |
48b142c9 ER |
3631 | + if (0 > fpm_cleanup_add(FPM_CLEANUP_PARENT, fpm_php_cleanup, 0)) { |
3632 | + return -1; | |
3633 | + } | |
fd1be940 ER |
3634 | + |
3635 | + return 0; | |
3636 | +} | |
3637 | + | |
3638 | +int fpm_php_init_child(struct fpm_worker_pool_s *wp) | |
3639 | +{ | |
3640 | + if (0 > fpm_php_apply_defines(wp) || | |
48b142c9 ER |
3641 | + 0 > fpm_php_set_allowed_clients(wp) || |
3642 | + 0 > fpm_php_set_fcgi_mgmt_vars(wp)) { | |
fd1be940 ER |
3643 | + return -1; |
3644 | + } | |
3645 | + | |
3646 | + return 0; | |
3647 | +} | |
37d32ffb ER |
3648 | diff --git a/sapi/cgi/fpm/fpm_php.h b/sapi/cgi/fpm/fpm_php.h |
3649 | new file mode 100644 | |
37d32ffb ER |
3650 | --- /dev/null |
3651 | +++ b/sapi/cgi/fpm/fpm_php.h | |
48b142c9 | 3652 | @@ -0,0 +1,22 @@ |
fd1be940 ER |
3653 | + |
3654 | + /* $Id$ */ | |
c6a6bfc9 | 3655 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
3656 | + |
3657 | +#ifndef FPM_PHP_H | |
3658 | +#define FPM_PHP_H 1 | |
3659 | + | |
48b142c9 | 3660 | +#include <TSRM.h> |
fd1be940 ER |
3661 | + |
3662 | +#include "build-defs.h" /* for PHP_ defines */ | |
3663 | + | |
48b142c9 ER |
3664 | +struct fpm_worker_pool_s; |
3665 | + | |
fd1be940 | 3666 | +int fpm_php_init_child(struct fpm_worker_pool_s *wp); |
48b142c9 ER |
3667 | +char *fpm_php_script_filename(TSRMLS_D); |
3668 | +char *fpm_php_request_method(TSRMLS_D); | |
3669 | +size_t fpm_php_content_length(TSRMLS_D); | |
c6a6bfc9 | 3670 | +void fpm_php_soft_quit(); |
fd1be940 ER |
3671 | +int fpm_php_init_main(); |
3672 | + | |
3673 | +#endif | |
3674 | + | |
37d32ffb ER |
3675 | diff --git a/sapi/cgi/fpm/fpm_php_trace.c b/sapi/cgi/fpm/fpm_php_trace.c |
3676 | new file mode 100644 | |
37d32ffb ER |
3677 | --- /dev/null |
3678 | +++ b/sapi/cgi/fpm/fpm_php_trace.c | |
48b142c9 | 3679 | @@ -0,0 +1,171 @@ |
fd1be940 ER |
3680 | + |
3681 | + /* $Id$ */ | |
c6a6bfc9 ER |
3682 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
3683 | + | |
3684 | +#include "fpm_config.h" | |
3685 | + | |
3686 | +#if HAVE_FPM_TRACE | |
3687 | + | |
3688 | +#include "php.h" | |
3689 | +#include "php_main.h" | |
3690 | + | |
3691 | +#include <stdio.h> | |
3692 | +#include <stddef.h> | |
3693 | +#include <stdint.h> | |
3694 | +#include <unistd.h> | |
3695 | +#include <sys/time.h> | |
3696 | +#include <sys/types.h> | |
3697 | +#include <errno.h> | |
3698 | + | |
3699 | +#include "fpm_trace.h" | |
3700 | +#include "fpm_php_trace.h" | |
3701 | +#include "fpm_children.h" | |
3702 | +#include "fpm_worker_pool.h" | |
3703 | +#include "fpm_process_ctl.h" | |
3704 | + | |
3705 | +#include "zlog.h" | |
3706 | + | |
3707 | + | |
3708 | +#define valid_ptr(p) ((p) && 0 == ((p) & (sizeof(long) - 1))) | |
3709 | + | |
3710 | +#if SIZEOF_LONG == 4 | |
3711 | +#define PTR_FMT "08" | |
3712 | +#elif SIZEOF_LONG == 8 | |
3713 | +#define PTR_FMT "016" | |
3714 | +#endif | |
3715 | + | |
3716 | + | |
48b142c9 | 3717 | +static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC) |
c6a6bfc9 ER |
3718 | +{ |
3719 | + int callers_limit = 20; | |
3720 | + pid_t pid = child->pid; | |
3721 | + struct timeval tv; | |
3722 | + static const int buf_size = 1024; | |
3723 | + char buf[buf_size]; | |
3724 | + long execute_data; | |
3725 | + long l; | |
3726 | + | |
3727 | + gettimeofday(&tv, 0); | |
3728 | + | |
3729 | + zlog_print_time(&tv, buf, buf_size); | |
3730 | + | |
3731 | + fprintf(slowlog, "\n%s pid %d (pool %s)\n", buf, (int) pid, child->wp->config->name); | |
3732 | + | |
3733 | + if (0 > fpm_trace_get_strz(buf, buf_size, (long) &SG(request_info).path_translated)) { | |
3734 | + return -1; | |
3735 | + } | |
3736 | + | |
3737 | + fprintf(slowlog, "script_filename = %s\n", buf); | |
3738 | + | |
3739 | + if (0 > fpm_trace_get_long((long) &EG(current_execute_data), &l)) { | |
3740 | + return -1; | |
3741 | + } | |
3742 | + | |
3743 | + execute_data = l; | |
3744 | + | |
3745 | + while (execute_data) { | |
3746 | + long function; | |
3747 | + uint lineno = 0; | |
3748 | + | |
3749 | + fprintf(slowlog, "[0x%" PTR_FMT "lx] ", execute_data); | |
3750 | + | |
3751 | + if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, function_state.function), &l)) { | |
3752 | + return -1; | |
3753 | + } | |
3754 | + | |
3755 | + function = l; | |
3756 | + | |
3757 | + if (valid_ptr(function)) { | |
3758 | + if (0 > fpm_trace_get_strz(buf, buf_size, function + offsetof(zend_function, common.function_name))) { | |
3759 | + return -1; | |
3760 | + } | |
3761 | + | |
3762 | + fprintf(slowlog, "%s()", buf); | |
3763 | + } | |
3764 | + else { | |
3765 | + fprintf(slowlog, "???"); | |
3766 | + } | |
3767 | + | |
3768 | + if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, op_array), &l)) { | |
3769 | + return -1; | |
3770 | + } | |
3771 | + | |
3772 | + *buf = '\0'; | |
3773 | + | |
3774 | + if (valid_ptr(l)) { | |
3775 | + long op_array = l; | |
3776 | + | |
3777 | + if (0 > fpm_trace_get_strz(buf, buf_size, op_array + offsetof(zend_op_array, filename))) { | |
3778 | + return -1; | |
3779 | + } | |
3780 | + } | |
3781 | + | |
3782 | + if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, opline), &l)) { | |
3783 | + return -1; | |
3784 | + } | |
3785 | + | |
3786 | + if (valid_ptr(l)) { | |
3787 | + long opline = l; | |
3788 | + uint *lu = (uint *) &l; | |
3789 | + | |
3790 | + if (0 > fpm_trace_get_long(opline + offsetof(struct _zend_op, lineno), &l)) { | |
3791 | + return -1; | |
3792 | + } | |
3793 | + | |
3794 | + lineno = *lu; | |
3795 | + } | |
3796 | + | |
3797 | + fprintf(slowlog, " %s:%u\n", *buf ? buf : "unknown", lineno); | |
3798 | + | |
3799 | + if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, prev_execute_data), &l)) { | |
3800 | + return -1; | |
3801 | + } | |
3802 | + | |
3803 | + execute_data = l; | |
3804 | + | |
3805 | + if (0 == --callers_limit) { | |
3806 | + break; | |
3807 | + } | |
3808 | + } | |
3809 | + | |
3810 | + return 0; | |
3811 | +} | |
3812 | + | |
3813 | +void fpm_php_trace(struct fpm_child_s *child) | |
3814 | +{ | |
48b142c9 | 3815 | + TSRMLS_FETCH(); |
c6a6bfc9 ER |
3816 | + FILE *slowlog; |
3817 | + | |
3818 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "about to trace %d", (int) child->pid); | |
3819 | + | |
3820 | + slowlog = fopen(child->wp->config->slowlog, "a+"); | |
3821 | + | |
3822 | + if (!slowlog) { | |
3823 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fopen(%s) failed", child->wp->config->slowlog); | |
3824 | + goto done0; | |
3825 | + } | |
3826 | + | |
3827 | + if (0 > fpm_trace_ready(child->pid)) { | |
3828 | + goto done1; | |
3829 | + } | |
3830 | + | |
48b142c9 | 3831 | + if (0 > fpm_php_trace_dump(child, slowlog TSRMLS_CC)) { |
c6a6bfc9 ER |
3832 | + fprintf(slowlog, "+++ dump failed\n"); |
3833 | + } | |
3834 | + | |
3835 | + if (0 > fpm_trace_close(child->pid)) { | |
3836 | + goto done1; | |
3837 | + } | |
3838 | + | |
3839 | +done1: | |
3840 | + fclose(slowlog); | |
3841 | + | |
3842 | +done0: | |
3843 | + fpm_pctl_kill(child->pid, FPM_PCTL_CONT); | |
3844 | + child->tracer = 0; | |
3845 | + | |
3846 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "finished trace of %d", (int) child->pid); | |
3847 | +} | |
3848 | + | |
3849 | +#endif | |
3850 | + | |
37d32ffb ER |
3851 | diff --git a/sapi/cgi/fpm/fpm_php_trace.h b/sapi/cgi/fpm/fpm_php_trace.h |
3852 | new file mode 100644 | |
37d32ffb ER |
3853 | --- /dev/null |
3854 | +++ b/sapi/cgi/fpm/fpm_php_trace.h | |
c6a6bfc9 ER |
3855 | @@ -0,0 +1,13 @@ |
3856 | + | |
3857 | + /* $Id$ */ | |
3858 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
3859 | + | |
3860 | +#ifndef FPM_PHP_TRACE_H | |
3861 | +#define FPM_PHP_TRACE_H 1 | |
3862 | + | |
3863 | +struct fpm_child_s; | |
3864 | + | |
3865 | +void fpm_php_trace(struct fpm_child_s *); | |
3866 | + | |
3867 | +#endif | |
3868 | + | |
37d32ffb ER |
3869 | diff --git a/sapi/cgi/fpm/fpm_process_ctl.c b/sapi/cgi/fpm/fpm_process_ctl.c |
3870 | new file mode 100644 | |
37d32ffb ER |
3871 | --- /dev/null |
3872 | +++ b/sapi/cgi/fpm/fpm_process_ctl.c | |
48b142c9 | 3873 | @@ -0,0 +1,354 @@ |
c6a6bfc9 ER |
3874 | + |
3875 | + /* $Id$ */ | |
3876 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
fd1be940 ER |
3877 | + |
3878 | +#include "fpm_config.h" | |
3879 | + | |
3880 | +#include <sys/types.h> | |
3881 | +#include <signal.h> | |
3882 | +#include <unistd.h> | |
3883 | +#include <stdlib.h> | |
3884 | + | |
3885 | +#include "fpm.h" | |
c6a6bfc9 | 3886 | +#include "fpm_clock.h" |
fd1be940 ER |
3887 | +#include "fpm_children.h" |
3888 | +#include "fpm_signals.h" | |
3889 | +#include "fpm_events.h" | |
3890 | +#include "fpm_process_ctl.h" | |
3891 | +#include "fpm_cleanup.h" | |
c6a6bfc9 | 3892 | +#include "fpm_request.h" |
fd1be940 ER |
3893 | +#include "fpm_worker_pool.h" |
3894 | +#include "zlog.h" | |
3895 | + | |
3896 | + | |
3897 | +static int fpm_state = FPM_PCTL_STATE_NORMAL; | |
3898 | +static int fpm_signal_sent = 0; | |
3899 | + | |
3900 | + | |
3901 | +static const char *fpm_state_names[] = { | |
3902 | + [FPM_PCTL_STATE_NORMAL] = "normal", | |
3903 | + [FPM_PCTL_STATE_RELOADING] = "reloading", | |
3904 | + [FPM_PCTL_STATE_TERMINATING] = "terminating", | |
3905 | + [FPM_PCTL_STATE_FINISHING] = "finishing" | |
3906 | +}; | |
3907 | + | |
3908 | +static int saved_argc; | |
3909 | +static char **saved_argv; | |
fd1be940 ER |
3910 | + |
3911 | +static void fpm_pctl_cleanup(int which, void *arg) | |
3912 | +{ | |
3913 | + int i; | |
3914 | + | |
3915 | + if (which != FPM_CLEANUP_PARENT_EXEC) { | |
3916 | + | |
c6a6bfc9 | 3917 | + for (i = 0; i < saved_argc; i++) { |
fd1be940 ER |
3918 | + free(saved_argv[i]); |
3919 | + } | |
3920 | + | |
3921 | + free(saved_argv); | |
3922 | + | |
3923 | + } | |
3924 | +} | |
3925 | + | |
c6a6bfc9 ER |
3926 | +static struct event pctl_event; |
3927 | + | |
3928 | +static void fpm_pctl_action(int fd, short which, void *arg) | |
3929 | +{ | |
3930 | + evtimer_del(&pctl_event); | |
3931 | + | |
3932 | + memset(&pctl_event, 0, sizeof(pctl_event)); | |
3933 | + | |
3934 | + fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_TIMEOUT); | |
3935 | +} | |
3936 | + | |
3937 | +static int fpm_pctl_timeout_set(int sec) | |
3938 | +{ | |
3939 | + struct timeval tv = { .tv_sec = sec, .tv_usec = 0 }; | |
3940 | + | |
3941 | + if (evtimer_initialized(&pctl_event)) { | |
3942 | + evtimer_del(&pctl_event); | |
3943 | + } | |
3944 | + | |
3945 | + evtimer_set(&pctl_event, &fpm_pctl_action, 0); | |
3946 | + | |
3947 | + evtimer_add(&pctl_event, &tv); | |
3948 | + | |
3949 | + return 0; | |
3950 | +} | |
3951 | + | |
fd1be940 ER |
3952 | +static void fpm_pctl_exit() |
3953 | +{ | |
3954 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "exiting, bye-bye!"); | |
3955 | + | |
3956 | + fpm_conf_unlink_pid(); | |
3957 | + | |
3958 | + fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT_MAIN); | |
3959 | + | |
3960 | + exit(0); | |
3961 | +} | |
3962 | + | |
3963 | +#define optional_arg(c) (saved_argc > c ? ", \"" : ""), (saved_argc > c ? saved_argv[c] : ""), (saved_argc > c ? "\"" : "") | |
3964 | + | |
3965 | +static void fpm_pctl_exec() | |
3966 | +{ | |
3967 | + | |
3968 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "reloading: execvp(\"%s\", {\"%s\"" | |
3969 | + "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" | |
3970 | + "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" | |
3971 | + "})", | |
3972 | + saved_argv[0], saved_argv[0], | |
3973 | + optional_arg(1), | |
3974 | + optional_arg(2), | |
3975 | + optional_arg(3), | |
3976 | + optional_arg(4), | |
3977 | + optional_arg(5), | |
3978 | + optional_arg(6), | |
3979 | + optional_arg(7), | |
3980 | + optional_arg(8), | |
3981 | + optional_arg(9), | |
3982 | + optional_arg(10) | |
3983 | + ); | |
3984 | + | |
3985 | + fpm_cleanups_run(FPM_CLEANUP_PARENT_EXEC); | |
3986 | + | |
3987 | + execvp(saved_argv[0], saved_argv); | |
3988 | + | |
3989 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "execvp() failed"); | |
3990 | + | |
c6a6bfc9 | 3991 | + exit(1); |
fd1be940 ER |
3992 | +} |
3993 | + | |
3994 | +static void fpm_pctl_action_last() | |
3995 | +{ | |
3996 | + switch (fpm_state) { | |
3997 | + | |
3998 | + case FPM_PCTL_STATE_RELOADING : | |
3999 | + | |
4000 | + fpm_pctl_exec(); | |
4001 | + break; | |
4002 | + | |
4003 | + case FPM_PCTL_STATE_FINISHING : | |
4004 | + | |
4005 | + case FPM_PCTL_STATE_TERMINATING : | |
4006 | + | |
4007 | + fpm_pctl_exit(); | |
4008 | + break; | |
4009 | + } | |
4010 | +} | |
4011 | + | |
c6a6bfc9 ER |
4012 | +int fpm_pctl_kill(pid_t pid, int how) |
4013 | +{ | |
4014 | + int s = 0; | |
4015 | + | |
4016 | + switch (how) { | |
4017 | + case FPM_PCTL_TERM : | |
4018 | + s = SIGTERM; | |
4019 | + break; | |
4020 | + case FPM_PCTL_STOP : | |
4021 | + s = SIGSTOP; | |
4022 | + break; | |
4023 | + case FPM_PCTL_CONT : | |
4024 | + s = SIGCONT; | |
4025 | + break; | |
4026 | + default : | |
4027 | + break; | |
4028 | + } | |
4029 | + | |
4030 | + return kill(pid, s); | |
4031 | +} | |
4032 | + | |
fd1be940 ER |
4033 | +static void fpm_pctl_kill_all(int signo) |
4034 | +{ | |
4035 | + struct fpm_worker_pool_s *wp; | |
4036 | + int alive_children = 0; | |
4037 | + | |
4038 | + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { | |
4039 | + struct fpm_child_s *child; | |
4040 | + | |
4041 | + for (child = wp->children; child; child = child->next) { | |
4042 | + | |
4043 | + int res = kill(child->pid, signo); | |
4044 | + | |
4045 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "sending signal %d %s to child %d (pool %s)", signo, | |
4046 | + fpm_signal_names[signo] ? fpm_signal_names[signo] : "", | |
4047 | + (int) child->pid, child->wp->config->name); | |
4048 | + | |
4049 | + if (res == 0) ++alive_children; | |
4050 | + } | |
4051 | + } | |
4052 | + | |
4053 | + if (alive_children) { | |
4054 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "%d %s still alive", alive_children, alive_children == 1 ? "child is" : "children are"); | |
4055 | + } | |
4056 | +} | |
4057 | + | |
4058 | +static void fpm_pctl_action_next() | |
4059 | +{ | |
4060 | + int sig, timeout; | |
4061 | + | |
4062 | + if (!fpm_globals.running_children) fpm_pctl_action_last(); | |
4063 | + | |
4064 | + if (fpm_signal_sent == 0) { | |
4065 | + if (fpm_state == FPM_PCTL_STATE_TERMINATING) { | |
4066 | + sig = SIGTERM; | |
4067 | + } | |
4068 | + else { | |
4069 | + sig = SIGQUIT; | |
4070 | + } | |
48b142c9 | 4071 | + timeout = fpm_global_config.process_control_timeout; |
fd1be940 ER |
4072 | + } |
4073 | + else { | |
4074 | + if (fpm_signal_sent == SIGQUIT) { | |
4075 | + sig = SIGTERM; | |
4076 | + } | |
4077 | + else { | |
4078 | + sig = SIGKILL; | |
4079 | + } | |
4080 | + timeout = 1; | |
4081 | + } | |
4082 | + | |
4083 | + fpm_pctl_kill_all(sig); | |
4084 | + | |
4085 | + fpm_signal_sent = sig; | |
4086 | + | |
c6a6bfc9 | 4087 | + fpm_pctl_timeout_set(timeout); |
fd1be940 ER |
4088 | +} |
4089 | + | |
4090 | +void fpm_pctl(int new_state, int action) | |
4091 | +{ | |
4092 | + switch (action) { | |
4093 | + | |
4094 | + case FPM_PCTL_ACTION_SET : | |
4095 | + | |
4096 | + if (fpm_state == new_state) { /* already in progress - just ignore duplicate signal */ | |
4097 | + return; | |
4098 | + } | |
4099 | + | |
4100 | + switch (fpm_state) { /* check which states can be overridden */ | |
4101 | + | |
4102 | + case FPM_PCTL_STATE_NORMAL : | |
4103 | + | |
4104 | + /* 'normal' can be overridden by any other state */ | |
4105 | + break; | |
4106 | + | |
4107 | + case FPM_PCTL_STATE_RELOADING : | |
4108 | + | |
4109 | + /* 'reloading' can be overridden by 'finishing' */ | |
4110 | + if (new_state == FPM_PCTL_STATE_FINISHING) break; | |
4111 | + | |
4112 | + case FPM_PCTL_STATE_FINISHING : | |
4113 | + | |
4114 | + /* 'reloading' and 'finishing' can be overridden by 'terminating' */ | |
4115 | + if (new_state == FPM_PCTL_STATE_TERMINATING) break; | |
4116 | + | |
4117 | + case FPM_PCTL_STATE_TERMINATING : | |
4118 | + | |
4119 | + /* nothing can override 'terminating' state */ | |
4120 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "not switching to '%s' state, because already in '%s' state", | |
4121 | + fpm_state_names[new_state], fpm_state_names[fpm_state]); | |
4122 | + | |
4123 | + return; | |
4124 | + } | |
4125 | + | |
4126 | + fpm_signal_sent = 0; | |
4127 | + fpm_state = new_state; | |
4128 | + | |
4129 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "switching to '%s' state", fpm_state_names[fpm_state]); | |
4130 | + | |
4131 | + /* fall down */ | |
4132 | + | |
4133 | + case FPM_PCTL_ACTION_TIMEOUT : | |
4134 | + | |
4135 | + fpm_pctl_action_next(); | |
4136 | + | |
4137 | + break; | |
4138 | + | |
4139 | + case FPM_PCTL_ACTION_LAST_CHILD_EXITED : | |
4140 | + | |
4141 | + fpm_pctl_action_last(); | |
4142 | + | |
4143 | + break; | |
4144 | + | |
4145 | + } | |
4146 | +} | |
4147 | + | |
4148 | +int fpm_pctl_can_spawn_children() | |
4149 | +{ | |
4150 | + return fpm_state == FPM_PCTL_STATE_NORMAL; | |
4151 | +} | |
4152 | + | |
4153 | +int fpm_pctl_child_exited() | |
4154 | +{ | |
4155 | + if (fpm_state == FPM_PCTL_STATE_NORMAL) return 0; | |
4156 | + | |
4157 | + if (!fpm_globals.running_children) { | |
4158 | + fpm_pctl(FPM_PCTL_STATE_UNSPECIFIED, FPM_PCTL_ACTION_LAST_CHILD_EXITED); | |
4159 | + } | |
4160 | + | |
4161 | + return 0; | |
4162 | +} | |
4163 | + | |
c6a6bfc9 | 4164 | +int fpm_pctl_init_main() |
fd1be940 | 4165 | +{ |
c6a6bfc9 | 4166 | + int i; |
fd1be940 | 4167 | + |
c6a6bfc9 | 4168 | + saved_argc = fpm_globals.argc; |
fd1be940 | 4169 | + |
c6a6bfc9 | 4170 | + saved_argv = malloc(sizeof(char *) * (saved_argc + 1)); |
fd1be940 | 4171 | + |
c6a6bfc9 ER |
4172 | + if (!saved_argv) { |
4173 | + return -1; | |
4174 | + } | |
fd1be940 | 4175 | + |
c6a6bfc9 ER |
4176 | + for (i = 0; i < saved_argc; i++) { |
4177 | + saved_argv[i] = strdup(fpm_globals.argv[i]); | |
fd1be940 | 4178 | + |
c6a6bfc9 ER |
4179 | + if (!saved_argv[i]) { |
4180 | + return -1; | |
4181 | + } | |
fd1be940 ER |
4182 | + } |
4183 | + | |
c6a6bfc9 | 4184 | + saved_argv[i] = 0; |
fd1be940 | 4185 | + |
48b142c9 ER |
4186 | + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_pctl_cleanup, 0)) { |
4187 | + return -1; | |
4188 | + } | |
fd1be940 ER |
4189 | + |
4190 | + return 0; | |
4191 | +} | |
4192 | + | |
c6a6bfc9 ER |
4193 | +static void fpm_pctl_check_request_timeout(struct timeval *now) |
4194 | +{ | |
4195 | + struct fpm_worker_pool_s *wp; | |
4196 | + | |
4197 | + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { | |
4198 | + int terminate_timeout = wp->config->request_terminate_timeout; | |
4199 | + int slowlog_timeout = wp->config->request_slowlog_timeout; | |
4200 | + struct fpm_child_s *child; | |
4201 | + | |
4202 | + if (terminate_timeout || slowlog_timeout) { | |
4203 | + for (child = wp->children; child; child = child->next) { | |
4204 | + fpm_request_check_timed_out(child, now, terminate_timeout, slowlog_timeout); | |
4205 | + } | |
4206 | + } | |
4207 | + } | |
4208 | + | |
4209 | +} | |
4210 | + | |
4211 | +void fpm_pctl_heartbeat(int fd, short which, void *arg) | |
4212 | +{ | |
4213 | + static struct event heartbeat; | |
4214 | + struct timeval tv = { .tv_sec = 0, .tv_usec = 130000 }; | |
4215 | + struct timeval now; | |
4216 | + | |
4217 | + if (which == EV_TIMEOUT) { | |
4218 | + evtimer_del(&heartbeat); | |
4219 | + fpm_clock_get(&now); | |
4220 | + fpm_pctl_check_request_timeout(&now); | |
4221 | + } | |
4222 | + | |
4223 | + evtimer_set(&heartbeat, &fpm_pctl_heartbeat, 0); | |
4224 | + | |
4225 | + evtimer_add(&heartbeat, &tv); | |
4226 | +} | |
4227 | + | |
37d32ffb ER |
4228 | diff --git a/sapi/cgi/fpm/fpm_process_ctl.h b/sapi/cgi/fpm/fpm_process_ctl.h |
4229 | new file mode 100644 | |
37d32ffb ER |
4230 | --- /dev/null |
4231 | +++ b/sapi/cgi/fpm/fpm_process_ctl.h | |
c6a6bfc9 | 4232 | @@ -0,0 +1,39 @@ |
fd1be940 ER |
4233 | + |
4234 | + /* $Id$ */ | |
c6a6bfc9 | 4235 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
4236 | + |
4237 | +#ifndef FPM_PROCESS_CTL_H | |
4238 | +#define FPM_PROCESS_CTL_H 1 | |
4239 | + | |
c6a6bfc9 ER |
4240 | +struct fpm_child_s; |
4241 | + | |
fd1be940 ER |
4242 | +void fpm_pctl(int new_state, int action); |
4243 | +int fpm_pctl_can_spawn_children(); | |
c6a6bfc9 ER |
4244 | +int fpm_pctl_kill(pid_t pid, int how); |
4245 | +void fpm_pctl_heartbeat(int fd, short which, void *arg); | |
fd1be940 | 4246 | +int fpm_pctl_child_exited(); |
c6a6bfc9 | 4247 | +int fpm_pctl_init_main(); |
fd1be940 ER |
4248 | + |
4249 | + | |
4250 | +enum { | |
4251 | + FPM_PCTL_STATE_UNSPECIFIED, | |
4252 | + FPM_PCTL_STATE_NORMAL, | |
4253 | + FPM_PCTL_STATE_RELOADING, | |
4254 | + FPM_PCTL_STATE_TERMINATING, | |
4255 | + FPM_PCTL_STATE_FINISHING | |
4256 | +}; | |
4257 | + | |
4258 | +enum { | |
4259 | + FPM_PCTL_ACTION_SET, | |
4260 | + FPM_PCTL_ACTION_TIMEOUT, | |
4261 | + FPM_PCTL_ACTION_LAST_CHILD_EXITED | |
4262 | +}; | |
4263 | + | |
c6a6bfc9 ER |
4264 | +enum { |
4265 | + FPM_PCTL_TERM, | |
4266 | + FPM_PCTL_STOP, | |
4267 | + FPM_PCTL_CONT | |
4268 | +}; | |
fd1be940 ER |
4269 | + |
4270 | +#endif | |
4271 | + | |
37d32ffb ER |
4272 | diff --git a/sapi/cgi/fpm/fpm_request.c b/sapi/cgi/fpm/fpm_request.c |
4273 | new file mode 100644 | |
37d32ffb ER |
4274 | --- /dev/null |
4275 | +++ b/sapi/cgi/fpm/fpm_request.c | |
48b142c9 | 4276 | @@ -0,0 +1,164 @@ |
fd1be940 ER |
4277 | + |
4278 | + /* $Id$ */ | |
c6a6bfc9 ER |
4279 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
4280 | + | |
4281 | +#include "fpm_config.h" | |
4282 | + | |
4283 | +#include "fpm_php.h" | |
4284 | +#include "fpm_str.h" | |
4285 | +#include "fpm_clock.h" | |
4286 | +#include "fpm_conf.h" | |
4287 | +#include "fpm_trace.h" | |
4288 | +#include "fpm_php_trace.h" | |
4289 | +#include "fpm_process_ctl.h" | |
4290 | +#include "fpm_children.h" | |
4291 | +#include "fpm_shm_slots.h" | |
4292 | +#include "fpm_request.h" | |
fd1be940 | 4293 | + |
c6a6bfc9 ER |
4294 | +#include "zlog.h" |
4295 | + | |
4296 | +void fpm_request_accepting() | |
4297 | +{ | |
4298 | + struct fpm_shm_slot_s *slot; | |
4299 | + | |
4300 | + slot = fpm_shm_slots_acquire(0, 0); | |
4301 | + | |
4302 | + slot->request_stage = FPM_REQUEST_ACCEPTING; | |
4303 | + | |
4304 | + fpm_clock_get(&slot->tv); | |
4305 | + memset(slot->request_method, 0, sizeof(slot->request_method)); | |
4306 | + slot->content_length = 0; | |
4307 | + memset(slot->script_filename, 0, sizeof(slot->script_filename)); | |
4308 | + | |
4309 | + fpm_shm_slots_release(slot); | |
4310 | +} | |
4311 | + | |
4312 | +void fpm_request_reading_headers() | |
4313 | +{ | |
4314 | + struct fpm_shm_slot_s *slot; | |
4315 | + | |
4316 | + slot = fpm_shm_slots_acquire(0, 0); | |
4317 | + | |
4318 | + slot->request_stage = FPM_REQUEST_READING_HEADERS; | |
4319 | + | |
4320 | + fpm_clock_get(&slot->tv); | |
4321 | + slot->accepted = slot->tv; | |
4322 | + | |
4323 | + fpm_shm_slots_release(slot); | |
4324 | +} | |
4325 | + | |
4326 | +void fpm_request_info() | |
4327 | +{ | |
48b142c9 | 4328 | + TSRMLS_FETCH(); |
c6a6bfc9 | 4329 | + struct fpm_shm_slot_s *slot; |
48b142c9 ER |
4330 | + char *request_method = fpm_php_request_method(TSRMLS_C); |
4331 | + char *script_filename = fpm_php_script_filename(TSRMLS_C); | |
c6a6bfc9 ER |
4332 | + |
4333 | + slot = fpm_shm_slots_acquire(0, 0); | |
4334 | + | |
4335 | + slot->request_stage = FPM_REQUEST_INFO; | |
4336 | + | |
4337 | + fpm_clock_get(&slot->tv); | |
4338 | + | |
4339 | + if (request_method) { | |
4340 | + cpystrn(slot->request_method, request_method, sizeof(slot->request_method)); | |
4341 | + } | |
4342 | + | |
48b142c9 | 4343 | + slot->content_length = fpm_php_content_length(TSRMLS_C); |
c6a6bfc9 ER |
4344 | + |
4345 | + /* if cgi.fix_pathinfo is set to "1" and script cannot be found (404) | |
4346 | + the sapi_globals.request_info.path_translated is set to NULL */ | |
4347 | + if (script_filename) { | |
4348 | + cpystrn(slot->script_filename, script_filename, sizeof(slot->script_filename)); | |
4349 | + } | |
4350 | + | |
4351 | + fpm_shm_slots_release(slot); | |
4352 | +} | |
4353 | + | |
4354 | +void fpm_request_executing() | |
4355 | +{ | |
4356 | + struct fpm_shm_slot_s *slot; | |
4357 | + | |
4358 | + slot = fpm_shm_slots_acquire(0, 0); | |
4359 | + | |
4360 | + slot->request_stage = FPM_REQUEST_EXECUTING; | |
4361 | + | |
4362 | + fpm_clock_get(&slot->tv); | |
4363 | + | |
4364 | + fpm_shm_slots_release(slot); | |
4365 | +} | |
4366 | + | |
4367 | +void fpm_request_finished() | |
4368 | +{ | |
4369 | + struct fpm_shm_slot_s *slot; | |
4370 | + | |
4371 | + slot = fpm_shm_slots_acquire(0, 0); | |
4372 | + | |
4373 | + slot->request_stage = FPM_REQUEST_FINISHED; | |
4374 | + | |
4375 | + fpm_clock_get(&slot->tv); | |
4376 | + memset(&slot->accepted, 0, sizeof(slot->accepted)); | |
4377 | + | |
4378 | + fpm_shm_slots_release(slot); | |
4379 | +} | |
4380 | + | |
4381 | +void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *now, int terminate_timeout, int slowlog_timeout) | |
4382 | +{ | |
4383 | + struct fpm_shm_slot_s *slot; | |
4384 | + struct fpm_shm_slot_s slot_c; | |
4385 | + | |
4386 | + slot = fpm_shm_slot(child); | |
4387 | + | |
4388 | + if (!fpm_shm_slots_acquire(slot, 1)) { | |
4389 | + return; | |
4390 | + } | |
4391 | + | |
4392 | + slot_c = *slot; | |
4393 | + | |
4394 | + fpm_shm_slots_release(slot); | |
4395 | + | |
4396 | +#if HAVE_FPM_TRACE | |
4397 | + if (child->slow_logged.tv_sec) { | |
4398 | + if (child->slow_logged.tv_sec != slot_c.accepted.tv_sec || child->slow_logged.tv_usec != slot_c.accepted.tv_usec) { | |
4399 | + child->slow_logged.tv_sec = 0; | |
4400 | + child->slow_logged.tv_usec = 0; | |
4401 | + } | |
4402 | + } | |
4403 | +#endif | |
4404 | + | |
4405 | + if (slot_c.request_stage > FPM_REQUEST_ACCEPTING && slot_c.request_stage < FPM_REQUEST_FINISHED) { | |
4406 | + char purified_script_filename[sizeof(slot_c.script_filename)]; | |
4407 | + struct timeval tv; | |
4408 | + | |
4409 | + timersub(now, &slot_c.accepted, &tv); | |
4410 | + | |
4411 | +#if HAVE_FPM_TRACE | |
4412 | + if (child->slow_logged.tv_sec == 0 && slowlog_timeout && | |
4413 | + slot_c.request_stage == FPM_REQUEST_EXECUTING && tv.tv_sec >= slowlog_timeout) { | |
4414 | + | |
4415 | + str_purify_filename(purified_script_filename, slot_c.script_filename, sizeof(slot_c.script_filename)); | |
4416 | + | |
4417 | + child->slow_logged = slot_c.accepted; | |
4418 | + child->tracer = fpm_php_trace; | |
4419 | + | |
4420 | + fpm_trace_signal(child->pid); | |
4421 | + | |
4422 | + zlog(ZLOG_STUFF, ZLOG_WARNING, "child %d, script '%s' (pool %s) executing too slow (%d.%06d sec), logging", | |
4423 | + (int) child->pid, purified_script_filename, child->wp->config->name, (int) tv.tv_sec, (int) tv.tv_usec); | |
4424 | + } | |
4425 | + | |
4426 | + else | |
4427 | +#endif | |
4428 | + if (terminate_timeout && tv.tv_sec >= terminate_timeout) { | |
4429 | + | |
4430 | + str_purify_filename(purified_script_filename, slot_c.script_filename, sizeof(slot_c.script_filename)); | |
4431 | + | |
4432 | + fpm_pctl_kill(child->pid, FPM_PCTL_TERM); | |
4433 | + | |
4434 | + zlog(ZLOG_STUFF, ZLOG_WARNING, "child %d, script '%s' (pool %s) execution timed out (%d.%06d sec), terminating", | |
4435 | + (int) child->pid, purified_script_filename, child->wp->config->name, (int) tv.tv_sec, (int) tv.tv_usec); | |
4436 | + } | |
4437 | + } | |
4438 | + | |
4439 | +} | |
4440 | + | |
37d32ffb ER |
4441 | diff --git a/sapi/cgi/fpm/fpm_request.h b/sapi/cgi/fpm/fpm_request.h |
4442 | new file mode 100644 | |
37d32ffb ER |
4443 | --- /dev/null |
4444 | +++ b/sapi/cgi/fpm/fpm_request.h | |
c6a6bfc9 | 4445 | @@ -0,0 +1,27 @@ |
fd1be940 ER |
4446 | + |
4447 | + /* $Id$ */ | |
c6a6bfc9 ER |
4448 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
4449 | + | |
4450 | +#ifndef FPM_REQUEST_H | |
4451 | +#define FPM_REQUEST_H 1 | |
4452 | + | |
4453 | +void fpm_request_accepting(); /* hanging in accept() */ | |
4454 | +void fpm_request_reading_headers(); /* start reading fastcgi request from very first byte */ | |
4455 | +void fpm_request_info(); /* not a stage really but a point in the php code, where all request params have become known to sapi */ | |
4456 | +void fpm_request_executing(); /* the script is executing */ | |
4457 | +void fpm_request_finished(); /* request processed: script response have been sent to web server */ | |
4458 | + | |
4459 | +struct fpm_child_s; | |
4460 | +struct timeval; | |
4461 | + | |
4462 | +void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *tv, int terminate_timeout, int slowlog_timeout); | |
4463 | + | |
4464 | +enum fpm_request_stage_e { | |
4465 | + FPM_REQUEST_ACCEPTING = 1, | |
4466 | + FPM_REQUEST_READING_HEADERS, | |
4467 | + FPM_REQUEST_INFO, | |
4468 | + FPM_REQUEST_EXECUTING, | |
4469 | + FPM_REQUEST_FINISHED | |
4470 | +}; | |
4471 | + | |
4472 | +#endif | |
37d32ffb ER |
4473 | diff --git a/sapi/cgi/fpm/fpm_shm.c b/sapi/cgi/fpm/fpm_shm.c |
4474 | new file mode 100644 | |
37d32ffb ER |
4475 | --- /dev/null |
4476 | +++ b/sapi/cgi/fpm/fpm_shm.c | |
c6a6bfc9 ER |
4477 | @@ -0,0 +1,100 @@ |
4478 | + | |
4479 | + /* $Id$ */ | |
4480 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
4481 | + | |
4482 | +#include "fpm_config.h" | |
4483 | + | |
4484 | +#include <unistd.h> | |
4485 | +#include <sys/mman.h> | |
4486 | +#include <stdlib.h> | |
4487 | + | |
4488 | +#include "fpm_shm.h" | |
4489 | +#include "zlog.h" | |
4490 | + | |
4491 | + | |
4492 | +/* MAP_ANON is depricated, but not in macosx */ | |
4493 | +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) | |
4494 | +#define MAP_ANONYMOUS MAP_ANON | |
4495 | +#endif | |
4496 | + | |
4497 | + | |
4498 | +struct fpm_shm_s *fpm_shm_alloc(size_t sz) | |
4499 | +{ | |
4500 | + struct fpm_shm_s *shm; | |
4501 | + | |
4502 | + shm = malloc(sizeof(*shm)); | |
4503 | + | |
4504 | + if (!shm) { | |
4505 | + return 0; | |
4506 | + } | |
4507 | + | |
4508 | + shm->mem = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); | |
4509 | + | |
4510 | + if (!shm->mem) { | |
4511 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "mmap(MAP_ANONYMOUS | MAP_SHARED) failed"); | |
4512 | + free(shm); | |
4513 | + return 0; | |
4514 | + } | |
4515 | + | |
4516 | + shm->used = 0; | |
4517 | + shm->sz = sz; | |
4518 | + | |
4519 | + return shm; | |
4520 | +} | |
4521 | + | |
4522 | +static void fpm_shm_free(struct fpm_shm_s *shm, int do_unmap) | |
4523 | +{ | |
4524 | + if (do_unmap) { | |
4525 | + munmap(shm->mem, shm->sz); | |
4526 | + } | |
4527 | + | |
4528 | + free(shm); | |
4529 | +} | |
4530 | + | |
4531 | +void fpm_shm_free_list(struct fpm_shm_s *shm, void *mem) | |
4532 | +{ | |
4533 | + struct fpm_shm_s *next; | |
4534 | + | |
4535 | + for (; shm; shm = next) { | |
4536 | + next = shm->next; | |
4537 | + | |
4538 | + fpm_shm_free(shm, mem != shm->mem); | |
4539 | + } | |
4540 | +} | |
4541 | + | |
4542 | +void *fpm_shm_alloc_chunk(struct fpm_shm_s **head, size_t sz, void **mem) | |
4543 | +{ | |
4544 | + size_t pagesize = getpagesize(); | |
4545 | + static const size_t cache_line_size = 16; | |
4546 | + size_t aligned_sz; | |
4547 | + struct fpm_shm_s *shm; | |
4548 | + void *ret; | |
4549 | + | |
4550 | + sz = (sz + cache_line_size - 1) & -cache_line_size; | |
4551 | + | |
4552 | + shm = *head; | |
4553 | + | |
4554 | + if (0 == shm || shm->sz - shm->used < sz) { | |
4555 | + /* allocate one more shm segment */ | |
4556 | + | |
4557 | + aligned_sz = (sz + pagesize - 1) & -pagesize; | |
4558 | + | |
4559 | + shm = fpm_shm_alloc(aligned_sz); | |
4560 | + | |
4561 | + if (!shm) { | |
4562 | + return 0; | |
4563 | + } | |
4564 | + | |
4565 | + shm->next = *head; | |
4566 | + if (shm->next) shm->next->prev = shm; | |
4567 | + shm->prev = 0; | |
4568 | + *head = shm; | |
4569 | + } | |
4570 | + | |
4571 | + *mem = shm->mem; | |
4572 | + ret = (char *) shm->mem + shm->used; | |
4573 | + shm->used += sz; | |
4574 | + | |
4575 | + return ret; | |
4576 | +} | |
4577 | + | |
37d32ffb ER |
4578 | diff --git a/sapi/cgi/fpm/fpm_shm.h b/sapi/cgi/fpm/fpm_shm.h |
4579 | new file mode 100644 | |
37d32ffb ER |
4580 | --- /dev/null |
4581 | +++ b/sapi/cgi/fpm/fpm_shm.h | |
c6a6bfc9 ER |
4582 | @@ -0,0 +1,22 @@ |
4583 | + | |
4584 | + /* $Id$ */ | |
4585 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
fd1be940 ER |
4586 | + |
4587 | +#ifndef FPM_SHM_H | |
4588 | +#define FPM_SHM_H 1 | |
4589 | + | |
c6a6bfc9 | 4590 | +struct fpm_shm_s; |
fd1be940 | 4591 | + |
c6a6bfc9 ER |
4592 | +struct fpm_shm_s { |
4593 | + struct fpm_shm_s *prev, *next; | |
4594 | + void *mem; | |
4595 | + size_t sz; | |
4596 | + size_t used; | |
4597 | +}; | |
4598 | + | |
4599 | +struct fpm_shm_s *fpm_shm_alloc(size_t sz); | |
4600 | +void fpm_shm_free_list(struct fpm_shm_s *, void *); | |
4601 | +void *fpm_shm_alloc_chunk(struct fpm_shm_s **head, size_t sz, void **mem); | |
fd1be940 ER |
4602 | + |
4603 | +#endif | |
4604 | + | |
37d32ffb ER |
4605 | diff --git a/sapi/cgi/fpm/fpm_shm_slots.c b/sapi/cgi/fpm/fpm_shm_slots.c |
4606 | new file mode 100644 | |
37d32ffb ER |
4607 | --- /dev/null |
4608 | +++ b/sapi/cgi/fpm/fpm_shm_slots.c | |
c6a6bfc9 ER |
4609 | @@ -0,0 +1,127 @@ |
4610 | + | |
4611 | + /* $Id$ */ | |
4612 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
4613 | + | |
4614 | +#include "fpm_config.h" | |
4615 | + | |
4616 | +#include "fpm_atomic.h" | |
4617 | +#include "fpm_worker_pool.h" | |
4618 | +#include "fpm_children.h" | |
4619 | +#include "fpm_shm.h" | |
4620 | +#include "fpm_shm_slots.h" | |
4621 | +#include "zlog.h" | |
4622 | + | |
4623 | +static void *shm_mem; | |
4624 | +static struct fpm_shm_slot_s *shm_slot; | |
4625 | + | |
4626 | +int fpm_shm_slots_prepare_slot(struct fpm_child_s *child) | |
4627 | +{ | |
4628 | + struct fpm_worker_pool_s *wp = child->wp; | |
4629 | + struct fpm_shm_slot_ptr_s *shm_slot_ptr; | |
4630 | + | |
4631 | + child->shm_slot_i = wp->slots_used.used; | |
4632 | + | |
4633 | + shm_slot_ptr = fpm_array_push(&wp->slots_used); | |
4634 | + | |
4635 | + if (0 == shm_slot_ptr) { | |
4636 | + return -1; | |
4637 | + } | |
4638 | + | |
4639 | + if (0 == wp->slots_free.used) { | |
4640 | + shm_slot_ptr->shm_slot = fpm_shm_alloc_chunk(&wp->shm_list, sizeof(struct fpm_shm_slot_s), &shm_slot_ptr->mem); | |
4641 | + | |
4642 | + if (!shm_slot_ptr->shm_slot) { | |
4643 | + return -1; | |
4644 | + } | |
4645 | + } | |
4646 | + else { | |
4647 | + *shm_slot_ptr = *(struct fpm_shm_slot_ptr_s *) fpm_array_item_last(&wp->slots_free); | |
4648 | + | |
4649 | + --wp->slots_free.used; | |
4650 | + } | |
4651 | + | |
4652 | + memset(shm_slot_ptr->shm_slot, 0, sizeof(struct fpm_shm_slot_s)); | |
4653 | + | |
4654 | + shm_slot_ptr->child = child; | |
4655 | + | |
4656 | + return 0; | |
4657 | +} | |
4658 | + | |
4659 | +void fpm_shm_slots_discard_slot(struct fpm_child_s *child) | |
4660 | +{ | |
4661 | + struct fpm_shm_slot_ptr_s *shm_slot_ptr; | |
4662 | + struct fpm_worker_pool_s *wp = child->wp; | |
4663 | + int n; | |
4664 | + | |
4665 | + shm_slot_ptr = fpm_array_push(&wp->slots_free); | |
4666 | + | |
4667 | + if (shm_slot_ptr) { | |
4668 | + | |
4669 | + struct fpm_shm_slot_ptr_s *shm_slot_ptr_used; | |
4670 | + | |
4671 | + shm_slot_ptr_used = fpm_array_item(&wp->slots_used, child->shm_slot_i); | |
4672 | + | |
4673 | + *shm_slot_ptr = *shm_slot_ptr_used; | |
4674 | + | |
4675 | + shm_slot_ptr->child = 0; | |
4676 | + | |
4677 | + } | |
4678 | + | |
4679 | + n = fpm_array_item_remove(&wp->slots_used, child->shm_slot_i); | |
4680 | + | |
4681 | + if (n > -1) { | |
4682 | + shm_slot_ptr = fpm_array_item(&wp->slots_used, n); | |
4683 | + | |
4684 | + shm_slot_ptr->child->shm_slot_i = n; | |
4685 | + } | |
4686 | +} | |
4687 | + | |
4688 | +void fpm_shm_slots_child_use_slot(struct fpm_child_s *child) | |
4689 | +{ | |
4690 | + struct fpm_shm_slot_ptr_s *shm_slot_ptr; | |
4691 | + struct fpm_worker_pool_s *wp = child->wp; | |
4692 | + | |
4693 | + shm_slot_ptr = fpm_array_item(&wp->slots_used, child->shm_slot_i); | |
4694 | + | |
4695 | + shm_slot = shm_slot_ptr->shm_slot; | |
4696 | + shm_mem = shm_slot_ptr->mem; | |
4697 | +} | |
4698 | + | |
4699 | +void fpm_shm_slots_parent_use_slot(struct fpm_child_s *child) | |
4700 | +{ | |
4701 | + /* nothing to do */ | |
4702 | +} | |
4703 | + | |
4704 | +void *fpm_shm_slots_mem() | |
4705 | +{ | |
4706 | + return shm_mem; | |
4707 | +} | |
4708 | + | |
4709 | +struct fpm_shm_slot_s *fpm_shm_slot(struct fpm_child_s *child) | |
4710 | +{ | |
4711 | + struct fpm_shm_slot_ptr_s *shm_slot_ptr; | |
4712 | + struct fpm_worker_pool_s *wp = child->wp; | |
4713 | + | |
4714 | + shm_slot_ptr = fpm_array_item(&wp->slots_used, child->shm_slot_i); | |
4715 | + | |
4716 | + return shm_slot_ptr->shm_slot; | |
4717 | +} | |
4718 | + | |
4719 | +struct fpm_shm_slot_s *fpm_shm_slots_acquire(struct fpm_shm_slot_s *s, int nohang) | |
4720 | +{ | |
4721 | + if (s == 0) { | |
4722 | + s = shm_slot; | |
4723 | + } | |
4724 | + | |
4725 | + if (0 > fpm_spinlock(&s->lock, nohang)) { | |
4726 | + return 0; | |
4727 | + } | |
4728 | + | |
4729 | + return s; | |
4730 | +} | |
4731 | + | |
4732 | +void fpm_shm_slots_release(struct fpm_shm_slot_s *s) | |
4733 | +{ | |
4734 | + s->lock = 0; | |
4735 | +} | |
4736 | + | |
37d32ffb ER |
4737 | diff --git a/sapi/cgi/fpm/fpm_shm_slots.h b/sapi/cgi/fpm/fpm_shm_slots.h |
4738 | new file mode 100644 | |
37d32ffb ER |
4739 | --- /dev/null |
4740 | +++ b/sapi/cgi/fpm/fpm_shm_slots.h | |
c6a6bfc9 | 4741 | @@ -0,0 +1,43 @@ |
fd1be940 ER |
4742 | + |
4743 | + /* $Id$ */ | |
c6a6bfc9 ER |
4744 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
4745 | + | |
4746 | +#ifndef FPM_SHM_SLOTS_H | |
4747 | +#define FPM_SHM_SLOTS_H 1 | |
4748 | + | |
4749 | +#include "fpm_atomic.h" | |
4750 | +#include "fpm_worker_pool.h" | |
4751 | +#include "fpm_request.h" | |
4752 | + | |
4753 | +struct fpm_child_s; | |
4754 | + | |
4755 | +struct fpm_shm_slot_s { | |
4756 | + union { | |
4757 | + atomic_t lock; | |
4758 | + char dummy[16]; | |
4759 | + }; | |
4760 | + enum fpm_request_stage_e request_stage; | |
4761 | + struct timeval accepted; | |
4762 | + struct timeval tv; | |
4763 | + char request_method[16]; | |
4764 | + size_t content_length; /* used with POST only */ | |
4765 | + char script_filename[256]; | |
4766 | +}; | |
4767 | + | |
4768 | +struct fpm_shm_slot_ptr_s { | |
4769 | + void *mem; | |
4770 | + struct fpm_shm_slot_s *shm_slot; | |
4771 | + struct fpm_child_s *child; | |
4772 | +}; | |
4773 | + | |
4774 | +int fpm_shm_slots_prepare_slot(struct fpm_child_s *child); | |
4775 | +void fpm_shm_slots_discard_slot(struct fpm_child_s *child); | |
4776 | +void fpm_shm_slots_child_use_slot(struct fpm_child_s *child); | |
4777 | +void fpm_shm_slots_parent_use_slot(struct fpm_child_s *child); | |
4778 | +void *fpm_shm_slots_mem(); | |
4779 | +struct fpm_shm_slot_s *fpm_shm_slot(struct fpm_child_s *child); | |
4780 | +struct fpm_shm_slot_s *fpm_shm_slots_acquire(struct fpm_shm_slot_s *, int nohang); | |
4781 | +void fpm_shm_slots_release(struct fpm_shm_slot_s *); | |
4782 | + | |
4783 | +#endif | |
4784 | + | |
37d32ffb ER |
4785 | diff --git a/sapi/cgi/fpm/fpm_signals.c b/sapi/cgi/fpm/fpm_signals.c |
4786 | new file mode 100644 | |
37d32ffb ER |
4787 | --- /dev/null |
4788 | +++ b/sapi/cgi/fpm/fpm_signals.c | |
c6a6bfc9 ER |
4789 | @@ -0,0 +1,252 @@ |
4790 | + | |
4791 | + /* $Id$ */ | |
4792 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
fd1be940 ER |
4793 | + |
4794 | +#include "fpm_config.h" | |
4795 | + | |
4796 | +#include <signal.h> | |
4797 | +#include <stdio.h> | |
4798 | +#include <sys/types.h> | |
4799 | +#include <sys/socket.h> | |
4800 | +#include <stdlib.h> | |
4801 | +#include <string.h> | |
4802 | +#include <fcntl.h> | |
4803 | +#include <unistd.h> | |
4804 | +#include <errno.h> | |
4805 | + | |
c6a6bfc9 | 4806 | +#include "fpm.h" |
fd1be940 ER |
4807 | +#include "fpm_signals.h" |
4808 | +#include "fpm_sockets.h" | |
c6a6bfc9 | 4809 | +#include "fpm_php.h" |
fd1be940 ER |
4810 | +#include "zlog.h" |
4811 | + | |
4812 | +static int sp[2]; | |
4813 | + | |
fd1be940 ER |
4814 | +const char *fpm_signal_names[NSIG + 1] = { |
4815 | +#ifdef SIGHUP | |
4816 | + [SIGHUP] = "SIGHUP", | |
4817 | +#endif | |
4818 | +#ifdef SIGINT | |
4819 | + [SIGINT] = "SIGINT", | |
4820 | +#endif | |
4821 | +#ifdef SIGQUIT | |
4822 | + [SIGQUIT] = "SIGQUIT", | |
4823 | +#endif | |
4824 | +#ifdef SIGILL | |
4825 | + [SIGILL] = "SIGILL", | |
4826 | +#endif | |
4827 | +#ifdef SIGTRAP | |
4828 | + [SIGTRAP] = "SIGTRAP", | |
4829 | +#endif | |
4830 | +#ifdef SIGABRT | |
4831 | + [SIGABRT] = "SIGABRT", | |
4832 | +#endif | |
4833 | +#ifdef SIGEMT | |
4834 | + [SIGEMT] = "SIGEMT", | |
4835 | +#endif | |
4836 | +#ifdef SIGBUS | |
4837 | + [SIGBUS] = "SIGBUS", | |
4838 | +#endif | |
4839 | +#ifdef SIGFPE | |
4840 | + [SIGFPE] = "SIGFPE", | |
4841 | +#endif | |
4842 | +#ifdef SIGKILL | |
4843 | + [SIGKILL] = "SIGKILL", | |
4844 | +#endif | |
4845 | +#ifdef SIGUSR1 | |
4846 | + [SIGUSR1] = "SIGUSR1", | |
4847 | +#endif | |
4848 | +#ifdef SIGSEGV | |
4849 | + [SIGSEGV] = "SIGSEGV", | |
4850 | +#endif | |
4851 | +#ifdef SIGUSR2 | |
4852 | + [SIGUSR2] = "SIGUSR2", | |
4853 | +#endif | |
4854 | +#ifdef SIGPIPE | |
4855 | + [SIGPIPE] = "SIGPIPE", | |
4856 | +#endif | |
4857 | +#ifdef SIGALRM | |
4858 | + [SIGALRM] = "SIGALRM", | |
4859 | +#endif | |
4860 | +#ifdef SIGTERM | |
4861 | + [SIGTERM] = "SIGTERM", | |
4862 | +#endif | |
4863 | +#ifdef SIGCHLD | |
4864 | + [SIGCHLD] = "SIGCHLD", | |
4865 | +#endif | |
4866 | +#ifdef SIGCONT | |
4867 | + [SIGCONT] = "SIGCONT", | |
4868 | +#endif | |
4869 | +#ifdef SIGSTOP | |
4870 | + [SIGSTOP] = "SIGSTOP", | |
4871 | +#endif | |
4872 | +#ifdef SIGTSTP | |
4873 | + [SIGTSTP] = "SIGTSTP", | |
4874 | +#endif | |
4875 | +#ifdef SIGTTIN | |
4876 | + [SIGTTIN] = "SIGTTIN", | |
4877 | +#endif | |
4878 | +#ifdef SIGTTOU | |
4879 | + [SIGTTOU] = "SIGTTOU", | |
4880 | +#endif | |
4881 | +#ifdef SIGURG | |
4882 | + [SIGURG] = "SIGURG", | |
4883 | +#endif | |
4884 | +#ifdef SIGXCPU | |
4885 | + [SIGXCPU] = "SIGXCPU", | |
4886 | +#endif | |
4887 | +#ifdef SIGXFSZ | |
4888 | + [SIGXFSZ] = "SIGXFSZ", | |
4889 | +#endif | |
4890 | +#ifdef SIGVTALRM | |
4891 | + [SIGVTALRM] = "SIGVTALRM", | |
4892 | +#endif | |
4893 | +#ifdef SIGPROF | |
4894 | + [SIGPROF] = "SIGPROF", | |
4895 | +#endif | |
4896 | +#ifdef SIGWINCH | |
4897 | + [SIGWINCH] = "SIGWINCH", | |
4898 | +#endif | |
4899 | +#ifdef SIGINFO | |
4900 | + [SIGINFO] = "SIGINFO", | |
4901 | +#endif | |
4902 | +#ifdef SIGIO | |
4903 | + [SIGIO] = "SIGIO", | |
4904 | +#endif | |
4905 | +#ifdef SIGPWR | |
4906 | + [SIGPWR] = "SIGPWR", | |
4907 | +#endif | |
4908 | +#ifdef SIGSYS | |
4909 | + [SIGSYS] = "SIGSYS", | |
4910 | +#endif | |
4911 | +#ifdef SIGWAITING | |
4912 | + [SIGWAITING] = "SIGWAITING", | |
4913 | +#endif | |
4914 | +#ifdef SIGLWP | |
4915 | + [SIGLWP] = "SIGLWP", | |
4916 | +#endif | |
4917 | +#ifdef SIGFREEZE | |
4918 | + [SIGFREEZE] = "SIGFREEZE", | |
4919 | +#endif | |
4920 | +#ifdef SIGTHAW | |
4921 | + [SIGTHAW] = "SIGTHAW", | |
4922 | +#endif | |
4923 | +#ifdef SIGCANCEL | |
4924 | + [SIGCANCEL] = "SIGCANCEL", | |
4925 | +#endif | |
4926 | +#ifdef SIGLOST | |
4927 | + [SIGLOST] = "SIGLOST", | |
4928 | +#endif | |
4929 | +}; | |
4930 | + | |
4931 | +static void sig_soft_quit(int signo) | |
4932 | +{ | |
c6a6bfc9 ER |
4933 | + int saved_errno = errno; |
4934 | + | |
fd1be940 ER |
4935 | + /* closing fastcgi listening socket will force fcgi_accept() exit immediately */ |
4936 | + close(0); | |
4937 | + socket(AF_UNIX, SOCK_STREAM, 0); | |
c6a6bfc9 ER |
4938 | + |
4939 | + fpm_php_soft_quit(); | |
4940 | + | |
4941 | + errno = saved_errno; | |
fd1be940 ER |
4942 | +} |
4943 | + | |
4944 | +static void sig_handler(int signo) | |
4945 | +{ | |
c6a6bfc9 | 4946 | + static const char sig_chars[NSIG + 1] = { |
fd1be940 ER |
4947 | + [SIGTERM] = 'T', |
4948 | + [SIGINT] = 'I', | |
c6a6bfc9 | 4949 | + [SIGUSR1] = '1', |
fd1be940 ER |
4950 | + [SIGUSR2] = '2', |
4951 | + [SIGQUIT] = 'Q', | |
4952 | + [SIGCHLD] = 'C' | |
4953 | + }; | |
c6a6bfc9 ER |
4954 | + char s; |
4955 | + int saved_errno; | |
fd1be940 | 4956 | + |
c6a6bfc9 ER |
4957 | + if (fpm_globals.parent_pid != getpid()) { |
4958 | + /* prevent a signal race condition when child process | |
4959 | + have not set up it's own signal handler yet */ | |
4960 | + return; | |
fd1be940 ER |
4961 | + } |
4962 | + | |
c6a6bfc9 ER |
4963 | + saved_errno = errno; |
4964 | + | |
4965 | + s = sig_chars[signo]; | |
4966 | + | |
4967 | + write(sp[1], &s, sizeof(s)); | |
4968 | + | |
fd1be940 ER |
4969 | + errno = saved_errno; |
4970 | +} | |
4971 | + | |
4972 | +int fpm_signals_init_main() | |
4973 | +{ | |
4974 | + struct sigaction act; | |
4975 | + | |
4976 | + if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) { | |
4977 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "socketpair() failed"); | |
4978 | + return -1; | |
4979 | + } | |
4980 | + | |
4981 | + if (0 > fd_set_blocked(sp[0], 0) || 0 > fd_set_blocked(sp[1], 0)) { | |
4982 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fd_set_blocked() failed"); | |
4983 | + return -1; | |
4984 | + } | |
4985 | + | |
4986 | + if (0 > fcntl(sp[0], F_SETFD, FD_CLOEXEC) || 0 > fcntl(sp[1], F_SETFD, FD_CLOEXEC)) { | |
4987 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fcntl(F_SETFD, FD_CLOEXEC) failed"); | |
4988 | + return -1; | |
4989 | + } | |
4990 | + | |
4991 | + memset(&act, 0, sizeof(act)); | |
c6a6bfc9 | 4992 | + act.sa_handler = sig_handler; |
fd1be940 ER |
4993 | + sigfillset(&act.sa_mask); |
4994 | + | |
4995 | + if (0 > sigaction(SIGTERM, &act, 0) || | |
4996 | + 0 > sigaction(SIGINT, &act, 0) || | |
c6a6bfc9 | 4997 | + 0 > sigaction(SIGUSR1, &act, 0) || |
fd1be940 ER |
4998 | + 0 > sigaction(SIGUSR2, &act, 0) || |
4999 | + 0 > sigaction(SIGCHLD, &act, 0) || | |
5000 | + 0 > sigaction(SIGQUIT, &act, 0)) { | |
5001 | + | |
5002 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "sigaction() failed"); | |
5003 | + return -1; | |
5004 | + } | |
5005 | + | |
5006 | + return 0; | |
5007 | +} | |
5008 | + | |
5009 | +int fpm_signals_init_child() | |
5010 | +{ | |
5011 | + struct sigaction act, act_dfl; | |
5012 | + | |
5013 | + memset(&act, 0, sizeof(act)); | |
5014 | + memset(&act_dfl, 0, sizeof(act_dfl)); | |
5015 | + | |
c6a6bfc9 | 5016 | + act.sa_handler = &sig_soft_quit; |
fd1be940 ER |
5017 | + act.sa_flags |= SA_RESTART; |
5018 | + | |
5019 | + act_dfl.sa_handler = SIG_DFL; | |
5020 | + | |
5021 | + close(sp[0]); | |
5022 | + close(sp[1]); | |
5023 | + | |
5024 | + if (0 > sigaction(SIGTERM, &act_dfl, 0) || | |
5025 | + 0 > sigaction(SIGINT, &act_dfl, 0) || | |
c6a6bfc9 | 5026 | + 0 > sigaction(SIGUSR1, &act_dfl, 0) || |
fd1be940 ER |
5027 | + 0 > sigaction(SIGUSR2, &act_dfl, 0) || |
5028 | + 0 > sigaction(SIGCHLD, &act_dfl, 0) || | |
5029 | + 0 > sigaction(SIGQUIT, &act, 0)) { | |
5030 | + | |
5031 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "sigaction() failed"); | |
5032 | + return -1; | |
5033 | + } | |
5034 | + | |
5035 | + return 0; | |
5036 | +} | |
5037 | + | |
5038 | +int fpm_signals_get_fd() | |
5039 | +{ | |
5040 | + return sp[0]; | |
5041 | +} | |
37d32ffb ER |
5042 | diff --git a/sapi/cgi/fpm/fpm_signals.h b/sapi/cgi/fpm/fpm_signals.h |
5043 | new file mode 100644 | |
37d32ffb ER |
5044 | --- /dev/null |
5045 | +++ b/sapi/cgi/fpm/fpm_signals.h | |
fd1be940 ER |
5046 | @@ -0,0 +1,16 @@ |
5047 | + | |
5048 | + /* $Id$ */ | |
c6a6bfc9 | 5049 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
5050 | + |
5051 | +#ifndef FPM_SIGNALS_H | |
5052 | +#define FPM_SIGNALS_H 1 | |
5053 | + | |
5054 | +#include <signal.h> | |
5055 | + | |
5056 | +int fpm_signals_init_main(); | |
5057 | +int fpm_signals_init_child(); | |
5058 | +int fpm_signals_get_fd(); | |
5059 | + | |
5060 | +extern const char *fpm_signal_names[NSIG + 1]; | |
5061 | + | |
5062 | +#endif | |
37d32ffb ER |
5063 | diff --git a/sapi/cgi/fpm/fpm_sockets.c b/sapi/cgi/fpm/fpm_sockets.c |
5064 | new file mode 100644 | |
37d32ffb ER |
5065 | --- /dev/null |
5066 | +++ b/sapi/cgi/fpm/fpm_sockets.c | |
48b142c9 | 5067 | @@ -0,0 +1,427 @@ |
fd1be940 ER |
5068 | + |
5069 | + /* $Id$ */ | |
c6a6bfc9 | 5070 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
5071 | + |
5072 | +#include "fpm_config.h" | |
5073 | + | |
5074 | +#ifdef HAVE_ALLOCA_H | |
5075 | +#include <alloca.h> | |
5076 | +#endif | |
5077 | +#include <sys/types.h> | |
5078 | +#include <sys/stat.h> /* for chmod(2) */ | |
5079 | +#include <sys/socket.h> | |
5080 | +#include <netinet/in.h> | |
5081 | +#include <arpa/inet.h> | |
5082 | +#include <sys/un.h> | |
5083 | +#include <netdb.h> | |
5084 | +#include <stdio.h> | |
5085 | +#include <stdlib.h> | |
5086 | +#include <string.h> | |
5087 | +#include <errno.h> | |
5088 | +#include <unistd.h> | |
5089 | + | |
5090 | +#include "zlog.h" | |
c6a6bfc9 | 5091 | +#include "fpm_arrays.h" |
fd1be940 ER |
5092 | +#include "fpm_sockets.h" |
5093 | +#include "fpm_worker_pool.h" | |
5094 | +#include "fpm_unix.h" | |
c6a6bfc9 | 5095 | +#include "fpm_str.h" |
fd1be940 ER |
5096 | +#include "fpm_env.h" |
5097 | +#include "fpm_cleanup.h" | |
5098 | + | |
c6a6bfc9 | 5099 | +struct listening_socket_s { |
fd1be940 ER |
5100 | + int refcount; |
5101 | + int sock; | |
5102 | + int type; | |
5103 | + char *key; | |
5104 | +}; | |
5105 | + | |
c6a6bfc9 | 5106 | +static struct fpm_array_s sockets_list; |
fd1be940 ER |
5107 | + |
5108 | +static int fpm_sockets_resolve_af_inet(char *node, char *service, struct sockaddr_in *addr) | |
5109 | +{ | |
5110 | + struct addrinfo *res; | |
5111 | + struct addrinfo hints; | |
5112 | + int ret; | |
5113 | + | |
5114 | + memset(&hints, 0, sizeof(hints)); | |
5115 | + | |
5116 | + hints.ai_family = AF_INET; | |
5117 | + | |
5118 | + ret = getaddrinfo(node, service, &hints, &res); | |
5119 | + | |
5120 | + if (ret != 0) { | |
5121 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "can't resolve hostname '%s%s%s': getaddrinfo said: %s%s%s\n", | |
5122 | + node, service ? ":" : "", service ? service : "", | |
5123 | + gai_strerror(ret), ret == EAI_SYSTEM ? ", system error: " : "", ret == EAI_SYSTEM ? strerror(errno) : ""); | |
5124 | + return -1; | |
5125 | + } | |
5126 | + | |
5127 | + *addr = *(struct sockaddr_in *) res->ai_addr; | |
5128 | + | |
5129 | + freeaddrinfo(res); | |
5130 | + | |
5131 | + return 0; | |
5132 | +} | |
5133 | + | |
5134 | +enum { FPM_GET_USE_SOCKET = 1, FPM_STORE_SOCKET = 2, FPM_STORE_USE_SOCKET = 3 }; | |
5135 | + | |
5136 | +static void fpm_sockets_cleanup(int which, void *arg) | |
5137 | +{ | |
5138 | + int i; | |
5139 | + char *env_value = 0; | |
5140 | + int p = 0; | |
c6a6bfc9 | 5141 | + struct listening_socket_s *ls = sockets_list.data; |
fd1be940 | 5142 | + |
c6a6bfc9 | 5143 | + for (i = 0; i < sockets_list.used; i++, ls++) { |
fd1be940 ER |
5144 | + |
5145 | + if (which != FPM_CLEANUP_PARENT_EXEC) { | |
5146 | + | |
5147 | + close(ls->sock); | |
5148 | + | |
5149 | + } | |
5150 | + else { /* on PARENT EXEC we want socket fds to be inherited through environment variable */ | |
5151 | + char fd[32]; | |
5152 | + sprintf(fd, "%d", ls->sock); | |
5153 | + env_value = realloc(env_value, p + (p ? 1 : 0) + strlen(ls->key) + 1 + strlen(fd) + 1); | |
5154 | + p += sprintf(env_value + p, "%s%s=%s", p ? "," : "", ls->key, fd); | |
5155 | + } | |
5156 | + | |
5157 | + if (which == FPM_CLEANUP_PARENT_EXIT_MAIN) { | |
5158 | + | |
5159 | + if (ls->type == FPM_AF_UNIX) { | |
5160 | + unlink(ls->key); | |
5161 | + } | |
5162 | + | |
5163 | + } | |
5164 | + | |
5165 | + free(ls->key); | |
5166 | + } | |
5167 | + | |
5168 | + if (env_value) { | |
5169 | + setenv("FPM_SOCKETS", env_value, 1); | |
c6a6bfc9 | 5170 | + free(env_value); |
fd1be940 ER |
5171 | + } |
5172 | + | |
c6a6bfc9 | 5173 | + fpm_array_free(&sockets_list); |
fd1be940 ER |
5174 | +} |
5175 | + | |
5176 | +static int fpm_sockets_hash_op(int sock, struct sockaddr *sa, char *key, int type, int op) | |
5177 | +{ | |
5178 | + | |
5179 | + if (key == NULL) { | |
5180 | + | |
5181 | + switch (type) { | |
5182 | + | |
5183 | + case FPM_AF_INET : { | |
5184 | + struct sockaddr_in *sa_in = (struct sockaddr_in *) sa; | |
5185 | + | |
5186 | + key = alloca(sizeof("xxx.xxx.xxx.xxx:ppppp")); | |
5187 | + | |
c6a6bfc9 | 5188 | + sprintf(key, "%u.%u.%u.%u:%u", IPQUAD(&sa_in->sin_addr), (unsigned int) ntohs(sa_in->sin_port)); |
fd1be940 ER |
5189 | + |
5190 | + break; | |
5191 | + } | |
5192 | + | |
5193 | + case FPM_AF_UNIX : { | |
5194 | + struct sockaddr_un *sa_un = (struct sockaddr_un *) sa; | |
5195 | + | |
5196 | + key = alloca(strlen(sa_un->sun_path) + 1); | |
5197 | + | |
5198 | + strcpy(key, sa_un->sun_path); | |
5199 | + | |
5200 | + break; | |
5201 | + } | |
5202 | + | |
5203 | + default : | |
5204 | + | |
5205 | + return -1; | |
5206 | + } | |
5207 | + | |
5208 | + } | |
5209 | + | |
5210 | + switch (op) { | |
5211 | + | |
5212 | + case FPM_GET_USE_SOCKET : | |
5213 | + { | |
5214 | + | |
5215 | + int i; | |
c6a6bfc9 | 5216 | + struct listening_socket_s *ls = sockets_list.data; |
fd1be940 | 5217 | + |
c6a6bfc9 | 5218 | + for (i = 0; i < sockets_list.used; i++, ls++) { |
fd1be940 ER |
5219 | + |
5220 | + if (!strcmp(ls->key, key)) { | |
5221 | + ++ls->refcount; | |
5222 | + return ls->sock; | |
5223 | + } | |
5224 | + } | |
5225 | + | |
5226 | + break; | |
5227 | + } | |
5228 | + | |
5229 | + case FPM_STORE_SOCKET : /* inherited socket */ | |
5230 | + case FPM_STORE_USE_SOCKET : /* just created */ | |
5231 | + { | |
5232 | + | |
c6a6bfc9 | 5233 | + struct listening_socket_s *ls; |
fd1be940 | 5234 | + |
c6a6bfc9 | 5235 | + ls = fpm_array_push(&sockets_list); |
fd1be940 | 5236 | + |
c6a6bfc9 ER |
5237 | + if (!ls) { |
5238 | + break; | |
fd1be940 ER |
5239 | + } |
5240 | + | |
fd1be940 ER |
5241 | + if (op == FPM_STORE_SOCKET) { |
5242 | + ls->refcount = 0; | |
5243 | + } | |
5244 | + else { | |
5245 | + ls->refcount = 1; | |
5246 | + } | |
5247 | + ls->type = type; | |
5248 | + ls->sock = sock; | |
5249 | + ls->key = strdup(key); | |
5250 | + | |
fd1be940 ER |
5251 | + return 0; |
5252 | + | |
5253 | + } | |
5254 | + } | |
5255 | + | |
5256 | + return -1; | |
5257 | + | |
5258 | +} | |
5259 | + | |
5260 | +static int fpm_sockets_new_listening_socket(struct fpm_worker_pool_s *wp, struct sockaddr *sa, int socklen) | |
5261 | +{ | |
5262 | + int backlog = -1; | |
5263 | + int flags = 1; | |
5264 | + int sock; | |
5265 | + mode_t saved_umask; | |
5266 | + | |
5267 | + /* we have custom backlog value */ | |
5268 | + if (wp->config->listen_options) { | |
5269 | + backlog = wp->config->listen_options->backlog; | |
5270 | + } | |
5271 | + | |
5272 | + sock = socket(sa->sa_family, SOCK_STREAM, 0); | |
5273 | + | |
5274 | + if (0 > sock) { | |
5275 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "socket() failed"); | |
5276 | + return -1; | |
5277 | + } | |
5278 | + | |
5279 | + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)); | |
5280 | + | |
5281 | + if (wp->listen_address_domain == FPM_AF_UNIX) { | |
5282 | + unlink( ((struct sockaddr_un *) sa)->sun_path); | |
5283 | + } | |
5284 | + | |
5285 | + saved_umask = umask(0777 ^ wp->socket_mode); | |
5286 | + | |
5287 | + if (0 > bind(sock, sa, socklen)) { | |
5288 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "bind() for address '%s' failed", wp->config->listen_address); | |
5289 | + return -1; | |
5290 | + } | |
5291 | + | |
5292 | + if (wp->listen_address_domain == FPM_AF_UNIX) { | |
5293 | + | |
5294 | + char *path = ((struct sockaddr_un *) sa)->sun_path; | |
5295 | + | |
5296 | + if (wp->socket_uid != -1 || wp->socket_gid != -1) { | |
5297 | + | |
5298 | + if (0 > chown(path, wp->socket_uid, wp->socket_gid)) { | |
5299 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "chown() for address '%s' failed", wp->config->listen_address); | |
5300 | + return -1; | |
5301 | + } | |
5302 | + | |
5303 | + } | |
5304 | + | |
5305 | + } | |
5306 | + | |
5307 | + umask(saved_umask); | |
5308 | + | |
5309 | + if (0 > listen(sock, backlog)) { | |
5310 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "listen() for address '%s' failed", wp->config->listen_address); | |
5311 | + return -1; | |
5312 | + } | |
5313 | + | |
5314 | + return sock; | |
5315 | +} | |
5316 | + | |
5317 | +static int fpm_sockets_get_listening_socket(struct fpm_worker_pool_s *wp, struct sockaddr *sa, int socklen) | |
5318 | +{ | |
5319 | + int sock; | |
5320 | + | |
5321 | + sock = fpm_sockets_hash_op(0, sa, 0, wp->listen_address_domain, FPM_GET_USE_SOCKET); | |
5322 | + | |
5323 | + if (sock >= 0) return sock; | |
5324 | + | |
5325 | + sock = fpm_sockets_new_listening_socket(wp, sa, socklen); | |
5326 | + | |
5327 | + fpm_sockets_hash_op(sock, sa, 0, wp->listen_address_domain, FPM_STORE_USE_SOCKET); | |
5328 | + | |
5329 | + return sock; | |
5330 | +} | |
5331 | + | |
5332 | +enum fpm_address_domain fpm_sockets_domain_from_address(char *address) | |
5333 | +{ | |
5334 | + if (strchr(address, ':')) return FPM_AF_INET; | |
5335 | + | |
5336 | + if (strlen(address) == strspn(address, "0123456789")) return FPM_AF_INET; | |
5337 | + | |
5338 | + return FPM_AF_UNIX; | |
5339 | +} | |
5340 | + | |
5341 | +static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) | |
5342 | +{ | |
5343 | + struct sockaddr_in sa_in; | |
5344 | + char *dup_address = strdup(wp->config->listen_address); | |
5345 | + char *port_str = strchr(dup_address, ':'); | |
5346 | + char *addr = NULL; | |
5347 | + int port = 0; | |
5348 | + | |
5349 | + if (port_str) { /* this is host:port pair */ | |
5350 | + *port_str++ = '\0'; | |
5351 | + port = atoi(port_str); | |
5352 | + addr = dup_address; | |
5353 | + } | |
5354 | + else if (strlen(dup_address) == strspn(dup_address, "0123456789")) { /* this is port */ | |
5355 | + port = atoi(dup_address); | |
5356 | + port_str = dup_address; | |
5357 | + } | |
5358 | + | |
5359 | + if (port == 0) { | |
5360 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "invalid port value '%s'", port_str); | |
5361 | + return -1; | |
5362 | + } | |
5363 | + | |
5364 | + memset(&sa_in, 0, sizeof(sa_in)); | |
5365 | + | |
5366 | + if (addr) { | |
5367 | + | |
5368 | + sa_in.sin_addr.s_addr = inet_addr(addr); | |
5369 | + | |
5370 | + if (sa_in.sin_addr.s_addr == INADDR_NONE) { /* do resolve */ | |
5371 | + if (0 > fpm_sockets_resolve_af_inet(addr, NULL, &sa_in)) { | |
5372 | + return -1; | |
5373 | + } | |
5374 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "address '%s' resolved as %u.%u.%u.%u", addr, IPQUAD(&sa_in.sin_addr)); | |
5375 | + } | |
5376 | + } | |
5377 | + else { | |
5378 | + | |
5379 | + sa_in.sin_addr.s_addr = htonl(INADDR_ANY); | |
5380 | + | |
5381 | + } | |
5382 | + | |
5383 | + sa_in.sin_family = AF_INET; | |
5384 | + sa_in.sin_port = htons(port); | |
5385 | + | |
5386 | + free(dup_address); | |
5387 | + | |
5388 | + return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_in, sizeof(struct sockaddr_in)); | |
5389 | +} | |
5390 | + | |
5391 | +static int fpm_socket_af_unix_listening_socket(struct fpm_worker_pool_s *wp) | |
5392 | +{ | |
5393 | + struct sockaddr_un sa_un; | |
5394 | + | |
5395 | + memset(&sa_un, 0, sizeof(sa_un)); | |
5396 | + | |
c6a6bfc9 | 5397 | + cpystrn(sa_un.sun_path, wp->config->listen_address, sizeof(sa_un.sun_path)); |
fd1be940 | 5398 | + sa_un.sun_family = AF_UNIX; |
fd1be940 ER |
5399 | + |
5400 | + return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_un, sizeof(struct sockaddr_un)); | |
5401 | +} | |
5402 | + | |
5403 | +int fpm_sockets_init_main() | |
5404 | +{ | |
5405 | + int i; | |
5406 | + struct fpm_worker_pool_s *wp; | |
5407 | + char *inherited = getenv("FPM_SOCKETS"); | |
c6a6bfc9 ER |
5408 | + struct listening_socket_s *ls; |
5409 | + | |
5410 | + if (0 == fpm_array_init(&sockets_list, sizeof(struct listening_socket_s), 10)) { | |
5411 | + return -1; | |
5412 | + } | |
fd1be940 ER |
5413 | + |
5414 | + /* import inherited sockets */ | |
5415 | + while (inherited && *inherited) { | |
5416 | + char *comma = strchr(inherited, ','); | |
5417 | + int type, fd_no; | |
5418 | + char *eq; | |
5419 | + | |
5420 | + if (comma) *comma = '\0'; | |
5421 | + | |
5422 | + eq = strchr(inherited, '='); | |
5423 | + | |
5424 | + if (eq) { | |
5425 | + *eq = '\0'; | |
5426 | + | |
5427 | + fd_no = atoi(eq + 1); | |
5428 | + | |
5429 | + type = fpm_sockets_domain_from_address(inherited); | |
5430 | + | |
5431 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "using inherited socket fd=%d, \"%s\"", fd_no, inherited); | |
5432 | + | |
5433 | + fpm_sockets_hash_op(fd_no, 0, inherited, type, FPM_STORE_SOCKET); | |
5434 | + } | |
5435 | + | |
5436 | + if (comma) inherited = comma + 1; | |
5437 | + else inherited = 0; | |
5438 | + } | |
5439 | + | |
c6a6bfc9 | 5440 | + /* create all required sockets */ |
fd1be940 ER |
5441 | + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { |
5442 | + | |
5443 | + if (!wp->is_template) { | |
5444 | + | |
5445 | + switch (wp->listen_address_domain) { | |
5446 | + | |
5447 | + case FPM_AF_INET : | |
5448 | + | |
5449 | + wp->listening_socket = fpm_socket_af_inet_listening_socket(wp); | |
5450 | + break; | |
5451 | + | |
5452 | + case FPM_AF_UNIX : | |
5453 | + | |
5454 | + if (0 > fpm_unix_resolve_socket_premissions(wp)) { | |
5455 | + return -1; | |
5456 | + } | |
5457 | + | |
5458 | + wp->listening_socket = fpm_socket_af_unix_listening_socket(wp); | |
5459 | + break; | |
5460 | + | |
5461 | + } | |
5462 | + | |
5463 | + if (wp->listening_socket == -1) { | |
5464 | + return -1; | |
5465 | + } | |
5466 | + } | |
5467 | + | |
5468 | + } | |
5469 | + | |
5470 | + /* close unused sockets that was inherited */ | |
c6a6bfc9 ER |
5471 | + ls = sockets_list.data; |
5472 | + | |
5473 | + for (i = 0; i < sockets_list.used; ) { | |
fd1be940 ER |
5474 | + |
5475 | + if (ls->refcount == 0) { | |
5476 | + close(ls->sock); | |
5477 | + if (ls->type == FPM_AF_UNIX) { | |
5478 | + unlink(ls->key); | |
5479 | + } | |
5480 | + free(ls->key); | |
c6a6bfc9 | 5481 | + fpm_array_item_remove(&sockets_list, i); |
fd1be940 ER |
5482 | + } |
5483 | + else { | |
5484 | + ++i; | |
c6a6bfc9 | 5485 | + ++ls; |
fd1be940 ER |
5486 | + } |
5487 | + } | |
5488 | + | |
48b142c9 ER |
5489 | + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_sockets_cleanup, 0)) { |
5490 | + return -1; | |
5491 | + } | |
fd1be940 ER |
5492 | + |
5493 | + return 0; | |
5494 | +} | |
37d32ffb ER |
5495 | diff --git a/sapi/cgi/fpm/fpm_sockets.h b/sapi/cgi/fpm/fpm_sockets.h |
5496 | new file mode 100644 | |
37d32ffb ER |
5497 | --- /dev/null |
5498 | +++ b/sapi/cgi/fpm/fpm_sockets.h | |
fd1be940 ER |
5499 | @@ -0,0 +1,37 @@ |
5500 | + | |
5501 | + /* $Id$ */ | |
c6a6bfc9 | 5502 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
5503 | + |
5504 | +#ifndef FPM_MISC_H | |
5505 | +#define FPM_MISC_H 1 | |
5506 | + | |
5507 | +#include <unistd.h> | |
5508 | +#include <fcntl.h> | |
5509 | + | |
5510 | +#include "fpm_worker_pool.h" | |
5511 | + | |
5512 | +enum fpm_address_domain fpm_sockets_domain_from_address(char *addr); | |
5513 | +int fpm_sockets_init_main(); | |
5514 | + | |
5515 | + | |
5516 | +static inline int fd_set_blocked(int fd, int blocked) | |
5517 | +{ | |
5518 | + int flags = fcntl(fd, F_GETFL); | |
5519 | + | |
5520 | + if (flags < 0) return -1; | |
5521 | + | |
5522 | + if (blocked) | |
5523 | + flags &= ~O_NONBLOCK; | |
5524 | + else | |
5525 | + flags |= O_NONBLOCK; | |
5526 | + | |
5527 | + return fcntl(fd, F_SETFL, flags); | |
5528 | +} | |
5529 | + | |
5530 | +#define IPQUAD(sin_addr) \ | |
c6a6bfc9 ER |
5531 | + (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[0], \ |
5532 | + (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[1], \ | |
5533 | + (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[2], \ | |
5534 | + (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[3] | |
fd1be940 ER |
5535 | + |
5536 | +#endif | |
37d32ffb ER |
5537 | diff --git a/sapi/cgi/fpm/fpm_stdio.c b/sapi/cgi/fpm/fpm_stdio.c |
5538 | new file mode 100644 | |
37d32ffb ER |
5539 | --- /dev/null |
5540 | +++ b/sapi/cgi/fpm/fpm_stdio.c | |
48b142c9 | 5541 | @@ -0,0 +1,286 @@ |
fd1be940 ER |
5542 | + |
5543 | + /* $Id$ */ | |
c6a6bfc9 | 5544 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
5545 | + |
5546 | +#include "fpm_config.h" | |
5547 | + | |
5548 | +#include <sys/types.h> | |
5549 | +#include <sys/stat.h> | |
5550 | +#include <string.h> | |
5551 | +#include <fcntl.h> | |
5552 | +#include <unistd.h> | |
5553 | +#include <errno.h> | |
5554 | + | |
5555 | +#include "fpm.h" | |
5556 | +#include "fpm_children.h" | |
5557 | +#include "fpm_events.h" | |
5558 | +#include "fpm_sockets.h" | |
5559 | +#include "fpm_stdio.h" | |
5560 | +#include "zlog.h" | |
5561 | + | |
c6a6bfc9 ER |
5562 | +static int fd_stdout[2]; |
5563 | +static int fd_stderr[2]; | |
5564 | + | |
fd1be940 ER |
5565 | +int fpm_stdio_init_main() |
5566 | +{ | |
c6a6bfc9 | 5567 | + int fd = open("/dev/null", O_RDWR); |
fd1be940 ER |
5568 | + |
5569 | + if (0 > fd) { | |
c6a6bfc9 | 5570 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(\"/dev/null\") failed"); |
fd1be940 ER |
5571 | + return -1; |
5572 | + } | |
5573 | + | |
48b142c9 ER |
5574 | + if (0 > dup2(fd, STDIN_FILENO) || 0 > dup2(fd, STDOUT_FILENO)) { |
5575 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed"); | |
5576 | + return -1; | |
5577 | + } | |
5578 | + | |
fd1be940 ER |
5579 | + close(fd); |
5580 | + | |
5581 | + return 0; | |
5582 | +} | |
5583 | + | |
5584 | +int fpm_stdio_init_final() | |
5585 | +{ | |
48b142c9 | 5586 | + if (fpm_global_config.daemonize) { |
fd1be940 ER |
5587 | + |
5588 | + if (fpm_globals.error_log_fd != STDERR_FILENO) { | |
c6a6bfc9 | 5589 | + /* there might be messages to stderr from libevent, we need to log them all */ |
48b142c9 ER |
5590 | + if (0 > dup2(fpm_globals.error_log_fd, STDERR_FILENO)) { |
5591 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed"); | |
5592 | + return -1; | |
5593 | + } | |
fd1be940 ER |
5594 | + } |
5595 | + | |
c6a6bfc9 ER |
5596 | + zlog_set_level(fpm_globals.log_level); |
5597 | + | |
fd1be940 ER |
5598 | + zlog_set_fd(fpm_globals.error_log_fd); |
5599 | + } | |
5600 | + | |
5601 | + return 0; | |
5602 | +} | |
5603 | + | |
5604 | +int fpm_stdio_init_child(struct fpm_worker_pool_s *wp) | |
5605 | +{ | |
fd1be940 ER |
5606 | + close(fpm_globals.error_log_fd); |
5607 | + fpm_globals.error_log_fd = -1; | |
c6a6bfc9 | 5608 | + zlog_set_fd(-1); |
fd1be940 ER |
5609 | + |
5610 | + if (wp->listening_socket != STDIN_FILENO) { | |
48b142c9 ER |
5611 | + if (0 > dup2(wp->listening_socket, STDIN_FILENO)) { |
5612 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "dup2() failed"); | |
5613 | + return -1; | |
5614 | + } | |
fd1be940 ER |
5615 | + } |
5616 | + | |
5617 | + return 0; | |
5618 | +} | |
5619 | + | |
fd1be940 ER |
5620 | +static void fpm_stdio_child_said(int fd, short which, void *arg) |
5621 | +{ | |
5622 | + static const int max_buf_size = 1024; | |
5623 | + char buf[max_buf_size]; | |
5624 | + struct fpm_child_s *child = arg; | |
5625 | + int is_stdout = fd == child->fd_stdout; | |
5626 | + struct event *ev = is_stdout ? &child->ev_stdout : &child->ev_stderr; | |
5627 | + int fifo_in = 1, fifo_out = 1; | |
5628 | + int is_last_message = 0; | |
5629 | + int in_buf = 0; | |
5630 | + int res; | |
5631 | + | |
5632 | +#if 0 | |
5633 | + zlog(ZLOG_STUFF, ZLOG_DEBUG, "child %d said %s", (int) child->pid, is_stdout ? "stdout" : "stderr"); | |
5634 | +#endif | |
5635 | + | |
5636 | + while (fifo_in || fifo_out) { | |
5637 | + | |
5638 | + if (fifo_in) { | |
5639 | + | |
5640 | + res = read(fd, buf + in_buf, max_buf_size - 1 - in_buf); | |
5641 | + | |
5642 | + if (res <= 0) { /* no data */ | |
5643 | + fifo_in = 0; | |
5644 | + | |
5645 | + if (res < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { | |
5646 | + /* just no more data ready */ | |
5647 | + } | |
5648 | + else { /* error or pipe is closed */ | |
5649 | + | |
5650 | + if (res < 0) { /* error */ | |
5651 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "read() failed"); | |
5652 | + } | |
5653 | + | |
5654 | + fpm_event_del(ev); | |
5655 | + is_last_message = 1; | |
5656 | + | |
5657 | + if (is_stdout) { | |
5658 | + close(child->fd_stdout); | |
5659 | + child->fd_stdout = -1; | |
5660 | + } | |
5661 | + else { | |
5662 | + close(child->fd_stderr); | |
5663 | + child->fd_stderr = -1; | |
5664 | + } | |
5665 | + | |
5666 | +#if 0 | |
5667 | + if (in_buf == 0 && !fpm_globals.is_child) { | |
5668 | + zlog(ZLOG_STUFF, ZLOG_DEBUG, "child %d (pool %s) %s pipe is closed", (int) child->pid, | |
5669 | + child->wp->config->name, is_stdout ? "stdout" : "stderr"); | |
5670 | + } | |
5671 | +#endif | |
5672 | + } | |
5673 | + } | |
5674 | + else { | |
5675 | + in_buf += res; | |
5676 | + } | |
5677 | + } | |
5678 | + | |
5679 | + if (fifo_out) { | |
5680 | + if (in_buf == 0) { | |
5681 | + fifo_out = 0; | |
5682 | + } | |
5683 | + else { | |
5684 | + char *nl; | |
5685 | + int should_print = 0; | |
5686 | + buf[in_buf] = '\0'; | |
5687 | + | |
5688 | + /* FIXME: there might be binary data */ | |
5689 | + | |
5690 | + /* we should print if no more space in the buffer */ | |
5691 | + if (in_buf == max_buf_size - 1) { | |
5692 | + should_print = 1; | |
5693 | + } | |
5694 | + | |
5695 | + /* we should print if no more data to come */ | |
5696 | + if (!fifo_in) { | |
5697 | + should_print = 1; | |
5698 | + } | |
5699 | + | |
5700 | + nl = strchr(buf, '\n'); | |
5701 | + | |
5702 | + if (nl || should_print) { | |
5703 | + | |
5704 | + if (nl) { | |
5705 | + *nl = '\0'; | |
5706 | + } | |
5707 | + | |
5708 | + zlog(ZLOG_STUFF, ZLOG_WARNING, "child %d (pool %s) said into %s: \"%s\"%s", (int) child->pid, | |
5709 | + child->wp->config->name, is_stdout ? "stdout" : "stderr", buf, is_last_message ? ", pipe is closed" : ""); | |
5710 | + | |
5711 | + if (nl) { | |
5712 | + int out_buf = 1 + nl - buf; | |
5713 | + memmove(buf, buf + out_buf, in_buf - out_buf); | |
5714 | + in_buf -= out_buf; | |
5715 | + } | |
5716 | + else { | |
5717 | + in_buf = 0; | |
5718 | + } | |
5719 | + } | |
5720 | + } | |
5721 | + } | |
5722 | + } | |
5723 | + | |
5724 | +} | |
5725 | + | |
c6a6bfc9 | 5726 | +int fpm_stdio_prepare_pipes(struct fpm_child_s *child) |
fd1be940 | 5727 | +{ |
c6a6bfc9 | 5728 | + if (0 == child->wp->config->catch_workers_output) { /* not required */ |
fd1be940 ER |
5729 | + return 0; |
5730 | + } | |
5731 | + | |
c6a6bfc9 ER |
5732 | + if (0 > pipe(fd_stdout)) { |
5733 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pipe() failed"); | |
5734 | + return -1; | |
5735 | + } | |
5736 | + | |
5737 | + if (0 > pipe(fd_stderr)) { | |
5738 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pipe() failed"); | |
5739 | + close(fd_stdout[0]); close(fd_stdout[1]); | |
5740 | + return -1; | |
5741 | + } | |
fd1be940 | 5742 | + |
c6a6bfc9 ER |
5743 | + if (0 > fd_set_blocked(fd_stdout[0], 0) || 0 > fd_set_blocked(fd_stderr[0], 0)) { |
5744 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fd_set_blocked() failed"); | |
5745 | + close(fd_stdout[0]); close(fd_stdout[1]); | |
5746 | + close(fd_stderr[0]); close(fd_stderr[1]); | |
5747 | + return -1; | |
5748 | + } | |
fd1be940 | 5749 | + |
c6a6bfc9 ER |
5750 | + return 0; |
5751 | +} | |
5752 | + | |
5753 | +int fpm_stdio_parent_use_pipes(struct fpm_child_s *child) | |
5754 | +{ | |
5755 | + if (0 == child->wp->config->catch_workers_output) { /* not required */ | |
5756 | + return 0; | |
5757 | + } | |
5758 | + | |
5759 | + close(fd_stdout[1]); | |
5760 | + close(fd_stderr[1]); | |
5761 | + | |
5762 | + child->fd_stdout = fd_stdout[0]; | |
5763 | + child->fd_stderr = fd_stderr[0]; | |
fd1be940 ER |
5764 | + |
5765 | + fpm_event_add(child->fd_stdout, &child->ev_stdout, fpm_stdio_child_said, child); | |
5766 | + fpm_event_add(child->fd_stderr, &child->ev_stderr, fpm_stdio_child_said, child); | |
5767 | + | |
5768 | + return 0; | |
5769 | +} | |
c6a6bfc9 ER |
5770 | + |
5771 | +int fpm_stdio_discard_pipes(struct fpm_child_s *child) | |
5772 | +{ | |
5773 | + if (0 == child->wp->config->catch_workers_output) { /* not required */ | |
5774 | + return 0; | |
5775 | + } | |
5776 | + | |
5777 | + close(fd_stdout[1]); | |
5778 | + close(fd_stderr[1]); | |
5779 | + | |
5780 | + close(fd_stdout[0]); | |
5781 | + close(fd_stderr[0]); | |
5782 | + | |
5783 | + return 0; | |
5784 | +} | |
5785 | + | |
5786 | +void fpm_stdio_child_use_pipes(struct fpm_child_s *child) | |
5787 | +{ | |
5788 | + if (child->wp->config->catch_workers_output) { | |
5789 | + dup2(fd_stdout[1], STDOUT_FILENO); | |
5790 | + dup2(fd_stderr[1], STDERR_FILENO); | |
5791 | + close(fd_stdout[0]); close(fd_stdout[1]); | |
5792 | + close(fd_stderr[0]); close(fd_stderr[1]); | |
5793 | + } | |
5794 | + else { | |
5795 | + /* stdout of parent is always /dev/null */ | |
5796 | + dup2(STDOUT_FILENO, STDERR_FILENO); | |
5797 | + } | |
5798 | +} | |
5799 | + | |
5800 | +int fpm_stdio_open_error_log(int reopen) | |
5801 | +{ | |
5802 | + int fd; | |
5803 | + | |
48b142c9 | 5804 | + fd = open(fpm_global_config.error_log, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); |
c6a6bfc9 ER |
5805 | + |
5806 | + if (0 > fd) { | |
48b142c9 | 5807 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(\"%s\") failed", fpm_global_config.error_log); |
c6a6bfc9 ER |
5808 | + return -1; |
5809 | + } | |
5810 | + | |
5811 | + if (reopen) { | |
48b142c9 | 5812 | + if (fpm_global_config.daemonize) { |
c6a6bfc9 ER |
5813 | + dup2(fd, STDERR_FILENO); |
5814 | + } | |
5815 | + | |
5816 | + dup2(fd, fpm_globals.error_log_fd); | |
5817 | + close(fd); | |
5818 | + fd = fpm_globals.error_log_fd; /* for FD_CLOSEXEC to work */ | |
5819 | + } | |
5820 | + else { | |
5821 | + fpm_globals.error_log_fd = fd; | |
5822 | + } | |
5823 | + | |
5824 | + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); | |
5825 | + | |
5826 | + return 0; | |
5827 | +} | |
37d32ffb ER |
5828 | diff --git a/sapi/cgi/fpm/fpm_stdio.h b/sapi/cgi/fpm/fpm_stdio.h |
5829 | new file mode 100644 | |
37d32ffb ER |
5830 | --- /dev/null |
5831 | +++ b/sapi/cgi/fpm/fpm_stdio.h | |
c6a6bfc9 | 5832 | @@ -0,0 +1,20 @@ |
fd1be940 ER |
5833 | + |
5834 | + /* $Id$ */ | |
c6a6bfc9 | 5835 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
5836 | + |
5837 | +#ifndef FPM_STDIO_H | |
5838 | +#define FPM_STDIO_H 1 | |
5839 | + | |
5840 | +#include "fpm_worker_pool.h" | |
5841 | + | |
5842 | +int fpm_stdio_init_main(); | |
5843 | +int fpm_stdio_init_final(); | |
5844 | +int fpm_stdio_init_child(struct fpm_worker_pool_s *wp); | |
c6a6bfc9 ER |
5845 | +int fpm_stdio_prepare_pipes(struct fpm_child_s *child); |
5846 | +void fpm_stdio_child_use_pipes(struct fpm_child_s *child); | |
fd1be940 | 5847 | +int fpm_stdio_parent_use_pipes(struct fpm_child_s *child); |
c6a6bfc9 ER |
5848 | +int fpm_stdio_discard_pipes(struct fpm_child_s *child); |
5849 | +int fpm_stdio_open_error_log(int reopen); | |
5850 | + | |
5851 | +#endif | |
5852 | + | |
37d32ffb ER |
5853 | diff --git a/sapi/cgi/fpm/fpm_str.h b/sapi/cgi/fpm/fpm_str.h |
5854 | new file mode 100644 | |
37d32ffb ER |
5855 | --- /dev/null |
5856 | +++ b/sapi/cgi/fpm/fpm_str.h | |
c6a6bfc9 ER |
5857 | @@ -0,0 +1,49 @@ |
5858 | + | |
5859 | + /* $Id$ */ | |
5860 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
5861 | + | |
5862 | +#ifndef FPM_STR_H | |
5863 | +#define FPM_STR_H 1 | |
5864 | + | |
5865 | +static inline char *cpystrn(char *dst, const char *src, size_t dst_size) | |
5866 | +{ | |
5867 | + char *d, *end; | |
5868 | + | |
5869 | + if (!dst_size) return dst; | |
5870 | + | |
5871 | + d = dst; | |
5872 | + end = dst + dst_size - 1; | |
5873 | + | |
5874 | + for (; d < end; ++d, ++src) { | |
5875 | + if (!(*d = *src)) { | |
5876 | + return d; | |
5877 | + } | |
5878 | + } | |
5879 | + | |
5880 | + *d = '\0'; | |
5881 | + | |
5882 | + return d; | |
5883 | +} | |
5884 | + | |
5885 | +static inline char *str_purify_filename(char *dst, char *src, size_t size) | |
5886 | +{ | |
5887 | + char *d, *end; | |
5888 | + | |
5889 | + d = dst; | |
5890 | + end = dst + size - 1; | |
5891 | + | |
5892 | + for (; d < end && *src; ++d, ++src) { | |
5893 | + if (* (unsigned char *) src < ' ' || * (unsigned char *) src > '\x7f') { | |
5894 | + *d = '.'; | |
5895 | + } | |
5896 | + else { | |
5897 | + *d = *src; | |
5898 | + } | |
5899 | + } | |
5900 | + | |
5901 | + *d = '\0'; | |
5902 | + | |
5903 | + return d; | |
5904 | +} | |
5905 | + | |
5906 | +#endif | |
37d32ffb ER |
5907 | diff --git a/sapi/cgi/fpm/fpm_trace.c b/sapi/cgi/fpm/fpm_trace.c |
5908 | new file mode 100644 | |
37d32ffb ER |
5909 | --- /dev/null |
5910 | +++ b/sapi/cgi/fpm/fpm_trace.c | |
c6a6bfc9 ER |
5911 | @@ -0,0 +1,46 @@ |
5912 | + | |
5913 | + /* $Id$ */ | |
5914 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
5915 | + | |
5916 | +#include "fpm_config.h" | |
5917 | + | |
5918 | +#include <sys/types.h> | |
5919 | + | |
5920 | +#include "fpm_trace.h" | |
5921 | + | |
5922 | +int fpm_trace_get_strz(char *buf, size_t sz, long addr) | |
5923 | +{ | |
5924 | + int i; | |
5925 | + long l; | |
5926 | + char *lc = (char *) &l; | |
5927 | + | |
5928 | + if (0 > fpm_trace_get_long(addr, &l)) { | |
5929 | + return -1; | |
5930 | + } | |
5931 | + | |
5932 | + i = l % SIZEOF_LONG; | |
5933 | + | |
5934 | + l -= i; | |
5935 | + | |
5936 | + for (addr = l; ; addr += SIZEOF_LONG) { | |
5937 | + | |
5938 | + if (0 > fpm_trace_get_long(addr, &l)) { | |
5939 | + return -1; | |
5940 | + } | |
5941 | + | |
5942 | + for ( ; i < SIZEOF_LONG; i++) { | |
5943 | + --sz; | |
5944 | + | |
5945 | + if (sz && lc[i]) { | |
5946 | + *buf++ = lc[i]; | |
5947 | + continue; | |
5948 | + } | |
5949 | + | |
5950 | + *buf = '\0'; | |
5951 | + return 0; | |
5952 | + } | |
5953 | + | |
5954 | + i = 0; | |
5955 | + } | |
5956 | +} | |
5957 | + | |
37d32ffb ER |
5958 | diff --git a/sapi/cgi/fpm/fpm_trace.h b/sapi/cgi/fpm/fpm_trace.h |
5959 | new file mode 100644 | |
37d32ffb ER |
5960 | --- /dev/null |
5961 | +++ b/sapi/cgi/fpm/fpm_trace.h | |
c6a6bfc9 ER |
5962 | @@ -0,0 +1,17 @@ |
5963 | + | |
5964 | + /* $Id$ */ | |
5965 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
5966 | + | |
5967 | +#ifndef FPM_TRACE_H | |
5968 | +#define FPM_TRACE_H 1 | |
5969 | + | |
5970 | +#include <unistd.h> | |
5971 | + | |
5972 | +int fpm_trace_signal(pid_t pid); | |
5973 | +int fpm_trace_ready(pid_t pid); | |
5974 | +int fpm_trace_close(pid_t pid); | |
5975 | +int fpm_trace_get_long(long addr, long *data); | |
5976 | +int fpm_trace_get_strz(char *buf, size_t sz, long addr); | |
fd1be940 ER |
5977 | + |
5978 | +#endif | |
5979 | + | |
37d32ffb ER |
5980 | diff --git a/sapi/cgi/fpm/fpm_trace_mach.c b/sapi/cgi/fpm/fpm_trace_mach.c |
5981 | new file mode 100644 | |
37d32ffb ER |
5982 | --- /dev/null |
5983 | +++ b/sapi/cgi/fpm/fpm_trace_mach.c | |
c6a6bfc9 ER |
5984 | @@ -0,0 +1,102 @@ |
5985 | + | |
5986 | + /* $Id$ */ | |
5987 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
5988 | + | |
5989 | +#include "fpm_config.h" | |
5990 | + | |
5991 | +#include <mach/mach.h> | |
5992 | +#include <mach/mach_vm.h> | |
5993 | + | |
5994 | +#include <unistd.h> | |
5995 | + | |
5996 | +#include "fpm_trace.h" | |
5997 | +#include "fpm_process_ctl.h" | |
5998 | +#include "fpm_unix.h" | |
5999 | +#include "zlog.h" | |
6000 | + | |
6001 | + | |
6002 | +static mach_port_name_t target; | |
6003 | +static vm_offset_t target_page_base; | |
6004 | +static vm_offset_t local_page; | |
6005 | +static mach_msg_type_number_t local_size; | |
6006 | + | |
6007 | +static void fpm_mach_vm_deallocate() | |
6008 | +{ | |
6009 | + if (local_page) { | |
6010 | + mach_vm_deallocate(mach_task_self(), local_page, local_size); | |
6011 | + target_page_base = 0; | |
6012 | + local_page = 0; | |
6013 | + local_size = 0; | |
6014 | + } | |
6015 | +} | |
6016 | + | |
6017 | +static int fpm_mach_vm_read_page(vm_offset_t page) | |
6018 | +{ | |
6019 | + kern_return_t kr; | |
6020 | + | |
6021 | + kr = mach_vm_read(target, page, fpm_pagesize, &local_page, &local_size); | |
6022 | + | |
6023 | + if (kr != KERN_SUCCESS) { | |
6024 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "mach_vm_read() failed: %s (%d)", mach_error_string(kr), kr); | |
6025 | + return -1; | |
6026 | + } | |
6027 | + | |
6028 | + return 0; | |
6029 | +} | |
6030 | + | |
6031 | +int fpm_trace_signal(pid_t pid) | |
6032 | +{ | |
6033 | + if (0 > fpm_pctl_kill(pid, FPM_PCTL_STOP)) { | |
6034 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "kill(SIGSTOP) failed"); | |
6035 | + return -1; | |
6036 | + } | |
6037 | + | |
6038 | + return 0; | |
6039 | +} | |
6040 | + | |
6041 | +int fpm_trace_ready(pid_t pid) | |
6042 | +{ | |
6043 | + kern_return_t kr; | |
6044 | + | |
6045 | + kr = task_for_pid(mach_task_self(), pid, &target); | |
6046 | + | |
6047 | + if (kr != KERN_SUCCESS) { | |
6048 | + char *msg = ""; | |
6049 | + | |
6050 | + if (kr == KERN_FAILURE) { | |
6051 | + msg = " It seems that master process does not have enough privileges to trace processes."; | |
6052 | + } | |
6053 | + | |
6054 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "task_for_pid() failed: %s (%d)%s", mach_error_string(kr), kr, msg); | |
6055 | + return -1; | |
6056 | + } | |
6057 | + | |
6058 | + return 0; | |
6059 | +} | |
6060 | + | |
6061 | +int fpm_trace_close(pid_t pid) | |
6062 | +{ | |
6063 | + fpm_mach_vm_deallocate(); | |
6064 | + | |
6065 | + target = 0; | |
6066 | + | |
6067 | + return 0; | |
6068 | +} | |
6069 | + | |
6070 | +int fpm_trace_get_long(long addr, long *data) | |
6071 | +{ | |
6072 | + size_t offset = ((uintptr_t) (addr) % fpm_pagesize); | |
6073 | + vm_offset_t base = (uintptr_t) (addr) - offset; | |
6074 | + | |
6075 | + if (base != target_page_base) { | |
6076 | + fpm_mach_vm_deallocate(); | |
6077 | + if (0 > fpm_mach_vm_read_page(base)) { | |
6078 | + return -1; | |
6079 | + } | |
6080 | + } | |
6081 | + | |
6082 | + *data = * (long *) (local_page + offset); | |
6083 | + | |
6084 | + return 0; | |
6085 | +} | |
6086 | + | |
37d32ffb ER |
6087 | diff --git a/sapi/cgi/fpm/fpm_trace_pread.c b/sapi/cgi/fpm/fpm_trace_pread.c |
6088 | new file mode 100644 | |
37d32ffb ER |
6089 | --- /dev/null |
6090 | +++ b/sapi/cgi/fpm/fpm_trace_pread.c | |
c6a6bfc9 | 6091 | @@ -0,0 +1,67 @@ |
fd1be940 ER |
6092 | + |
6093 | + /* $Id$ */ | |
c6a6bfc9 ER |
6094 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
6095 | + | |
6096 | +#define _GNU_SOURCE | |
6097 | +#define _FILE_OFFSET_BITS 64 | |
6098 | + | |
6099 | +#include "fpm_config.h" | |
6100 | + | |
6101 | +#include <unistd.h> | |
6102 | + | |
6103 | +#include <fcntl.h> | |
6104 | +#include <stdio.h> | |
6105 | +#include <stdint.h> | |
6106 | + | |
6107 | +#include "fpm_trace.h" | |
6108 | +#include "fpm_process_ctl.h" | |
6109 | +#include "zlog.h" | |
6110 | + | |
6111 | + | |
6112 | +static int mem_file = -1; | |
6113 | + | |
6114 | +int fpm_trace_signal(pid_t pid) | |
6115 | +{ | |
6116 | + if (0 > fpm_pctl_kill(pid, FPM_PCTL_STOP)) { | |
6117 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "kill(SIGSTOP) failed"); | |
6118 | + return -1; | |
6119 | + } | |
6120 | + | |
6121 | + return 0; | |
6122 | +} | |
6123 | + | |
6124 | +int fpm_trace_ready(pid_t pid) | |
6125 | +{ | |
6126 | + char buf[128]; | |
6127 | + | |
6128 | + sprintf(buf, "/proc/%d/" PROC_MEM_FILE, (int) pid); | |
6129 | + | |
6130 | + mem_file = open(buf, O_RDONLY); | |
6131 | + | |
6132 | + if (0 > mem_file) { | |
6133 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(%s) failed", buf); | |
6134 | + return -1; | |
6135 | + } | |
6136 | + | |
6137 | + return 0; | |
6138 | +} | |
6139 | + | |
6140 | +int fpm_trace_close(pid_t pid) | |
6141 | +{ | |
6142 | + close(mem_file); | |
6143 | + | |
6144 | + mem_file = -1; | |
6145 | + | |
6146 | + return 0; | |
6147 | +} | |
6148 | + | |
6149 | +int fpm_trace_get_long(long addr, long *data) | |
6150 | +{ | |
6151 | + if (sizeof(*data) != pread(mem_file, (void *) data, sizeof(*data), (uintptr_t) addr)) { | |
6152 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "pread() failed"); | |
6153 | + return -1; | |
6154 | + } | |
6155 | + | |
6156 | + return 0; | |
6157 | +} | |
6158 | + | |
37d32ffb ER |
6159 | diff --git a/sapi/cgi/fpm/fpm_trace_ptrace.c b/sapi/cgi/fpm/fpm_trace_ptrace.c |
6160 | new file mode 100644 | |
37d32ffb ER |
6161 | --- /dev/null |
6162 | +++ b/sapi/cgi/fpm/fpm_trace_ptrace.c | |
c6a6bfc9 ER |
6163 | @@ -0,0 +1,85 @@ |
6164 | + | |
6165 | + /* $Id$ */ | |
6166 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
6167 | + | |
6168 | +#include "fpm_config.h" | |
6169 | + | |
6170 | +#include <sys/wait.h> | |
6171 | +#include <sys/ptrace.h> | |
6172 | +#include <unistd.h> | |
6173 | +#include <errno.h> | |
6174 | + | |
6175 | +#if defined(PT_ATTACH) && !defined(PTRACE_ATTACH) | |
6176 | +#define PTRACE_ATTACH PT_ATTACH | |
6177 | +#endif | |
6178 | + | |
6179 | +#if defined(PT_DETACH) && !defined(PTRACE_DETACH) | |
6180 | +#define PTRACE_DETACH PT_DETACH | |
6181 | +#endif | |
6182 | + | |
6183 | +#if defined(PT_READ_D) && !defined(PTRACE_PEEKDATA) | |
6184 | +#define PTRACE_PEEKDATA PT_READ_D | |
6185 | +#endif | |
6186 | + | |
6187 | +#include "fpm_trace.h" | |
6188 | +#include "zlog.h" | |
6189 | + | |
6190 | +static pid_t traced_pid; | |
6191 | + | |
6192 | +int fpm_trace_signal(pid_t pid) | |
6193 | +{ | |
6194 | + if (0 > ptrace(PTRACE_ATTACH, pid, 0, 0)) { | |
6195 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(ATTACH) failed"); | |
6196 | + return -1; | |
6197 | + } | |
6198 | + | |
6199 | + return 0; | |
6200 | +} | |
6201 | + | |
6202 | +int fpm_trace_ready(pid_t pid) | |
6203 | +{ | |
6204 | + traced_pid = pid; | |
6205 | + | |
6206 | + return 0; | |
6207 | +} | |
6208 | + | |
6209 | +int fpm_trace_close(pid_t pid) | |
6210 | +{ | |
6211 | + if (0 > ptrace(PTRACE_DETACH, pid, (void *) 1, 0)) { | |
6212 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(DETACH) failed"); | |
6213 | + return -1; | |
6214 | + } | |
6215 | + | |
6216 | + traced_pid = 0; | |
6217 | + | |
6218 | + return 0; | |
6219 | +} | |
6220 | + | |
6221 | +int fpm_trace_get_long(long addr, long *data) | |
6222 | +{ | |
6223 | +#ifdef PT_IO | |
6224 | + struct ptrace_io_desc ptio = { | |
6225 | + .piod_op = PIOD_READ_D, | |
6226 | + .piod_offs = (void *) addr, | |
6227 | + .piod_addr = (void *) data, | |
6228 | + .piod_len = sizeof(long) | |
6229 | + }; | |
6230 | + | |
6231 | + if (0 > ptrace(PT_IO, traced_pid, (void *) &ptio, 0)) { | |
6232 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(PT_IO) failed"); | |
6233 | + return -1; | |
6234 | + } | |
6235 | +#else | |
6236 | + errno = 0; | |
6237 | + | |
6238 | + *data = ptrace(PTRACE_PEEKDATA, traced_pid, (void *) addr, 0); | |
6239 | + | |
6240 | + if (errno) { | |
6241 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "ptrace(PEEKDATA) failed"); | |
6242 | + return -1; | |
6243 | + } | |
6244 | +#endif | |
6245 | + | |
6246 | + return 0; | |
6247 | +} | |
6248 | + | |
37d32ffb ER |
6249 | diff --git a/sapi/cgi/fpm/fpm_unix.c b/sapi/cgi/fpm/fpm_unix.c |
6250 | new file mode 100644 | |
37d32ffb ER |
6251 | --- /dev/null |
6252 | +++ b/sapi/cgi/fpm/fpm_unix.c | |
c6a6bfc9 ER |
6253 | @@ -0,0 +1,289 @@ |
6254 | + | |
6255 | + /* $Id$ */ | |
6256 | + /* (c) 2007,2008 Andrei Nigmatulin */ | |
fd1be940 ER |
6257 | + |
6258 | +#include "fpm_config.h" | |
6259 | + | |
6260 | +#include <string.h> | |
6261 | +#include <sys/time.h> | |
6262 | +#include <sys/resource.h> | |
6263 | +#include <stdlib.h> | |
6264 | +#include <unistd.h> | |
6265 | +#include <sys/types.h> | |
6266 | +#include <pwd.h> | |
6267 | +#include <grp.h> | |
6268 | + | |
c6a6bfc9 | 6269 | +#ifdef HAVE_PRCTL |
fd1be940 ER |
6270 | +#include <sys/prctl.h> |
6271 | +#endif | |
6272 | + | |
c6a6bfc9 | 6273 | +#include "fpm.h" |
fd1be940 ER |
6274 | +#include "fpm_conf.h" |
6275 | +#include "fpm_cleanup.h" | |
c6a6bfc9 | 6276 | +#include "fpm_clock.h" |
fd1be940 ER |
6277 | +#include "fpm_stdio.h" |
6278 | +#include "fpm_unix.h" | |
6279 | +#include "zlog.h" | |
6280 | + | |
c6a6bfc9 ER |
6281 | +size_t fpm_pagesize; |
6282 | + | |
fd1be940 ER |
6283 | +int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp) |
6284 | +{ | |
6285 | + struct fpm_listen_options_s *lo = wp->config->listen_options; | |
6286 | + | |
6287 | + /* uninitialized */ | |
6288 | + wp->socket_uid = -1; | |
6289 | + wp->socket_gid = -1; | |
6290 | + wp->socket_mode = 0666; | |
6291 | + | |
6292 | + if (!lo) return 0; | |
6293 | + | |
6294 | + if (lo->owner && *lo->owner) { | |
6295 | + struct passwd *pwd; | |
6296 | + | |
6297 | + pwd = getpwnam(lo->owner); | |
6298 | + | |
6299 | + if (!pwd) { | |
6300 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "cannot get uid for user '%s', pool '%s'", lo->owner, wp->config->name); | |
6301 | + return -1; | |
6302 | + } | |
6303 | + | |
6304 | + wp->socket_uid = pwd->pw_uid; | |
6305 | + wp->socket_gid = pwd->pw_gid; | |
6306 | + } | |
6307 | + | |
6308 | + if (lo->group && *lo->group) { | |
6309 | + struct group *grp; | |
6310 | + | |
6311 | + grp = getgrnam(lo->group); | |
6312 | + | |
6313 | + if (!grp) { | |
6314 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "cannot get gid for group '%s', pool '%s'", lo->group, wp->config->name); | |
6315 | + return -1; | |
6316 | + } | |
6317 | + | |
6318 | + wp->socket_gid = grp->gr_gid; | |
6319 | + } | |
6320 | + | |
6321 | + if (lo->mode && *lo->mode) { | |
6322 | + wp->socket_mode = strtoul(lo->mode, 0, 8); | |
6323 | + } | |
6324 | + | |
6325 | + return 0; | |
6326 | +} | |
6327 | + | |
6328 | +static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) | |
6329 | +{ | |
6330 | + int is_root = !geteuid(); | |
6331 | + | |
6332 | + if (is_root) { | |
6333 | + if (wp->config->user && *wp->config->user) { | |
fd1be940 | 6334 | + |
c6a6bfc9 ER |
6335 | + if (strlen(wp->config->user) == strspn(wp->config->user, "0123456789")) { |
6336 | + wp->set_uid = strtoul(wp->config->user, 0, 10); | |
fd1be940 | 6337 | + } |
c6a6bfc9 ER |
6338 | + else { |
6339 | + struct passwd *pwd; | |
fd1be940 | 6340 | + |
c6a6bfc9 | 6341 | + pwd = getpwnam(wp->config->user); |
fd1be940 | 6342 | + |
c6a6bfc9 ER |
6343 | + if (!pwd) { |
6344 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "cannot get uid for user '%s', pool '%s'", wp->config->user, wp->config->name); | |
6345 | + return -1; | |
6346 | + } | |
6347 | + | |
6348 | + wp->set_uid = pwd->pw_uid; | |
6349 | + wp->set_gid = pwd->pw_gid; | |
6350 | + | |
6351 | + wp->user = strdup(pwd->pw_name); | |
6352 | + wp->home = strdup(pwd->pw_dir); | |
6353 | + } | |
fd1be940 ER |
6354 | + } |
6355 | + | |
6356 | + if (wp->config->group && *wp->config->group) { | |
fd1be940 | 6357 | + |
c6a6bfc9 ER |
6358 | + if (strlen(wp->config->group) == strspn(wp->config->group, "0123456789")) { |
6359 | + wp->set_gid = strtoul(wp->config->group, 0, 10); | |
fd1be940 | 6360 | + } |
c6a6bfc9 ER |
6361 | + else { |
6362 | + struct group *grp; | |
6363 | + | |
6364 | + grp = getgrnam(wp->config->group); | |
fd1be940 | 6365 | + |
c6a6bfc9 ER |
6366 | + if (!grp) { |
6367 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "cannot get gid for group '%s', pool '%s'", wp->config->group, wp->config->name); | |
6368 | + return -1; | |
6369 | + } | |
6370 | + | |
6371 | + wp->set_gid = grp->gr_gid; | |
6372 | + } | |
fd1be940 ER |
6373 | + } |
6374 | + | |
6375 | +#ifndef I_REALLY_WANT_ROOT_PHP | |
6376 | + if (wp->set_uid == 0 || wp->set_gid == 0) { | |
6377 | + zlog(ZLOG_STUFF, ZLOG_ERROR, "please specify user and group other than root, pool '%s'", wp->config->name); | |
6378 | + return -1; | |
6379 | + } | |
6380 | +#endif | |
6381 | + } | |
6382 | + else { /* not root */ | |
6383 | + if (wp->config->user && *wp->config->user) { | |
6384 | + zlog(ZLOG_STUFF, ZLOG_WARNING, "'user' directive is ignored, pool '%s'", wp->config->name); | |
6385 | + } | |
6386 | + if (wp->config->group && *wp->config->group) { | |
6387 | + zlog(ZLOG_STUFF, ZLOG_WARNING, "'group' directive is ignored, pool '%s'", wp->config->name); | |
6388 | + } | |
6389 | + if (wp->config->chroot && *wp->config->chroot) { | |
6390 | + zlog(ZLOG_STUFF, ZLOG_WARNING, "'chroot' directive is ignored, pool '%s'", wp->config->name); | |
6391 | + } | |
6392 | + | |
6393 | + { /* set up HOME and USER anyway */ | |
6394 | + struct passwd *pwd; | |
6395 | + | |
6396 | + pwd = getpwuid(getuid()); | |
6397 | + | |
6398 | + if (pwd) { | |
6399 | + wp->user = strdup(pwd->pw_name); | |
6400 | + wp->home = strdup(pwd->pw_dir); | |
6401 | + } | |
6402 | + } | |
6403 | + } | |
6404 | + | |
6405 | + return 0; | |
6406 | +} | |
6407 | + | |
6408 | +int fpm_unix_init_child(struct fpm_worker_pool_s *wp) | |
6409 | +{ | |
6410 | + int is_root = !geteuid(); | |
6411 | + int made_chroot = 0; | |
6412 | + | |
6413 | + if (wp->config->rlimit_files) { | |
6414 | + struct rlimit r; | |
6415 | + | |
6416 | + getrlimit(RLIMIT_NOFILE, &r); | |
6417 | + | |
6418 | + r.rlim_cur = (rlim_t) wp->config->rlimit_files; | |
37d32ffb | 6419 | + r.rlim_max = r.rlim_cur; |
fd1be940 ER |
6420 | + if (0 > setrlimit(RLIMIT_NOFILE, &r)) { |
6421 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setrlimit(RLIMIT_NOFILE) failed"); | |
6422 | + } | |
6423 | + } | |
6424 | + | |
6425 | + if (wp->config->rlimit_core) { | |
6426 | + struct rlimit r; | |
6427 | + | |
6428 | + getrlimit(RLIMIT_CORE, &r); | |
6429 | + | |
6430 | + r.rlim_cur = wp->config->rlimit_core == -1 ? (rlim_t) RLIM_INFINITY : (rlim_t) wp->config->rlimit_core; | |
37d32ffb | 6431 | + r.rlim_max = r.rlim_cur; |
fd1be940 ER |
6432 | + if (0 > setrlimit(RLIMIT_CORE, &r)) { |
6433 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setrlimit(RLIMIT_CORE) failed"); | |
6434 | + } | |
6435 | + } | |
6436 | + | |
6437 | + if (is_root && wp->config->chroot && *wp->config->chroot) { | |
6438 | + if (0 > chroot(wp->config->chroot)) { | |
6439 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "chroot(%s) failed", wp->config->chroot); | |
6440 | + return -1; | |
6441 | + } | |
6442 | + made_chroot = 1; | |
6443 | + } | |
6444 | + | |
6445 | + if (wp->config->chdir && *wp->config->chdir) { | |
6446 | + if (0 > chdir(wp->config->chdir)) { | |
6447 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "chdir(%s) failed", wp->config->chdir); | |
6448 | + return -1; | |
6449 | + } | |
6450 | + } | |
6451 | + else if (made_chroot) { | |
6452 | + chdir("/"); | |
6453 | + } | |
6454 | + | |
6455 | + if (is_root) { | |
6456 | + if (wp->set_gid) { | |
c6a6bfc9 ER |
6457 | + if (0 > setgid(wp->set_gid)) { |
6458 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setgid(%d) failed", wp->set_gid); | |
6459 | + return -1; | |
6460 | + } | |
fd1be940 ER |
6461 | + } |
6462 | + if (wp->set_uid) { | |
c6a6bfc9 ER |
6463 | + if (0 > initgroups(wp->config->user, wp->set_gid)) { |
6464 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "initgroups(%s, %d) failed", wp->config->user, wp->set_gid); | |
6465 | + return -1; | |
6466 | + } | |
6467 | + if (0 > setuid(wp->set_uid)) { | |
6468 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "setuid(%d) failed", wp->set_uid); | |
6469 | + return -1; | |
6470 | + } | |
fd1be940 ER |
6471 | + } |
6472 | + } | |
6473 | + | |
c6a6bfc9 | 6474 | +#ifdef HAVE_PRCTL |
fd1be940 ER |
6475 | + if (0 > prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) { |
6476 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "prctl(PR_SET_DUMPABLE) failed"); | |
6477 | + } | |
6478 | +#endif | |
6479 | + | |
c6a6bfc9 ER |
6480 | + if (0 > fpm_clock_init()) { |
6481 | + return -1; | |
6482 | + } | |
6483 | + | |
fd1be940 ER |
6484 | + return 0; |
6485 | +} | |
6486 | + | |
6487 | +int fpm_unix_init_main() | |
6488 | +{ | |
6489 | + struct fpm_worker_pool_s *wp; | |
6490 | + | |
c6a6bfc9 ER |
6491 | + fpm_pagesize = getpagesize(); |
6492 | + | |
48b142c9 | 6493 | + if (fpm_global_config.daemonize) { |
fd1be940 ER |
6494 | + |
6495 | + switch (fork()) { | |
6496 | + | |
6497 | + case -1 : | |
6498 | + | |
6499 | + zlog(ZLOG_STUFF, ZLOG_SYSERROR, "fork() failed"); | |
6500 | + return -1; | |
6501 | + | |
6502 | + case 0 : | |
6503 | + | |
6504 | + break; | |
6505 | + | |
6506 | + default : | |
6507 | + | |
6508 | + fpm_cleanups_run(FPM_CLEANUP_PARENT_EXIT); | |
6509 | + exit(0); | |
6510 | + | |
6511 | + } | |
6512 | + | |
6513 | + } | |
6514 | + | |
6515 | + setsid(); | |
6516 | + | |
c6a6bfc9 ER |
6517 | + if (0 > fpm_clock_init()) { |
6518 | + return -1; | |
6519 | + } | |
6520 | + | |
6521 | + fpm_globals.parent_pid = getpid(); | |
6522 | + | |
fd1be940 ER |
6523 | + for (wp = fpm_worker_all_pools; wp; wp = wp->next) { |
6524 | + | |
6525 | + if (0 > fpm_unix_conf_wp(wp)) { | |
6526 | + return -1; | |
6527 | + } | |
6528 | + | |
6529 | + } | |
6530 | + | |
6531 | + fpm_stdio_init_final(); | |
6532 | + | |
c6a6bfc9 ER |
6533 | + { |
6534 | + struct rlimit r; | |
6535 | + getrlimit(RLIMIT_NOFILE, &r); | |
6536 | + | |
6537 | + zlog(ZLOG_STUFF, ZLOG_NOTICE, "getrlimit(nofile): max:%lld, cur:%lld", | |
6538 | + (long long) r.rlim_max, (long long) r.rlim_cur); | |
6539 | + } | |
6540 | + | |
fd1be940 ER |
6541 | + return 0; |
6542 | +} | |
37d32ffb ER |
6543 | diff --git a/sapi/cgi/fpm/fpm_unix.h b/sapi/cgi/fpm/fpm_unix.h |
6544 | new file mode 100644 | |
37d32ffb ER |
6545 | --- /dev/null |
6546 | +++ b/sapi/cgi/fpm/fpm_unix.h | |
c6a6bfc9 | 6547 | @@ -0,0 +1,17 @@ |
fd1be940 ER |
6548 | + |
6549 | + /* $Id$ */ | |
c6a6bfc9 | 6550 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
6551 | + |
6552 | +#ifndef FPM_UNIX_H | |
6553 | +#define FPM_UNIX_H 1 | |
6554 | + | |
6555 | +#include "fpm_worker_pool.h" | |
6556 | + | |
6557 | +int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp); | |
6558 | +int fpm_unix_init_child(struct fpm_worker_pool_s *wp); | |
6559 | +int fpm_unix_init_main(); | |
6560 | + | |
c6a6bfc9 ER |
6561 | +extern size_t fpm_pagesize; |
6562 | + | |
fd1be940 ER |
6563 | +#endif |
6564 | + | |
37d32ffb ER |
6565 | diff --git a/sapi/cgi/fpm/fpm_worker_pool.c b/sapi/cgi/fpm/fpm_worker_pool.c |
6566 | new file mode 100644 | |
37d32ffb ER |
6567 | --- /dev/null |
6568 | +++ b/sapi/cgi/fpm/fpm_worker_pool.c | |
48b142c9 | 6569 | @@ -0,0 +1,69 @@ |
fd1be940 ER |
6570 | + |
6571 | + /* $Id$ */ | |
c6a6bfc9 | 6572 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
6573 | + |
6574 | +#include "fpm_config.h" | |
6575 | + | |
6576 | +#include <string.h> | |
6577 | +#include <stdlib.h> | |
6578 | +#include <unistd.h> | |
6579 | + | |
6580 | +#include "fpm_worker_pool.h" | |
6581 | +#include "fpm_cleanup.h" | |
6582 | +#include "fpm_children.h" | |
c6a6bfc9 ER |
6583 | +#include "fpm_shm.h" |
6584 | +#include "fpm_shm_slots.h" | |
fd1be940 ER |
6585 | +#include "fpm_conf.h" |
6586 | + | |
6587 | +struct fpm_worker_pool_s *fpm_worker_all_pools; | |
6588 | + | |
c6a6bfc9 | 6589 | +static void fpm_worker_pool_cleanup(int which, void *arg) |
fd1be940 ER |
6590 | +{ |
6591 | + struct fpm_worker_pool_s *wp, *wp_next; | |
6592 | + | |
6593 | + for (wp = fpm_worker_all_pools; wp; wp = wp_next) { | |
6594 | + wp_next = wp->next; | |
6595 | + fpm_worker_pool_config_free(wp->config); | |
6596 | + fpm_children_free(wp->children); | |
c6a6bfc9 ER |
6597 | + fpm_array_free(&wp->slots_used); |
6598 | + fpm_array_free(&wp->slots_free); | |
6599 | + fpm_shm_free_list(wp->shm_list, which == FPM_CLEANUP_CHILD ? fpm_shm_slots_mem() : 0); | |
fd1be940 ER |
6600 | + free(wp->config); |
6601 | + free(wp->user); | |
6602 | + free(wp->home); | |
6603 | + free(wp); | |
6604 | + } | |
6605 | + | |
6606 | + fpm_worker_all_pools = 0; | |
6607 | +} | |
6608 | + | |
6609 | +struct fpm_worker_pool_s *fpm_worker_pool_alloc() | |
6610 | +{ | |
6611 | + struct fpm_worker_pool_s *ret; | |
6612 | + | |
6613 | + ret = malloc(sizeof(struct fpm_worker_pool_s)); | |
6614 | + | |
6615 | + if (!ret) { | |
6616 | + return 0; | |
6617 | + } | |
6618 | + | |
6619 | + memset(ret, 0, sizeof(struct fpm_worker_pool_s)); | |
6620 | + | |
6621 | + if (!fpm_worker_all_pools) { | |
6622 | + fpm_worker_all_pools = ret; | |
6623 | + } | |
6624 | + | |
c6a6bfc9 ER |
6625 | + fpm_array_init(&ret->slots_used, sizeof(struct fpm_shm_slot_ptr_s), 50); |
6626 | + fpm_array_init(&ret->slots_free, sizeof(struct fpm_shm_slot_ptr_s), 50); | |
6627 | + | |
fd1be940 ER |
6628 | + return ret; |
6629 | +} | |
6630 | + | |
6631 | +int fpm_worker_pool_init_main() | |
6632 | +{ | |
48b142c9 ER |
6633 | + if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_worker_pool_cleanup, 0)) { |
6634 | + return -1; | |
6635 | + } | |
fd1be940 ER |
6636 | + |
6637 | + return 0; | |
6638 | +} | |
37d32ffb ER |
6639 | diff --git a/sapi/cgi/fpm/fpm_worker_pool.h b/sapi/cgi/fpm/fpm_worker_pool.h |
6640 | new file mode 100644 | |
37d32ffb ER |
6641 | --- /dev/null |
6642 | +++ b/sapi/cgi/fpm/fpm_worker_pool.h | |
c6a6bfc9 | 6643 | @@ -0,0 +1,46 @@ |
fd1be940 ER |
6644 | + |
6645 | + /* $Id$ */ | |
c6a6bfc9 | 6646 | + /* (c) 2007,2008 Andrei Nigmatulin */ |
fd1be940 ER |
6647 | + |
6648 | +#ifndef FPM_WORKER_POOL_H | |
6649 | +#define FPM_WORKER_POOL_H 1 | |
6650 | + | |
6651 | +#include "fpm_conf.h" | |
c6a6bfc9 | 6652 | +#include "fpm_arrays.h" |
fd1be940 ER |
6653 | + |
6654 | +struct fpm_worker_pool_s; | |
6655 | +struct fpm_child_s; | |
c6a6bfc9 ER |
6656 | +struct fpm_child_stat_s; |
6657 | +struct fpm_shm_s; | |
fd1be940 ER |
6658 | + |
6659 | +enum fpm_address_domain { | |
6660 | + FPM_AF_UNIX = 1, | |
6661 | + FPM_AF_INET = 2 | |
6662 | +}; | |
6663 | + | |
6664 | +struct fpm_worker_pool_s { | |
6665 | + struct fpm_worker_pool_s *next; | |
6666 | + struct fpm_worker_pool_config_s *config; | |
6667 | + char *user, *home; /* for setting env USER and HOME */ | |
6668 | + enum fpm_address_domain listen_address_domain; | |
6669 | + int listening_socket; | |
6670 | + int set_uid, set_gid; /* config uid and gid */ | |
c6a6bfc9 | 6671 | + unsigned is_template:1; /* just config template, no processes will be created */ |
fd1be940 ER |
6672 | + int socket_uid, socket_gid, socket_mode; |
6673 | + | |
c6a6bfc9 ER |
6674 | + struct fpm_shm_s *shm_list; |
6675 | + struct fpm_array_s slots_used; | |
6676 | + struct fpm_array_s slots_free; | |
6677 | + | |
fd1be940 ER |
6678 | + /* runtime */ |
6679 | + struct fpm_child_s *children; | |
fd1be940 ER |
6680 | + int running_children; |
6681 | +}; | |
6682 | + | |
6683 | +struct fpm_worker_pool_s *fpm_worker_pool_alloc(); | |
6684 | +int fpm_worker_pool_init_main(); | |
6685 | + | |
6686 | +extern struct fpm_worker_pool_s *fpm_worker_all_pools; | |
6687 | + | |
6688 | +#endif | |
6689 | + | |
37d32ffb ER |
6690 | diff --git a/sapi/cgi/fpm/init.d/php-fpm.in b/sapi/cgi/fpm/init.d/php-fpm.in |
6691 | new file mode 100644 | |
37d32ffb ER |
6692 | --- /dev/null |
6693 | +++ b/sapi/cgi/fpm/init.d/php-fpm.in | |
c6a6bfc9 ER |
6694 | @@ -0,0 +1,139 @@ |
6695 | +#! /bin/sh | |
6696 | + | |
6697 | +php_fpm_BIN=@prefix@/bin/php-cgi | |
6698 | +php_fpm_CONF=@php_fpm_conf_path@ | |
6699 | +php_fpm_PID=@php_fpm_pid_path@ | |
6700 | + | |
6701 | + | |
6702 | +php_opts="--fpm-config $php_fpm_CONF" | |
6703 | + | |
6704 | + | |
6705 | +wait_for_pid () { | |
6706 | + try=0 | |
6707 | + | |
6708 | + while test $try -lt 35 ; do | |
6709 | + | |
6710 | + case "$1" in | |
6711 | + 'created') | |
6712 | + if [ -f "$2" ] ; then | |
6713 | + try='' | |
6714 | + break | |
6715 | + fi | |
6716 | + ;; | |
6717 | + | |
6718 | + 'removed') | |
6719 | + if [ ! -f "$2" ] ; then | |
6720 | + try='' | |
6721 | + break | |
6722 | + fi | |
6723 | + ;; | |
6724 | + esac | |
6725 | + | |
6726 | + echo -n . | |
6727 | + try=`expr $try + 1` | |
6728 | + sleep 1 | |
6729 | + | |
6730 | + done | |
6731 | + | |
6732 | +} | |
6733 | + | |
6734 | +case "$1" in | |
6735 | + start) | |
6736 | + echo -n "Starting php_fpm " | |
6737 | + | |
6738 | + $php_fpm_BIN --fpm $php_opts | |
6739 | + | |
6740 | + if [ "$?" != 0 ] ; then | |
6741 | + echo " failed" | |
6742 | + exit 1 | |
6743 | + fi | |
6744 | + | |
6745 | + wait_for_pid created $php_fpm_PID | |
6746 | + | |
6747 | + if [ -n "$try" ] ; then | |
6748 | + echo " failed" | |
6749 | + exit 1 | |
6750 | + else | |
6751 | + echo " done" | |
6752 | + fi | |
6753 | + ;; | |
6754 | + | |
6755 | + stop) | |
6756 | + echo -n "Shutting down php_fpm " | |
6757 | + | |
6758 | + if [ ! -r $php_fpm_PID ] ; then | |
6759 | + echo "warning, no pid file found - php-fpm is not running ?" | |
6760 | + exit 1 | |
6761 | + fi | |
6762 | + | |
6763 | + kill -TERM `cat $php_fpm_PID` | |
6764 | + | |
6765 | + wait_for_pid removed $php_fpm_PID | |
6766 | + | |
6767 | + if [ -n "$try" ] ; then | |
6768 | + echo " failed" | |
6769 | + exit 1 | |
6770 | + else | |
6771 | + echo " done" | |
6772 | + fi | |
6773 | + ;; | |
6774 | + | |
6775 | + quit) | |
6776 | + echo -n "Gracefully shutting down php_fpm " | |
fd1be940 | 6777 | + |
c6a6bfc9 ER |
6778 | + if [ ! -r $php_fpm_PID ] ; then |
6779 | + echo "warning, no pid file found - php-fpm is not running ?" | |
6780 | + exit 1 | |
6781 | + fi | |
6782 | + | |
6783 | + kill -QUIT `cat $php_fpm_PID` | |
6784 | + | |
6785 | + wait_for_pid removed $php_fpm_PID | |
6786 | + | |
6787 | + if [ -n "$try" ] ; then | |
6788 | + echo " failed" | |
6789 | + exit 1 | |
6790 | + else | |
6791 | + echo " done" | |
6792 | + fi | |
6793 | + ;; | |
6794 | + | |
6795 | + restart) | |
6796 | + $0 stop | |
6797 | + $0 start | |
6798 | + ;; | |
6799 | + | |
6800 | + reload) | |
6801 | + | |
6802 | + echo -n "Reload service php-fpm " | |
6803 | + | |
6804 | + if [ ! -r $php_fpm_PID ] ; then | |
6805 | + echo "warning, no pid file found - php-fpm is not running ?" | |
6806 | + exit 1 | |
6807 | + fi | |
6808 | + | |
6809 | + kill -USR2 `cat $php_fpm_PID` | |
6810 | + | |
6811 | + echo " done" | |
6812 | + ;; | |
6813 | + | |
6814 | + logrotate) | |
6815 | + | |
6816 | + echo -n "Re-opening php-fpm log file " | |
6817 | + | |
6818 | + if [ ! -r $php_fpm_PID ] ; then | |
6819 | + echo "warning, no pid file found - php-fpm is not running ?" | |
6820 | + exit 1 | |
6821 | + fi | |
6822 | + | |
6823 | + kill -USR1 `cat $php_fpm_PID` | |
6824 | + | |
6825 | + echo " done" | |
6826 | + ;; | |
6827 | + | |
6828 | + *) | |
6829 | + echo "Usage: $0 {start|stop|quit|restart|reload|logrotate}" | |
6830 | + exit 1 | |
6831 | + ;; | |
6832 | + | |
6833 | +esac | |
37d32ffb ER |
6834 | diff --git a/sapi/cgi/fpm/xml_config.c b/sapi/cgi/fpm/xml_config.c |
6835 | new file mode 100644 | |
37d32ffb ER |
6836 | --- /dev/null |
6837 | +++ b/sapi/cgi/fpm/xml_config.c | |
fd1be940 ER |
6838 | @@ -0,0 +1,278 @@ |
6839 | + | |
6840 | + /* $Id$ */ | |
6841 | + /* (c) 2004-2007 Andrei Nigmatulin */ | |
6842 | + | |
6843 | +#include "fpm_config.h" | |
6844 | + | |
6845 | +#ifdef HAVE_ALLOCA_H | |
6846 | +#include <alloca.h> | |
6847 | +#endif | |
6848 | +#include <string.h> | |
6849 | +#include <stdio.h> | |
6850 | +#include <stddef.h> | |
6851 | +#include <stdlib.h> | |
6852 | + | |
6853 | +#include <libxml/parser.h> | |
6854 | +#include <libxml/tree.h> | |
6855 | + | |
6856 | +#include "xml_config.h" | |
6857 | + | |
6858 | +static struct xml_conf_section **xml_conf_sections = 0; | |
6859 | +static int xml_conf_sections_allocated = 0; | |
6860 | +static int xml_conf_sections_used = 0; | |
6861 | + | |
6862 | +char *xml_conf_set_slot_boolean(void **conf, char *name, void *vv, intptr_t offset) | |
6863 | +{ | |
6864 | + char *value = vv; | |
6865 | + long value_y = !strcasecmp(value, "yes") || !strcmp(value, "1") || !strcasecmp(value, "on"); | |
6866 | + long value_n = !strcasecmp(value, "no") || !strcmp(value, "0") || !strcasecmp(value, "off"); | |
6867 | + | |
6868 | + if (!value_y && !value_n) { | |
6869 | + return "xml_conf_set_slot(): invalid boolean value"; | |
6870 | + } | |
6871 | + | |
6872 | +#ifdef XML_CONF_DEBUG | |
6873 | + fprintf(stderr, "setting boolean '%s' => %s\n", name, value_y ? "TRUE" : "FALSE"); | |
6874 | +#endif | |
6875 | + | |
6876 | + * (int *) ((char *) *conf + offset) = value_y ? 1 : 0; | |
6877 | + | |
6878 | + return NULL; | |
6879 | +} | |
6880 | + | |
6881 | +char *xml_conf_set_slot_string(void **conf, char *name, void *vv, intptr_t offset) | |
6882 | +{ | |
6883 | + char *value = vv; | |
6884 | + char *v = strdup(value); | |
6885 | + | |
6886 | + if (!v) return "xml_conf_set_slot_string(): strdup() failed"; | |
6887 | + | |
6888 | +#ifdef XML_CONF_DEBUG | |
6889 | + fprintf(stderr, "setting string '%s' => '%s'\n", name, v); | |
6890 | +#endif | |
6891 | + | |
6892 | + * (char **) ((char *) *conf + offset) = v; | |
6893 | + | |
6894 | + return NULL; | |
6895 | +} | |
6896 | + | |
6897 | +char *xml_conf_set_slot_integer(void **conf, char *name, void *vv, intptr_t offset) | |
6898 | +{ | |
6899 | + char *value = vv; | |
6900 | + int v = atoi(value); | |
6901 | + | |
6902 | + * (int *) ((char *) *conf + offset) = v; | |
6903 | + | |
6904 | +#ifdef XML_CONF_DEBUG | |
6905 | + fprintf(stderr, "setting integer '%s' => %d\n", name, v); | |
6906 | +#endif | |
6907 | + | |
6908 | + return NULL; | |
6909 | +} | |
6910 | + | |
6911 | +char *xml_conf_set_slot_time(void **conf, char *name, void *vv, intptr_t offset) | |
6912 | +{ | |
6913 | + char *value = vv; | |
6914 | + int len = strlen(value); | |
6915 | + char suffix; | |
6916 | + int seconds; | |
6917 | + | |
6918 | + if (!len) return "xml_conf_set_slot_timeval(): invalid timeval value"; | |
6919 | + | |
6920 | + suffix = value[len-1]; | |
6921 | + | |
6922 | + value[len-1] = '\0'; | |
6923 | + | |
6924 | + switch (suffix) { | |
6925 | + case 's' : | |
6926 | + seconds = atoi(value); | |
6927 | + break; | |
6928 | + case 'm' : | |
6929 | + seconds = 60 * atoi(value); | |
6930 | + break; | |
6931 | + case 'h' : | |
6932 | + seconds = 60 * 60 * atoi(value); | |
6933 | + break; | |
6934 | + case 'd' : | |
6935 | + seconds = 24 * 60 * 60 * atoi(value); | |
6936 | + break; | |
6937 | + default : | |
6938 | + return "xml_conf_set_slot_timeval(): unknown suffix used in timeval value"; | |
6939 | + } | |
6940 | + | |
6941 | + * (int *) ((char *) *conf + offset) = seconds; | |
6942 | + | |
6943 | +#ifdef XML_CONF_DEBUG | |
6944 | + fprintf(stderr, "setting time '%s' => %d:%02d:%02d:%02d\n", name, expand_dhms(seconds)); | |
6945 | +#endif | |
6946 | + | |
6947 | + return NULL; | |
6948 | +} | |
6949 | + | |
6950 | +char *xml_conf_parse_section(void **conf, struct xml_conf_section *section, void *xml_node) | |
6951 | +{ | |
6952 | + xmlNode *element = xml_node; | |
6953 | + char *ret = 0; | |
6954 | + | |
6955 | +#ifdef XML_CONF_DEBUG | |
6956 | + fprintf(stderr, "processing a section %s\n", section->path); | |
6957 | +#endif | |
6958 | + | |
6959 | + for ( ; element; element = element->next) { | |
6960 | + if (element->type == XML_ELEMENT_NODE && !strcmp((const char *) element->name, "value") && element->children) { | |
6961 | + xmlChar *name = xmlGetProp(element, (unsigned char *) "name"); | |
6962 | + | |
6963 | + if (name) { | |
6964 | + int i; | |
6965 | + | |
6966 | +#ifdef XML_CONF_DEBUG | |
6967 | + fprintf(stderr, "found a value: %s\n", name); | |
6968 | +#endif | |
6969 | + for (i = 0; section->parsers[i].parser; i++) { | |
6970 | + if (!section->parsers[i].name || !strcmp(section->parsers[i].name, (char *) name)) { | |
6971 | + break; | |
6972 | + } | |
6973 | + } | |
6974 | + | |
6975 | + if (section->parsers[i].parser) { | |
6976 | + if (section->parsers[i].type == XML_CONF_SCALAR) { | |
6977 | + if (element->children->type == XML_TEXT_NODE) { | |
6978 | + ret = section->parsers[i].parser(conf, (char *) name, element->children->content, section->parsers[i].offset); | |
6979 | + } | |
6980 | + else { | |
6981 | + ret = "XML_TEXT_NODE is expected, something different is given"; | |
6982 | + } | |
6983 | + } | |
6984 | + else { | |
6985 | + ret = section->parsers[i].parser(conf, (char *) name, element->children, section->parsers[i].offset); | |
6986 | + } | |
6987 | + | |
6988 | + xmlFree(name); | |
6989 | + if (ret) return ret; | |
6990 | + else continue; | |
6991 | + } | |
6992 | + | |
c6a6bfc9 | 6993 | + fprintf(stderr, "Warning, unknown setting '%s' in section '%s'\n", (char *) name, section->path); |
fd1be940 ER |
6994 | + |
6995 | + xmlFree(name); | |
6996 | + } | |
6997 | + } | |
6998 | + } | |
6999 | + | |
7000 | + return NULL; | |
7001 | +} | |
7002 | + | |
7003 | +static char *xml_conf_parse_file(xmlNode *element) | |
7004 | +{ | |
7005 | + char *ret = 0; | |
7006 | + | |
7007 | + for ( ; element; element = element->next) { | |
7008 | + | |
7009 | + if (element->parent && element->type == XML_ELEMENT_NODE && !strcmp((const char *) element->name, "section")) { | |
7010 | + xmlChar *name = xmlGetProp(element, (unsigned char *) "name"); | |
7011 | + | |
7012 | + if (name) { | |
7013 | + char *parent_name = (char *) xmlGetNodePath(element->parent); | |
7014 | + char *full_name; | |
7015 | + int i; | |
7016 | + struct xml_conf_section *section = NULL; | |
7017 | + | |
7018 | +#ifdef XML_CONF_DEBUG | |
7019 | + fprintf(stderr, "got a section: %s/%s\n", parent_name, name); | |
7020 | +#endif | |
7021 | + full_name = alloca(strlen(parent_name) + strlen((char *) name) + 1 + 1); | |
7022 | + | |
c6a6bfc9 | 7023 | + sprintf(full_name, "%s/%s", parent_name, (char *) name); |
fd1be940 ER |
7024 | + |
7025 | + xmlFree(parent_name); | |
7026 | + xmlFree(name); | |
7027 | + | |
7028 | + for (i = 0; i < xml_conf_sections_used; i++) { | |
7029 | + if (!strcmp(xml_conf_sections[i]->path, full_name)) { | |
7030 | + section = xml_conf_sections[i]; | |
7031 | + } | |
7032 | + } | |
7033 | + | |
7034 | + if (section) { /* found a registered section */ | |
7035 | + void *conf = section->conf(); | |
7036 | + ret = xml_conf_parse_section(&conf, section, element->children); | |
7037 | + if (ret) break; | |
7038 | + } | |
7039 | + | |
7040 | + } | |
7041 | + } | |
7042 | + | |
7043 | + if (element->children) { | |
7044 | + ret = xml_conf_parse_file(element->children); | |
7045 | + if (ret) break; | |
7046 | + } | |
7047 | + } | |
7048 | + | |
7049 | + return ret; | |
7050 | +} | |
7051 | + | |
7052 | +char *xml_conf_load_file(char *file) | |
7053 | +{ | |
7054 | + char *ret = 0; | |
7055 | + xmlDoc *doc; | |
7056 | + | |
7057 | + LIBXML_TEST_VERSION | |
7058 | + | |
7059 | + doc = xmlParseFile(file); | |
7060 | + | |
7061 | + if (doc) { | |
7062 | + ret = xml_conf_parse_file(doc->children); | |
7063 | + xmlFreeDoc(doc); | |
7064 | + } | |
7065 | + else { | |
7066 | + ret = "failed to parse conf file"; | |
7067 | + } | |
7068 | + | |
7069 | + xmlCleanupParser(); | |
7070 | + return ret; | |
7071 | +} | |
7072 | + | |
7073 | +int xml_conf_init() | |
7074 | +{ | |
7075 | + return 0; | |
7076 | +} | |
7077 | + | |
7078 | +void xml_conf_clean() | |
7079 | +{ | |
7080 | + if (xml_conf_sections) { | |
7081 | + free(xml_conf_sections); | |
7082 | + } | |
7083 | +} | |
7084 | + | |
7085 | +int xml_conf_section_register(struct xml_conf_section *section) | |
7086 | +{ | |
7087 | + if (xml_conf_sections_allocated == xml_conf_sections_used) { | |
7088 | + int new_size = xml_conf_sections_used + 10; | |
7089 | + void *new_ptr = realloc(xml_conf_sections, sizeof(struct xml_conf_section *) * new_size); | |
7090 | + | |
7091 | + if (new_ptr) { | |
7092 | + xml_conf_sections = new_ptr; | |
7093 | + xml_conf_sections_allocated = new_size; | |
7094 | + } | |
7095 | + else { | |
7096 | + fprintf(stderr, "xml_conf_section_register(): out of memory\n"); | |
7097 | + return -1; | |
7098 | + } | |
7099 | + } | |
7100 | + | |
7101 | + xml_conf_sections[xml_conf_sections_used++] = section; | |
7102 | + | |
7103 | + return 0; | |
7104 | +} | |
7105 | + | |
7106 | +int xml_conf_sections_register(struct xml_conf_section *sections[]) | |
7107 | +{ | |
7108 | + for ( ; sections && *sections; sections++) { | |
7109 | + if (0 > xml_conf_section_register(*sections)) { | |
7110 | + return -1; | |
7111 | + } | |
7112 | + } | |
7113 | + | |
7114 | + return 0; | |
7115 | +} | |
7116 | + | |
37d32ffb ER |
7117 | diff --git a/sapi/cgi/fpm/xml_config.h b/sapi/cgi/fpm/xml_config.h |
7118 | new file mode 100644 | |
37d32ffb ER |
7119 | --- /dev/null |
7120 | +++ b/sapi/cgi/fpm/xml_config.h | |
fd1be940 ER |
7121 | @@ -0,0 +1,43 @@ |
7122 | + | |
7123 | + /* $Id$ */ | |
7124 | + /* (c) 2004-2007 Andrei Nigmatulin */ | |
7125 | + | |
7126 | +#ifndef XML_CONFIG_H | |
7127 | +#define XML_CONFIG_H 1 | |
7128 | + | |
7129 | +#include <stdint.h> | |
7130 | + | |
7131 | +struct xml_value_parser; | |
7132 | + | |
7133 | +struct xml_value_parser { | |
7134 | + int type; | |
7135 | + char *name; | |
7136 | + char *(*parser)(void **, char *, void *, intptr_t offset); | |
7137 | + intptr_t offset; | |
7138 | +}; | |
7139 | + | |
7140 | +struct xml_conf_section { | |
7141 | + void *(*conf)(); | |
7142 | + char *path; | |
c6a6bfc9 | 7143 | + struct xml_value_parser *parsers; |
fd1be940 ER |
7144 | +}; |
7145 | + | |
7146 | +char *xml_conf_set_slot_boolean(void **conf, char *name, void *value, intptr_t offset); | |
7147 | +char *xml_conf_set_slot_string(void **conf, char *name, void *value, intptr_t offset); | |
7148 | +char *xml_conf_set_slot_integer(void **conf, char *name, void *value, intptr_t offset); | |
7149 | +char *xml_conf_set_slot_time(void **conf, char *name, void *value, intptr_t offset); | |
7150 | + | |
7151 | +int xml_conf_init(); | |
7152 | +void xml_conf_clean(); | |
7153 | +char *xml_conf_load_file(char *file); | |
7154 | +char *xml_conf_parse_section(void **conf, struct xml_conf_section *section, void *ve); | |
7155 | +int xml_conf_section_register(struct xml_conf_section *section); | |
7156 | +int xml_conf_sections_register(struct xml_conf_section *sections[]); | |
7157 | + | |
7158 | +#define expand_hms(value) (value) / 3600, ((value) % 3600) / 60, (value) % 60 | |
7159 | + | |
7160 | +#define expand_dhms(value) (value) / 86400, ((value) % 86400) / 3600, ((value) % 3600) / 60, (value) % 60 | |
7161 | + | |
7162 | +enum { XML_CONF_SCALAR = 1, XML_CONF_SUBSECTION = 2 }; | |
7163 | + | |
7164 | +#endif | |
37d32ffb ER |
7165 | diff --git a/sapi/cgi/fpm/zlog.c b/sapi/cgi/fpm/zlog.c |
7166 | new file mode 100644 | |
37d32ffb ER |
7167 | --- /dev/null |
7168 | +++ b/sapi/cgi/fpm/zlog.c | |
c6a6bfc9 | 7169 | @@ -0,0 +1,113 @@ |
fd1be940 ER |
7170 | + |
7171 | + /* $Id$ */ | |
7172 | + /* (c) 2004-2007 Andrei Nigmatulin */ | |
7173 | + | |
7174 | +#include "fpm_config.h" | |
7175 | + | |
7176 | +#include <stdio.h> | |
7177 | +#include <unistd.h> | |
7178 | +#include <time.h> | |
7179 | +#include <string.h> | |
7180 | +#include <stdarg.h> | |
7181 | +#include <sys/time.h> | |
7182 | +#include <errno.h> | |
7183 | + | |
7184 | +#include "zlog.h" | |
7185 | + | |
7186 | +#define MAX_LINE_LENGTH 1024 | |
7187 | + | |
7188 | +static int zlog_fd = -1; | |
c6a6bfc9 | 7189 | +static int zlog_level = ZLOG_NOTICE; |
fd1be940 ER |
7190 | + |
7191 | +static const char *level_names[] = { | |
7192 | + [ZLOG_DEBUG] = "DEBUG", | |
7193 | + [ZLOG_NOTICE] = "NOTICE", | |
7194 | + [ZLOG_WARNING] = "WARNING", | |
7195 | + [ZLOG_ERROR] = "ERROR", | |
7196 | + [ZLOG_ALERT] = "ALERT", | |
7197 | +}; | |
7198 | + | |
c6a6bfc9 | 7199 | +size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len) |
fd1be940 | 7200 | +{ |
fd1be940 ER |
7201 | + struct tm t; |
7202 | + size_t len; | |
7203 | + | |
c6a6bfc9 ER |
7204 | + len = strftime(timebuf, timebuf_len, "%b %d %H:%M:%S", localtime_r((const time_t *) &tv->tv_sec, &t)); |
7205 | + len += snprintf(timebuf + len, timebuf_len - len, ".%06d", (int) tv->tv_usec); | |
fd1be940 ER |
7206 | + |
7207 | + return len; | |
7208 | +} | |
7209 | + | |
7210 | +int zlog_set_fd(int new_fd) | |
7211 | +{ | |
7212 | + int old_fd = zlog_fd; | |
7213 | + zlog_fd = new_fd; | |
7214 | + | |
7215 | + return old_fd; | |
7216 | +} | |
7217 | + | |
c6a6bfc9 ER |
7218 | +int zlog_set_level(int new_value) |
7219 | +{ | |
7220 | + int old_value = zlog_level; | |
7221 | + | |
7222 | + zlog_level = new_value; | |
7223 | + | |
7224 | + return old_value; | |
7225 | +} | |
7226 | + | |
fd1be940 ER |
7227 | +void zlog(const char *function, int line, int flags, const char *fmt, ...) |
7228 | +{ | |
c6a6bfc9 | 7229 | + struct timeval tv; |
fd1be940 ER |
7230 | + char buf[MAX_LINE_LENGTH]; |
7231 | + const size_t buf_size = MAX_LINE_LENGTH; | |
7232 | + va_list args; | |
7233 | + size_t len; | |
7234 | + int truncated = 0; | |
c6a6bfc9 | 7235 | + int saved_errno; |
fd1be940 | 7236 | + |
c6a6bfc9 ER |
7237 | + if ((flags & ZLOG_LEVEL_MASK) < zlog_level) { |
7238 | + return; | |
7239 | + } | |
7240 | + | |
7241 | + saved_errno = errno; | |
7242 | + | |
7243 | + gettimeofday(&tv, 0); | |
7244 | + | |
7245 | + len = zlog_print_time(&tv, buf, buf_size); | |
fd1be940 ER |
7246 | + |
7247 | + len += snprintf(buf + len, buf_size - len, " [%s] %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line); | |
7248 | + | |
7249 | + if (len > buf_size - 1) { | |
7250 | + truncated = 1; | |
7251 | + } | |
7252 | + | |
7253 | + if (!truncated) { | |
7254 | + va_start(args, fmt); | |
7255 | + | |
7256 | + len += vsnprintf(buf + len, buf_size - len, fmt, args); | |
7257 | + | |
7258 | + va_end(args); | |
7259 | + | |
7260 | + if (len >= buf_size) { | |
7261 | + truncated = 1; | |
7262 | + } | |
7263 | + } | |
7264 | + | |
7265 | + if (!truncated) { | |
7266 | + if (flags & ZLOG_HAVE_ERRNO) { | |
7267 | + len += snprintf(buf + len, buf_size - len, ": %s (%d)", strerror(saved_errno), saved_errno); | |
7268 | + if (len >= buf_size) { | |
7269 | + truncated = 1; | |
7270 | + } | |
7271 | + } | |
7272 | + } | |
7273 | + | |
7274 | + if (truncated) { | |
7275 | + memcpy(buf + buf_size - sizeof("..."), "...", sizeof("...") - 1); | |
7276 | + len = buf_size - 1; | |
7277 | + } | |
7278 | + | |
7279 | + buf[len++] = '\n'; | |
7280 | + | |
7281 | + write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len); | |
7282 | +} | |
37d32ffb ER |
7283 | diff --git a/sapi/cgi/fpm/zlog.h b/sapi/cgi/fpm/zlog.h |
7284 | new file mode 100644 | |
37d32ffb ER |
7285 | --- /dev/null |
7286 | +++ b/sapi/cgi/fpm/zlog.h | |
c6a6bfc9 | 7287 | @@ -0,0 +1,34 @@ |
fd1be940 ER |
7288 | + |
7289 | + /* $Id$ */ | |
7290 | + /* (c) 2004-2007 Andrei Nigmatulin */ | |
7291 | + | |
7292 | +#ifndef ZLOG_H | |
7293 | +#define ZLOG_H 1 | |
7294 | + | |
7295 | +#define ZLOG_STUFF __func__, __LINE__ | |
7296 | + | |
c6a6bfc9 ER |
7297 | +struct timeval; |
7298 | + | |
fd1be940 | 7299 | +int zlog_set_fd(int new_fd); |
c6a6bfc9 ER |
7300 | +int zlog_set_level(int new_value); |
7301 | + | |
7302 | +size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len); | |
fd1be940 ER |
7303 | + |
7304 | +void zlog(const char *function, int line, int flags, const char *fmt, ...) | |
7305 | + __attribute__ ((format(printf,4,5))); | |
7306 | + | |
7307 | +enum { | |
7308 | + ZLOG_DEBUG = 1, | |
7309 | + ZLOG_NOTICE = 2, | |
7310 | + ZLOG_WARNING = 3, | |
7311 | + ZLOG_ERROR = 4, | |
7312 | + ZLOG_ALERT = 5, | |
7313 | +}; | |
7314 | + | |
7315 | +#define ZLOG_LEVEL_MASK 7 | |
7316 | + | |
7317 | +#define ZLOG_HAVE_ERRNO 0x100 | |
7318 | + | |
7319 | +#define ZLOG_SYSERROR (ZLOG_ERROR | ZLOG_HAVE_ERRNO) | |
7320 | + | |
7321 | +#endif |