root/ext/pcntl/pcntl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_GET_MODULE
  2. php_pcntl_register_errno_constants
  3. PHP_GINIT_FUNCTION
  4. PHP_RINIT_FUNCTION
  5. PHP_MINIT_FUNCTION
  6. PHP_MSHUTDOWN_FUNCTION
  7. PHP_RSHUTDOWN_FUNCTION
  8. PHP_MINFO_FUNCTION
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. PHP_FUNCTION
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION
  17. PHP_FUNCTION
  18. PHP_FUNCTION
  19. PHP_FUNCTION
  20. PHP_FUNCTION
  21. PHP_FUNCTION
  22. PHP_FUNCTION
  23. PHP_FUNCTION
  24. pcntl_sigwaitinfo
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. PHP_FUNCTION
  30. PHP_FUNCTION
  31. pcntl_signal_handler
  32. pcntl_signal_dispatch

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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 
 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 
 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 
 500 static PHP_GINIT_FUNCTION(pcntl)
 501 {
 502         memset(pcntl_globals, 0, sizeof(*pcntl_globals));
 503 }
 504 
 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 
 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 
 521 PHP_MSHUTDOWN_FUNCTION(pcntl)
 522 {
 523         return SUCCESS;
 524 }
 525 
 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 
 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*/
 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*/
 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 */
 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         convert_to_long_ex(z_status);
 631 
 632         status = Z_LVAL_P(z_status);
 633 
 634 #ifdef HAVE_WAIT4
 635         if (z_rusage) {
 636                 if (Z_TYPE_P(z_rusage) != IS_ARRAY) {
 637                         zval_dtor(z_rusage);
 638                         array_init(z_rusage);
 639                 } else {
 640                         zend_hash_clean(Z_ARRVAL_P(z_rusage));
 641                 }
 642 
 643                 memset(&rusage, 0, sizeof(struct rusage));
 644                 child_id = wait4((pid_t) pid, &status, options, &rusage);
 645         } else {
 646                 child_id = waitpid((pid_t) pid, &status, options);
 647         }
 648 #else
 649         child_id = waitpid((pid_t) pid, &status, options);
 650 #endif
 651 
 652         if (child_id < 0) {
 653                 PCNTL_G(last_error) = errno;
 654         }
 655 
 656 #ifdef HAVE_WAIT4
 657         if (child_id > 0) {
 658                 PHP_RUSAGE_TO_ARRAY(rusage, z_rusage);
 659         }
 660 #endif
 661 
 662         Z_LVAL_P(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 */
 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         convert_to_long_ex(z_status);
 684 
 685         status = Z_LVAL_P(z_status);
 686 #ifdef HAVE_WAIT3
 687         if (z_rusage) {
 688                 if (Z_TYPE_P(z_rusage) != IS_ARRAY) {
 689                         zval_dtor(z_rusage);
 690                         array_init(z_rusage);
 691                 } else {
 692                         zend_hash_clean(Z_ARRVAL_P(z_rusage));
 693                 }
 694 
 695                 memset(&rusage, 0, sizeof(struct rusage));
 696                 child_id = wait3(&status, options, &rusage);
 697         } else if (options) {
 698                 child_id = wait3(&status, options, NULL);
 699         } else {
 700                 child_id = wait(&status);
 701         }
 702 #else
 703         child_id = wait(&status);
 704 #endif
 705         if (child_id < 0) {
 706                 PCNTL_G(last_error) = errno;
 707         }
 708 
 709 #ifdef HAVE_WAIT3
 710         if (child_id > 0) {
 711                 PHP_RUSAGE_TO_ARRAY(rusage, z_rusage);
 712         }
 713 #endif
 714         Z_LVAL_P(z_status) = status;
 715 
 716         RETURN_LONG((zend_long) child_id);
 717 }
 718 /* }}} */
 719 
 720 #undef PHP_RUSAGE_PARA
 721 #undef PHP_RUSAGE_SPECIAL
 722 #undef PHP_RUSAGE_COMMON
 723 #undef PHP_RUSAGE_TO_ARRAY
 724 
 725 /* {{{ proto bool pcntl_wifexited(int status) 
 726    Returns true if the child status code represents a successful exit */
 727 PHP_FUNCTION(pcntl_wifexited)
 728 {
 729 #ifdef WIFEXITED
 730         zend_long status_word;
 731 
 732         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
 733                return;
 734         }
 735 
 736         if (WIFEXITED(status_word))
 737                 RETURN_TRUE;
 738 #endif
 739         RETURN_FALSE;
 740 }
 741 /* }}} */
 742 
 743 /* {{{ proto bool pcntl_wifstopped(int status)
 744    Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
 745 PHP_FUNCTION(pcntl_wifstopped)
 746 {
 747 #ifdef WIFSTOPPED
 748         zend_long status_word;
 749 
 750         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
 751                return;
 752         }
 753 
 754         if (WIFSTOPPED(status_word))
 755                 RETURN_TRUE;
 756 #endif
 757         RETURN_FALSE;
 758 }
 759 /* }}} */
 760 
 761 /* {{{ proto bool pcntl_wifsignaled(int status)
 762    Returns true if the child status code represents a process that was terminated due to a signal */
 763 PHP_FUNCTION(pcntl_wifsignaled)
 764 {
 765 #ifdef WIFSIGNALED
 766         zend_long status_word;
 767 
 768         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
 769                return;
 770         }
 771 
 772         if (WIFSIGNALED(status_word))
 773                 RETURN_TRUE;
 774 #endif
 775         RETURN_FALSE;
 776 }
 777 /* }}} */
 778 /* {{{ proto bool pcntl_wifcontinued(int status)
 779    Returns true if the child status code represents a process that was resumed due to a SIGCONT signal */
 780 PHP_FUNCTION(pcntl_wifcontinued)
 781 {
 782 #ifdef HAVE_WCONTINUED
 783         zend_long status_word;
 784 
 785         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
 786                return;
 787         }
 788 
 789         if (WIFCONTINUED(status_word))
 790                 RETURN_TRUE;
 791 #endif
 792         RETURN_FALSE;
 793 }
 794 /* }}} */
 795 
 796 
 797 /* {{{ proto int pcntl_wexitstatus(int status)
 798    Returns the status code of a child's exit */
 799 PHP_FUNCTION(pcntl_wexitstatus)
 800 {
 801 #ifdef WEXITSTATUS
 802         zend_long status_word;
 803 
 804         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
 805                return;
 806         }
 807 
 808         RETURN_LONG(WEXITSTATUS(status_word));
 809 #else
 810         RETURN_FALSE;
 811 #endif
 812 }
 813 /* }}} */
 814 
 815 /* {{{ proto int pcntl_wtermsig(int status)
 816    Returns the number of the signal that terminated the process who's status code is passed  */
 817 PHP_FUNCTION(pcntl_wtermsig)
 818 {
 819 #ifdef WTERMSIG
 820         zend_long status_word;
 821 
 822         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
 823                return;
 824         }
 825 
 826         RETURN_LONG(WTERMSIG(status_word));
 827 #else
 828         RETURN_FALSE;
 829 #endif
 830 }
 831 /* }}} */
 832 
 833 /* {{{ proto int pcntl_wstopsig(int status)
 834    Returns the number of the signal that caused the process to stop who's status code is passed */
 835 PHP_FUNCTION(pcntl_wstopsig)
 836 {
 837 #ifdef WSTOPSIG
 838         zend_long status_word;
 839 
 840         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) {
 841                return;
 842         }
 843 
 844         RETURN_LONG(WSTOPSIG(status_word));
 845 #else
 846         RETURN_FALSE;
 847 #endif
 848 }
 849 /* }}} */
 850 
 851 /* {{{ proto bool pcntl_exec(string path [, array args [, array envs]])
 852    Executes specified program in current process space as defined by exec(2) */
 853 PHP_FUNCTION(pcntl_exec)
 854 {
 855         zval *args = NULL, *envs = NULL;
 856         zval *element;
 857         HashTable *args_hash, *envs_hash;
 858         int argc = 0, argi = 0;
 859         int envc = 0, envi = 0;
 860         char **argv = NULL, **envp = NULL;
 861         char **current_arg, **pair;
 862         int pair_length;
 863         zend_string *key;
 864         char *path;
 865         size_t path_len;
 866         zend_ulong key_num;
 867 
 868         if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|aa", &path, &path_len, &args, &envs) == FAILURE) {
 869                 return;
 870         }
 871 
 872         if (ZEND_NUM_ARGS() > 1) {
 873                 /* Build argument list */
 874                 args_hash = Z_ARRVAL_P(args);
 875                 argc = zend_hash_num_elements(args_hash);
 876 
 877                 argv = safe_emalloc((argc + 2), sizeof(char *), 0);
 878                 *argv = path;
 879                 current_arg = argv+1;
 880                 ZEND_HASH_FOREACH_VAL(args_hash, element) {
 881                         if (argi >= argc) break;
 882                         convert_to_string_ex(element);
 883                         *current_arg = Z_STRVAL_P(element);
 884                         argi++;
 885                         current_arg++;
 886                 } ZEND_HASH_FOREACH_END();
 887                 *(current_arg) = NULL;
 888         } else {
 889                 argv = emalloc(2 * sizeof(char *));
 890                 *argv = path;
 891                 *(argv+1) = NULL;
 892         }
 893 
 894         if ( ZEND_NUM_ARGS() == 3 ) {
 895                 /* Build environment pair list */
 896                 envs_hash = Z_ARRVAL_P(envs);
 897                 envc = zend_hash_num_elements(envs_hash);
 898 
 899                 pair = envp = safe_emalloc((envc + 1), sizeof(char *), 0);
 900                 ZEND_HASH_FOREACH_KEY_VAL(envs_hash, key_num, key, element) {
 901                         if (envi >= envc) break;
 902                         if (!key) {
 903                                 key = zend_long_to_str(key_num);
 904                         } else {
 905                                 zend_string_addref(key);
 906                         }
 907 
 908                         convert_to_string_ex(element);
 909 
 910                         /* Length of element + equal sign + length of key + null */
 911                         pair_length = Z_STRLEN_P(element) + ZSTR_LEN(key) + 2;
 912                         *pair = emalloc(pair_length);
 913                         strlcpy(*pair, ZSTR_VAL(key), ZSTR_LEN(key) + 1);
 914                         strlcat(*pair, "=", pair_length);
 915                         strlcat(*pair, Z_STRVAL_P(element), pair_length);
 916 
 917                         /* Cleanup */
 918                         zend_string_release(key);
 919                         envi++;
 920                         pair++;
 921                 } ZEND_HASH_FOREACH_END();
 922                 *(pair) = NULL;
 923 
 924                 if (execve(path, argv, envp) == -1) {
 925                         PCNTL_G(last_error) = errno;
 926                         php_error_docref(NULL, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
 927                 }
 928 
 929                 /* Cleanup */
 930                 for (pair = envp; *pair != NULL; pair++) efree(*pair);
 931                 efree(envp);
 932         } else {
 933 
 934                 if (execv(path, argv) == -1) {
 935                         PCNTL_G(last_error) = errno;
 936                         php_error_docref(NULL, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
 937                 }
 938         }
 939 
 940         efree(argv);
 941 
 942         RETURN_FALSE;
 943 }
 944 /* }}} */
 945 
 946 /* {{{ proto bool pcntl_signal(int signo, callback handle [, bool restart_syscalls])
 947    Assigns a system signal handler to a PHP function */
 948 PHP_FUNCTION(pcntl_signal)
 949 {
 950         zval *handle;
 951         zend_string *func_name;
 952         zend_long signo;
 953         zend_bool restart_syscalls = 1;
 954 
 955         if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) {
 956                 return;
 957         }
 958 
 959         if (signo < 1 || signo > 32) {
 960                 php_error_docref(NULL, E_WARNING, "Invalid signal");
 961                 RETURN_FALSE;
 962         }
 963 
 964         if (!PCNTL_G(spares)) {
 965                 /* since calling malloc() from within a signal handler is not portable,
 966                  * pre-allocate a few records for recording signals */
 967                 int i;
 968                 for (i = 0; i < 32; i++) {
 969                         struct php_pcntl_pending_signal *psig;
 970 
 971                         psig = emalloc(sizeof(*psig));
 972                         psig->next = PCNTL_G(spares);
 973                         PCNTL_G(spares) = psig;
 974                 }
 975         }
 976 
 977         /* Special long value case for SIG_DFL and SIG_IGN */
 978         if (Z_TYPE_P(handle) == IS_LONG) {
 979                 if (Z_LVAL_P(handle) != (zend_long) SIG_DFL && Z_LVAL_P(handle) != (zend_long) SIG_IGN) {
 980                         php_error_docref(NULL, E_WARNING, "Invalid value for handle argument specified");
 981                         RETURN_FALSE;
 982                 }
 983                 if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
 984                         PCNTL_G(last_error) = errno;
 985                         php_error_docref(NULL, E_WARNING, "Error assigning signal");
 986                         RETURN_FALSE;
 987                 }
 988                 zend_hash_index_del(&PCNTL_G(php_signal_table), signo);
 989                 RETURN_TRUE;
 990         }
 991 
 992         if (!zend_is_callable(handle, 0, &func_name)) {
 993                 PCNTL_G(last_error) = EINVAL;
 994                 php_error_docref(NULL, E_WARNING, "%s is not a callable function name error", ZSTR_VAL(func_name));
 995                 zend_string_release(func_name);
 996                 RETURN_FALSE;
 997         }
 998         zend_string_release(func_name);
 999 
