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