xref: /PHP-5.3/ext/pcntl/pcntl.c (revision a2045ff3)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 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, "s|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_EXISTANT:
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 occured: (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 occured: (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 (!PCNTL_G(spares)) {
853 		/* since calling malloc() from within a signal handler is not portable,
854 		 * pre-allocate a few records for recording signals */
855 		int i;
856 		for (i = 0; i < 32; i++) {
857 			struct php_pcntl_pending_signal *psig;
858 
859 			psig = emalloc(sizeof(*psig));
860 			psig->next = PCNTL_G(spares);
861 			PCNTL_G(spares) = psig;
862 		}
863 	}
864 
865 	/* Special long value case for SIG_DFL and SIG_IGN */
866 	if (Z_TYPE_P(handle)==IS_LONG) {
867 		if (Z_LVAL_P(handle)!= (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) {
868 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for handle argument specified");
869 		}
870 		if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
871 			PCNTL_G(last_error) = errno;
872 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
873 			RETURN_FALSE;
874 		}
875 		RETURN_TRUE;
876 	}
877 
878 	if (!zend_is_callable(handle, 0, &func_name TSRMLS_CC)) {
879 		PCNTL_G(last_error) = EINVAL;
880 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a callable function name error", func_name);
881 		efree(func_name);
882 		RETURN_FALSE;
883 	}
884 	efree(func_name);
885 
886 	/* Add the function name to our signal table */
887 	zend_hash_index_update(&PCNTL_G(php_signal_table), signo, (void **) &handle, sizeof(zval *), (void **) &dest_handle);
888 	if (dest_handle) zval_add_ref(dest_handle);
889 
890 	if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == SIG_ERR) {
891 		PCNTL_G(last_error) = errno;
892 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
893 		RETURN_FALSE;
894 	}
895 	RETURN_TRUE;
896 }
897 /* }}} */
898 
899 /* {{{ proto bool pcntl_signal_dispatch()
900    Dispatch signals to signal handlers */
PHP_FUNCTION(pcntl_signal_dispatch)901 PHP_FUNCTION(pcntl_signal_dispatch)
902 {
903 	pcntl_signal_dispatch();
904 	RETURN_TRUE;
905 }
906 /* }}} */
907 
908 #ifdef HAVE_SIGPROCMASK
909 /* {{{ proto bool pcntl_sigprocmask(int how, array set[, array &oldset])
910    Examine and change blocked signals */
PHP_FUNCTION(pcntl_sigprocmask)911 PHP_FUNCTION(pcntl_sigprocmask)
912 {
913 	long          how, signo;
914 	zval         *user_set, *user_oldset = NULL, **user_signo;
915 	sigset_t      set, oldset;
916 	HashPosition  pos;
917 
918 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "la|z", &how, &user_set, &user_oldset) == FAILURE) {
919 		return;
920 	}
921 
922 	if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) {
923 		PCNTL_G(last_error) = errno;
924 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
925 		RETURN_FALSE;
926 	}
927 
928 	zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos);
929 	while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS)
930 	{
931 		if (Z_TYPE_PP(user_signo) != IS_LONG) {
932 			SEPARATE_ZVAL(user_signo);
933 			convert_to_long_ex(user_signo);
934 		}
935 		signo = Z_LVAL_PP(user_signo);
936 		if (sigaddset(&set, signo) != 0) {
937 			PCNTL_G(last_error) = errno;
938 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
939 			RETURN_FALSE;
940 		}
941 		zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
942 	}
943 
944 	if (sigprocmask(how, &set, &oldset) != 0) {
945 		PCNTL_G(last_error) = errno;
946 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
947 		RETURN_FALSE;
948 	}
949 
950 	if (user_oldset != NULL) {
951 		if (Z_TYPE_P(user_oldset) != IS_ARRAY) {
952 			zval_dtor(user_oldset);
953 			array_init(user_oldset);
954 		} else {
955 			zend_hash_clean(Z_ARRVAL_P(user_oldset));
956 		}
957 		for (signo = 1; signo < MAX(NSIG-1, SIGRTMAX); ++signo) {
958 			if (sigismember(&oldset, signo) != 1) {
959 				continue;
960 			}
961 			add_next_index_long(user_oldset, signo);
962 		}
963 	}
964 
965 	RETURN_TRUE;
966 }
967 /* }}} */
968 #endif
969 
970 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS,int timedwait)971 static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */
972 {
973 	zval            *user_set, **user_signo, *user_siginfo = NULL;
974 	long             tv_sec = 0, tv_nsec = 0;
975 	sigset_t         set;
976 	HashPosition     pos;
977 	int              signo;
978 	siginfo_t        siginfo;
979 	struct timespec  timeout;
980 
981 	if (timedwait) {
982 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) {
983 			return;
984 		}
985 	} else {
986 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|z", &user_set, &user_siginfo) == FAILURE) {
987 			return;
988 		}
989 	}
990 
991 	if (sigemptyset(&set) != 0) {
992 		PCNTL_G(last_error) = errno;
993 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
994 		RETURN_FALSE;
995 	}
996 
997 	zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(user_set), &pos);
998 	while (zend_hash_get_current_data_ex(Z_ARRVAL_P(user_set), (void **)&user_signo, &pos) == SUCCESS)
999 	{
1000 		if (Z_TYPE_PP(user_signo) != IS_LONG) {
1001 			SEPARATE_ZVAL(user_signo);
1002 			convert_to_long_ex(user_signo);
1003 		}
1004 		signo = Z_LVAL_PP(user_signo);
1005 		if (sigaddset(&set, signo) != 0) {
1006 			PCNTL_G(last_error) = errno;
1007 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
1008 			RETURN_FALSE;
1009 		}
1010 		zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
1011 	}
1012 
1013 	if (timedwait) {
1014 		timeout.tv_sec  = (time_t) tv_sec;
1015 		timeout.tv_nsec = tv_nsec;
1016 		signo = sigtimedwait(&set, &siginfo, &timeout);
1017 	} else {
1018 		signo = sigwaitinfo(&set, &siginfo);
1019 	}
1020 	if (signo == -1 && errno != EAGAIN) {
1021 		PCNTL_G(last_error) = errno;
1022 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
1023 	}
1024 
1025 	/*
1026 	 * sigtimedwait and sigwaitinfo can return 0 on success on some
1027 	 * platforms, e.g. NetBSD
1028 	 */
1029 	if (!signo && siginfo.si_signo) {
1030 		signo = siginfo.si_signo;
1031 	}
1032 
1033 	if (signo > 0 && user_siginfo) {
1034 		if (Z_TYPE_P(user_siginfo) != IS_ARRAY) {
1035 			zval_dtor(user_siginfo);
1036 			array_init(user_siginfo);
1037 		} else {
1038 			zend_hash_clean(Z_ARRVAL_P(user_siginfo));
1039 		}
1040 		add_assoc_long_ex(user_siginfo, "signo", sizeof("signo"), siginfo.si_signo);
1041 		add_assoc_long_ex(user_siginfo, "errno", sizeof("errno"), siginfo.si_errno);
1042 		add_assoc_long_ex(user_siginfo, "code",  sizeof("code"),  siginfo.si_code);
1043 		switch(signo) {
1044 #ifdef SIGCHLD
1045 			case SIGCHLD:
1046 				add_assoc_long_ex(user_siginfo,   "status", sizeof("status"), siginfo.si_status);
1047 # ifdef si_utime
1048 				add_assoc_double_ex(user_siginfo, "utime",  sizeof("utime"),  siginfo.si_utime);
1049 # endif
1050 # ifdef si_stime
1051 				add_assoc_double_ex(user_siginfo, "stime",  sizeof("stime"),  siginfo.si_stime);
1052 # endif
1053 				add_assoc_long_ex(user_siginfo,   "pid",    sizeof("pid"),    siginfo.si_pid);
1054 				add_assoc_long_ex(user_siginfo,   "uid",    sizeof("uid"),    siginfo.si_uid);
1055 				break;
1056 #endif
1057 			case SIGILL:
1058 			case SIGFPE:
1059 			case SIGSEGV:
1060 			case SIGBUS:
1061 				add_assoc_double_ex(user_siginfo, "addr", sizeof("addr"), (long)siginfo.si_addr);
1062 				break;
1063 #ifdef SIGPOLL
1064 			case SIGPOLL:
1065 				add_assoc_long_ex(user_siginfo, "band", sizeof("band"), siginfo.si_band);
1066 # ifdef si_fd
1067 				add_assoc_long_ex(user_siginfo, "fd",   sizeof("fd"),   siginfo.si_fd);
1068 # endif
1069 				break;
1070 #endif
1071 			EMPTY_SWITCH_DEFAULT_CASE();
1072 		}
1073 	}
1074 
1075 	RETURN_LONG(signo);
1076 }
1077 /* }}} */
1078 
1079 /* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo])
1080    Synchronously wait for queued signals */
PHP_FUNCTION(pcntl_sigwaitinfo)1081 PHP_FUNCTION(pcntl_sigwaitinfo)
1082 {
1083 	pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1084 }
1085 /* }}} */
1086 
1087 /* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]])
1088    Wait for queued signals */
PHP_FUNCTION(pcntl_sigtimedwait)1089 PHP_FUNCTION(pcntl_sigtimedwait)
1090 {
1091 	pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1092 }
1093 /* }}} */
1094 #endif
1095 
1096 #ifdef HAVE_GETPRIORITY
1097 /* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]])
1098    Get the priority of any process */
PHP_FUNCTION(pcntl_getpriority)1099 PHP_FUNCTION(pcntl_getpriority)
1100 {
1101 	long who = PRIO_PROCESS;
1102 	long pid = getpid();
1103 	int pri;
1104 
1105 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &pid, &who) == FAILURE) {
1106 		RETURN_FALSE;
1107 	}
1108 
1109 	/* needs to be cleared, since any returned value is valid */
1110 	errno = 0;
1111 
1112 	pri = getpriority(who, pid);
1113 
1114 	if (errno) {
1115 		PCNTL_G(last_error) = errno;
1116 		switch (errno) {
1117 			case ESRCH:
1118 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
1119 				break;
1120 			case EINVAL:
1121 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
1122 				break;
1123 			default:
1124 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occured", errno);
1125 				break;
1126 		}
1127 		RETURN_FALSE;
1128 	}
1129 
1130 	RETURN_LONG(pri);
1131 }
1132 /* }}} */
1133 #endif
1134 
1135 #ifdef HAVE_SETPRIORITY
1136 /* {{{ proto bool pcntl_setpriority(int priority [, int pid [, int process_identifier]])
1137    Change the priority of any process */
PHP_FUNCTION(pcntl_setpriority)1138 PHP_FUNCTION(pcntl_setpriority)
1139 {
1140 	long who = PRIO_PROCESS;
1141 	long pid = getpid();
1142 	long pri;
1143 
1144 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ll", &pri, &pid, &who) == FAILURE) {
1145 		RETURN_FALSE;
1146 	}
1147 
1148 	if (setpriority(who, pid, pri)) {
1149 		PCNTL_G(last_error) = errno;
1150 		switch (errno) {
1151 			case ESRCH:
1152 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
1153 				break;
1154 			case EINVAL:
1155 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
1156 				break;
1157 			case EPERM:
1158 				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);
1159 				break;
1160 			case EACCES:
1161 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Only a super user may attempt to increase the process priority", errno);
1162 				break;
1163 			default:
1164 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occured", errno);
1165 				break;
1166 		}
1167 		RETURN_FALSE;
1168 	}
1169 
1170 	RETURN_TRUE;
1171 }
1172 /* }}} */
1173 #endif
1174 
1175 /* {{{ proto int pcntl_get_last_error(void)
1176    Retrieve the error number set by the last pcntl function which failed. */
PHP_FUNCTION(pcntl_get_last_error)1177 PHP_FUNCTION(pcntl_get_last_error)
1178 {
1179         RETURN_LONG(PCNTL_G(last_error));
1180 }
1181 /* }}} */
1182 
1183 /* {{{ proto string pcntl_strerror(int errno)
1184    Retrieve the system error message associated with the given errno. */
PHP_FUNCTION(pcntl_strerror)1185 PHP_FUNCTION(pcntl_strerror)
1186 {
1187         long error;
1188 
1189         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &error) == FAILURE) {
1190                 RETURN_FALSE;
1191         }
1192 
1193         RETURN_STRING(strerror(error), 1);
1194 }
1195 /* }}} */
1196 
1197 /* Our custom signal handler that calls the appropriate php_function */
pcntl_signal_handler(int signo)1198 static void pcntl_signal_handler(int signo)
1199 {
1200 	struct php_pcntl_pending_signal *psig;
1201 	TSRMLS_FETCH();
1202 
1203 	psig = PCNTL_G(spares);
1204 	if (!psig) {
1205 		/* oops, too many signals for us to track, so we'll forget about this one */
1206 		return;
1207 	}
1208 	PCNTL_G(spares) = psig->next;
1209 
1210 	psig->signo = signo;
1211 	psig->next = NULL;
1212 
1213 	/* the head check is important, as the tick handler cannot atomically clear both
1214 	 * the head and tail */
1215 	if (PCNTL_G(head) && PCNTL_G(tail)) {
1216 		PCNTL_G(tail)->next = psig;
1217 	} else {
1218 		PCNTL_G(head) = psig;
1219 	}
1220 	PCNTL_G(tail) = psig;
1221 }
1222 
pcntl_signal_dispatch()1223 void pcntl_signal_dispatch()
1224 {
1225 	zval *param, **handle, *retval;
1226 	struct php_pcntl_pending_signal *queue, *next;
1227 	sigset_t mask;
1228 	sigset_t old_mask;
1229 	TSRMLS_FETCH();
1230 
1231 	/* Mask all signals */
1232 	sigfillset(&mask);
1233 	sigprocmask(SIG_BLOCK, &mask, &old_mask);
1234 
1235 	/* Bail if the queue is empty or if we are already playing the queue*/
1236 	if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue)) {
1237 		sigprocmask(SIG_SETMASK, &old_mask, NULL);
1238 		return;
1239 	}
1240 
1241 	/* Prevent reentrant handler calls */
1242 	PCNTL_G(processing_signal_queue) = 1;
1243 
1244 	queue = PCNTL_G(head);
1245 	PCNTL_G(head) = NULL; /* simple stores are atomic */
1246 
1247 	/* Allocate */
1248 
1249 	while (queue) {
1250 		if (zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo, (void **) &handle)==SUCCESS) {
1251 			MAKE_STD_ZVAL(retval);
1252 			MAKE_STD_ZVAL(param);
1253 			ZVAL_NULL(retval);
1254 			ZVAL_LONG(param, queue->signo);
1255 
1256 			/* Call php signal handler - Note that we do not report errors, and we ignore the return value */
1257 			/* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
1258 			call_user_function(EG(function_table), NULL, *handle, retval, 1, &param TSRMLS_CC);
1259 			zval_ptr_dtor(&param);
1260 			zval_ptr_dtor(&retval);
1261 		}
1262 
1263 		next = queue->next;
1264 		queue->next = PCNTL_G(spares);
1265 		PCNTL_G(spares) = queue;
1266 		queue = next;
1267 	}
1268 
1269 	/* Re-enable queue */
1270 	PCNTL_G(processing_signal_queue) = 0;
1271 
1272 	/* return signal mask to previous state */
1273 	sigprocmask(SIG_SETMASK, &old_mask, NULL);
1274 }
1275 
1276 
1277 
1278 /*
1279  * Local variables:
1280  * tab-width: 4
1281  * c-basic-offset: 4
1282  * indent-tabs-mode: t
1283  * End:
1284  */
1285