1000         /* Add the function name to our signal table */
1001         if (zend_hash_index_update(&PCNTL_G(php_signal_table), signo, handle)) {
1002                 if (Z_REFCOUNTED_P(handle)) Z_ADDREF_P(handle);
1003         }
1004 
1005         if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == SIG_ERR) {
1006                 PCNTL_G(last_error) = errno;
1007                 php_error_docref(NULL, E_WARNING, "Error assigning signal");
1008                 RETURN_FALSE;
1009         }
1010         RETURN_TRUE;
1011 }
1012 /* }}} */
1013 
1014 /* {{{ proto bool pcntl_signal_dispatch()
1015    Dispatch signals to signal handlers */
1016 PHP_FUNCTION(pcntl_signal_dispatch)
1017 {
1018         pcntl_signal_dispatch();
1019         RETURN_TRUE;
1020 }
1021 /* }}} */
1022 
1023 #ifdef HAVE_SIGPROCMASK
1024 /* {{{ proto bool pcntl_sigprocmask(int how, array set[, array &oldset])
1025    Examine and change blocked signals */
1026 PHP_FUNCTION(pcntl_sigprocmask)
1027 {
1028         zend_long          how, signo;
1029         zval         *user_set, *user_oldset = NULL, *user_signo;
1030         sigset_t      set, oldset;
1031 
1032         if (zend_parse_parameters(ZEND_NUM_ARGS(), "la|z/", &how, &user_set, &user_oldset) == FAILURE) {
1033                 return;
1034         }
1035 
1036         if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) {
1037                 PCNTL_G(last_error) = errno;
1038                 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1039                 RETURN_FALSE;
1040         }
1041 
1042         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(user_set), user_signo) {
1043                 signo = zval_get_long(user_signo);
1044                 if (sigaddset(&set, signo) != 0) {
1045                         PCNTL_G(last_error) = errno;
1046                         php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1047                         RETURN_FALSE;
1048                 }
1049         } ZEND_HASH_FOREACH_END();
1050 
1051         if (sigprocmask(how, &set, &oldset) != 0) {
1052                 PCNTL_G(last_error) = errno;
1053                 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1054                 RETURN_FALSE;
1055         }
1056 
1057         if (user_oldset != NULL) {
1058                 if (Z_TYPE_P(user_oldset) != IS_ARRAY) {
1059                         zval_dtor(user_oldset);
1060                         array_init(user_oldset);
1061                 } else {
1062                         zend_hash_clean(Z_ARRVAL_P(user_oldset));
1063                 }
1064                 for (signo = 1; signo < MAX(NSIG-1, SIGRTMAX); ++signo) {
1065                         if (sigismember(&oldset, signo) != 1) {
1066                                 continue;
1067                         }
1068                         add_next_index_long(user_oldset, signo);
1069                 }
1070         }
1071 
1072         RETURN_TRUE;
1073 }
1074 /* }}} */
1075 #endif
1076 
1077 #if HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT
1078 static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{{ */
1079 {
1080         zval            *user_set, *user_signo, *user_siginfo = NULL;
1081         zend_long             tv_sec = 0, tv_nsec = 0;
1082         sigset_t         set;
1083         int              signo;
1084         siginfo_t        siginfo;
1085         struct timespec  timeout;
1086 
1087         if (timedwait) {
1088                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|z/ll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) {
1089                         return;
1090                 }
1091         } else {
1092                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|z/", &user_set, &user_siginfo) == FAILURE) {
1093                         return;
1094                 }
1095         }
1096 
1097         if (sigemptyset(&set) != 0) {
1098                 PCNTL_G(last_error) = errno;
1099                 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1100                 RETURN_FALSE;
1101         }
1102 
1103         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(user_set), user_signo) {
1104                 signo = zval_get_long(user_signo);
1105                 if (sigaddset(&set, signo) != 0) {
1106                         PCNTL_G(last_error) = errno;
1107                         php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1108                         RETURN_FALSE;
1109                 }
1110         } ZEND_HASH_FOREACH_END();
1111 
1112         if (timedwait) {
1113                 timeout.tv_sec  = (time_t) tv_sec;
1114                 timeout.tv_nsec = tv_nsec;
1115                 signo = sigtimedwait(&set, &siginfo, &timeout);
1116         } else {
1117                 signo = sigwaitinfo(&set, &siginfo);
1118         }
1119         if (signo == -1 && errno != EAGAIN) {
1120                 PCNTL_G(last_error) = errno;
1121                 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
1122         }
1123 
1124         /*
1125          * sigtimedwait and sigwaitinfo can return 0 on success on some
1126          * platforms, e.g. NetBSD
1127          */
1128         if (!signo && siginfo.si_signo) {
1129                 signo = siginfo.si_signo;
1130         }
1131 
1132         if (signo > 0 && user_siginfo) {
1133                 if (Z_TYPE_P(user_siginfo) != IS_ARRAY) {
1134                         zval_dtor(user_siginfo);
1135                         array_init(user_siginfo);
1136                 } else {
1137                         zend_hash_clean(Z_ARRVAL_P(user_siginfo));
1138                 }
1139                 add_assoc_long_ex(user_siginfo, "signo", sizeof("signo")-1, siginfo.si_signo);
1140                 add_assoc_long_ex(user_siginfo, "errno", sizeof("errno")-1, siginfo.si_errno);
1141                 add_assoc_long_ex(user_siginfo, "code",  sizeof("code")-1,  siginfo.si_code);
1142                 switch(signo) {
1143 #ifdef SIGCHLD
1144                         case SIGCHLD:
1145                                 add_assoc_long_ex(user_siginfo,   "status", sizeof("status")-1, siginfo.si_status);
1146 # ifdef si_utime
1147                                 add_assoc_double_ex(user_siginfo, "utime",  sizeof("utime")-1,  siginfo.si_utime);
1148 # endif
1149 # ifdef si_stime
1150                                 add_assoc_double_ex(user_siginfo, "stime",  sizeof("stime")-1,  siginfo.si_stime);
1151 # endif
1152                                 add_assoc_long_ex(user_siginfo,   "pid",    sizeof("pid")-1,    siginfo.si_pid);
1153                                 add_assoc_long_ex(user_siginfo,   "uid",    sizeof("uid")-1,    siginfo.si_uid);
1154                                 break;
1155 #endif
1156                         case SIGILL:
1157                         case SIGFPE:
1158                         case SIGSEGV:
1159                         case SIGBUS:
1160                                 add_assoc_double_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo.si_addr);
1161                                 break;
1162 #ifdef SIGPOLL
1163                         case SIGPOLL:
1164                                 add_assoc_long_ex(user_siginfo, "band", sizeof("band")-1, siginfo.si_band);
1165 # ifdef si_fd
1166                                 add_assoc_long_ex(user_siginfo, "fd",   sizeof("fd")-1,   siginfo.si_fd);
1167 # endif
1168                                 break;
1169 #endif
1170                 }
1171         }
1172 
1173         RETURN_LONG(signo);
1174 }
1175 /* }}} */
1176 
1177 /* {{{ proto int pcnlt_sigwaitinfo(array set[, array &siginfo])
1178    Synchronously wait for queued signals */
1179 PHP_FUNCTION(pcntl_sigwaitinfo)
1180 {
1181         pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1182 }
1183 /* }}} */
1184 
1185 /* {{{ proto int pcntl_sigtimedwait(array set[, array &siginfo[, int seconds[, int nanoseconds]]])
1186    Wait for queued signals */
1187 PHP_FUNCTION(pcntl_sigtimedwait)
1188 {
1189         pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1190 }
1191 /* }}} */
1192 #endif
1193 
1194 #ifdef HAVE_GETPRIORITY
1195 /* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]])
1196    Get the priority of any process */
1197 PHP_FUNCTION(pcntl_getpriority)
1198 {
1199         zend_long who = PRIO_PROCESS;
1200         zend_long pid = getpid();
1201         int pri;
1202 
1203         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &pid, &who) == FAILURE) {
1204                 RETURN_FALSE;
1205         }
1206 
1207         /* needs to be cleared, since any returned value is valid */
1208         errno = 0;
1209 
1210         pri = getpriority(who, pid);
1211 
1212         if (errno) {
1213                 PCNTL_G(last_error) = errno;
1214                 switch (errno) {
1215                         case ESRCH:
1216                                 php_error_docref(NULL, E_WARNING, "Error %d: No process was located using the given parameters", errno);
1217                                 break;
1218                         case EINVAL:
1219                                 php_error_docref(NULL, E_WARNING, "Error %d: Invalid identifier flag", errno);
1220                                 break;
1221                         default:
1222                                 php_error_docref(NULL, E_WARNING, "Unknown error %d has occurred", errno);
1223                                 break;
1224                 }
1225                 RETURN_FALSE;
1226         }
1227 
1228         RETURN_LONG(pri);
1229 }
1230 /* }}} */
1231 #endif
1232 
1233 #ifdef HAVE_SETPRIORITY
1234 /* {{{ proto bool pcntl_setpriority(int priority [, int pid [, int process_identifier]])
1235    Change the priority of any process */
1236 PHP_FUNCTION(pcntl_setpriority)
1237 {
1238         zend_long who = PRIO_PROCESS;
1239         zend_long pid = getpid();
1240         zend_long pri;
1241 
1242         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|ll", &pri, &pid, &who) == FAILURE) {
1243                 RETURN_FALSE;
1244         }
1245 
1246         if (setpriority(who, pid, pri)) {
1247                 PCNTL_G(last_error) = errno;
1248                 switch (errno) {
1249                         case ESRCH:
1250                                 php_error_docref(NULL, E_WARNING, "Error %d: No process was located using the given parameters", errno);
1251                                 break;
1252                         case EINVAL:
1253                                 php_error_docref(NULL, E_WARNING, "Error %d: Invalid identifier flag", errno);
1254                                 break;
1255                         case EPERM:
1256                                 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);
1257                                 break;
1258                         case EACCES:
1259                                 php_error_docref(NULL, E_WARNING, "Error %d: Only a super user may attempt to increase the process priority", errno);
1260                                 break;
1261                         default:
1262                                 php_error_docref(NULL, E_WARNING, "Unknown error %d has occurred", errno);
1263                                 break;
1264                 }
1265                 RETURN_FALSE;
1266         }
1267 
1268         RETURN_TRUE;
1269 }
1270 /* }}} */
1271 #endif
1272 
1273 /* {{{ proto int pcntl_get_last_error(void)
1274    Retrieve the error number set by the last pcntl function which failed. */
1275 PHP_FUNCTION(pcntl_get_last_error)
1276 {
1277         RETURN_LONG(PCNTL_G(last_error));
1278 }
1279 /* }}} */
1280 
1281 /* {{{ proto string pcntl_strerror(int errno)
1282    Retrieve the system error message associated with the given errno. */
1283 PHP_FUNCTION(pcntl_strerror)
1284 {
1285         zend_long error;
1286 
1287         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &error) == FAILURE) {
1288                 RETURN_FALSE;
1289         }
1290 
1291         RETURN_STRING(strerror(error));
1292 }
1293 /* }}} */
1294 
1295 /* Our custom signal handler that calls the appropriate php_function */
1296 static void pcntl_signal_handler(int signo)
1297 {
1298         struct php_pcntl_pending_signal *psig;
1299 
1300         psig = PCNTL_G(spares);
1301         if (!psig) {
1302                 /* oops, too many signals for us to track, so we'll forget about this one */
1303                 return;
1304         }
1305         PCNTL_G(spares) = psig->next;
1306 
1307         psig->signo = signo;
1308         psig->next = NULL;
1309 
1310         /* the head check is important, as the tick handler cannot atomically clear both
1311          * the head and tail */
1312         if (PCNTL_G(head) && PCNTL_G(tail)) {
1313                 PCNTL_G(tail)->next = psig;
1314         } else {
1315                 PCNTL_G(head) = psig;
1316         }
1317         PCNTL_G(tail) = psig;
1318         PCNTL_G(pending_signals) = 1;
1319 }
1320 
1321 void pcntl_signal_dispatch()
1322 {
1323         zval param, *handle, retval;
1324         struct php_pcntl_pending_signal *queue, *next;
1325         sigset_t mask;
1326         sigset_t old_mask;
1327 
1328         if(!PCNTL_G(pending_signals)) {
1329                 return;
1330         }
1331 
1332         /* Mask all signals */
1333         sigfillset(&mask);
1334         sigprocmask(SIG_BLOCK, &mask, &old_mask);
1335 
1336         /* Bail if the queue is empty or if we are already playing the queue*/
1337         if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue)) {
1338                 sigprocmask(SIG_SETMASK, &old_mask, NULL);
1339                 return;
1340         }
1341 
1342         /* Prevent reentrant handler calls */
1343         PCNTL_G(processing_signal_queue) = 1;
1344 
1345         queue = PCNTL_G(head);
1346         PCNTL_G(head) = NULL; /* simple stores are atomic */
1347 
1348         /* Allocate */
1349 
1350         while (queue) {
1351                 if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {
1352                         ZVAL_NULL(&retval);
1353                         ZVAL_LONG(&param, queue->signo);
1354 
1355                         /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
1356                         /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
1357                         call_user_function(EG(function_table), NULL, handle, &retval, 1, &param);
1358                         zval_ptr_dtor(&param);
1359                         zval_ptr_dtor(&retval);
1360                 }
1361 
1362                 next = queue->next;
1363                 queue->next = PCNTL_G(spares);
1364                 PCNTL_G(spares) = queue;
1365                 queue = next;
1366         }
1367 
1368         PCNTL_G(pending_signals) = 0;
1369 
1370         /* Re-enable queue */
1371         PCNTL_G(processing_signal_queue) = 0;
1372 
1373         /* return signal mask to previous state */
1374         sigprocmask(SIG_SETMASK, &old_mask, NULL);
1375 }
1376 
1377 
1378 
1379 /*
1380  * Local variables:
1381  * tab-width: 4
1382  * c-basic-offset: 4
1383  * indent-tabs-mode: t
1384  * End:
1385  */

/* [<][>][^][v][top][bottom][index][help] */