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(¶m, 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, ¶m);
1359 zval_ptr_dtor(¶m);
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