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