xref: /PHP-5.5/ext/pcntl/pcntl.c (revision be9b2a95)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2015 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Jason Greene <jason@inetgurus.net>                           |
16    +----------------------------------------------------------------------+
17  */
18 
19 /* $Id$ */
20 
21 #define PCNTL_DEBUG 0
22 
23 #if PCNTL_DEBUG
24 #define DEBUG_OUT printf("DEBUG: ");printf
25 #define IF_DEBUG(z) z
26 #else
27 #define IF_DEBUG(z)
28 #endif
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 
34 #include "php.h"
35 #include "php_ini.h"
36 #include "ext/standard/info.h"
37 #include "php_pcntl.h"
38 #include "php_signal.h"
39 #include "php_ticks.h"
40 
41 #if HAVE_GETPRIORITY || HAVE_SETPRIORITY || HAVE_WAIT3
42 #include <sys/wait.h>
43 #include <sys/time.h>
44 #include <sys/resource.h>
45 #endif
46 
47 #include <errno.h>
48 
49 ZEND_DECLARE_MODULE_GLOBALS(pcntl)
50 static PHP_GINIT_FUNCTION(pcntl);
51 
52 /* {{{ arginfo */
53 ZEND_BEGIN_ARG_INFO(arginfo_pcntl_void, 0)
54 ZEND_END_ARG_INFO()
55 
56 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_waitpid, 0, 0, 2)
57 	ZEND_ARG_INFO(0, pid)
58 	ZEND_ARG_INFO(1, status)
59 	ZEND_ARG_INFO(0, options)
60 ZEND_END_ARG_INFO()
61 
62 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wait, 0, 0, 1)
63 	ZEND_ARG_INFO(1, status)
64 	ZEND_ARG_INFO(0, options)
65 ZEND_END_ARG_INFO()
66 
67 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_signal, 0, 0, 2)
68 	ZEND_ARG_INFO(0, signo)
69 	ZEND_ARG_INFO(0, handler)
70 	ZEND_ARG_INFO(0, restart_syscalls)
71 ZEND_END_ARG_INFO()
72 
73 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigprocmask, 0, 0, 2)
74 	ZEND_ARG_INFO(0, how)
75 	ZEND_ARG_INFO(0, set)
76 	ZEND_ARG_INFO(1, oldset)
77 ZEND_END_ARG_INFO()
78 
79 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigwaitinfo, 0, 0, 1)
80 	ZEND_ARG_INFO(0, set)
81 	ZEND_ARG_INFO(1, info)
82 ZEND_END_ARG_INFO()
83 
84 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_sigtimedwait, 0, 0, 1)
85 	ZEND_ARG_INFO(0, set)
86 	ZEND_ARG_INFO(1, info)
87 	ZEND_ARG_INFO(0, seconds)
88 	ZEND_ARG_INFO(0, nanoseconds)
89 ZEND_END_ARG_INFO()
90 
91 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexited, 0, 0, 1)
92 	ZEND_ARG_INFO(0, status)
93 ZEND_END_ARG_INFO()
94 
95 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifstopped, 0, 0, 1)
96 	ZEND_ARG_INFO(0, status)
97 ZEND_END_ARG_INFO()
98 
99 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifsignaled, 0, 0, 1)
100 	ZEND_ARG_INFO(0, status)
101 ZEND_END_ARG_INFO()
102 
103 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wifexitstatus, 0, 0, 1)
104 	ZEND_ARG_INFO(0, status)
105 ZEND_END_ARG_INFO()
106 
107 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wtermsig, 0, 0, 1)
108 	ZEND_ARG_INFO(0, status)
109 ZEND_END_ARG_INFO()
110 
111 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_wstopsig, 0, 0, 1)
112 	ZEND_ARG_INFO(0, status)
113 ZEND_END_ARG_INFO()
114 
115 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_exec, 0, 0, 1)
116 	ZEND_ARG_INFO(0, path)
117 	ZEND_ARG_INFO(0, args)
118 	ZEND_ARG_INFO(0, envs)
119 ZEND_END_ARG_INFO()
120 
121 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_alarm, 0, 0, 1)
122 	ZEND_ARG_INFO(0, seconds)
123 ZEND_END_ARG_INFO()
124 
125 #ifdef HAVE_GETPRIORITY
126 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_getpriority, 0, 0, 0)
127 	ZEND_ARG_INFO(0, pid)
128 	ZEND_ARG_INFO(0, process_identifier)
129 ZEND_END_ARG_INFO()
130 #endif
131 
132 #ifdef HAVE_SETPRIORITY
133 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_setpriority, 0, 0, 1)
134 	ZEND_ARG_INFO(0, priority)
135 	ZEND_ARG_INFO(0, pid)
136 	ZEND_ARG_INFO(0, process_identifier)
137 ZEND_END_ARG_INFO()
138 #endif
139 
140 ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_strerror, 0, 0, 1)
141         ZEND_ARG_INFO(0, errno)
142 ZEND_END_ARG_INFO()
143 /* }}} */
144 
145 const zend_function_entry pcntl_functions[] = {
146 	PHP_FE(pcntl_fork,			arginfo_pcntl_void)
147 	PHP_FE(pcntl_waitpid,		arginfo_pcntl_waitpid)
148 	PHP_FE(pcntl_wait,			arginfo_pcntl_wait)
149 	PHP_FE(pcntl_signal,		arginfo_pcntl_signal)
150 	PHP_FE(pcntl_signal_dispatch,	arginfo_pcntl_void)
151 	PHP_FE(pcntl_wifexited,		arginfo_pcntl_wifexited)
152 	PHP_FE(pcntl_wifstopped,	arginfo_pcntl_wifstopped)
153 	PHP_FE(pcntl_wifsignaled,	arginfo_pcntl_wifsignaled)
154 	PHP_FE(pcntl_wexitstatus,	arginfo_pcntl_wifexitstatus)
155 	PHP_FE(pcntl_wtermsig,		arginfo_pcntl_wtermsig)
156 	PHP_FE(pcntl_wstopsig,		arginfo_pcntl_wstopsig)
157 	PHP_FE(pcntl_exec,			arginfo_pcntl_exec)
158 	PHP_FE(pcntl_alarm,			arginfo_pcntl_alarm)
159 	PHP_FE(pcntl_get_last_error,	arginfo_pcntl_void)
160 	PHP_FALIAS(pcntl_errno, pcntl_get_last_error,	NULL)
161 	PHP_FE(pcntl_strerror,		arginfo_pcntl_strerror)
162 #ifdef HAVE_GETPRIORITY
163 	PHP_FE(pcntl_getpriority,	arginfo_pcntl_getpriority)
164 #endif
165 #ifdef HAVE_SETPRIORITY
166 	PHP_FE(pcntl_setpriority,	arginfo_pcntl_setpriority)
167 #endif
168 #ifdef HAVE_SIGPROCMASK
169 	PHP_FE(pcntl_sigprocmask,	arginfo_pcntl_sigprocmask)
170 #endif
171 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
172 	PHP_FE(pcntl_sigwaitinfo,	arginfo_pcntl_sigwaitinfo)
173 	PHP_FE(pcntl_sigtimedwait,	arginfo_pcntl_sigtimedwait)
174 #endif
175 	PHP_FE_END
176 };
177 
178 zend_module_entry pcntl_module_entry = {
179 	STANDARD_MODULE_HEADER,
180 	"pcntl",
181 	pcntl_functions,
182 	PHP_MINIT(pcntl),
183 	PHP_MSHUTDOWN(pcntl),
184 	PHP_RINIT(pcntl),
185 	PHP_RSHUTDOWN(pcntl),
186 	PHP_MINFO(pcntl),
187 	NO_VERSION_YET,
188 	PHP_MODULE_GLOBALS(pcntl),
189 	PHP_GINIT(pcntl),
190 	NULL,
191 	NULL,
192 	STANDARD_MODULE_PROPERTIES_EX
193 };
194 
195 #ifdef COMPILE_DL_PCNTL
196 ZEND_GET_MODULE(pcntl)
197 #endif
198 
199 static void pcntl_signal_handler(int);
200 static void pcntl_signal_dispatch();
201 
php_register_signal_constants(INIT_FUNC_ARGS)202 void php_register_signal_constants(INIT_FUNC_ARGS)
203 {
204 
205 	/* Wait Constants */
206 #ifdef WNOHANG
207 	REGISTER_LONG_CONSTANT("WNOHANG",  (long) WNOHANG, CONST_CS | CONST_PERSISTENT);
208 #endif
209 #ifdef WUNTRACED
210 	REGISTER_LONG_CONSTANT("WUNTRACED",  (long) WUNTRACED, CONST_CS | CONST_PERSISTENT);
211 #endif
212 
213 	/* Signal Constants */
214 	REGISTER_LONG_CONSTANT("SIG_IGN",  (long) SIG_IGN, CONST_CS | CONST_PERSISTENT);
215 	REGISTER_LONG_CONSTANT("SIG_DFL",  (long) SIG_DFL, CONST_CS | CONST_PERSISTENT);
216 	REGISTER_LONG_CONSTANT("SIG_ERR",  (long) SIG_ERR, CONST_CS | CONST_PERSISTENT);
217 	REGISTER_LONG_CONSTANT("SIGHUP",   (long) SIGHUP,  CONST_CS | CONST_PERSISTENT);
218 	REGISTER_LONG_CONSTANT("SIGINT",   (long) SIGINT,  CONST_CS | CONST_PERSISTENT);
219 	REGISTER_LONG_CONSTANT("SIGQUIT",  (long) SIGQUIT, CONST_CS | CONST_PERSISTENT);
220 	REGISTER_LONG_CONSTANT("SIGILL",   (long) SIGILL,  CONST_CS | CONST_PERSISTENT);
221 	REGISTER_LONG_CONSTANT("SIGTRAP",  (long) SIGTRAP, CONST_CS | CONST_PERSISTENT);
222 	REGISTER_LONG_CONSTANT("SIGABRT",  (long) SIGABRT, CONST_CS | CONST_PERSISTENT);
223 #ifdef SIGIOT
224 	REGISTER_LONG_CONSTANT("SIGIOT",   (long) SIGIOT,  CONST_CS | CONST_PERSISTENT);
225 #endif
226 	REGISTER_LONG_CONSTANT("SIGBUS",   (long) SIGBUS,  CONST_CS | CONST_PERSISTENT);
227 	REGISTER_LONG_CONSTANT("SIGFPE",   (long) SIGFPE,  CONST_CS | CONST_PERSISTENT);
228 	REGISTER_LONG_CONSTANT("SIGKILL",  (long) SIGKILL, CONST_CS | CONST_PERSISTENT);
229 	REGISTER_LONG_CONSTANT("SIGUSR1",  (long) SIGUSR1, CONST_CS | CONST_PERSISTENT);
230 	REGISTER_LONG_CONSTANT("SIGSEGV",  (long) SIGSEGV, CONST_CS | CONST_PERSISTENT);
231 	REGISTER_LONG_CONSTANT("SIGUSR2",  (long) SIGUSR2, CONST_CS | CONST_PERSISTENT);
232 	REGISTER_LONG_CONSTANT("SIGPIPE",  (long) SIGPIPE, CONST_CS | CONST_PERSISTENT);
233 	REGISTER_LONG_CONSTANT("SIGALRM",  (long) SIGALRM, CONST_CS | CONST_PERSISTENT);
234 	REGISTER_LONG_CONSTANT("SIGTERM",  (long) SIGTERM, CONST_CS | CONST_PERSISTENT);
235 #ifdef SIGSTKFLT
236 	REGISTER_LONG_CONSTANT("SIGSTKFLT",(long) SIGSTKFLT, CONST_CS | CONST_PERSISTENT);
237 #endif
238 #ifdef SIGCLD
239 	REGISTER_LONG_CONSTANT("SIGCLD",   (long) SIGCLD, CONST_CS | CONST_PERSISTENT);
240 #endif
241 #ifdef SIGCHLD
242 	REGISTER_LONG_CONSTANT("SIGCHLD",  (long) SIGCHLD, CONST_CS | CONST_PERSISTENT);
243 #endif
244 	REGISTER_LONG_CONSTANT("SIGCONT",  (long) SIGCONT, CONST_CS | CONST_PERSISTENT);
245 	REGISTER_LONG_CONSTANT("SIGSTOP",  (long) SIGSTOP, CONST_CS | CONST_PERSISTENT);
246 	REGISTER_LONG_CONSTANT("SIGTSTP",  (long) SIGTSTP, CONST_CS | CONST_PERSISTENT);
247 	REGISTER_LONG_CONSTANT("SIGTTIN",  (long) SIGTTIN, CONST_CS | CONST_PERSISTENT);
248 	REGISTER_LONG_CONSTANT("SIGTTOU",  (long) SIGTTOU, CONST_CS | CONST_PERSISTENT);
249 	REGISTER_LONG_CONSTANT("SIGURG",   (long) SIGURG , CONST_CS | CONST_PERSISTENT);
250 	REGISTER_LONG_CONSTANT("SIGXCPU",  (long) SIGXCPU, CONST_CS | CONST_PERSISTENT);
251 	REGISTER_LONG_CONSTANT("SIGXFSZ",  (long) SIGXFSZ, CONST_CS | CONST_PERSISTENT);
252 	REGISTER_LONG_CONSTANT("SIGVTALRM",(long) SIGVTALRM, CONST_CS | CONST_PERSISTENT);
253 	REGISTER_LONG_CONSTANT("SIGPROF",  (long) SIGPROF, CONST_CS | CONST_PERSISTENT);
254 	REGISTER_LONG_CONSTANT("SIGWINCH", (long) SIGWINCH, CONST_CS | CONST_PERSISTENT);
255 #ifdef SIGPOLL
256 	REGISTER_LONG_CONSTANT("SIGPOLL",  (long) SIGPOLL, CONST_CS | CONST_PERSISTENT);
257 #endif
258 	REGISTER_LONG_CONSTANT("SIGIO",    (long) SIGIO, CONST_CS | CONST_PERSISTENT);
259 #ifdef SIGPWR
260 	REGISTER_LONG_CONSTANT("SIGPWR",   (long) SIGPWR, CONST_CS | CONST_PERSISTENT);
261 #endif
262 #ifdef SIGSYS
263 	REGISTER_LONG_CONSTANT("SIGSYS",   (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
264 	REGISTER_LONG_CONSTANT("SIGBABY",  (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
265 #endif
266 
267 #if HAVE_GETPRIORITY || HAVE_SETPRIORITY
268 	REGISTER_LONG_CONSTANT("PRIO_PGRP", PRIO_PGRP, CONST_CS | CONST_PERSISTENT);
269 	REGISTER_LONG_CONSTANT("PRIO_USER", PRIO_USER, CONST_CS | CONST_PERSISTENT);
270 	REGISTER_LONG_CONSTANT("PRIO_PROCESS", PRIO_PROCESS, CONST_CS | CONST_PERSISTENT);
271 #endif
272 
273 	/* {{{ "how" argument for sigprocmask */
274 #ifdef HAVE_SIGPROCMASK
275 	REGISTER_LONG_CONSTANT("SIG_BLOCK",   SIG_BLOCK, CONST_CS | CONST_PERSISTENT);
276 	REGISTER_LONG_CONSTANT("SIG_UNBLOCK", SIG_UNBLOCK, CONST_CS | CONST_PERSISTENT);
277 	REGISTER_LONG_CONSTANT("SIG_SETMASK", SIG_SETMASK, CONST_CS | CONST_PERSISTENT);
278 #endif
279 	/* }}} */
280 
281 	/* {{{ si_code */
282 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
283 	REGISTER_LONG_CONSTANT("SI_USER",    SI_USER,    CONST_CS | CONST_PERSISTENT);
284 #ifdef SI_NOINFO
285 	REGISTER_LONG_CONSTANT("SI_NOINFO",  SI_NOINFO,  CONST_CS | CONST_PERSISTENT);
286 #endif
287 #ifdef SI_KERNEL
288 	REGISTER_LONG_CONSTANT("SI_KERNEL",  SI_KERNEL,  CONST_CS | CONST_PERSISTENT);
289 #endif
290 	REGISTER_LONG_CONSTANT("SI_QUEUE",   SI_QUEUE,   CONST_CS | CONST_PERSISTENT);
291 	REGISTER_LONG_CONSTANT("SI_TIMER",   SI_TIMER,   CONST_CS | CONST_PERSISTENT);
292 	REGISTER_LONG_CONSTANT("SI_MESGQ",   SI_MESGQ,   CONST_CS | CONST_PERSISTENT);
293 	REGISTER_LONG_CONSTANT("SI_ASYNCIO", SI_ASYNCIO, CONST_CS | CONST_PERSISTENT);
294 #ifdef SI_SIGIO
295 	REGISTER_LONG_CONSTANT("SI_SIGIO",   SI_SIGIO,   CONST_CS | CONST_PERSISTENT);
296 #endif
297 #ifdef SI_TKILL
298 	REGISTER_LONG_CONSTANT("SI_TKILL",   SI_TKILL,   CONST_CS | CONST_PERSISTENT);
299 #endif
300 
301 	/* si_code for SIGCHILD */
302 #ifdef CLD_EXITED
303 	REGISTER_LONG_CONSTANT("CLD_EXITED",    CLD_EXITED,    CONST_CS | CONST_PERSISTENT);
304 #endif
305 #ifdef CLD_KILLED
306 	REGISTER_LONG_CONSTANT("CLD_KILLED",    CLD_KILLED,    CONST_CS | CONST_PERSISTENT);
307 #endif
308 #ifdef CLD_DUMPED
309 	REGISTER_LONG_CONSTANT("CLD_DUMPED",    CLD_DUMPED,    CONST_CS | CONST_PERSISTENT);
310 #endif
311 #ifdef CLD_TRAPPED
312 	REGISTER_LONG_CONSTANT("CLD_TRAPPED",   CLD_TRAPPED,   CONST_CS | CONST_PERSISTENT);
313 #endif
314 #ifdef CLD_STOPPED
315 	REGISTER_LONG_CONSTANT("CLD_STOPPED",   CLD_STOPPED,   CONST_CS | CONST_PERSISTENT);
316 #endif
317 #ifdef CLD_CONTINUED
318 	REGISTER_LONG_CONSTANT("CLD_CONTINUED", CLD_CONTINUED, CONST_CS | CONST_PERSISTENT);
319 #endif
320 
321 	/* si_code for SIGTRAP */
322 #ifdef TRAP_BRKPT
323 	REGISTER_LONG_CONSTANT("TRAP_BRKPT", TRAP_BRKPT, CONST_CS | CONST_PERSISTENT);
324 #endif
325 #ifdef TRAP_TRACE
326 	REGISTER_LONG_CONSTANT("TRAP_TRACE", TRAP_TRACE, CONST_CS | CONST_PERSISTENT);
327 #endif
328 
329 	/* si_code for SIGPOLL */
330 #ifdef POLL_IN
331 	REGISTER_LONG_CONSTANT("POLL_IN",  POLL_IN,  CONST_CS | CONST_PERSISTENT);
332 #endif
333 #ifdef POLL_OUT
334 	REGISTER_LONG_CONSTANT("POLL_OUT", POLL_OUT, CONST_CS | CONST_PERSISTENT);
335 #endif
336 #ifdef POLL_MSG
337 	REGISTER_LONG_CONSTANT("POLL_MSG", POLL_MSG, CONST_CS | CONST_PERSISTENT);
338 #endif
339 #ifdef POLL_ERR
340 	REGISTER_LONG_CONSTANT("POLL_ERR", POLL_ERR, CONST_CS | CONST_PERSISTENT);
341 #endif
342 #ifdef POLL_PRI
343 	REGISTER_LONG_CONSTANT("POLL_PRI", POLL_PRI, CONST_CS | CONST_PERSISTENT);
344 #endif
345 #ifdef POLL_HUP
346 	REGISTER_LONG_CONSTANT("POLL_HUP", POLL_HUP, CONST_CS | CONST_PERSISTENT);
347 #endif
348 
349 #ifdef ILL_ILLOPC
350 	REGISTER_LONG_CONSTANT("ILL_ILLOPC", ILL_ILLOPC, CONST_CS | CONST_PERSISTENT);
351 #endif
352 #ifdef ILL_ILLOPN
353 	REGISTER_LONG_CONSTANT("ILL_ILLOPN", ILL_ILLOPN, CONST_CS | CONST_PERSISTENT);
354 #endif
355 #ifdef ILL_ILLADR
356 	REGISTER_LONG_CONSTANT("ILL_ILLADR", ILL_ILLADR, CONST_CS | CONST_PERSISTENT);
357 #endif
358 #ifdef ILL_ILLTRP
359 	REGISTER_LONG_CONSTANT("ILL_ILLTRP", ILL_ILLTRP, CONST_CS | CONST_PERSISTENT);
360 #endif
361 #ifdef ILL_PRVOPC
362 	REGISTER_LONG_CONSTANT("ILL_PRVOPC", ILL_PRVOPC, CONST_CS | CONST_PERSISTENT);
363 #endif
364 #ifdef ILL_PRVREG
365 	REGISTER_LONG_CONSTANT("ILL_PRVREG", ILL_PRVREG, CONST_CS | CONST_PERSISTENT);
366 #endif
367 #ifdef ILL_COPROC
368 	REGISTER_LONG_CONSTANT("ILL_COPROC", ILL_COPROC, CONST_CS | CONST_PERSISTENT);
369 #endif
370 #ifdef ILL_BADSTK
371 	REGISTER_LONG_CONSTANT("ILL_BADSTK", ILL_BADSTK, CONST_CS | CONST_PERSISTENT);
372 #endif
373 
374 #ifdef FPE_INTDIV
375 	REGISTER_LONG_CONSTANT("FPE_INTDIV", FPE_INTDIV, CONST_CS | CONST_PERSISTENT);
376 #endif
377 #ifdef FPE_INTOVF
378 	REGISTER_LONG_CONSTANT("FPE_INTOVF", FPE_INTOVF, CONST_CS | CONST_PERSISTENT);
379 #endif
380 #ifdef FPE_FLTDIV
381 	REGISTER_LONG_CONSTANT("FPE_FLTDIV", FPE_FLTDIV, CONST_CS | CONST_PERSISTENT);
382 #endif
383 #ifdef FPE_FLTOVF
384 	REGISTER_LONG_CONSTANT("FPE_FLTOVF", FPE_FLTOVF, CONST_CS | CONST_PERSISTENT);
385 #endif
386 #ifdef FPE_FLTUND
387 	REGISTER_LONG_CONSTANT("FPE_FLTUND", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
388 #endif
389 #ifdef FPE_FLTRES
390 	REGISTER_LONG_CONSTANT("FPE_FLTRES", FPE_FLTRES, CONST_CS | CONST_PERSISTENT);
391 #endif
392 #ifdef FPE_FLTINV
393 	REGISTER_LONG_CONSTANT("FPE_FLTINV", FPE_FLTINV, CONST_CS | CONST_PERSISTENT);
394 #endif
395 #ifdef FPE_FLTSUB
396 	REGISTER_LONG_CONSTANT("FPE_FLTSUB", FPE_FLTSUB, CONST_CS | CONST_PERSISTENT);
397 #endif
398 
399 #ifdef SEGV_MAPERR
400 	REGISTER_LONG_CONSTANT("SEGV_MAPERR", SEGV_MAPERR, CONST_CS | CONST_PERSISTENT);
401 #endif
402 #ifdef SEGV_ACCERR
403 	REGISTER_LONG_CONSTANT("SEGV_ACCERR", SEGV_ACCERR, CONST_CS | CONST_PERSISTENT);
404 #endif
405 
406 #ifdef BUS_ADRALN
407 	REGISTER_LONG_CONSTANT("BUS_ADRALN", BUS_ADRALN, CONST_CS | CONST_PERSISTENT);
408 #endif
409 #ifdef BUS_ADRERR
410 	REGISTER_LONG_CONSTANT("BUS_ADRERR", BUS_ADRERR, CONST_CS | CONST_PERSISTENT);
411 #endif
412 #ifdef BUS_OBJERR
413 	REGISTER_LONG_CONSTANT("BUS_OBJERR", BUS_OBJERR, CONST_CS | CONST_PERSISTENT);
414 #endif
415 #endif /* HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT */
416 	/* }}} */
417 }
418 
php_pcntl_register_errno_constants(INIT_FUNC_ARGS)419 static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS)
420 {
421 #ifdef EINTR
422 	REGISTER_PCNTL_ERRNO_CONSTANT(EINTR);
423 #endif
424 #ifdef ECHILD
425 	REGISTER_PCNTL_ERRNO_CONSTANT(ECHILD);
426 #endif
427 #ifdef EINVAL
428 	REGISTER_PCNTL_ERRNO_CONSTANT(EINVAL);
429 #endif
430 #ifdef EAGAIN
431 	REGISTER_PCNTL_ERRNO_CONSTANT(EAGAIN);
432 #endif
433 #ifdef ESRCH
434 	REGISTER_PCNTL_ERRNO_CONSTANT(ESRCH);
435 #endif
436 #ifdef EACCES
437 	REGISTER_PCNTL_ERRNO_CONSTANT(EACCES);
438 #endif
439 #ifdef EPERM
440 	REGISTER_PCNTL_ERRNO_CONSTANT(EPERM);
441 #endif
442 #ifdef ENOMEM
443 	REGISTER_PCNTL_ERRNO_CONSTANT(ENOMEM);
444 #endif
445 #ifdef E2BIG
446 	REGISTER_PCNTL_ERRNO_CONSTANT(E2BIG);
447 #endif
448 #ifdef EFAULT
449 	REGISTER_PCNTL_ERRNO_CONSTANT(EFAULT);
450 #endif
451 #ifdef EIO
452 	REGISTER_PCNTL_ERRNO_CONSTANT(EIO);
453 #endif
454 #ifdef EISDIR
455 	REGISTER_PCNTL_ERRNO_CONSTANT(EISDIR);
456 #endif
457 #ifdef ELIBBAD
458 	REGISTER_PCNTL_ERRNO_CONSTANT(ELIBBAD);
459 #endif
460 #ifdef ELOOP
461 	REGISTER_PCNTL_ERRNO_CONSTANT(ELOOP);
462 #endif
463 #ifdef EMFILE
464 	REGISTER_PCNTL_ERRNO_CONSTANT(EMFILE);
465 #endif
466 #ifdef ENAMETOOLONG
467 	REGISTER_PCNTL_ERRNO_CONSTANT(ENAMETOOLONG);
468 #endif
469 #ifdef ENFILE
470 	REGISTER_PCNTL_ERRNO_CONSTANT(ENFILE);
471 #endif
472 #ifdef ENOENT
473 	REGISTER_PCNTL_ERRNO_CONSTANT(ENOENT);
474 #endif
475 #ifdef ENOEXEC
476 	REGISTER_PCNTL_ERRNO_CONSTANT(ENOEXEC);
477 #endif
478 #ifdef ENOTDIR
479 	REGISTER_PCNTL_ERRNO_CONSTANT(ENOTDIR);
480 #endif
481 #ifdef ETXTBSY
482 	REGISTER_PCNTL_ERRNO_CONSTANT(ETXTBSY);
483 #endif
484 }
485 
PHP_GINIT_FUNCTION(pcntl)486 static PHP_GINIT_FUNCTION(pcntl)
487 {
488 	memset(pcntl_globals, 0, sizeof(*pcntl_globals));
489 }
490 
PHP_RINIT_FUNCTION(pcntl)491 PHP_RINIT_FUNCTION(pcntl)
492 {
493 	zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0);
494 	PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL;
495 	return SUCCESS;
496 }
497 
PHP_MINIT_FUNCTION(pcntl)498 PHP_MINIT_FUNCTION(pcntl)
499 {
500 	php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
501 	php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);
502 	php_add_tick_function(pcntl_signal_dispatch);
503 
504 	return SUCCESS;
505 }
506 
PHP_MSHUTDOWN_FUNCTION(pcntl)507 PHP_MSHUTDOWN_FUNCTION(pcntl)
508 {
509 	return SUCCESS;
510 }
511 
PHP_RSHUTDOWN_FUNCTION(pcntl)512 PHP_RSHUTDOWN_FUNCTION(pcntl)
513 {
514 	struct php_pcntl_pending_signal *sig;
515 
516 	/* FIXME: if a signal is delivered after this point, things will go pear shaped;
517 	 * need to remove signal handlers */
518 	zend_hash_destroy(&PCNTL_G(php_signal_table));
519 	while (PCNTL_G(head)) {
520 		sig = PCNTL_G(head);
521 		PCNTL_G(head) = sig->next;
522 		efree(sig);
523 	}
524 	while (PCNTL_G(spares)) {
525 		sig = PCNTL_G(spares);
526 		PCNTL_G(spares) = sig->next;
527 		efree(sig);
528 	}
529 	return SUCCESS;
530 }
531 
PHP_MINFO_FUNCTION(pcntl)532 PHP_MINFO_FUNCTION(pcntl)
533 {
534 	php_info_print_table_start();
535 	php_info_print_table_header(2, "pcntl support", "enabled");
536 	php_info_print_table_end();
537 }
538 
539 /* {{{ proto int pcntl_fork(void)
540    Forks the currently running process following the same behavior as the UNIX fork() system call*/
PHP_FUNCTION(pcntl_fork)541 PHP_FUNCTION(pcntl_fork)
542 {
543 	pid_t id;
544 
545 	id = fork();
546 	if (id == -1) {
547 		PCNTL_G(last_error) = errno;
548 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d", errno);
549 	}
550 
551 	RETURN_LONG((long) id);
552 }
553 /* }}} */
554 
555 /* {{{ proto int pcntl_alarm(int seconds)
556    Set an alarm clock for delivery of a signal*/
PHP_FUNCTION(pcntl_alarm)557 PHP_FUNCTION(pcntl_alarm)
558 {
559 	long seconds;
560 
561 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &seconds) == FAILURE)
562 		return;
563 
564 	RETURN_LONG ((long) alarm(seconds));
565 }
566 /* }}} */
567 
568 /* {{{ proto int pcntl_waitpid(int pid, int &status, int options)
569    Waits on or returns the status of a forked child as defined by the waitpid() system call */
PHP_FUNCTION(pcntl_waitpid)570 PHP_FUNCTION(pcntl_waitpid)
571 {
572 	long pid, options = 0;
573 	zval *z_status = NULL;
574 	int status;
575 	pid_t child_id;
576 
577 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|l", &pid, &z_status, &options) == FAILURE)
578 		return;
579 
580 	convert_to_long_ex(&z_status);
581 
582 	status = Z_LVAL_P(z_status);
583 
584 	child_id = waitpid((pid_t) pid, &status, options);
585 
586 	if (child_id < 0) {
587 		PCNTL_G(last_error) = errno;
588 	}
589 
590 	Z_LVAL_P(z_status) = status;
591 
592 	RETURN_LONG((long) child_id);
593 }
594 /* }}} */
595 
596 /* {{{ proto int pcntl_wait(int &status)
597    Waits on or returns the status of a forked child as defined by the waitpid() system call */
PHP_FUNCTION(pcntl_wait)598 PHP_FUNCTION(pcntl_wait)
599 {
600 	long options = 0;
601 	zval *z_status = NULL;
602 	int status;
603 	pid_t child_id;
604 
605 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &z_status, &options) == FAILURE)
606 		return;
607 
608 	convert_to_long_ex(&z_status);
609 
610 	status = Z_LVAL_P(z_status);
611 #ifdef HAVE_WAIT3
612 	if(options) {
613 		child_id = wait3(&status, options, NULL);
614 	}
615 	else {
616 		child_id = wait(&status);
617 	}
618 #else
619 	child_id = wait(&status);
620 #endif
621 	if (child_id < 0) {
622 		PCNTL_G(last_error) = errno;
623 	}
624 
625 	Z_LVAL_P(z_status) = status;
626 
627 	RETURN_LONG((long) child_id);
628 }
629 /* }}} */
630 
631 /* {{{ proto bool pcntl_wifexited(int status)
632    Returns true if the child status code represents a successful exit */
PHP_FUNCTION(pcntl_wifexited)633 PHP_FUNCTION(pcntl_wifexited)
634 {
635 #ifdef WIFEXITED
636 	long status_word;
637 
638 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
639 	       return;
640 	}
641 
642 	if (WIFEXITED(status_word))
643 		RETURN_TRUE;
644 #endif
645 	RETURN_FALSE;
646 }
647 /* }}} */
648 
649 /* {{{ proto bool pcntl_wifstopped(int status)
650    Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
PHP_FUNCTION(pcntl_wifstopped)651 PHP_FUNCTION(pcntl_wifstopped)
652 {
653 #ifdef WIFSTOPPED
654 	long status_word;
655 
656 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
657 	       return;
658 	}
659 
660 	if (WIFSTOPPED(status_word))
661 		RETURN_TRUE;
662 #endif
663 	RETURN_FALSE;
664 }
665 /* }}} */
666 
667 /* {{{ proto bool pcntl_wifsignaled(int status)
668    Returns true if the child status code represents a process that was terminated due to a signal */
PHP_FUNCTION(pcntl_wifsignaled)669 PHP_FUNCTION(pcntl_wifsignaled)
670 {
671 #ifdef WIFSIGNALED
672 	long status_word;
673 
674 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
675 	       return;
676 	}
677 
678 	if (WIFSIGNALED(status_word))
679 		RETURN_TRUE;
680 #endif
681 	RETURN_FALSE;
682 }
683 /* }}} */
684 
685 /* {{{ proto int pcntl_wexitstatus(int status)
686    Returns the status code of a child's exit */
PHP_FUNCTION(pcntl_wexitstatus)687 PHP_FUNCTION(pcntl_wexitstatus)
688 {
689 #ifdef WEXITSTATUS
690 	long status_word;
691 
692 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
693 	       return;
694 	}
695 
696 	RETURN_LONG(WEXITSTATUS(status_word));
697 #else
698 	RETURN_FALSE;
699 #endif
700 }
701 /* }}} */
702 
703 /* {{{ proto int pcntl_wtermsig(int status)
704    Returns the number of the signal that terminated the process who's status code is passed  */
PHP_FUNCTION(pcntl_wtermsig)705 PHP_FUNCTION(pcntl_wtermsig)
706 {
707 #ifdef WTERMSIG
708 	long status_word;
709 
710 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
711 	       return;
712 	}
713 
714 	RETURN_LONG(WTERMSIG(status_word));
715 #else
716 	RETURN_FALSE;
717 #endif
718 }
719 /* }}} */
720 
721 /* {{{ proto int pcntl_wstopsig(int status)
722    Returns the number of the signal that caused the process to stop who's status code is passed */
PHP_FUNCTION(pcntl_wstopsig)723 PHP_FUNCTION(pcntl_wstopsig)
724 {
725 #ifdef WSTOPSIG
726 	long status_word;
727 
728 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &status_word) == FAILURE) {
729 	       return;
730 	}
731 
732 	RETURN_LONG(WSTOPSIG(status_word));
733 #else
734 	RETURN_FALSE;
735 #endif
736 }
737 /* }}} */
738 
739 /* {{{ proto bool pcntl_exec(string path [, array args [, array envs]])
740    Executes specified program in current process space as defined by exec(2) */
PHP_FUNCTION(pcntl_exec)741 PHP_FUNCTION(pcntl_exec)
742 {
743 	zval *args = NULL, *envs = NULL;
744 	zval **element;
745 	HashTable *args_hash, *envs_hash;
746 	int argc = 0, argi = 0;
747 	int envc = 0, envi = 0;
748 	int return_val = 0;
749 	char **argv = NULL, **envp = NULL;
750 	char **current_arg, **pair;
751 	int pair_length;
752 	char *key;
753 	uint key_length;
754 	char *path;
755 	int path_len;
756 	ulong key_num;
757 
758 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|aa", &path, &path_len, &args, &envs) == FAILURE) {
759 		return;
760 	}
761 
762 	if (ZEND_NUM_ARGS() > 1) {
763 		/* Build argument list */
764 		args_hash = HASH_OF(args);
765 		argc = zend_hash_num_elements(args_hash);
766 
767 		argv = safe_emalloc((argc + 2), sizeof(char *), 0);
768 		*argv = path;
769 		for ( zend_hash_internal_pointer_reset(args_hash), current_arg = argv+1;
770 			(argi < argc && (zend_hash_get_current_data(args_hash, (void **) &element) == SUCCESS));
771 			(argi++, current_arg++, zend_hash_move_forward(args_hash)) ) {
772 
773 			convert_to_string_ex(element);
774 			*current_arg = Z_STRVAL_PP(element);
775 		}
776 		*(current_arg) = NULL;
777 	} else {
778 		argv = emalloc(2 * sizeof(char *));
779 		*argv = path;
780 		*(argv+1) = NULL;
781 	}
782 
783 	if ( ZEND_NUM_ARGS() == 3 ) {
784 		/* Build environment pair list */
785 		envs_hash = HASH_OF(envs);
786 		envc = zend_hash_num_elements(envs_hash);
787 
788 		envp = safe_emalloc((envc + 1), sizeof(char *), 0);
789 		for ( zend_hash_internal_pointer_reset(envs_hash), pair = envp;
790 			(envi < envc && (zend_hash_get_current_data(envs_hash, (void **) &element) == SUCCESS));
791 			(envi++, pair++, zend_hash_move_forward(envs_hash)) ) {
792 			switch (return_val = zend_hash_get_current_key_ex(envs_hash, &key, &key_length, &key_num, 0, NULL)) {
793 				case HASH_KEY_IS_LONG:
794 					key = emalloc(101);
795 					snprintf(key, 100, "%ld", key_num);
796 					key_length = strlen(key);
797 					break;
798 				case HASH_KEY_NON_EXISTENT:
799 					pair--;
800 					continue;
801 			}
802 
803 			convert_to_string_ex(element);
804 
805 			/* Length of element + equal sign + length of key + null */
806 			pair_length = Z_STRLEN_PP(element) + key_length + 2;
807 			*pair = emalloc(pair_length);
808 			strlcpy(*pair, key, key_length);
809 			strlcat(*pair, "=", pair_length);
810 			strlcat(*pair, Z_STRVAL_PP(element), pair_length);
811 
812 			/* Cleanup */
813 			if (return_val == HASH_KEY_IS_LONG) efree(key);
814 		}
815 		*(pair) = NULL;
816 
817 		if (execve(path, argv, envp) == -1) {
818 			PCNTL_G(last_error) = errno;
819 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
820 		}
821 
822 		/* Cleanup */
823 		for (pair = envp; *pair != NULL; pair++) efree(*pair);
824 		efree(envp);
825 	} else {
826 
827 		if (execv(path, argv) == -1) {
828 			PCNTL_G(last_error) = errno;
829 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
830 		}
831 	}
832 
833 	efree(argv);
834 
835 	RETURN_FALSE;
836 }
837 /* }}} */
838 
839 /* {{{ proto bool pcntl_signal(int signo, callback handle [, bool restart_syscalls])
840    Assigns a system signal handler to a PHP function */
PHP_FUNCTION(pcntl_signal)841 PHP_FUNCTION(pcntl_signal)
842 {
843 	zval *handle, **dest_handle = NULL;
844 	char *func_name;
845 	long signo;
846 	zend_bool restart_syscalls = 1;
847 
848 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) {
849 		return;
850 	}
851 
852 	if (signo < 1 || signo > 32) {
853 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid signal");
854 		RETURN_FALSE;
855 	}
856 
857 	if (!PCNTL_G(spares)) {
858 		/* since calling malloc() from within a signal handler is not portable,
859 		 * pre-allocate a few records for recording signals */
860 		int i;
861 		for (i = 0; i < 32; i++) {
862 			struct php_pcntl_pending_signal *psig;
863 
864 			psig = emalloc(sizeof(*psig));
865 			psig->next = PCNTL_G(spares);
866 			PCNTL_G(spares) = psig;
867 		}
868 	}
869 
870 	/* Special long value case for SIG_DFL and SIG_IGN */
871 	if (Z_TYPE_P(handle) == IS_LONG) {
872 		if (Z_LVAL_P(handle) != (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) {
873 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for handle argument specified");
874 			RETURN_FALSE;
875 		}
876 		if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
877 			PCNTL_G(last_error) = errno;
878 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
879 			RETURN_FALSE;
880 		}
881 		zend_hash_index_del(&PCNTL_G(php_signal_table), signo);
882 		RETURN_TRUE;
883 	}
884 
885 	if (!zend_is_callable(handle, 0, &func_name TSRMLS_CC)) {
886 		PCNTL_G(last_error) = EINVAL;
887 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a callable function name error", func_name);
888 		efree(func_name);
889 		RETURN_FALSE;
890 	}
891 	efree(func_name);
892 
893 	/* Add the function name to our signal table */
894 	zend_hash_index_update(&PCNTL_G(php_signal_table), signo, (void **) &handle, sizeof(zval *), (void **) &dest_handle);
895 	if (dest_handle) zval_add_ref(dest_handle);
896 
897 	if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == SIG_ERR) {
898 		PCNTL_G(last_error) = errno;
899 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
900 		RETURN_FALSE;
901 	}
902 	RETURN_TRUE;
903 }
904 /* }}} */
905 
906 /* {{{ proto bool pcntl_signal_dispatch()
907    Dispatch signals to signal handlers */
PHP_FUNCTION(pcntl_signal_dispatch)908 PHP_FUNCTION(pcntl_signal_dispatch)
909 {
910 	pcntl_signal_dispatch();
911 	RETURN_TRUE;
912 }
913 /* }}} */
914 
915 #ifdef HAVE_SIGPROCMASK
916 /* {{{ proto bool pcntl_sigprocmask(int how, array set[, array &oldset])
917    Examine and change blocked signals */
PHP_FUNCTION(pcntl_sigprocmask)918 PHP_FUNCTION(pcntl_sigprocmask)
919 {
920 	long          how, signo;
921 	zval         *user_set, *user_oldset = NULL, **user_signo;
922 	sigset_t      set, oldset;
923 	HashPosition  pos;
924 
925 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "la|z", &how, &user_set, &user_oldset) == FAILURE) {
926 		return;
927 	}
928 
929 	if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) {
930 		PCNTL_G(last_error) = errno;
931 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
932 		RETURN_FALSE;
933 	}
934 
935 	zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos);
936 	while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS)
937 	{
938 		if (Z_TYPE_PP(user_signo) != IS_LONG) {
939 			SEPARATE_ZVAL(user_signo);
940 			convert_to_long_ex(user_signo);
941 		}
942 		signo = Z_LVAL_PP(user_signo);
943 		if (sigaddset(&set, signo) != 0) {
944 			PCNTL_G(last_error) = errno;
945 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
946 			RETURN_FALSE;
947 		}
948 		zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
949 	}
950 
951 	if (sigprocmask(how, &set, &oldset) != 0) {
952 		PCNTL_G(last_error) = errno;
953 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
954 		RETURN_FALSE;
955 	}
956 
957 	if (user_oldset != NULL) {
958 		if (Z_TYPE_P(user_oldset) != IS_ARRAY) {
959 			zval_dtor(user_oldset);
960 			array_init(user_oldset);
961 		} else {
962 			zend_hash_clean(Z_ARRVAL_P(user_oldset));
963 		}
964 		for (signo = 1; signo < MAX(NSIG-1, SIGRTMAX); ++signo) {
965 			if (sigismember(&oldset, signo) != 1) {
966 				continue;
967 			}
968 			add_next_index_long(user_oldset, signo);
969 		}
970 	}
971 
972 	RETURN_TRUE;
973 }
974 /* }}} */
975 #endif
976 
977 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS,int timedwait)978 static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */
979 {
980 	zval            *user_set, **user_signo, *user_siginfo = NULL;
981 	long             tv_sec = 0, tv_nsec = 0;
982 	sigset_t         set;
983 	HashPosition     pos;
984 	int              signo;
985 	siginfo_t        siginfo;
986 	struct timespec  timeout;
987 
988 	if (timedwait) {
989 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) {
990 			return;
991 		}
992 	} else {
993 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &user_set, &user_siginfo) == FAILURE) {
994 			return;
995 		}
996 	}
997 
998 	if (sigemptyset(&set) != 0) {
999 		PCNTL_G(last_error) = errno;
1000 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
1001 		RETURN_FALSE;
1002 	}
1003 
1004 	zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos);
1005 	while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS)
1006 	{
1007 		if (Z_TYPE_PP(user_signo) != IS_LONG) {
1008 			SEPARATE_ZVAL(user_signo);
1009 			convert_to_long_ex(user_signo);
1010 		}
1011 		signo = Z_LVAL_PP(user_signo);
1012 		if (sigaddset(&set, signo) != 0) {
1013 			PCNTL_G(last_error) = errno;
1014 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
1015 			RETURN_FALSE;
1016 		}
1017 		zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
1018 	}
1019 
1020 	if (timedwait) {
1021 		timeout.tv_sec  = (time_t) tv_sec;
1022 		timeout.tv_nsec = tv_nsec;
1023 		signo = sigtimedwait(&set, &siginfo, &timeout);
1024 	} else {
1025 		signo = sigwaitinfo(&set, &siginfo);
1026 	}
1027 	if (signo == -1 && errno != EAGAIN) {
1028 		PCNTL_G(last_error) = errno;
1029 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
1030 	}
1031 
1032 	/*
1033 	 * sigtimedwait and sigwaitinfo can return 0 on success on some
1034 	 * platforms, e.g. NetBSD
1035 	 */
1036 	if (!signo && siginfo.si_signo) {
1037 		signo = siginfo.si_signo;
1038 	}
1039 
1040 	if (signo > 0 && user_siginfo) {
1041 		if (Z_TYPE_P(user_siginfo) != IS_ARRAY) {
1042 			zval_dtor(user_siginfo);
1043 			array_init(user_siginfo);
1044 		} else {
1045 			zend_hash_clean(Z_ARRVAL_P(user_siginfo));
1046 		}
1047 		add_assoc_long_ex(user_siginfo, "signo", sizeof("signo"), siginfo.si_signo);
1048 		add_assoc_long_ex(user_siginfo, "errno", sizeof("errno"), siginfo.si_errno);
1049 		add_assoc_long_ex(user_siginfo, "code",  sizeof("code"),  siginfo.si_code);
1050 		switch(signo) {
1051 #ifdef SIGCHLD
1052 			case SIGCHLD:
1053 				add_assoc_long_ex(user_siginfo,   "status", sizeof("status"), siginfo.si_status);
1054 # ifdef si_utime
1055 				add_assoc_double_ex(user_siginfo, "utime",  sizeof("utime"),  siginfo.si_utime);
1056 # endif
1057 # ifdef si_stime
1058 				add_assoc_double_ex(user_siginfo, "stime",  sizeof("stime"),  siginfo.si_stime);
1059 # endif
1060 				add_assoc_long_ex(user_siginfo,   "pid",    sizeof("pid"),    siginfo.si_pid);
1061 				add_assoc_long_ex(user_siginfo,   "uid",    sizeof("uid"),    siginfo.si_uid);
1062 				break;
1063 #endif
1064 			case SIGILL:
1065 			case SIGFPE:
1066 			case SIGSEGV:
1067 			case SIGBUS:
1068 				add_assoc_double_ex(user_siginfo, "addr", sizeof("addr"), (long)siginfo.si_addr);
1069 				break;
1070 #ifdef SIGPOLL
1071 			case SIGPOLL:
1072 				add_assoc_long_ex(user_siginfo, "band", sizeof("band"), siginfo.si_band);
1073 # ifdef si_fd
1074 				add_assoc_long_ex(user_siginfo, "fd",   sizeof("fd"),   siginfo.si_fd);
1075 # endif
1076 				break;
1077 #endif
1078 			EMPTY_SWITCH_DEFAULT_CASE();
1079 		}
1080 	}
1081 
1082 	RETURN_LONG(signo);
1083 }
1084 /* }}} */
1085 
1086 /* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo])
1087    Synchronously wait for queued signals */
PHP_FUNCTION(pcntl_sigwaitinfo)1088 PHP_FUNCTION(pcntl_sigwaitinfo)
1089 {
1090 	pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1091 }
1092 /* }}} */
1093 
1094 /* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]])
1095    Wait for queued signals */
PHP_FUNCTION(pcntl_sigtimedwait)1096 PHP_FUNCTION(pcntl_sigtimedwait)
1097 {
1098 	pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1099 }
1100 /* }}} */
1101 #endif
1102 
1103 #ifdef HAVE_GETPRIORITY
1104 /* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]])
1105    Get the priority of any process */
PHP_FUNCTION(pcntl_getpriority)1106 PHP_FUNCTION(pcntl_getpriority)
1107 {
1108 	long who = PRIO_PROCESS;
1109 	long pid = getpid();
1110 	int pri;
1111 
1112 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &pid, &who) == FAILURE) {
1113 		RETURN_FALSE;
1114 	}
1115 
1116 	/* needs to be cleared, since any returned value is valid */
1117 	errno = 0;
1118 
1119 	pri = getpriority(who, pid);
1120 
1121 	if (errno) {
1122 		PCNTL_G(last_error) = errno;
1123 		switch (errno) {
1124 			case ESRCH:
1125 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
1126 				break;
1127 			case EINVAL:
1128 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
1129 				break;
1130 			default:
1131 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occurred", errno);
1132 				break;
1133 		}
1134 		RETURN_FALSE;
1135 	}
1136 
1137 	RETURN_LONG(pri);
1138 }
1139 /* }}} */
1140 #endif
1141 
1142 #ifdef HAVE_SETPRIORITY
1143 /* {{{ proto bool pcntl_setpriority(int priority [, int pid [, int process_identifier]])
1144    Change the priority of any process */
PHP_FUNCTION(pcntl_setpriority)1145 PHP_FUNCTION(pcntl_setpriority)
1146 {
1147 	long who = PRIO_PROCESS;
1148 	long pid = getpid();
1149 	long pri;
1150 
1151 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ll", &pri, &pid, &who) == FAILURE) {
1152 		RETURN_FALSE;
1153 	}
1154 
1155 	if (setpriority(who, pid, pri)) {
1156 		PCNTL_G(last_error) = errno;
1157 		switch (errno) {
1158 			case ESRCH:
1159 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
1160 				break;
1161 			case EINVAL:
1162 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
1163 				break;
1164 			case EPERM:
1165 				php_error_docref(NULL TSRMLS_CC, 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);
1166 				break;
1167 			case EACCES:
1168 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Only a super user may attempt to increase the process priority", errno);
1169 				break;
1170 			default:
1171 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occurred", errno);
1172 				break;
1173 		}
1174 		RETURN_FALSE;
1175 	}
1176 
1177 	RETURN_TRUE;
1178 }
1179 /* }}} */
1180 #endif
1181 
1182 /* {{{ proto int pcntl_get_last_error(void)
1183    Retrieve the error number set by the last pcntl function which failed. */
PHP_FUNCTION(pcntl_get_last_error)1184 PHP_FUNCTION(pcntl_get_last_error)
1185 {
1186         RETURN_LONG(PCNTL_G(last_error));
1187 }
1188 /* }}} */
1189 
1190 /* {{{ proto string pcntl_strerror(int errno)
1191    Retrieve the system error message associated with the given errno. */
PHP_FUNCTION(pcntl_strerror)1192 PHP_FUNCTION(pcntl_strerror)
1193 {
1194         long error;
1195 
1196         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &error) == FAILURE) {
1197                 RETURN_FALSE;
1198         }
1199 
1200         RETURN_STRING(strerror(error), 1);
1201 }
1202 /* }}} */
1203 
1204 /* Our custom signal handler that calls the appropriate php_function */
pcntl_signal_handler(int signo)1205 static void pcntl_signal_handler(int signo)
1206 {
1207 	struct php_pcntl_pending_signal *psig;
1208 	TSRMLS_FETCH();
1209 
1210 	psig = PCNTL_G(spares);
1211 	if (!psig) {
1212 		/* oops, too many signals for us to track, so we'll forget about this one */
1213 		return;
1214 	}
1215 	PCNTL_G(spares) = psig->next;
1216 
1217 	psig->signo = signo;
1218 	psig->next = NULL;
1219 
1220 	/* the head check is important, as the tick handler cannot atomically clear both
1221 	 * the head and tail */
1222 	if (PCNTL_G(head) && PCNTL_G(tail)) {
1223 		PCNTL_G(tail)->next = psig;
1224 	} else {
1225 		PCNTL_G(head) = psig;
1226 	}
1227 	PCNTL_G(tail) = psig;
1228 	PCNTL_G(pending_signals) = 1;
1229 }
1230 
pcntl_signal_dispatch()1231 void pcntl_signal_dispatch()
1232 {
1233 	zval *param, **handle, *retval;
1234 	struct php_pcntl_pending_signal *queue, *next;
1235 	sigset_t mask;
1236 	sigset_t old_mask;
1237 	TSRMLS_FETCH();
1238 
1239 	if(!PCNTL_G(pending_signals)) {
1240 		return;
1241 	}
1242 
1243 	/* Mask all signals */
1244 	sigfillset(&mask);
1245 	sigprocmask(SIG_BLOCK, &mask, &old_mask);
1246 
1247 	/* Bail if the queue is empty or if we are already playing the queue*/
1248 	if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue)) {
1249 		sigprocmask(SIG_SETMASK, &old_mask, NULL);
1250 		return;
1251 	}
1252 
1253 	/* Prevent reentrant handler calls */
1254 	PCNTL_G(processing_signal_queue) = 1;
1255 
1256 	queue = PCNTL_G(head);
1257 	PCNTL_G(head) = NULL; /* simple stores are atomic */
1258 
1259 	/* Allocate */
1260 
1261 	while (queue) {
1262 		if (zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo, (void **) &handle)==SUCCESS) {
1263 			MAKE_STD_ZVAL(retval);
1264 			MAKE_STD_ZVAL(param);
1265 			ZVAL_NULL(retval);
1266 			ZVAL_LONG(param, queue->signo);
1267 
1268 			/* Call php signal handler - Note that we do not report errors, and we ignore the return value */
1269 			/* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
1270 			call_user_function(EG(function_table), NULL, *handle, retval, 1, &param TSRMLS_CC);
1271 			zval_ptr_dtor(&param);
1272 			zval_ptr_dtor(&retval);
1273 		}
1274 
1275 		next = queue->next;
1276 		queue->next = PCNTL_G(spares);
1277 		PCNTL_G(spares) = queue;
1278 		queue = next;
1279 	}
1280 
1281 	PCNTL_G(pending_signals) = 0;
1282 
1283 	/* Re-enable queue */
1284 	PCNTL_G(processing_signal_queue) = 0;
1285 
1286 	/* return signal mask to previous state */
1287 	sigprocmask(SIG_SETMASK, &old_mask, NULL);
1288 }
1289 
1290 
1291 
1292 /*
1293  * Local variables:
1294  * tab-width: 4
1295  * c-basic-offset: 4
1296  * indent-tabs-mode: t
1297  * End:
1298  */
1299