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(¶ms[0], queue->signo);
1402 #ifdef HAVE_STRUCT_SIGINFO_T
1403 array_init(¶ms[1]);
1404 pcntl_siginfo_to_zval(queue->signo, &queue->siginfo, ¶ms[1]);
1405 #else
1406 ZVAL_NULL(¶ms[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(¶ms[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