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