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(¶ms[0], queue->signo);
1358 #ifdef HAVE_STRUCT_SIGINFO_T
1359 array_init(¶ms[1]);
1360 pcntl_siginfo_to_zval(queue->signo, &queue->siginfo, ¶ms[1]);
1361 #else
1362 ZVAL_NULL(¶ms[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(¶ms[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