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