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