1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Jason Greene <jason@inetgurus.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #define PCNTL_DEBUG 0
20
21 #if PCNTL_DEBUG
22 #define DEBUG_OUT printf("DEBUG: ");printf
23 #define IF_DEBUG(z) z
24 #else
25 #define IF_DEBUG(z)
26 #endif
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "php.h"
33 #include "php_ini.h"
34 #include "ext/standard/info.h"
35 #include "php_pcntl.h"
36 #include "php_signal.h"
37 #include "php_ticks.h"
38
39 #if HAVE_GETPRIORITY || HAVE_SETPRIORITY || HAVE_WAIT3
40 #include <sys/wait.h>
41 #include <sys/time.h>
42 #include <sys/resource.h>
43 #endif
44
45 #include <errno.h>
46
47 #ifndef NSIG
48 # ifdef SIGRTMAX
49 # define NSIG (SIGRTMAX + 1)
50 # else
51 # define NSIG 32
52 # endif
53 #endif
54
55 ZEND_DECLARE_MODULE_GLOBALS(pcntl)
56 static PHP_GINIT_FUNCTION(pcntl);
57
58 /* {{{ arginfo */
59 ZEND_BEGIN_ARG_INFO(arginfo_pcntl_void, 0)
60 ZEND_END_ARG_INFO()
61
62 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_waitpid, 0, 0, 2)
63 ZEND_ARG_INFO(0, pid)
64 ZEND_ARG_INFO(1, status)
65 ZEND_ARG_INFO(0, options)
66 ZEND_ARG_INFO(1, rusage)
67 ZEND_END_ARG_INFO()
68
69 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wait, 0, 0, 1)
70 ZEND_ARG_INFO(1, status)
71 ZEND_ARG_INFO(0, options)
72 ZEND_ARG_INFO(1, rusage)
73 ZEND_END_ARG_INFO()
74
75 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal, 0, 0, 2)
76 ZEND_ARG_INFO(0, signo)
77 ZEND_ARG_INFO(0, handler)
78 ZEND_ARG_INFO(0, restart_syscalls)
79 ZEND_END_ARG_INFO()
80
81 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal_get_handler, 0, 0, 1)
82 ZEND_ARG_INFO(0, signo)
83 ZEND_END_ARG_INFO()
84
85 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigprocmask, 0, 0, 2)
86 ZEND_ARG_INFO(0, how)
87 ZEND_ARG_INFO(0, set)
88 ZEND_ARG_INFO(1, oldset)
89 ZEND_END_ARG_INFO()
90
91 #ifdef HAVE_STRUCT_SIGINFO_T
92 # if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
93 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigwaitinfo, 0, 0, 1)
94 ZEND_ARG_INFO(0, set)
95 ZEND_ARG_INFO(1, info)
96 ZEND_END_ARG_INFO()
97
98 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigtimedwait, 0, 0, 1)
99 ZEND_ARG_INFO(0, set)
100 ZEND_ARG_INFO(1, info)
101 ZEND_ARG_INFO(0, seconds)
102 ZEND_ARG_INFO(0, nanoseconds)
103 ZEND_END_ARG_INFO()
104 # endif
105 #endif
106
107 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexited, 0, 0, 1)
108 ZEND_ARG_INFO(0, status)
109 ZEND_END_ARG_INFO()
110
111 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifstopped, 0, 0, 1)
112 ZEND_ARG_INFO(0, status)
113 ZEND_END_ARG_INFO()
114
115 #ifdef HAVE_WCONTINUED
116 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifcontinued, 0, 0, 1)
117 ZEND_ARG_INFO(0, status)
118 ZEND_END_ARG_INFO()
119 #endif
120
121 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifsignaled, 0, 0, 1)
122 ZEND_ARG_INFO(0, status)
123 ZEND_END_ARG_INFO()
124
125 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexitstatus, 0, 0, 1)
126 ZEND_ARG_INFO(0, status)
127 ZEND_END_ARG_INFO()
128
129 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wtermsig, 0, 0, 1)
130 ZEND_ARG_INFO(0, status)
131 ZEND_END_ARG_INFO()
132
133 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wstopsig, 0, 0, 1)
134 ZEND_ARG_INFO(0, status)
135 ZEND_END_ARG_INFO()
136
137 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_exec, 0, 0, 1)
138 ZEND_ARG_INFO(0, path)
139 ZEND_ARG_INFO(0, args)
140 ZEND_ARG_INFO(0, envs)
141 ZEND_END_ARG_INFO()
142
143 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_alarm, 0, 0, 1)
144 ZEND_ARG_INFO(0, seconds)
145 ZEND_END_ARG_INFO()
146
147 #ifdef HAVE_GETPRIORITY
148 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_getpriority, 0, 0, 0)
149 ZEND_ARG_INFO(0, pid)
150 ZEND_ARG_INFO(0, process_identifier)
151 ZEND_END_ARG_INFO()
152 #endif
153
154 #ifdef HAVE_SETPRIORITY
155 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_setpriority, 0, 0, 1)
156 ZEND_ARG_INFO(0, priority)
157 ZEND_ARG_INFO(0, pid)
158 ZEND_ARG_INFO(0, process_identifier)
159 ZEND_END_ARG_INFO()
160 #endif
161
162 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_strerror, 0, 0, 1)
163 ZEND_ARG_INFO(0, errno)
164 ZEND_END_ARG_INFO()
165
166 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_async_signals, 0, 0, 1)
167 ZEND_ARG_INFO(0, on)
168 ZEND_END_ARG_INFO()
169 /* }}} */
170
171 static const zend_function_entry pcntl_functions[] = {
172 PHP_FE(pcntl_fork, arginfo_pcntl_void)
173 PHP_FE(pcntl_waitpid, arginfo_pcntl_waitpid)
174 PHP_FE(pcntl_wait, arginfo_pcntl_wait)
175 PHP_FE(pcntl_signal, arginfo_pcntl_signal)
176 PHP_FE(pcntl_signal_get_handler, arginfo_pcntl_signal_get_handler)
177 PHP_FE(pcntl_signal_dispatch, arginfo_pcntl_void)
178 PHP_FE(pcntl_wifexited, arginfo_pcntl_wifexited)
179 PHP_FE(pcntl_wifstopped, arginfo_pcntl_wifstopped)
180 PHP_FE(pcntl_wifsignaled, arginfo_pcntl_wifsignaled)
181 PHP_FE(pcntl_wexitstatus, arginfo_pcntl_wifexitstatus)
182 PHP_FE(pcntl_wtermsig, arginfo_pcntl_wtermsig)
183 PHP_FE(pcntl_wstopsig, arginfo_pcntl_wstopsig)
184 PHP_FE(pcntl_exec, arginfo_pcntl_exec)
185 PHP_FE(pcntl_alarm, arginfo_pcntl_alarm)
186 PHP_FE(pcntl_get_last_error, arginfo_pcntl_void)
187 PHP_FALIAS(pcntl_errno, pcntl_get_last_error, NULL)
188 PHP_FE(pcntl_strerror, arginfo_pcntl_strerror)
189 #ifdef HAVE_GETPRIORITY
190 PHP_FE(pcntl_getpriority, arginfo_pcntl_getpriority)
191 #endif
192 #ifdef HAVE_SETPRIORITY
193 PHP_FE(pcntl_setpriority, arginfo_pcntl_setpriority)
194 #endif
195 #ifdef HAVE_SIGPROCMASK
196 PHP_FE(pcntl_sigprocmask, arginfo_pcntl_sigprocmask)
197 #endif
198 #ifdef HAVE_STRUCT_SIGINFO_T
199 # if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
200 PHP_FE(pcntl_sigwaitinfo, arginfo_pcntl_sigwaitinfo)
201 PHP_FE(pcntl_sigtimedwait, arginfo_pcntl_sigtimedwait)
202 # endif
203 #endif
204 #ifdef HAVE_WCONTINUED
205 PHP_FE(pcntl_wifcontinued, arginfo_pcntl_wifcontinued)
206 #endif
207 PHP_FE(pcntl_async_signals, arginfo_pcntl_async_signals)
208 PHP_FE_END
209 };
210
211 zend_module_entry pcntl_module_entry = {
212 STANDARD_MODULE_HEADER,
213 "pcntl",
214 pcntl_functions,
215 PHP_MINIT(pcntl),
216 PHP_MSHUTDOWN(pcntl),
217 PHP_RINIT(pcntl),
218 PHP_RSHUTDOWN(pcntl),
219 PHP_MINFO(pcntl),
220 PHP_PCNTL_VERSION,
221 PHP_MODULE_GLOBALS(pcntl),
222 PHP_GINIT(pcntl),
223 NULL,
224 NULL,
225 STANDARD_MODULE_PROPERTIES_EX
226 };
227
228 #ifdef COMPILE_DL_PCNTL
229 ZEND_GET_MODULE(pcntl)
230 #endif
231
232 static void (*orig_interrupt_function)(zend_execute_data *execute_data);
233
234 #ifdef HAVE_STRUCT_SIGINFO_T
235 static void pcntl_signal_handler(int, siginfo_t*, void*);
236 static void pcntl_siginfo_to_zval(int, siginfo_t*, zval*);
237 #else
238 static void pcntl_signal_handler(int);
239 #endif
240 static void pcntl_signal_dispatch();
241 static void pcntl_interrupt_function(zend_execute_data *execute_data);
242
php_register_signal_constants(INIT_FUNC_ARGS)243 void php_register_signal_constants(INIT_FUNC_ARGS)
244 {
245
246 /* Wait Constants */
247 #ifdef WNOHANG
248 REGISTER_LONG_CONSTANT("WNOHANG", (zend_long) WNOHANG, CONST_CS | CONST_PERSISTENT);
249 #endif
250 #ifdef WUNTRACED
251 REGISTER_LONG_CONSTANT("WUNTRACED", (zend_long) WUNTRACED, CONST_CS | CONST_PERSISTENT);
252 #endif
253 #ifdef HAVE_WCONTINUED
254 REGISTER_LONG_CONSTANT("WCONTINUED", (zend_long) WCONTINUED, CONST_CS | CONST_PERSISTENT);
255 #endif
256
257 /* Signal Constants */
258 REGISTER_LONG_CONSTANT("SIG_IGN", (zend_long) SIG_IGN, CONST_CS | CONST_PERSISTENT);
259 REGISTER_LONG_CONSTANT("SIG_DFL", (zend_long) SIG_DFL, CONST_CS | CONST_PERSISTENT);
260 REGISTER_LONG_CONSTANT("SIG_ERR", (zend_long) SIG_ERR, CONST_CS | CONST_PERSISTENT);
261 REGISTER_LONG_CONSTANT("SIGHUP", (zend_long) SIGHUP, CONST_CS | CONST_PERSISTENT);
262 REGISTER_LONG_CONSTANT("SIGINT", (zend_long) SIGINT, CONST_CS | CONST_PERSISTENT);
263 REGISTER_LONG_CONSTANT("SIGQUIT", (zend_long) SIGQUIT, CONST_CS | CONST_PERSISTENT);
264 REGISTER_LONG_CONSTANT("SIGILL", (zend_long) SIGILL, CONST_CS | CONST_PERSISTENT);
265 REGISTER_LONG_CONSTANT("SIGTRAP", (zend_long) SIGTRAP, CONST_CS | CONST_PERSISTENT);
266 REGISTER_LONG_CONSTANT("SIGABRT", (zend_long) SIGABRT, CONST_CS | CONST_PERSISTENT);
267 #ifdef SIGIOT
268 REGISTER_LONG_CONSTANT("SIGIOT", (zend_long) SIGIOT, CONST_CS | CONST_PERSISTENT);
269 #endif
270 REGISTER_LONG_CONSTANT("SIGBUS", (zend_long) SIGBUS, CONST_CS | CONST_PERSISTENT);
271 REGISTER_LONG_CONSTANT("SIGFPE", (zend_long) SIGFPE, CONST_CS | CONST_PERSISTENT);
272 REGISTER_LONG_CONSTANT("SIGKILL", (zend_long) SIGKILL, CONST_CS | CONST_PERSISTENT);
273 REGISTER_LONG_CONSTANT("SIGUSR1", (zend_long) SIGUSR1, CONST_CS | CONST_PERSISTENT);
274 REGISTER_LONG_CONSTANT("SIGSEGV", (zend_long) SIGSEGV, CONST_CS | CONST_PERSISTENT);
275 REGISTER_LONG_CONSTANT("SIGUSR2", (zend_long) SIGUSR2, CONST_CS | CONST_PERSISTENT);
276 REGISTER_LONG_CONSTANT("SIGPIPE", (zend_long) SIGPIPE, CONST_CS | CONST_PERSISTENT);
277 REGISTER_LONG_CONSTANT("SIGALRM", (zend_long) SIGALRM, CONST_CS | CONST_PERSISTENT);
278 REGISTER_LONG_CONSTANT("SIGTERM", (zend_long) SIGTERM, CONST_CS | CONST_PERSISTENT);
279 #ifdef SIGSTKFLT
280 REGISTER_LONG_CONSTANT("SIGSTKFLT",(zend_long) SIGSTKFLT, CONST_CS | CONST_PERSISTENT);
281 #endif
282 #ifdef SIGCLD
283 REGISTER_LONG_CONSTANT("SIGCLD", (zend_long) SIGCLD, CONST_CS | CONST_PERSISTENT);
284 #endif
285 #ifdef SIGCHLD
286 REGISTER_LONG_CONSTANT("SIGCHLD", (zend_long) SIGCHLD, CONST_CS | CONST_PERSISTENT);
287 #endif
288 REGISTER_LONG_CONSTANT("SIGCONT", (zend_long) SIGCONT, CONST_CS | CONST_PERSISTENT);
289 REGISTER_LONG_CONSTANT("SIGSTOP", (zend_long) SIGSTOP, CONST_CS | CONST_PERSISTENT);
290 REGISTER_LONG_CONSTANT("SIGTSTP", (zend_long) SIGTSTP, CONST_CS | CONST_PERSISTENT);
291 REGISTER_LONG_CONSTANT("SIGTTIN", (zend_long) SIGTTIN, CONST_CS | CONST_PERSISTENT);
292 REGISTER_LONG_CONSTANT("SIGTTOU", (zend_long) SIGTTOU, CONST_CS | CONST_PERSISTENT);
293 REGISTER_LONG_CONSTANT("SIGURG", (zend_long) SIGURG , CONST_CS | CONST_PERSISTENT);
294 REGISTER_LONG_CONSTANT("SIGXCPU", (zend_long) SIGXCPU, CONST_CS | CONST_PERSISTENT);
295 REGISTER_LONG_CONSTANT("SIGXFSZ", (zend_long) SIGXFSZ, CONST_CS | CONST_PERSISTENT);
296 REGISTER_LONG_CONSTANT("SIGVTALRM",(zend_long) SIGVTALRM, CONST_CS | CONST_PERSISTENT);
297 REGISTER_LONG_CONSTANT("SIGPROF", (zend_long) SIGPROF, CONST_CS | CONST_PERSISTENT);
298 REGISTER_LONG_CONSTANT("SIGWINCH", (zend_long) SIGWINCH, CONST_CS | CONST_PERSISTENT);
299 #ifdef SIGPOLL
300 REGISTER_LONG_CONSTANT("SIGPOLL", (zend_long) SIGPOLL, CONST_CS | CONST_PERSISTENT);
301 #endif
302 REGISTER_LONG_CONSTANT("SIGIO", (zend_long) SIGIO, CONST_CS | CONST_PERSISTENT);
303 #ifdef SIGPWR
304 REGISTER_LONG_CONSTANT("SIGPWR", (zend_long) SIGPWR, CONST_CS | CONST_PERSISTENT);
305 #endif
306 #ifdef SIGSYS
307 REGISTER_LONG_CONSTANT("SIGSYS", (zend_long) SIGSYS, CONST_CS | CONST_PERSISTENT);
308 REGISTER_LONG_CONSTANT("SIGBABY", (zend_long) SIGSYS, CONST_CS | CONST_PERSISTENT);
309 #endif
310 #ifdef SIGRTMIN
311 REGISTER_LONG_CONSTANT("SIGRTMIN", (zend_long) SIGRTMIN, CONST_CS | CONST_PERSISTENT);
312 #endif
313 #ifdef SIGRTMAX
314 REGISTER_LONG_CONSTANT("SIGRTMAX", (zend_long) SIGRTMAX, CONST_CS | CONST_PERSISTENT);
315 #endif
316
317 #if HAVE_GETPRIORITY || HAVE_SETPRIORITY
318 REGISTER_LONG_CONSTANT("PRIO_PGRP", PRIO_PGRP, CONST_CS | CONST_PERSISTENT);
319 REGISTER_LONG_CONSTANT("PRIO_USER", PRIO_USER, CONST_CS | CONST_PERSISTENT);
320 REGISTER_LONG_CONSTANT("PRIO_PROCESS", PRIO_PROCESS, CONST_CS | CONST_PERSISTENT);
321 #endif
322
323 /* {{{ "how" argument for sigprocmask */
324 #ifdef HAVE_SIGPROCMASK
325 REGISTER_LONG_CONSTANT("SIG_BLOCK", SIG_BLOCK, CONST_CS | CONST_PERSISTENT);
326 REGISTER_LONG_CONSTANT("SIG_UNBLOCK", SIG_UNBLOCK, CONST_CS | CONST_PERSISTENT);
327 REGISTER_LONG_CONSTANT("SIG_SETMASK", SIG_SETMASK, CONST_CS | CONST_PERSISTENT);
328 #endif
329 /* }}} */
330
331 /* {{{ si_code */
332 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
333 REGISTER_LONG_CONSTANT("SI_USER", SI_USER, CONST_CS | CONST_PERSISTENT);
334 #ifdef SI_NOINFO
335 REGISTER_LONG_CONSTANT("SI_NOINFO", SI_NOINFO, CONST_CS | CONST_PERSISTENT);
336 #endif
337 #ifdef SI_KERNEL
338 REGISTER_LONG_CONSTANT("SI_KERNEL", SI_KERNEL, CONST_CS | CONST_PERSISTENT);
339 #endif
340 REGISTER_LONG_CONSTANT("SI_QUEUE", SI_QUEUE, CONST_CS | CONST_PERSISTENT);
341 REGISTER_LONG_CONSTANT("SI_TIMER", SI_TIMER, CONST_CS | CONST_PERSISTENT);
342 REGISTER_LONG_CONSTANT("SI_MESGQ", SI_MESGQ, CONST_CS | CONST_PERSISTENT);
343 REGISTER_LONG_CONSTANT("SI_ASYNCIO", SI_ASYNCIO, CONST_CS | CONST_PERSISTENT);
344 #ifdef SI_SIGIO
345 REGISTER_LONG_CONSTANT("SI_SIGIO", SI_SIGIO, CONST_CS | CONST_PERSISTENT);
346 #endif
347 #ifdef SI_TKILL
348 REGISTER_LONG_CONSTANT("SI_TKILL", SI_TKILL, CONST_CS | CONST_PERSISTENT);
349 #endif
350
351 /* si_code for SIGCHILD */
352 #ifdef CLD_EXITED
353 REGISTER_LONG_CONSTANT("CLD_EXITED", CLD_EXITED, CONST_CS | CONST_PERSISTENT);
354 #endif
355 #ifdef CLD_KILLED
356 REGISTER_LONG_CONSTANT("CLD_KILLED", CLD_KILLED, CONST_CS | CONST_PERSISTENT);
357 #endif
358 #ifdef CLD_DUMPED
359 REGISTER_LONG_CONSTANT("CLD_DUMPED", CLD_DUMPED, CONST_CS | CONST_PERSISTENT);
360 #endif
361 #ifdef CLD_TRAPPED
362 REGISTER_LONG_CONSTANT("CLD_TRAPPED", CLD_TRAPPED, CONST_CS | CONST_PERSISTENT);
363 #endif
364 #ifdef CLD_STOPPED
365 REGISTER_LONG_CONSTANT("CLD_STOPPED", CLD_STOPPED, CONST_CS | CONST_PERSISTENT);
366 #endif
367 #ifdef CLD_CONTINUED
368 REGISTER_LONG_CONSTANT("CLD_CONTINUED", CLD_CONTINUED, CONST_CS | CONST_PERSISTENT);
369 #endif
370
371 /* si_code for SIGTRAP */
372 #ifdef TRAP_BRKPT
373 REGISTER_LONG_CONSTANT("TRAP_BRKPT", TRAP_BRKPT, CONST_CS | CONST_PERSISTENT);
374 #endif
375 #ifdef TRAP_TRACE
376 REGISTER_LONG_CONSTANT("TRAP_TRACE", TRAP_TRACE, CONST_CS | CONST_PERSISTENT);
377 #endif
378
379 /* si_code for SIGPOLL */
380 #ifdef POLL_IN
381 REGISTER_LONG_CONSTANT("POLL_IN", POLL_IN, CONST_CS | CONST_PERSISTENT);
382 #endif
383 #ifdef POLL_OUT
384 REGISTER_LONG_CONSTANT("POLL_OUT", POLL_OUT, CONST_CS | CONST_PERSISTENT);
385 #endif
386 #ifdef POLL_MSG
387 REGISTER_LONG_CONSTANT("POLL_MSG", POLL_MSG, CONST_CS | CONST_PERSISTENT);
388 #endif
389 #ifdef POLL_ERR
390 REGISTER_LONG_CONSTANT("POLL_ERR", POLL_ERR, CONST_CS | CONST_PERSISTENT);
391 #endif
392 #ifdef POLL_PRI
393 REGISTER_LONG_CONSTANT("POLL_PRI", POLL_PRI, CONST_CS | CONST_PERSISTENT);
394 #endif
395 #ifdef POLL_HUP
396 REGISTER_LONG_CONSTANT("POLL_HUP", POLL_HUP, CONST_CS | CONST_PERSISTENT);
397 #endif
398
399 #ifdef ILL_ILLOPC
400 REGISTER_LONG_CONSTANT("ILL_ILLOPC", ILL_ILLOPC, CONST_CS | CONST_PERSISTENT);
401 #endif
402 #ifdef ILL_ILLOPN
403 REGISTER_LONG_CONSTANT("ILL_ILLOPN", ILL_ILLOPN, CONST_CS | CONST_PERSISTENT);
404 #endif
405 #ifdef ILL_ILLADR
406 REGISTER_LONG_CONSTANT("ILL_ILLADR", ILL_ILLADR, CONST_CS | CONST_PERSISTENT);
407 #endif
408 #ifdef ILL_ILLTRP
409 REGISTER_LONG_CONSTANT("ILL_ILLTRP", ILL_ILLTRP, CONST_CS | CONST_PERSISTENT);
410 #endif
411 #ifdef ILL_PRVOPC
412 REGISTER_LONG_CONSTANT("ILL_PRVOPC", ILL_PRVOPC, CONST_CS | CONST_PERSISTENT);
413 #endif
414 #ifdef ILL_PRVREG
415 REGISTER_LONG_CONSTANT("ILL_PRVREG", ILL_PRVREG, CONST_CS | CONST_PERSISTENT);
416 #endif
417 #ifdef ILL_COPROC
418 REGISTER_LONG_CONSTANT("ILL_COPROC", ILL_COPROC, CONST_CS | CONST_PERSISTENT);
419 #endif
420 #ifdef ILL_BADSTK
421 REGISTER_LONG_CONSTANT("ILL_BADSTK", ILL_BADSTK, CONST_CS | CONST_PERSISTENT);
422 #endif
423
424 #ifdef FPE_INTDIV
425 REGISTER_LONG_CONSTANT("FPE_INTDIV", FPE_INTDIV, CONST_CS | CONST_PERSISTENT);
426 #endif
427 #ifdef FPE_INTOVF
428 REGISTER_LONG_CONSTANT("FPE_INTOVF", FPE_INTOVF, CONST_CS | CONST_PERSISTENT);
429 #endif
430 #ifdef FPE_FLTDIV
431 REGISTER_LONG_CONSTANT("FPE_FLTDIV", FPE_FLTDIV, CONST_CS | CONST_PERSISTENT);
432 #endif
433 #ifdef FPE_FLTOVF
434 REGISTER_LONG_CONSTANT("FPE_FLTOVF", FPE_FLTOVF, CONST_CS | CONST_PERSISTENT);
435 #endif
436 #ifdef FPE_FLTUND
437 REGISTER_LONG_CONSTANT("FPE_FLTUND", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
438 #endif
439 #ifdef FPE_FLTRES
440 REGISTER_LONG_CONSTANT("FPE_FLTRES", FPE_FLTRES, CONST_CS | CONST_PERSISTENT);
441 #endif
442 #ifdef FPE_FLTINV
443 REGISTER_LONG_CONSTANT("FPE_FLTINV", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
444 #endif
445 #ifdef FPE_FLTSUB
446 REGISTER_LONG_CONSTANT("FPE_FLTSUB", FPE_FLTSUB, CONST_CS | CONST_PERSISTENT);
447 #endif
448
449 #ifdef SEGV_MAPERR
450 REGISTER_LONG_CONSTANT("SEGV_MAPERR", SEGV_MAPERR, CONST_CS | CONST_PERSISTENT);
451 #endif
452 #ifdef SEGV_ACCERR
453 REGISTER_LONG_CONSTANT("SEGV_ACCERR", SEGV_ACCERR, CONST_CS | CONST_PERSISTENT);
454 #endif
455
456 #ifdef BUS_ADRALN
457 REGISTER_LONG_CONSTANT("BUS_ADRALN", BUS_ADRALN, CONST_CS | CONST_PERSISTENT);
458 #endif
459 #ifdef BUS_ADRERR
460 REGISTER_LONG_CONSTANT("BUS_ADRERR", BUS_ADRERR, CONST_CS | CONST_PERSISTENT);
461 #endif
462 #ifdef BUS_OBJERR
463 REGISTER_LONG_CONSTANT("BUS_OBJERR", BUS_OBJERR, CONST_CS | CONST_PERSISTENT);
464 #endif
465 #endif /* HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT */
466 /* }}} */
467 }
468
php_pcntl_register_errno_constants(INIT_FUNC_ARGS)469 static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS)
470 {
471 #ifdef EINTR
472 REGISTER_PCNTL_ERRNO_CONSTANT(EINTR);
473 #endif
474 #ifdef ECHILD
475 REGISTER_PCNTL_ERRNO_CONSTANT(ECHILD);
476 #endif
477 #ifdef EINVAL
478 REGISTER_PCNTL_ERRNO_CONSTANT(EINVAL);
479 #endif
480 #ifdef EAGAIN
481 REGISTER_PCNTL_ERRNO_CONSTANT(EAGAIN);
482 #endif
483 #ifdef ESRCH
484 REGISTER_PCNTL_ERRNO_CONSTANT(ESRCH);
485 #endif
486 #ifdef EACCES
487 REGISTER_PCNTL_ERRNO_CONSTANT(EACCES);
488 #endif
489 #ifdef EPERM
490 REGISTER_PCNTL_ERRNO_CONSTANT(EPERM);
491 #endif
492 #ifdef ENOMEM
493 REGISTER_PCNTL_ERRNO_CONSTANT(ENOMEM);
494 #endif
495 #ifdef E2BIG
496 REGISTER_PCNTL_ERRNO_CONSTANT(E2BIG);
497 #endif
498 #ifdef EFAULT
499 REGISTER_PCNTL_ERRNO_CONSTANT(EFAULT);
500 #endif
501 #ifdef EIO
502 REGISTER_PCNTL_ERRNO_CONSTANT(EIO);
503 #endif
504 #ifdef EISDIR
505 REGISTER_PCNTL_ERRNO_CONSTANT(EISDIR);
506 #endif
507 #ifdef ELIBBAD
508 REGISTER_PCNTL_ERRNO_CONSTANT(ELIBBAD);
509 #endif
510 #ifdef ELOOP
511 REGISTER_PCNTL_ERRNO_CONSTANT(ELOOP);
512 #endif
513 #ifdef EMFILE
514 REGISTER_PCNTL_ERRNO_CONSTANT(EMFILE);
515 #endif
516 #ifdef ENAMETOOLONG
517 REGISTER_PCNTL_ERRNO_CONSTANT(ENAMETOOLONG);
518 #endif
519 #ifdef ENFILE
520 REGISTER_PCNTL_ERRNO_CONSTANT(ENFILE);
521 #endif
522 #ifdef ENOENT
523 REGISTER_PCNTL_ERRNO_CONSTANT(ENOENT);
524 #endif
525 #ifdef ENOEXEC
526 REGISTER_PCNTL_ERRNO_CONSTANT(ENOEXEC);
527 #endif
528 #ifdef ENOTDIR
529 REGISTER_PCNTL_ERRNO_CONSTANT(ENOTDIR);
530 #endif
531 #ifdef ETXTBSY
532 REGISTER_PCNTL_ERRNO_CONSTANT(ETXTBSY);
533 #endif
534 }
535
PHP_GINIT_FUNCTION(pcntl)536 static PHP_GINIT_FUNCTION(pcntl)
537 {
538 memset(pcntl_globals, 0, sizeof(*pcntl_globals));
539 }
540
PHP_RINIT_FUNCTION(pcntl)541 PHP_RINIT_FUNCTION(pcntl)
542 {
543 zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0);
544 PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL;
545 PCNTL_G(async_signals) = 0;
546 return SUCCESS;
547 }
548
PHP_MINIT_FUNCTION(pcntl)549 PHP_MINIT_FUNCTION(pcntl)
550 {
551 php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
552 php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);
553 php_add_tick_function(pcntl_signal_dispatch, NULL);
554 orig_interrupt_function = zend_interrupt_function;
555 zend_interrupt_function = pcntl_interrupt_function;
556
557 return SUCCESS;
558 }
559
PHP_MSHUTDOWN_FUNCTION(pcntl)560 PHP_MSHUTDOWN_FUNCTION(pcntl)
561 {
562 return SUCCESS;
563 }
564
PHP_RSHUTDOWN_FUNCTION(pcntl)565 PHP_RSHUTDOWN_FUNCTION(pcntl)
566 {
567 struct php_pcntl_pending_signal *sig;
568
569 /* FIXME: if a signal is delivered after this point, things will go pear shaped;
570 * need to remove signal handlers */
571 zend_hash_destroy(&PCNTL_G(php_signal_table));
572 while (PCNTL_G(head)) {
573 sig = PCNTL_G(head);
574 PCNTL_G(head) = sig->next;
575 efree(sig);
576 }
577 while (PCNTL_G(spares)) {
578 sig = PCNTL_G(spares);
579 PCNTL_G(spares) = sig->next;
580 efree(sig);
581 }
582 return SUCCESS;
583 }
584
PHP_MINFO_FUNCTION(pcntl)585 PHP_MINFO_FUNCTION(pcntl)
586 {
587 php_info_print_table_start();
588 php_info_print_table_header(2, "pcntl support", "enabled");
589 php_info_print_table_end();
590 }
591
592 /* {{{ proto int pcntl_fork(void)
593 Forks the currently running process following the same behavior as the UNIX fork() system call*/
PHP_FUNCTION(pcntl_fork)594 PHP_FUNCTION(pcntl_fork)
595 {
596 pid_t id;
597
598 id = fork();
599 if (id == -1) {
600 PCNTL_G(last_error) = errno;
601 php_error_docref(NULL, E_WARNING, "Error %d", errno);
602 }
603
604 RETURN_LONG((zend_long) id);
605 }
606 /* }}} */
607
608 /* {{{ proto int pcntl_alarm(int seconds)
609 Set an alarm clock for delivery of a signal*/
PHP_FUNCTION(pcntl_alarm)610 PHP_FUNCTION(pcntl_alarm)
611 {
612 zend_long seconds;
613
614 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &seconds) == FAILURE)
615 return;
616
617 RETURN_LONG ((zend_long) alarm(seconds));
618 }
619 /* }}} */
620
621 #define PHP_RUSAGE_PARA(from, to, field) \
622 add_assoc_long(to, #field, from.field)
623 #ifndef _OSD_POSIX
624 #define PHP_RUSAGE_SPECIAL(from, to) \
625 PHP_RUSAGE_PARA(from, to, ru_oublock); \
626 PHP_RUSAGE_PARA(from, to, ru_inblock); \
627 PHP_RUSAGE_PARA(from, to, ru_msgsnd); \
628 PHP_RUSAGE_PARA(from, to, ru_msgrcv); \
629 PHP_RUSAGE_PARA(from, to, ru_maxrss); \
630 PHP_RUSAGE_PARA(from, to, ru_ixrss); \
631 PHP_RUSAGE_PARA(from, to, ru_idrss); \
632 PHP_RUSAGE_PARA(from, to, ru_minflt); \
633 PHP_RUSAGE_PARA(from, to, ru_majflt); \
634 PHP_RUSAGE_PARA(from, to, ru_nsignals); \
635 PHP_RUSAGE_PARA(from, to, ru_nvcsw); \
636 PHP_RUSAGE_PARA(from, to, ru_nivcsw); \
637 PHP_RUSAGE_PARA(from, to, ru_nswap);
638 #else /*_OSD_POSIX*/
639 #define PHP_RUSAGE_SPECIAL(from, to)
640 #endif
641
642 #define PHP_RUSAGE_COMMON(from ,to) \
643 PHP_RUSAGE_PARA(from, to, ru_utime.tv_usec); \
644 PHP_RUSAGE_PARA(from, to, ru_utime.tv_sec); \
645 PHP_RUSAGE_PARA(from, to, ru_stime.tv_usec); \
646 PHP_RUSAGE_PARA(from, to, ru_stime.tv_sec);
647
648 #define PHP_RUSAGE_TO_ARRAY(from, to) \
649 if (to) { \
650 PHP_RUSAGE_SPECIAL(from, to) \
651 PHP_RUSAGE_COMMON(from, to); \
652 }
653
654 /* {{{ proto int pcntl_waitpid(int pid, int &status, int options, array &$rusage)
655 Waits on or returns the status of a forked child as defined by the waitpid() system call */
PHP_FUNCTION(pcntl_waitpid)656 PHP_FUNCTION(pcntl_waitpid)
657 {
658 zend_long pid, options = 0;
659 zval *z_status = NULL, *z_rusage = NULL;
660 int status;
661 pid_t child_id;
662 #ifdef HAVE_WAIT4
663 struct rusage rusage;
664 #endif
665
666 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz/|lz/", &pid, &z_status, &options, &z_rusage) == FAILURE) {
667 return;
668 }
669
670 status = zval_get_long(z_status);
671
672 #ifdef HAVE_WAIT4
673 if (z_rusage) {
674 if (Z_TYPE_P(z_rusage) != IS_ARRAY) {
675 zval_ptr_dtor(z_rusage);
676 array_init(z_rusage);
677 } else {
678 zend_hash_clean(Z_ARRVAL_P(z_rusage));
679 }
680
681 memset(&rusage, 0, sizeof(struct rusage));
682 child_id = wait4((pid_t) pid, &status, options, &rusage);
683 } else {
684 child_id = waitpid((pid_t) pid, &status, options);
685 }
686 #else
687 child_id = waitpid((pid_t) pid, &status, options);
688 #endif
689
690 if (child_id < 0) {
691 PCNTL_G(last_error) = errno;
692 }
693
694 #ifdef HAVE_WAIT4
695 if (child_id > 0) {
696 PHP_RUSAGE_TO_ARRAY(rusage, z_rusage);
697 }
698 #endif
699
700 zval_ptr_dtor(z_status);
701 ZVAL_LONG(z_status, status);
702
703 RETURN_LONG((zend_long) child_id);
704 }
705 /* }}} */
706
707 /* {{{ proto int pcntl_wait(int &status, int $options, array &$rusage)
708 Waits on or returns the status of a forked child as defined by the waitpid() system call */
PHP_FUNCTION(pcntl_wait)709 PHP_FUNCTION(pcntl_wait)
710 {
711 zend_long options = 0;
712 zval *z_status = NULL, *z_rusage = NULL;
713 int status;
714 pid_t child_id;
715 #ifdef HAVE_WAIT3
716 struct rusage rusage;
717 #endif
718
719 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z/|lz/", &z_status, &options, &z_rusage) == FAILURE) {
720 return;
721 }
722
723 status = zval_get_long(z_status);
724 #ifdef HAVE_WAIT3
725 if (z_rusage) {
726 if (Z_TYPE_P(z_rusage) != IS_ARRAY) {
727 zval_ptr_dtor(z_rusage);
728 array_init(z_rusage);
729 } else {
730 zend_hash_clean(Z_ARRVAL_P(z_rusage));
731 }
732
733 memset(&rusage, 0, sizeof(struct rusage));
734 child_id = wait3(&status, options, &rusage);
735 } else if (options) {
736 child_id = wait3(&status, options, NULL);
737 } else {
738 child_id = wait(&status);
739 }
740 #else
741 child_id = wait(&status);
742 #endif
743 if (child_id < 0) {
744 PCNTL_G(last_error) = errno;
745 }
746
747 #ifdef HAVE_WAIT3
748 if (child_id > 0) {
749 PHP_RUSAGE_TO_ARRAY(rusage, z_rusage);
750 }
751 #endif
752
753 zval_ptr_dtor(z_status);
754 ZVAL_LONG(z_status, status);
755
756 RETURN_LONG((zend_long) child_id);
757 }
758 /* }}} */
759
760 #undef PHP_RUSAGE_PARA
761 #undef PHP_RUSAGE_SPECIAL
762 #undef PHP_RUSAGE_COMMON
763 #undef PHP_RUSAGE_TO_ARRAY
764
765 /* {{{ proto bool pcntl_wifexited(int status)
766 Returns true if the child status code represents a successful exit */
PHP_FUNCTION(pcntl_wifexited)767 PHP_FUNCTION(pcntl_wifexited)
768 {
769 #ifdef WIFEXITED
770 zend_long status_word;
771 int int_status_word;
772
773 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
774 return;
775 }
776
777 int_status_word = (int) status_word;
778 if (WIFEXITED(int_status_word))
779 RETURN_TRUE;
780 #endif
781
782 RETURN_FALSE;
783 }
784 /* }}} */
785
786 /* {{{ proto bool pcntl_wifstopped(int status)
787 Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
PHP_FUNCTION(pcntl_wifstopped)788 PHP_FUNCTION(pcntl_wifstopped)
789 {
790 #ifdef WIFSTOPPED
791 zend_long status_word;
792 int int_status_word;
793
794 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
795 return;
796 }
797
798 int_status_word = (int) status_word;
799 if (WIFSTOPPED(int_status_word))
800 RETURN_TRUE;
801 #endif
802 RETURN_FALSE;
803 }
804 /* }}} */
805
806 /* {{{ proto bool pcntl_wifsignaled(int status)
807 Returns true if the child status code represents a process that was terminated due to a signal */
PHP_FUNCTION(pcntl_wifsignaled)808 PHP_FUNCTION(pcntl_wifsignaled)
809 {
810 #ifdef WIFSIGNALED
811 zend_long status_word;
812 int int_status_word;
813
814 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
815 return;
816 }
817
818 int_status_word = (int) status_word;
819 if (WIFSIGNALED(int_status_word))
820 RETURN_TRUE;
821 #endif
822 RETURN_FALSE;
823 }
824 /* }}} */
825 /* {{{ proto bool pcntl_wifcontinued(int status)
826 Returns true if the child status code represents a process that was resumed due to a SIGCONT signal */
PHP_FUNCTION(pcntl_wifcontinued)827 PHP_FUNCTION(pcntl_wifcontinued)
828 {
829 #ifdef HAVE_WCONTINUED
830 zend_long status_word;
831 int int_status_word;
832
833 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
834 return;
835 }
836
837 int_status_word = (int) status_word;
838 if (WIFCONTINUED(int_status_word))
839 RETURN_TRUE;
840 #endif
841 RETURN_FALSE;
842 }
843 /* }}} */
844
845
846 /* {{{ proto int pcntl_wexitstatus(int status)
847 Returns the status code of a child's exit */
PHP_FUNCTION(pcntl_wexitstatus)848 PHP_FUNCTION(pcntl_wexitstatus)
849 {
850 #ifdef WEXITSTATUS
851 zend_long status_word;
852 int int_status_word;
853
854 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
855 return;
856 }
857
858 int_status_word = (int) status_word;
859 RETURN_LONG(WEXITSTATUS(int_status_word));
860 #else
861 RETURN_FALSE;
862 #endif
863 }
864 /* }}} */
865
866 /* {{{ proto int pcntl_wtermsig(int status)
867 Returns the number of the signal that terminated the process who's status code is passed */
PHP_FUNCTION(pcntl_wtermsig)868 PHP_FUNCTION(pcntl_wtermsig)
869 {
870 #ifdef WTERMSIG
871 zend_long status_word;
872 int int_status_word;
873
874 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
875 return;
876 }
877
878 int_status_word = (int) status_word;
879 RETURN_LONG(WTERMSIG(int_status_word));
880 #else
881 RETURN_FALSE;
882 #endif
883 }
884 /* }}} */
885
886 /* {{{ proto int pcntl_wstopsig(int status)
887 Returns the number of the signal that caused the process to stop who's status code is passed */
PHP_FUNCTION(pcntl_wstopsig)888 PHP_FUNCTION(pcntl_wstopsig)
889 {
890 #ifdef WSTOPSIG
891 zend_long status_word;
892 int int_status_word;
893
894 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
895 return;
896 }
897
898 int_status_word = (int) status_word;
899 RETURN_LONG(WSTOPSIG(int_status_word));
900 #else
901 RETURN_FALSE;
902 #endif
903 }
904 /* }}} */
905
906 /* {{{ proto bool pcntl_exec(string path [, array args [, array envs]])
907 Executes specified program in current process space as defined by exec(2) */
PHP_FUNCTION(pcntl_exec)908 PHP_FUNCTION(pcntl_exec)
909 {
910 zval *args = NULL, *envs = NULL;
911 zval *element;
912 HashTable *args_hash, *envs_hash;
913 int argc = 0, argi = 0;
914 int envc = 0, envi = 0;
915 char **argv = NULL, **envp = NULL;
916 char **current_arg, **pair;
917 int pair_length;
918 zend_string *key;
919 char *path;
920 size_t path_len;
921 zend_ulong key_num;
922
923 if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|aa", &path, &path_len, &args, &envs) == FAILURE) {
924 return;
925 }
926
927 if (ZEND_NUM_ARGS() > 1) {
928 /* Build argument list */
929 args_hash = Z_ARRVAL_P(args);
930 argc = zend_hash_num_elements(args_hash);
931
932 argv = safe_emalloc((argc + 2), sizeof(char *), 0);
933 *argv = path;
934 current_arg = argv+1;
935 ZEND_HASH_FOREACH_VAL(args_hash, element) {
936 if (argi >= argc) break;
937 convert_to_string_ex(element);
938 *current_arg = Z_STRVAL_P(element);
939 argi++;
940 current_arg++;
941 } ZEND_HASH_FOREACH_END();
942 *(current_arg) = NULL;
943 } else {
944 argv = emalloc(2 * sizeof(char *));
945 *argv = path;
946 *(argv+1) = NULL;
947 }
948
949 if ( ZEND_NUM_ARGS() == 3 ) {
950 /* Build environment pair list */
951 envs_hash = Z_ARRVAL_P(envs);
952 envc = zend_hash_num_elements(envs_hash);
953
954 pair = envp = safe_emalloc((envc + 1), sizeof(char *), 0);
955 ZEND_HASH_FOREACH_KEY_VAL(envs_hash, key_num, key, element) {
956 if (envi >= envc) break;
957 if (!key) {
958 key = zend_long_to_str(key_num);
959 } else {
960 zend_string_addref(key);
961 }
962
963 convert_to_string_ex(element);
964
965 /* Length of element + equal sign + length of key + null */
966 pair_length = Z_STRLEN_P(element) + ZSTR_LEN(key) + 2;
967 *pair = emalloc(pair_length);
968 strlcpy(*pair, ZSTR_VAL(key), ZSTR_LEN(key) + 1);
969 strlcat(*pair, "=", pair_length);
970 strlcat(*pair, Z_STRVAL_P(element), pair_length);
971
972 /* Cleanup */
973 zend_string_release_ex(key, 0);
974 envi++;
975 pair++;
976 } ZEND_HASH_FOREACH_END();
977 *(pair) = NULL;
978
979 if (execve(path, argv, envp) == -1) {
980 PCNTL_G(last_error) = errno;
981 php_error_docref(NULL, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
982 }
983
984 /* Cleanup */
985 for (pair = envp; *pair != NULL; pair++) efree(*pair);
986 efree(envp);
987 } else {
988
989 if (execv(path, argv) == -1) {
990 PCNTL_G(last_error) = errno;
991 php_error_docref(NULL, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
992 }
993 }
994
995 efree(argv);
996
997 RETURN_FALSE;
998 }
999 /* }}} */
1000
1001 /* {{{ proto bool pcntl_signal(int signo, callback handle [, bool restart_syscalls])
1002 Assigns a system signal handler to a PHP function */
PHP_FUNCTION(pcntl_signal)1003 PHP_FUNCTION(pcntl_signal)
1004 {
1005 zval *handle;
1006 zend_long signo;
1007 zend_bool restart_syscalls = 1;
1008 char *error = NULL;
1009
1010 if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) {
1011 return;
1012 }
1013
1014 if (signo < 1 || signo >= NSIG) {
1015 php_error_docref(NULL, E_WARNING, "Invalid signal");
1016 RETURN_FALSE;
1017 }
1018
1019 if (!PCNTL_G(spares)) {
1020 /* since calling malloc() from within a signal handler is not portable,
1021 * pre-allocate a few records for recording signals */
1022 int i;
1023 for (i = 0; i < NSIG; i++) {
1024 struct php_pcntl_pending_signal *psig;
1025
1026 psig = emalloc(sizeof(*psig));
1027 psig->next = PCNTL_G(spares);
1028 PCNTL_G(spares) = psig;
1029 }
1030 }
1031
1032 /* Special long value case for SIG_DFL and SIG_IGN */
1033 if (Z_TYPE_P(handle) == IS_LONG) {
1034 if (Z_LVAL_P(handle) != (zend_long) SIG_DFL && Z_LVAL_P(handle) != (zend_long) SIG_IGN) {
1035 php_error_docref(NULL, E_WARNING, "Invalid value for handle argument specified");
1036 RETURN_FALSE;
1037 }
1038 if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == (Sigfunc *)SIG_ERR) {
1039 PCNTL_G(last_error) = errno;
1040 php_error_docref(NULL, E_WARNING, "Error assigning signal");
1041 RETURN_FALSE;
1042 }
1043 zend_hash_index_update(&PCNTL_G(php_signal_table), signo, handle);
1044 RETURN_TRUE;
1045 }
1046
1047 if (!zend_is_callable_ex(handle, NULL, 0, NULL, NULL, &error)) {
1048 zend_string *func_name = zend_get_callable_name(handle);
1049 PCNTL_G(last_error) = EINVAL;
1050 php_error_docref(NULL, E_WARNING, "Specified handler \"%s\" is not callable (%s)", ZSTR_VAL(func_name), error);
1051 zend_string_release_ex(func_name, 0);
1052 efree(error);
1053 RETURN_FALSE;
1054 }
1055 ZEND_ASSERT(!error);
1056
1057 /* Add the function name to our signal table */
1058 handle = zend_hash_index_update(&PCNTL_G(php_signal_table), signo, handle);
1059 Z_TRY_ADDREF_P(handle);
1060
1061 if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == (Sigfunc *)SIG_ERR) {
1062 PCNTL_G(last_error) = errno;
1063 php_error_docref(NULL, E_WARNING, "Error assigning signal");
1064 RETURN_FALSE;
1065 }
1066 RETURN_TRUE;
1067 }
1068 /* }}} */
1069
1070 /* {{{ proto bool pcntl_signal_get_handler(int signo)
1071 Gets signal handler */
PHP_FUNCTION(pcntl_signal_get_handler)1072 PHP_FUNCTION(pcntl_signal_get_handler)
1073 {
1074 zval *prev_handle;
1075 zend_long signo;
1076
1077 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &signo) == FAILURE) {
1078 return;
1079 }
1080
1081 if (signo < 1 || signo > 32) {
1082 php_error_docref(NULL, E_WARNING, "Invalid signal");
1083 RETURN_FALSE;
1084 }
1085
1086 if ((prev_handle = zend_hash_index_find(&PCNTL_G(php_signal_table), signo)) != NULL) {
1087 RETURN_ZVAL(prev_handle, 1, 0);
1088 } else {
1089 RETURN_LONG((zend_long)SIG_DFL);
1090 }
1091 }
1092
1093 /* {{{ proto bool pcntl_signal_dispatch()
1094 Dispatch signals to signal handlers */
PHP_FUNCTION(pcntl_signal_dispatch)1095 PHP_FUNCTION(pcntl_signal_dispatch)
1096 {
1097 pcntl_signal_dispatch();
1098 RETURN_TRUE;
1099 }
1100 /* }}} */
1101
1102 #ifdef HAVE_SIGPROCMASK
1103 /* {{{ proto bool pcntl_sigprocmask(int how, array set[, array &oldset])
1104 Examine and change blocked signals */
PHP_FUNCTION(pcntl_sigprocmask)1105 PHP_FUNCTION(pcntl_sigprocmask)
1106 {
1107 zend_long how, signo;
1108 zval *user_set, *user_oldset = NULL, *user_signo;
1109 sigset_t set, oldset;
1110
1111 if (zend_parse_parameters(ZEND_NUM_ARGS(), "la|z/", &how, &user_set, &user_oldset) == FAILURE) {
1112 return;
1113 }
1114
1115 if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) {
1116 PCNTL_G(last_error) = errno;
1117 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1118 RETURN_FALSE;
1119 }
1120
1121 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(user_set), user_signo) {
1122 signo = zval_get_long(user_signo);
1123 if (sigaddset(&set, signo) != 0) {
1124 PCNTL_G(last_error) = errno;
1125 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1126 RETURN_FALSE;
1127 }
1128 } ZEND_HASH_FOREACH_END();
1129
1130 if (sigprocmask(how, &set, &oldset) != 0) {
1131 PCNTL_G(last_error) = errno;
1132 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1133 RETURN_FALSE;
1134 }
1135
1136 if (user_oldset != NULL) {
1137 if (Z_TYPE_P(user_oldset) != IS_ARRAY) {
1138 zval_ptr_dtor(user_oldset);
1139 array_init(user_oldset);
1140 } else {
1141 zend_hash_clean(Z_ARRVAL_P(user_oldset));
1142 }
1143 for (signo = 1; signo < NSIG; ++signo) {
1144 if (sigismember(&oldset, signo) != 1) {
1145 continue;
1146 }
1147 add_next_index_long(user_oldset, signo);
1148 }
1149 }
1150
1151 RETURN_TRUE;
1152 }
1153 /* }}} */
1154 #endif
1155
1156 #ifdef HAVE_STRUCT_SIGINFO_T
1157 # if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS,int timedwait)1158 static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */
1159 {
1160 zval *user_set, *user_signo, *user_siginfo = NULL;
1161 zend_long tv_sec = 0, tv_nsec = 0;
1162 sigset_t set;
1163 int signo;
1164 siginfo_t siginfo;
1165 struct timespec timeout;
1166
1167 if (timedwait) {
1168 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|z/ll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) {
1169 return;
1170 }
1171 } else {
1172 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|z/", &user_set, &user_siginfo) == FAILURE) {
1173 return;
1174 }
1175 }
1176
1177 if (sigemptyset(&set) != 0) {
1178 PCNTL_G(last_error) = errno;
1179 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1180 RETURN_FALSE;
1181 }
1182
1183 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(user_set), user_signo) {
1184 signo = zval_get_long(user_signo);
1185 if (sigaddset(&set, signo) != 0) {
1186 PCNTL_G(last_error) = errno;
1187 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1188 RETURN_FALSE;
1189 }
1190 } ZEND_HASH_FOREACH_END();
1191
1192 if (timedwait) {
1193 timeout.tv_sec = (time_t) tv_sec;
1194 timeout.tv_nsec = tv_nsec;
1195 signo = sigtimedwait(&set, &siginfo, &timeout);
1196 } else {
1197 signo = sigwaitinfo(&set, &siginfo);
1198 }
1199 if (signo == -1 && errno != EAGAIN) {
1200 PCNTL_G(last_error) = errno;
1201 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1202 }
1203
1204 /*
1205 * sigtimedwait and sigwaitinfo can return 0 on success on some
1206 * platforms, e.g. NetBSD
1207 */
1208 if (!signo && siginfo.si_signo) {
1209 signo = siginfo.si_signo;
1210 }
1211 pcntl_siginfo_to_zval(signo, &siginfo, user_siginfo);
1212 RETURN_LONG(signo);
1213 }
1214 /* }}} */
1215
1216 /* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo])
1217 Synchronously wait for queued signals */
PHP_FUNCTION(pcntl_sigwaitinfo)1218 PHP_FUNCTION(pcntl_sigwaitinfo)
1219 {
1220 pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1221 }
1222 /* }}} */
1223
1224 /* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]])
1225 Wait for queued signals */
PHP_FUNCTION(pcntl_sigtimedwait)1226 PHP_FUNCTION(pcntl_sigtimedwait)
1227 {
1228 pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1229 }
1230 /* }}} */
1231 # endif
1232
pcntl_siginfo_to_zval(int signo,siginfo_t * siginfo,zval * user_siginfo)1233 static void pcntl_siginfo_to_zval(int signo, siginfo_t *siginfo, zval *user_siginfo) /* {{{ */
1234 {
1235 if (signo > 0 && user_siginfo) {
1236 if (Z_TYPE_P(user_siginfo) != IS_ARRAY) {
1237 zval_ptr_dtor(user_siginfo);
1238 array_init(user_siginfo);
1239 } else {
1240 zend_hash_clean(Z_ARRVAL_P(user_siginfo));
1241 }
1242 add_assoc_long_ex(user_siginfo, "signo", sizeof("signo")-1, siginfo->si_signo);
1243 add_assoc_long_ex(user_siginfo, "errno", sizeof("errno")-1, siginfo->si_errno);
1244 add_assoc_long_ex(user_siginfo, "code", sizeof("code")-1, siginfo->si_code);
1245 switch(signo) {
1246 #ifdef SIGCHLD
1247 case SIGCHLD:
1248 add_assoc_long_ex(user_siginfo, "status", sizeof("status")-1, siginfo->si_status);
1249 # ifdef si_utime
1250 add_assoc_double_ex(user_siginfo, "utime", sizeof("utime")-1, siginfo->si_utime);
1251 # endif
1252 # ifdef si_stime
1253 add_assoc_double_ex(user_siginfo, "stime", sizeof("stime")-1, siginfo->si_stime);
1254 # endif
1255 add_assoc_long_ex(user_siginfo, "pid", sizeof("pid")-1, siginfo->si_pid);
1256 add_assoc_long_ex(user_siginfo, "uid", sizeof("uid")-1, siginfo->si_uid);
1257 break;
1258 case SIGUSR1:
1259 case SIGUSR2:
1260 add_assoc_long_ex(user_siginfo, "pid", sizeof("pid")-1, siginfo->si_pid);
1261 add_assoc_long_ex(user_siginfo, "uid", sizeof("uid")-1, siginfo->si_uid);
1262 break;
1263 #endif
1264 case SIGILL:
1265 case SIGFPE:
1266 case SIGSEGV:
1267 case SIGBUS:
1268 add_assoc_double_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo->si_addr);
1269 break;
1270 #ifdef SIGPOLL
1271 case SIGPOLL:
1272 add_assoc_long_ex(user_siginfo, "band", sizeof("band")-1, siginfo->si_band);
1273 # ifdef si_fd
1274 add_assoc_long_ex(user_siginfo, "fd", sizeof("fd")-1, siginfo->si_fd);
1275 # endif
1276 break;
1277 #endif
1278 }
1279 #if defined(SIGRTMIN) && defined(SIGRTMAX)
1280 if (SIGRTMIN <= signo && signo <= SIGRTMAX) {
1281 add_assoc_long_ex(user_siginfo, "pid", sizeof("pid")-1, siginfo->si_pid);
1282 add_assoc_long_ex(user_siginfo, "uid", sizeof("uid")-1, siginfo->si_uid);
1283 }
1284 #endif
1285 }
1286 }
1287 /* }}} */
1288 #endif
1289
1290 #ifdef HAVE_GETPRIORITY
1291 /* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]])
1292 Get the priority of any process */
PHP_FUNCTION(pcntl_getpriority)1293 PHP_FUNCTION(pcntl_getpriority)
1294 {
1295 zend_long who = PRIO_PROCESS;
1296 zend_long pid = getpid();
1297 int pri;
1298
1299 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &pid, &who) == FAILURE) {
1300 RETURN_FALSE;
1301 }
1302
1303 /* needs to be cleared, since any returned value is valid */
1304 errno = 0;
1305
1306 pri = getpriority(who, pid);
1307
1308 if (errno) {
1309 PCNTL_G(last_error) = errno;
1310 switch (errno) {
1311 case ESRCH:
1312 php_error_docref(NULL, E_WARNING, "Error %d: No process was located using the given parameters", errno);
1313 break;
1314 case EINVAL:
1315 php_error_docref(NULL, E_WARNING, "Error %d: Invalid identifier flag", errno);
1316 break;
1317 default:
1318 php_error_docref(NULL, E_WARNING, "Unknown error %d has occurred", errno);
1319 break;
1320 }
1321 RETURN_FALSE;
1322 }
1323
1324 RETURN_LONG(pri);
1325 }
1326 /* }}} */
1327 #endif
1328
1329 #ifdef HAVE_SETPRIORITY
1330 /* {{{ proto bool pcntl_setpriority(int priority [, int pid [, int process_identifier]])
1331 Change the priority of any process */
PHP_FUNCTION(pcntl_setpriority)1332 PHP_FUNCTION(pcntl_setpriority)
1333 {
1334 zend_long who = PRIO_PROCESS;
1335 zend_long pid = getpid();
1336 zend_long pri;
1337
1338 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|ll", &pri, &pid, &who) == FAILURE) {
1339 RETURN_FALSE;
1340 }
1341
1342 if (setpriority(who, pid, pri)) {
1343 PCNTL_G(last_error) = errno;
1344 switch (errno) {
1345 case ESRCH:
1346 php_error_docref(NULL, E_WARNING, "Error %d: No process was located using the given parameters", errno);
1347 break;
1348 case EINVAL:
1349 php_error_docref(NULL, E_WARNING, "Error %d: Invalid identifier flag", errno);
1350 break;
1351 case EPERM:
1352 php_error_docref(NULL, E_WARNING, "Error %d: A process was located, but neither its effective nor real user ID matched the effective user ID of the caller", errno);
1353 break;
1354 case EACCES:
1355 php_error_docref(NULL, E_WARNING, "Error %d: Only a super user may attempt to increase the process priority", errno);
1356 break;
1357 default:
1358 php_error_docref(NULL, E_WARNING, "Unknown error %d has occurred", errno);
1359 break;
1360 }
1361 RETURN_FALSE;
1362 }
1363
1364 RETURN_TRUE;
1365 }
1366 /* }}} */
1367 #endif
1368
1369 /* {{{ proto int pcntl_get_last_error(void)
1370 Retrieve the error number set by the last pcntl function which failed. */
PHP_FUNCTION(pcntl_get_last_error)1371 PHP_FUNCTION(pcntl_get_last_error)
1372 {
1373 RETURN_LONG(PCNTL_G(last_error));
1374 }
1375 /* }}} */
1376
1377 /* {{{ proto string pcntl_strerror(int errno)
1378 Retrieve the system error message associated with the given errno. */
PHP_FUNCTION(pcntl_strerror)1379 PHP_FUNCTION(pcntl_strerror)
1380 {
1381 zend_long error;
1382
1383 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &error) == FAILURE) {
1384 RETURN_FALSE;
1385 }
1386
1387 RETURN_STRING(strerror(error));
1388 }
1389 /* }}} */
1390
1391 /* Our custom signal handler that calls the appropriate php_function */
1392 #ifdef HAVE_STRUCT_SIGINFO_T
pcntl_signal_handler(int signo,siginfo_t * siginfo,void * context)1393 static void pcntl_signal_handler(int signo, siginfo_t *siginfo, void *context)
1394 #else
1395 static void pcntl_signal_handler(int signo)
1396 #endif
1397 {
1398 struct php_pcntl_pending_signal *psig;
1399
1400 psig = PCNTL_G(spares);
1401 if (!psig) {
1402 /* oops, too many signals for us to track, so we'll forget about this one */
1403 return;
1404 }
1405 PCNTL_G(spares) = psig->next;
1406
1407 psig->signo = signo;
1408 psig->next = NULL;
1409
1410 #ifdef HAVE_STRUCT_SIGINFO_T
1411 psig->siginfo = *siginfo;
1412 #endif
1413
1414 /* the head check is important, as the tick handler cannot atomically clear both
1415 * the head and tail */
1416 if (PCNTL_G(head) && PCNTL_G(tail)) {
1417 PCNTL_G(tail)->next = psig;
1418 } else {
1419 PCNTL_G(head) = psig;
1420 }
1421 PCNTL_G(tail) = psig;
1422 PCNTL_G(pending_signals) = 1;
1423 if (PCNTL_G(async_signals)) {
1424 EG(vm_interrupt) = 1;
1425 }
1426 }
1427
pcntl_signal_dispatch()1428 void pcntl_signal_dispatch()
1429 {
1430 zval params[2], *handle, retval;
1431 struct php_pcntl_pending_signal *queue, *next;
1432 sigset_t mask;
1433 sigset_t old_mask;
1434
1435 if(!PCNTL_G(pending_signals)) {
1436 return;
1437 }
1438
1439 /* Mask all signals */
1440 sigfillset(&mask);
1441 sigprocmask(SIG_BLOCK, &mask, &old_mask);
1442
1443 /* Bail if the queue is empty or if we are already playing the queue */
1444 if (!PCNTL_G(head) || PCNTL_G(processing_signal_queue)) {
1445 sigprocmask(SIG_SETMASK, &old_mask, NULL);
1446 return;
1447 }
1448
1449 /* Prevent reentrant handler calls */
1450 PCNTL_G(processing_signal_queue) = 1;
1451
1452 queue = PCNTL_G(head);
1453 PCNTL_G(head) = NULL; /* simple stores are atomic */
1454
1455 /* Allocate */
1456 while (queue) {
1457 if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {
1458 if (Z_TYPE_P(handle) != IS_LONG) {
1459 ZVAL_NULL(&retval);
1460 ZVAL_LONG(¶ms[0], queue->signo);
1461 #ifdef HAVE_STRUCT_SIGINFO_T
1462 array_init(¶ms[1]);
1463 pcntl_siginfo_to_zval(queue->signo, &queue->siginfo, ¶ms[1]);
1464 #else
1465 ZVAL_NULL(¶ms[1]);
1466 #endif
1467
1468 /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
1469 /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
1470 call_user_function(EG(function_table), NULL, handle, &retval, 2, params);
1471 zval_ptr_dtor(&retval);
1472 #ifdef HAVE_STRUCT_SIGINFO_T
1473 zval_ptr_dtor(¶ms[1]);
1474 #endif
1475 }
1476 }
1477
1478 next = queue->next;
1479 queue->next = PCNTL_G(spares);
1480 PCNTL_G(spares) = queue;
1481 queue = next;
1482 }
1483
1484 PCNTL_G(pending_signals) = 0;
1485
1486 /* Re-enable queue */
1487 PCNTL_G(processing_signal_queue) = 0;
1488
1489 /* return signal mask to previous state */
1490 sigprocmask(SIG_SETMASK, &old_mask, NULL);
1491 }
1492
1493 /* {{{ proto bool pcntl_async_signals([bool on[)
1494 Enable/disable asynchronous signal handling and return the old setting. */
PHP_FUNCTION(pcntl_async_signals)1495 PHP_FUNCTION(pcntl_async_signals)
1496 {
1497 zend_bool on;
1498
1499 if (ZEND_NUM_ARGS() == 0) {
1500 RETURN_BOOL(PCNTL_G(async_signals));
1501 }
1502 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &on) == FAILURE) {
1503 return;
1504 }
1505 RETVAL_BOOL(PCNTL_G(async_signals));
1506 PCNTL_G(async_signals) = on;
1507 }
1508 /* }}} */
1509
pcntl_interrupt_function(zend_execute_data * execute_data)1510 static void pcntl_interrupt_function(zend_execute_data *execute_data)
1511 {
1512 pcntl_signal_dispatch();
1513 if (orig_interrupt_function) {
1514 orig_interrupt_function(execute_data);
1515 }
1516 }
1517
1518 /*
1519 * Local variables:
1520 * tab-width: 4
1521 * c-basic-offset: 4
1522 * indent-tabs-mode: t
1523 * End:
1524 */
1525